基于STM32F107与RT

编程入门 行业动态 更新时间:2024-10-23 17:26:48

基于STM32F107与<a href=https://www.elefans.com/category/jswz/34/1767001.html style=RT"/>

基于STM32F107与RT

作者

孙冬梅:南京工业大学自动化与电气工程学院博士、副教授,资深RT-Thread开发者

欢迎给RT-Thread投稿,获赠RT-Thread T恤一件。

征稿 | 你写不写,福利就在这里~~


设计了基于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("\r\n网络断。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。\r\n ");}else if(rt_strstr((char const*)gprs_rx_buffer,"Call Ready"))//模塊重啟{net_status = CONNECT_NULL;rt_kprintf("\r\n模塊重啟。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。\r\n ");}else if(rt_strstr((char const*)gprs_rx_buffer,"+CPIN: NOT READY"))//卡被拔出{net_status = CONNECT_ERROR;rt_kprintf("\r\n卡被拔出。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。\r\n ");}else if(rt_strstr((char const*)gprs_rx_buffer,"$MYURCACT: 0,0"))//網絡斷開{net_status = CONNECT_DISCONNECT;rt_kprintf("\r\n网络断开。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。\r\n ");}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 = :%s\n" ,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 = :%s\n" ,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 = %d\n" ,dbm);              rt_kprintf("\n RSSI = %02x%02x\n" ,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);}}elseres = RT_FALSE;}if(rt_strstr((char const*)gprs_rx_buffer,"MYURCREAD: 0"))//有网络数据{net_status = CONNECT_GPRSDATAIN;rt_kprintf("\r\n收到网络数据!\r\n");}}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上: applications中,都有一个对应的 test**** 文件。该文件中,全部使用的finsh 在串口控制中操作。

- End - 

支持RT-Thread,请关注RT-Thread公众号

添加微信13924608367 为好友,注明rt-thread,拉进RT-Thread Nano微信交流群,与RT-Thread官方团队直接交流。

阅读原文可报名12月16日上海RT-Thread开发者大会,现场实战RT-Thread入门,快速搭建开发框架, 一网打尽物联网技术,创建炫酷GUI,干货不断,等你来!

更多推荐

基于STM32F107与RT

本文发布于:2024-02-06 07:13:16,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1746966.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:RT

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!