技术天地

WinCE主板与STM32多功能模块通讯说明作者:刘乾坤    发布时间:2017-11-3 13:18:06    被阅览数:

  ETA321是英创推出的基于STM32单片机的多功能扩展模块,可为英创现有的WinCE系统增加AD、DA、PWM、脉冲计数等功能。ETA321使用了一片STM32F103RCT6单片机,STM32F103RCT6通过其USB Device接口与英创工控主板连接通讯,STM32在WinCE系统中被当做一个串口设备,英创主板作为上位机已经固化了STM32的USB驱动程序,同时我们封装了一组STM32与英创WinCE系统通讯的API接口函数,客户可以利用我们提供的接口函数,把成熟的实时控制算法移植到ETA321上,快速实现与英创主板的数据通讯。在使用这些API函数时,需要遵从以下约定:


  1、通讯以数据包(结构体)作为基本单元,每次通讯收/发一个数据包,每个数据包最大为255字节,数据包第一个字节为本数据包的字节长度,第二个字节为命令码,数据包的其它内容由用户自定义。


  2、数据包的第二个命令码字节用于表明本数据包的“身份”。当STM32接收到数据包,得到命令码后,会根据命令码执行相应的操作,当上位机接收到数据包后,根据命令码就可以知道接收到了什么数据。0~127命令码表示常规命令和数据,128~255表示实时数据或实时命令。


  3、数据包和命令码的定义在WinCE上位机端和STM32端必须完全一致。STM32必须对接收到的每个命令数据包回复一个相同命令码的应答包,如果没有数据需要回复,可简单回复通用应答数据包。


  下面是命令码和数据包定义示例:


  /************************* 定义命令代码*************************/

  #define MCU_GENERIC_VER_INFO       0

  #define MCU_GENERIC_ADC                1

 

  // STM32返回的实时数据命令码

  #define MCU_REALTIME_ADC             (0 + MCU_REALTIME_DATA)

 

   /*********************** 定义数据包(结构体) **********************/

  // 获取单片机固件版本信息

  typedef struct                                

  {

         BYTE      ucSize;                               // size of the structure < 256

         BYTE      ucCmd;                              // = MCU_GENERIC_VER_INFO

         WORD   wMajor;                      // major version number

         WORD   wMinor;                            // minor version number

         char       ucName[24];                            // name of realtime driver

  } MCU_VER_INFO, *PMCU_VER_INFO;         // struct for Version Info

  // ADC命令

  typedef struct                                

  {

         BYTE      ucSize;                               // size of the structure < 256

         BYTE      ucCmd;                              // = MCU_GENERIC_ADC

         BYTE      ucCH;                                // AD通道

         DWORD       dwSamplingRate;             // 采样率

  } MCU_ADC, *PMCU_ADC;                           // struct for Version Info

 

  // STM32通用应答数据包

  typedef struct 

  {

         BYTE      ucSize;                               // size of the structure < 256

         BYTE      ucCmd;                              //

         BYTE      ucRerult;

  }MCU_GENERIC_REPLY, *PMCU_GENERIC_REPLY;


WinCE上位机API函数


  在WinCE上使用我们提供的API函数时,需要在工程中包含以下3个文件

  #include "mcu_class.h"                        // API接口函数定义

  #include "mcuCmdInfo.h"                           // 命令码和数据包定义

  #pragma comment(lib, "mcu_class.lib")     // 包含库文件


  下面是API函数说明:


  /**

   @brief  打开MCU设备,初始化相关环境

   @param  None

   @retval = 返回true 打开成功

  **/

  BOOL       OpenMCU();

 

  /**

   @brief  给STM32发送控制指令

   @param  *pCmdInfo[in]:符合约定数据结构的命令数据

   @param  *pBuf[out]: 接收STM32返回数据的数据缓存,此参数可为NULL

   @param  dwBufSize[in]:数据缓存大小

   @retval = true 发送成功,返回true仅表示数据通讯成功,命令执行情况可查看pBuf返回的数据

  **/

  BOOL       SendCmd(BYTE *pCmdInfo, BYTE *pBuf, DWORD dwBufSize = 0);

 

  /**

   @brief  关闭MCU,释放相关资源

   @param  None

   @retval = true 关闭成功

  **/

  BOOL       CloseMCU();

 

  /**

   @brief 接收STM32实时回传数据的回调函数指针,当接收到128~255命令码时被调用

  **/

  REPLYPRO MCUReplyPro;


