龙鳞铁碎牙 发表于 2025-8-29 20:34

【APM32E030R Micro-EVB开发板评测】——电总协议解析

电总协议又称为空调协议,广泛应用于家用空调和一些高压输电场合,在电力电子当中使用非常的广泛!!!
先看数据帧格式!!



1.物理接口
串行通信口采用RS485/RS232。
信息传输方式为异步方式,起始位1位,数据位8位,停止位1位,无校验。
数据传输速率为1200、2400、4800、9600和19200bits可以设置。2.通信方式
在局站内的监控系统为分布式结构。局站监控单元(SU)与设备监控模块(SM)的通信为主从方式,监控单元为上位机,监控模块为下位机。SU呼叫SM并下发命令,SM收到命令后返回响应信息。SU 500ms内接收不到SM响应或接收响应信息错误,则认为本次通信过程失败。
在本系统中,精密空调控制器为SM,上位机为SU。3.1 信息类型
信息分两种类型:
(1) 由SU(上位机)发出到SM(精密空调控制器)的命令信息(简称命令信息);
(2) 由SM(精密空调控制器)返回到SU(上位机)的响应信息(简称响应信息)。在基本格式中的各项除SOI和EOI是以十六进制解释(SOI = 7EH,EOI = 0DH),十六进制传输外,其余各项都是以十六进制解释,以ASCII码的方式传输,每个字节用
两个ASCII码表示,即高四位用一个ASCII码表示,低四位用一个ASCII码表示。例:
CID2 = 4BH,传送时顺序发送34H,42H。
因此,上表以及以下各表中“字节数”是指“解释字节数”,除SOI和EOI外,实际传输字节数应该乘以2。

3.2 基本数据格式
在7.2基本格式中的各项除SOI和EOI是以(SOI = 7EH,EOI = 0DH)十六进制传输外,其余各项都是以ASCII码的方式传输,每个字节用两个ASCII码表示,即高四位一个ASCII码表示,低四位用一个ASCII码表示。例:CID2 = 4BH,传送时顺序发送34H,42H。

LENGTH共2个字节,由LENID和LCHKSUM组成,LENID表示INFO项的ASCII码字节数,
当LENID = 0时,INFO为空,即无该项。LENGTH传输中先传高字节,再传低字节,分四个ASCII码传送。
校验码的计算:D11D10D9D8 + D7D6D5D4 + D3D2D1D0,求和后模16余数取反加1。INFO项的ASCII码字节数为18,即LENID = 0000 0001 0010B。
D11D10D9D8 + D7D6D5D4 + D3D2D1D0 = 0000B + 0001B + 0010B = 0011B,模16余数为0011B,0011B取反加1就是1101B,即LCHKSUM为1101B。
可得:
LENGTH为1101 0000 0001 0010B,即D012H。3.3. CHKSUM 数据格式CHKSUM的计算是除SOI、EOI和CHKSUM外,其他字符按ASCII码值累加求和,所得结果模65536余数取反加1。
收到或发送的字符序列是:“~20014043E00200FD3BCR”(“~”为SOI,“CR”为
EOI),则最后五个字符“FD3BCR”中的FD3B是CHKSUM,计算方法是:
‘2’+‘0’+‘0’+…+‘E’+‘0’+‘0’+‘2’ +‘0’+‘0’
= 32H + 30H + 30H + … + 45H + 30H + 30H + 32H + 30H + 30H= 02C5H
其中‘1’表示1的ASCII码值,‘E’表示E的ASCII码值。02C5H模65536余数是02C5H,02C5H取反加1就是FD3BH。3.4 INFO 数据格式有符号整型数
-32768 ~ +32767
无符号整型数
0 ~ +65535
两个字节的整型数据传送顺序为先高字节后低字节。日期时间格式
CID1、CID2编码分配及分类见表6和表7

1 获取模拟量数据(定点数)(42H)

0x7E,0x21,0x01,0x60,0x42,0x00,0x00,0xFD,0xB0,0x0D

好了,开始进入核心代码

#ifndefCOMM_H#defineCOMM_H

#include "main.h"

#defineREC_MAX   1024    // 定义接收缓存区的大小#defineSEND_MAX1024    // 定义发送缓存区的大小

#defineprint printf



