RXD
#include "ModBus.h"
/******************************************************************/
StrRxd xdata sys_rxd; //定义接收处理结构体
/******************************************************************/
/*******公有函数***************************************************/
void init_proc_rxd(void); //初始化串口通信变量
void process_rxd(void); //通信处理函数
void init_serial(void); //初始化串口
/*******私有函数***************************************************/
uint8 read_sys_rxd(void); //读接收缓冲区
uint8 data_check(void); //校验和检验
uint8 lenghchk(void); //数据长度检验
void data_change(void); //数据ASCII转换成HEX
/******************************************************************/
void init_proc_rxd(void)//初始化串口通信变量
{
uint8 idata i;
for( i = 0;i < POOLLEN;i++ )
{
//读
sys_rxd.pool[i] = 0;//接收数据缓冲区
sys_rxd.rec_buf[i] = 0;//去除包头包尾后的数据保留区,这里只保留一帧有效数据
//写
sys_txd.pool[i] = 0;//发送数据ASCII缓冲区
sys_txd.combuf[i] = 0;//发送数据HEX缓冲区
}
for( i = 0;i < 16;i++ )
{
sys_rxd.add_buf[i] = 0;//用于存放接收缓冲的地址,可以存放16个帧地址,奇数位是首地址,偶数位是尾地址
}
sys_rxd.front = 0;
sys_rxd.rear = 0;
sys_rxd.frm_num = 0;//缓冲区中的帧数量
sys_rxd.rd_byte = 0;//暂存读数据
sys_rxd.start_0x7e = 0;
sys_rxd.end_0x0d = 0;
sys_txd.txd_len = 0;//发送数据长度
}
/*****************************************************************/
uint8 read_sys_rxd(void)//读接收缓冲区
{
if( sys_rxd.rear == sys_rxd.front )
{
return WRONG;
}
else
{
sys_rxd.rd_byte = sys_rxd.pool[sys_rxd.front];
sys_rxd.front = (sys_rxd.front+1) % POOLLEN;
return RIGHT;
}
}
/*****************************************************************/
uint8 data_check(void)//校验和检验
{
uint8 add_len,temp;
uint8 i,j,k,fram_temp;
uint16 chk_sum,chk_sum_temp;
fram_temp = sys_rxd.frm_num;//如何防止在处理数据的同时新的中断使该值变化
add_len = 0;
if( fram_temp )//接收的一帧完整数据
{
fram_temp -= 1;
j = sys_rxd.add_buf[fram_temp * 2];
k = sys_rxd.add_buf[fram_temp * 2 + 1];
if(k > j)
{
add_len = k-j;
}
else
{
add_len = (POOLLEN - j ) + k;//地址确认
}
sys_rxd.front = j;
chk_sum = 0;
for( i = 0;i < add_len - 4;i++ ) //4 byte is check sum
{
read_sys_rxd(); //the poionter is add1
if( sys_rxd.rd_byte == FRAME_START )
{
sys_rxd.rd_byte = 0;
}
chk_sum += sys_rxd.rd_byte;
}
chk_sum = (~chk_sum) + 1;
chk_sum_temp = 0;
for(i=0;i<4;i++)
{
read_sys_rxd();
temp = sys_rxd.rd_byte;//rd_byte 暂存读数据
if(temp > 0x40)
{
temp -= 0x37; // get the hex valume
}
else
{
temp -= 0x30;
}
chk_sum_temp += temp;
if( i < 3 )
{
chk_sum_temp = chk_sum_temp << 4;
}
}
if( chk_sum_temp == chk_sum )
{
return RIGHT;
}
else
{
return WRONG;
}
}
else
{
return WRONG;
}
}
/*****************************************************************/
uint8 lenghchk(void) //数据长度检验
{
uint8 link_sum,link_sum_temp;
uint8 add_len;
uint8 j,k,fram_temp;
if( sys_rxd.rec_buf[4] != lchksum(sys_rxd.rec_buf[5]) )
{
return WRONG;
}
fram_temp = sys_rxd.frm_num; //如何防止在处理数据的同时新的中断使该值变化
if ( fram_temp == 0 )
{
return WRONG;
}
fram_temp--;
j = sys_rxd.add_buf[fram_temp*2];
k = sys_rxd.add_buf[fram_temp*2+1];
if(k>j)
{
add_len = k-j;
}
else
{
add_len = ( POOLLEN - j ) + k;
}
link_sum_temp = (add_len - 17);
link_sum = sys_rxd.rec_buf[5];
if(link_sum != link_sum_temp)
{
return WRONG;
}
else
{
return RIGHT;
}
}
/*****************************************************************/
void data_change(void)//数据ASCII转换成HEX
{
uint8 add_len;
uint8 i,j,k,temp1,fram_temp;
uint8 temp;
fram_temp = sys_rxd.frm_num; //如何防止在处理数据的同时新的中断使该值变化
if ( fram_temp == 0 )
{
return;
}
fram_temp--;
j = sys_rxd.add_buf[fram_temp*2];
k = sys_rxd.add_buf[fram_temp*2+1];
if(k>j)
{
add_len = k-j;
}
else
{
add_len = ( POOLLEN - j ) + k;
}
add_len = add_len / 2 + 1; //cup down 2 byte chksum
sys_rxd.front = j;
for(i = 0;i < add_len;i++ )
{
read_sys_rxd(); //the poionter is add1
if (sys_rxd.rd_byte == 0x0d)
{
sys_rxd.rec_buf[i] = 0xaa;
sys_rxd.rec_buf[i+1]=0x55;
return;
}
if (sys_rxd.rd_byte == 0x7e)
{
read_sys_rxd();
}
temp = sys_rxd.rd_byte;
if(temp>0x40)
{
temp-=0x37;
}
else
{
temp -=0x30;
}
temp = temp<<4;//高4位
read_sys_rxd();//the poionter is add1
temp1 = sys_rxd.rd_byte;
if(temp1>0x40)
{
temp1-=0x37;
}
else
{
temp1-=0x30;
}
sys_rxd.rec_buf[i] = temp+temp1; // include ver/adr/cid1/cid2/length/info
}
}
/*****************************************************************/
void process_rxd(void) //接收缓冲区中的数据 入处理缓冲区
{
while(sys_rxd.frm_num)
{
if(data_check() == WRONG)
{
sys_rxd.add_buf[sys_rxd.frm_num*2] = 0;
sys_rxd.add_buf[sys_rxd.frm_num*2+1] =0;
sys_rxd.frm_num --;
txd_uni(0x02); //校验和错误
return;
}
data_change();
if( (sys_rxd.rec_buf[1] == ADDR ) ) //地址正确
{
if( lenghchk() ==WRONG ) //长度校验
{
sys_rxd.add_buf[sys_rxd.frm_num*2] = 0;
sys_rxd.add_buf[sys_rxd.frm_num*2+1] =0;
sys_rxd.frm_num --;
txd_uni(0x03); //长度校验错误
return;
}
if(sys_rxd.rec_buf[0] != VER)
{
sys_rxd.add_buf[sys_rxd.frm_num*2] = 0;
sys_rxd.add_buf[sys_rxd.frm_num*2+1] =0;
sys_rxd.frm_num --;
txd_uni(0x01); //版本错
return;
}
if( (sys_rxd.rec_buf[2] != M_CID)) //设备ID错
{
sys_rxd.add_buf[sys_rxd.frm_num*2] = 0;
sys_rxd.add_buf[sys_rxd.frm_num*2+1] =0;
sys_rxd.frm_num--;
txd_uni(0xe1); //设备ID错
return;
}
switch(sys_rxd.rec_buf[3])
{
case 0x44:
txd_sta();
break;
case 0x4f:
txd_uni(0x4f); //发送通讯协议版本号
break;
case 0x50:
txd_uni(0x50); //发送设备地址
break;
case 0x51:
txd_man(); //发送设备厂家信息
break;
case 0x60:
txd_uni(0x60); //系统初始化
break;
default:
txd_uni(0x04); //无效命令
break;
}
}
sys_rxd.frm_num--;
}
}
/*****************************************************************/
void init_serial(void)//初始化串口
{
//串行口波特率等设置
TMOD=0x21; // T1 mode 2 T0,mode 1 //GATE C/T M1 M0 GATE C/T M1 M0
TL1=0xfa; // 0xfa=4800 bps 0xfd=9600 bps 0xe8 = 1200 0xf4 = 2400
TH1=0xfa;
TH0=-(10000/256);
TL0=-(10000%256);
PCON=0; //波特率不变等设置
SCON=0x50; //串口1方式1,允许接收
IT0=1; //外部中断0下降沿有效
IT1=1; //外部中断1下降沿有效
TR0=1; //启动定时器0
TR1=1; //启动定时器1
ET0=1; //开放定时器0中断
ES=1; //串行中断
EX0=0; //外部中断0
EX1=1; //外部中断1
EA=1; //开总中断
// RS485EN = 0;
}
/*****************************************************************/
void serial_uart(void) interrupt 4
{
uchar idata temp;
uchar idata num;
if(RI)
{
RI = 0;
temp = SBUF;
if( sys_rxd.start_0x7e && (temp != FRAME_END) )
{
sys_rxd.pool[sys_rxd.rear] = temp;
sys_rxd.rear = (sys_rxd.rear + 1) % POOLLEN;
return;
}
else
{
if( (temp ^ FRAME_START)==0 ) //如果接收到包起始位
{
if( (sys_rxd.start_0x7e) && (sys_rxd.end_0x0d) )
{
sys_rxd.rear = sys_rxd.add_buf[num];
}
else
{ //第一次接收到起始位
sys_rxd.start_0x7e = 1;
sys_rxd.end_0x0d = 1;
num = sys_rxd.frm_num * 2; //新的一帧的起始地址下标
sys_rxd.add_buf[num] = sys_rxd.rear; //起始地址保存
}
sys_rxd.pool[sys_rxd.rear] = temp;
sys_rxd.rear=(sys_rxd.rear+1) % POOLLEN;
return;
}
else
{
if( sys_rxd.start_0x7e && ( temp == FRAME_END ) )
{
sys_rxd.end_0x0d = 0;
sys_rxd.start_0x7e = 0;
sys_rxd.pool[sys_rxd.rear] = temp;
sys_rxd.rear = (sys_rxd.rear+1) % POOLLEN;
num = sys_rxd.frm_num*2+1;//结束地址位
if(sys_rxd.rear==0) //对于POOLLEN不是255的时候,如果直接-1做尾地址。肯定造成尾地址错误。因为 0-1=255
{
sys_rxd.add_buf[num] = POOLLEN - 1;//在写进后的地址已加上1
}
else
{
sys_rxd.add_buf[num] = sys_rxd.rear-1;//在写进后的地址已加上1
}
sys_rxd.frm_num++;//增加一帧//成功才加一位
sys_rxd.frm_num = sys_rxd.frm_num % 16;
return;
}
}
}
}
}
Dies ist ein Beispiel für ein eingebettetes C-Code zur Verarbeitung der Modbus-Kommunikation mit Funktionen wie serieller Port-Kommunikation, Datenüberprüfung, Datenlängeüberprüfung und Datenkonvertierung. Hier ist eine kurze Beschreibung dieses Codes:
StrRxdStrukturen werden verwendet, um relevante Variablen und Daten für die Empfangsverarbeitung zu speichern.init_proc_rxdDie Funktion wird verwendet, um die Variablen der seriellen Kommunikation zu initialisieren. Es löscht einige Puffer - und Flag-Variablen auf Null, um die Daten vorzubereiten.read_sys_rxdDie Funktion wird verwendet, um ein Byte von Daten aus dem Empfangspuffer zu lesen und es in einemsys_rxd.rd_bytezu speichern.data_checkDie Funktion wird für die Überprüfung von Summen verwendet. Es berechnet die Prüfsumme der empfangenen Daten und vergleicht sie mit dem Prüfschutzfeld der empfangenen Daten, um die Datenintegrität zu gewährleisten.lenghchkDie Funktion wird für den Datenlänge-Test verwendet. Es vergleicht das empfangene Datenlänge Feld mit der tatsächlichen Datenlänge, um sicherzustellen, dass die Datenlänge korrekt ist.data_changeDie Funktion wird verwendet, um Daten im ASCII-Format in Daten im Hex-Format für die weitere Verarbeitung zu konvertieren.process_rxdDie Funktion wird verwendet, um die empfangenen Daten zu verarbeiten. Es prüft die Version, die Adresse und die Befehle der Daten anhand der Protokollspezifikation und führt dann entsprechende Aktionen aus.init_serialDie Funktion wird verwendet, um die serielle Kommunikation zu initialisieren. Es konfiguriert Parameter wie die Baudrate und den Timer des seriellen Anschlusses.serial_uartDie Funktion ist ein serieller Port-Empfang Interrupt-Dienstprogramm. Es wird ausgelöst, wenn Daten am seriellen Anschluss empfangen werden, speichert die Daten im Empfangspuffer und löst die entsprechende Verarbeitung Funktion aus.
Dieser Code implementiert einen einfachen Modbus-Protokoll - Parser zum Empfangen und Verarbeiten von Modbus-RTU - Frames. Beachten Sie, dass der Code in diesem Beispiel für spezifische Hardware - und Kommunikationsanforderungen geschrieben wurde und daher entsprechend Ihren Hardware - und Anwendungsanforderungen angemessen geändert werden muss. Darüber hinaus enthält es einige Interruptionsverarbeitung, wie Serien-Empfang - Interrupts und Timer-Interrupts, um asynchrone Kommunikation zu unterstützen. Dieses Code-Beispiel ist ein Ausgangspunkt, den Sie je nach Bedarf erweitern und optimieren können.
TXD
#include "ModBus.h"
//--------公有函数和变量-------
StrTxd xdata sys_txd;
/****************************************/
uint8 lchksum(uint8 data_len); //求LENTH_SUM函数
void txd_sta(void); //发送系统告警信息
void txd_man(void); //发送厂家信息
void txd_uni(uint8 cid2); //发送系统通信信息
/******************************************/
void package(void); //数据打包成ASCII码
void chksum (void); //求校验和
void com(void); //公共的发送函数
/******************************************/
uint8 lchksum(uint8 data_len)//求LENTH_SUM函数
{
uint8 sum,temp1;
sum = 0;
if (data_len)
{
sum = data_len & 0x0f;
temp1 = (data_len & 0xf0)>>4;
sum += temp1;
sum = sum %16;
sum = (~sum)+1;
sum = sum <<4;
}
return sum;
}
/******************************************/
void package(void)//数据打包成ASCII码
{
uint8 i;
uint8 temp1,temp2;
sys_txd.pool[0] = FRAME_START;
for(i = 1;i < POOLLEN; i++)
{
if( (sys_txd.combuf[i] == 0xaa ) && (sys_txd.combuf[i+1] == 0x55 ) ) //结束标志
{
sys_txd.pool[i*2-1] = FRAME_END;
break;
}
else
{
temp1 = sys_txd.combuf[i];
temp2 = temp1 & 0x0f;
temp1 = temp1 & 0xf0;
temp1 = temp1>>4;
sys_txd.pool[i*2-1] = (temp1>0x09)?(temp1+0x37):(temp1+0x30);
sys_txd.pool[i*2] = (temp2>0x09)?(temp2+0x37):(temp2+0x30);
}
}
}
/******************************************/
void chksum (void)//求校验和
{
uint8 i;
uint8 sumh,suml,temp;
uint16 sum = 0;
for(i = 1;i < POOLLEN;i++ )
{
if( sys_txd.pool[i] == FRAME_END )
{
temp = i;
break;
}
else
{
sum += sys_txd.pool[i]; //溢出部分不用考虑
}
}
sum = (~sum) + 1;//取反+1
sumh = (uint8)(sum/256);//高8位
suml = (uint8)sum;
i = temp;
temp = (sumh&0xf0)>>4;
temp = (temp>0x09)?(temp+0x37):(temp+0x30);
sys_txd.pool[i] = temp;
temp = (sumh & 0x0f);
temp = (temp>0x09)?(temp+0x37):(temp+0x30);
sys_txd.pool[i+1] = temp;
temp = (suml&0xf0)>>4;
temp = (temp>0x09)?(temp+0x37):(temp+0x30);
sys_txd.pool[i+2] = temp;
temp = (suml&0x0f);
temp = (temp>0x09)?(temp+0x37):(temp+0x30);
sys_txd.pool[i+3] = temp;
sys_txd.pool[i+4] = FRAME_END;
sys_txd.txd_len = i+4;
return;
}
/******************************************/
void com(void)//公共的发送函数
{
uint8 i;
uint8 j;
EA = 0;
// RS485EN = 1; //使用485通信的时候使用
for( i = 0;i <= sys_txd.txd_len;i++ )
{
SBUF = sys_txd.pool[i];
while(TI==0);
TI = 0;
if( sys_txd.pool[i] == FRAME_END )
{
for( j=0;j <= sys_txd.txd_len;j++ )
{
sys_txd.pool[i] = 0; //对已经发送的数据清0
}
}
}
// RS485EN = 0;
// RI = 0; //注意,如果485的接收使能一直有效,必须要这一行解决
EA = 1;
}
/******************************************/
void txd_sta(void)//发送系统告警信息
{
sys_txd.combuf[0] = FRAME_START; //起始标志
sys_txd.combuf[1] = VER; //版本号
sys_txd.combuf[2] = ADDR; //地址,主机
sys_txd.combuf[3] = M_CID; //设备ID
//------以上是包头---------
sys_txd.combuf[4] = 0x44; //Cid2=0x44,表示发送所有的告警状态
//------length---------
sys_txd.combuf[5] = lchksum(20); //length checksum//////////////////////
sys_txd.combuf[6] = 20; //length id
/********************************************/
sys_txd.combuf[7] = 20; //这里放告警信息
sys_txd.combuf[8] = 20; //
sys_txd.combuf[9] = 20; //
sys_txd.combuf[10] = 20; //
/********************************************/
sys_txd.combuf[11] = 0xaa; //end ;
sys_txd.combuf[12] = 0x55; //数据打包成ASCII码
package(); //////////////////////////////
chksum(); //除起始和校验和以及结束之外的ASCII码求校验和
com();
}
/******************************************************/
void txd_man(void)//发送厂家信息
{
//-----------------------------------------------------------------
sys_txd.combuf[0] = FRAME_START; //起始标志
sys_txd.combuf[1] = VER; //版本号
sys_txd.combuf[2] = ADDR; //地址,主机
sys_txd.combuf[3] = M_CID; //设备ID
//----------以上是包头
//-----------------------------------------------------------------
sys_txd.combuf[4] =0x51;
sys_txd.combuf[5] =lchksum(0x40);
sys_txd.combuf[6] =0x40;
sys_txd.combuf[7] = 'L'; //L
sys_txd.combuf[8] = 'I'; //I
sys_txd.combuf[9] = 'N'; //N
sys_txd.combuf[10] = 'E'; //E
sys_txd.combuf[11] = 0;
sys_txd.combuf[12] = 0x00;
sys_txd.combuf[13] = 0x00;
sys_txd.combuf[14] = 0x00;
sys_txd.combuf[15] = 0x00;
sys_txd.combuf[16] = 0x00;
sys_txd.combuf[17] = 0x01; //1 版本
sys_txd.combuf[18] = 0x00; //0
sys_txd.combuf[19] = 0x41; //A 厂家
sys_txd.combuf[20] = 0x41; //A
sys_txd.combuf[21] = 0x41; //A
sys_txd.combuf[22] = 0x41; //A
sys_txd.combuf[23] = 0x41; //A
sys_txd.combuf[24] = 0x41; //A
sys_txd.combuf[25] = 0x41; //A
sys_txd.combuf[26] = 0x41; //A
sys_txd.combuf[27] = 0x41; //A
sys_txd.combuf[28] = 0x41; //A
sys_txd.combuf[29] = 0x00;
sys_txd.combuf[30] = 0x00;
sys_txd.combuf[31] = 0x00;
sys_txd.combuf[32] = 0x00;
sys_txd.combuf[33] = 0x00;
sys_txd.combuf[34] = 0x00;
sys_txd.combuf[35] = 0x00;
sys_txd.combuf[36] = 0x00;
sys_txd.combuf[37] = 0x00;
sys_txd.combuf[38] = 0x00;
sys_txd.combuf[39] = 0xaa;
sys_txd.combuf[40] = 0x55;
package(); //数据打包成ASCII码
chksum(); //除起始和校验和以及结束之外的ASCII码求校验和
com();
}
/******************************************/
void txd_uni(uint8 cid2)//发送系统通信信息
{
//-----------------------------------------------------------------
sys_txd.combuf[0] = FRAME_START; //起始标志
sys_txd.combuf[1] = VER; //版本号
sys_txd.combuf[2] = ADDR; //地址,主机
sys_txd.combuf[3] = M_CID; //设备ID
//----------以上是包头
//-----------------------------------------------------------------
sys_txd.combuf[4] = cid2;
sys_txd.combuf[5] = lchksum(0x00); //length checksum 0x00
sys_txd.combuf[6] = 0x00; //length id 00
sys_txd.combuf[7] = 0xaa; //length id=00,所以,没有info
sys_txd.combuf[8] = 0x55;
package(); //数据打包成ASCII码
chksum(); //除起始和校验和以及结束之外的ASCII码求校验和
com();
}
/******************************************/
Dieser Code ist eine Funktion, die das Verpacken und Senden von Daten in der Modbus-Kommunikation verarbeitet. Hier finden Sie eine kurze Beschreibung jeder Funktion: Die Funktion
lchksumwird verwendet, um die Länge-Checksumme (length checksum) zu berechnen, um sicherzustellen, dass das Datenlänge-Feld korrekt ist. Es akzeptiert einen Parameterdata_len, berechnet und gibt eine Prüfsumme der Länge zurück.packageFunktionen werden verwendet, um Daten in ASCII-Format zu verpacken. Es konvertiert Daten im HEX-Format in ASCII-Code und fügt geeignete Trennzeichen zwischen jedes HEX-Byte ein. Die endgültigen Daten werden in dersys_txd.combufgespeichert.chksumDie Funktion wird zur Berechnung der Prüfsumme verwendet. Es berechnet die Prüfsumme aller Daten außer dem Start-Flag, dem Prüfsummefeld und dem End-Flag und fügt diese zu den Daten hinzu.comFunktionen werden verwendet, um Daten zu senden. Es sendet Daten über einen seriellen Anschluss und löscht die gesendeten Daten für die nächste Verwendung.txd_staDie Funktion wird verwendet, um Systemwarnmeldungen zu senden. Er gibt einen bestimmten Befehl.cid2(0x44) ein, der den Senden einer Warnmeldung angibt. Anschließend wird die Datenlänge, die Warnmeldung und andere relevante Felder festgelegt und schließlich die Funktionpackage、chksum和comFunktionen senden Daten.txd_manDie Funktion wird verwendet, um Herstellerinformationen zu senden. Er gibt einen bestimmten Befehl.cid2(0x51): Anzeigt, dass die Hersteller-Informationen gesendet werden. Anschließend wird die Datenlänge, die Herstellerinformationen und andere relevante Felder festgelegt und schließlich die Funktionpackage、chksum和comaufgerufen, um die Daten zu senden.txd_uniDie Funktion wird verwendet, um Systemkommunikationsinformationen zu senden. Es akzeptiert einen Parametercid2, der den Kommunikationsbefehl darstellt. Abhängig voncid2setzt er den entsprechenden Befehl und sendet die entsprechenden Daten.
Diese Funktionen erstellen zusammen den Prozess des Datensendens, um verschiedene Modbus-Frame - Arten zu senden. Beachten Sie, dass der Code in diesem Beispiel für eine spezifische Anwendung geschrieben wurde und daher entsprechend Ihren Anforderungen angepasst werden muss. Darüber hinaus enthält das Codebeispiel einige Funktionen für die serielle Kommunikation und Datenkonvertierung zur Unterstützung der Modbus-Kommunikation.
ModBusStr
#ifndef MODBUSSTR_H
#define MODBUSSTR_H
//==============================================
#define uchar unsigned char
#define uint unsigned int
#define uint8 unsigned char
#define uint16 unsigned int
//接收缓冲区结构变量
typedef struct str_rxd_pool
{
uint8 pool[255]; //接收数据缓冲区
uint8 front; //头指针
uint8 rear; //尾指针
uint8 rd_byte; //暂存读数据
uint8 frm_num; //缓冲区中的帧数量
uint8 add_buf[16]; //用于存放接收缓冲的地址,可以存放16个帧地址,奇数位是首地址,偶数位是尾地址
uint8 rec_buf[255]; //去除包头包尾后的数据保留区,这里只保留一帧有效数据
uint8 start_0x7e; //接收到帧头标志
uint8 end_0x0d; //接收到帧尾标志
}StrRxd;
//===============================================
//发送缓冲区结构变量
typedef struct str_txd_pool
{
uint8 pool[255]; //发送数据ASCII缓冲区
uint8 combuf[255]; //发送数据HEX缓冲区
uint8 txd_len; //发送数据长度
}StrTxd;
#endifDies ist eine C-Headerdatei (MODBUSSTR.H), die die Datenstrukturen und die zugehörigen Typen-Aliases für die Modbus-Kommunikation definiert. Hier sind die wichtigsten Elemente, die in dieser Header-Datei definiert sind:
- Header-Datei - Schutz Makro-Definition
#ifndef MODBUSSTR_H和#define MODBUSSTR_H, um sicherzustellen, dass die Datei nur einmal enthalten wird. - Definition für einige Typen von Alias, wobei
uchar、uint、uint8和uint16unsignierte Zeichen, unsignierte Ganzzahl und unsignierte Ganzzahl unterschiedlicher Breite darstellt. StrRxdStruktur-Definition, die für den Empfang der zugehörigen Datenstruktur des Puffers verwendet wird. Diese Struktur umfasst folgende Mitglieder:
pool[255]: Der Puffer zum Speichern empfangener Daten mit einer maximalen Länge von 255 Bytes.front: Der Kopfzeiger zeigt auf den Anfang des Puffers.rear: Endzeiger, der auf das Ende des Puffers zeigt.rd_byte: Speichern von gelesenen Daten.frm_num: Die Anzahl der Frames im Puffer.add_buf[16]: Die Adresse des Empfangspuffers kann 16 Frame-Adressen gespeichert werden, ungerade Bits sind die Anfangs-Adresse, gerade Bits sind die End-Adresse.rec_buf[255]: Speichert die Daten nach dem Entfernen von Header und End und behält nur einen Frame der gültigen Daten.start_0x7e: Indiziert, ob ein Frame-Header - Flag empfangen wurde.end_0x0d: Zeigt an, ob ein Frame-End - Flag empfangen wurde.
StrTxdStruktur-Definition, die für die Übertragung der zugehörigen Datenstrukturen des Puffers verwendet wird. Diese Struktur umfasst folgende Mitglieder:
pool[255]: Puffer in Form von ASCII-Codes für die Speicherung der gesendeten Daten, maximal 255 Byte lang.combuf[255]: Puffer in Hexform für die Speicherung der gesendeten Daten, maximal 255 Byte lang.txd_len: Die Länge der übertragenen Daten.
Diese Header-Datei definiert die Datenstrukturen, die für die Modbus-Kommunikation verwendet werden, und Sie können diese Header-Dateien in Ihre Anwendung enthalten, um auf diese Datenstrukturen und Typ-Alias zuzugreifen. Dies hilft bei der besseren Organisation und Verwaltung von Daten in der Modbus-Kommunikation.
ModBus
#include "reg51.h"
#include "ModBusStr.h"
#define uchar unsigned char
#define uint unsigned int
#define uint8 unsigned char
#define uint16 unsigned int
#define OK 1
#define ERROR 0
#define RIGHT 1
#define WRONG 0
#define POOLLEN 255 //缓冲区大小
#define INIT_COMMAND 0x20
#define START_COMMAND 0x21
#define END_COMMAND 0x22
#define ALARM_COMMAND 0x23
#define FRAME_START 0x7e //帧开始标志
#define FRAME_END 0x0d //帧结束标志
#define VER 0x10
#define ADDR 0x01
#define M_CID 0x25 //设备识别码,0x25代表直流电源柜
extern StrRxd xdata sys_rxd;
extern StrTxd xdata sys_txd;
extern void init_proc_rxd(void);
extern void process_rxd(void);
extern void init_serial(void);
extern uint8 lchksum(uint8 data_len);
extern void txd_sta(void);
extern void txd_man(void);
extern void txd_uni(uint8 cid2);
Dieser Code ist eine Header-Datei, die einige Makro-Definitionen, Datenstrukturen enthält."ModBusStr.h"für Makro-Definitionen, Datenstrukturen und andere verwandte Headerdateien"reg51.h"sowie globale Variablen und Funktionsprototypen.
Hier sind einige wichtige Elemente im Code: Die
- Header enthält:
"reg51.h": Dies ist eine Standard-Headerdatei für die 8051 - Serie von Single-Chip - Computern, die die Definitionen von Registeren und Makros für die Chips der Serie enthält."ModBusStr.h": Dies ist eine Header-Datei, die Sie selbst erstellt haben und enthält die Datenstrukturen und Typen-Alias, die für die Modbus-Kommunikation relevant sind.
- Definition von Macro:
OK和ERROR: definiert zwei Konstanten, 1 und 0, die normalerweise für den Erfolg und Misserfolg einer Funktion verwendet werden.RIGHT和WRONG: definiert zwei Konstanten, die häufig zum Erfolg oder Misserfolg bestimmter Bedingungen oder Vorgänge verwendet werdenPOOLLEN: Die maximale Länge des Puffers ist 255 definiert.INIT_COMMAND、START_COMMAND、END_COMMAND和ALARM_COMMAND: Definiert Befehlkonstanten, die verschiedene Operationen darstellen.FRAME_START和FRAME_END: Die Beginn - und End-Fahlen des Frames werden definiert.VER和ADDR: Die Versionsnummer und die Adresse werden festgelegt.M_CID: Der ID-Code des Geräts wird definiert.
- Externe globale Variablendeklaration:
StrRxd xdata sys_rxd和StrTxd xdata sys_txd: Zwei externe globale Variablen,sys_rxd和sys_txdDiese Variablen werden in anderen Quelldateien definiert und werden für die Speicherung von Daten im Zusammenhang mit der Modbus-Kommunikation verwendet.
- Externe Funktionsprototypdeklaration:
void init_proc_rxd(void)、void process_rxd(void)和void init_serial(void): Diese Funktionsprototypendeklarationen werden für die Initialisierung der Empfangsverarbeitung, Kommunikationsverarbeitung und der Initialisierung der seriellen Ports verwendet.uint8 lchksum(uint8 data_len)、void txd_sta(void)、void txd_man(void)和void txd_uni(uint8 cid2): Diese Funktionsprototypen deklarieren die Längensprüfsumme, das Senden von Systemwarnmeldungen, das Senden von Herstellerinformationen und das Senden von Systemkommunikationsinformationen.
Dieser Code organisiert die Daten und Funktionen, die für die Modbus-Kommunikation relevant sind, und stellt diese Definitionen und Deklarationen anderen Quelldateien über eine Headerdatei zur Verfügung. Die Quelldatei kann diese Header-Datei enthalten, um auf diese Definitionen und Deklarationen zuzugreifen, um die Modbus-Kommunikationsfunktionen zu implementieren.
MainTest
#include "ModBus.h"
void main(void)
{
init_serial();//初始化串口
init_proc_rxd();//初始化串口通信变量
while(1)
{
process_rxd();//通信处理函数 接收缓冲区中的数据 入处理缓冲区
}
}
Dies ist ein Beispiel für das Hauptprogramm auf einem 8051 - MCU, das die Modbus-Kommunikationsverarbeitung ausführt. In der Hauptfunktion verfolgt sie folgende Schritte:
- enthält die
ModBus.h- Headerdatei, die alle notwendigen Definitionen, globalen Variablen und Funktionsprototypen enthält, um die Modbus-Kommunikation zu unterstützen. - Aufruft die
init_serial()- Funktion zur Initialisierung der seriellen Anschlusskommunikation, ein wichtiger Schritt zur Einrichtung und Vorbereitung der Kommunikation mit anderen Geräten. - Aufruft die
init_proc_rxd()- Funktion zur Initialisierung der Serienport-Kommunikationsvariablen. Dieser Schritt dient normalerweise dazu, sicherzustellen, dass sich die Kommunikationsvariablen im richtigen Ausgangszustand befinden. - tritt in eine unendliche Schleife (
while(1)) ein, in der die folgenden Aktionen fortgesetzt werden:
- ruft die
process_rxd()- Funktion auf, die für die Kommunikationsverarbeitung verwendet wird, die Daten aus dem Puffer empfängt und verarbeitet. In der Regel handelt es sich um einen Prozess, der kontinuierlich Modbus-Kommunikationsanfragen von anderen Geräten überwacht und verarbeitet.
Das gesamte Programm läuft kontinuierlich, wartet auf die Kommunikationsanfrage von anderen Geräten und führt dann die entsprechenden Aktionen aus. In diesem Beispiel wird hauptsächlich die Initialisierung und Verarbeitung der Modbus-Kommunikation verwendet, wobei die tatsächliche Kommunikationslogik und die Antwort in der Funktionprocess_rxd()implementiert werden.

Antwort veröffentlichen