Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
内核学习营
AP6181
RT-Thread学习的综合应用-使用AP6181对接OneNET应用
发布于 2019-03-18 17:13:50 浏览:2499
订阅该版
[tocm] # RT-Thread学习的综合应用——使用AP6181 WiFi模组对接OneNET应用示例 >学习了RT-Thread的内核也有一段时间了,由于各种各样的琐事自己没有去做一个综合应用示例,刚最近有点时间,做了一个对接OneNET的历程,采用的是OneNET的EDP协议,关于OneNET的EDP协议可以[点击跳转至OneNET EDP协议讲解与应用](https://blog.csdn.net/Sanjay_Wu/article/details/84800189)这篇博客看一下,这篇博客会比较详细的介绍对接EDP协议的思路。本篇博客会根据着重的将RT-Thread的应用思路,在本应用示例也只是用来软件定时器、线程管理、信号量而已,因为我用的是潘多拉开发板进行实验,所以AP6181驱动就直接用RT-Thread的,自己也只是在这个基础上做了应用。 >使用AP6181 WiFi模组对接OneNET应用示例:STM32+AP6181(SDIO WiFi模组)对接OneNET,实现温湿度定时上报,控制上报周期、控制设备LED灯、蜂鸣器以及电机,掉线自动连接、WiFi自动连接。 ## 整个工程代码 [点击跳转至GitHub获取](https://github.com/sanjaywu/IoT_Board_OneNET_Demo)。 ## 一、移植需要修改的地方 在移植时,主要也就是修改几个地方,代码如下: ```c #define ONENET_EDP_PRODUCT_ID "190254" /* 产品id */ #define ONENET_EDP_PRODUCT_APIKEY "cWPICK6PDU6cOHP=T0SqMcXWRc4=" /* api key */ #define ONENET_EDP_DEVICE_ID "504890772" /* 设备id */ #define ONENET_EDP_DEVICE_AUTHKEY "edp20181122" /* 设备鉴权信息 */ ``` 需要修改的为产品ID、APIKEY、设备ID、设备鉴权信息,将这些信息修改为你自己在OneNET开发者中心的产品信息或设备信息。 ## 二、连接OneNET思路 1、开机后,RT-Thread完成一系列的初始化后进入main线程,首先进入main函数会进行执行`onenet_edp_sample();`函数进行信号量创建、软件定时器创建以及线程创建: ```c rt_err_t onenet_edp_sample(void) { /* 连接OneNET信号量 */ link_onenet_sem = rt_sem_create("link_onenet_sem", 0, RT_IPC_FLAG_FIFO); if(link_onenet_sem == RT_NULL) { rt_kprintf("[EDP]link_onenet_sem create failed
"); return RT_ERROR; } /* 发送心跳信号量 */ send_heart_sem = rt_sem_create("send_heart_sem", 0, RT_IPC_FLAG_FIFO); if(send_heart_sem == RT_NULL) { rt_kprintf("[EDP]send_heart_sem create failed
"); return RT_ERROR; } /* 用于获取温湿度和发送温湿度信号量 */ humi_temp_sem = rt_sem_create("humi_temp_sem", 1, RT_IPC_FLAG_FIFO); if(humi_temp_sem == RT_NULL) { rt_kprintf("[EDP]humi_temp_sem create failed
"); return RT_ERROR; } /* 用于定时触发上报温湿度数据信号量 */ send_humi_temp_sem = rt_sem_create("send_humi_temp_sem", 0, RT_IPC_FLAG_FIFO); if(send_humi_temp_sem == RT_NULL) { rt_kprintf("[EDP]send_humi_temp_sem create failed
"); return RT_ERROR; } /* 软件定时器,周期执行,120秒 */ send_heart_timer = rt_timer_create("send_heart_timer", send_heart_timer_callback, RT_NULL, 120000, RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_PERIODIC); if(send_heart_timer == RT_NULL) { rt_kprintf("[EDP]send_heart_timer create failed
"); return RT_ERROR; } /* 软件定时器,周期执行,300秒 */ send_humi_temp_timer = rt_timer_create("send_humi_temp_timer", send_humi_temp_timer_callback, RT_NULL, 30000, RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_PERIODIC); if(send_humi_temp_timer == RT_NULL) { rt_kprintf("[EDP]send_humi_temp_timer create failed
"); return RT_ERROR; } /* 连接设备线程 */ link_dev_thread = rt_thread_create("link_dev_thread", onenet_edp_link_device_thread, RT_NULL, 2048, 4, 200); if(link_dev_thread == RT_NULL) { rt_kprintf("[EDP]link_dev_thread create failed
"); return RT_ERROR; } rt_thread_startup(link_dev_thread); /* 发送心跳线程 */ send_heart_thread = rt_thread_create("send_heart_thread", onenet_edp_send_heart_thread, RT_NULL, 1024, 4, 50); if(send_heart_thread == RT_NULL) { rt_kprintf("[EDP]send_heart_thread create failed
"); return RT_ERROR; } rt_thread_startup(send_heart_thread); /* 平台下发命令或结果处理线程 */ recv_data_pro_thread = rt_thread_create("recv_data_pro_thread",onenet_edp_receive_process_thread, RT_NULL, 4096, 4, 100); if(recv_data_pro_thread == RT_NULL) { rt_kprintf("[EDP]recv_data_pro_thread create failed
"); return RT_ERROR; } rt_thread_startup(recv_data_pro_thread); /* 获取温湿度数据线程 */ get_humi_temp_thread = rt_thread_create("get_humi_temp_thread", onenet_edp_get_humi_temp_thread, RT_NULL, 4096, 4, 50); if(get_humi_temp_thread == RT_NULL) { rt_kprintf("[EDP]get_humi_temp_thread create failed
"); return RT_ERROR; } rt_thread_startup(get_humi_temp_thread); /* 上报温湿度数据到平台线程 */ send_humi_temp_thread = rt_thread_create("send_humi_temp_thread", onenet_edp_send_humi_temp_thread, RT_NULL, 4096, 4, 100); if(send_humi_temp_thread == RT_NULL) { rt_kprintf("[EDP]send_humi_temp_thread create failed
"); return RT_ERROR; } rt_thread_startup(send_humi_temp_thread); return RT_EOK; } ``` 2、完成信号量创建、软件定时器的线程创建后,会进行注册网络就绪事件回调、网络断开事件回调、以及连接网络、开启自动连接网络: ```c /* 注册网络就绪回调、 */ rt_wlan_register_event_handler(RT_WLAN_EVT_READY, wlan_ready_handler, RT_NULL); /* 注册网络断开事件回调 */ rt_wlan_register_event_handler(RT_WLAN_EVT_STA_DISCONNECTED, wlan_station_disconnect_handler, RT_NULL); /* 连接路由器 */ rt_wlan_connect(WLAN_SSID, WLAN_PASSWORD); rt_thread_mdelay(1000); /* 开启自动连接 */ wlan_autoconnect_init(); rt_wlan_config_autoreconnect(RT_TRUE); ``` 3、网络就绪回调函数用于释放连接OneNET信号量,告诉系统已经有网络了,可以去连接OneNET了: ```c void wlan_ready_handler(int event, struct rt_wlan_buff *buff, void *parameter) { rt_kprintf("wlan ready
"); if(link_onenet_sem != RT_NULL) { rt_sem_release(link_onenet_sem); } } ``` 而另一方面,连接OneNET线程会移植挂起等待连接OneNET的信号量,指导获取到这个信号量才开始去连接OneNET: ```c /************************************************************** 函数名称:onenet_edp_link_device_thread 函数功能:连接OneNET平台设备线程 输入参数:parameter:线程入口参数 返 回 值:无 备 注:WiFi注册上网了后连接平台,连接成功则启动定时器发送心跳 **************************************************************/ void onenet_edp_link_device_thread(void *parameter) { rt_err_t result = RT_ERROR; while(1) { result = rt_sem_take(link_onenet_sem, RT_WAITING_FOREVER); /* 等待时间:一直等 */ if(RT_EOK == result) { #ifdef USING_DEVICEID_APIKEY_LINK onenet_edp_link_device(ONENET_EDP_SRV_ADDR, ONENET_EDP_SRV_PORT, ONENET_EDP_DEVICE_ID, ONENET_EDP_PRODUCT_APIKEY); #else onenet_edp_link_device(ONENET_EDP_SRV_ADDR, ONENET_EDP_SRV_PORT, ONENET_EDP_PRODUCT_ID, ONENET_EDP_DEVICE_AUTHKEY); #endif } rt_thread_mdelay(1); rt_thread_yield();/* 放弃剩余时间片,进行一次线程切换 */ } } ``` ## 三、数据上报和心跳发送思路 1、连接上OneNET之后,处理平台下发命令或结果的线程会得到连接成功返回结果并进行处理,启动软件定时器进行发送心跳和上报数据: ``` case 0: { rt_kprintf("Tips: 连接成功
"); if(send_heart_timer != RT_NULL) { rt_kprintf("[EDP]start send_heart_timer
"); rt_timer_start(send_heart_timer);/* 启动软件定时器定时发送心跳 */ } if(send_humi_temp_timer != RT_NULL) { rt_kprintf("[EDP]start send_humi_temp_timer
"); rt_timer_start(send_humi_temp_timer);/* 启动软件定时器定时上报数据 */ } break; } ``` 2、软件定时器回调函数用于释放发送心跳信号量: ```c /************************************************************** 函数名称:send_heart_timer_callback 函数功能:软件定时器回调函数,用于定时发送信号量来触发发送心跳包 输入参数:parameter:入口参数 返 回 值:无 备 注:无 **************************************************************/ void send_heart_timer_callback(void *parameter) { if(send_heart_timer != RT_NULL) { rt_sem_release(send_heart_sem); } } ``` 3、发送心跳线程获取到信号量之后执行发送心跳操作: ```c /************************************************************** 函数名称:onenet_edp_send_heart_thread 函数功能:发送心跳线程 输入参数:parameter:线程入口参数 返 回 值:无 备 注:无 **************************************************************/ void onenet_edp_send_heart_thread(void *parameter) { rt_err_t result = RT_ERROR; while(1) { result = rt_sem_take(send_heart_sem, RT_WAITING_FOREVER); /* 等待时间:一直等 */ if(RT_EOK == result) { onenet_edp_send_heart(); } rt_thread_mdelay(1); rt_thread_yield();/* 放弃剩余时间片,进行一次线程切换 */ } } ``` 4、同理,上报数据也是等待信号量,一旦获取到就上报数据,为保证数据上报的同步,获取数据与上报数据用来二值信号量,实现代码: ```c /************************************************************** 函数名称:onenet_edp_get_humi_temp_thread 函数功能:获取温湿度数据线程 输入参数:parameter:线程入口参数 返 回 值:无 备 注:无 **************************************************************/ void onenet_edp_get_humi_temp_thread(void *parameter) { rt_err_t result = RT_ERROR; while(1) { result = rt_sem_take(send_humi_temp_sem, RT_WAITING_FOREVER); /* 等待时间:一直等 */ if(RT_EOK == result) { result = rt_sem_take(humi_temp_sem, RT_WAITING_FOREVER); /* 等待时间:一直等 */ if(RT_EOK == result) { aht10_read_data(&g_temperature, &g_humidity); } rt_sem_release(humi_temp_sem); /* 释放信号量 */ } rt_thread_mdelay(1); rt_thread_yield();/* 放弃剩余时间片,进行一次线程切换 */ } } /************************************************************** 函数名称:onenet_edp_send_humi_temp_thread 函数功能:发送温湿度数据线程 输入参数:parameter:线程入口参数 返 回 值:无 备 注:无 **************************************************************/ void onenet_edp_send_humi_temp_thread(void *parameter) { rt_err_t result = RT_ERROR; while(1) { result = rt_sem_take(send_humi_temp_sem, RT_WAITING_FOREVER); /* 等待时间:一直等 */ if(RT_EOK == result) { result = rt_sem_take(humi_temp_sem, RT_WAITING_FOREVER); /* 等待时间:一直等 */ if(RT_EOK == result) { /* 上传温湿度数据到平台 */ if(RT_EOK == onenet_edp_send_data(FORMAT_TYPE3, ONENET_EDP_DEVICE_ID, ONENET_EDP_PRODUCT_APIKEY, humi_temp_data_stream, humi_temp_data_stream_cnt)) { rt_kprintf("Humi_Temp Send success
"); } else { rt_kprintf("Humi_Temp Status Send failed
"); } } rt_sem_release(humi_temp_sem); /* 释放信号量 */ } rt_thread_mdelay(1); rt_thread_yield();/* 放弃剩余时间片,进行一次线程切换 */ } } ``` ## 四、设备断开与网络断开处理 1、如果在有网络的情况下设备突然断开,那么就需要重新连接OneNET了,首先会停止所有定时器、接着重新发送连接OneNET信号量,处理如下: ```c case DISCONNECT: { rt_kprintf("WARN:连接断开,准备重连
"); if(send_heart_timer != RT_NULL) { rt_kprintf("[EDP]stop send_heart_timer
"); rt_timer_stop(send_heart_timer);/* 关闭软件定时器 */ } if(send_humi_temp_timer != RT_NULL) { rt_kprintf("[EDP]stop send_humi_temp_timer
"); rt_timer_stop(send_humi_temp_timer);/* 关闭软件定时器 */ } if(link_onenet_sem != RT_NULL) { rt_sem_release(link_onenet_sem); } break; } ``` 2、如果是网络断开,那么就需要停止软件定时器,处理如下: ```c void wlan_station_disconnect_handler(int event, struct rt_wlan_buff *buff, void *parameter) { rt_kprintf("disconnect from the network!
"); if(send_heart_timer != RT_NULL) { rt_kprintf("[EDP]stop send_heart_timer
"); rt_timer_stop(send_heart_timer);/* 关闭软件定时器 */ } if(send_humi_temp_timer != RT_NULL) { rt_kprintf("[EDP]stop send_humi_temp_timer
"); rt_timer_stop(send_humi_temp_timer);/* 关闭软件定时器 */ } } ``` ## 五、finsh抓取log **1、连接OneNET** ![20190316120049678.png](/uploads/201903/18/182438mf2jmkx75iffzfx7.png)‘’ **2、发送数据到OneNET** ![20190316120324545.png](/uploads/201903/18/182502zk5wv5yhm8oke78l.png) **3、命令下发处理** ![20190316120500474.png](/uploads/201903/18/182520h870af72epca0plc.png) **4、发送心跳** ![20190316120220575.png](/uploads/201903/18/182413c1uplbeiipihpwbh.png) ## 六、在OneNET实现的应用示例 [点击跳转至在OneNET实现的应用](https://open.iot.10086.cn/iotbox/appsquare/appview?openid=8da9012c0dcc77af73399b63a29662d8) ![20190316115745161.png](/uploads/201903/18/182558saf4v4kvpruf0p4w.png)
查看更多
3
个回答
默认排序
按发布时间排序
Sanjay_Wu
2019-03-18
这家伙很懒,什么也没写!
>顶一个~ >不过楼主可以重新上传一下图片呢,图片全部上传失败了,看不到 已经上传
shadowliang
2019-03-19
Hello,world!!!
顶一个~
撰写答案
登录
注册新账号
关注者
0
被浏览
2.5k
关于作者
Sanjay_Wu
这家伙很懒,什么也没写!
提问
13
回答
32
被采纳
0
关注TA
发私信
相关问题
1
【内核学习】rtthread内核移植记录-STM32F103ZET6-HAL库
2
《内核学习营》+水一方+自用STM32F103VC 板RT-Thread内核移植分享
3
《内核学习营》+水一方+项目中创建标准的 RT-Thread工程
4
内核学习营+坦然+探索者stm32f407板子RT-thread循环点亮led灯
5
<内核学习营>+坦然+探索者stm32f407板子RT-thread串口字符点灯
6
<内核学习营>+坦然+探索者stm32f407板子RT-thread的pwm点灯实验
7
<内核学习营>+坦然+探索者stm32f407板子RT-thread串口实验
8
<内核学习营>+坦然+野火stm32f103板子RT-thread读写SD卡实验
9
<内核学习营>+坦然+探索者stm32f407板子RT-thread的RTC闹钟实验
10
【内核学习营】+王秀峰+led_rgb
推荐文章
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组件
最新文章
1
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
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
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
13
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
7
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部