// 通讯常量定义 #defineSERIAL_TIME_ISR   5            // 定时器间隔 ms #defineTIME_OUT          500          // 接收超时时间 500ms #defineTIME_SLEEP      10000      // 休眠超时时间 10S
typedef struct {uint8_tRecBuf;    // 接收缓存区uint16_t RecCount;         // 接收的字节数uint8_tSendBuf;   // 发送缓存区uint16_t SendCount;          // 要发送的字节数uint8_tRecOver;            // 接收完成标志uint16_t RecTimer;         // 接收计时器uint16_t SleepTime;          // 休眠计时uint8_tSleepFlag;          // 通讯休眠标志} MSG;
typedef enum {Normal,VER_ERROR,CHKSUM_ERROR,LCHKSUM_ERROR,CID2_INVALID,CMD_ERROR,DARA_ERROR,ASCII_ERROR=0x80,} RTN;

extern MSG MSG_SERIAL;extern void SerialInput(uint8_t RevData);extern void SerialTimer(void); // 由定时器调用extern void SerialDecode(void);// 由主函数调用




#endif


#include <string.h>
#include "Serial.h"



#defineSOI       0x7E   // 起始标志
#defineVER       0x10   // v1.0
#defineADR       0x01   // 地址描述符
#defineCID1      0x2A   // 设备描述符
#defineEOI       0x0D   // 结束码
#defineCID2      0x43






MSG MSG_SERIAL;
uint16_t leng_id = 0;
uint16_t leng_id1 = 0;


#defineMODX   0x10000
#definesendData MSG_SERIAL.SendBuf

static uint16_t LENID(void);
static uint8_t LCHKSUM(uint16_t h1);

static uint16_t ChkSum(uint8_t* pData, uint16_t count);
static void SerialTimeOut(void);
static uint8_t atohex16(uint8_t *cp);

static uint8_t RcvChk(void);
static void atoh2b(uint8_t *hp, uint8_t *cp);
static void htoa(uint8_t *pA, uint8_t H);
static void htoa3b(uint8_t *cp, uint16_t h1);

static void htoa4b(uint8_t *cp, uint16_t h1);
static void ClrRcvBuf(void);
static void SerialDecoding(uint8_t pData);
static void SerialStartSend(uint8_t *pData);


staticuint8_t * FloatToChar(float *pFData);
staticfloat * CharToFloat(uint8_t *pChar);



staticuint8_t htoa_H(uint8_t H);
staticuint8_t htoa_L(uint8_t H);


static void SendBuff(void);

static void SerialSend41h(void);
static void SerialSend43h(void);

// 串口接收数据
void SerialInput(uint8_t RecData)
{
   if(MSG_SERIAL.RecOver) return; // 停止接收?
   if((RecData==SOI)&&(MSG_SERIAL.RecCount==0))         
   {MSG_SERIAL.SleepTime=0;
      MSG_SERIAL.SleepFlag=0;   
      MSG_SERIAL.RecBuf=SOI;MSG_SERIAL.RecCount=1; // 启动接收
   }
   else if((MSG_SERIAL.RecBuf==SOI)&&(MSG_SERIAL.RecCount<REC_MAX)) // 如果已经接收到起始位
   {
             MSG_SERIAL.RecBuf=RecData;
   } // 将数据添加到缓存区
   else
   {
             MSG_SERIAL.RecCount=0;
   }
   if((RecData==EOI)&&(MSG_SERIAL.RecCount==(LENID()+18)))
   {
   MSG_SERIAL.RecOver=1;
   MSG_SERIAL.RecTimer=0;          // 清计时器
   } //接收完成         
}




static uint16_t LENID(void)
{
        uint8_tLF_hex = {0};
        uint16_t LENGTH = 0;
        uint8_tlchsum = 0;

        atoh2b(&LF_hex, &MSG_SERIAL.RecBuf);
        atoh2b(&LF_hex, &MSG_SERIAL.RecBuf);
        LENGTH = (uint16_t)LF_hex<<8|LF_hex;
        lchsum = htoa_L((uint8_t) ((~((((LENGTH >> 8)&0x0F) | ((LENGTH >> 4) & 0x0F) | (LENGTH & 0x0F)) % MODX) + 1) & 0x0F));
       
#if 1
        if(lchsum == MSG_SERIAL.RecBuf)
        {
                leng_id = (uint16_t) (LENGTH & 0x0FFF);
        }
#else
        leng_id = (uint16_t) (LENGTH & 0x0FFF);
#endif
    return leng_id;
}

static uint16_t ChkSum(uint8_t* pData, uint16_t count)
{
    uint16_t chkSum = 0;
   
    while (count--)
    {
      chkSum += (*pData++);
    }
        chkSum=~chkSum%MODX+1;
    return (chkSum);
}


//=============================================================
// CONVERTS 2 ASCII BYTES REPRESENTING A HEX NUMBER INTO BYTE HEX NUMBER.
// ON ENTRY - cp POINTS TO 1ST ASCII BYTE (HIGH NIBBLE OF HEX BYTE),
//          - hp POINTS TO A LOCATION TO RECEIVE THE BYTE HEX NUMBER.
//-------------------------------------------------------------
static void atoh2b(uint8_t *hp, uint8_t *cp)
{
        // CONVERT 1ST ASCII BYTE TO HIGH NIBBLE OF HEX BYTE:
        if (*cp <= '9')
        *hp = *cp - '0';
        else
        {
        *cp &= 0xdf;   // IF IT'S 'A'-'F' DIGIT MAKE IT UPPERCASE
        *hp = *cp - '7';
        }

        *hp = *hp << 4;   // IT'S HIGH NIBBLE OF HEX BYTE
        ++cp;             // POINT TO 2ND ASCII BYTE

        // CONVERT 2ND ASCII BYTE TO LOW NIBBLE OF HEX BYTE:
        if (*cp <= '9')
        *hp += *cp - '0';
        else
        {
        *cp &= 0xdf;   // IF IT'S 'A'-'F' DIGIT MAKE IT UPPERCASE
        *hp += *cp - '7';
        }

return;
}

//=============================================================
// CONVERTS A HEX BYTE NUMBER TO 2 ASCII BYTES REPRESENTING THAT NUMBER.
// ON ENTRY - H HEX BYTE TO BE CONVERTED TO 2 ASCII BYTES,
//          - pA POINTS TO 1ST ASCII BYTE WHICH WILL RECEIVE HIGH NIBBLE
//               OF HEX NUMBER H.
//-------------------------------------------------------------
static void htoa(uint8_t *pA, uint8_t H)
{
uint8_t h1;

h1 = H >> 4;   // h1 = HI NIBBLE OF HEX BYTE

// CONVERT HIGH NIBBLE TO 1ST ASCII BYTE:
if (h1 <= 0x09)
    *pA = h1 + '0';
else
    *pA = h1 + '7';

++pA;            // POINT TO 2ND ASCII BYTE
h1 = H & 0x0f; // h1 = LOW NIBBLE OF HEX BYTE

// CONVERT LOW NIBBLE OF HEX BYTE TO 2ND ASCII BYTE:
if (h1 <= 0x09)
    *pA = h1 + '0';
else
    *pA = h1 + '7';

++pA;            // POINT TO NEXT FREE ASCII BYTE

return;
}
//=============================================================
// CONVERTS A HEX WORD NUMBER TO 4 ASCII BYTES REPRESENTING THAT NUMBER.
// ON ENTRY - h1 HEX BYTE TO BE CONVERTED TO 4 ASCII BYTES,
//          - cp POINTS TO 1ST ASCII BYTE WHICH WILL RECEIVE HIGH NIBBLE
//               OF HIGH BYTE OF THE HEX NUMBER IN h1.
//-------------------------------------------------------------
static void htoa4b(uint8_t *cp, uint16_t h1)
{
uint8_t c1;

// cp POINTS TO ASCII BYTE 0
// HI NIBBLE OF HI BYTE:
c1 = (uint8_t)(h1 >> 12);
if (c1 <= 0x09)
    *cp = c1 + '0';
else
    *cp = c1 + '7';

// POINT TO ASCII BYTE 1:
++cp;

// LO NIBBLE OF HI BYTE:
c1 = (uint8_t)((h1 >> 8) & 0x0F);
if (c1 <= 0x09)
    *cp = c1 + '0';
else
    *cp = c1 + '7';

// POINT TO ASCII BYTE 2:
++cp;

// HI NIBBLE OF LO BYTE:
c1 = (uint8_t)((h1 >> 4) & 0x0F);
if (c1 <= 0x09)
    *cp = c1 + '0';
else
    *cp = c1 + '7';

// POINT TO ASCII BYTE 3:
++cp;

// LO NIBBLE OF LO BYTE:
c1 = (uint8_t)(h1 & 0x0F);
if (c1 <= 0x09)
    *cp = c1 + '0';
else
    *cp = c1 + '7';

return;
}

static uint8_t LCHKSUM(uint16_t h1)
{
        uint8_t sum = 0;
        sum = htoa_L((uint8_t) ((~((((h1 >> 8)&0x0F) | ((h1 >> 4) & 0x0F) | (h1 & 0x0F)) % MODX) + 1) & 0x0F));
        //print("sum = 0x%02x\r\n",sum);
        return sum;
}

static void htoa3b(uint8_t *cp, uint16_t h1)
{
uint8_t c1;



// LO NIBBLE OF HI BYTE:
c1 = (uint8_t)((h1 >> 8) & 0x0F);//print("c1 = 0x%02x\r\n",c1);
if (c1 <= 0x09)
    *cp = c1 + '0';
else
    *cp = c1 + '7';

// POINT TO ASCII BYTE 2:
++cp;

// HI NIBBLE OF LO BYTE:
c1 = (uint8_t)((h1 >> 4) & 0x0F);//print("c1 = 0x%02x\r\n",c1);
if (c1 <= 0x09)
    *cp = c1 + '0';
else
    *cp = c1 + '7';

// POINT TO ASCII BYTE 3:
++cp;

// LO NIBBLE OF LO BYTE:
c1 = (uint8_t)(h1 & 0x0F);//print("c1 = 0x%02x\r\n",c1);
if (c1 <= 0x09)
    *cp = c1 + '0';
else
    *cp = c1 + '7';

return;
}

static uint8_t atohex16(uint8_t *cp)
{
        uint8_t hex = 0;
        uint8_t dat1 = 0;
        uint8_t dat2 = 0;

        // CONVERT 1ST ASCII BYTE TO HIGH NIBBLE OF HEX BYTE:
        if (*cp <= '9')
        dat1 = *cp - '0';
        else
        {
        *cp &= 0xdf;   // IF IT'S 'A'-'F' DIGIT MAKE IT UPPERCASE
        dat1 = *cp - '7';
        }

        ++cp;             // POINT TO 2ND ASCII BYTE

        // CONVERT 2ND ASCII BYTE TO LOW NIBBLE OF HEX BYTE:
        if (*cp <= '9')
        dat2 += *cp - '0';
        else
        {
        *cp &= 0xdf;   // IF IT'S 'A'-'F' DIGIT MAKE IT UPPERCASE
        dat2 += *cp - '7';
        }
        hex = (uint16_t)(dat1<<4|dat2);

return hex;
}


static uint8_t htoa_H(uint8_t H)
{
    uint8_t h1   = 0;
    uint8_t DATA = 0;

    h1 = H >> 4;   // h1 = HI NIBBLE OF HEX BYTE

    // CONVERT HIGH NIBBLE TO 1ST ASCII BYTE:
    if (h1 <= 0x09)
      DATA = h1 + '0';
    else
      DATA = h1 + '7';


    return DATA;
}

static uint8_t htoa_L(uint8_t H)
{
    uint8_t h1   = 0;
    uint8_t DATA = 0;

    h1 = H & 0x0f; // h1 = LOW NIBBLE OF HEX BYTE

    // CONVERT LOW NIBBLE OF HEX BYTE TO 2ND ASCII BYTE:
    if (h1 <= 0x09)
      DATA = h1 + '0';
    else
      DATA = h1 + '7';

    return DATA;
}


// 接收数据校验
static uint8_t RcvChk(void)
{
uint8_tLF_TxB = {0};
uint16_t CHKSUM= 0;

atoh2b(&LF_TxB, &MSG_SERIAL.RecBuf);
atoh2b(&LF_TxB, &MSG_SERIAL.RecBuf);

CHKSUM= (uint16_t)(LF_TxB<<8|LF_TxB);

if(CHKSUM==ChkSum(&MSG_SERIAL.RecBuf,12+leng_id))
{return 1;}
else
{return 0;}
}
// 由定时器调用
void SerialTimer(void)
{
        if(MSG_SERIAL.RecCount!=0)
    {
       MSG_SERIAL.RecTimer++;
    }
    if(MSG_SERIAL.RecCount==0)
    {
       MSG_SERIAL.SleepTime++;
    }
}

// 接收超时处理
static void SerialTimeOut(void)
{
   if(MSG_SERIAL.RecTimer>(TIME_OUT/SERIAL_TIME_ISR)) // 如果接收超时
   {
      MSG_SERIAL.RecCount=0;         // 清接收数据计数器
      MSG_SERIAL.RecTimer=0;         // 清计时器
          MSG_SERIAL.RecOver=0;          // 允许接
   }
   if(MSG_SERIAL.SleepFlag) return;
   if(MSG_SERIAL.SleepTime>(TIME_SLEEP/SERIAL_TIME_ISR))
   {
               MSG_SERIAL.SleepFlag=1;
   }
}
// 清接收缓存区
static void ClrRcvBuf(void)
{       
        memset(MSG_SERIAL.RecBuf,0,REC_MAX);
    MSG_SERIAL.RecCount=0; // 清接收数据计数器
        MSG_SERIAL.RecTimer=0; // 清计时器
        MSG_SERIAL.RecOver=0;// 允许接
}

// 数据解码
void SerialDecode(void)
{
   SerialTimeOut();
   if(!MSG_SERIAL.RecOver) {return;} // 接收没有完成
   if(atohex16(&MSG_SERIAL.RecBuf)!= VER) {return;} //
   if(atohex16(&MSG_SERIAL.RecBuf)!= ADR) {return;} //
   if(atohex16(&MSG_SERIAL.RecBuf)!= CID1) {return;} //
   if(!RcvChk()) {return;} // 如果校验错误
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
#if 1
                uint16_t i = 0;
                print("MSG_SERIAL.RecCount= %d\r\n",MSG_SERIAL.RecCount);
                for(i=0;i<MSG_SERIAL.RecCount;i++)
                {
                   print("MSG_SERIAL.RecBuf[%02d]= 0x%02x\r\n",i,MSG_SERIAL.RecBuf);
                }
#endif
///////////////////////////////////////////////////////
///////////////////////////////////////////////////////   
   SerialDecoding(atohex16(&MSG_SERIAL.RecBuf)); //
   ClrRcvBuf();          // 清缓存区
}

// 将浮点数分解为4个字节
static uint8_t * FloatToChar(float *pFData)
{
   void *pVoid;
   static uint8_t chart;
   uint8_t i;
   pVoid=pFData;
   for(i=0;i<4;i++)
   {
   chart=*((uint8_t *)pVoid+i);
   }
   return (&chart);
}
// 将4个字节 合并为浮点数
static float * CharToFloat(uint8_t *pChar)
{
static float fData;
void *pVoid;
uint8_t i;
pVoid=&fData;
for(i=0;i<4;i++)
{
    *((uint8_t *)pVoid+i)=*(pChar+i);
}
return (&fData);
}


// 启动串口发送数据
static void SerialStartSend(uint8_t *pData)
{
   uint8_t i;

   MSG_SERIAL.SendCount=leng_id1 + 18;
   for(i=0;i<MSG_SERIAL.SendCount;i++)
   {
           MSG_SERIAL.SendBuf=*(pData+i);
   }
   Serial_SendArray(MSG_SERIAL.SendBuf,MSG_SERIAL.SendCount);
}


// 数据提取
static void SerialDecoding(uint8_t pData)
{
   switch(pData)
   {
      case 0x41:// 电池电压(0x02),电流(0x03),电量(0x04),数据请求   
      print("0x41\r\n");
             SerialSend41h();
             break;      
      case 0x43:// 内部用命令
                print("0x43\r\n");          
                        SerialSend43h();
             break;
                case 0x44:// 内部用命令
                print("0x44\r\n");          
             break;
                case 0x4F:// 内部用命令
                print("0x4F\r\n");          
             break;
                case 0x50:// 内部用命令
                print("0x50\r\n");          
             break;
                case 0x51:// 内部用命令
                print("0x51\r\n");          
             break;
                case 0xE1:// 内部用命令
                print("0xE1\r\n");          
             break;
                case 0xE2:// 内部用命令
                print("0xE2\r\n");          
             break;
                case 0xE3:// 内部用命令
                print("0xE3\r\n");          
             break;
                case 0xDB:// 内部用命令
                print("0xDB\r\n");          
             break;
      default:
                print("unsported command!\r\n");
                        break;
   }
}

static void SendBuff(void)
{
        uint8_t index = 0;
       
        sendData = SOI;      //print("index = %02d\r\n",index);
        sendData = htoa_H(VER);//print("index = %02d\r\n",index);
        sendData = htoa_L(VER);
        sendData = htoa_H(ADR);
        sendData = htoa_L(ADR);
        sendData = htoa_H(CID1);
        sendData = htoa_L(CID1);
        sendData = htoa_H(CID2);
        sendData = htoa_L(CID2);//print("index = %02d\r\n",index);
}


static void SerialSend41h(void)
{
   uint16_t checksum = 0;
   uint8_t i = 0;

   SendBuff();
        leng_id1 = 18;
        sendData=LCHKSUM(leng_id1);//9
        htoa3b(&sendData, leng_id1);//10 11 12
        sendData=htoa_H(1);sendData=htoa_L(1);//1
        sendData=htoa_H(00);sendData=htoa_L(00);sendData=htoa_H(0xFA);sendData=htoa_L(0xFA);
        sendData=htoa_H(2);sendData=htoa_L(2);//2
        sendData=htoa_H(00);sendData=htoa_L(00);sendData=htoa_H(0xFA);sendData=htoa_L(0xFA);
        sendData=htoa_H(3);sendData=htoa_L(3);//3
        sendData=htoa_H(00);sendData=htoa_L(00);sendData=htoa_H(0xFA);sendData=htoa_L(0xFA);
        checksum = ChkSum(&sendData,12+leng_id1);//print("checksum = 0x%02x\r\n",checksum);
       
        htoa4b(&sendData, checksum);//31 32 33 34
        sendData=EOI;
        SerialStartSend(sendData); // 启动发送       
}

static void SerialSend43h(void)
{
        uint16_t checksum = 0;

        leng_id1 = 0;
        SendBuff();
        sendData = LCHKSUM(leng_id1);
        htoa3b(&sendData, leng_id1);//10 11 12
        checksum = ChkSum(&sendData,12+leng_id1);
        htoa4b(&sendData, checksum);
        sendData=EOI;
        SerialStartSend(sendData); // 启动发送       
}



/*!
* @file      main.c
*
* @brief       Main program body
*
* @version   V1.0.2
*
* @date      2025-05-15
*
* @attention
*
*Copyright (C) 2024-2025 Geehy Semiconductor
*
*You may not use this file except in compliance with the
*GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
*The program is only for reference, which is distributed in the hope
*that it will be useful and instructional for customers to develop
*their software. Unless required by applicable law or agreed to in
*writing, the program is distributed on an "AS IS" BASIS, WITHOUT
*ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
*See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
*and limitations under the License.
*/

/* Includes */
#include "main.h"
#include "ebtn_app.h"
#include "Serial.h"






/** @addtogroup Examples
@{
*/

/** @addtogroup USART_Interrupt
@{
*/

/** @defgroup USART_Interrupt_Macros Macros
@{
*/

/* printf function configs to USART1*/
#define DEBUG_USARTUSART1

/**@} end of group USART_Interrupt_Macros */

/** @defgroup USART_Interrupt_Enumerations Enumerations
@{
*/

/**@} end of group USART_Interrupt_Enumerations */

/** @defgroup USART_Interrupt_Structures Structures
@{
*/

/**@} end of group USART_Interrupt_Structures */

/** @defgroup USART_Interrupt_Variables Variables
@{
*/

/**@} end of group USART_Interrupt_Variables */

/** @defgroup USART_Interrupt_Functions Functions
@{
*/

/* System tick */
volatile uint32_t sysTick = 0;
volatile uint32_t g_tfime_5ms = 0;

volatile uint32_t sysTick20ms = 0;

/* USART Write Data */
void USART_Write(USART_T* usart, uint8_t* dat);

uint8_tU1_RxBuff;
uint16_t U1_Rxlen = 0;
uint16_t U1_RxlencntPre = 0;


#define CMD_LEN 64
static char cmd;
static uint8_t cmd_index = 0;



/*!
* @brief       Main program
*
* @param       None
*
* @retval      None
*
* @note
*/
int main(void)
{
    GPIO_Config_T gpioConfig;
    USART_Config_T usartConfigStruct;

        hal_systick_init();

    /* Enable GPIO clock */
    RCM_EnableAHBPeriphClock(TINY_COM1_TX_GPIO_CLK);

    /* Enable COM1 clock */
    RCM_EnableAPB2PeriphClock(TINY_COM1_CLK);

    /* Enable the BUTTON Clock */
    RCM_EnableAHBPeriphClock(KEY1_BUTTON_GPIO_CLK);
    RCM_EnableAHBPeriphClock(KEY2_BUTTON_GPIO_CLK);
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);

    /* Connect PXx to USARTx_Tx */
    GPIO_ConfigPinAF(TINY_COM1_TX_GPIO_PORT, TINY_COM1_TX_SOURCE, TINY_COM1_TX_AF);

    /* Connect PXx to USARRX_Rx */
    GPIO_ConfigPinAF(TINY_COM1_RX_GPIO_PORT, TINY_COM1_RX_SOURCE, TINY_COM1_RX_AF);

    /* Configure USART Tx as alternate function push-pull */
    gpioConfig.mode = GPIO_MODE_AF;
    gpioConfig.pin = TINY_COM1_TX_PIN;
    gpioConfig.speed = GPIO_SPEED_50MHz;
    gpioConfig.outtype = GPIO_OUT_TYPE_PP;
    gpioConfig.pupd = GPIO_PUPD_PU;
    GPIO_Config(TINY_COM1_TX_GPIO_PORT, &gpioConfig);

    /* Configure USART Rx as input floating */
    gpioConfig.pin= TINY_COM1_RX_PIN;
    GPIO_Config(TINY_COM1_RX_GPIO_PORT, &gpioConfig);

    /* TINY_USARTs configured as follow: */
    /* BaudRate = 115200 baud */
    usartConfigStruct.baudRate = 115200;
    /* Receive and transmit enabled */
    usartConfigStruct.mode   = USART_MODE_TX_RX;
    /* Hardware flow control disabled (RTS and CTS signals) */
    usartConfigStruct.hardwareFlowCtrl = USART_FLOW_CTRL_NONE;
    /* No parity */
    usartConfigStruct.parity   = USART_PARITY_NONE;
    /* One Stop Bit */
    usartConfigStruct.stopBits =USART_STOP_BIT_1;
    /* Word Length = 8 Bits */
    usartConfigStruct.wordLength = USART_WORD_LEN_8B;
    /* USART_Config */
    USART_Config(TINY_COM1, &usartConfigStruct);

    /* Enable USART_Interrupt_RXBNEIE */
    USART_EnableInterrupt(TINY_COM1, USART_INT_RXBNEIE);

    NVIC_EnableIRQRequest(TINY_COM1_IRQn, 2);

    /* Enable USART */
    USART_Enable(TINY_COM1);

    RCM_EnableAHBPeriphClock(LED2_GPIO_CLK | LED3_GPIO_CLK);
    /* LED2 GPIO configuration */
    gpioConfig.pin = LED2_PIN;
    gpioConfig.mode = GPIO_MODE_OUT;
    gpioConfig.outtype = GPIO_OUT_TYPE_PP;
    gpioConfig.speed = GPIO_SPEED_50MHz;
    gpioConfig.pupd = GPIO_PUPD_NO;
    GPIO_Config(LED2_GPIO_PORT, &gpioConfig);

    /* LED3 GPIO configuration */
    gpioConfig.pin = LED3_PIN;
    GPIO_Config(LED3_GPIO_PORT, &gpioConfig);

    /* Turn LED2 on */
    //GPIO_ClearBit(LED2_GPIO_PORT, LED2_PIN);
        GPIO_SetBit(LED2_GPIO_PORT, LED2_PIN);
    /* Turn LED3 off */
    GPIO_SetBit(LED3_GPIO_PORT, LED3_PIN);
        //GPIO_ClearBit(LED3_GPIO_PORT, LED3_PIN);

    /* Configure Button pin as input floating */
    gpioConfig.mode = GPIO_MODE_IN;
    gpioConfig.pupd = GPIO_PUPD_PU;
    gpioConfig.pin = KEY1_BUTTON_PIN;
    GPIO_Config(KEY1_BUTTON_GPIO_PORT, &gpioConfig);

    gpioConfig.pin = KEY2_BUTTON_PIN;
    GPIO_Config(KEY2_BUTTON_GPIO_PORT, &gpioConfig);

        ebtn_APP_Key_INIT();

        shell_init();

       
    while (1)
    {

          SerialDecode();

    }
}



