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

发布者:乐观向前最新更新时间:2023-09-28 来源: elecfans关键字:STM32F107  RT-Thread  数据采集器 手机看文章 扫描二维码
随时随地手机看文章

设计了基于STM32F107设计的数据采集器,实现多种数据(串口、CAN口)采集处理后通过 GPRS模块 无线上传。重点编写了CAN设备驱动; 使用设备方式实现GPRS模块串口数据的上传下载;最后提出了使用线程过程中出现的一些问题。


一、 功能分析

系统功能如图1 所示,不算太复杂。由于下级传感器模块的上报的数据内容很多,导致编写处理程序内容较多。

二、CAN驱动编写

为了模块化地处理传感器的主动上报数据,CAN设备不再用以前的中断处理,而是采用了RTT的设备框架,重新编写了device的驱动。研究RTT里的CAN总线收发设备:

2675485821d7663c20ea692db69b6151_0933053224-4.png

发现只有框架,没有内容。就仿着串口写一个candevice。研究组件使用 中的串口驱动:

71dae03b73d62638126606c24b0681e5_0933055562-5.png

这是一个读代码的过程,弄清楚框架后,编写类似于linux中的驱动编写。

b95d76d3b6575c539d7dc97b22f837f3_0933056310-6.png

以上程序全部写好后,就可以使用设备通用操作函数来操作CAN。在主程序中首先要初始化设备,再注册设备。

32a241585142bc83d008e3db7200b804_09330514E-7.png

三、设备方式实现串口数据处理

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, 极大地方便了调试。


17a6754a3399c7d999917d4330693030_09330561X-8.png

引用用户手册的说明:编写了一个函数,如果不在程序中运行,便可以将此函数引出到finsh中。

d8b0b413e9cb8d4ebff8e8877ae9a84e_093305L26-9.png

在串口控制台中操作,就可以很方便地实现GPRS相关函数的调试,而并需要在主程序中运行以上函数。


3.RTT例程的格式

编写了基于RTT的 STM32F107平台的例程,发布在github上:https://github.com/sundm75/STM32F107Board-rttproject每个example下的 applications中,都有一个对应的 test**** 文件。该文件中,全部使用的finsh 在串口控制中操作。

9739fdeff3f17660b60767fbefea657d_0933055437-10.png

- End -


关键字:STM32F107  RT-Thread  数据采集器 引用地址:基于STM32F107与RT-Thread的数据采集器方案设计与解析

上一篇:介绍一种关于STM32 ADC 多通道16路电压采集技术
下一篇:STM32看门狗配置(独立看门狗IWDG和窗口看门狗WWDG)

推荐阅读最新更新时间:2024-11-09 05:53

怎么设计一种基于RT-Thread和infineon开发板的智能家居系统?
功能简介 本次设计基于RT-Thread和infineon PSoC™ 62 with CAPSENSE™ evaluation kit开发板,实现了一个简易的智能家居系统。通过SHT31温湿度传感器和VEML7700光照传感器来采集室内的温湿度和光照强度,并通过esp8266联网和MQTT协议上传到onenet云平台,并且通过onenet可视化平台可以实现远程查看温湿度和光照数据,而且可以通过开发板上自带的按键,实现是否开灯自动调节室内亮度。 VEML7700 VEML7700是一款高精度环境光数字16位分辨率传感器,通过I2C进行传输,用典型的I2C时序即可进行读写。 SHT31 SHT31是一款高精度温湿度传感器,在正常
[嵌入式]
怎么设计一种基于<font color='red'>RT-Thread</font>和infineon开发板的智能家居系统?
基于RT-Thread的RoboMaster电控框架(六)
背景 使用的开发板为大疆的 RoboMaster-C 型开发板,基础工程为 rt-thread bsp stm32f407-robomaster-c MSG模块开发 MSG 模块主要应用于应用层线程间通讯,实现一种发布者发布话题,订阅者订阅话题的通讯方式。接下来主要讨论开发 MSG 模块的初衷,以及与其他线程间通讯方式的对比。 开发的初衷是受 ROS 及其他学校的如吉林大学的软总线中心,湖南大学的消息中心模块的启发,(主要还是苦全局变量久矣),开发一套简单易用、线程安全、模块解耦、逻辑清晰的线程间通讯机制显得尤为重要。 但是 RTOS 中不是已经提供了诸如:邮箱,消息队列、信号(软中断,这里不具体讨论)的线程间通信机制,为什么
[单片机]
热门资源推荐
热门放大器推荐
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved