設計了基于STM32F107設計的數據采集器,實現多種數據(串口、CAN口)采集處理后通過 GPRS模塊 無線上傳。重點編寫了CAN設備驅動; 使用設備方式實現GPRS模塊串口數據的上傳下載;最后提出了使用線程過程中出現的一些問題。
一、 功能分析
系統功能如圖1 所示,不算太復雜。由于下級傳感器模塊的上報的數據內容很多,導致編寫處理程序內容較多。
二、CAN驅動編寫
為了模塊化地處理傳感器的主動上報數據,CAN設備不再用以前的中斷處理,而是采用了RTT的設備框架,重新編寫了device的驅動。研究RTT里的CAN總線收發設備:
發現只有框架,沒有內容。就仿著串口寫一個candevice。研究組件使用 中的串口驅動:
這是一個讀代碼的過程,弄清楚框架后,編寫類似于linux中的驅動編寫。
以上程序全部寫好后,就可以使用設備通用操作函數來操作CAN。在主程序中首先要初始化設備,再注冊設備。
三、設備方式實現串口數據處理
GPRS模塊使用實際上是串口數據的收到處理。首先創建gprswatch進程,用來監控串口接收數據。
void gprswatch(void){ rt_thread_t thread; thread = rt_thread_find("gprswatch"); if( thread != RT_NULL) rt_thread_delete(thread); /* 創建gprswatch線程*/ thread = rt_thread_create("gprswatch", gprswatch_entry, RT_NULL, 0x1000, 0x12, 200); /* 創建成功則啟動線程*/ if( thread != RT_NULL) { rt_thread_startup(thread); //rt_thread_delay(RT_TICK_PER_SECOND/2); } }
監視GPRS串口線程中,當收到串口數據后,接收并分析,置位網絡狀態。
/* 監視GPRS串口線程入口*/void gprswatch_entry(void* parameter){ rt_err_t result = RT_EOK; rt_uint32_t event; unsigned char gprs_rx_buffer[GPRS_RX_LEN]={0x00}; while(1) { result = rt_event_recv(&rev_event, REV_MASK, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &event); if (result == RT_EOK) { if (event & REV_DATA) { rt_memset(gprs_rx_buffer,0x00,sizeof(gprs_rx_buffer)); rt_thread_delay(RT_TICK_PER_SECOND/10); rt_device_read(gprs_device, 0, gprs_rx_buffer, GPRS_RX_LEN); rt_kprintf(gprs_rx_buffer); /*監視GPRS模塊接收數據*/ if(rt_strstr((char const*)gprs_rx_buffer,"MYURCCLOSE: 0"))//網絡斷 { net_status = CONNECT_ERROR; rt_kprintf(" 網絡斷。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 "); } else if(rt_strstr((char const*)gprs_rx_buffer,"Call Ready"))//模塊重啟 { net_status = CONNECT_NULL; rt_kprintf(" 模塊重啟。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 "); } else if(rt_strstr((char const*)gprs_rx_buffer,"+CPIN: NOT READY"))//卡被拔出 { net_status = CONNECT_ERROR; rt_kprintf(" 卡被拔出。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 "); } else if(rt_strstr((char const*)gprs_rx_buffer,"$MYURCACT: 0,0"))//網絡斷開 { net_status = CONNECT_DISCONNECT; rt_kprintf(" 網絡斷開。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 "); } else if(rt_strstr((char const*)gprs_rx_buffer,"MYURCREAD: 0"))//有網絡數據 { net_status = CONNECT_GPRSDATAIN; } else if(rt_strstr((char const*)gprs_rx_buffer,"+CMTI:"))//有短信來 { net_status = CONNECT_MSGDATAIN; } else { } } if (event & REV_STOPWATCH) { return; } } }}
在程序其它地方完成對應GPRS模塊的監控和操作。對GPRS模塊讀和寫操作也編寫了一個設備操作函數,主要是利用前面編寫的gprswatch線程操作:
/*GPRS模塊發送和接收*/rt_bool_t gprs_send_data_package(unsigned char *cmd,char *ack,rt_uint32_t waittime, rt_uint8_t retrytime, rt_uint32_t len){ rt_bool_t res = RT_FALSE; rt_err_t result = RT_EOK; rt_uint32_t event; unsigned char gprs_rx_buffer[GPRS_RX_LEN]={0x00}; rt_thread_t thread; thread = rt_thread_find("gprswatch"); if( thread != RT_NULL) { rt_thread_delete(thread); } do { rt_device_write(gprs_device, 0, cmd, len); result = rt_event_recv(&rev_event, REV_MASK, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, waittime*RT_TICK_PER_SECOND, &event); if (result == RT_EOK) { if (event & REV_DATA) { rt_memset(gprs_rx_buffer,0x00,sizeof(gprs_rx_buffer)); rt_thread_delay(RT_TICK_PER_SECOND/2); rt_device_read(gprs_device, 0, gprs_rx_buffer, GPRS_RX_LEN); rt_kprintf(gprs_rx_buffer); if(rt_strstr(cmd,MSG_IMSI))//如果是讀IMSI 解析出IMSI數據 { unsigned char *addr; addr = rt_strstr((char const*)gprs_rx_buffer,"AT+CIMI")+10; if(addr!=NULL) { strncpy(&imsi[0],addr,15); rt_kprintf(" IMSI = :%s " ,imsi); } } if(rt_strstr(cmd,MSG_IMEI))//如果是讀IMEI 解析出IMEI數據 { unsigned char *addr; addr = rt_strstr((char const*)gprs_rx_buffer,""")+1; if(addr!=NULL) { strncpy(&imei[0],addr,15); rt_kprintf(" IMEI = :%s " ,imei); } } if(rt_strstr(cmd,CSQ_CMD))//如果是讀CSQ 解析出dbm數據 { unsigned char csq[5] = {0x00}; unsigned char *addr; rt_int16_t dbm; addr = rt_strstr((char const*)gprs_rx_buffer,",") - 3; rt_strncpy(csq, addr,3); if(addr!=NULL) { dbm = 2* atoi(csq) - 109; dbm_data[0] = dbm; dbm_data[1] = dbm>>8; rt_kprintf(" DBM = %d " ,dbm); rt_kprintf(" RSSI = %02x%02x " ,dbm_data[0],dbm_data[1]); } } if((rt_strstr(gprs_rx_buffer,ack))||(rt_strstr(gprs_rx_buffer,"OK"))) { res = RT_TRUE; if(rt_strstr(cmd,MG323_READ_CMD))//如果是讀數據命令,將數據拷出 { rt_memcpy(gprs_rx_data, gprs_rx_buffer, GPRS_RX_LEN); } } else res = RT_FALSE; } if(rt_strstr((char const*)gprs_rx_buffer,"MYURCREAD: 0"))//有網絡數據 { net_status = CONNECT_GPRSDATAIN; rt_kprintf(" 收到網絡數據! "); } } retrytime--; }while((!res)&&(retrytime>=1)); gprswatch(); return res;}
至此,基本實現了GPRS模塊的設備操作。
四、調試過程中的經驗
1.進程初始化及分配內存
在RTT工程中,int rt_application_init(void) 函數給出了一個最基本的使用方法,動態創建線程rt_thread_create,動態分配內存。在程序編寫的過程,由于內存太小,不得不心劃分分配的內存。手冊建議在程序運行過程中使用命令查看線程的占用內存,再按經驗分內存,這樣操作,還是地調試過程中出現很多次錯誤。后來再翻看手冊,仿造例子修改程序為靜態分配內存的線程創建,rt_thread_init,上面的錯誤就不再出現了。
2.使用finsh
在調試過程中大量使用了finsh, 極大地方便了調試。
引用用戶手冊的說明:編寫了一個函數,如果不在程序中運行,便可以將此函數引出到finsh中。
在串口控制臺中操作,就可以很方便地實現GPRS相關函數的調試,而并需要在主程序中運行以上函數。
3.RTT例程的格式
編寫了基于RTT的 STM32F107平臺的例程,發布在github上:https://github.com/sundm75/STM32F107Board-rttproject每個example下的 applications中,都有一個對應的 test**** 文件。該文件中,全部使用的finsh 在串口控制中操作。
- End -
-
STM32
+關注
關注
2270文章
10915瀏覽量
356754 -
數據采集器
+關注
關注
1文章
141瀏覽量
14955 -
rt_thread
+關注
關注
2文章
13瀏覽量
14661
原文標題:基于STM32F107與RT-Thread設計的數據采集器
文章出處:【微信號:RTThread,微信公眾號:RTThread物聯網操作系統】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論