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

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

4。获取开关输入状态(43H)

好了,开始进入核心代码
#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;
++cp;
if (*cp <= '9')
*hp += *cp - '0';
else
{
*cp &= 0xdf;
*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[i]);
}
#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[i]=*((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[i]=*(pData+i);
}
uart9_Send_Bytes(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); // 启动发送
}
#include "hal_data.h"
#include "usart9.h"
#include "shell.h"
#include "ebtn_app.h"
#include "Serial.h"
FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER
/*******************************************************************************************************************//**
-
main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used. This function
-
is called by main() when no RTOS is used.
*********************************************************************************************************************/
void hal_entry(void)
{
/ TODO: add your own code here */
UART9_Init();hal_systick_init();
shell_init();
ebtn_APP_Key_INIT();
while(1)
{
SerialDecode();
/*
switch(key_count)
{
case 1:
led2_off();
led1_on();HAL_Delay(200);
led1_off();HAL_Delay(200);
break;
case 2:
led1_off();
led2_on();HAL_Delay(200);
led2_off();HAL_Delay(200);
break;
case 3:
led1_on();led2_on();HAL_Delay(200);
led1_off();led2_off();HAL_Delay(200);
break;
case 4:
led1_on();led2_off();HAL_Delay(200);
led1_off();led2_on();HAL_Delay(200);
break;
case 5:
led1_on();led2_on();
break;
default:
led1_off();led2_off();
break;
}
*/
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
/*******************************************************************************************************************//**
-
This function is called at various points during the startup process. This implementation uses the event that is
-
called right before main() to set up the pins.
-
@param[in] event Where at in the start up process the code is currently at
**********************************************************************************************************************/
void R_BSP_WarmStart (bsp_warm_start_event_t event)
{
if (BSP_WARM_START_RESET == event)
{
#if BSP_FEATURE_FLASH_LP_VERSION != 0
R_FACI_LP->DFLCTL = 1U;
#endif
}
if (BSP_WARM_START_POST_C == event)
{
R_IOPORT_Open(&IOPORT_CFG_CTRL, &IOPORT_CFG_NAME);
#if BSP_CFG_SDRAM_ENABLED
R_BSP_SdramInit(true);
#endif
}
}
#if BSP_TZ_SECURE_BUILD
FSP_CPP_HEADER
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();
/* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ()
{
}
FSP_CPP_FOOTER
#endif




编译烧录板子

打开电总协议上位机软件

设置好参数

发送数据 7e 31 30 30 31 32 41 34 33 45 30 30 32 34 33 46 44 32 36 0d (~10012A43E00243FD26 )
接收数据 7e 31 30 30 31 32 41 34 33 30 30 30 30 46 44 41 34 0d (~10012A430000FDA4 )
数据正常,完结!!!!!!!!!!