本文分享自华为云社区《基于STM32+华为云IOT设计的酒驾监控系统【玩转华为云】》,作者: DS小龙哥。

1. 前言

随着人们生活水平的提高,为了减少和杜绝车祸的现象越来越多,所引发的交通事故也引起了人们的重视,为了减少和杜绝酒后驾车导致事故发生,当前设计了一种安装在驾驶室内,能根据具体功能进行鉴别酒精浓度的系统,当识别到酒驾之后会发出警报,并发送短信给指定紧急联系人,通知家人通知酒驾,一起监督行车安全。并将GPS数据上传到华为云物联网平台,调用地图模块显示具体位置,主控芯片采用STM32单片机,GSM模块采用IM800C。系统还带了一块LCD显示屏,可以实时显示检测的酒精含量,酒精超标后,本地蜂鸣器也会发出警报,提醒驾驶员。

测量酒驾的标准是:
(1)饮酒驾车是指车辆驾驶人员血液中的酒精含量大于或者等于20mg/100ml,小于80mg/100ml的驾驶行为。
(2)醉酒驾车是指车辆驾驶人员血液中的酒精含量大于或者等于80mg/100ml的驾驶行为。

需要使用的硬件如下:

(1)STM32系统板
(2)酒精检测传感器
(3)LCD显示屏
(4)供电模块
(5)SIM800C模块
(6)蜂鸣器模块
(7)GPS模块–采用SIM800C内部的GPS功能获取GPS数据。

v2-2729195ae245de444cc8bfb4a8504203_720w.jpg
v2-a706cda67177558b43387a4d2211b11d_720w.jpg
v2-1d906a9bccb55e54aea896c6245628cd_720w.jpg
为了测试,搞了几口二锅头。

v2-dde10ad16d376caaa5b2e142bad39aa1_720w.jpg
上位机采用QT开发,调用华为云的应用侧接口获取设备上传的数据。再调用百度接口,获取GPS定位的位置。

v2-b4fc715ed973905c56ec82cdeb6b9144_720w.jpg
2. 登录华为云创建云端设备  
2.1 创建产品
华为运官网: https://www.huaweicloud.com/
v2-b473236c09f8b5f4f60668d7a781742c_720w.jpg
v2-960cec9b1cf6df118ac8a8399d4c05de_720w.jpg
v2-874c0552c6a1ee4923defcdb5c2e4074_720w.jpg
在这里可以查看接入的协议的端口号和地址。

v2-6a82b3bc3b473730ece5f40355f8d2ac_720w.jpg
v2-48433135b56ec6c81a2f3cb799e081f9_720w.jpg
MQTT (1883)        a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com  
我们设备接入的协议选择MQTT,端口对应是1883