/*!
* @brief      serial port tramsimt data
*
* @param      pointer to date that need to be sent
*
* @retval       None
*
* @note
*/
void USART_Write(USART_T* usart, uint8_t* dat)
{
    while (*dat)
    {
      while (USART_ReadStatusFlag(usart, USART_FLAG_TXBE) == RESET);

      USART_TxData(usart, *dat++);
    }
}

void Serial_SendByte(uint8_t Byte)
{
        USART_TxData(TINY_COM1, Byte);
        while (USART_ReadStatusFlag(TINY_COM1, USART_FLAG_TXBE) == RESET);
}

void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
        uint16_t i;
        for (i = 0; i < Length; i ++)
        {
                Serial_SendByte(Array);
        }
}

void Serial_SendString(char *String)
{
        uint16_t i;
        for (i = 0; String != '\0'; i ++)
        {
                Serial_SendByte(String);
        }
}

/*!
* @brief      This function handles USART1 RX interrupt Handler
*
* @param      None
*
* @retval       None
*
* @NOTE      This function need to put intovoid USART1_IRQHandler(void)
*/
voidUSART_Receive_Isr(void)
{
    uint8_t dat;

    if (USART_ReadStatusFlag(TINY_COM1, USART_FLAG_RXBNE) == SET)
    {
      dat = (uint8_t)USART_RxData(TINY_COM1);

                SerialInput(dat);
       
                //if(U1_Rxlen >= sizeof(U1_RxBuff))        U1_Rxlen = 0; //防止串口被刷爆
                //U1_RxBuff = dat;

      //printf("%c", ReceiveTmp);
    }
}


