功能
//硬件:msp430f5529、dht22、LCD1602、蜂鳴器、煙霧傳感器、藍牙模塊。
//功能:讀取溫濕度、煙霧濃度顯示到屏幕;
//按鍵調節三個報警數值;
//溫度、濕度、煙霧濃度,任意一個大于報警數值就蜂鳴器報警;
//單片機將溫度、濕度、煙霧濃度,通過藍牙模塊,發送到電腦端顯示。
//電腦端也可以調節三個報警數值。
引腳
//PCF8574 LCD1602----MSP430F5529
//GND----------------GND
//VCC----------------3.3v
//SDA----------------P2.4
//SCL----------------P2.5//HC05 藍牙----------MSP430F5529
//GND----------------GND
//VCC----------------3.3v
//RX-----------------P3.3 T
//TX-----------------P3.4 R//PM2煙霧傳感器 0~3.3v電壓轉為ppm單位 20~20000ppm
//DHT22--------------MSP430F5529
//GND----------------GND
//VCC----------------3.3v
//DAT----------------P2.3//煙霧---------------MSP430F5529
//GND----------------GND
//VCC----------------3.3v
//A0-----------------P6.5//蜂鳴器-------------MSP430F5529
//GND----------------GND
//VCC----------------3.3v
//DAT----------------P1.6//按鍵----------------MSP430F5529
//KEY1----------------P1.2
//KEY2----------------P1.3
//KEY3----------------P1.4
//KEY4----------------P1.5
//GND-----------------GND//板子自己有的按鍵
//KEY5----------------P1.1
//KEY6----------------P2.1
部分程序
unsigned char get_key(void) //聲明一個函數,返回值類型為 unsigned char,函數名為 get_key,參數列表為空
{unsigned char key; //聲明一個名為 key 的無符號字符變量if ((P1IN & BIT2) == 0) //如果 P1IN 寄存器的第二位是 0,說明按鍵1被按下{delay_ms(10); //延時 10 毫秒,以確保讀取的值穩定if ((P1IN & BIT2) == 0) //再次檢測按鍵1是否被按下{key = 1; //將 key 設置為 1,表示按下了按鍵1while ((P1IN & BIT2) == 0)//等待按鍵1松開;}}else if ((P1IN & BIT3) == 0) //如果按鍵1未被按下,檢測按鍵2是否被按下{delay_ms(10); //同樣進行延時if ((P1IN & BIT3) == 0) //檢測按鍵2是否被按下{key = 2; //將 key 設置為 2,表示按下了按鍵2while ((P1IN & BIT3) == 0)//等待按鍵2松開;}}else if ((P1IN & BIT4) == 0){delay_ms(10);if ((P1IN & BIT4) == 0){key = 3;while ((P1IN & BIT4) == 0);}}else if ((P1IN & BIT5) == 0){delay_ms(10);if ((P1IN & BIT5) == 0){key = 4;while ((P1IN & BIT5) == 0);}}else if ((P1IN & BIT1) == 0){delay_ms(10);if ((P1IN & BIT1) == 0){key = 5;while ((P1IN & BIT1) == 0);}}else if ((P2IN & BIT1) == 0){delay_ms(10);if ((P2IN & BIT1) == 0){key = 6;while ((P2IN & BIT1) == 0);}}else{key = 0;}return key;
}u8 data[5];
u16 shidu, wendu, yanwu;
u16 shidu_baojing = 900, wendu_baojing = 400, yanwu_baojing = 10000;
u8 disp[20];
u8 count = 0;
u8 timecnt = 0;
u8 keyvalue = 0;void disp_line1(void) // 定義名為disp_line1的函數
{count = 0; // 初始化計數器disp[count++] = wendu % 1000 / 100 + '0'; // 將溫度百位數字轉換為字符存入顯示緩存數組,計數器+1disp[count++] = wendu % 100 / 10 + '0'; // 將溫度十位數字轉換為字符存入顯示緩存數組,計數器+1disp[count++] = 'C'; // 存入字符'C',表示攝氏度,計數器+1disp[count++] = ' '; // 存入空格字符,計數器+1disp[count++] = shidu % 1000 / 100 + '0'; // 將濕度百位數字轉換為字符存入顯示緩存數組,計數器+1disp[count++] = shidu % 100 / 10 + '0'; // 將濕度十位數字轉換為字符存入顯示緩存數組,計數器+1disp[count++] = '%'; // 存入字符'%',表示百分比符號,計數器+1disp[count++] = ' '; // 存入空格字符,計數器+1disp[count++] = yanwu % 100000 / 10000 + '0'; // 將煙霧萬位數字轉換為字符存入顯示緩存數組,計數器+1disp[count++] = yanwu % 10000 / 1000 + '0'; // 將煙霧千位數字轉換為字符存入顯示緩存數組,計數器+1disp[count++] = yanwu % 1000 / 100 + '0'; // 將煙霧百位數字轉換為字符存入顯示緩存數組,計數器+1disp[count++] = yanwu % 100 / 10 + '0'; // 將煙霧十位數字轉換為字符存入顯示緩存數組,計數器+1disp[count++] = yanwu % 10 + '0'; // 將煙霧個位數字轉換為字符存入顯示緩存數組,計數器+1disp[count++] = 'p'; // 存入字符'p',表示“ppm”(parts per million),計數器+1disp[count++] = 0; // 存入字符'\0',表示字符串結束,計數器+1LCD_write_str(0, 0, disp); // 在LCD屏幕第0行顯示disp數組中的內容
}void send_computer(void)
{count = 0;disp[count++] = wendu % 1000 / 100 + '0';disp[count++] = wendu % 100 / 10 + '0';disp[count++] = 'C';disp[count++] = ' ';disp[count++] = shidu % 1000 / 100 + '0';disp[count++] = shidu % 100 / 10 + '0';disp[count++] = '%';disp[count++] = ' ';disp[count++] = yanwu % 100000 / 10000 + '0';disp[count++] = yanwu % 10000 / 1000 + '0';disp[count++] = yanwu % 1000 / 100 + '0';disp[count++] = yanwu % 100 / 10 + '0';disp[count++] = yanwu % 10 + '0';disp[count++] = 'p';disp[count++] = '\r';disp[count++] = '\n';disp[count++] = 0;Print_Str(disp);
}void disp_line2(void)
{count = 0; //計數器清零//顯示濕度報警值的百位、十位disp[count++] = shidu_baojing % 1000 / 100 + '0';disp[count++] = shidu_baojing % 100 / 10 + '0';disp[count++] = 'C'; //顯示'C'disp[count++] = ' '; //顯示空格//顯示溫度報警值的百位、十位disp[count++] = wendu_baojing % 1000 / 100 + '0';disp[count++] = wendu_baojing % 100 / 10 + '0';disp[count++] = '%'; //顯示'%'disp[count++] = ' '; //顯示空格//顯示煙霧報警值的萬位、千位、百位、十位、個位disp[count++] = yanwu_baojing % 100000 / 10000 + '0';disp[count++] = yanwu_baojing % 10000 / 1000 + '0';disp[count++] = yanwu_baojing % 1000 / 100 + '0';disp[count++] = yanwu_baojing % 100 / 10 + '0';disp[count++] = yanwu_baojing % 10 + '0';disp[count++] = 'p'; //顯示'p'disp[count++] = 0; //末尾字符為0//在LCD的第1行第0列顯示字符串dispLCD_write_str(0, 1, disp);
}void deal_key(void)
{// 定義一個函數deal_key,沒有返回值,沒有參數if (keyvalue == 1){// 如果keyvalue的值為1shidu_baojing += 10;// 濕度報警值加10if (shidu_baojing > 900){// 如果濕度報警值大于900shidu_baojing = 900;// 把濕度報警值設為900}}else if (keyvalue == 2){// 否則,如果keyvalue的值為2shidu_baojing -= 10;// 濕度報警值減10if (shidu_baojing < 100){// 如果濕度報警值小于100shidu_baojing = 100;// 把濕度報警值設為100}}else if (keyvalue == 3){// 否則,如果keyvalue的值為3wendu_baojing += 10;// 溫度報警值加10if (wendu_baojing > 900){// 如果溫度報警值大于900wendu_baojing = 900;// 把溫度報警值設為900}}else if (keyvalue == 4){// 否則,如果keyvalue的值為4wendu_baojing -= 10;// 溫度報警值減10if (wendu_baojing < 100){// 如果溫度報警值小于100wendu_baojing = 100;// 把溫度報警值設為100}}else if (keyvalue == 5){// 否則,如果keyvalue的值為5yanwu_baojing += 100;// 煙霧報警值加100if (yanwu_baojing > 20000){// 如果煙霧報警值大于20000yanwu_baojing = 20000;// 把煙霧報警值設為20000}}else if (keyvalue == 6){// 否則,如果keyvalue的值為6yanwu_baojing -= 100;// 煙霧報警值減100if (yanwu_baojing < 200){// 如果煙霧報警值大于200yanwu_baojing = 200;// 把煙霧報警值設為200}}
}void contorl_beep(void) // 定義一個名為 contorl_beep 的函數
{if ((shidu > shidu_baojing) || (wendu > wendu_baojing) // 如果濕度、溫度或煙霧任意一個超過了警戒值|| (yanwu > yanwu_baojing)){P1OUT &= ~BIT6; // 將 P1OUT 寄存器的第 6 位設置為 0,表示開啟蜂鳴器}else // 如果濕度、溫度和煙霧都沒有超過警戒值{P1OUT |= BIT6; // 將 P1OUT 寄存器的第 6 位設置為 1,表示關閉開啟蜂鳴器}
}/* 煙霧濃度換算 */
static unsigned int yw_ppm_count(unsigned int x1)
{float a =0 ,b = 0,c = 0,d = 0;float ax =0 ,bx = 0,cx = 0,dx = 0;float y;float x;x=x1*3.3/4096;a = x * x * x * x * x;b = x * x * x * x;c = x * x * x;d = x * x ;ax = 0.0001923 * a;bx = 0.006017 * b;cx = 0.07267 * c;dx = 0.425 * d;y = ax - bx + cx - dx + (1.267 * x) + 1.209;y = y * 1000;return (unsigned int)y;
}void main(void)
{WDTCTL = WDTPW + WDTHOLD; // 停止看門狗定時器init_clock(); // 初始化時鐘init_uart(); // 初始化UART串口init_adc(); // 初始化ADC模塊init_key(); // 初始化按鍵init_beep(); // 初始化蜂鳴器while (DHT22_Init() == 1) // 初始化DHT22溫濕度傳感器{delay_ms(100); // 延時100毫秒}delay_ms(1000);LCD_Init(); // 初始化液晶屏disp_line2(); // 在液晶屏上顯示第二行_EINT(); // 開啟總中斷while (1) // 無限循環{delay_ms(10); // 延時10毫秒timecnt++; // 時間計數器加1if (timecnt > 200) // 如果時間計數器超過200{timecnt = 0; // 重置時間計數器DHT22_Read_Data(data); // 讀取DHT22傳感器數據shidu = data[0]; // 濕度數據shidu = (shidu << 8) + data[1]; // 拼接數據wendu = data[2]; // 溫度數據wendu = (wendu << 8) + data[3]; // 拼接數據yanwu = get_adc(); // 獲取煙霧濃度值//0到4096轉為0到20000ppmyanwu = yw_ppm_count(yanwu); // 將ADC值轉換為煙霧濃度值contorl_beep(); // 控制蜂鳴器disp_line1(); // 在液晶屏上顯示第一行disp_line2(); // 在液晶屏上顯示第二行send_computer();}keyvalue = get_key(); // 獲取按鍵值if (keyvalue) // 如果有按鍵按下{deal_key(); // 處理按鍵disp_line2(); // 在液晶屏上顯示第二行}}
}unsigned char revchar = 0; // 定義一個無符號字符變量,初始值為0,用于保存接收到的字符
unsigned char revchar_openflag = 0; // 定義一個無符號字符變量,初始值為0,用于標志接收到的字符是否為有效數據
unsigned char revchar_cnt = 0; // 定義一個無符號字符變量,初始值為0,用于計數接收到的有效數據個數
unsigned char revchar_buffer[20]; // 定義一個無符號字符數組,長度為20,用于存儲接收到的有效數據#pragma vector=USCI_A0_VECTOR // 定義中斷函數,當 USCI_A0_VECTOR 中斷發生時,執行以下函數
__interrupt void USCI_A0_ISR(void)
{switch (__even_in_range(UCA0IV, 4))// 獲取 USCI_A0_VECTOR 中斷的狀態{case 0: // Vector 0 - no interrupt,無中斷狀態break;case 2: // Vector 2 - RXIFG,接收到數據的中斷狀態revchar = UCA0RXBUF; // 讀取 USCI_A0_VECTOR 的接收緩沖區數據到變量 revcharif (revchar_openflag) // 如果接收到的字符是有效數據{//S889912345 // 檢查接收到的數據是否符合特定的格式,如S889912345if ((revchar >= '0') && (revchar <= '9')) // 如果接收到的數據是數字字符{revchar_buffer[revchar_cnt] = revchar - '0'; // 把接收到的數字字符轉化為對應的數字存入 revchar_buffer 數組中revchar_cnt++; // 計數器加1if (revchar_cnt >= 9) // 如果接收到的數字字符數量達到特定的數量{shidu_baojing = revchar_buffer[0] * 100+ revchar_buffer[1] * 10; // 計算濕度報警值wendu_baojing = revchar_buffer[2] * 100+ revchar_buffer[3] * 10; // 計算溫度報警值yanwu_baojing = revchar_buffer[4] * 10000+ revchar_buffer[5] * 1000 + revchar_buffer[6] * 100+ revchar_buffer[7] * 10 + revchar_buffer[8]; // 計算煙霧報警值revchar_openflag = 0; // 清除接收標志revchar_cnt = 0; // 清除計數器}}else // 如果接收到的字符不是數字字符{revchar_openflag = 0; // 清除接收標志revchar_cnt = 0; // 清除計數器}}if (revchar == 'S'){revchar_openflag = 1;revchar_cnt = 0;}break;case 4:break; // Vector 4 - TXIFGdefault:break;}
}
全部程序
https://docs.qq.com/sheet/DUEdqZ2lmbmR6UVdU?tab=BB08J2