接下来继续创建产品,点击产品页面,点击右上角创建产品:
v2-19c0b532c326a6d07068ae178cd6556f_720w.jpg
v2-5c8f405cbdb4f57259baed84d40c252d_720w.jpg
v2-a8bd3665b39fe5d3f80f67b368cac997_720w.jpg
2.2 创建设备 v2-6a7de76c8f7697faa9c763aaf7c91b67_720w.jpg
v2-5eced66bf3da3328e0cbba56f5b9ba99_720w.jpg
v2-6f3c6b175dbc75819324b9dbcba0b49d_720w.jpg
这是我的设备信息:
设备ID
  • 625cd29cecf9c41c38215ba5_1126626497
  • 设备密钥
  • 1126626497
  •    
  • {
  •     "device_id": "625cd29cecf9c41c38215ba5_1126626497",
  •     "secret": "1126626497"
  • }
  • 复制代码

    2.3 产品模型定义
    这一步就是设置上报设备的属性,也就是设备的数据类型定义。

    v2-8409b639c58636420cb5ce71b2008ccd_720w.jpg
    v2-b729fb5faee8c15a9069c70a2920d14b_720w.jpg
    v2-affc03e38be893991b6283d26d3830eb_720w.jpg
    v2-d15bc095e618273a49bf42d9a60d52af_720w.jpg
    2.4 生成MQTT登录密匙
    创建完产品、设备之后,接下来就需要知道如何通过MQTT协议登陆华为云服务器。

    官方的详细介绍在这里: https://support.huaweicloud.com/devg-iothub/iot_01_2127.html#ZH-CN_TOPIC_0240834853__zh-cn_topic_0251997880_li365284516112
    v2-4e34cb13ea1641111a1dac98df1b4fc2_720w.jpg
    v2-7a80fae4f94f38b771efec1c910b74c9_720w.jpg

    MQTT设备登陆密匙生成地址: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/

    v2-610aac95ca27ac8425b2d2d92048965b_720w.jpg
    下面就得到了MQTT协议设备登录的参数。

    2.5 使用MQTT客户端软件登录

    所有的参数已经得到,接下来采用MQTT客户端登录华为云进行测试。
    华为云物联网平台的域名是: a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com
    华为云物联网平台的IP地址是: 121.36.42.100
    在软件里参数填充正确之后,就看到设备已经连接成功了。
    接下来打开设备页面,可以看到设备已经在线了。

    2.6 上报数据

    官方文档: https://support.huaweicloud.com/devg-iothub/iot_01_2127.html#ZH-CN_TOPIC_0240834853__zh-cn_topic_0251997880_li365284516112
    在这个文档里介绍了MQTT上报数据的格式。

    v2-4864d7f44279a369fd82e997b32c7137_720w.jpg
    v2-1335a97c38f3cc07aa6ca4511e0aaadc_720w.jpg
    总结的格式:
    //订阅主题: 平台下发消息给设备
  • $oc/devices/625cd29cecf9c41c38215ba5_1126626497/sys/messages/down
  • //设备上报数据
  • $oc/devices/625cd29cecf9c41c38215ba5_1126626497/sys/properties/report
  • //上报的属性消息 (一次可以上报多个属性,在json里增加就行了)
  • {"services": [{"service_id": "MQ3","properties":{"MQ3":50}}]}
  • 复制代码
    到此,设备数据已经上报成功,如果需要增加更多的属性,按照流程继续增加即可。

    3. STM32代码实现
    酒精浓度传感器的预热时间要20秒~1分钟左右,这段时间之后采集的数据才会稳定。预热模块会发热,烫手,这个是正常现象。

    3.1 系统原理图
    v2-7601ba903c78ad4671fd3884a8b9b207_720w.jpg
    v2-abe1bd688a6732edc439b56bd4814e59_720w.jpg
    3.2 程序下载
    通过USB进行程序下载: 下载软件在软件包目录下。

    点击开始编程之后,点击板子上的复位键即可下载程序,如果失败,重试几次即可。正常的效果如下。

    v2-fa8fc76e41f44ac13e1dbff229b83734_720w.jpg
    正常程序运行之后,打开串口调试助手看到的初始化信息如下:

    v2-b8c3fb36af2157903193712586eb9f8b_720w.jpg
    3.3 字体取模
    v2-a93494468a2f335a6b7834a23e7b3199_720w.jpg

    3.4 main.c代码
    keil工程可以在这里get: https://download.csdn.net/download/xiaolong1126626497/81993720
    #include "stm32f10x.h"
  • #include "led.h"
  • #include "delay.h"
  • #include "key.h"
  • #include "usart.h"
  • #include <string.h>
  • #include "timer.h"
  • #include "oled.h"
  • #include "adc.h"
  • #include <string.h>
  • #include <stdlib.h>
  • #include "font.h"
  • #include "sim800c.h"
  • #include "mqtt.h"
  • /*
  • 硬件连接方式:
  • 1. TFT 1.44 寸彩屏接线
  • GND   电源地
  • VCC   接5V或3.3v电源
  • SCL   接PC8(SCL)
  • SDA   接PC9(SDA)
  • RST   接PC10
  • DC    接PB7
  • CS    接PB8
  • BL          接PB11
  • 2. 蜂鸣器
  • VCC--->3.3V
  • DAT--->PA6
  • GND--->GND
  • 3. 酒精检测传感器MQ3
  • VCC--->3.3V
  • GND--->GND
  • DAT--->PA1
  • 4. 板载LED灯接线
  • LED1---PA8
  • LED2---PD2
  • 5. 板载按键接线
  • K0---PA0
  • K1---PC5
  • K2---PA15
  • 6. SIM800C--GSM模块
  • GND----GND
  • VCC--->3.3V
  • PA2----SIM800C_RXD
  • PA3----SIM800C_TXD
  • */
  • //华为物联网服务器的设备信息
  • #define MQTT_ClientID "62381267575fb713ee164ad2_xl_1_0_0_2022032106"
  • #define MQTT_UserName "62381267575fb713ee164ad2_xl_1"
  • #define MQTT_PassWord "124344feff3e3d96ff6af13cf36af36766619ff1eeee40e99cbae9b7b9739fe4"
  • //订阅与发布的主题
  • #define SET_TOPIC  "$oc/devices/62381267575fb713ee164ad2_xl_1/sys/messages/down"  //订阅
  • #define POST_TOPIC "$oc/devices/62381267575fb713ee164ad2_xl_1/sys/properties/report"  //发布
  • //设置连接的路由器信息
  • #define CONNECT_WIFI  "Xiaomi_meizi6"   //将要连接的路由器名称 --不要出现中文、空格等特殊字符
  • #define CONNECT_PASS "12170307yu"       //将要连接的路由器密码
  • #define CONNECT_SERVER_IP "a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com"   //服务器IP地址
  • #define CONNECT_SERVER_PORT 1883            //服务器端口
  • //JTAG模式设置,用于设置JTAG的模式
  • //mode:jtag,swd模式设置;00,全使能;01,使能SWD;10,全关闭;           
  • #define JTAG_SWD_DISABLE   0X02
  • #define SWD_ENABLE         0X01
  • #define JTAG_SWD_ENABLE    0X00                  
  • void JTAG_Set(u8 mode)
  • {
  •         u32 temp;
  •         temp=mode;
  •         temp<<=25;
  •         RCC->APB2ENR|=1<<0;     //开启辅助时钟           
  •         AFIO->MAPR&=0XF8FFFFFF; //清除MAPR的[26:24]
  •         AFIO->MAPR|=temp;       //设置jtag模式
  • }
  • u16 MQ3_data=0; //酒精浓度
  • float MQ3_data_float=0; //mg/l
  • char data_buff[100];
  • //酒精超标提示
  • u8 sim800c_buff[100]="Drunk driving reminder";
  • int main()
  • {
  •     u8 state=0;
  •     u8 key=0;
  •     u32 time_cnt=0;
  •     JTAG_Set(JTAG_SWD_DISABLE); //释放PA15
  •     LED_Init();  //LED灯初始化
  •     BEEP_Init(); //蜂鸣器初始化
  •     KEY_Init();  //按键初始化
  •     USART1_Init(115200); //串口1初始化-打印调试信息
  •     Lcd_Init();    //LCD初始化
  •     Lcd_Clear(0);  //清屏为黑色
  •     LCD_LED_SET;   //通过IO控制背光亮               
  •     AdcInit();     //ADC初始化--检测酒精传感器的值
  •     TIMER2_Init(72,20000);//辅助串口2接收,超时时间为20ms
  •     USART2_Init(115200); //可能的波特率(测试):  57600 、9600、115200
  •     USART3_Init(115200);//串口-WIFI
  •     TIMER3_Init(72,20000); //超时时间20ms
  •    
  •     //预热视频
  •     LCD_ShowChineseFont(0,16*3,16,HZ_FONT_16[20],RED,0);
  •     LCD_ShowChineseFont(16,16*3,16,HZ_FONT_16[21],RED,0);
  •     LCD_ShowChineseFont(16*2,16*3,16,HZ_FONT_16[22],RED,0);
  •     LCD_ShowChineseFont(16*3,16*3,16,HZ_FONT_16[23],RED,0);
  •     LCD_ShowChineseFont(16*4,16*3,16,HZ_FONT_16[24],RED,0);
  •     LCD_ShowChineseFont(16*5,16*3,16,HZ_FONT_16[25],RED,0);
  •     LCD_ShowChineseFont(16*6,16*3,16,HZ_FONT_16[26],RED,0);
  •     LCD_ShowChineseFont(16*7,16*3,16,HZ_FONT_16[27],RED,0);
  •     //delay_ms(30000); //初始化时间30秒
  •     delay_ms(5000); //初始化时间5秒
  •     Lcd_Clear(0);  //清屏为黑色
  •    
  •    //采集数据的真实数据
  •    LCD_ShowChineseFont(0,16*2,16,HZ_FONT_16[0],RED,0);
  •    LCD_ShowChineseFont(16,16*2,16,HZ_FONT_16[1],RED,0);
  •    LCD_ShowChineseFont(16*2,16*2,16,HZ_FONT_16[2],RED,0);
  •    LCD_ShowChineseFont(16*3,16*2,16,HZ_FONT_16[3],RED,0);
  •    
  •    //酒精含量计算结果
  •    LCD_ShowChineseFont(0,16*3,16,HZ_FONT_16[4],RED,0);
  •    LCD_ShowChineseFont(16,16*3,16,HZ_FONT_16[5],RED,0);
  •    LCD_ShowChineseFont(16*2,16*3,16,HZ_FONT_16[6],RED,0);
  •    LCD_ShowChineseFont(16*3,16*3,16,HZ_FONT_16[7],RED,0);
  •     //酒精超标显示
  •     Gui_DrawFont_GBK16(0,16*4,RED,0,(u8*)"        ");
  •     LCD_ShowChineseFont(0,16*4,16,HZ_FONT_16[16],RED,0);
  •     LCD_ShowChineseFont(16,16*4,16,HZ_FONT_16[17],RED,0);
  •     LCD_ShowChineseFont(16*2,16*4,16,HZ_FONT_16[18],RED,0);
  •     LCD_ShowChineseFont(16*3,16*4,16,HZ_FONT_16[19],RED,0);
  •     //初始化SIM800C
  •     state=SIM800C_InitCheck();
  •     printf("SIM800C初始化状态:%d\r\n",state);
  •     DelayMs(1000);
  •    
  •     //设置文本模式
  •     state=SIM800C_SetNoteTextMode();
  •     printf("设置文本模式状态:%d\r\n",state);
  •     DelayMs(1000);
  •    
  •     //
  •    
  •       printf("正在初始化WIFI请稍等.\r\n");
  •    
  •     for(i=0;i<5;i++)
  •     {
  •         if(ESP8266_Init()==0)
  •         {
  •             esp8266_state=1;
  •             break;
  •         }
  •         else
  •         {
  •             esp8266_state=0;
  •             printf("ESP8266硬件检测错误.\n");  
  •         }
  •     }
  •   
  •    if(esp8266_state)
  •    {
  •        printf("准备连接服务器....\r\n");
  •         //非加密端口
  •         printf("WIFI:%d\n",ESP8266_STA_TCP_Client_Mode(CONNECT_WIFI,CONNECT_PASS,CONNECT_SERVER_IP,CONNECT_SERVER_PORT,1));
  •          
  •         //2. MQTT协议初始化        
  •         MQTT_Init();
  •         //3. 连接服务器  
  •         for(i=0;i<5;i++)
  •         {
  •             if(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord)==0)
  •             {
  •                 esp8266_state=1;
  •                 break;
  •             }
  •             esp8266_state=0;
  •             printf("服务器连接失败,正在重试...\n");
  •             delay_ms(500);
  •         }
  •         printf("服务器连接成功.\n");
  •         //3. 订阅主题
  •         if(MQTT_SubscribeTopic(SET_TOPIC,0,1))
  •         {
  •            printf("主题订阅失败.\n");
  •         }
  •         else
  •         {
  •            printf("主题订阅成功.\n");
  •         }
  •    }
  •    
  •    while(1)
  •    {
  •         key=KEY_Scan();
  •         if(key)
  •         {
  •             printf("key=%d\r\n",key);
  •         }
  •       
  •         //控制LED灯
  •         if(key==2)
  •         {
  •             LED2=!LED2;
  •         }   
  •         
  •         //手动控制蜂鸣器测试
  •         //手动发送短信测试
  •         if(key==1)
  •         {
  •             BEEP=1;
  •             delay_ms(100);
  •             BEEP=0;
  •             sprintf((char*)sim800c_buff,"Drunk driving reminder:%d",MQ3_data);
  •             //发送短信
  •             if(SIM800C_SendNote((u8*)"13800138000",sim800c_buff,strlen((char*)sim800c_buff))==0)
  •             printf("短信发送成功\r\n");
  •             else
  •             printf("短信发送失败\r\n");
  •         }
  •         
  •         //轮询时间到达
  •         if(time_cnt>300)
  •         {
  •             time_cnt=0;
  •             LED1=!LED1;
  •             //获取空气质量
  •             MQ3_data=GetAdcCHxDATA(1);
  •             printf("采集MQ3数据:%d\r\n",MQ3_data);
  •          
  •              //上报数据
  •             sprintf(data_buff,"{"services": [{"service_id":"STM32","properties":{"MQ3":%d}]}",
  •             MQ3_data);
  •             
  •             MQTT_PublishData(POST_TOPIC,data_buff,0);
  •             
  •                //上报数据
  •             sprintf(data_buff,"{"services": [{"service_id":"STM32","properties":{"MQ3":%d}]}",
  •             MQ3_data);
  •             
  •             MQTT_PublishData(POST_TOPIC,data_buff,0);
  •             
  •             //LCD屏实时显示酒精浓度     
  •             //采集数据
  •             sprintf(data_buff,"%d",MQ3_data);
  •             Gui_DrawFont_GBK16(72,16*2,RED,0,(u8*)"       ");
  •             Gui_DrawFont_GBK16(72,16*2,RED,0,(u8*)data_buff);
  •             
  •             //酒精含量
  •             //MQ3_data_float=((float)MQ3_data*(5.0/4096))*0.36-1.08;
  •             MQ3_data_float=((float)MQ3_data*(5.0/4096))*0.36;
  •             sprintf(data_buff,"%0.2f mg/L",MQ3_data_float);
  •             printf("计算酒精浓度:%s\r\n",data_buff);
  •             Gui_DrawFont_GBK16(72,16*3,RED,0,(u8*)"        ");
  •             Gui_DrawFont_GBK16(72,16*3,RED,0,(u8*)data_buff);  
  •             
  •              //判断酒精浓度是否超标,设置阀值
  •             if(MQ3_data>2000)
  •             {
  •                 sprintf((char*)sim800c_buff," :%d",MQ3_data);
  •                 //发送短信
  •                 if(SIM800C_SendNote((u8*)"18171571217",sim800c_buff,strlen((char*)sim800c_buff))==0)
  •                 printf("短信发送成功\r\n");
  •                 else
  •                 printf("短信发送失败\r\n");
  •             }
  •             
  •             //采集的值越小,表明酒精浓度越高。反之越大。
  •             //根据阀值显示不同的文字提示
  •             if(MQ3_data>2000)
  •             {
  •                  //你已酒驾
  •                 Gui_DrawFont_GBK16(0,16*4,RED,0,(u8*)"        ");
  •                 LCD_ShowChineseFont(0,16*4,16,HZ_FONT_16[8],RED,0);
  •                 LCD_ShowChineseFont(16,16*4,16,HZ_FONT_16[9],RED,0);
  •                 LCD_ShowChineseFont(16*2,16*4,16,HZ_FONT_16[10],RED,0);
  •                 LCD_ShowChineseFont(16*3,16*4,16,HZ_FONT_16[11],RED,0);
  •             }
  •             //正常稳定范围采集的值是500左右
  •             else
  •             {
  •                 //安全范围
  •                 Gui_DrawFont_GBK16(0,16*4,RED,0,(u8*)"        ");
  •                 LCD_ShowChineseFont(0,16*4,16,HZ_FONT_16[16],RED,0);
  •                 LCD_ShowChineseFont(16,16*4,16,HZ_FONT_16[17],RED,0);
  •                 LCD_ShowChineseFont(16*2,16*4,16,HZ_FONT_16[18],RED,0);
  •                 LCD_ShowChineseFont(16*3,16*4,16,HZ_FONT_16[19],RED,0);
  •             }
  •         }
  •         
  •         DelayMs(10);
  •         time_cnt++;
  •          }
  • }
  • 复制代码