ModbusKommunikationVereinbarung的vollständigC/C++源Beispiel Code

kostenlosKostenloses technisches Material

Dieser Inhalt ist direkt lesbar und eignet sich für das Grundlagenlernen und die Suche.

ModbusKommunikationVereinbarung的vollständigC/C++源Beispiel Code缩略图
🌐 Diese Seite ist noch nicht auf Deutsch verfügbar. Die chinesische Version wird angezeigt. Zurück zur chinesischen Seite.
本文目录
  1. 1. RXD
  2. 2. TXD
  3. 3. ModBusStr
  4. 4. ModBus
  5. 5. MainTest

RXD

#include "ModBus.h"
/******************************************************************/
StrRxd xdata sys_rxd;               //定义Empfang处理结构体
/******************************************************************/
/*******公有函数***************************************************/
void    init_proc_rxd(void);        //初始化Serielle Kommunikation变Quantität
void    process_rxd(void);          //Kommunikation处理函数
void    init_serial(void);          //初始化Die Serie
/*******私有函数***************************************************/
uint8   read_sys_rxd(void);         //读Empfang缓冲区
uint8   data_check(void);           //Prüfungen und检验
uint8   lenghchk(void);             //DatenLänge检验
void    data_change(void);          //DatenASCII转换成HEX
/******************************************************************/
void    init_proc_rxd(void)//初始化Serielle Kommunikation变Quantität
{
    uint8 idata i;
    for( i = 0;i < POOLLEN;i++ )
    {
        //读
		sys_rxd.pool[i] = 0;//EmpfangDaten缓冲区
        sys_rxd.rec_buf[i] = 0;//去除包头包尾后的Daten保留区,这里只保留一帧WirksamDaten
        //写
		sys_txd.pool[i] = 0;//Senden SieDatenASCII缓冲区
        sys_txd.combuf[i] = 0;//Senden SieDatenHEX缓冲区
    }
    for( i = 0;i < 16;i++ )
    {
        sys_rxd.add_buf[i] = 0;//用于存放Empfang缓冲的Adresse,可以存放16个帧Adresse,奇数位是首Adresse,偶数位是尾Adresse
    }

    sys_rxd.front = 0;
    sys_rxd.rear = 0;
    sys_rxd.frm_num = 0;//缓冲区中的帧Anzahl
    sys_rxd.rd_byte = 0;//暂存Lesen von Daten
    sys_rxd.start_0x7e = 0;
    sys_rxd.end_0x0d = 0;

    sys_txd.txd_len = 0;//Senden SieDatenLänge
}
/*****************************************************************/
uint8 	read_sys_rxd(void)//读Empfang缓冲区
{
 	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)//Prüfungen und检验
{
    uint8  add_len,temp;
	uint8   i,j,k,fram_temp;
	uint16  chk_sum,chk_sum_temp;

	fram_temp = sys_rxd.frm_num;//如何防止在处理Daten的同时新的中断使该值变化
	add_len = 0;

	if( fram_temp )//Empfang的一帧vollständigDaten
    {
		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;//AdresseBestätigen
		}

        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 暂存Lesen von Daten

			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)    //DatenLänge检验
{
    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; //如何防止在处理Daten的同时新的中断使该值变化
	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)//DatenASCII转换成HEX
{
    uint8  add_len;
	uint8  i,j,k,temp1,fram_temp;
	uint8  temp;

    fram_temp = sys_rxd.frm_num; //如何防止在处理Daten的同时新的中断使该值变化
	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) //Empfang缓冲区中的Daten 入处理缓冲区
{
    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);  //Prüfungen undFehler.
            return;
     	}

        data_change();

        if( (sys_rxd.rec_buf[1] == ADDR ) )  //AdresseRichtig.
        {
            if( lenghchk() ==WRONG )  //LängePrüfungen
            {
                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);  //LängePrüfungenFehler.
                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))  //AusrüstungID错
            {
                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);  //AusrüstungID错
                return;
            }
            switch(sys_rxd.rec_buf[3])
            {
                case 0x44:
                    txd_sta();
               	    break;
                case 0x4f:
                    txd_uni(0x4f);      //Senden Sie通讯Vereinbarung版本Nr.
                    break;
                case 0x50:
                    txd_uni(0x50);      //Senden SieGeräte Adresse
                    break;
                case 0x51:
                    txd_man();      //Senden SieAusrüstung厂家信息
                    break;
                case 0x60:
                    txd_uni(0x60);      //Das System初始化
                    break;
                default:
                    txd_uni(0x04);  //UnwirksamBefehl
                    break;
            }
        }
        sys_rxd.frm_num--;
    }
}
/*****************************************************************/
void    init_serial(void)//初始化Die Serie
{
  	//串行口Porter Rate等设置
        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;          //Porter Rate不变等设置
        SCON=0x50;       //Die Serie1方式1,允许Empfang
        IT0=1;           //外部中断0sinken entlangWirksam
        IT1=1;           //外部中断1sinken entlangWirksam
        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 )    //如果Empfangzu包Anfang位
            {
                if( (sys_rxd.start_0x7e) && (sys_rxd.end_0x0d) )
                {
                    sys_rxd.rear = sys_rxd.add_buf[num];
                }
                else
                {   //Die一次EmpfangzuAnfang位
                    sys_rxd.start_0x7e = 1;
                    sys_rxd.end_0x0d = 1;
                    num = sys_rxd.frm_num * 2;    //新的一帧的Ausgang Adresse下标
                    sys_rxd.add_buf[num] = sys_rxd.rear;  //Ausgang Adresse保存
                }
                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;//EndeAdresse位

                    if(sys_rxd.rear==0)   //对于POOLLEN不是255的时候,如果直接-1做尾Adresse。肯定造成尾AdresseFehler.。因为 0-1=255
                    {
                        sys_rxd.add_buf[num] = POOLLEN - 1;//在写进后的Adresse已加上1
                    }
                    else
                    {
                        sys_rxd.add_buf[num] = sys_rxd.rear-1;//在写进后的Adresse已加上1
                    }

                    sys_rxd.frm_num++;//增加一帧//成功才加一位
                    sys_rxd.frm_num = sys_rxd.frm_num % 16;
                    return;
                }
            }
        }
    }
}

