达特甲醛探测仪是基于英国达特公司设计开发的WZ-S型甲醛检测模组设计开发的,它可以用于检测环境中甲醛的浓度,以提示用户运用科学有效的方法降低甲醛污染,进而使环境的空气质量变得更加清新,也进一步提高用户的健康意识以及对生活品质的追求。
项目开源地址:https://gitee.com/morixinguan/smart-dart-detect
该系统由小熊派开发板、达特甲醛模组、ESP8266模块、热敏打印机模组构成。
小熊派BearPi开发板是南京厚德物联网有限公司为着力于开发者打造的一款简单、丰富、低成本、可扩展、支持多种IoT通信的物联网开发板,可广泛应用于智能家居、智慧农业、智慧城市等等领域。
达特甲醛模组采用的是英国达特WZ-S型甲醛模组,它可以用于将环境中甲醛的含量转换成浓度值,然后进行标准化数字输出,也便于系统集成。
该模组的硬件接口为腾讯团队定制的符合物联网俱乐部定义的标准E53接口,如下硬件原理图所示:
ESP8266模块小熊派开发板套件提供的用于通过Wi-Fi传输数据的通信扩展板,该拓展板采用的是乐鑫ESP8266 Wi-Fi通信模组,支持常见的IPv4/TCP/UDP/HTTP/FTP等通信协议。
该模组的硬件接口为小熊派定制的符合物联网俱乐部定义的标准WAN接口,如下硬件原理图所示:
热敏打印机模组采用的是深圳市荔璟科技有限公司的MC-EH205嵌入式小票打印机,该模组主要应用于各种仪器仪表打印相关凭证及检测数据明细,可广泛应用于邮政快递行业、仓储服务行业、安防安检行业、警用军工行业等等。
该模组支持串口TTL或者USB接口通讯,采用开关电源或主板供电,工作电压为5-9V,工作电流0.5~1.5A,瞬间电流约等于2A。
4.6、STM32CubeMX配置
智能达特甲醛探测系统主要是基于TencentOS tiny物联网操作系统进行开发,整体架构图如下:
达特智能系统主要包括硬件组成部分、驱动组成部分、操作系统(TencentOS tiny物联网操作系统)组成部分以及应用逻辑交互部分等,其整体产品架构设计如下:
其中,界面交互部分是整个产品最核心的部分,主要由以下逻辑构成:
关于界面交互,依赖于核心的软件框架,主要是基于事件驱动的方式来实现:
关于产品的操作系统启动流程由以下流程图构成:
(1)默认任务设计与功能实现
功能实现:
void default_task(void *pdata)
{
tos_knl_sched_lock();
/*创建队列,用于接收传感器数据*/
tos_msg_q_create(&sensor_data_msg, sensor_msg_pool, SENSOR_U3_BUFFER_SIZE);
tos_msg_q_create(&uploader_data_msg, uploader_msg_pool, NETWORK_BUF);
tos_msg_q_create(&recv_data_msg, recv_msg_pool, CMD_STR_SIZE);
/*创建按键任务*/
osThreadCreate(osThread(KeyTask), NULL);
/*创建状态栏任务*/
osThreadCreate(osThread(Status_Task), NULL);
/*创建数据上传任务*/
osThreadCreate(osThread(uploader_task), NULL);
/*创建传感器数据任务*/
osThreadCreate(osThread(Sensor_Task), NULL);
/*创建串口接收任务*/
osThreadCreate(osThread(UartCmdTask), NULL);
tos_knl_sched_unlock();
}
(2)按键任务设计与功能实现
功能实现:
软件逻辑实现:
void KeyTask(void *argument)
{
__IO uint8_t KeyCode = 255;
while(1)
{
/*获取键值*/
GetKey(&KeyCode);
if(255 != KeyCode)
{
Menu_Select_Item(Flow_Cursor.flow_cursor, KeyCode);
KeyCode = 255 ;
}
tos_sleep_ms(5);
}
}
(3)状态栏任务设计与功能实现
功能实现:
软件逻辑实现:
void Status_Task(void *argument)
{
LCD_Fill_Para status_bar_fill_para = {0, 240, 0, 27, WHITE} ;
lcd_model.lcd_driver->lcd_fill(status_bar_fill_para);
display_runing_time_font(1);
while(1)
{
Get_Date_Time();
if(0 == plot_handler.plot_mode)
{
sprintf(DateTime_Handler_Info.DisPlay_DateBuf, "%02d:%02d:%02d", \
DateTime_Handler_Info.hour, DateTime_Handler_Info.minute, DateTime_Handler_Info.sec);
lcd_model.lcd_driver->lcd_show_ascii_str(datatime_display_para);
if(MAIN_PAGE == Flow_Cursor.flow_cursor)
display_runing_time(DateTime_Handler_Info.hour, DateTime_Handler_Info.minute, DateTime_Handler_Info.sec, 1);
}
if(MAIN_PAGE == Flow_Cursor.flow_cursor)
{
tos_knl_sched_lock();
save_record_to_flash();
tos_knl_sched_unlock();
}
if(1 == User_Memory_Para.alarm)
{
/*如果大于0.062ppm,则报警灯闪烁,否则熄灭*/
if(0 == User_Memory_Para.unit)
{
if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 0.062)
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
else
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
}
/*如果大于0.062*0.74666mg/m3,则报警灯闪烁,否则熄灭*/
else
{
if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 0.046)
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
else
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
}
}
else
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
}
/*刷新WIFI连接状态*/
if(0 == wifi_connect_flag)
display_signal_status(0);
else
display_signal_status(4);
/*刷新服务器连接状态*/
if(0 == server_connect_flag)
display_server_status(0);
else
display_server_status(1);
/*刷新上传状态*/
if(0 == User_Memory_Para.upload_flag)
display_upload_status(0);
else
display_upload_status(1);
/*刷新设备密码状态*/
if(1 == User_Memory_Para.password_enable_flag)
display_passwd_icon(0);
else
display_passwd_icon(1);
/*刷新SD卡状态*/
refresh_sd_card_status();
tos_sleep_ms(1000);
}
}
(4)数据上传任务设计与功能实现
功能实现:(注意,需要腾讯云固件支持,后续章节讲解)
软件逻辑实现:(mqtt_demo_task代码过长,此处省略,详细请看代码)
void uploader_task(void *arg)
{
mqtt_demo_task();
while (1)
{
printf("This is a mqtt demo!\r\n");
tos_task_delay(1000);
}
}
(5)传感器任务设计与功能实现
功能实现:
软件逻辑实现:
void Sensor_Task(void *argument)
{
char ch20_data[20] = {0};
/*传感器注册*/
Sensor_Register(&Formaldehyde_Sensor_interface);
while(1)
{
/*获取传感器数据*/
Formaldehyde_Sensor_interface.get_Formaldehyde_Value(&Formaldehyde_Sensor_interface);
/*处理传感器数据展示*/
if(MAIN_PAGE == Flow_Cursor.flow_cursor)
{
display_work_status(Formaldehyde_Sensor_interface.Formaldehyde_Value, 1);
//PPM
if(0 == User_Memory_Para.unit)
{
/* 正常解析之后通过队列发送 */
memset(ch20_data, 0, 20);
if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 2)
{
Formaldehyde_Sensor_interface.Formaldehyde_Value = 2 ;
sprintf(ch20_data, "ppm:%.3f", Formaldehyde_Sensor_interface.Formaldehyde_Value);
}
else
sprintf(ch20_data, "ppm:%.3f", Formaldehyde_Sensor_interface.Formaldehyde_Value);
/*如果网络功能开的状态下才会进行队列发送*/
if(1 == User_Memory_Para.upload_flag && 1 == wifi_connect_flag && 1 == server_connect_flag)
tos_msg_q_post(&uploader_data_msg, ch20_data);
if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 2)
{
ch20_ppm_value_printf = 2;
display_hcho_value(ch20_ppm_value_printf, RED, 1);
if(1 == User_Memory_Para.value)
{
display_hcho_max_value(ch20_ppm_value_printf, GREEN, 1);
display_hcho_min_value(ch20_ppm_value_printf, GREEN, 1);
}
else
{
display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
}
}
else
{
if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 0.062)
{
ch20_ppm_value_printf = Formaldehyde_Sensor_interface.Formaldehyde_Value;
display_hcho_value(Formaldehyde_Sensor_interface.Formaldehyde_Value, RED, 1);
if(1 == User_Memory_Para.value)
{
display_hcho_max_value(Formaldehyde_Sensor_interface.Formaldehyde_Max_Value, GREEN, 1);
display_hcho_min_value(Formaldehyde_Sensor_interface.Formaldehyde_Min_Value, GREEN, 1);
}
else
{
display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
}
}
else
{
ch20_ppm_value_printf = Formaldehyde_Sensor_interface.Formaldehyde_Value;
display_hcho_value(Formaldehyde_Sensor_interface.Formaldehyde_Value, GREEN, 1);
if(1 == User_Memory_Para.value)
{
display_hcho_max_value(Formaldehyde_Sensor_interface.Formaldehyde_Max_Value, GREEN, 1);
display_hcho_min_value(Formaldehyde_Sensor_interface.Formaldehyde_Min_Value, GREEN, 1);
}
else
{
display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
}
}
}
}
//mg/m3
else
{
/* 正常解析之后通过队列发送 */
memset(ch20_data, 0, 20);
if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 0.046)
{
Formaldehyde_Sensor_interface.Formaldehyde_Value = 0.046 ;
sprintf(ch20_data, "mgm3:%.3f", Formaldehyde_Sensor_interface.Formaldehyde_Value);
}
else
sprintf(ch20_data, "mgm3:%.3f", Formaldehyde_Sensor_interface.Formaldehyde_Value);
/*如果网络功能开的状态下才会进行队列发送*/
if(1 == User_Memory_Para.upload_flag && 1 == wifi_connect_flag && 1 == server_connect_flag)
tos_msg_q_post(&uploader_data_msg, ch20_data);
if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 1.493) //2 * 0.74666
{
ch20_ppm_value_printf = 1.493;
display_hcho_value(ch20_ppm_value_printf, RED, 1);
if(1 == User_Memory_Para.value)
{
display_hcho_max_value(ch20_ppm_value_printf, GREEN, 1);
display_hcho_min_value(ch20_ppm_value_printf, GREEN, 1);
}
else
{
display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
}
}
else
{
if(Formaldehyde_Sensor_interface.Formaldehyde_Value > 0.046)
{
ch20_ppm_value_printf = Formaldehyde_Sensor_interface.Formaldehyde_Value;
display_hcho_value(ch20_ppm_value_printf, RED, 1);
if(1 == User_Memory_Para.value)
{
display_hcho_max_value(ch20_ppm_value_printf, GREEN, 1);
display_hcho_min_value(ch20_ppm_value_printf, GREEN, 1);
}
else
{
display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
}
}
else
{
ch20_ppm_value_printf = Formaldehyde_Sensor_interface.Formaldehyde_Value;
display_hcho_value(ch20_ppm_value_printf, GREEN, 1);
if(1 == User_Memory_Para.value)
{
display_hcho_max_value(ch20_ppm_value_printf, GREEN, 1);
display_hcho_min_value(ch20_ppm_value_printf, GREEN, 1);
}
else
{
display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
display_hcho_max_value(ch20_ppm_value_printf, BLACK, 0);
}
}
}
}
}
}
}
(6)串口接收任务设计与功能实现
功能实现:
软件逻辑实现如下:
/*注册命令*/
REGISTER_CMD(reset, cpu_reset_process);
REGISTER_CMD(led_on, led_on_process);
REGISTER_CMD(led_off, led_off_process);
REGISTER_CMD(get_sensor_data, get_sensor_data);
REGISTER_CMD(get_system_para, get_system_para);
REGISTER_CMD(get_system_version, get_system_version);
void UartCmdTask(void *argument)
{
k_err_t err;
void *msg_received;
uint8_t uart_recv_buf[CMD_STR_SIZE] = {0};
/*命令初始化*/
cmd_init();
HAL_UART_Receive_IT(&huart1, (uint8_t *)&cmd_parse_typedef.Res, 1);
while(1)
{
err = tos_msg_q_pend(&recv_data_msg, &msg_received, TOS_TIME_FOREVER);
if (err == K_ERR_NONE)
{
memcpy(uart_recv_buf, msg_received, CMD_STR_SIZE);
cmd_parsing((char *)uart_recv_buf);
memset(&cmd_parse_typedef, 0, sizeof(cmd_parse_typedef));
}
}
}
(1)下载腾讯云官方提供的ESP8266固件
https://github.com/tencentyun/qcloud-iot-esp-wifi
(2)下载烧录工具
使用乐鑫官方下载工具ESPFlashDownloadTool,下载链接如下:
https://www.espressif.com/zh-hans/support/download/other-tools
(3)操作步骤
1、确保硬件连接正确,上电即能进入ESP8266烧录模式
2、打开烧录工具
选择开发者模式
选择ESP8266下载工具
配置烧录界面面板参数
点击START查看模组信息:
导入要下载的固件,设置地址从0x000开始
重新点击START下载腾讯云固件
如图所示看见完成即固件更新成功。
将ESP8266硬件恢复为正常模式,也就是将那些线全部用烙铁取掉,将ESP8266模块插在小熊派开发板上,如下图所示,切换开关为AT PC模式:
发送模组信息读取命令查看当前模组信息:
如果能打印和文档描述信息则表示固件更新正确。
(1)打开腾讯云官网,提前登录成功后,选择物联网开发平台选项
然后点击立即进入。
(2)根据腾讯云开发文档指示创建项目并配置好参数
详细配置流程请参考:TencentOS官方公众号文章
https://mp.weixin.qq.com/s/t8iVaypA1BtZwt7EEkAWyw
(3)根据腾讯云开发文档指示配置腾讯连连小程序面板
详细配置流程请参考:TencentOS官方公众号文章
https://mp.weixin.qq.com/s/t8iVaypA1BtZwt7EEkAWyw
(4)程序连连小程序操作步骤
位于腾讯IoT explorer物联网开发平台的设备调试页面,有一个二维码的选项,点击扫码添加,结果如下图所示:
最后,在确保硬件正常连接的情况下,设备能够按操作视频所述正常工作,部分现象如下图所示:
(1)操作简单,技术支持到位
腾讯云IoT explorer致力于让用户快速将设备联网接入,完善的官方操作指引以及简单的操作界面,用户很快就能学习并应用到实际的产品开发中去,其次是腾讯云IoT explorer拥有强大的售后技术支持团队,致力于解决用户使用过程中的任何疑难杂症,保证用户能够简单,高效,快速完成腾讯云平台的对接。
(2)完善的开发者解决方案
腾讯云IoT explorer还提供多个解决方案,通过提供简单的API给用户,用户通过简单调用就可以轻松接入,完善的解决方案注定腾讯云IoT explorer未来能够引领物联网行业走向,促进物联网生态快速发展。
(3)移动端快速资源整合
腾讯云Iot explorer与腾讯连连小程序的默契配合,将物联网网页端平台展现的数据也可以通过手机等移动端随时随地的展示,十分迎合当下信息化时代的发展以及用户需求,该小程序还支持用户二次开发和定制,让用户设备可以有更多的展示空间。
本次参加腾讯连连IoT开发大赛,让我全方位的学习了TencetOS tiny操作系统的使用、腾讯云IoT物联网平台的配置和使用以及腾讯小程序腾讯连连的配置和使用,加深了我对物联网产品开发的理解,同时也让我收获了基于腾讯云物联网设备的开发流程和步骤,经过本次的学习和实践,未来在物联网产品的开发上,优先考虑本次实践的方案。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。