設(shè)計(jì)了基于STM32F107設(shè)計(jì)的數(shù)據(jù)采集器,實(shí)現(xiàn)多種數(shù)據(jù)(串口、CAN口)采集處理后通過 GPRS模塊 無線上傳。重點(diǎn)編寫了CAN設(shè)備驅(qū)動(dòng); 使用設(shè)備方式實(shí)現(xiàn)GPRS模塊串口數(shù)據(jù)的上傳下載;最后提出了使用線程過程中出現(xiàn)的一些問題。
一、 功能分析
系統(tǒng)功能如圖1 所示,不算太復(fù)雜。由于下級(jí)傳感器模塊的上報(bào)的數(shù)據(jù)內(nèi)容很多,導(dǎo)致編寫處理程序內(nèi)容較多。
二、CAN驅(qū)動(dòng)編寫
為了模塊化地處理傳感器的主動(dòng)上報(bào)數(shù)據(jù),CAN設(shè)備不再用以前的中斷處理,而是采用了RTT的設(shè)備框架,重新編寫了device的驅(qū)動(dòng)。研究RTT里的CAN總線收發(fā)設(shè)備:
發(fā)現(xiàn)只有框架,沒有內(nèi)容。就仿著串口寫一個(gè)candevice。研究組件使用 中的串口驅(qū)動(dòng):
這是一個(gè)讀代碼的過程,弄清楚框架后,編寫類似于linux中的驅(qū)動(dòng)編寫。
以上程序全部寫好后,就可以使用設(shè)備通用操作函數(shù)來操作CAN。在主程序中首先要初始化設(shè)備,再注冊設(shè)備。
三、設(shè)備方式實(shí)現(xiàn)串口數(shù)據(jù)處理
GPRS模塊使用實(shí)際上是串口數(shù)據(jù)的收到處理。首先創(chuàng)建gprswatch進(jìn)程,用來監(jiān)控串口接收數(shù)據(jù)。
void gprswatch(void){ rt_thread_t thread; thread = rt_thread_find("gprswatch"); if( thread != RT_NULL) rt_thread_delete(thread); /* 創(chuàng)建gprswatch線程*/ thread = rt_thread_create("gprswatch", gprswatch_entry, RT_NULL, 0x1000, 0x12, 200); /* 創(chuàng)建成功則啟動(dòng)線程*/ if( thread != RT_NULL) { rt_thread_startup(thread); //rt_thread_delay(RT_TICK_PER_SECOND/2); } }
監(jiān)視GPRS串口線程中,當(dāng)收到串口數(shù)據(jù)后,接收并分析,置位網(wǎng)絡(luò)狀態(tài)。
/* 監(jiān)視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); /*監(jiān)視GPRS模塊接收數(shù)據(jù)*/ if(rt_strstr((char const*)gprs_rx_buffer,"MYURCCLOSE: 0"))//網(wǎng)絡(luò)斷 { net_status = CONNECT_ERROR; rt_kprintf(" 網(wǎng)絡(luò)斷。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 "); } 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"))//網(wǎng)絡(luò)斷開 { net_status = CONNECT_DISCONNECT; rt_kprintf(" 網(wǎng)絡(luò)斷開。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 "); } else if(rt_strstr((char const*)gprs_rx_buffer,"MYURCREAD: 0"))//有網(wǎng)絡(luò)數(shù)據(jù) { net_status = CONNECT_GPRSDATAIN; } else if(rt_strstr((char const*)gprs_rx_buffer,"+CMTI:"))//有短信來 { net_status = CONNECT_MSGDATAIN; } else { } } if (event & REV_STOPWATCH) { return; } } }}
在程序其它地方完成對(duì)應(yīng)GPRS模塊的監(jiān)控和操作。對(duì)GPRS模塊讀和寫操作也編寫了一個(gè)設(shè)備操作函數(shù),主要是利用前面編寫的gprswatch線程操作:
/*GPRS模塊發(fā)送和接收*/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數(shù)據(jù) { 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數(shù)據(jù) { 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數(shù)據(jù) { 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))//如果是讀數(shù)據(jù)命令,將數(shù)據(jù)拷出 { 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"))//有網(wǎng)絡(luò)數(shù)據(jù) { net_status = CONNECT_GPRSDATAIN; rt_kprintf(" 收到網(wǎng)絡(luò)數(shù)據(jù)! "); } } retrytime--; }while((!res)&&(retrytime>=1)); gprswatch(); return res;}
至此,基本實(shí)現(xiàn)了GPRS模塊的設(shè)備操作。
四、調(diào)試過程中的經(jīng)驗(yàn)
1.進(jìn)程初始化及分配內(nèi)存
在RTT工程中,int rt_application_init(void) 函數(shù)給出了一個(gè)最基本的使用方法,動(dòng)態(tài)創(chuàng)建線程rt_thread_create,動(dòng)態(tài)分配內(nèi)存。在程序編寫的過程,由于內(nèi)存太小,不得不心劃分分配的內(nèi)存。手冊建議在程序運(yùn)行過程中使用命令查看線程的占用內(nèi)存,再按經(jīng)驗(yàn)分內(nèi)存,這樣操作,還是地調(diào)試過程中出現(xiàn)很多次錯(cuò)誤。后來再翻看手冊,仿造例子修改程序?yàn)殪o態(tài)分配內(nèi)存的線程創(chuàng)建,rt_thread_init,上面的錯(cuò)誤就不再出現(xiàn)了。
2.使用finsh
在調(diào)試過程中大量使用了finsh, 極大地方便了調(diào)試。
引用用戶手冊的說明:編寫了一個(gè)函數(shù),如果不在程序中運(yùn)行,便可以將此函數(shù)引出到finsh中。
在串口控制臺(tái)中操作,就可以很方便地實(shí)現(xiàn)GPRS相關(guān)函數(shù)的調(diào)試,而并需要在主程序中運(yùn)行以上函數(shù)。
3.RTT例程的格式
編寫了基于RTT的 STM32F107平臺(tái)的例程,發(fā)布在github上:https://github.com/sundm75/STM32F107Board-rttproject每個(gè)example下的 applications中,都有一個(gè)對(duì)應(yīng)的 test**** 文件。該文件中,全部使用的finsh 在串口控制中操作。
- End -
-
STM32
+關(guān)注
關(guān)注
2270文章
10910瀏覽量
356615 -
數(shù)據(jù)采集器
+關(guān)注
關(guān)注
1文章
141瀏覽量
14951 -
rt_thread
+關(guān)注
關(guān)注
2文章
13瀏覽量
14660
原文標(biāo)題:基于STM32F107與RT-Thread設(shè)計(jì)的數(shù)據(jù)采集器
文章出處:【微信號(hào):RTThread,微信公眾號(hào):RTThread物聯(lián)網(wǎng)操作系統(tǒng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論