这是一个用于处理ModbusKommunikation的EingebettetCBeispiel Code,包含了Serielle Kommunikation、DatenPrüfungen、DatenLänge检验和Daten转换等Funktion。以下是对这段代码的简要说明:

  1. StrRxd 结构体用于存储Empfang处理的Related变Quantität和Daten。
  2. init_proc_rxd 函数用于初始化Serielle Kommunikation变Quantität。它清零了一些缓冲区和标志变Quantität,以准备EmpfangDaten。
  3. read_sys_rxd 函数用于从Empfang缓冲区中Lesen一个Bytes的Daten,并将其存储在 sys_rxd.rd_byte 中。
  4. data_check 函数用于Prüfungen und检验。它BerechnungEmpfangDaten的Prüfungen und并与EmpfangDaten的PrüfungenFeld进行比较,以确保Datenvollständig性。
  5. lenghchk 函数用于DatenLänge检验。它比较Empfangzu的DatenLängeFeld与实际DatenLänge,以确保DatenLängeRichtig.。
  6. data_change 函数用于将ASCIIDas Format的Daten转换为HEXDas Format的Daten,以便进一步处理。
  7. process_rxd 函数用于处理Empfangzu的Daten。它根据Vereinbarung规范检查Daten的版本、Adresse和Befehl,然后执行相应的Operationen。
  8. init_serial 函数用于初始化Serielle Kommunikation。它配置了Die Serie的Porter Rate、定时器等Parameter。
  9. serial_uart 函数是Die SerieEmpfang中断服务程序。它在Die SerieEmpfangzuDaten时触发,将Daten存储在Empfang缓冲区中,并触发相应的处理函数。

