0 卖盘信息
BOM询价
您现在的位置: 首页 > 技术方案 >工业控制 > 基于STM32F107与RT-Thread的数据采集器设计方案

基于STM32F107与RT-Thread的数据采集器设计方案

来源: elecfans
2021-08-04
类别:工业控制
eye 15
文章创建人 拍明

原标题:基于STM32F107与RT-Thread的数据采集器设计方案

  作者孙冬梅:南京工业大学自动化与电气工程学院博士、副教授

  设计了基于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 -


责任编辑:David

【免责声明】

1、本文内容、数据、图表等来源于网络引用或其他公开资料,版权归属原作者、原发表出处。若版权所有方对本文的引用持有异议,请联系拍明芯城(marketing@iczoom.com),本方将及时处理。

2、本文的引用仅供读者交流学习使用,不涉及商业目的。

3、本文内容仅代表作者观点,拍明芯城不对内容的准确性、可靠性或完整性提供明示或暗示的保证。读者阅读本文后做出的决定或行为,是基于自主意愿和独立判断做出的,请读者明确相关结果。

4、如需转载本方拥有版权的文章,请联系拍明芯城(marketing@iczoom.com)注明“转载原因”。未经允许私自转载拍明芯城将保留追究其法律责任的权利。

拍明芯城拥有对此声明的最终解释权。

相关资讯

方案推荐
基于MC33771主控芯片的新能源锂电池管理系统解决方案

基于MC33771主控芯片的新能源锂电池管理系统解决方案

AMIC110 32位Sitara ARM MCU开发方案

AMIC110 32位Sitara ARM MCU开发方案

基于AMIC110多协议可编程工业通信处理器的32位Sitara ARM MCU开发方案

基于AMIC110多协议可编程工业通信处理器的32位Sitara ARM MCU开发方案

基于展讯SC9820超低成本LTE芯片平台的儿童智能手表解决方案

基于展讯SC9820超低成本LTE芯片平台的儿童智能手表解决方案

基于TI公司的AM437x双照相机参考设计

基于TI公司的AM437x双照相机参考设计

基于MTK6580芯片的W2智能手表解决方案

基于MTK6580芯片的W2智能手表解决方案