利用STM32G030实现除湿器
1、项目介绍
1.1 除湿器项目设计说明
功能概述:
功能要求:
设备自检功能:
设备上电自检(检查传感器采集是否正常, DHT11有存在响应, 可以自检使用, 有电池电压检测,可以判断电压是否正常)自检通过后,由串口打印设备状态信息。
自动控制功能:
进入自动控制模式, LCD显示温湿度信息以及电池电压 。与上位机通信( 串口助手), 每2s发送设备状态信息到上位机 。
阈值设置功能:
可以通过五向按键选择并调整温湿度的阈值大小。
可以通过上位机发送命令设定温湿度的阈值大小。
2、STM32cubeMX配置
配置的所有东西展示:
2.1 LCD显示屏
需要是GPIO_output模式
给引脚添加标签
输出速度为高电平
2.2 UART串口
2.3 RCC时钟
2.4 灯的引脚
2.5 ADC
PA0采集电源电压值,PA1采集五行按键不同按键按下时的电压
再把五行按键按下时,数据引脚设置为外部中断
2.6 温湿度传感器数据输入输出口
2.7 DMA
2.8 NVIC打开中断
3、代码
main函数中实现开机时,显示开机画面
Lcd_Init();
//显示欢迎界面
Lcd_Clear(0xffff);
for(int wi=128;wi>-60;wi--)
{
Gui_DrawFont_1616(wi,60,BLACK,WHITE,openword,4);
}
//显示图片
showimage(gImage_xiaokeai);
HAL_Delay(2000);
Lcd_Clear(0xF800);
2)main函数中,显示设置的初始阈值与电源电压与温湿度
FJ代表风机的状态。ZH代表制热板,ZL代表制冷。
F代表:关
T代表:开
//高温阈值显示
//printf("tempHthres=%d\n",tempHthres);
Gui_DrawFont_1616(10,58,BLUE,RED,tempHthresbuf,5);
Gui_DrawFont_GBK16(90,58,BLUE,RED,tempHthresb);
//低温阈值显示
Gui_DrawFont_1616(10,74,BLUE,RED,tempLthresbuf,5);
Gui_DrawFont_GBK16(90,74,BLUE,RED,tempLthresb);
//湿度阈值显示
Gui_DrawFont_1616(10,90,BLUE,RED,humiHthresbuf,5);
Gui_DrawFont_GBK16(90,90,BLUE,RED,humiHthresb);
//风机制冷制热片LCD显示
uint8_t fc='F';
sprintf(feijibuf,"FJ:%c ",fc);
Gui_DrawFont_GBK16(10,106,BLUE,RED,feijibuf);
uint8_t hc='F';
sprintf(zhirebuf,"ZH:%c",hc);
Gui_DrawFont_GBK16(50,106,BLUE,RED,zhirebuf);
uint8_t lc='F';
sprintf(zhilengbuf,"ZL:%c",fc);
Gui_DrawFont_GBK16(90,106,BLUE,RED,zhilengbuf);
3)打开串口1空闲不定长接收中断
//打开串口1空闲中断
HAL_UART_Receive_DMA(&huart1,interruptbuf,sizeof(interruptbuf));
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
4)初始化时检测DHT11模块是否存在
FS_DHT11_Init();
DHT11_Rst();
if(FS_DHT11_Init()==0)
printf("dht11正常");
else
printf("dht11不存在");
5)main函数while(1)循环中每间隔2s循环获取电压值
//获取按键与电压值
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)buf,2);
ADC转换完成后,回调的函数中
先停止DMA搬运,把采集到的电压值转化成对应格式传输到串口,在电脑端串口助手中打印。并同时在LCD上显示。想通过Printf()函数发送给串口,需要重写fputc函数。
int fputc(int ch,FILE *p)
{
while(!(USART1->ISR&1<<7));
USART1->TDR=ch;
return ch;
}
HAL_ADC_Stop_DMA(&hadc1);
//电压
buf[0]=buf[0]*3000/4096/1000*2;
float floatbuf=(float)buf[0]; //转化成浮点型
char volt[12]={0};
sprintf(volt,"%1.2fV",floatbuf); //转换成字符串
printf("电压=%1.1f\n",floatbuf);
Gui_DrawFont_1616(10,10,BLUE,RED,volbuf,3);
Gui_DrawFont_GBK16(48,10,BLUE,RED,(uint8_t *)volt);
6)五行按键按下时,触发按键中断PA8引脚的EXIT8
//按键中断
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin==GPIO_PIN_8)
{
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)buf,2);
flag=1;
}
}
flag标志着是否发生按键中断,当按键中断时,标志位置1
//ADC转换完成,并DMA取完数据触发的中断函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
HAL_ADC_Stop_DMA(&hadc1);
//电压
buf[0]=buf[0]*3000/4096/1000*2;
float floatbuf=(float)buf[0]; //转化成浮点型
char volt[12]={0};
sprintf(volt,"%1.2fV",floatbuf); //转换成字符串
printf("电压=%1.1f\n",floatbuf);
Gui_DrawFont_1616(10,10,BLUE,RED,volbuf,3);
Gui_DrawFont_GBK16(48,10,BLUE,RED,(uint8_t *)volt);
//printf("key=%d\n",buf[1]);
//上方向键调高温阈值,下方向键调低温阈值,左方向键调湿度阈值
if(flag)
{
printf("flag=%d\n",flag);
if(buf[1]<2400&&buf[1]>2100)
{
tempHthres--;
if(tempHthres<26)
tempHthres=46;
sprintf(tempHthresb,"%d",tempHthres);
Gui_DrawFont_GBK16(90,58,BLACK,RED,tempHthresb);
}
if(buf[1]<900&&buf[1]>500)
{
tempLthres--;
if(tempLthres<18)
tempLthres=32;
sprintf(tempLthresb,"%d",tempLthres);
Gui_DrawFont_GBK16(90,74,BLACK,RED,tempLthresb);
}
if(buf[1]<1800&&buf[1]>1500)
{
humiHthres--;
if(humiHthres<53)
humiHthres=68;
sprintf(humiHthresb,"%d",humiHthres);
Gui_DrawFont_GBK16(90,90,BLACK,RED,humiHthresb);
}
if(buf[1]<2900&&buf[1]>2500)
{
Gui_DrawFont_GBK16(90,58,BLUE,RED,tempHthresb);
Gui_DrawFont_GBK16(90,74,BLUE,RED,tempLthresb);
Gui_DrawFont_GBK16(90,90,BLUE,RED,humiHthresb);
}
flag=0;
}
}
当flag=1是,说明有按键中断,需要通过按键调整阈值。
采集到按键电压范围在2100到2400之间时,说明上方向按键被按下,修改高温阈值
采集到按键电压范围在500到900之间时,说明下方向按键被按下,修改低温阈值
采集到按键电压范围在1500到1800之间时,说明左方向按键被按下,修改湿度阈值
采集到按键电压范围在2500到2900之间时,说明中间方向按键被按下,确认修改阈值
处理完成后重新把flag标志置零
7)温湿度
main函数while(1)循环中,每间隔2s采集一次温湿度数据
//获取温湿度
DHT11_Read_Data(&humiH,&humiL,&tempH,&tempL);
temp = tempH + tempL*0.1;
printf("温度 = %.2fC 湿度 = %d%%",temp,humiH);
//温度显示在LCD
char tempb[10]={0};
sprintf(tempb,"%.2f",temp);
Gui_DrawFont_1616(10,26,BLUE,RED,tempbuf,3);
Gui_DrawFont_GBK16(48,26,BLUE,RED,(uint8_t *)tempb);
//湿度显示在LCD
char hum[6]={0};
sprintf(hum,"%hu%%",humiH);
Gui_DrawFont_1616(10,42,BLUE,RED,humiditybuf,3);
Gui_DrawFont_GBK16(48,42,BLUE,RED,(uint8_t *)hum);
HAL_Delay(2000);
dht11.c中的代码见下面详细的总代码
8)判断采集到的温湿度与设定的阈值之间的关系,执行相应的逻辑处理
main函数while(1)循环中,在采集完成后判断
高于高温阈值,绿灯亮,表示制冷片开启。并在LCD上显示ZL:T。表示制冷片开启
低于低温阈值,黄灯亮,表示加热片开启,并在LCD上显示ZH:T。表示制热片开启
当采集到的湿度大于设定的湿度阈值时,蓝灯亮,表示除湿器开启,并在LCD上显示FJ:T.表示除湿器开启
当加热片工作过程中,如果温度大于高温阈值+5,停止加热片
当制冷片工作过程中,如果温度小于低温阈值-5,停止制冷片
当除湿器工作过程中,湿度小于设定的湿度阈值时,停止除湿器
//高温绿灯亮,低温黄灯亮,湿度高蓝灯亮
if(temp>tempHthres)
{
HAL_GPIO_WritePin(GREEN_GPIO_Port,GREEN_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GREEN_GPIO_Port,YELO_Pin,GPIO_PIN_SET);
temp-=1; //模拟降温过程
//制冷LCD显示
lc='T';
sprintf(zhilengbuf,"ZL:%c",lc);
Gui_DrawFont_GBK16(90,106,BLUE,RED,zhilengbuf);
}
if(temp<tempLthres)
{
HAL_GPIO_WritePin(GREEN_GPIO_Port,YELO_Pin,GPIO_PIN_RESET);
//HAL_GPIO_WritePin(GREEN_GPIO_Port,GREEN_Pin,GPIO_PIN_SET);
temp+=1; //模拟升温过程
//制热LCD显示
hc='T';
sprintf(zhirebuf,"ZH:%c",hc);
Gui_DrawFont_GBK16(50,106,BLUE,RED,zhirebuf);
}
if(humiH>humiHthres)
{
HAL_GPIO_WritePin(GREEN_GPIO_Port,BLUE_Pin,GPIO_PIN_RESET);
humiH-=1; //模拟除湿过程
//风机状态LCD显示
fc='T';
sprintf(feijibuf,"FJ:%c ",fc);
Gui_DrawFont_GBK16(10,106,BLUE,RED,feijibuf);
}
//如果在正常范围内关闭所有的灯
if(temp<tempHthres&&temp>tempLthres)
{
HAL_GPIO_WritePin(GREEN_GPIO_Port,YELO_Pin|GREEN_Pin,GPIO_PIN_SET);
}
//温度大于高温阈值+5,关闭制热
if(temp>tempHthres+5)
{
HAL_GPIO_WritePin(GREEN_GPIO_Port,YELO_Pin,GPIO_PIN_SET);
hc='F';
sprintf(zhirebuf,"ZH:%c",hc);
Gui_DrawFont_GBK16(50,106,BLUE,RED,zhirebuf);
}
//温度低于低温阈值-5,关闭制冷
if(temp<tempLthres-5)
{
HAL_GPIO_WritePin(GREEN_GPIO_Port,GREEN_Pin,GPIO_PIN_SET);
lc='F';
sprintf(zhilengbuf,"ZL:%c",fc);
Gui_DrawFont_GBK16(90,106,BLUE,RED,zhilengbuf);
}
//低于除湿阈值,关闭风机
if(humiH<humiHthres)
{
HAL_GPIO_WritePin(GREEN_GPIO_Port,BLUE_Pin,GPIO_PIN_SET);
fc='F';
sprintf(feijibuf,"FJ:%c ",fc);
Gui_DrawFont_GBK16(10,106,BLUE,RED,feijibuf);
}
9)通过串口修改设定的温湿度阈值
当发送数据过程中,发送完成后,会检测一个字节周期内没有数据发送,会触发串口空闲中断,调到串口空闲中断服务程序进行相应的逻辑处理
串口中断服务程序所在的.C文件中需要添加的头文件
#include <string.h>
#include <stdio.h>
#include "lcd.h"
需要引入main中定义的变量
extern uint8_t tempHthres; //高温阈值
extern uint8_t tempLthres; //低温阈值
extern uint8_t humiHthres; //湿度阈值
extern uint8_t tempHthresb[6];
extern uint8_t tempLthresb[6];
extern uint8_t humiHthresb[6];
extern uint8_t interruptbuf[256];//串口接收到的数据
uint8_t cmdbuf[64]; //命令
uint8_t valuebuf[256]; //数值
extern uint8_t wifibuf[256];//串口2接收到的数据
进入中断服务程序后,先判断根据空闲中断标志位是不是空闲中断,如果是,
1)清除空闲标志位
2)停止DMA搬运
3)调用自定义的数据处理函数对接收到的数据进行处理
4)重新开启DMA接收
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_IDLE);
HAL_UART_DMAStop(&huart1);
recivemag(); //处理接受到的数据(命令和要设置的值)
uint8_t len=sizeof(interruptbuf)-hdma_usart1_rx.Instance->CNDTR;
// HAL_UART_Transmit_DMA(&huart1,interruptbuf,len);
HAL_UART_Receive_DMA(&huart1,interruptbuf,sizeof(interruptbuf));
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
命令
修改高温阈值
th=要修改的数值
修改低温阈值
tl=要修改的数值
修改湿度阈值
hu=要修改的数值
void recivemag()函数
先根据间隔符;把“=”前面的命令取出,在把等号后面的数值取出。
uint16_t chartoint()函数
因为接受到的是字符串,所以我们需要把接受到的数值进行处理,转化成int型的变量
void setHthresb()函数
调用chartoint()函数,获取转化后的数值,根据命令判断是那个阈值需要修改,修改相应的数值,并对LCD上显示的阈值更新。
串口1
//温湿度数值字符串转整形
uint16_t chartoint()
{
uint8_t *valuep=valuebuf;
uint16_t sum=0;
while(*valuep!='\0')
{
sum=sum*10+(*valuep-48);
valuep++;
}
return sum;
}
//送到LCD修改显示阈值
void setHthresb()
{
uint16_t value=chartoint();
if(strcmp(cmdbuf,"th")==0)
{
tempHthres=value;
sprintf(tempHthresb,"%d",tempHthres);
//高温阈值显示
Gui_DrawFont_GBK16(90,58,BLUE,RED,tempHthresb);
printf("高温阈值:%s",valuebuf);
}
else if(strcmp(cmdbuf,"tl")==0)
{
tempLthres=value;
sprintf(tempLthresb,"%d",tempLthres);
//低温阈值显示
Gui_DrawFont_GBK16(90,74,BLUE,RED,tempLthresb);
printf("低温阈值:%s",valuebuf);
}
else if(strcmp(cmdbuf,"hu")==0)
{
humiHthres=value;
sprintf(humiHthresb,"%d",humiHthres);
//湿度阈值显示
Gui_DrawFont_GBK16(90,90,BLUE,RED,humiHthresb);
printf("湿度阈值:%s",valuebuf);
}
}
//处理接受到的数据
void recivemag()
{
uint8_t *p=interruptbuf;
uint8_t i=0;
while(*p!='\0')
{
while(*p!='=')
{
cmdbuf[i++]=*p;
p++;
}
cmdbuf[i]='\0';
i=0;
p++;
while(*p!='\0')
{
valuebuf[i++]=*p;
p++;
}
valuebuf[i]='\0';
setHthresb(); //调用设置LCD显示阈值的函数
}
}
10) 需要图片取模软件和中文字符取模软件取出16进制的数组
软件见下方的项目代码链接。
//电压文字
const char volbuf[][32]=
{
{0x01,0x00,0x01,0x00,0x01,0x00,0x3F,0xF8,0x21,0x08,0x21,0x08,0x21,0x08,0x3F,0xF8,0x21,0x08,0x21,0x08,0x21,0x08,0x3F,0xF8,0x21,0x0A,0x01,0x02,0x01,0x02,0x00,0xFE},/*"电",0*/
{0x00,0x00,0x3F,0xFE,0x20,0x00,0x20,0x80,0x20,0x80,0x20,0x80,0x20,0x80,0x2F,0xFC,0x20,0x80,0x20,0x80,0x20,0x90,0x20,0x88,0x20,0x88,0x40,0x80,0x5F,0xFE,0x80,0x00},/*"压",1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*":",2*/
};
//温度
const char tempbuf[][32]=
{
{0x00,0x00,0x23,0xF8,0x12,0x08,0x12,0x08,0x83,0xF8,0x42,0x08,0x42,0x08,0x13,0xF8,0x10,0x00,0x27,0xFC,0xE4,0xA4,0x24,0xA4,0x24,0xA4,0x24,0xA4,0x2F,0xFE,0x00,0x00},/*"温",0*/
{0x01,0x00,0x00,0x80,0x3F,0xFE,0x22,0x20,0x22,0x20,0x3F,0xFC,0x22,0x20,0x22,0x20,0x23,0xE0,0x20,0x00,0x2F,0xF0,0x24,0x10,0x42,0x20,0x41,0xC0,0x86,0x30,0x38,0x0E},/*"度",1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*":",2*/
};
//湿度
const char humiditybuf[][32]=
{
{0x00,0x00,0x27,0xF8,0x14,0x08,0x14,0x08,0x87,0xF8,0x44,0x08,0x44,0x08,0x17,0xF8,0x11,0x20,0x21,0x20,0xE9,0x24,0x25,0x28,0x23,0x30,0x21,0x20,0x2F,0xFE,0x00,0x00},/*"湿",0*/
{0x01,0x00,0x00,0x80,0x3F,0xFE,0x22,0x20,0x22,0x20,0x3F,0xFC,0x22,0x20,0x22,0x20,0x23,0xE0,0x20,0x00,0x2F,0xF0,0x24,0x10,0x42,0x20,0x41,0xC0,0x86,0x30,0x38,0x0E},/*"度",1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*":",2*/
};
//低温阈值
const char tempLthresbuf[][32]=
{
{0x08,0x08,0x08,0x3C,0x0B,0xE0,0x12,0x20,0x12,0x20,0x32,0x20,0x32,0x20,0x53,0xFE,0x92,0x20,0x12,0x10,0x12,0x10,0x12,0x12,0x12,0x0A,0x12,0x8A,0x13,0x26,0x12,0x12},/*"低",0*/
{0x00,0x00,0x23,0xF8,0x12,0x08,0x12,0x08,0x83,0xF8,0x42,0x08,0x42,0x08,0x13,0xF8,0x10,0x00,0x27,0xFC,0xE4,0xA4,0x24,0xA4,0x24,0xA4,0x24,0xA4,0x2F,0xFE,0x00,0x00},/*"温",1*/
{0x20,0x00,0x17,0xFC,0x00,0x84,0x40,0xA4,0x40,0x94,0x5F,0xF4,0x40,0x84,0x4E,0xA4,0x4A,0xA4,0x4E,0xA4,0x40,0xC4,0x46,0x54,0x58,0xB4,0x41,0x14,0x42,0x04,0x40,0x0C},/*"阈",2*/
{0x08,0x40,0x08,0x40,0x0F,0xFC,0x10,0x40,0x10,0x40,0x33,0xF8,0x32,0x08,0x53,0xF8,0x92,0x08,0x13,0xF8,0x12,0x08,0x13,0xF8,0x12,0x08,0x12,0x08,0x1F,0xFE,0x10,0x00},/*"值",3*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*":",4*/
};
//高温阈值
const char tempHthresbuf[][32]=
{
{0x02,0x00,0x01,0x00,0xFF,0xFE,0x00,0x00,0x0F,0xE0,0x08,0x20,0x08,0x20,0x0F,0xE0,0x00,0x00,0x7F,0xFC,0x40,0x04,0x4F,0xE4,0x48,0x24,0x48,0x24,0x4F,0xE4,0x40,0x0C},/*"高",0*/
{0x00,0x00,0x23,0xF8,0x12,0x08,0x12,0x08,0x83,0xF8,0x42,0x08,0x42,0x08,0x13,0xF8,0x10,0x00,0x27,0xFC,0xE4,0xA4,0x24,0xA4,0x24,0xA4,0x24,0xA4,0x2F,0xFE,0x00,0x00},/*"温",1*/
{0x20,0x00,0x17,0xFC,0x00,0x84,0x40,0xA4,0x40,0x94,0x5F,0xF4,0x40,0x84,0x4E,0xA4,0x4A,0xA4,0x4E,0xA4,0x40,0xC4,0x46,0x54,0x58,0xB4,0x41,0x14,0x42,0x04,0x40,0x0C},/*"阈",2*/
{0x08,0x40,0x08,0x40,0x0F,0xFC,0x10,0x40,0x10,0x40,0x33,0xF8,0x32,0x08,0x53,0xF8,0x92,0x08,0x13,0xF8,0x12,0x08,0x13,0xF8,0x12,0x08,0x12,0x08,0x1F,0xFE,0x10,0x00},/*"值",3*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*":",4*/
};
//湿度阈值
const char humiHthresbuf[][32]=
{
{0x00,0x00,0x27,0xF8,0x14,0x08,0x14,0x08,0x87,0xF8,0x44,0x08,0x44,0x08,0x17,0xF8,0x11,0x20,0x21,0x20,0xE9,0x24,0x25,0x28,0x23,0x30,0x21,0x20,0x2F,0xFE,0x00,0x00},/*"湿",0*/
{0x01,0x00,0x00,0x80,0x3F,0xFE,0x22,0x20,0x22,0x20,0x3F,0xFC,0x22,0x20,0x22,0x20,0x23,0xE0,0x20,0x00,0x2F,0xF0,0x24,0x10,0x42,0x20,0x41,0xC0,0x86,0x30,0x38,0x0E},/*"度",1*/
{0x20,0x00,0x17,0xFC,0x00,0x84,0x40,0xA4,0x40,0x94,0x5F,0xF4,0x40,0x84,0x4E,0xA4,0x4A,0xA4,0x4E,0xA4,0x40,0xC4,0x46,0x54,0x58,0xB4,0x41,0x14,0x42,0x04,0x40,0x0C},/*"阈",2*/
{0x08,0x40,0x08,0x40,0x0F,0xFC,0x10,0x40,0x10,0x40,0x33,0xF8,0x32,0x08,0x53,0xF8,0x92,0x08,0x13,0xF8,0x12,0x08,0x13,0xF8,0x12,0x08,0x12,0x08,0x1F,0xFE,0x10,0x00},/*"值",3*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*":",4*/
};
全部代码
main.c
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "lcd.h"
#include <string.h>
#include "dht11.h"
#include "xiaokeai.h"
static uint32_t fac_us = 0; //us延时倍乘数
void delay_init(uint8_t SYSCLK)
{
fac_us = SYSCLK;
}
void delay_us(uint32_t nus)//100 6800
{
uint32_t ticks;
uint32_t told, tnow, tcnt = 0;
uint32_t reload = SysTick->LOAD; //LOAD的值
ticks = nus * fac_us; //需要的节拍数
told = SysTick->VAL; // 24 刚进入时的计数器值
while (1)
{
tnow = SysTick->VAL;//22 20 0
if (tnow != told)
{
if (tnow < told)
tcnt += told - tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了.
else
tcnt += reload - tnow + told;
told = tnow;
if (tcnt >= ticks)
break; //时间超过/等于要延迟的时间,则退出.
}
};
}
void delay_ms(uint16_t nms)
{
uint32_t i;
for (i = 0; i < nms; i++)
delay_us(1000);
}
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
uint8_t humiH;
uint8_t humiL;
uint8_t tempH;
uint8_t tempL;
uint8_t tempHthres=30; //高温阈值
uint8_t tempLthres=26; //低温阈值
uint8_t humiHthres=60; //湿度阈值
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
uint16_t buf[2]; //电压和按钮
//电压文字
const char volbuf[][32]=
{
{0x01,0x00,0x01,0x00,0x01,0x00,0x3F,0xF8,0x21,0x08,0x21,0x08,0x21,0x08,0x3F,0xF8,0x21,0x08,0x21,0x08,0x21,0x08,0x3F,0xF8,0x21,0x0A,0x01,0x02,0x01,0x02,0x00,0xFE},/*"电",0*/
{0x00,0x00,0x3F,0xFE,0x20,0x00,0x20,0x80,0x20,0x80,0x20,0x80,0x20,0x80,0x2F,0xFC,0x20,0x80,0x20,0x80,0x20,0x90,0x20,0x88,0x20,0x88,0x40,0x80,0x5F,0xFE,0x80,0x00},/*"压",1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*":",2*/
};
//温度
const char tempbuf[][32]=
{
{0x00,0x00,0x23,0xF8,0x12,0x08,0x12,0x08,0x83,0xF8,0x42,0x08,0x42,0x08,0x13,0xF8,0x10,0x00,0x27,0xFC,0xE4,0xA4,0x24,0xA4,0x24,0xA4,0x24,0xA4,0x2F,0xFE,0x00,0x00},/*"温",0*/
{0x01,0x00,0x00,0x80,0x3F,0xFE,0x22,0x20,0x22,0x20,0x3F,0xFC,0x22,0x20,0x22,0x20,0x23,0xE0,0x20,0x00,0x2F,0xF0,0x24,0x10,0x42,0x20,0x41,0xC0,0x86,0x30,0x38,0x0E},/*"度",1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*":",2*/
};
//湿度
const char humiditybuf[][32]=
{
{0x00,0x00,0x27,0xF8,0x14,0x08,0x14,0x08,0x87,0xF8,0x44,0x08,0x44,0x08,0x17,0xF8,0x11,0x20,0x21,0x20,0xE9,0x24,0x25,0x28,0x23,0x30,0x21,0x20,0x2F,0xFE,0x00,0x00},/*"湿",0*/
{0x01,0x00,0x00,0x80,0x3F,0xFE,0x22,0x20,0x22,0x20,0x3F,0xFC,0x22,0x20,0x22,0x20,0x23,0xE0,0x20,0x00,0x2F,0xF0,0x24,0x10,0x42,0x20,0x41,0xC0,0x86,0x30,0x38,0x0E},/*"度",1*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*":",2*/
};
//低温阈值
const char tempLthresbuf[][32]=
{
{0x08,0x08,0x08,0x3C,0x0B,0xE0,0x12,0x20,0x12,0x20,0x32,0x20,0x32,0x20,0x53,0xFE,0x92,0x20,0x12,0x10,0x12,0x10,0x12,0x12,0x12,0x0A,0x12,0x8A,0x13,0x26,0x12,0x12},/*"低",0*/
{0x00,0x00,0x23,0xF8,0x12,0x08,0x12,0x08,0x83,0xF8,0x42,0x08,0x42,0x08,0x13,0xF8,0x10,0x00,0x27,0xFC,0xE4,0xA4,0x24,0xA4,0x24,0xA4,0x24,0xA4,0x2F,0xFE,0x00,0x00},/*"温",1*/
{0x20,0x00,0x17,0xFC,0x00,0x84,0x40,0xA4,0x40,0x94,0x5F,0xF4,0x40,0x84,0x4E,0xA4,0x4A,0xA4,0x4E,0xA4,0x40,0xC4,0x46,0x54,0x58,0xB4,0x41,0x14,0x42,0x04,0x40,0x0C},/*"阈",2*/
{0x08,0x40,0x08,0x40,0x0F,0xFC,0x10,0x40,0x10,0x40,0x33,0xF8,0x32,0x08,0x53,0xF8,0x92,0x08,0x13,0xF8,0x12,0x08,0x13,0xF8,0x12,0x08,0x12,0x08,0x1F,0xFE,0x10,0x00},/*"值",3*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*":",4*/
};
//高温阈值
const char tempHthresbuf[][32]=
{
{0x02,0x00,0x01,0x00,0xFF,0xFE,0x00,0x00,0x0F,0xE0,0x08,0x20,0x08,0x20,0x0F,0xE0,0x00,0x00,0x7F,0xFC,0x40,0x04,0x4F,0xE4,0x48,0x24,0x48,0x24,0x4F,0xE4,0x40,0x0C},/*"高",0*/
{0x00,0x00,0x23,0xF8,0x12,0x08,0x12,0x08,0x83,0xF8,0x42,0x08,0x42,0x08,0x13,0xF8,0x10,0x00,0x27,0xFC,0xE4,0xA4,0x24,0xA4,0x24,0xA4,0x24,0xA4,0x2F,0xFE,0x00,0x00},/*"温",1*/
{0x20,0x00,0x17,0xFC,0x00,0x84,0x40,0xA4,0x40,0x94,0x5F,0xF4,0x40,0x84,0x4E,0xA4,0x4A,0xA4,0x4E,0xA4,0x40,0xC4,0x46,0x54,0x58,0xB4,0x41,0x14,0x42,0x04,0x40,0x0C},/*"阈",2*/
{0x08,0x40,0x08,0x40,0x0F,0xFC,0x10,0x40,0x10,0x40,0x33,0xF8,0x32,0x08,0x53,0xF8,0x92,0x08,0x13,0xF8,0x12,0x08,0x13,0xF8,0x12,0x08,0x12,0x08,0x1F,0xFE,0x10,0x00},/*"值",3*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*":",4*/
};
//湿度阈值
const char humiHthresbuf[][32]=
{
{0x00,0x00,0x27,0xF8,0x14,0x08,0x14,0x08,0x87,0xF8,0x44,0x08,0x44,0x08,0x17,0xF8,0x11,0x20,0x21,0x20,0xE9,0x24,0x25,0x28,0x23,0x30,0x21,0x20,0x2F,0xFE,0x00,0x00},/*"湿",0*/
{0x01,0x00,0x00,0x80,0x3F,0xFE,0x22,0x20,0x22,0x20,0x3F,0xFC,0x22,0x20,0x22,0x20,0x23,0xE0,0x20,0x00,0x2F,0xF0,0x24,0x10,0x42,0x20,0x41,0xC0,0x86,0x30,0x38,0x0E},/*"度",1*/
{0x20,0x00,0x17,0xFC,0x00,0x84,0x40,0xA4,0x40,0x94,0x5F,0xF4,0x40,0x84,0x4E,0xA4,0x4A,0xA4,0x4E,0xA4,0x40,0xC4,0x46,0x54,0x58,0xB4,0x41,0x14,0x42,0x04,0x40,0x0C},/*"阈",2*/
{0x08,0x40,0x08,0x40,0x0F,0xFC,0x10,0x40,0x10,0x40,0x33,0xF8,0x32,0x08,0x53,0xF8,0x92,0x08,0x13,0xF8,0x12,0x08,0x13,0xF8,0x12,0x08,0x12,0x08,0x1F,0xFE,0x10,0x00},/*"值",3*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00},/*":",4*/
};
uint8_t tempHthresb[6];
uint8_t tempLthresb[6];
uint8_t humiHthresb[6];
uint8_t feijibuf[6];
uint8_t zhilengbuf[6];
uint8_t zhirebuf[6];
uint8_t flag=0; //按键中断触发标志
uint8_t interruptbuf[256];//串口1接收到的数据
uint8_t wifibuf[256];//串口2接收到的数据
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_USART1_UART_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
Lcd_Init();
//显示欢迎界面
Lcd_Clear(0xffff);
for(int wi=128;wi>-60;wi--)
{
Gui_DrawFont_1616(wi,60,BLACK,WHITE,openword,4);
}
//显示图片
showimage(gImage_xiaokeai);
HAL_Delay(2000);
Lcd_Clear(0xF800);
//打开串口1空闲中断
HAL_UART_Receive_DMA(&huart1,interruptbuf,sizeof(interruptbuf));
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
//打开串口2空闲中断(wifi)
HAL_UART_Receive_DMA(&huart2,wifibuf,sizeof(wifibuf));
__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);
delay_init(64);
FS_DHT11_Init();
DHT11_Rst();
if(FS_DHT11_Init()==0)
printf("dht11正常");
else
printf("dht11不存在");
float temp;
//将温湿度阈值转化为字符串
sprintf(tempHthresb,"%d",tempHthres);
sprintf(tempLthresb,"%d",tempLthres);
sprintf(humiHthresb,"%d",humiHthres);
//高温阈值显示
//printf("tempHthres=%d\n",tempHthres);
Gui_DrawFont_1616(10,58,BLUE,RED,tempHthresbuf,5);
Gui_DrawFont_GBK16(90,58,BLUE,RED,tempHthresb);
//低温阈值显示
Gui_DrawFont_1616(10,74,BLUE,RED,tempLthresbuf,5);
Gui_DrawFont_GBK16(90,74,BLUE,RED,tempLthresb);
//湿度阈值显示
Gui_DrawFont_1616(10,90,BLUE,RED,humiHthresbuf,5);
Gui_DrawFont_GBK16(90,90,BLUE,RED,humiHthresb);
//风机制冷制热片LCD显示
uint8_t fc='F';
sprintf(feijibuf,"FJ:%c ",fc);
Gui_DrawFont_GBK16(10,106,BLUE,RED,feijibuf);
uint8_t hc='F';
sprintf(zhirebuf,"ZH:%c",hc);
Gui_DrawFont_GBK16(50,106,BLUE,RED,zhirebuf);
uint8_t lc='F';
sprintf(zhilengbuf,"ZL:%c",fc);
Gui_DrawFont_GBK16(90,106,BLUE,RED,zhilengbuf);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//获取按键与电压值
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)buf,2);
//获取温湿度
DHT11_Read_Data(&humiH,&humiL,&tempH,&tempL);
temp = tempH + tempL*0.1;
printf("温度 = %.2fC 湿度 = %d%%",temp,humiH);
//温度显示在LCD
char tempb[10]={0};
sprintf(tempb,"%.2f",temp);
Gui_DrawFont_1616(10,26,BLUE,RED,tempbuf,3);
Gui_DrawFont_GBK16(48,26,BLUE,RED,(uint8_t *)tempb);
//湿度显示在LCD
char hum[6]={0};
sprintf(hum,"%hu%%",humiH);
Gui_DrawFont_1616(10,42,BLUE,RED,humiditybuf,3);
Gui_DrawFont_GBK16(48,42,BLUE,RED,(uint8_t *)hum);
HAL_Delay(2000);
//高温绿灯亮,低温黄灯亮,湿度高蓝灯亮
if(temp>tempHthres)
{
HAL_GPIO_WritePin(GREEN_GPIO_Port,GREEN_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GREEN_GPIO_Port,YELO_Pin,GPIO_PIN_SET);
temp-=1; //模拟降温过程
//制冷LCD显示
lc='T';
sprintf(zhilengbuf,"ZL:%c",lc);
Gui_DrawFont_GBK16(90,106,BLUE,RED,zhilengbuf);
}
if(temp<tempLthres)
{
HAL_GPIO_WritePin(GREEN_GPIO_Port,YELO_Pin,GPIO_PIN_RESET);
//HAL_GPIO_WritePin(GREEN_GPIO_Port,GREEN_Pin,GPIO_PIN_SET);
temp+=1; //模拟升温过程
//制热LCD显示
hc='T';
sprintf(zhirebuf,"ZH:%c",hc);
Gui_DrawFont_GBK16(50,106,BLUE,RED,zhirebuf);
}
if(humiH>humiHthres)
{
HAL_GPIO_WritePin(GREEN_GPIO_Port,BLUE_Pin,GPIO_PIN_RESET);
humiH-=1; //模拟除湿过程
//风机状态LCD显示
fc='T';
sprintf(feijibuf,"FJ:%c ",fc);
Gui_DrawFont_GBK16(10,106,BLUE,RED,feijibuf);
}
//如果在正常范围内关闭所有的灯
if(temp<tempHthres&&temp>tempLthres)
{
HAL_GPIO_WritePin(GREEN_GPIO_Port,YELO_Pin|GREEN_Pin,GPIO_PIN_SET);
}
//温度大于高温阈值+5,关闭制热
if(temp>tempHthres+5)
{
HAL_GPIO_WritePin(GREEN_GPIO_Port,YELO_Pin,GPIO_PIN_SET);
hc='F';
sprintf(zhirebuf,"ZH:%c",hc);
Gui_DrawFont_GBK16(50,106,BLUE,RED,zhirebuf);
}
//温度低于低温阈值-5,关闭制冷
if(temp<tempLthres-5)
{
HAL_GPIO_WritePin(GREEN_GPIO_Port,GREEN_Pin,GPIO_PIN_SET);
lc='F';
sprintf(zhilengbuf,"ZL:%c",fc);
Gui_DrawFont_GBK16(90,106,BLUE,RED,zhilengbuf);
}
//低于除湿阈值,关闭风机
if(humiH<humiHthres)
{
HAL_GPIO_WritePin(GREEN_GPIO_Port,BLUE_Pin,GPIO_PIN_SET);
fc='F';
sprintf(feijibuf,"FJ:%c ",fc);
Gui_DrawFont_GBK16(10,106,BLUE,RED,feijibuf);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV1;
RCC_OscInitStruct.PLL.PLLN = 16;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
/** Initializes the peripherals clocks
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_ADC;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
PeriphClkInit.AdcClockSelection = RCC_ADCCLKSOURCE_SYSCLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
int fputc(int ch,FILE *p)
{
while(!(USART1->ISR&1<<7));
USART1->TDR=ch;
return ch;
}
//按键中断
void HAL_GPIO_EXTI_Rising_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin==GPIO_PIN_8)
{
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)buf,2);
flag=1;
}
}
//ADC转换完成,并DMA取完数据触发的中断函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
HAL_ADC_Stop_DMA(&hadc1);
//电压
buf[0]=buf[0]*3000/4096/1000*2;
float floatbuf=(float)buf[0]; //转化成浮点型
char volt[12]={0};
sprintf(volt,"%1.2fV",floatbuf); //转换成字符串
printf("电压=%1.1f\n",floatbuf);
Gui_DrawFont_1616(10,10,BLUE,RED,volbuf,3);
Gui_DrawFont_GBK16(48,10,BLUE,RED,(uint8_t *)volt);
//printf("key=%d\n",buf[1]);
//上方向键调高温阈值,下方向键调低温阈值,左方向键调湿度阈值
if(flag)
{
printf("flag=%d\n",flag);
if(buf[1]<2400&&buf[1]>2100)
{
tempHthres--;
if(tempHthres<26)
tempHthres=46;
sprintf(tempHthresb,"%d",tempHthres);
Gui_DrawFont_GBK16(90,58,BLACK,RED,tempHthresb);
}
if(buf[1]<900&&buf[1]>500)
{
tempLthres--;
if(tempLthres<18)
tempLthres=32;
sprintf(tempLthresb,"%d",tempLthres);
Gui_DrawFont_GBK16(90,74,BLACK,RED,tempLthresb);
}
if(buf[1]<1800&&buf[1]>1500)
{
humiHthres--;
if(humiHthres<53)
humiHthres=68;
sprintf(humiHthresb,"%d",humiHthres);
Gui_DrawFont_GBK16(90,90,BLACK,RED,humiHthresb);
}
if(buf[1]<2900&&buf[1]>2500)
{
Gui_DrawFont_GBK16(90,58,BLUE,RED,tempHthresb);
Gui_DrawFont_GBK16(90,74,BLUE,RED,tempLthresb);
Gui_DrawFont_GBK16(90,90,BLUE,RED,humiHthresb);
}
flag=0;
}
}
stm32g0xx_it.c(串口中断服务程序所在的.c文件)
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
#include <string.h>
#include <stdio.h>
#include "lcd.h"
/* USER CODE END TD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
extern uint8_t tempHthres; //高温阈值
extern uint8_t tempLthres; //低温阈值
extern uint8_t humiHthres; //湿度阈值
extern uint8_t tempHthresb[6];
extern uint8_t tempLthresb[6];
extern uint8_t humiHthresb[6];
extern uint8_t interruptbuf[256];//串口接收到的数据
uint8_t cmdbuf[64]; //命令
uint8_t valuebuf[256]; //数值
extern uint8_t wifibuf[256];//串口2接收到的数据
串口1
//温湿度数值字符串转整形
uint16_t chartoint()
{
uint8_t *valuep=valuebuf;
uint16_t sum=0;
while(*valuep!='\0')
{
sum=sum*10+(*valuep-48);
valuep++;
}
return sum;
}
//送到LCD修改显示阈值
void setHthresb()
{
uint16_t value=chartoint();
if(strcmp(cmdbuf,"th")==0)
{
tempHthres=value;
sprintf(tempHthresb,"%d",tempHthres);
//高温阈值显示
Gui_DrawFont_GBK16(90,58,BLUE,RED,tempHthresb);
printf("高温阈值:%s",valuebuf);
}
else if(strcmp(cmdbuf,"tl")==0)
{
tempLthres=value;
sprintf(tempLthresb,"%d",tempLthres);
//低温阈值显示
Gui_DrawFont_GBK16(90,74,BLUE,RED,tempLthresb);
printf("低温阈值:%s",valuebuf);
}
else if(strcmp(cmdbuf,"hu")==0)
{
humiHthres=value;
sprintf(humiHthresb,"%d",humiHthres);
//湿度阈值显示
Gui_DrawFont_GBK16(90,90,BLUE,RED,humiHthresb);
printf("湿度阈值:%s",valuebuf);
}
}
//处理接受到的数据
void recivemag()
{
uint8_t *p=interruptbuf;
uint8_t i=0;
while(*p!='\0')
{
while(*p!='=')
{
cmdbuf[i++]=*p;
p++;
}
cmdbuf[i]='\0';
i=0;
p++;
while(*p!='\0')
{
valuebuf[i++]=*p;
p++;
}
valuebuf[i]='\0';
setHthresb(); //调用设置LCD显示阈值的函数
}
}
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_IDLE);
HAL_UART_DMAStop(&huart1);
recivemag(); //处理接受到的数据(命令和要设置的值)
uint8_t len=sizeof(interruptbuf)-hdma_usart1_rx.Instance->CNDTR;
// HAL_UART_Transmit_DMA(&huart1,interruptbuf,len);
HAL_UART_Receive_DMA(&huart1,interruptbuf,sizeof(interruptbuf));
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
lcd.c
#include "gpio.h"
#include "stdint.h"
#include "lcd.h"
#include "lcd_font.h"
#include <string.h>
//static uint8_t lcd_send_data = 0;
//extern void HalLcd_HW_WaitUs(uint16 i);
/*
* Initialize LCD Service
*/
void HalLcdInit(void);
//LCD Init For 1.44Inch LCD Panel with ST7735R.
void Lcd_Init(void)
{
HAL_Delay(10);
//开LCD背光
HAL_GPIO_WritePin(LCD_GPIO_Port, LCD_Pin, GPIO_PIN_SET);
Lcd_WriteIndex(0x11);
HAL_Delay(3);//Sleep exit HAL_Delay(10);
Lcd_WriteIndex(0x11);
// HAL_Delay(1000);
// HAL_Delay(1000);
// HAL_Delay(1000);
HAL_Delay(5);
Lcd_WriteIndex(0x36);
HAL_Delay(5);
Lcd_WriteIndex(0x36);//MX, MY, RGB mode
HAL_Delay(5);
Lcd_WriteData(0xC8);
HAL_Delay(5);
Lcd_WriteData(0xC8);
HAL_Delay(5);
Lcd_WriteIndex(0x3A);
HAL_Delay(5);
Lcd_WriteIndex(0x3A);//65k mode
HAL_Delay(5);
Lcd_WriteData(0x05);
HAL_Delay(5);
Lcd_WriteData(0x05);
HAL_Delay(20);
Lcd_WriteIndex(0x29);
HAL_Delay(5);
Lcd_WriteIndex(0x29);//Display on//有问题
}
//
///*
// * Write a string to the LCD
// */
//
//void HalLcdWriteString ( char *str, uint8 option);
//
///*
// * Write a value to the LCD
// */
//extern void HalLcdWriteValue ( uint32 value, const uint8 radix, uint8 option);
//
///*
// * Write a value to the LCD
// */
//extern void HalLcdWriteScreen( char *line1, char *line2 );
//
///*
// * Write a string followed by a value to the LCD
// */
//extern void HalLcdWriteStringValue( char *title, uint16 value, uint8 format, uint8 line );
//
///*
// * Write a string followed by 2 values to the LCD
// */
//extern void HalLcdWriteStringValueValue( char *title, uint16 value1, uint8 format1, uint16 value2, uint8 format2, uint8 line );
//
///*
// * Write a percentage bar to the LCD
// */
//extern void HalLcdDisplayPercentBar( char *title, uint8 value );
//
//extern void Gui_DrawFont_GBK16(uint16 x, uint16 y, uint16 fc, uint16 bc, uint8 *s);
//void Line_Dsp_single_colour(unsigned int x_start,unsigned int y_start,unsigned int x_end,unsigned int y_end,unsigned int color);
//void dsp_single_colour(int color);
void Delay_ms(int time)
{
int i,j;
for(i=0; i<time*10; i++)
{
for(j=0; j<100; j++)
{
}
}
}
void SPI_WriteData(uint8_t Data)
{
unsigned char i;
for(i=8; i>0; i--)
{
if(Data & 0x80)
{
LCD_SDA_SET; //数据输出高电平
}
else
{
LCD_SDA_CLR; //数据输出低电平
}
LCD_SCL_SET; //时钟高
LCD_SCL_CLR; //时钟低
Data <<= 1;
}
}
void LCD_WriteData_16Bit(uint16_t Data)
{
LCD_CS_CLR;
LCD_RS_SET;
SPI_WriteData(Data>>8); //写入高8位数据
SPI_WriteData(Data); //写入低8位数据
LCD_CS_SET;
}
//向液晶屏写一个8位指令
void Lcd_WriteIndex(uint8_t Index)
{
//SPI 写命令时序开始
LCD_CS_CLR;
LCD_RS_CLR; //LCD_RS_CLR
SPI_WriteData(Index);
LCD_CS_SET;
}
//向液晶屏写一个8位数据
void Lcd_WriteData(uint8_t Data)
{
LCD_CS_CLR;
LCD_RS_SET;
SPI_WriteData(Data);
LCD_CS_SET;
}
void Lcd_WriteReg(uint8_t Index,uint8_t Data)
{
LCD_CS_CLR;
Lcd_WriteIndex(Index);
Lcd_WriteData(Data);
LCD_CS_SET;
}
LCD Init For 1.44Inch LCD Panel with ST7735R.
//void Lcd_Init(void)
//{
// Lcd_WriteIndex(0x11);//Sleep exit
// HAL_Delay(120);
//
// Lcd_WriteIndex(0x36); //MX, MY, RGB mode
// Lcd_WriteData(0xC8);
//
// Lcd_WriteIndex(0x3A); //65k mode
// Lcd_WriteData(0x05);
//
// Lcd_WriteIndex(0x29);//Display on
//}
/*************************************************
函数名:LCD_Set_Region
功能:设置lcd显示区域,在此区域写点数据自动换行
入口参数:xy起点和终点
返回值:无
*************************************************/
void Lcd_SetRegion(uint16_t x_start,uint16_t y_start,uint16_t x_end,uint16_t y_end)
{
Lcd_WriteIndex(0x2a);
Lcd_WriteData(0x00);
Lcd_WriteData(x_start+2);
Lcd_WriteData(0x00);
Lcd_WriteData(x_end+2);
Lcd_WriteIndex(0x2b);
Lcd_WriteData(0x00);
Lcd_WriteData(y_start+3);
Lcd_WriteData(0x00);
Lcd_WriteData(y_end+3);
Lcd_WriteIndex(0x2c);
}
/*************************************************
函数名:LCD_Set_XY
功能:设置lcd显示起始点
入口参数:xy坐标
返回值:无
*************************************************/
void Lcd_SetXY(uint16_t x,uint16_t y)
{
Lcd_SetRegion(x,y,x,y);
}
/*************************************************
函数名:LCD_DrawPoint
功能:画一个点
入口参数:无
返回值:无
*************************************************/
void Gui_DrawPoint(uint16_t x,uint16_t y,uint16_t Data)
{
Lcd_SetRegion(x,y,x+1,y+1);
LCD_WriteData_16Bit(Data);
}
/*****************************************
函数功能:读TFT某一点的颜色
出口参数:color 点颜色值
******************************************/
//unsigned int Lcd_ReadPoint(uint16_t x,uint16_t y)
//{
// unsigned int Data;
// Lcd_SetXY(x,y);
//
// //Lcd_ReadData();//丢掉无用字节
// //Data=Lcd_ReadData();
// Lcd_WriteData(Data);
// return Data;
//}
/*************************************************
函数名:Lcd_Clear
功能:全屏清屏函数
入口参数:填充颜色COLOR
返回值:无
*************************************************/
void Lcd_Clear(uint16_t Color)
{
unsigned int i,m;
Lcd_SetRegion(0,0,X_MAX_PIXEL-1,Y_MAX_PIXEL-1);
Lcd_WriteIndex(0x2C);
for(i=0; i<X_MAX_PIXEL; i++)
for(m=0; m<Y_MAX_PIXEL; m++)
{
LCD_WriteData_16Bit(Color);
}
}
//取模方式 水平扫描 从左到右 低位在前
void showimage_farsight(const unsigned char *p) //显示128*35 QQ图片
{
int i;
unsigned char picH,picL;
//Lcd_Clear(WHITE); //清屏
Lcd_SetRegion(0,0,127,34); //坐标设置
for(i=0; i<128*35; i++)
{
picL=*(p+i*2); //数据低位在前
picH=*(p+i*2+1);
LCD_WriteData_16Bit(picH<<8|picL);
}
}
void showimage(const unsigned char *p) //显示128*35 QQ图片
{
int i;
unsigned char picH,picL;
//Lcd_Clear(WHITE); //清屏
Lcd_SetRegion(0,0,127,127); //坐标设置
for(i=0; i<128*128; i++)
{
picL=*(p+i*2); //数据低位在前
picH=*(p+i*2+1);
LCD_WriteData_16Bit(picH<<8|picL);
}
}
//void Gui_DrawFont_GBK16(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *s)
//{
// unsigned char i,j;
// unsigned short k,x0;
// x0=x;
//
// while(*s)
// {
// if((*s) < 128)
// {
// k=*s;
// if (k == 13)
// {
// x=x0;
// y+=16;
// }
// else
// {
// if (k>32) k-=32; else k=0;
//
// for(i=0;i<16;i++)
// for(j=0;j<8;j++)
// {
// if(asc16[k*16+i]&(0x80>>j)) Gui_DrawPoint(x+j,y+i,fc);
// else
// {
// if (fc!=bc) Gui_DrawPoint(x+j,y+i,bc);
// }
// }
// x+=8;
// }
// s++;
// }
//
// else
// {
//
//
// for (k=0;k<hz16_num;k++)
// {
// if ((hz16[k].Index[0]==*(s))&&(hz16[k].Index[1]==*(s+1)))
// {
// for(i=0;i<16;i++)
// {
// for(j=0;j<8;j++)
// {
// if(hz16[k].Msk[i*2]&(0x80>>j)) Gui_DrawPoint(x+j,y+i,fc);
// else {
// if (fc!=bc) Gui_DrawPoint(x+j,y+i,bc);
// }
// }
// for(j=0;j<8;j++)
// {
// if(hz16[k].Msk[i*2+1]&(0x80>>j)) Gui_DrawPoint(x+j+8,y+i,fc);
// else
// {
// if (fc!=bc) Gui_DrawPoint(x+j+8,y+i,bc);
// }
// }
// }
// }
// }
// s+=2;x+=16;
// }
//
// }
//}
void Gui_DrawFont_GBK16(uint16_t x0, uint16_t y0, uint16_t fc, uint16_t bc, uint8_t *s)
{
int i,j,k,x,y,xx;
unsigned char qm;
long int ulOffset;
char ywbuf[32];
// char temp[2];
for(i = 0; i<strlen((char*)s); i++)
{
if(((unsigned char)(*(s+i))) >= 161)
{
// temp[0] = *(s+i);
// temp[1] = '\0';
return;
}
else
{
qm = *(s+i);
ulOffset = (long int)(qm) * 16;
for (j = 0; j < 16; j ++)
{
ywbuf[j]=Zk_ASCII8X16[ulOffset+j];
}
for(y = 0; y < 16; y++)
{
for(x=0; x<8; x++)
{
k=x % 8;
if(ywbuf[y]&(0x80 >> k))
{
xx=x0+x+i*8;
Gui_DrawPoint(xx,y+y0,fc);
}
else
{
xx=x0+x+i*8;
Gui_DrawPoint(xx,y+y0,bc);
}
}
}
}
}
}
void Gui_DrawFont_1616(uint16_t x0, uint16_t y0, uint16_t fc, uint16_t bc,const char tfont16[][32],int num)
{
uint16_t i,j;
uint8_t Hznum;
for(Hznum = 0;Hznum < num;Hznum++)
{
// 设置汉子显示的区域
Lcd_SetRegion(x0+Hznum*16,y0,x0+16-1+Hznum*16,y0+16-1);
for(i = 0;i < 32;i++) //一个汉字的字模由32个元素组成
{
for(j = 0;j < 8;j++) //每个元素有8位,每一位代表一个亮点
{
if(tfont16[Hznum][i] & (0x80 >> j))
{
LCD_WriteData_16Bit(fc);
}
else
{
LCD_WriteData_16Bit(bc);
}
}
}
}
}
lcd.h
#ifndef __LCD_H
#define __LCD_H
#include "stdint.h"
#include "main.h"
#define RED 0xf800
#define GREEN 0x07e0
#define BLUE 0x001f
#define WHITE 0xffff
#define BLACK 0x0000
#define YELLOW 0xFFE0
#define CYAN 0x07ff
#define BRIGHT_RED 0xf810
#define GRAY0 0xEF7D //灰色0 3165 00110 001011 00101
#define GRAY1 0x8410 //灰色1 00000 000000 00000
#define GRAY2 0x4208 //灰色2 1111111111011111
#define X_MAX_PIXEL 128
#define Y_MAX_PIXEL 128
//LCD的SPI引脚的定义
#define LCD_CTRL_PORT GPIOB //定义TFT数据端口
#define LCD_LED LCD_Pin //LCD背光--->>TFT --BL
#define LCD_RS MISO_Pin //MISO--->>TFT --RS/DC
#define LCD_SDA MOSI_Pin //MOSI--->>TFT --SDA/DIN
#define LCD_SCL SCLK_Pin //SCK--->>TFT --SCL/SCK
#define LCD_CS_PORT CSS_GPIO_Port
#define LCD_CS CSS_Pin //MCU_PB11--->>TFT --CS/CE
//液晶控制口置1操作语句宏定义
#define LCD_CS_SET LCD_CS_PORT->BSRR=LCD_CS
#define LCD_RS_SET LCD_CTRL_PORT->BSRR=LCD_RS
#define LCD_SDA_SET LCD_CTRL_PORT->BSRR=LCD_SDA
#define LCD_SCL_SET LCD_CTRL_PORT->BSRR=LCD_SCL
#define LCD_LED_SET LCD_CTRL_PORT->BSRR=LCD_LED
//液晶控制口置0操作语句宏定义
#define LCD_CS_CLR LCD_CS_PORT->BRR=LCD_CS
#define LCD_RS_CLR LCD_CTRL_PORT->BRR=LCD_RS
#define LCD_SDA_CLR LCD_CTRL_PORT->BRR=LCD_SDA
#define LCD_SCL_CLR LCD_CTRL_PORT->BRR=LCD_SCL
#define LCD_LED_CLR LCD_CTRL_PORT->BRR=LCD_LED
void LCD_GPIO_Init(void);
void Lcd_WriteIndex(uint8_t Index);
void Lcd_WriteData(uint8_t Data);
void Lcd_WriteReg(uint8_t Index,uint8_t Data);
uint16_t Lcd_ReadReg(uint8_t LCD_Reg);
void Lcd_Reset(void);
void Lcd_Init(void);
void Lcd_Clear(uint16_t Color);
void Lcd_SetXY(uint16_t x,uint16_t y);
void Gui_DrawPoint(uint16_t x,uint16_t y,uint16_t Data);
unsigned int Lcd_ReadPoint(uint16_t x,uint16_t y);
void Lcd_SetRegion(uint16_t x_start,uint16_t y_start,uint16_t x_end,uint16_t y_end);
void LCD_WriteData_16Bit(uint16_t Data);
void showimage(const unsigned char *p);
void Lcd_ReadID(void);
void showimage_farsight(const unsigned char *p);
void Gui_DrawFont_GBK16(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *s);
void Gui_DrawFont_1616(uint16_t x0, uint16_t y0, uint16_t fc, uint16_t bc,const char tfont16[][32],int num);
#endif
dht11.c
#include "dht11.h"
#define DHT11_GPIO_PORT GPIOB
#define DHT11_GPIO_PIN GPIO_PIN_8
#define DHT11_DQ_IN HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_GPIO_PIN)
static void DHT11_IO_IN(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = DHT11_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct);
}
static void DHT11_IO_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = DHT11_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct);
}
//复位DHT11 \\起始
void DHT11_Rst(void)
{
DHT11_IO_OUT(); //SET OUTPUT 转换成输出模式
HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_GPIO_PIN, GPIO_PIN_RESET); //拉低DQ
HAL_Delay(20); //拉低至少18ms
HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_GPIO_PIN, GPIO_PIN_SET); //DQ=1
delay_us(30); //主机拉高20~40us
}
//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
uint8_t DHT11_Check(void)
{
uint8_t retry=0;
DHT11_IO_IN();//SET INPUT 转换成输入模式
while (!DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
{
retry++;
delay_us(1);
}
if(retry>=100) //说明,dht11还是大于80us的低电平信号,正常的话,应该是80us后,变成高电平,retry应该小于100接近80
return 1;
else
retry=0;
while (DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
{
retry++;
delay_us(1);
}
if(retry>=100)
return 1;
return 0;
}
//从DHT11读取一个位
//返回值:1/0
uint8_t DHT11_Read_Bit(void)
{
uint8_t retry=0;
while(DHT11_DQ_IN&&retry<100)//等待变为低电平
{
retry++;
delay_us(1);
}//延时100
retry=0;
while(!DHT11_DQ_IN&&retry<100)//等待变高电平
{
retry++;
delay_us(1);
}
delay_us(40);//等待40us
if(DHT11_DQ_IN)return 1;
else return 0;
}
//从DHT11读取一个字节
//返回值:读到的数据
uint8_t DHT11_Read_Byte(void)
{
uint8_t i,dat;
dat=0;
for (i=0; i<8; i++)
{
dat<<=1;
dat|=DHT11_Read_Bit();
}
return dat;
}
//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:HAL_OK,正常;1,读取失败
uint8_t DHT11_Read_Data(uint8_t *humiH,uint8_t *humiL,uint8_t *tempH,uint8_t *tempL)
{
uint8_t buf[5];
uint8_t i;
DHT11_Rst();
if(DHT11_Check()==0)
{
for(i=0; i<5; i++) //读取40位数据
{
buf[i]=DHT11_Read_Byte();
}
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
{
*humiH=buf[0];
*humiL=buf[1];
*tempH=buf[2];
*tempL=buf[3];
}
} else
return HAL_ERROR;
return HAL_OK;
}
//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在
uint8_t FS_DHT11_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = DHT11_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct);
HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_GPIO_PIN, GPIO_PIN_SET); // 输出高
DHT11_Rst(); //复位DHT11
return DHT11_Check();//等待DHT11的回应
}
dht11.h
#ifndef __DHT11_H__
#define __DHT11_H__
#include "main.h"
uint8_t DHT11_Read_Data(uint8_t *humiH,uint8_t *humiL,uint8_t *tempH,uint8_t *tempL);
uint8_t FS_DHT11_Init(void);
#endif