void hal_systick_init(void)
{
    SysTick_Config(SystemCoreClock / TICKS_PER_SECONDS);
}

uint32_t HAL_GetTick(void)
{
    return sysTick;
}

void HAL_Delay(uint32_t Delay)
{
#define HAL_MAX_DELAY      0xFFFFFFFFU

uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;

/* Add a freq to guarantee minimum wait */
if (wait < HAL_MAX_DELAY)
{
    wait++;
}

while ((HAL_GetTick() - tickstart) < wait)
{
}
}

#if defined (__CC_ARM) || defined (__ICCARM__) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))

/*!
* @brief       Redirect C Library function printf to serial port.
*            After Redirection, you can use printf function.
*
* @param       ch:The characters that need to be send.
*
* @param       *f:pointer to a FILE that can recording all information
*            needed to control a stream
*
* @retval      The characters that need to be send.
*
* @note
*/
int fputc(int ch, FILE* f)
{
    /* send a byte of data to the serial port */
    USART_TxData(DEBUG_USART, (uint8_t)ch);

    /* wait for the data to be send*/
    while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);

    return (ch);
}

#elif defined (__GNUC__)

/*!
* @brief       Redirect C Library function printf to serial port.
*            After Redirection, you can use printf function.
*
* @param       ch:The characters that need to be send.
*
* @retval      The characters that need to be send.
*
* @note
*/
int __io_putchar(int ch)
{
    /* send a byte of data to the serial port */
    USART_TxData(DEBUG_USART, ch);

    /* wait for the data to be send*/
    while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);

    return ch;
}

