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

[复制链接]
543|2
龙鳞铁碎牙 发表于 2025-8-29 20:34 | 显示全部楼层 |阅读模式
电总协议又称为空调协议,广泛应用于家用空调和一些高压输电场合,在电力电子当中使用非常的广泛!!!
先看数据帧格式!!

4206268b19c539e820.png

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。
9822368b19c7bce745.png
2861568b19c8a4464b.png
3.2 基本数据格式
在7.2基本格式中的各项除SOI和EOI是以(SOI = 7EH,EOI = 0DH)十六进制传输外,其余各项都是以ASCII码的方式传输,每个字节用两个ASCII码表示,即高四位一个ASCII码表示,低四位用一个ASCII码表示。例:CID2 = 4BH,传送时顺序发送34H,42H。
4913468b19ca5d44df.png
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
两个字节的整型数据传送顺序为先高字节后低字节。
日期时间格式
6995268b19cc0331a2.png
CID1、CID2编码分配及分类见表6和表7
1542268b19cda8c4e0.png
1 获取模拟量数据(定点数)(42H)
2404768b19d128c42d.png
0x7E,0x21,0x01,0x60,0x42,0x00,0x00,0xFD,0xB0,0x0D
2466768b19d24da1bc.png
好了,开始进入核心代码

#ifndef  COMM_H
#define  COMM_H


#include "main.h"


#define  REC_MAX   1024    // 定义接收缓存区的大小
#define  SEND_MAX  1024    // 定义发送缓存区的大小


#define  print printf




// 通讯常量定义
#define  SERIAL_TIME_ISR   5            // 定时器间隔 ms
#define  TIME_OUT          500          // 接收超时时间 500ms
#define  TIME_SLEEP        10000        // 休眠超时时间 10S

typedef struct
{
  uint8_t  RecBuf[REC_MAX];    // 接收缓存区
  uint16_t RecCount;           // 接收的字节数
  uint8_t  SendBuf[REC_MAX];   // 发送缓存区
  uint16_t SendCount;          // 要发送的字节数
  uint8_t  RecOver;            // 接收完成标志
  uint16_t RecTimer;           // 接收计时器
  uint16_t SleepTime;          // 休眠计时
  uint8_t  SleepFlag;          // 通讯休眠标志
} 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"



#define  SOI       0x7E     // 起始标志
#define  VER       0x10     // v1.0
#define  ADR       0x01     // 地址描述符
#define  CID1      0x2A     // 设备描述符
#define  EOI       0x0D     // 结束码
#define  CID2      0x43






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


#define  MODX   0x10000
#define  sendData 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);


static  uint8_t * FloatToChar(float *pFData);
static  float * CharToFloat(uint8_t *pChar);



static  uint8_t htoa_H(uint8_t H);
static  uint8_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[0]=SOI;MSG_SERIAL.RecCount=1; // 启动接收
   }  
   else if((MSG_SERIAL.RecBuf[0]==SOI)&&(MSG_SERIAL.RecCount<REC_MAX)) // 如果已经接收到起始位
   {
             MSG_SERIAL.RecBuf[MSG_SERIAL.RecCount++]=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_t  LF_hex[2] = {0};
        uint16_t LENGTH = 0;
        uint8_t  lchsum = 0;

        atoh2b(&LF_hex[0], &MSG_SERIAL.RecBuf[9]);
        atoh2b(&LF_hex[1], &MSG_SERIAL.RecBuf[11]);
        LENGTH = (uint16_t)LF_hex[0]<<8|LF_hex[1];
        lchsum = htoa_L((uint8_t) ((~((((LENGTH >> 8)&0x0F) | ((LENGTH >> 4) & 0x0F) | (LENGTH & 0x0F)) % MODX) + 1) & 0x0F));
       
#if 1
        if(lchsum == MSG_SERIAL.RecBuf[9])
        {
                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_t  LF_TxB[2] = {0};
  uint16_t CHKSUM  = 0;

  atoh2b(&LF_TxB[0], &MSG_SERIAL.RecBuf[13+leng_id]);
  atoh2b(&LF_TxB[1], &MSG_SERIAL.RecBuf[15+leng_id]);

  CHKSUM  = (uint16_t)(LF_TxB[0]<<8|LF_TxB[1]);

  if(CHKSUM==ChkSum(&MSG_SERIAL.RecBuf[1],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[1])!= VER) {return;} //
   if(atohex16(&MSG_SERIAL.RecBuf[3])!= ADR) {return;} //
   if(atohex16(&MSG_SERIAL.RecBuf[5])!= 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[7])); //  
   ClrRcvBuf();          // 清缓存区  
}