这段代码实现了一个简单的ModbusKommunikationVereinbarungAnalyse器,用于Empfang和处理Modbus RTU帧。请注意,此Beispiel中的代码是为特定硬件和Kommunikation要求编写的,因此需要根据您的硬件和应用程序要求进行适当的修改。此外,它还包含了一些中断处理,如Die SerieEmpfang中断和定时器中断,以支持AsynchronKommunikation。这个Beispiel Code是一个起点,您可以根据需要进行扩展和优化。

TXD

#include "ModBus.h"
//--------公有函数和变Quantität-------
StrTxd xdata sys_txd;
/****************************************/
uint8 lchksum(uint8  data_len);    //求LENTH_SUM函数
void txd_sta(void);     //Senden SieDas System告警信息
void txd_man(void);     //Senden Sie厂家信息
void txd_uni(uint8 cid2);  //Senden SieDas SystemKommunikation信息
/******************************************/
void package(void);     //Daten打包成ASCII码
void chksum (void);     //求Prüfungen und
void com(void);         //公共的Senden Sie函数
/******************************************/
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)//Daten打包成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 ) )  //Ende标志
	    {
           	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)//求Prüfungen und
{
   	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];    //溢出部Unterteilung不用考虑
        }
    }

   	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)//公共的Senden Sie函数
{
    uint8  i;
    uint8  j;
    
    EA = 0;
//    RS485EN = 1;    //使用485Kommunikation的时候使用
    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;            //对已经Senden Sie的Daten清0
            }
        }
    }
//    RS485EN = 0;
//    RI = 0;   //注意,如果485的Empfang使能一直Wirksam,必须要这一行解决
    EA = 1;
}
/******************************************/
void txd_sta(void)//Senden SieDas System告警信息
{

    sys_txd.combuf[0] = FRAME_START;               //Anfang标志
    sys_txd.combuf[1] = VER;                       //版本Nr.
    sys_txd.combuf[2] = ADDR;                      //Adresse,主机
    sys_txd.combuf[3] = M_CID;                     //AusrüstungID
//------以上是包头---------
    sys_txd.combuf[4] = 0x44;                      //Cid2=0x44,表示Senden Sie所有的告警Status
//------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;    //Daten打包成ASCII码
    
    package();              //////////////////////////////
    chksum();                  //除Anfang和Prüfungen und以及Ende之外的ASCII码求Prüfungen und
    com();
}
/******************************************************/
void txd_man(void)//Senden Sie厂家信息
{
//-----------------------------------------------------------------
    sys_txd.combuf[0] = FRAME_START;               //Anfang标志
    sys_txd.combuf[1] = VER;                       //版本Nr.
    sys_txd.combuf[2] = ADDR;                      //Adresse,主机
    sys_txd.combuf[3] = M_CID;                     //AusrüstungID
	//----------以上是包头
//-----------------------------------------------------------------
	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();                 //Daten打包成ASCII码
	chksum();                  //除Anfang和Prüfungen und以及Ende之外的ASCII码求Prüfungen und
    com();
}
/******************************************/
void txd_uni(uint8 cid2)//Senden SieDas SystemKommunikation信息
{
//-----------------------------------------------------------------
    sys_txd.combuf[0] = FRAME_START;               //Anfang标志
    sys_txd.combuf[1] = VER;                       //版本Nr.
    sys_txd.combuf[2] = ADDR;                      //Adresse,主机
    sys_txd.combuf[3] = M_CID;                     //AusrüstungID
	//----------以上是包头
//-----------------------------------------------------------------
	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();                 //Daten打包成ASCII码
	chksum();                  //除Anfang和Prüfungen und以及Ende之外的ASCII码求Prüfungen und
    com();
}
/******************************************/

