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;
// 處理實時數據......
}
-
嵌入式主板
+關注
關注
7文章
6085瀏覽量
35296
發布評論請先 登錄
相關推薦
評論