// 将浮点数分解为4个字节
static uint8_t * FloatToChar(float *pFData)
{
   void *pVoid;
   static uint8_t chart[4];
   uint8_t i;
   pVoid=pFData;
   for(i=0;i<4;i++)
   {
     chart=*((uint8_t *)pVoid+i);
   }
   return (&chart[0]);
}
// 将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[index++] = SOI;        //print("index = %02d\r\n",index);
        sendData[index++] = htoa_H(VER);//print("index = %02d\r\n",index);
        sendData[index++] = htoa_L(VER);
        sendData[index++] = htoa_H(ADR);
        sendData[index++] = htoa_L(ADR);
        sendData[index++] = htoa_H(CID1);
        sendData[index++] = htoa_L(CID1);
        sendData[index++] = htoa_H(CID2);
        sendData[index++] = 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[9]=LCHKSUM(leng_id1);  //9
        htoa3b(&sendData[10], leng_id1);//10 11 12
        sendData[13]=htoa_H(1);sendData[14]=htoa_L(1);//1
        sendData[15]=htoa_H(00);sendData[16]=htoa_L(00);sendData[17]=htoa_H(0xFA);sendData[18]=htoa_L(0xFA);
        sendData[19]=htoa_H(2);sendData[20]=htoa_L(2);//2
        sendData[21]=htoa_H(00);sendData[22]=htoa_L(00);sendData[23]=htoa_H(0xFA);sendData[24]=htoa_L(0xFA);
        sendData[25]=htoa_H(3);sendData[26]=htoa_L(3);//3
        sendData[27]=htoa_H(00);sendData[28]=htoa_L(00);sendData[29]=htoa_H(0xFA);sendData[30]=htoa_L(0xFA);
        checksum = ChkSum(&sendData[1],12+leng_id1);//print("checksum = 0x%02x\r\n",checksum);
       
        htoa4b(&sendData[31], checksum);//31 32 33 34
        sendData[35]=EOI;
        SerialStartSend(sendData); // 启动发送       
}

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

        leng_id1 = 0;
        SendBuff();
        sendData[9] = LCHKSUM(leng_id1);
        htoa3b(&sendData[10], leng_id1);//10 11 12
        checksum = ChkSum(&sendData[1],12+leng_id1);
        htoa4b(&sendData[13], checksum);
        sendData[17]=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_USART  USART1

/**@} 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_t  U1_RxBuff[RXBUFFLENGTH];
uint16_t U1_Rxlen = 0;
uint16_t U1_RxlencntPre = 0;


#define CMD_LEN 64
static char cmd[CMD_LEN];
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 into  void USART1_IRQHandler(void)
*/
void  USART_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[U1_Rxlen++] = 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 */



主函数中直接解析
4307568b19d79ef58e.png


2699768b19d8a421af.png
编译烧录到板子
3739968b19da88e05a.png
打开电总协议串口助手
2139668b19dcab7fa1.png
[2025-08-29 20:32:35.890][发送]: 7e 31 30 30 31 32 41 34 33 45 30 30 32 31 31 46 44 32 42 0d (~10012A43E00211FD2B )

[2025-08-29 20:32:35.949][接收]: 7e 31 30 30 31 32 41 34 33 30 30 30 30 46 44 41 34 0d (~10012A430000FDA4 )
6164068b19ddcbaa5b.png
[2025-08-29 20:32:38.703][发送]: 7e 31 30 30 31 32 41 34 33 45 30 30 32 32 32 46 44 32 39 0d (~10012A43E00222FD29 )

[2025-08-29 20:32:38.764][接收]: 7e 31 30 30 31 32 41 34 33 30 30 30 30 46 44 41 34 0d (~10012A430000FDA4 )
可以看到数据正常收发
7895468b19e0c33ab3.png
[2025-08-29 20:33:26.066][发送]: 7e 31 30 30 31 32 41 34 33 45 30 30 32 34 31 46 44 32 38 0d (~10012A43E00241FD28 )

[2025-08-29 20:33:26.125][接收]: 7e 31 30 30 31 32 41 34 33 30 30 30 30 46 44 41 34 0d (~10012A430000FDA4 )




6299068b19d96be3f5.png
1653268b19de47f700.png
霜咬回响 发表于 2025-8-30 15:17 | 显示全部楼层
这个协议一次性要发送这么的数据帧呀!
 楼主| 龙鳞铁碎牙 发表于 2025-8-30 15:50 | 显示全部楼层
霜咬回响 发表于 2025-8-30 15:17
这个协议一次性要发送这么的数据帧呀!

一发一收,没这么多,那是帧内容,不是数据
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

54

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部