/*!
* @brief       Redirect C Library function printf to serial port.
*            After Redirection, you can use printf function.
*
* @param       file:Meaningless in this function.
*
* @param       *ptr:Buffer pointer for data to be sent.
*
* @param       len:Length of data to be sent.
*
* @retval      The characters that need to be send.
*
* @note
*/
int _write(int file, char* ptr, int len)
{
    int i;
    for (i = 0; i < len; i++)
    {
      __io_putchar(*ptr++);
    }

    return len;
}

#else
#warning Not supported compiler type
#endif




void user_uart_clear(void)
{

        memset(U1_RxBuff, 0, sizeof(U1_RxBuff));
        U1_Rxlen = 0;

}


uint8_t user_uart_wait_receive(void)
{

        if(U1_Rxlen == 0)                                                         //如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数
                return REV_WAIT;
               
        if(U1_Rxlen == U1_RxlencntPre)                                //如果上一次的值和这次相同,则说明接收完毕
        {
                U1_Rxlen = 0;                                                        //清0接收计数
                       
                return REV_OK;                                                                //返回接收完成标志
        }
               
        U1_RxlencntPre = U1_Rxlen;                                        //置为相同
       
        return REV_WAIT;                                                                //返回接收未完成标志

}


void shell_init(void)
{
    printf("\r\n澶氬姛鑳芥寜閿祴璇曞簱\r\n");
}

