概述:
這是一個數(shù)據(jù)采集的裝置,本身沒有什么亮點。主要是基于RT-Thread操作系統(tǒng),驅動NB模塊-BC26來實現(xiàn)數(shù)據(jù)的發(fā)送。值得一說的是RT-Thread本身有BC-26的驅動包。不過這里并沒有使用,而是使用at-device軟件包來驅動的BC26。因此稍微改一改內部的代碼,就能驅動其他的AT設備。話回正題,我使用at-thread的目的就是驅動BC26建立TCP或UDP連接,使得板卡采集得到的數(shù)據(jù)能發(fā)送到我電腦上的TCP Server。當然,除了數(shù)據(jù)上傳之外,也能實現(xiàn)上位機控制板卡。還有則是在代碼中發(fā)現(xiàn)利用郵箱+消息隊列來進行數(shù)據(jù)傳輸和通信真的很爽。
開發(fā)環(huán)境:
- 硬件部分
- ART-Pi (主控)
- BC-26 (NB-IOT模塊)
- BHT11 (溫濕度傳感器)
- RT-Thread版本
- RT-Thread V4.0.2
- 開發(fā)工具及版本
- RT-Thread Studio V2.0.0 :RT-thread推出的IDE,免費。
- Putty V0.73:開源免費的一款工具,我純把他當成串口助手使用
- 花生殼 V5 :內網(wǎng)穿透工具。
- 網(wǎng)絡調試助手(MetAssist V4.3.13):網(wǎng)上下的,應該比較出名。
RT-Thread使用情況描述:
- 內核部分
- 調度器
- 消息隊列
- 郵箱
- 組件部分
- at_device
- UART
硬件框架描述
先附圖一張:
很簡單的一個框架,總共只有主控,傳感器,執(zhí)行器,以及比較重要的云平臺,這四大部分。傳感器可以是任意傳感器,只要發(fā)送的數(shù)值種類不一次性超出兩種即可。執(zhí)行器我在這里使用了板載的LED燈充當。云平臺則是利用網(wǎng)絡調試助手搭了一個TCP Server來充當。由于我個人沒有固定外網(wǎng)IP,所以我如果直接使用網(wǎng)絡助手,是無法將ART采集得到的數(shù)據(jù)傳輸?shù)轿业碾娔X上的。因此我利用花生殼將我的IP映射到了外網(wǎng),使得板卡能連接到我創(chuàng)建的TCP Server上。
軟件框架說明
流程圖如下:
本人并不是很會畫流程圖,所以辛苦大家看一看介紹吧。
其實在這個板卡中是要燒兩套程序的,一套是bootloader負責初始化QSPI并且運行QSPI內的程序。所以這份程序是下載到片內Flash的。另一份則是具體的功能添加的比較多的程序。他是運行在QSPI中的。這兩個程序必須先運行BootLoader否則QSPI中的程序是無法運行的。而由于BootLoader的職責是讓程序從 0x08000000
跳轉到0x90000000
運行所以,如果QSPI中沒有其他程序的話,Bootloader只會運行一次,表現(xiàn)的現(xiàn)象就是只打印一個LOGO。
其實在RT-Thread中其實有BC26的驅動包,可以直接拿來用,不需要自己再對BC26進行初始化,但是我這里使用的是at_device驅動包,所以自己要寫一部分的代碼,進行初始化。創(chuàng)建郵箱和消息隊列則是為了兩者相互配合一起實現(xiàn)發(fā)送同步消息的功能。
數(shù)據(jù)采集線程和數(shù)據(jù)發(fā)送線程之間使用消息隊列+郵箱的方式實現(xiàn)消息同步,在這里數(shù)據(jù)采集線程可以有多個,而數(shù)據(jù)發(fā)送線程我這設立了一個。發(fā)送線程會將接收到的信息都發(fā)送到云平臺中。
數(shù)據(jù)接收則是利用at_device中的代碼實現(xiàn)的。利用內部的代碼還可實現(xiàn)云平臺發(fā)送消息控制板卡上的LED燈或者其他執(zhí)行器。
軟件模塊說明
- 消息隊列+郵箱的消息同步方式
在使用消息隊列+郵箱的方式來進行線程間消息同步的話需要先創(chuàng)建一個結構體,一個動態(tài)郵箱,一個消息隊列。然后對結構體進行填充后利用消息隊列發(fā)送出去,具體請看以下代碼示例:
//創(chuàng)建結構體部分
struct msg //消息隊列發(fā)送此結構體的地址來實現(xiàn)線程間的同步
{
char *str;
int vol;
float data1;
int data2;
struct rt_mailbox* ack;
};//創(chuàng)建動態(tài)郵箱部分
rt_mailbox_t mail_box1 = RT_NULL; //創(chuàng)建二氧化氮線程應答郵箱控制塊
rt_mailbox_t mail_box2 = RT_NULL; //創(chuàng)建二氧化硫線程應答郵箱控制塊
rt_mailbox_t mail_box3 = RT_NULL; //創(chuàng)建粉塵數(shù)據(jù)線程應答郵箱控制塊
rt_mailbox_t mail_box4 = RT_NULL; //創(chuàng)建備用線程郵箱控制塊/**************創(chuàng)建多個應答郵箱******************/
int move_mail_box_sample(void)
{
mail_box1 = rt_mb_create("mail_box1", 1, RT_IPC_FLAG_FIFO); //創(chuàng)建動態(tài)郵箱1
mail_box2 = rt_mb_create("mail_box2", 4, RT_IPC_FLAG_FIFO); //創(chuàng)建動態(tài)郵箱1
mail_box3 = rt_mb_create("mail_box3", 4, RT_IPC_FLAG_FIFO); //創(chuàng)建動態(tài)郵箱1
mail_box4 = rt_mb_create("mail_box1", 4, RT_IPC_FLAG_FIFO); //創(chuàng)建動態(tài)郵箱1
}//填充發(fā)送
struct msg msage;
msage.str = "NO2";
msage.data1 = data1;
msage.ack = mail_box1;result = rt_mq_send(&mq,&msage, sizeof(struct msg)); //發(fā)送消息隊列
if(result != RT_EOK)
{
rt_kprintf("消息發(fā)送失敗rn");
}//接收處理
LOG_I("準備接收各個數(shù)據(jù)rn");
data_send = at_create_resp(128, 0, rt_tick_from_millisecond(5000)); //分配內存,并設定超時接收時間.準備接收消息隊列
if (data_send == RT_NULL)
LOG_E("響應結構沒有內存!");if(rt_mq_recv(&mq, &msage, sizeof(struct msg), RT_WAITING_FOREVER) == RT_EOK) /**接收消息隊列**/
{
rt_kprintf("收到信息:%srn",msage.str);
linshi = (int)msage.data1 *10;
rt_kprintf("收到發(fā)送的消息%drn",linshi);
抱歉,第一次寫,不知道重點在哪,先這樣吧。
演示效果
- 圖片
- 視頻
比賽感悟
首先非常感謝舉辦方舉辦的這場比賽,這也是我第一次參加這樣的比賽,也正是此次比賽讓我認識到了和同齡人的差距,也讓我感受到了這么多的奇思妙想。很多參賽者的構思和實力令我嘆為觀止。我個人是沒有做過什么項目的,也沒進行過系統(tǒng)的學習,RT-thread對我來講也是一個接觸沒多久的新事物。我對其也只是會使用一些皮毛。從大一到現(xiàn)在也只是接觸一些PLC和電動機。對于ARM都是憑著一份愛好去做。一直以來沒有什么眼界和想法。通過這次比賽我發(fā)現(xiàn),它的能力超出了我的想象。對我指明了一點前進的方向。并且在使用RT-Thread的過程中,我發(fā)現(xiàn)編程并不像以前那么復雜了。在使用RT-Thread的時候我可以不再考慮怎樣實現(xiàn)一個模塊的驅動,而是將重點放到了邏輯上,這對來講還是比較新奇的。最后其實是想對官方人員道個歉的,畢竟這款作品由于時間的原因,并沒有進行細改,而是一個趕出來的作品。沒有擺正心態(tài),真的很抱歉。