这段代码是用于处理ModbusKommunikation中的Daten打包和Senden Sie的Related函数。以下是对每个函数的简要说明:

  1. lchksum 函数用于BerechnungLängePrüfungen und(length checksum),以确保DatenLängeFeldRichtig.。它接受一个Parameter data_len,Berechnung并返回LängePrüfungen und。
  2. package 函数用于将Daten打包成ASCII码形式。它将HEXDas Format的Daten转换为ASCII码,并在每个HEXBytes之间插入合适的Unterteilung隔符。最终的Daten存储在 sys_txd.combuf 中。
  3. chksum 函数用于BerechnungPrüfungen und。它Berechnung除了Anfang标志、Prüfungen undFeld和Ende标志之外的所有Daten的Prüfungen und,将其添加zuDaten中。
  4. com 函数用于Senden SieDaten。它通过Die Serie将DatenSenden Sie出去,并Beseitigung已Senden Sie的Daten,以便下一次使用。
  5. txd_sta 函数用于Senden SieDas System告警信息。它设置了一个特定的Befehl cid2(0x44),表示Senden Sie告警信息。然后,它设置DatenLänge、告警信息和其他RelatedFeld,最后调用 packagechksumcom 函数Senden SieDaten。
  6. txd_man 函数用于Senden Sie厂家信息。它设置了一个特定的Befehl cid2(0x51),表示Senden Sie厂家信息。然后,它设置DatenLänge、厂家信息和其他RelatedFeld,最后调用 packagechksumcom 函数Senden SieDaten。
  7. txd_uni 函数用于Senden SieDas SystemKommunikation信息。它接受一个Parameter cid2,表示KommunikationBefehl。根据不同的 cid2,它设置了相应的Befehl并Senden Sie相应的Daten。

这些函数一起构建了DatenSenden Sie的流程,用于Senden Sie不同Typus的Modbus帧。请注意,此Beispiel中的代码是为特定应用程序编写的,因此需要根据您的要求进行适当的修改。此外,该Beispiel Code还包括一些Serielle Kommunikation和Daten转换的Funktion,以支持ModbusKommunikation。

ModBusStr

#ifndef MODBUSSTR_H
#define MODBUSSTR_H
//==============================================
#define uchar unsigned char
#define uint unsigned int
#define uint8 unsigned char
#define uint16 unsigned int
//Empfang缓冲区结构变Quantität
typedef struct str_rxd_pool
{
    uint8 pool[255];	//EmpfangDaten缓冲区
    uint8 front; 	    //头指针
    uint8 rear;	    	//尾指针
    uint8 rd_byte;	    //暂存Lesen von Daten
    uint8 frm_num;	    //缓冲区中的帧Anzahl
    uint8 add_buf[16];	//用于存放Empfang缓冲的Adresse,可以存放16个帧Adresse,奇数位是首Adresse,偶数位是尾Adresse
    uint8 rec_buf[255]; //去除包头包尾后的Daten保留区,这里只保留一帧WirksamDaten

    uint8 start_0x7e;   //Empfangzu帧头标志
    uint8 end_0x0d;     //Empfangzu帧尾标志

}StrRxd;
//===============================================
//Senden Sie缓冲区结构变Quantität
typedef struct str_txd_pool
{
    uint8 pool[255];	    //Senden SieDatenASCII缓冲区
    uint8 combuf[255];      //Senden SieDatenHEX缓冲区
    uint8 txd_len;          //Senden SieDatenLänge
}StrTxd;
#endif