STM32单片机API函数


  在编写STM32程序时,同样应该包含和上位机定义一致的"mcuCmdInfo.h"文件。STM32使用API函数定义如下:


  /**

    * @brief  USBD初始化及CDC类初始化

    * @param  None

    * @retval None

   **/

  void         USBCDC_Init(void);

 

  /**

    * @brief  查检是否有上位机发来的命令

    * @param  pBuf:用于接收命令的数据缓存

    * @param  pBuf:用于接收命令的数据缓存大小

    * @retval  =0:未接收到命令 >0:接收到数据包的长度(字节数)

   **/

  uint8_t  CheckCommand(uint8_t *pBuf, uint32_t nBufSize);

 

  /**

    * @brief  向上位机发送数据

    * @param  要发送的数据缓存

    * @param  要发送的数据字节数

    * @retval 返回发送字节数

   **/

  uint8_t  SendData(uint8_t *pBuf, uint32_t nSendBytes);


  STM32应用程序首先需要调用USBCDC_Init初始化USB接口,然后调用CheckCommand函数检查是否接收到上位机发来的命令,再根据命令码执行相应的操作,调用SendData函数发送应答数据或实时数据。


  下面是WinCE系统中实现读取ETA321版本信息和实时波形数据采样的示例程序:


  #include "stdafx.h"

  #include "mcu_class.h"                               // API接口函数定义

  #include "mcuCmdInfo.h"                                  // 命令码和数据包定义

  #pragma comment(lib, "mcu_class.lib")             // 包含库文件

 

  // 声明实时数据处理回调函数

  static void CALLBACK MCUReplyPro(BYTE *buf, DWORD buflen);

 

  int _tmain(int argc, _TCHAR* argv[])

  {

         MCU_CLASS        mcu;

         BYTE                    Buf[MAX_BUF_SIZE];

         TCHAR                csBuf[MAX_BUF_SIZE];

         DWORD              dwSize, dwCnt = 0;

         MCU_VER_INFO  getVerInfo;

         MCU_ADC           adc;      

         size_t                   RetrunSize;

             

         // 打开MCU设备

         if(!mcu.OpenMCU()) {

                return -1;

         }

 

         // 指定MCU实时数据处理回调函数

         mcu.MCUReplyPro = MCUReplyPro;

 

         // 调用SenCmd函数之前必须初始化的个变量

         getVerInfo.ucSize = sizeof(MCU_VER_INFO);         // 发送的命令结构体大小(字节数)

         getVerInfo.ucCmd = MCU_GENERIC_VER_INFO;      // 命令代码:获取MCU版本信息

         dwSize = sizeof(Buf);                                          // 用于接收MCU数据的缓存大小

         if(mcu.SendCmd((BYTE *)(&getVerInfo), (BYTE *)&getVerInfo, dwSize)) {

         // 窄字符转宽字符

         mbstowcs_s(&RetrunSize, csBuf, _countof(csBuf), getVerInfo.ucName_TRUNCATE);    

         OutputMessage(TEXT("mcu-ver %x-%x '%s'\r\n"), getVerInfo.wMajor,getVerInfo.wMinor,csBuf);

         }

         else       {

                OutputMessage(TEXT("send command:%d failed!!!\r\n"), getVerInfo.ucCmd);

         }

 

         // 调用SenCmd函数之前必须初始化的变量

         adc.ucSize = sizeof(MCU_ADC);               // 发送的命令结构体大小(字节数)

         adc.ucCmd = MCU_GENERIC_ADC;             // 命令代码:获取MCU版本信息

         adc.ucCH = 0;                                        // 设备ADC通道

         adc.dwSamplingRate = 10000;                    // 设置ADC采样率KHz

         if(!mcu.SendCmd((BYTE *)(&adc), NULL))  {

                OutputMessage(TEXT("send command:%d failed!!!\r\n"), adc.ucCmd);

         }

 

         while(1) {

                Sleep(1000);

                if(dwCnt > 10)           // 10S后退出

                       break;

         }

 

         adc.dwSamplingRate = 0;                     // 停止ADC采集

         if(!mcu.SendCmd((BYTE *)(&adc), NULL))  {

                OutputMessage(TEXT("send command:%d failed!!!\r\n"), adc.ucCmd);

         }

 

         Sleep(1000);

         // 关闭MCU设备,释放相关资源

         mcu.CloseMCU();

         return 0;

  }

 

  // 实时数据处理回调函数

  void CALLBACK   MCUReplyPro(BYTE *buf, DWORD buflen)

  {

         PMCU_ADC_DATA    pADCData;

         static DWORD    cnt = 0;

   

         pADCData = (PMCU_ADC_DATA)buf;

         cnt += pADCData->ucSize;

 

         // 处理实时数据......

 

  }

Go Top