一、項(xiàng)目背景
隨著人們生活水平的不斷提高,對居住環(huán)境的舒適度要求也越來越高??照{(diào)作為一種重要的家電設(shè)備,已經(jīng)成為了現(xiàn)代家庭中必不可少的一部分。本文介紹了一種基于STM32的智能空調(diào)設(shè)計(jì)方案,可以自動(dòng)地根據(jù)環(huán)境溫度進(jìn)行溫度調(diào)節(jié)。
二、設(shè)計(jì)思路
2.1 整體構(gòu)架
智能空調(diào)系統(tǒng)由溫度檢測傳感器、微控制器、OLED顯示屏、按鍵及直流電源等組件構(gòu)成。傳感器用于檢測環(huán)境溫度,通過微控制器進(jìn)行處理后,將結(jié)果輸出到OLED顯示屏上展示。按鍵可根據(jù)需求調(diào)整預(yù)設(shè)閥值,切換模式等操作。
2.2 硬件設(shè)計(jì)
(1)溫度檢測傳感器
選擇DS18B20數(shù)字溫度傳感器作為本系統(tǒng)的溫度檢測器件。該傳感器具有精度高,響應(yīng)速度快等特點(diǎn),可以滿足該系統(tǒng)的檢測需求。
(2)微控制器
使用STM32F103系列的微控制器,在該控制器活躍的生態(tài)環(huán)境下,以及其先進(jìn)的處理能力,可以對信號進(jìn)行快速采集、處理和控制。
(3)OLED顯示屏
本系統(tǒng)使用的是一塊128 * 64 OLED顯示屏,顯示屏具有高亮度、高對比度和低功耗等優(yōu)點(diǎn),易于與STM32微控制器進(jìn)行通信。
2.3 軟件設(shè)計(jì)
在軟件設(shè)計(jì)方面,實(shí)現(xiàn)了溫度檢測傳感器數(shù)據(jù)的采集,使用處理算法對數(shù)據(jù)進(jìn)行處理,根據(jù)預(yù)設(shè)閥值自動(dòng)調(diào)節(jié)溫度,同時(shí)可以根據(jù)用戶需求,切換制冷、制熱和關(guān)閉等3種模式。最后,將結(jié)果通過OLED顯示屏進(jìn)行輸出。
三、代碼設(shè)計(jì)
3.1 DS18B20溫度檢測代碼
#include "main.h"
#include "delay.h"
#define GPIO_PORT_TEMP GPIOA //溫度數(shù)據(jù)引腳所在的端口
#define GPIO_PIN_TEMP GPIO_Pin_0 //溫度數(shù)據(jù)引腳所在的引腳編號
#define RCC_PORT_TEMPP RCC_APB2Periph_GPIOA // 溫度引腳所在端口時(shí)鐘號
void USART_SendByte( USART_TypeDef * pUSARTx, uint8_t ch );
void delay_us(uint32_t us){ // 延時(shí)us微秒函數(shù)
uint8_t i;
for(i=0;i<us;i++){
asm("nop");
}
}
float get_temp(){ // 獲取溫度函數(shù)
uint16_t temp;
uint8_t buf[2];
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_InitStruct;
RCC_APB2PeriphClockCmd(RCC_PORT_TEMPP,ENABLE);
//DATA拉低480us復(fù)位
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_PIN_TEMP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIO_PORT_TEMP , &GPIO_InitStruct);
GPIO_ResetBits(GPIO_PORT_TEMP , GPIO_PIN_TEMP );
delay_us(500);
GPIO_SetBits(GPIO_PORT_TEMP , GPIO_PIN_TEMP );
delay_us(60);
//查詢DS18B20是否存在
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin = GPIO_PIN_TEMP;
GPIO_Init(GPIO_PORT_TEMP , &GPIO_InitStruct);
while (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET);
//通信開始
GPIO_ResetBits(GPIO_PORT_TEMP , GPIO_PIN_TEMP );
delay_us(480);
GPIO_SetBits(GPIO_PORT_TEMP , GPIO_PIN_TEMP );
delay_us(60);
//讀取溫度數(shù)據(jù)
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin = GPIO_PIN_TEMP ;
GPIO_Init(GPIO_PORT_TEMP , &GPIO_InitStruct);
delay_us(10);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
temp |=0x01;
}
else{
temp &=0xfe;
}
delay_us(50);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
temp |=0x02;
}
else{
temp &=0xfd;
}
delay_us(50);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
temp |=0x04;
}
else{
temp &=0xfb;
}
delay_us(50);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
temp |=0x08;
}
else{
temp &=0xf7;
}
delay_us(50);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
temp |=0x10;
}
else{
temp &=0xef;
}
delay_us(50);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
temp |=0x20;
}
else{
temp &=0xdf;
}
delay_us(50);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
temp |=0x40;
}
else{
temp &=0xbf;
}
delay_us(50);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
temp |=0x80;
}
else{
temp &=0x7f;
}
delay_us(50);
//讀取溫度小數(shù)點(diǎn)數(shù)據(jù)
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
buf[0] |=0x01;
}
else{
buf[0] &=0xfe;
}
delay_us(50);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
buf[0] |=0x02;
}
else{
buf[0] &=0xfd;
}
delay_us(50);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
buf[0] |=0x04;
}
else{
buf[0] &=0xfb;
}
delay_us(50);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
buf[0] |=0x08;
}
else{
buf[0] &=0xf7;
}
delay_us(50);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
buf[0] |=0x10;
}
else{
buf[0] &=0xef;
}
delay_us(50);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
buf[0] |=0x20;
}
else{
buf[0] &=0xdf;
}
delay_us(50);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
buf[0] |=0x40;
}
else{
buf[0] &=0xbf;
}
delay_us(50);
if (GPIO_ReadInputDataBit(GPIO_PORT_TEMP , GPIO_PIN_TEMP ) == RESET){
buf[0] |=0x80;
}
else{
buf[0] &=0x7f;
}
delay_us(50);
return (float)temp+((float)buf[0]/16.0); // 將溫度整數(shù)位和小數(shù)位轉(zhuǎn)換為十進(jìn)制
}
int main(void){
char temp_buf[20]; // 接收溫度值的臨時(shí)緩沖區(qū)
USART_InitTypeDef USART_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
USART_InitStruct.USART_BaudRate = 115200;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1,&USART_InitStruct);
USART_Cmd(USART1,ENABLE);
while(1){
float temp_get=get_temp(); // 獲取當(dāng)前溫度值
sprintf(temp_buf,"temp:%0.1frn",temp_get); // 將溫度值格式化為字符串輸出
for(int i=0;i<strlen(temp_buf);i++){ // 逐字符發(fā)送溫度值至串口
USART_SendByte(USART1,temp_buf[i]);
}
delay_ms(1000); // 延時(shí)1s后再次獲取溫度值
}
}
void USART_SendByte( USART_TypeDef * pUSARTx, uint8_t ch ){
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE) == RESET);
USART_SendData(pUSARTx,ch);
}
3.2 OLED顯示屏代碼
#include "main.h"
#include "delay.h"
#include "oled.h"
void iic_init(void);
void GPIO_I2C_Delay(void);
void write_com(unsigned char com);
void write_data(unsigned char data);
int main(void){
unsigned char x,y;
iic_init(); // 初始化IIC接口
OLED_Init(); // 初始化OLED顯示屏
while(1){
OLED_ShowString(0,0,"1234"); // 在OLED顯示屏上顯示字符串“1234”
delay_ms(500); // 延時(shí)500ms
OLED_Clear(); // 清空OLED顯示屏
}
}
void iic_init(void){
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //GPIOB使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); //I2C1使能
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD; //配置開漏輸出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStruct);
I2C_InitTypeDef I2C_InitStruct;
I2C_DeInit(I2C1);
I2C_InitStruct.I2C_Mode = I2C_Mode_I2C; // I2C 模式
I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 數(shù)傳比率 2
I2C_InitStruct.I2C_OwnAddress1 = 0x00; // 地址1, 設(shè)備地址
I2C_InitStruct.I2C_Ack = I2C_Ack_Enable; // 開啟I2C應(yīng)答機(jī)制
I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //設(shè)備地址長度為 7 位
I2C_InitStruct.I2C_ClockSpeed = 400000; // 時(shí)鐘速度為400kHz
I2C_Cmd(I2C1, ENABLE);
I2C_Init(I2C1, &I2C_InitStruct);
}
void GPIO_I2C_Delay(void){
uint32_t i = 1000;
while(i--);
}
void write_com(unsigned char com){
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY)); //等待I2C總線空閑
I2C_GenerateSTART(I2C1,ENABLE); //發(fā)送起始信號
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1,0x78,I2C_Direction_Transmitter);//選擇寫入模式,發(fā)送從機(jī)器OLED的地址0x78
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C1,0x00); //發(fā)送控制字節(jié)0x00表示寫入指令
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(I2C1,com); //寫入要發(fā)送的指令
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2C1,ENABLE); //停止信號,傳輸結(jié)束
}
void write_data(unsigned char data){
while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY)); //等待I2C總線空閑
I2C_GenerateSTART(I2C1,ENABLE); //發(fā)送起始信號
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1,0x78,I2C_Direction_Transmitter); //選擇寫入模式,發(fā)送從機(jī)器OLED的地址0x78
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C1,0x40); //發(fā)送控制字節(jié)0x40表示寫入數(shù)據(jù)
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(I2C1,data); //寫入要發(fā)送的數(shù)據(jù)
while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2C1,ENABLE); //停止信號,傳輸結(jié)束
}