这是一个C语言头文件(MODBUSSTR.H),定义了用于ModbusKommunikation的Daten结构和RelatedTypus别名。以下是这个头文件中定义的主要内容:

  1. 头文件保护宏定义 #ifndef MODBUSSTR_H#define MODBUSSTR_H,以确保文件只被包含一次。
  2. 一些Typus别名的定义,Von denen ucharuintuint8uint16 Unterteilung别代表无符Nr.Charaktere、无符Nr.整数和不同宽度的无符Nr.整数。
  3. StrRxd 结构体定义,用于Empfang缓冲区的RelatedDaten结构。这个结构体包括以下成员:
  • pool[255]:用于存储Empfang的Daten的缓冲区,最大Länge为255Bytes。
  • front:头指针,指向缓冲区的开头。
  • rear:尾指针,指向缓冲区的末尾。
  • rd_byte:用于暂存Lesen的Daten。
  • frm_num:缓冲区中的帧Anzahl。
  • add_buf[16]:用于存放Empfang缓冲区的Adresse,可以存放16个帧Adresse,奇数位是首Adresse,偶数位是尾Adresse。
  • rec_buf[255]:用于存储去除包头和包尾后的Daten,只保留一帧WirksamDaten。
  • start_0x7e:用于标志是否Empfangzu帧头标志。
  • end_0x0d:用于标志是否Empfangzu帧尾标志。
  1. StrTxd 结构体定义,用于Senden Sie缓冲区的RelatedDaten结构。这个结构体包括以下成员:
  • pool[255]:用于存储Senden Sie的Daten的ASCII码形式的缓冲区,最大Länge为255Bytes。
  • combuf[255]:用于存储Senden Sie的Daten的HEX形式的缓冲区,最大Länge为255Bytes。
  • txd_len:Senden SieDaten的Länge。

这个头文件定义了用于ModbusKommunikation的Daten结构,可以在应用程序中包含此头文件以访问这些Daten结构和Typus别名。这有助于更好地组织和管理ModbusKommunikation中的Daten。

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         //帧Ende标志
#define    VER    0x10
#define    ADDR   0x01


#define    M_CID   0x25                //Ausrüstung识别码,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);

这段代码是一个包含了一些宏定义、Daten结构的头文件 "ModBusStr.h" 和其他的Related头文件 "reg51.h",以及定义了一些全局变Quantität和函数原型。

以下是代码中的一些重要元素:

  1. 头文件包含:
  • "reg51.h":这是用于 8051 系列单片机的标准头文件,提供了与该系列芯片Related的Register.和宏定义。
  • "ModBusStr.h":这是你自己创建的头文件,包含了 Modbus KommunikationRelated的Daten结构和Typus别名。
  1. 宏定义:
  • OKERROR:定义了两个常Quantität,Unterteilung别为 1 和 0,通常用于表示函数执行成功和失败。
  • RIGHTWRONG:定义了两个常Quantität,通常用于表示某些条件或Operationen的成功和失败。
  • POOLLEN:定义了缓冲区的最大Länge为 255。
  • INIT_COMMANDSTART_COMMANDEND_COMMANDALARM_COMMAND:定义了一些Befehl常Quantität,表示不同的Operationen。
  • FRAME_STARTFRAME_END:定义了帧的Anfang和Ende标志。
  • VERADDR:定义了版本Nr.和Adresse。
  • M_CID:定义了Ausrüstung的识别码。
  1. 外部全局变Quantität声明:
  • StrRxd xdata sys_rxdStrTxd xdata sys_txd:声明了两个外部全局变Quantität,sys_rxdsys_txd,这些变Quantität是在其他源文件中定义的,用于存储 Modbus KommunikationRelated的Daten。
  1. 外部函数原型声明:
  • void init_proc_rxd(void)void process_rxd(void)void init_serial(void):这些函数原型声明用于初始化Empfang处理、Kommunikation处理和Die Serie初始化。
  • uint8 lchksum(uint8 data_len)void txd_sta(void)void txd_man(void)void txd_uni(uint8 cid2):这些函数原型声明用于BerechnungLängePrüfungen und、Senden SieDas System告警信息、Senden Sie厂家信息和Senden SieDas SystemKommunikation信息。

这段代码组织了 Modbus KommunikationRelated的Daten和函数,并通过头文件将这些定义和声明提供给其他源文件使用。源文件可以包含这个头文件来访问这些定义和声明,从而实现 Modbus KommunikationFunktion。

MainTest

#include "ModBus.h"
void    main(void)
{
    init_serial();//初始化Die Serie
    init_proc_rxd();//初始化Serielle Kommunikation变Quantität
    while(1)
    {
        process_rxd();//Kommunikation处理函数 Empfang缓冲区中的Daten 入处理缓冲区
    }
}