void shell_process(void)
{
    if(user_uart_wait_receive() == REV_OK)       
        {
                if(strcmp(U1_RxBuff,"LED2_ON") == 0)
                {
                  APM_TINY_LEDOn(LED2);
                  printf("Led2 点亮!\n");
                }
                else if(strcmp(U1_RxBuff,"LED2_OFF") == 0)
                {
                  APM_TINY_LEDOff(LED2);
                  printf("Led2 熄灭!\n");
                }
                else if(strcmp(U1_RxBuff,"LED3_ON") == 0)
                {
                  APM_TINY_LEDOn(LED3);
                  printf("Led3 点亮!\n");
                }
                else if(strcmp(U1_RxBuff,"LED3_OFF") == 0)
                {
                  APM_TINY_LEDOff(LED3);
                  printf("Led3 熄灭!\n");
                }
                else if(strcmp(U1_RxBuff,"LED_ON") == 0)
                {
                  APM_TINY_LEDOn(LED2);APM_TINY_LEDOn(LED3);
                  printf("Led2 Led3 全亮!\n");
                }
                else if(strcmp(U1_RxBuff,"LED_OFF") == 0)
                {
                  APM_TINY_LEDOff(LED2);APM_TINY_LEDOff(LED3);
                  printf("Led2 Led3 全灭!\n");
                }

                user_uart_clear();
    }
        HAL_Delay(10);
}


