课程设计题目智能厨房,记录一下过程
单片机的源码百度网盘链接:
链接:https://pan.baidu.com/s/1n8sGvSJCIPi6uyorMEM5tQ
提取码:6682
需求分析
1.设备端能够采集厨房的温度,湿度,烟雾浓度和是否有火、可燃气体泄露,并将结果显示在oled屏幕上
2.在火焰传感器检测到有火焰后,需要自动打开蜂鸣器报警,并自动打开水泵抽水灭火,同时发送报警信息给用户端。没有火焰后自动关闭水泵和蜂鸣器,发送报警解除信息给用户端
3.在烟雾浓度过大或检测到有可燃气体泄露时,自动打开蜂鸣器报警,打开风扇,同时发送报警信息给用户端。没有烟雾和可燃气体后自动关闭风扇和蜂鸣器,发送报警解除信息给用户端
4.用户端需要能够实时显示厨房的温湿度,烟雾浓度和是否有可燃气体泄露
5.用户端能够手动控制风扇和水泵的开启/关闭。可以滑动条控制风扇转速
6.用户端在使用前需要登录,需要用到user数据库
7.用户端可以实现对厨房食材的库存管理(crud)
8.使用imx6ull跑Linux,使用qt界面实现用户端的全部功能
系统架构
黑色为项目基础实现功能,红色为项目完成过程中可拓展部分
stm32设备端实现
在此次项目我主要负责硬件,即stm32设备端
接线
代码
模块
定时器TIM1和TIM4
时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); //时钟使能
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
tim4简单,都是普通定时器,初始化和tim2一样
/*TIMER4*/
TIM_InternalClockConfig(TIM4);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 10000 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 7200 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM4, TIM_FLAG_Update);
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
tim1是高级定时器 初始化:
/*TIMER1*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 5000-1; //设置自动重装载寄存器周期值
TIM_TimeBaseStructure.TIM_Prescaler =7200-1;//设置预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;//重复计数设置
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //参数初始化
TIM_ClearFlag(TIM1, TIM_FLAG_Update);//清中断标志位
TIM_ITConfig( //使能或者失能指定的TIM中断
TIM1, //TIM1
TIM_IT_Update | //TIM 更新中断源
TIM_IT_Trigger, //TIM 触发中断源
ENABLE //使能
);
配置中断优先级NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
//设置优先级
NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级0级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
使能TIM1和TIM4
TIM_Cmd(TIM1, ENABLE); //使能TIMx外设
TIM_Cmd(TIM4, ENABLE);
LED模块,OLED模块,蜂鸣器模块,CO传感器模块,火焰传感器模块
除了OLED模块都是简单的GPIO
CO传感器模块需要将DO口接到stm32中带有FT标志的引脚上(5V容忍)
OLED模块直接去找商家要
USART串口模块
初始化(略)
使用usart1,PA9,PA10,波特率115200
printf函数重定向
点击魔术棒勾选lib
在c/c++处加上 --no-multibyte-chars:
void Serial_Printf(char *format, ...)
{
char String[100];
va_list arg;
va_start(arg, format);
vsprintf(String, format, arg);
va_end(arg);
Serial_SendString(String);
}
usart1中断函数:
定义一个数据缓冲区来接收用户端的数据:
#define USART_REC_LEN 200
u8 USART_RX_BUF[USART_REC_LEN];
u16 USART_RX_STA=0;
在.h文件中需要extern定义一下:
#define USART_REC_LEN 200
extern u8 USART_RX_BUF[USART_REC_LEN];;
extern u16 USART_RX_STA;
void USART1_IRQHandler(void)
{
u8 Res;
if (USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) {
Res=USART_ReceiveData(USART1);
if ((USART_RX_STA&0x8000)==0){
if(USART_RX_STA&0x4000){
if(Res!=0x0a) USART_RX_STA=0;
else USART_RX_STA|=0x8000;
}else{
if(Res==0x0d) USART_RX_STA |=0x4000;
else{
USART_RX_BUF[USART_RX_STA&0x3FFF]=Res;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1)) USART_RX_STA=0;
}
}
}
}
}
dht11温湿度模块
找商家要或者
AD+DMA获取烟雾传感器
烟雾传感器是5v供电,使用AD时要用AO口接stm32的引脚上,这里不用像CO传感器一样接FT标志的引脚,因为AD模拟输出的电压一般不会飙到4095那么高,直接接就行了
AD初始化
时钟和GPIO:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
ADC:
/*通道9是烟雾传感器*/
ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_55Cycles5);
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
DMA:
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
使能:
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
设标志位和软件触发
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
每五次取一次平均值:
u16 Get_ADC0_Aver(u8 times){
u32 ad_val=0;
u8 t;
for(t=0;t<times;t++){
ad_val+=AD_Value[0];
Delay_ms(5);
}
return ad_val/times;
}
PWM控制风扇和水泵
使用定时器2的通道3控制风扇转速,定时器3的通道1控制水泵
pwm.c
配置时钟和GPIO
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM2和TIM3初始化
TIM_InternalClockConfig(TIM2);
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
TIM2和TIM3pwm配置
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC3Init(TIM2, &TIM_OCInitStructure);
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0; //CCR
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
使能
TIM_Cmd(TIM2, ENABLE);
TIM_Cmd(TIM3, ENABLE);
控制转速:
void PWM_SetCompare3(uint16_t Compare){
TIM_SetCompare3(TIM2, Compare);
}
void PWM_SetCompare1(uint16_t Compare){
TIM_SetCompare1(TIM3, Compare);
}
Motor.c
风扇初始化
void Motor_Init(void){
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
PWM_Init();
}
打开风扇
void Motor_SetSpeed(int8_t Speed){
GPIO_SetBits(GPIOA, GPIO_Pin_1);
GPIO_ResetBits(GPIOA, GPIO_Pin_0);
PWM_SetCompare3(Speed);
}
关闭风扇
void Motor_Stop(void){
PWM_SetCompare3(0);
}
Pump.c
水泵初始化
void Pump_Init(void){
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
PWM_Init();
}
打开水泵
void Pump_SetSpeed(int8_t Speed){
GPIO_SetBits(GPIOA, GPIO_Pin_4);
GPIO_ResetBits(GPIOA, GPIO_Pin_5);
PWM_SetCompare1(Speed);
}
关闭水泵
void Pump_Stop(void){
PWM_SetCompare1(0);
}
main.c
头文件(略)
定义各种标志
DHT11_Data_TypeDef DHT11_Data;/*dht11数据结构体*/
uint8_t Fire_flag=0,CO_flag=0;/*flag*/
uint16_t j;
uint16_t Smoke_AD;/*烟雾浓度AD获取*/
接收用户端命令后要比对的字符串:
/*灯*/
char led_on[] = "{\"light\":1}";
char led_off[] = "{\"light\":0}";
/*风扇*/
char fan_on[] = "{\"fan\":1}";
char fan_off[] = "{\"fan\":0}";
/*水泵*/
char pump_on[] = "{\"pump\":1}";
char pump_off[] = "{\"pump\":0}";
各种模块初始化,定时器在最后初始化
看门狗初始化:
/*看门狗设置2250ms*/
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(IWDG_Prescaler_32);
IWDG_SetReload(3124);
IWDG_ReloadCounter();
IWDG_Enable();
while(1)中负责
喂狗:
/*喂狗*/
IWDG_ReloadCounter();
①对用户端信息的接收,包括led_on,fan_on,pump_on等
/*接收阿里云的消息并控制led灯*/
if (USART_RX_STA&0x8000){
USART_RX_STA=0;
if(strstr((const char*)USART_RX_BUF,led_on)){
LED1_ON();
}else if(strstr((const char*)USART_RX_BUF,led_off)){
LED1_OFF();
}else if(strstr((const char*)USART_RX_BUF,fan_on)){
Motor_SetSpeed(80);
}else if(strstr((const char*)USART_RX_BUF,fan_off)){
Motor_Stop();
}else if(strstr((const char*)USART_RX_BUF,pump_on)){
Pump_SetSpeed(0);
}else if(strstr((const char*)USART_RX_BUF,pump_off)){
Pump_Stop();
}
memset(USART_RX_BUF,0,600);
}
②发送温度,湿度,烟雾浓度和可燃气体检测到阿里云平台
/*每隔3s发送温湿度给阿里云*/
if (j++>3){
/*发送温度*/
printf("AT+MQTTPUB=0,\"/k09szKIuB0S/ESP8266DUAN/user/ESP8266DUAN\",\"
{\\\"temp\\\":%d.%d}\",1,0\r\n",
DHT11_Data.temp_int,DHT11_Data.temp_deci);
Delay_ms(250);
/*发送湿度*/
printf("AT+MQTTPUB=0,\"/k09szKIuB0S/ESP8266DUAN/user/ESP8266DUAN\",\"
{\\\"hum\\\":%d.%d}\",1,0\r\n",
DHT11_Data.humi_int-20,DHT11_Data.humi_deci);
Delay_ms(250);
/*发送有无CO*/
printf("AT+MQTTPUB=0,\"/k09szKIuB0S/ESP8266DUAN/user/ESP8266DUAN\",\"
{\\\"CO\\\":%d}\",1,0\r\n",
!CO_flag);
Delay_ms(250);
/*发送烟雾浓度*/
printf("AT+MQTTPUB=0,\"/k09szKIuB0S/ESP8266DUAN/user/ESP8266DUAN\",\"
{\\\"smoke\\\":%d.%d}\",1,0\r\n",
smoke_int,smoke_dec);
Delay_ms(250);
j=0;
}
if (!Fire_flag){
printf("AT+MQTTPUB=0,\"/k09szKIuB0S/ESP8266DUAN/user/ESP8266DUAN\",\"
{\\\"pump\\\":1}\",1,0\r\n");
Delay_ms(250);
}
if (!CO_flag){
printf("AT+MQTTPUB=0,\"/k09szKIuB0S/ESP8266DUAN/user/ESP8266DUAN\",\"
{\\\"fan\\\":1}\",1,0\r\n");
Delay_ms(250);
}
③更新对各个传感器flag,如fire_flag,CO_flag等
/*判断各个传感器数据并置标志位,有异常则发送消息给阿里云*/
Fire_flag= FireSensor_Get();
CO_flag=CO_Sensor_Get();
定时器1
获取主函数中的flag并判断,以此控制风扇,水泵,蜂鸣器等
//定时器1,用来判断各种传感器标志
void TIM1_UP_IRQHandler(void)
{
if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)//检查指定的TIM中断发生与否:TIM 中断源
{
TIM_ClearITPendingBit(TIM1, TIM_IT_Update);//清除TIMx的中断待处理位:TIM 中断源
/***************在此处添加中断执行内容******************/
/*开蜂鸣器*/
if (Fire_flag&&CO_flag&&smoke_int<5) Buzzer_OFF();
else Buzzer_Turn();
/*开水泵*/
if (!Fire_flag) Pump_SetSpeed(0);
/*开风扇*/
if (!CO_flag) Motor_SetSpeed(80);
}
}
定时器4
对oled数据更新
//定时器4,用来显示oled
void TIM4_IRQHandler(void)
{
if (TIM_GetITStatus(TIM4, TIM_IT_Update) == SET)
{
/*温度*/
OLED_ShowString(1,1,"temp:");
OLED_ShowString(1,8,".");
OLED_ShowString(1,10,"C");
OLED_ShowNum(1,6,DHT11_Data.temp_int,2);
OLED_ShowNum(1,9,DHT11_Data.temp_deci,1);
/*湿度*/
OLED_ShowString(2,1,"humi:");
OLED_ShowString(2,8,".");
OLED_ShowString(2,10,"%");
OLED_ShowNum(2,6,DHT11_Data.humi_int-20,2);
OLED_ShowNum(2,9,DHT11_Data.humi_deci,1);
/*烟雾浓度*/
OLED_ShowString(3,1,"smoke:");
OLED_ShowNum(3,7,Smoke_AD,4);
/*可燃气体*/
OLED_ShowString(4,1,"CO:");
OLED_ShowNum(4,4,CO_flag,1);
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
}
}
stm32+esp8266连接阿里云
阿里云配置
登录阿里云,进入物联网平台创建产品,添加设备,可以去b站找详细配置教程
esp8266
//连接wifi
void WIFI_Connect(char *my_wifi,char *password){
printf("AT+CWJAP=\"%s\",\"%s\"\r\n",my_wifi,password);
Delay_ms(5000);
}
//wifi初始化
void WIFI_Init(void){
WIFI_Connect(MY_WIFI,PASSWORD);
}
阿里云初始化,这里账号密码改成你自己创建阿里云产品时的账号密码,client,包括发布和订阅消息也一样要改
//连接阿里云
void Aliyun_Connect(void){
printf("AT+CIPSNTPCFG=1,8,\"ntp1.aliyun.com\"\r\n");
Delay_ms(250);
//账号密码 --6
printf("AT+MQTTUSERCFG=0,1,\"NULL\",\"ESP8266DUAN&k09szKIuB0S\",\"742c23f0cfddd6c880ec54d394ff1ad10d5bc276dbe46f026db89ee120f6330a\",0,0,\"\"\r\n");
Delay_ms(250);
//client --7
printf("AT+MQTTCLIENTID=0,\"k09szKIuB0S.ESP8266DUAN|securemode=2\\,signmethod=hmacsha256\\,timestamp=1697433121277|\"\r\n");
Delay_ms(250);
//连接域名 url --8
printf("AT+MQTTCONN=0,\"iot-06z00g2179nz53u.mqtt.iothub.aliyuncs.com\",1883,1\r\n");
Delay_ms(250);
}
订阅阿里云
//订阅 subscribe
void Subscribe_aliyun(void){
printf("AT+MQTTSUB=0,\"/sys/k09szKIuB0S/ESP8266DUAN/thing/service/property/set\",1\r\n");
Delay_ms(1000);
}