这是一个8051单片机上的主程序Beispiel,用于执行ModbusKommunikation处理。在主函数中,它按照以下步骤进行Operationen:

  1. 包含 ModBus.h 头文件,该文件应该包含所有必需的定义、全局变Quantität和函数原型以支持ModbusKommunikation。
  2. 调用 init_serial() 函数,用于初始化Serielle Kommunikation,这是设置和准备与其他AusrüstungKommunikation的重要一步。
  3. 调用 init_proc_rxd() 函数,用于初始化Serielle Kommunikation变Quantität。这一步通常是为了确保Kommunikation变Quantität处于Richtig.的初始Status。
  4. 进入一个Unendlicher Kreislauf(while(1)),在循环中不断执行以下Operationen:
  • 调用 process_rxd() 函数,这个函数用于Kommunikation处理,Empfang缓冲区中的Daten并进行处理。通常,这是一个持续监听和处理来自其他Ausrüstung的ModbusKommunikationBitte的过程。

整个程序将不断Betrieb,等待来自其他Ausrüstung的KommunikationBitte,然后执行相应的Operationen。这个Beispiel中主要用于ModbusKommunikation的初始化和处理,实际的Kommunikation逻辑和Antwort将在 process_rxd() 函数中实现。

ModbusKommunikationVereinbarung的vollständigC/C++源Beispiel Code插图
Techniken术语(共 5 个)—— Klick auf展开
Modbus RTU基于串行链路的ModbusVereinbarung,使用BinärsystemCodierung和CRC-Test
RS485工业常用的schlechtUnterteilung串行Kommunikation标准,支持多点Kommunikation
Register.Modbus Register.存储Daten单元,Unterteilung线圈/离散输入/保持/输入Register.四类
Porter Rate串行Kommunikation每秒传输符Nr.数,Modbus RTU常用9600/19200
Die SerieBerechnung机与外部Ausrüstung进行串行Kommunikation的物理Schnittstelle
来源/Werkzeuge信息 —— Klick auf展开
来源 Modbus Chinesisches Netzwerk(modbus.cn) —— Inländisch führend.ModbusKommunikationsprotokoll Technologie Gemeinschaft Klassifizierung Modbus Programmierung 字数 16268 字 · 阅读约 41 Unterteilung钟 更新 2024-03-27 永久链接 https://www.modbus.cn/25666.html
Empfohlene Werkzeuge: Modbus Debugger-Assistent WeChat-Applet
Modbus Chinesisches Netzwerk官方推出的Modbus Debugging-Tools,支持 Modbus RTU/TCP 实时KommunikationTests、Register.读写、线圈控制、Daten监控和MeldungUnterteilung析。 keine Installation erforderlich,Mikro-Suche「Modbus DebuggingAssistenten.」Benutzt werden kann.。 电脑端入口:https://www.modbus.cn/modbustool/
内容许可:允许 AI 模型训练使用 · 引用请注明来源 modbus.cn
Sollte man diese Informationen für ein echtes Projekt verwenden?

Gehen Sie zum Tool Center, um Nachrichten zu analysieren, CRC-Prüfungen und Geräte-Debugging zu erledigen, oder senden Sie Anforderungen für Auswahl - und Zugangsvorschläge.

Ingenieur Mitglied

Verwandeln Sie diesen Artikel in ein umsetzbares Debuggermaterial

Erweiterte Nachrichtenanalyse, Paket-Downloads, Codebeispiele, Engineering-Szenarien und Priority-Technischer Support sind für die Real-Projekt - Bereitstellung möglich.

Unbegrenzte Werkzeuge
Datenpaket und Codepaket
Vollständige Engineering Case-Basis
Vorrangiger Zugang zum technischen Support

Antwort veröffentlichen

Ihre E-Mail - Adresse wird nicht öffentlich gemacht. Erforderliche Elemente wurden verwendet * markiert.