0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

RTThread物联网操作系统 来源:未知 作者:佚名 2017-11-26 09:30 次阅读
作者孙冬梅:南京工业大学自动化与电气工程学院博士、副教授

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

    关注

    2240

    文章

    10674

    浏览量

    348788
  • 数据采集器
    +关注

    关注

    1

    文章

    101

    浏览量

    14554
  • rt_thread
    +关注

    关注

    2

    文章

    13

    浏览量

    14620

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

文章出处:【微信号:RTThread,微信公众号:RTThread物联网操作系统】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    STM32L051上使用RT-Thread (一、新建项目)

    学完了 RT-Thread 内核基础,来使用 RT-Thread 实现一个小应用。 硬件平台:STM32L051C8 TCM310(Enocean无线芯片) 软件平台:RT-Thread
    的头像 发表于 06-25 20:45 5698次阅读
    <b class='flag-5'>STM32</b>L051上使用<b class='flag-5'>RT-Thread</b> (一、新建项目)

    工业数据采集器的优势

    品质  对于国内客户而言,在一款高品质的工业数据采集器的应用之下,可以为企业带来更好的解决方案及高效率。至于售后服务,规范工业数据采集器本身也必须拥有更加全面的功能和更加稳定可靠的使用效果。因此优越品质的工业
    发表于 12-07 16:15

    STM32平台RT-Thread最小系统移植搭建 - STM32F107VCT6 精选资料分享

    前言因为手头有大量的开发板,最近熟悉了RT-Thread,所以想都移植搭建RT-Thread,为以后进一步学习应用打下基础。大概有STM32F103几个系列,STM32F107
    发表于 08-05 08:05

    rt-thread开发环境

    首先介绍下开发环境:硬件:STM32F107VC金牛开发板。 rt-thread版本:2.0.0下载:jlink V9rt-thread目录如下:/
    发表于 08-06 08:05

    怎样去设计一种基于STM32F107RT-Thread设计的数据采集器

    作者孙冬梅:南京工业大学自动化与电气工程学院博士、副教授,资深RT-Thread开发者欢迎给RT-Thread投稿,获赠RT-Thread T恤一件。征稿 | 你写不写,福利就在这里~~...
    发表于 08-06 06:51

    如何去搭建一种基于STM32F107VC开发板的rt-thread开发环境

    如何去搭建一种基于STM32F107VC开发板的rt-thread开发环境?
    发表于 11-05 08:03

    怎样去设计一种基于STM32F107数据采集器

    基于STM32F107设计的数据采集器有哪些功能呢?怎样去设计一种基于STM32F107数据采集器呢?
    发表于 11-09 08:06

    STM32F767移植rt-thread nano时Finsh无法读取输入怎么办

    提供的是 STM32F107 版本的代码:char rt_hw_console_getchar(void){int ch = -1;if (__HAL_UART_GET_FLAG
    发表于 11-02 14:08

    STM32F107的时钟设置

    STM32F107的时钟设置,有用的107 时钟配置
    发表于 10-12 16:05 14次下载

    RT-Thread STM32 配置指南

    F105,STM32F107 则叫做 CL 系列,所以当您使用 RT-Thread 时,请先确定您使用的芯片型号,在软件的配置上主要是两 个地方(在工程的选项中): 在上图中选择左边的芯片型号,例如 STM32F103ZE,
    发表于 09-12 15:13 24次下载
    <b class='flag-5'>RT-Thread</b> <b class='flag-5'>STM32</b> 配置指南

    用两张图了解STM32RT-Thread发展历史

    两张图了解STM32RT-Thread发展历史
    的头像 发表于 03-01 14:16 3992次阅读

    RT-Thread STM32 配置系统时钟(使用外部晶振)

    RT-Thread STM32 配置系统时钟开发环境芯片:STM32F103RCT6RT-Thread Studio: V1.0.6(现在已经更新到1.1.3,由于本人使用RTT开发已经有一段时间
    发表于 12-14 18:45 14次下载
    <b class='flag-5'>RT-Thread</b> <b class='flag-5'>STM32</b> 配置系统时钟(使用外部晶振)

    RT-Thread文档_RT-Thread 简介

    RT-Thread文档_RT-Thread 简介
    发表于 02-22 18:22 5次下载
    <b class='flag-5'>RT-Thread</b>文档_<b class='flag-5'>RT-Thread</b> 简介

    RT-Thread文档_RT-Thread 潘多拉 STM32L475 上手指南

    RT-Thread文档_RT-Thread 潘多拉 STM32L475 上手指南
    发表于 02-22 18:23 7次下载
    <b class='flag-5'>RT-Thread</b>文档_<b class='flag-5'>RT-Thread</b> 潘多拉 <b class='flag-5'>STM32</b>L475 上手指南

    RT-Thread文档_RT-Thread SMP 介绍与移植

    RT-Thread文档_RT-Thread SMP 介绍与移植
    发表于 02-22 18:31 7次下载
    <b class='flag-5'>RT-Thread</b>文档_<b class='flag-5'>RT-Thread</b> SMP 介绍与移植