【2022得捷创新设计大赛】基于STM32F7508-DK多平台物联网有害气体检测系统
[复制链接]
一、作品简介
在北方农村冬季取暖,家家户户都有一个火炉。每年11月至次年3月是我国北方农村地区非职业性一氧化碳中毒的高发时期。一氧化碳中毒,是指含碳物质不完全燃烧产生无色、无味的窒息性气体,经呼吸道吸入机体后与血红蛋白结合,从而引起机体缺氧。造成以中枢神经系统功能损害为主的多脏器病变,严重者可能危及生命。农村地区居民使用煤炉、土暖气取暖时往往门窗紧闭,加之冬季低气压、低风速、湿度大等不利于烟道排烟的气象要素,这些因素叠加可能造成一氧化碳中毒,一氧化碳中毒由于不会引起人不适,不容易发现,因此危害极大。小时候的玩伴一家全部中毒身亡。
基于基于STM32F7508-DK物联网有害气体检测改善民生做得一个有意义的项目,能够实时采集室内一氧化碳,甲烷,烟感,温度湿度信息,如果发现一氧化碳,甲烷等有害气体超标。就会蜂鸣器报警,通过物联网平台传到手机或者云端。室外子女能够及时发现,提醒人开窗。
二、系统框图
得捷提供主控板STM32F7508-DK探索板,是为基于STMicroelectronics Arm® Cortex®-M7内核的 STM32F750N8H6STM32F750的芯片拥有3 个 ADC,这些 ADC 可以独立使用,也可以使用双重/三重模式(提高采样率)。 ADC 是 12 位逐次逼近型的模拟数字转换器。有 19 个通道,可测量 16 个外部源、2 个内部源和 Vbat 通道的信号。可以采集多路空气质量传感器。这些通道的 A/D 转换可以单次、连续、扫描或间断模式执行。ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。 模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
STM32F7 的 ADC 最大的转换速率为 2.4Mhz,也就是转换时间为 0.41us(ADCCLK=36M,采样周期为 3 个 ADC 时钟下得到),不要让 不 ADC 的时钟超过 的 36M,否则将导致结果准确度下降。STM32F7 将 ADC 的转换分为 2 个通道组:规则通道组和注入通道组。规则通道相当于 你正常运行的程序,而注入通道呢,就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换,在注入通道被转换完成之后,规则通道才得以继续转换。STM32F767 其 ADC 的规则通道组最多包含 16 个转换,而注入通道组最多包含 4 个通道。
显示屏:4.3 寸电容触摸 LCD-TFT,480x272 像素,
STM32F7芯片使用LTDC、DMA2D、及RAM存储器,构成了一个完整的液晶控制器。LTDC负责不断刷新液晶屏(将数据从显存搬运到液晶屏),DMA2D用于图像数据搬运、混合及格式转换(将数据搬运到显存),RAM存储器作为S显存。
三、各部分功能说明:
1,传感器模块,包括MQ-2 烟雾气敏传感器, MQ-135 空气质量检测传感,MQ-9B 一氧化碳 可燃气体传感器
得捷提供MQ-9B传感器,重点讲解一下。MQ-9B 气体传感器所使用的气敏材料是在清洁空气中电导率较低的二氧化锡(SnO2)。采用高低温循环检测方式检测一氧化碳(1.5V),高温(5.0V) 时不仅可以检测甲烷,还可以清洗低温时吸附的杂 质气体。传感器的电导率随空气中一氧化碳及甲烷 气体浓度增加而增大,使用简单的电路即可将电导率的变化转换为与该气体浓度相对应的输出信号。MQ-9B可燃气体传感器对一氧化碳、甲烷、液化气的灵敏度高,这种气体传感器可检测多种含一氧化碳及可燃性的气体,是一款适合多种应用的低成本传感器。
主要参数:
传感器特性描述:
驱动电路:
驱动板
该模块的使用,需开启ADC端口的浮空输出,就可以检测相关的电压信号,再根据电压信号进行计算,得到一个相对来说准确的数据。
关键代码如下:
#include "adc.h"
#include "delay.h"
ADC_HandleTypeDef AdcHandle;
_ADC_ISR_ adc_isr;
//在HAL_ADC_Init中调用
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{
GPIO_InitTypeDef GPIO_InitStruct;
static DMA_HandleTypeDef hdma_adc;
//使能ADC3时钟
__ADC3_CLK_ENABLE();
//使能ADC管脚IO口时钟
__GPIOF_CLK_ENABLE();
//配置ADC管脚GPIO,PF10,ADC3_IN8
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
#ifdef ADC_DMA_ENABLE
//使能DMA2时钟
__HAL_RCC_DMA2_CLK_ENABLE();
//配置DMA2
hdma_adc.Instance = DMA2_Stream0;
hdma_adc.Init.Channel = DMA_CHANNEL_2;
hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_adc.Init.Mode = DMA_CIRCULAR;
hdma_adc.Init.Priority = DMA_PRIORITY_HIGH;
hdma_adc.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_adc.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
hdma_adc.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_adc.Init.PeriphBurst = DMA_PBURST_SINGLE;
HAL_DMA_Init(&hdma_adc);
/* Associate the initialized DMA handle to the ADC handle */
__HAL_LINKDMA(hadc, DMA_Handle, hdma_adc);
//配置NVIC中断
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
#endif
}
/*******************************************************************************
* Function Name : STM32_ADC_Init
* Description : ADC初始化
* Input : ADCx ADC外设
Channel ADC输入通道
ISR 中断处理回调指针
* Output : None
* Return : None
* Note : None
*******************************************************************************/
void STM32_ADC_Init(ADC_TypeDef *ADCx, uint32_t Channel, void (*ISR)(void))
{
ADC_ChannelConfTypeDef sConfig;
adc_isr.isr_op = ISR; //挂载中断处理函数
//配置ADC外设
AdcHandle.Instance = ADCx;
AdcHandle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4; //ADC时钟=APB2时钟4分频
AdcHandle.Init.Resolution = ADC_RESOLUTION_12B; //12位分辨率
AdcHandle.Init.ScanConvMode = DISABLE; //禁止扫描模式
AdcHandle.Init.ContinuousConvMode = ENABLE; //使能连续转换
AdcHandle.Init.DiscontinuousConvMode = DISABLE; //禁止常规通道的不连续采样模式
AdcHandle.Init.NbrOfDiscConversion = 0; //不连续采样模式下的转换常规通道数
AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //禁止外部触发检测
AdcHandle.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; //触发源定时器CC1事件,此处无效
AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT; //右对齐
AdcHandle.Init.NbrOfConversion = 1; //常规通道序列长度,2次转换
#ifdef ADC_DMA_ENABLE //使能DMA
AdcHandle.Init.DMAContinuousRequests = ENABLE; //使能DMA请求
#else
AdcHandle.Init.DMAContinuousRequests = DISABLE; //禁止DMA请求
#endif
AdcHandle.Init.EOCSelection = DISABLE; //结束转换选择
HAL_ADC_Init(&AdcHandle);
//配置ADC通道
sConfig.Channel = Channel; //转换通道
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
sConfig.Offset = 0;
HAL_ADC_ConfigChannel(&AdcHandle, &sConfig);
#ifdef ADC_DMA_ENABLE //使能DMA
HAL_ADC_Start_DMA(&AdcHandle, (uint32_t*)&uhADCxConvertedValue, 1);
#else
//使能ADC中断,启动ADC
HAL_ADC_Start_IT(&AdcHandle);
#endif
}
//ADC中断服务函数
void ADC_IRQHandler(void)
{
HAL_ADC_IRQHandler(&AdcHandle);
}
//在HAL_ADC_IRQHandler中调用
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
if(adc_isr.isr_op != NULL) adc_isr.isr_op();
}
#ifdef ADC_DMA_ENABLE //使能DMA
//DMA中断
void DMA2_Stream0_IRQHandler(void)
{
HAL_DMA_IRQHandler(AdcHandle.DMA_Handle);
}
#endif
//电压采样
uint16_t Vol_Sample(void)
{
uint32_t Vol_ADC_Val;
Vol_ADC_Val = HAL_ADC_GetValue(&AdcHandle);
return Vol_ADC_Val*3300/4096; //返回电压值扩大1000倍
}
#define MAX_CONVERTED_VALUE 4095 /* Max converted value */
#define VREF 3300
#define SMOG_READ_TIMES 5
//读取MQ-135传感器的电压值
float MQ9B_Get_Vol(void)
{
u32 temp_val=0;
u8 t;
for(t=0;t<SMOG_READ_TIMES;t++)
{
temp_val+=HAL_ADC_GetValue(&AdcHandle); //读取ADC值
delay_ms(SMOG_READ_TIMES);
}
temp_val/=5;//得到平均值
return (u16)temp_val;
}
u16 MQ_135_Value(void)
{
u16 ppm = 0;
u16 temp =MQ9B_Get_Vol();
printf("%d\n",temp);
ppm =temp*3300/4095 ;
return ppm;
}
2,物联网模块
ESP8266,4G CAT1。云平台选择OneNET,支持适配各种网络环境和协议类型,可实现各种传感器和智能硬件的快速接入,提供丰富的 API 和应用模板以支撑各类行业应用和智能硬件的开发,有效降低物联网应用开发和部署成本,满足物联网领域设备连接、协议适配、数据存储、数据安全以及大数据分析等平台级服务需求。全新版本 OneNET 平台,向下延展终端适配接入能力,向上整合细分行业应用,可提供设备接入、设备管理等基础设备管理能力,以及位置定位LBS、远程升级 OTA、数据可视化 View、消息队列 MQ 等 PaaS 能力。
实现功能:
1) 每隔 1S,采集多路 空气传感器,DHT11 传感器的温湿度的值
2)程序运行后 WIFI(ESP8266)模块或者 4G 模块或者 NBIOT 模块或者以太网,会自动连接 onenet 平台,连接上后,会自动发起 MQTT 连接。
3) 连接上 Onenet 后,每隔 几秒,向平台传输一次温湿度及其上下限阈值信息;每隔 30 秒,向平台发送一次心跳包。
4) 空气传感器或者温度或湿度超过设定的阈值,会触发蜂鸣器报警;onenet 平台会发送邮件通知。
ESP8266 MQTT OneNET
#include "esp8266.h"
#include "Usart.h"
#include "delay.h"
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
uint16_t esp_rx_index = 0,esp_recv_len,esp_recv_complete;
uint8_t esp_recv_timeout = 0; //接收超时
uint8_t esp_recv_buff[RECV_MAX_LEN];
uint8_t esp_connect_ok = ESP_STA_DISCONNECTED;
uint8_t esp_airkiss_use = 1; //微信配网使用标志,1--使用
uint8_t esp_airkiss_start = 0; //启动配网标志,1--启动配网
/*******************************************************************************
* Function Name : ESP_RX_ISR
* Description : 串口接收处理函数,在接收中断中调用
* Input : None
* Output : None
* Return : None
* Note : None
*******************************************************************************/
void ESP_RX_ISR(u8 RX_Data)
{
if(esp_rx_index < RECV_MAX_LEN)
{
esp_recv_buff[esp_rx_index++] = RX_Data;
}
esp_recv_timeout = 0; //超时计数器清零
}
/*******************************************************************************
* Function Name : ESP_Init
* Description : WIFI模块初始化
* Input : None
* Output : None
* Return : None
* Note : None
*******************************************************************************/
void ESP_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
//使能GPIO端口时钟
ESP_RST_GPIO_ClK_ENABLE();
//KEY 输出
GPIO_InitStruct.Pin = ESP_RST_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //输出
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(ESP_RST_GPIO_PORT, &GPIO_InitStruct);
//HC05 串口初始化
USART2_Init(115200, NULL, ESP_RX_ISR);
esp_recv_timeout = 30;
esp_rx_index = 0;
}
/*******************************************************************************
* Function Name : ESP_Send
* Description : WIFI发送
* Input : buff 待发送数据 len 发送数据长度
* Output : None
* Return : None
* Note : None
*******************************************************************************/
void ESP_Send(uint8_t *buff, uint16_t len)
{
USART2_Send_Poll(buff,len);
}
/*******************************************************************************
* Function Name : ESP_UartSend
* Description : WIFI串口AT指令发送,用户移植接口
* Input : s 待发送字符串
* Output : None
* Return : None
* Note : 不能发送0x00
*******************************************************************************/
void ESP_UartSend(unsigned char *s)
{
USART2_SendString((char *)s);
}
/*******************************************************************************
* Function Name : ESP_RecvBuff_Clear
* Description : 清空接收缓存
* Input : None
* Output : None
* Return : None
* Note : None
*******************************************************************************/
void ESP_RecvBuff_Clear(void)
{
u16 i;
esp_rx_index = 0;
for(i = 0; i < sizeof(esp_recv_buff);i++)
esp_recv_buff = 0;
}
/*******************************************************************************
* Function Name : ESP_str_find
* Description : 查找匹配字符串
* Input : buff 查找缓存 str 要查找匹配的字符串
* Output : None
* Return : 0 找到匹配 1 未找到匹配
* Note : None
*******************************************************************************/
u8 ESP_str_find(u8 *buff, u8 *str)
{
u8 *p,*q;
p=buff;
q=str;
while(*p != '\0')
{
if(*p == *q)
{
q++;
if(*q == '\0') //匹配结束
{
return 0;
}
}
else
{
// if(q != str) //表示已经匹配字符
// {
// if(*q != '\0') //没有匹配结束
// {
// return 1; //返回错误
// }
// }
q=str;
}
p++;
}
return 1;
}
/*******************************************************************************
* Function Name : ESP_strstr
* Description : 查找匹配字符串
* Input : buff 查找缓存 str 要查找匹配的字符串 buff_len 查找缓存长度
* Output : None
* Return : 0 找到匹配 1 未找到匹配
* Note : None
*******************************************************************************/
u8 ESP_strstr(u8 *buff, u8 *str, u16 buff_len)
{
u8 *p,*q;
u16 i;
p=buff;
q=str;
//while(*p != '\0')
for(i = 0; i < buff_len; i++)
{
if(*p == *q)
{
q++;
if(*q == '\0') //匹配结束
{
return 0;
}
}
else
{
// if(q != str) //表示已经匹配字符
// {
// if(*q != '\0') //没有匹配结束
// {
// return 1; //返回错误
// }
// }
q=str;
}
p++;
}
return 1;
}
/*******************************************************************************
* Function Name : ESP_Cmd_Send
* Description : WIFI模块命令发送
* Input : cmd 命令字符串 ack 应答字符串 timeout 超时时间,单位毫秒
* Output : None
* Return : ESP_ACK_OK 收到应答 ESP_ACK_ERR 无应答
* Note : None
*******************************************************************************/
u8 ESP_Cmd_Send(u8 *cmd, u8 *ack, u16 timeout)
{
u8 res = ESP_ACK_ERR;
ESP_RecvBuff_Clear(); //清空应答缓存
delay_ms(10);
ESP_UartSend(cmd); //发送命令
//等待应答
if(ack == NULL)
{
res = ESP_ACK_OK;
goto CMD_END; //无应答
}
else
{
while(--timeout)
{
delay_ms(1); //延时1mS,等待接收完成
if(ESP_str_find(esp_recv_buff,(u8 *)ack) == ESP_ACK_OK) //收到应答
{
res = ESP_ACK_OK;
break; //跳出循环
}
else
{
res = ESP_ACK_ERR;
}
}
}
CMD_END:
return res;
}
/*******************************************************************************
* Function Name : ESP_HardReset
* Description : 硬件复位WIFI模块
* Input : timeout 超时时间
* Output : None
* Return : None
* Note : None
*******************************************************************************/
u8 ESP_HardReset(u16 timeout)
{
u8 res = ESP_ACK_ERR;
//硬件复位
ESP_RST_LOW();
delay_ms(500);
ESP_RST_HIGH();
while(--timeout)
{
delay_ms(1); //延时1mS,等待接收完成
if(ESP_strstr(esp_recv_buff,(u8 *)"ready",esp_rx_index) == ESP_ACK_OK) //收到应答
{
res = ESP_ACK_OK;
break; //跳出循环
}
else
{
res = ESP_ACK_ERR;
}
}
return res;
}
/*******************************************************************************
* Function Name : ESP_Smartconfig_Check
* Description : WIFI模块,配网检测
* Input : timeout 超时时间
* Output : None
* Return : None
* Note : None
*******************************************************************************/
u8 ESP_Smartconfig_Check(u16 timeout)
{
u8 res = ESP_ACK_ERR;
while(--timeout)
{
delay_ms(1); //延时1mS,等待接收完成
if(ESP_strstr(esp_recv_buff,(u8 *)"smartconfig connected wifi",esp_rx_index) == ESP_ACK_OK) //收到应答
{
res = ESP_ACK_OK;
break; //跳出循环
}
else
{
res = ESP_ACK_ERR;
}
}
return res;
}
const char *wifi_mode[2]={"TCP","UDP"};//连接模式
/*******************************************************************************
* Function Name : ESP_Client_ConnectServer
* Description : WIFI客户端连接,单链路非透传
* Input : mode: 0 TCP 1 UDP
addr_dns: IP地址或域名
port: 端口号
ap_ssid: 路由器名称(配网时,不需要)
ap_password:路由器密码(配网时,不需要)
* Output : None
* Return : 转换后的值
* Note : None
*******************************************************************************/
uint8_t ESP_Client_ConnectServer(u8 mode, u8 *addr_dns, u8 *port, u8 *ap_ssid, u8 *ap_password)
{
char buff[100];
esp_connect_ok = ESP_STA_DISCONNECTED; //断开网络
//硬件复位
if(ESP_HardReset(5000) != ESP_ACK_OK)
{
ESP_RecvBuff_Clear(); //清空应答缓存
return 1;
}
printf("RESET OK\r\n");
if(ESP_Cmd_Send((u8 *)"ATE0\r\n",(u8 *)"OK",200) != ESP_ACK_OK) return 2;
printf("ATE0 OK\r\n");
//设置模式STA
if(ESP_Cmd_Send((u8 *)"AT+CWMODE=1\r\n",(u8 *)"OK",200) != ESP_ACK_OK) return 3;
printf("AT+CWMODE OK\r\n");
if(esp_airkiss_use == 0)
{
//加入路由器
memset(buff,0,100); //清零
sprintf((char*)buff,"AT+CWJAP=\"%s\",\"%s\"\r\n",ap_ssid,ap_password);
if(ESP_Cmd_Send((u8 *)buff,(u8 *)"WIFI GOT IP\r\n\r\nOK",20000) != ESP_ACK_OK) return 4;
printf("Join AP OK\r\n");
}
else
{
if(esp_airkiss_start == 1)
{
esp_airkiss_start = 0; //清除配网启动标志
//设置自动连接
if(ESP_Cmd_Send((u8 *)"AT+CWAUTOCONN=1\r\n",(u8 *)"OK",200) != ESP_ACK_OK) return 9;
printf("CWAUTOCONN OK\r\n");
//启动配网
printf("Airkiss Start\r\n");
if(ESP_Cmd_Send((u8 *)"AT+CWSTARTSMART\r\n",(u8 *)"OK",200) != ESP_ACK_OK) return 10;
//等待配网完成,超时1分钟
printf("Waitting.......\r\n");
if(ESP_Smartconfig_Check(60000) == ESP_ACK_OK)
{
printf("Airkiss Success\r\n");
}
else
{
printf("Airkiss Fail\r\n");
}
//停止配网
if(ESP_Cmd_Send((u8 *)"AT+CWSTOPSMART\r\n",(u8 *)"OK",200) != ESP_ACK_OK) return 11;
printf("Airkiss Stop\r\n");
}
else //不启动配网时,要查询WIFI是否连接上路由器
{
// if(ESP_Cmd_Send((u8 *)buff,(u8 *)"WIFI GOT IP\r\n\r\nOK",20000) != ESP_ACK_OK) return 4;
// printf("Join AP OK\r\n");
delay_ms(3000); //延时3秒等待模块自动连接上路由
}
}
//获取IP
if(ESP_Cmd_Send((u8 *)"AT+CIFSR\r\n",(u8 *)"OK",500) != ESP_ACK_OK) return 5;
printf((const char *)esp_recv_buff);
//开启透传,5S超时
if(ESP_Cmd_Send((u8 *)"AT+CIPMODE=1\r\n",(u8 *)"OK",5000) != ESP_ACK_OK) return 6;
printf("AT+CIPMODE OK\r\n");
//连接服务器,超时10S
memset(buff,0,100); //清零
sprintf((char*)buff,"AT+CIPSTART=\"%s\",\"%s\",%s\r\n",wifi_mode[mode],addr_dns,port);
if(ESP_Cmd_Send((u8 *)buff,(u8 *)"OK",10000) != ESP_ACK_OK) return 7;
printf("Connect OK\r\n");
//进入透传,5S超时
if(ESP_Cmd_Send((u8 *)"AT+CIPSEND\r\n",(u8 *)"\r\nOK\r\n\r\n>",5000) != ESP_ACK_OK) return 8;
printf("AT+CIPSEND OK\r\n");
esp_recv_timeout = 30;
esp_rx_index = 0;
ESP_RecvBuff_Clear();
esp_connect_ok = ESP_STA_CONNECTED; //标记连接上网络
return 0;
}
/*******************************************************************************
* Function Name : ESP_Data_Send_FixedLen
* Description : ESP数据发送,指定长度方式
* Input : databuff: 待发送数据缓存 len: 发送数据长度
* Output : None
* Return : None
* Note : None
*******************************************************************************/
void ESP_Data_Send_FixedLen(u8 *databuff, u16 len)
{
if(esp_connect_ok != ESP_STA_CONNECTED) return;
//发送数据
ESP_Send(databuff,len);
}
/*******************************************************************************
* Function Name : ESP_InitServer
* Description : WIFI服务器建立,多连接
* Input : port: 端口号
ap_ssid: 路由器名称
ap_password:路由器密码
* Output : None
* Return : 转换后的值
* Note : None
*******************************************************************************/
uint8_t ESP_InitServer(u8 *port, u8 *ap_ssid, u8 *ap_password)
{
char buff[100];
esp_connect_ok = ESP_STA_DISCONNECTED; //断开网络
//硬件复位
if(ESP_HardReset(5000) != ESP_ACK_OK)
{
ESP_RecvBuff_Clear(); //清空应答缓存
return 1;
}
printf("RESET OK\r\n");
if(ESP_Cmd_Send((u8 *)"ATE0\r\n",(u8 *)"OK",200) != ESP_ACK_OK) return 2;
printf("ATE0 OK\r\n");
//设置模式STA
if(ESP_Cmd_Send((u8 *)"AT+CWMODE=1\r\n",(u8 *)"OK",200) != ESP_ACK_OK) return 3;
printf("AT+CWMODE OK\r\n");
//加入路由器
memset(buff,0,100); //清零
sprintf((char*)buff,"AT+CWJAP=\"%s\",\"%s\"\r\n",ap_ssid,ap_password);
if(ESP_Cmd_Send((u8 *)buff,(u8 *)"WIFI GOT IP\r\n\r\nOK",20000) != ESP_ACK_OK) return 4;
printf("Join AP OK");
//获取IP
if(ESP_Cmd_Send((u8 *)"AT+CIFSR\r\n",(u8 *)"OK",500) != ESP_ACK_OK) return 5;
printf((const char *)esp_recv_buff);
//关闭透传,5S超时
if(ESP_Cmd_Send((u8 *)"AT+CIPMODE=0\r\n",(u8 *)"OK",5000) != ESP_ACK_OK) return 6;
printf("AT+CIPMODE OK\r\n");
//开启多路连接,5S超时
if(ESP_Cmd_Send((u8 *)"AT+CIPMUX=1\r\n",(u8 *)"OK",5000) != ESP_ACK_OK) return 6;
printf("AT+CIPMUX OK\r\n");
//开启服务器,超时10S
memset(buff,0,100); //清零
sprintf((char*)buff,"AT+CIPSERVER=1,%s\r\n",port);
if(ESP_Cmd_Send((u8 *)buff,(u8 *)"OK",10000) != ESP_ACK_OK) return 7;
printf("Server Create OK\r\n");
//进入透传,5S超时
// if(ESP_Cmd_Send((u8 *)"AT+CIPSEND\r\n",(u8 *)"\r\nOK\r\n\r\n>",5000) != ESP_ACK_OK) return 8;
// printf("AT+CIPSEND OK\r\n");
esp_recv_timeout = 30;
esp_rx_index = 0;
ESP_RecvBuff_Clear();
esp_connect_ok = ESP_STA_CONNECTED; //标记连接上网络
return 0;
}
/*******************************************************************************
* Function Name : ESP_ServerData_Send
* Description : ESP数据发送,指定长度方式
* Input : id: 连接号 databuff: 待发送数据缓存 len: 发送数据长度
* Output : None
* Return : None
* Note : None
*******************************************************************************/
void ESP_ServerData_Send(u8 id, u8 *databuff, u16 len)
{
char strbuf[30];
if(esp_connect_ok != ESP_STA_CONNECTED) return;
sprintf(strbuf,"AT+CIPSEND=%d,%d\r\n",id,len);
if(ESP_Cmd_Send((u8 *)strbuf,(u8 *)">",500) == ESP_ACK_OK) //发送数据
{
//发送数据
ESP_Send(databuff,len);
}
}
/*******************************************************************************
* Function Name : ESP_Server_LinkStatusCheck
* Description : 服务器连接状态查询,周期调用
* Input : None
* Output : None
* Return : None
* Note : None
*******************************************************************************/
void ESP_Server_LinkStatusCheck(void)
{
u8 *p;
u8 id;
p = esp_recv_buff;
id = strtol((const char *)p,NULL,10);
if(strstr((const char *)esp_recv_buff,(const char *)"CONNECT") != 0) //连接建立
{
printf("link %d connect\r\n",id);
ESP_RecvBuff_Clear();
}
else if(strstr((const char *)esp_recv_buff,(const char *)"CLOSED") != 0) //连接断开
{
printf("link %d disconnect\r\n",id);
ESP_RecvBuff_Clear();
}
}
_ESP_INFO wifi_server;
/*******************************************************************************
* Function Name : ESP_ServerRecv_Process
* Description : wifi服务器接收处理,接收数据格式+IPD,1,6:ABCDEF
* Input : None
* Output : None
* Return : None
* Note : None
*******************************************************************************/
void ESP_ServerRecv_Process(void)
{
char *p;
if(esp_connect_ok != ESP_STA_CONNECTED) return; //服务器未打开,返回
p = strstr((const char *)esp_recv_buff,(const char *)"+IPD");
if(p != 0) //接收到数据
{
delay_ms(100); //确保数据接收完成
p+=5; //指针偏移到数据连接id开始处
//提取连接ID
wifi_server.link_id = strtol((const char *)p,NULL,10);
p+=2; //指针偏移到数据长度开始处
//提取数据长度
wifi_server.recv_len = strtol((const char *)p,NULL,10);
//找到数据载体起始位置
wifi_server.recv_start = (u8 *)strstr((const char *)p,(const char *)":") + 1;
//接收回调
if(wifi_server.recv_len != 0)
{
if(wifi_server.RecvData != NULL) wifi_server.RecvData(wifi_server.link_id,wifi_server.recv_start,wifi_server.recv_len);
//清空接收缓存
ESP_RecvBuff_Clear();
}
}
else if(strstr((const char *)esp_recv_buff,(const char *)"SEND OK")) //发送成功
{
}
else if(strstr((const char *)esp_recv_buff,(const char *)"SEND FAIL")) //发送失败
{
//执行重发,超过5次,重启模块
}
else if(strstr((const char *)esp_recv_buff,(const char *)"ERROR")) //发送失败
{
}
}
/*******************************************************************************
* Function Name : ESP_Client_ConnectServer_AP
* Description : WIFI AP模式客户端连接,单链路透传
* Input : mode: 0 TCP 1 UDP
addr_dns: IP地址或域名
port: 端口号
ap_ssid: AP热点名称
ap_password:AP热点密码
ap_ip: AP热点的IP地址
* Output : None
* Return : 转换后的值
* Note : None
*******************************************************************************/
uint8_t ESP_Client_ConnectServer_AP(u8 mode, u8 *addr_dns, u8 *port, u8 *ap_ssid, u8 *ap_password, u8 *ap_ip)
{
char buff[100];
esp_connect_ok = ESP_STA_DISCONNECTED; //断开网络
//硬件复位
if(ESP_HardReset(5000) != ESP_ACK_OK)
{
ESP_RecvBuff_Clear(); //清空应答缓存
return 1;
}
printf("RESET OK\r\n");
if(ESP_Cmd_Send((u8 *)"ATE0\r\n",(u8 *)"OK",200) != ESP_ACK_OK) return 2;
printf("ATE0 OK\r\n");
//设置模式AP
if(ESP_Cmd_Send((u8 *)"AT+CWMODE=2\r\n",(u8 *)"OK",200) != ESP_ACK_OK) return 3;
printf("AT+CWMODE OK\r\n");
//设置AP热点IP
memset(buff,0,100); //清零
sprintf((char*)buff,"AT+CIPAP=\"%s\"\r\n",ap_ip);
if(ESP_Cmd_Send((u8 *)buff,(u8 *)"OK",20000) != ESP_ACK_OK) return 4;
printf("AT+CIPAP OK\r\n");
//设置AP热点参数
memset(buff,0,100); //清零
sprintf((char*)buff,"AT+CWSAP=\"%s\",\"%s\",4,4\r\n",ap_ssid,ap_password);
if(ESP_Cmd_Send((u8 *)buff,(u8 *)"OK",20000) != ESP_ACK_OK) return 4;
printf("Set AP OK\r\n");
//获取IP
if(ESP_Cmd_Send((u8 *)"AT+CIFSR\r\n",(u8 *)"OK",500) != ESP_ACK_OK) return 5;
printf((const char *)esp_recv_buff);
//开启透传,5S超时
if(ESP_Cmd_Send((u8 *)"AT+CIPMODE=1\r\n",(u8 *)"OK",5000) != ESP_ACK_OK) return 6;
printf("AT+CIPMODE OK\r\n");
//连接服务器,超时10S
memset(buff,0,100); //清零
sprintf((char*)buff,"AT+CIPSTART=\"%s\",\"%s\",%s\r\n",wifi_mode[mode],addr_dns,port);
if(ESP_Cmd_Send((u8 *)buff,(u8 *)"OK",10000) != ESP_ACK_OK) return 7;
printf("Connect OK\r\n");
//进入透传,5S超时
if(ESP_Cmd_Send((u8 *)"AT+CIPSEND\r\n",(u8 *)"\r\nOK\r\n\r\n>",5000) != ESP_ACK_OK) return 8;
printf("AT+CIPSEND OK\r\n");
esp_recv_timeout = 30;
esp_rx_index = 0;
ESP_RecvBuff_Clear();
esp_connect_ok = ESP_STA_CONNECTED; //标记连接上网络
return 0;
}
/*******************************************************************************
* Function Name : ESP_InitServer_AP
* Description : WIFI服务器建立,多连接
* Input : port: 端口号
ap_ssid: AP热点名称
ap_password: AP热点密码
ap_ip: AP热点的IP地址
* Output : None
* Return : 转换后的值
* Note : None
*******************************************************************************/
uint8_t ESP_InitServer_AP(u8 *port, u8 *ap_ssid, u8 *ap_password, u8 *ap_ip)
{
char buff[100];
esp_connect_ok = ESP_STA_DISCONNECTED; //断开网络
//硬件复位
if(ESP_HardReset(5000) != ESP_ACK_OK)
{
ESP_RecvBuff_Clear(); //清空应答缓存
return 1;
}
printf("RESET OK\r\n");
if(ESP_Cmd_Send((u8 *)"ATE0\r\n",(u8 *)"OK",200) != ESP_ACK_OK) return 2;
printf("ATE0 OK\r\n");
//设置模式AP
if(ESP_Cmd_Send((u8 *)"AT+CWMODE=2\r\n",(u8 *)"OK",200) != ESP_ACK_OK) return 3;
printf("AT+CWMODE OK\r\n");
//设置AP热点IP
memset(buff,0,100); //清零
sprintf((char*)buff,"AT+CIPAP=\"%s\"\r\n",ap_ip);
if(ESP_Cmd_Send((u8 *)buff,(u8 *)"OK",20000) != ESP_ACK_OK) return 4;
printf("AT+CIPAP OK\r\n");
//设置AP热点参数
memset(buff,0,100); //清零
sprintf((char*)buff,"AT+CWSAP=\"%s\",\"%s\",4,4\r\n",ap_ssid,ap_password);
if(ESP_Cmd_Send((u8 *)buff,(u8 *)"OK",20000) != ESP_ACK_OK) return 4;
printf("Set AP OK\r\n");
//获取IP
if(ESP_Cmd_Send((u8 *)"AT+CIFSR\r\n",(u8 *)"OK",500) != ESP_ACK_OK) return 5;
printf((const char *)esp_recv_buff);
//关闭透传,5S超时
if(ESP_Cmd_Send((u8 *)"AT+CIPMODE=0\r\n",(u8 *)"OK",5000) != ESP_ACK_OK) return 6;
printf("AT+CIPMODE OK\r\n");
//开启多路连接,5S超时
if(ESP_Cmd_Send((u8 *)"AT+CIPMUX=1\r\n",(u8 *)"OK",5000) != ESP_ACK_OK) return 6;
printf("AT+CIPMUX OK\r\n");
//开启服务器,超时10S
memset(buff,0,100); //清零
sprintf((char*)buff,"AT+CIPSERVER=1,%s\r\n",port);
if(ESP_Cmd_Send((u8 *)buff,(u8 *)"OK",10000) != ESP_ACK_OK) return 7;
printf("AP Server Create OK\r\n");
//进入透传,5S超时
// if(ESP_Cmd_Send((u8 *)"AT+CIPSEND\r\n",(u8 *)"\r\nOK\r\n\r\n>",5000) != ESP_ACK_OK) return 8;
// printf("AT+CIPSEND OK\r\n");
esp_recv_timeout = 30;
esp_rx_index = 0;
ESP_RecvBuff_Clear();
esp_connect_ok = ESP_STA_CONNECTED; //标记连接上网络
return 0;
}
3,GUI液晶显示
3.1 LCD-TFT
1)、初始化LCD驱动的引脚
2)、使用LTDC初始化结构体,配置液晶屏的控制参数
3)、使用LTDC的层级初始化结构体,配置各层的控制参数
4)、直接操控显存,控制液晶屏显示图形
5)、使用DMA2D快速绘制直线及矩形
可以把图片放在内部flash,放在外部QSPI,或者SD卡中,下面SD卡解码STM32F750 来解码 BMP/JPG/JPEG/GIF 等图片,并在 LCD 上显示出来。
3.2本项目是在touchGFX GUI实现。标题设置成标签样式,放置一个box黑屏为背景,引入中文字库显示。
放置一个textArea控件,开启通配符,在其他任务中更新textArea控件计数值。中文字库引入。特殊字体。
实物成品图:
在Screen1Presenter.hpp文件中声明一个变量和方法
在Screen1Presenter.cpp文件中实现方法
定义一个Screen1View 变量,在启动和停止函数中赋值
定义一个全局函数调用成员add_num函数,使用C语言编译器进行编译
#ifndef SCREEN1VIEW_HPP
#define SCREEN1VIEW_HPP
#include <gui_generated/screen1_screen/Screen1ViewBase.hpp>
#include <gui/screen1_screen/Screen1Presenter.hpp>
class Screen1View : public Screen1ViewBase
{
public:
Screen1View();
virtual ~Screen1View() {}
virtual void setupScreen();
virtual void tearDownScreen();
void add_num();
protected:
uint16_t num;
};
#endif // SCREEN1VIEW_HPP
#include <gui/screen1_screen/Screen1View.hpp>
#include <touchgfx/Unicode.hpp>
extern "C" void update_control_text();
Screen1View *screen1;
Screen1View::Screen1View():
num(0)
{
}
void Screen1View::setupScreen()
{
Screen1ViewBase::setupScreen();
screen1 = this;
}
void Screen1View::tearDownScreen()
{
screen1 = NULL;
Screen1ViewBase::tearDownScreen();
}
void Screen1View::add_num()
{
this->num++;
Unicode::snprintf(this->textArea1Buffer, this->TEXTAREA1_SIZE,"%d" ,this->num);
textArea1.resizeToCurrentText();
textArea1.invalidate();
// getRootContainer().invalidate();//解决屏幕乱跳
}
extern "C" void update_control_text()
{
if(screen1)
4,机器人平台
实现手机遥控智能车动态采集不同区域的有害气体。
四、作品源码
见附件
五、作品功能演示视频
点击查看 >> 作品功能演示视频
六、项目总结
能够婉转STM32F7508-DK的外设,开发一个产品能够有实际价值就心满意足了。
七、其他
|