/**@} end of group USART_Interrupt_Functions */
/**@} end of group USART_Interrupt */
/**@} end of group Examples */



主函数中直接解析




编译烧录到板子
打开电总协议串口助手
[发送]: 7e 31 30 30 31 32 41 34 33 45 30 30 32 31 31 46 44 32 42 0d (~10012A43E00211FD2B )

[接收]: 7e 31 30 30 31 32 41 34 33 30 30 30 30 46 44 41 34 0d (~10012A430000FDA4 )

[发送]: 7e 31 30 30 31 32 41 34 33 45 30 30 32 32 32 46 44 32 39 0d (~10012A43E00222FD29 )

[接收]: 7e 31 30 30 31 32 41 34 33 30 30 30 30 46 44 41 34 0d (~10012A430000FDA4 )
可以看到数据正常收发
[发送]: 7e 31 30 30 31 32 41 34 33 45 30 30 32 34 31 46 44 32 38 0d (~10012A43E00241FD28 )

[接收]: 7e 31 30 30 31 32 41 34 33 30 30 30 30 46 44 41 34 0d (~10012A430000FDA4 )




霜咬回响 发表于 2025-8-30 15:17

这个协议一次性要发送这么的数据帧呀!

龙鳞铁碎牙 发表于 2025-8-30 15:50

霜咬回响 发表于 2025-8-30 15:17
这个协议一次性要发送这么的数据帧呀!

一发一收,没这么多,那是帧内容,不是数据
页: [1]
查看完整版本: 【APM32E030R Micro-EVB开发板评测】——电总协议解析