完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
设计了基于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(“rn网络断。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。rn ”); } else if(rt_strstr((char const*)gprs_rx_buffer,“Call Ready”))//模塊重啟 { net_status = CONNECT_NULL; rt_kprintf(“rn模塊重啟。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。rn ”); } else if(rt_strstr((char const*)gprs_rx_buffer,“+CPIN: NOT READY”))//卡被拔出 { net_status = CONNECT_ERROR; rt_kprintf(“rn卡被拔出。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。rn ”); } else if(rt_strstr((char const*)gprs_rx_buffer,“$MYURCACT: 0,0”))//網絡斷開 { net_status = CONNECT_DISCONNECT; rt_kprintf(“rn网络断开。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。rn ”); } 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(“nIMSI = :%sn” ,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(”nIMEI = :%sn“ ,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(”n DBM = %dn“ ,dbm); rt_kprintf(”n RSSI = %02x%02xn“ ,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(”rn收到网络数据!rn“); } } 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平台的例程,每个example下的 applications中,都有一个对应的 test**** 文件。该文件中,全部使用的finsh 在串口控制中操作。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1298 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1310 浏览 1 评论
721 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
531 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1327 浏览 2 评论
1727浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
435浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
390浏览 3评论
378浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
357浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-9-20 13:56 , Processed in 0.980126 second(s), Total 45, Slave 40 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号