Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
AT组件
lwgps
MQTT
利用RT-Thread与MQTT实现的毕业设计——智慧班车管理系统的设计与实现实录
发布于 2023-06-03 00:16:40 浏览:458
订阅该版
[tocm] 大家好,我是一位刚刚接触RT-Thread的小白(┭┮﹏┭┮21入坑,中间有很长时间摸鱼),本次毕业设计的题目是智慧班车管理系统的设计与实现,其理论基础是基于我在专科和老师申请的一个实用新型专利——一种智慧班车信息管理系统【这是我专科的专利,本科的毕设哈,本人现已考研到新疆大学计算机技术专业】 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/3eb3f234e6d2e0d6004609aab13a8e0c.png.webp) # 项目成果演示 下面是对于本个项目实现效果的演示: https://live.csdn.net/v/embed/299837 # 项目硬件开发总结 下面从开发者的角度对本项目进行总结:(因为不是写paper所以比较随意哈~) 项目采用的IoT架构,底层是STM32L475VET6潘多拉开发板+RT-Thread,对于RT-Thread的资源使用情况在论文中也有提到,这里直接截个图: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/f45d1fab2b3714bf354e0d0c31663537.png) ## RT-Thread使用情况详情 内核层的信号量、邮箱、消息队列等机制是用于线程同步以及线程通信的,中断一开始是用于检测PIN设备的IRQ,但是后来去掉了,原因是不好用,确实是用中断的时候自己懒得调试了,程序运行会出现很多问题,所以直接开了个线程,这个后面会讲到。 设备与驱动层中I/O设备模型是最基本的设备Model,所以不再赘述。UART设备是值得一提的哈。因为这个项目需要用到三个串口,即串口1用于Finsh组件调试,串口2用于NB-IoT通信,串口3用于GPS数据的URC解析,但是官方给的BSP中没有添加串口3设备,所以需要自己添加UART设备。 ## 添加UART设备 在RT-Thread文档中心已经给出了详细的添加步骤,所在路径如下: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/428048fcef3f0aada42f2a19034e122c.png) 这里也贴上了具体链接:[外设驱动添加指南](https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/make-bsp/stm32-bsp/STM32%E7%B3%BB%E5%88%97%E5%A4%96%E8%AE%BE%E9%A9%B1%E5%8A%A8%E6%B7%BB%E5%8A%A0%E6%8C%87%E5%8D%97 "外设驱动添加指南") 首先,需要本地安装Cubemx,然后打开裁剪过的BSP目录中的board文件夹 【关于BSP的裁剪工作可以通过ENV工具,使用scons--dist完成】 然后找到该文件夹 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/f69b81808ececf759c031b0ac1032619.png) 并打开其中的Cube工程: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/0a14a81ce815ff90ba8b1b6481535b46.png) 打开完成后如果Cube版本与官方制作BSP使用的Cube版本不同时会弹出如下提示框: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/1b88535b3e4827912b8f97967f1218f5.png.webp) 这里可以选择Migrate迁移选项,这样就会在线获取对应版本的Cube,另外,这里提供一个“文明上网”的Blog:[使用Edge打开~](https://p6p.net/22826.html) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/084a2937033ccf05c6f757e500a8a6bf.png.webp) 找到UART3选项,设置为异步模式 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/db59df95cc3c7e6617dfc3c15a1e5f74.png) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/16ec64c292cc0e3c235f903b4877aec4.png.webp) 同时,需要注意的是USART3默认使用的端口,潘多拉开发板并没有引出,所以需要到引出的PB10和PB11单独设置端口的模式: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/15f5b9707f38ae49dbdfb62a270f0095.png) 设置完成后不要直接生成,检查一下不要生成单独的c和h文件,即下面的选项不要勾选: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/2b0144720e85f968d6b19582fb788e3a.png.webp) 然后点击生成代码: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/0539a1e8e31278302d699bd64abaf67c.png.webp) 最后,需要打开board文件夹中的Kconfig文件,添加UART3选项:【建议使用Notepad打开,这样打开的文件格式对称,便于复制】 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/01acd6df76ff3f587f3d402ec9b23dae.png) 添加完成后,打开ENV工具输入menuconfig命令,依次进入Hardware Drivers Config--->On-chip Peripheral Drivers--->Enable UART就可以看到新添加的UART3选项: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/0588834e4e563d9167e1b0fc111bdd5b.png) 选中后重新生成工程,打开后记得重新编译。这样,UART3设备驱动已经添加成功。 ## 适配软件包 回顾一下本项目需要完成的功能,这里直接贴出了论文截图:(懒了~) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/c403748f3adb75132e7fe43ac6550d30.png) 综上,项目使用到的软件包包括AHT10软件包(适配Sensor框架)、lwgps软件包(硬件使用的是整点原子官方的GPS模块ATK-1218-BD:[官网链接](http://www.openedv.com/docs/modules/other/ATK-1218-BD.html))。另外需要说明的是: MQ2使用的是DO输出,所以用于采集空气质量的MQ2和采集班车人数的红外对射模块使用的RT-Thread提供的PIN设备框架,直接使用API获取管脚电平即可,缩短开发周期。 **AHT10软件包的使用** 将AHT10软件包添加后,只需要关心应用层的逻辑即可。 我的应用层线程初始化都是在main线程中完成的,有关于AHT10数据采集线程的初始化如下: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/2b736d4c5ef15da8f37e0d0812cda95e.png.webp) 线程入口函数如下: ```c static void aht10_thread_entry() { rt_device_t dev_temp = RT_NULL; rt_device_t dev_humi = RT_NULL; struct tmp_msg msg; struct rt_sensor_data sensor_data; rt_size_t res_temp,res_humi; rt_err_t res; res = rt_sem_take(send_AHT_sem, RT_WAITING_FOREVER); if(res != RT_EOK) { rt_kprintf("getGps_thread take a nb semaphore, failed.\n"); return; } dev_temp = rt_device_find("temp_aht"); dev_humi = rt_device_find("humi_aht"); if (dev_temp == RT_NULL) { rt_kprintf("Can't find device:dev_temp\n"); return; } if (rt_device_open(dev_temp, RT_DEVICE_FLAG_RDWR) != RT_EOK) { rt_kprintf("open device dev_temp failed!\n"); return; } if (dev_humi == RT_NULL) { rt_kprintf("Can't find dev_humi device\n"); return; } if (rt_device_open(dev_humi, RT_DEVICE_FLAG_RDWR) != RT_EOK) { rt_kprintf("open device dev_humi failed!\n"); return; } while(1) { res_temp = rt_device_read(dev_temp, 0, &sensor_data, 1); if (res_temp != 1) { rt_kprintf("read temp data failed!"); rt_device_close(dev_temp); return; } else { // rt_kprintf("temp:%3dC\n",abs(sensor_data.data.temp)/10); msg.temp_value=(abs(sensor_data.data.temp)/10); } rt_thread_mdelay(10); res_humi = rt_device_read(dev_humi, 0, &sensor_data, 1); if (res_humi != 1) { rt_kprintf("read humi data failed!\n"); rt_device_close(dev_humi); return; } else { // rt_kprintf("hum:%2d%, timestamp:%5d\n",abs(sensor_data.data.humi)/10); msg.humi_value=abs(sensor_data.data.humi)/10; } rt_mq_send(tmp_msg_mq, &msg,sizeof(msg)); // rt_kprintf("======aht10-Thread Send a mq,msg.tem:%d,msg.hum:%d======\r\n",msg.temp_value,msg.humi_value); rt_thread_mdelay(300); } } ``` 在上述代码中首先是获取NB初始化完成后release的信号量;获取成功后,再获取注册到Sensor框架中的温湿度传感器(注意:这里的温湿度传感器是分开的,可以通过list_device在Finshi终端查看);然后是打开设备并读取温湿度信息;最后将采集到的数据以邮箱机制发送到NB发送线程。这是整个AHT10软件包的添加和数据的读取工作(需要注意:AHT10是通过I2C进行通信的,所以需要开启I2C设备框架) **lwgps软件包的使用** lwgps软件包是一个轻量级的gps的URC解析包,支持NEMA格式。在使用软件包的时候也遇到过不少的坑哈,但是庆幸的是都已经解决了,这里需要感谢一位RT-Thread社区朋友提供的驱动文件,链接在这:[有关lwgps软件包使用问题的社区链接地址](https://club.rt-thread.org/index.php/ask/question/2dcf3494d6930f65.html) 可以直接使用该作者提供的驱动框架。特别需要注意的是:这里有一个小坑,可能很多人会忽略,软件包已经使用了`INIT_APP_EXPORT(lwgps2rtt_init);`添加了lwgps的初始化,因此不需要在应用层调用,如果调用会出现我之前出现的报错信息: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/ae541eedd81a6aa286b4aac895e0ee55.png.webp) 完成软件包添加后可利用Finsh组件输入`lwgps_example`命令,查看官方给出的example,它的位置是在lwgps软件包的example.c中: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/c40e86824bb5e5ba5a729b70784dd95b.png.webp) **在应用层使用lwgps软件包** 类似于AHT10线程创建一样简单,直接使用create动态创建GPS数据采集线程: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/889099399d45ea4e79a4388ca7bb062a.png.webp) 线程入口函数如下: ```c static void getGps_thread_entry() { lwgps_t gps_info; struct gps_msg gpsmsg; float lati , longi; rt_err_t res; // res = rt_sem_take(send_Gps_sem, RT_WAITING_FOREVER); // if(res != RT_EOK) // { // rt_kprintf("getGps_thread take a nb semaphore, failed.\n"); // return; // } while(1) { lwgps2rtt_get_gps_info(&gps_info); gpsmsg.lati_value=(gps_info.latitude); gpsmsg.longi_value=(gps_info.longitude); gpsmsg.hour=(gps_info.hours); // rt_kprintf("GPS-Data:hour-->%d\r\n",gpsmsg.hour); rt_mq_send(gps_msg_mq,&gpsmsg,sizeof(gpsmsg)); rt_thread_delay(500); } } ``` ## 使用PIN设备——MQ2数据采集 关于MQ2的数据读取,并没有使用到ADC设备,因为我想缩短开发周期赶论文┭┮﹏┭┮。我选用的是MQ2的DO输出模式,通过调整电位器设置阈值,实现原理比较简单哈,不再赘述。同时,它的软件读取工作也比较简单。但是由于项目实时性要求,上行数据流是采用JSON封装的,方便小程序端解析,所以需要持续发送采集数据,因此无论是检测到可燃气体还是没有检测到都要发送消息队列。 详细代码如下: ```c static void test_thread_entry() { char TR_ARRAY[]="true"; char FA_ARRAY[]="false"; struct mq_msg mq2_msg; while(1) { // rt_kprintf("test\r\n"); if(rt_pin_read(MQ2_PIN_NUM)==PIN_LOW) { memcpy(mq2_msg.msg,TR_ARRAY,sizeof(TR_ARRAY)); rt_mq_send(mq2_msg_mq,&mq2_msg,sizeof(mq2_msg)); rt_pin_write(BEEP_PIN_NUM, PIN_HIGH); rt_thread_mdelay(500); rt_pin_write(BEEP_PIN_NUM, PIN_LOW); } else{ memcpy(mq2_msg.msg,FA_ARRAY,sizeof(FA_ARRAY)); rt_mq_send(mq2_msg_mq,&mq2_msg,sizeof(mq2_msg)); } rt_thread_mdelay(200); } } ``` ## 使用PIN设备——红外对射数据采集 红外模块采用的“消抖”操作,因为有可能车门位置经过的人会一直停留,所以按照按键消抖处理的,详细的流程不再说明,直接上代码了: ```c /* 红外检测线程入口函数*/ static void hw_thread_entry(void *parameter) { static rt_uint8_t hw_up = 1; /* 无人标志 */ /* 初始化红外对射模块 */ rt_pin_mode(PIN_NUM_ADD, PIN_MODE_INPUT); rt_pin_mode(PIN_NUM_SUB, PIN_MODE_INPUT); rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT); tmp_msg_mb = rt_mb_create("temp_mb0", MB_LEN, RT_IPC_FLAG_FIFO); while (1) { /* 检测无人标志 */ if (hw_up && ((rt_pin_read(PIN_NUM_ADD) == PIN_LOW) || (rt_pin_read(PIN_NUM_SUB) == PIN_LOW))) { rt_thread_mdelay(50); /* 延时消抖*/ hw_up = 0; if (rt_pin_read(PIN_NUM_SUB) == PIN_LOW) { rt_kprintf("Having person-SUB!\n"); rt_pin_write(LED0_PIN, PIN_HIGH); if(people_num<=0) { rt_kprintf("The number of people is empty\n"); continue; } else{ people_num--; rt_kprintf("The num of people is %d\r\n",people_num); //rt_mb_send(tmp_msg_mb,people_num); // rt_mb_send(tmp_msg_mb,people_num); } } else if (rt_pin_read(PIN_NUM_ADD) == PIN_LOW) { rt_kprintf("Having person-ADD!\n"); rt_pin_write(LED0_PIN, PIN_LOW);//点亮 if(people_num>=30) { rt_kprintf("The number of people is full!\n"); continue; } else{ people_num++; rt_kprintf("The num of people is %d\r\n",people_num); // rt_mb_send(tmp_msg_mb,people_num); } } } else if((rt_pin_read(PIN_NUM_ADD) == PIN_HIGH) && (rt_pin_read(PIN_NUM_SUB) == PIN_HIGH)) { hw_up = 1; /*无人标志 */ // rt_mb_send(tmp_msg_mb,people_num); } rt_mb_send(tmp_msg_mb,people_num); rt_thread_mdelay(100); } } ``` ## 使用AT设备——NB模块初始化与NB模块数据发送 首先需要在项目中添加AT组件,同时添加M5311软件包,添加完成后,在应用层main线程中开启NB初始化以及NB订阅和发送线程(采用MQTT协议) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230603/4ca722e242c5171c1fcd8caaa9a765da.png.webp) 初始化线程入口函数如下: ```c //NB初始化线程:新建MQTT机制+连接MQTT服务器 static void NB_mqtt_thread_entery() { nb_client = at_client_get("uart2"); nb_resp = at_create_resp(1024, 0, rt_tick_from_millisecond(300)); if(at_obj_exec_cmd(nb_client,nb_resp,arv)!=RT_EOK) { LOG_E("The MQTT haven't inited success\r\n"); } else{ LOG_E("MQTT HAVE INITED SUCCESS\r\n"); if(at_obj_exec_cmd(nb_client,nb_resp,"AT+MQTTOPEN=1,1,0,0,0,'',''")!=RT_EOK) { LOG_E("The MQTT haven't inited success\r\n"); } else{//真正完成了新建MQTT机制和连接服务器 LOG_E("The MQTT haven inited success\r\n"); rt_pin_write(BEEP_PIN_NUM, PIN_HIGH); rt_thread_mdelay(500); rt_pin_write(BEEP_PIN_NUM, PIN_LOW); rt_sem_release(nb_sem);//释放信号量 rt_sem_release(send_Gps_sem); rt_sem_release(send_AHT_sem); } } rt_thread_mdelay(1000); } ``` 订阅和发送线程入口函数如下: ```c static void NB_mqtt_send_thread_entery() { struct tmp_msg msg; struct gps_msg GPS; struct mq_msg mq2msg; static rt_err_t result; int pep_num=0; result = rt_sem_take(nb_sem, RT_WAITING_FOREVER); if(result != RT_EOK) { rt_kprintf("NB_mqtt_send_thread take a nb semaphore, failed.\n"); return; }else{ for(;;) { if(at_obj_exec_cmd(nb_client,nb_resp,"AT+MQTTSUB=\"pyr\",1")==RT_EOK)//订阅主题 { rt_kprintf("The NB-IoT have subscribed the pyr topic\r\n"); break; } } while(1) { if((rt_mq_recv(gps_msg_mq,&GPS,sizeof(GPS),RT_WAITING_FOREVER)==RT_EOK)&& (rt_mq_recv(tmp_msg_mq, &msg, sizeof(msg), RT_WAITING_FOREVER)==RT_EOK)&& (rt_mq_recv(mq2_msg_mq, &mq2msg, sizeof(mq2msg), RT_WAITING_FOREVER)==RT_EOK)&& (rt_mb_recv(tmp_msg_mb,(int*)&pep_num,RT_WAITING_FOREVER)==RT_EOK)) { rt_kprintf("---------->NB Send Thread Receive the data-hour:%d,tmp:%d,mq2:%s,pep_num:%d\r\n",GPS.hour,msg.temp_value,mq2msg.msg,pep_num); if(at_obj_exec_cmd(nb_client,nb_resp,"AT+MQTTPUB=\"pyr\",1,1,0,0,\"{\"temp\":%d,\"hum\":%d,\"lati\":%f,\"longi\":%f,\"mq2\":%s,\"pep_num\":%d}\"",msg.temp_value,msg.humi_value,GPS.lati_value,GPS.longi_value,mq2msg.msg,pep_num)!=RT_EOK) { LOG_E("Send the MEssage of the MQTT failed\r\n"); } // if(at_obj_exec_cmd(nb_client,nb_resp,"AT+MQTTPUB=\"pyr\",1,1,0,0,\"{\"latitude\":37.3862770000,\"longitude\":117.9898270000,\"temp\":23,\"humi\":60,\"person\":15,\"smoke\":false}\"")!=RT_EOK) // { // LOG_E("Send the MEssage of the MQTT failed\r\n"); // } } rt_thread_mdelay(500); // rt_thread_mdelay(1000); 有延时,所以采用0.5S-Debug测出来的 } } } ``` # 项目软件开发总结 项目的应用软件使用的是微信小程序,涉及到的内容包括:小程序适配MQTT客户端连接服务器以及订阅和发布消息、小程序云开发模式Serverless、小程序使用Map组件、小程序使用腾讯云SMS服务(个人版)、小程序实现左滑删除样式等内容... ...另外,MQTT服务器使用的是EMQ搭建的免费版MQTT服务器。 这是使用的MQTT地址,目前仍然可以使用:[EMQ服务器IP地址](https://123.60.181.106) ,支持端口号18083、8083、8084、18084访问,同时提供匿名访问 微信小程序的具体实现比较简单,这里不再赘述,详细的内容参见代码即可 另外,本项目涉及的所有代码全部开源,请自行获取:[Gitee库地址](https://gitee.com/lhzstudio/graduation_-design/blob/master/) 欢迎大佬们批评指正~
3
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
Agony_L
这家伙很懒,什么也没写!
文章
1
回答
11
被采纳
0
关注TA
发私信
相关文章
1
umqtt 软件包使用后,连接上emqx服务器,过一会儿就掉线了
2
使用正点原子的 潘多拉 开发板 的例程19_iot_mqtt
3
mqtt软件包,不支持直接关闭?
4
kawaii_mqtt 申请内存崩溃
5
_signal_entry() 函数中dbg_enter在哪里定义呢?
6
start to connect mqtt server 失败
7
MQTT 在“ read 0:1, break “后断开重连
8
paho_mqtt线程相关疑问
9
RT thread studio kawaii mqtt 无法连接EMQ
10
调试bc26 ,断言错误failed at rt_thread_timeout
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
SFUD
msh
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1443
个答案
289
次被采纳
张世争
805
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部