⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 modbus.c

📁 根据标准MODBUS协议
💻 C
字号:
#include ".\STC89c5x.H"

//串口通讯设置相关参数
#define IP_VALUE				0x10       //串行中断高优先级	
#define TMOD_VALUE			0x21   	//T0十六位定时器,T1 波特率发生器
#define SCON_VALUE 			0x50	//方式1,10位,能接收
#define PCON_VALUE			0x00	//单倍波特率
#define BAUD_VALUE			0xFA	//22.1184MHz晶振,波特率设定植为9600
#define TH0_VALUE			0xB8	//T0定时10mS判断信息帧结束
#define TL0_VALUE			0
#define T2CON_VALUE			0x00	//T2 act as 16 bit timer
#define RCAP2H_VALUE		0x6F	//定时20ms

#define   UART_COMPLETE   1
#define	MOD_ADDR		  1
#define 	UART_LEN		  128

unsigned char bdata cy_flag;//程序处理标志单元
sbit    cy_uartcomplete=cy_flag^3;//串口接受完一组数据

#define    BIT_NUM		80
#define   WORD_NUM		150
unsigned char	cy_bitdata[BIT_NUM/8];//位存储区,可读可写
unsigned int    iy_wdata[WORD_NUM];//字存储区,可读可写
unsigned char data cy_uartnumber;
unsigned char cy_receive_buf[UART_LEN];

sbit  RTS_485=P3^5;

sbit RUN_FLAG=P3^2;//运行状态指示灯

void uart_timer_set(void)
	{
		TCON=0x00;
    		PCON=PCON_VALUE;			//波特率选择
    		IP=IP_VALUE;	    			//设置各中断优先级		
    		TMOD=TMOD_VALUE;   		//设置各定时器的工作方式
    		T2CON=T2CON_VALUE;
    		SCON=SCON_VALUE;    		//设置串行工作方式
    		TH1=TL1=BAUD_VALUE; 		//设定波特率的值
		TH0=TH0_VALUE;
              TL0=TL0_VALUE;
		TR1=1;
    		TR0=TI=RI=0;
	}

//-----------------------------------------------------------------------------
union crc  //check crc 2 byte;
	{
		unsigned int word;
		struct 
			{
				unsigned char	hi;
				unsigned char	lo;
			}bytes;
	};
union crc   crc_chec;

void crc_chec_fuc(unsigned char datain)
	{

		unsigned char i;
		crc_chec.bytes.lo=crc_chec.bytes.lo^datain;
		for(i=0;i<8;i++)
			{
				if((crc_chec.word & 0x0001)==1)
					{
						crc_chec.word=crc_chec.word>>1;
						crc_chec.word=crc_chec.word^0xa001;
					}
				else
					crc_chec.word=crc_chec.word>>1;
			}
	}

void start_crc_chec(void)
	{ 
		unsigned char i;
		crc_chec.word=0xffff;
		for(i=0;i<(cy_uartnumber-2);i++)
			crc_chec_fuc(cy_receive_buf[i]);
		
	}

void generic_crc(unsigned char cyz_num)
	{
		unsigned char	i;
		
		crc_chec.word=0xffff;
		for(i=0;i<cyz_num;i++)
			crc_chec_fuc(cy_receive_buf[i]);
		
		cy_receive_buf[cyz_num+1]=crc_chec.bytes.hi;
		cy_receive_buf[cyz_num]=crc_chec.bytes.lo;
	}

//发送一个字节
void uart_send(unsigned char s)
 	{
		SBUF=s;
		while(TI!=1);
		 TI=0;
	}

//发送一帧数据
void frame_send(unsigned char t)//发送数据桢
	{
		unsigned char i;
		
		for(i=0;i<t;i++)
			uart_send(cy_receive_buf[i]);

	}
//-----------------------------------------------------------------------------
void uart_run(void)
	{ 
		unsigned char cy_q,cy_s,x,y,x_num,y_num;
		
		if(cy_uartcomplete==UART_COMPLETE)
			{
				start_crc_chec();
				if((crc_chec.bytes.hi==cy_receive_buf[cy_uartnumber-1])\
					&&(crc_chec.bytes.lo==cy_receive_buf[cy_uartnumber-2]))	    //crc
						    {		
						    		EA=0;
								RTS_485=!RTS_485;	
						    		switch(cy_receive_buf[1])
								    {
										case 1://读位
											if((cy_receive_buf[2]==0)&&(cy_receive_buf[4]==0)&&(cy_receive_buf[3]<BIT_NUM)\
												&&(cy_receive_buf[5]<BIT_NUM)&&((cy_receive_buf[3]+cy_receive_buf[5])<BIT_NUM))  ////地址分析
												{
													x=cy_receive_buf[3]/8;//the byte no.x
													y=cy_receive_buf[3]%8;//the byte no.x & y bit
													
													x_num=cy_receive_buf[5]/8;
													y_num=cy_receive_buf[5]%8;
													if ((y_num!=0)||(y!=0))
														x_num++;
	
													for(cy_s=0;cy_s<x_num;cy_s++)
														cy_receive_buf[cy_s+3]=cy_bitdata[cy_s+x];
													for(cy_s=0;cy_s<x_num;cy_s++)
														{
															crc_chec.bytes.lo=cy_receive_buf[cy_s+3];
															crc_chec.bytes.hi=cy_receive_buf[cy_s+4];
															crc_chec.word=crc_chec.word>>y;
															cy_receive_buf[cy_s+3]=crc_chec.bytes.lo;
														}
													if(y_num!=0)
														{
															cy_s=0xff;
															cy_s=cy_s>>(8-y_num);
															cy_receive_buf[x_num+2]=cy_receive_buf[x_num+2]&cy_s;
														 }

													if(y!=0)
														x_num--;

													cy_receive_buf[2]=x_num;//the number of the bytes
													cy_uartnumber=3+x_num;		
													generic_crc(cy_uartnumber);															generic_crc(cy_uartnumber);
													cy_uartnumber=cy_uartnumber+2;
													frame_send(cy_uartnumber);//发送数据
												}
										case 3://读寄存器
											if((cy_receive_buf[2]==0)&&(cy_receive_buf[4]==0)&&(cy_receive_buf[3]<WORD_NUM)\
												&&(cy_receive_buf[5]<WORD_NUM)&&((cy_receive_buf[3]+cy_receive_buf[5])<WORD_NUM))  ////地址分析
												{	
													cy_receive_buf[2]=cy_receive_buf[5]*2;
													cy_uartnumber=3;
													cy_q=cy_receive_buf[3]+cy_receive_buf[5];
													for(cy_s=cy_receive_buf[3];cy_s<cy_q;cy_s++)
														{
															cy_receive_buf[cy_uartnumber]=iy_wdata[cy_s]/0x100;
															cy_uartnumber++;
															cy_receive_buf[cy_uartnumber]=iy_wdata[cy_s]%0x100;
															cy_uartnumber++;	
														}
													generic_crc(cy_uartnumber);
													cy_uartnumber=cy_uartnumber+2;
													frame_send(cy_uartnumber);//发送数据
												}
										break;
										case 5://写单个位
											if((cy_receive_buf[2]==0)&&(cy_receive_buf[3]<BIT_NUM))////地址分析
												{
													x=cy_receive_buf[3]/8;//the byte no.x
													y=cy_receive_buf[3]%8;//the byte no.x & y bit

													if(cy_receive_buf[4]==0)
														{
															x_num=0xfe;
															for(cy_s=0;cy_s<y;cy_s++)
																x_num=(x_num<<1)|0x01;
															
															cy_bitdata[x]=cy_bitdata[x]&x_num;	
														}
													else{
															x_num=0x01;
															x_num=x_num<<y;
															
															cy_bitdata[x]=cy_bitdata[x]|x_num;
														}

													frame_send(8);//发送数据
												}
										break;
										break;
										case 6://写单个寄存器
											if((cy_receive_buf[2]==0)&&(cy_receive_buf[3]<WORD_NUM))  //地址分析
												{	
													iy_wdata[cy_receive_buf[3]]=cy_receive_buf[4]*0x100+cy_receive_buf[5];//更改指定数据
													frame_send(cy_uartnumber);//发送数据
												}

										break;
										case 15://写多个位
										break;
										case 16://写多个寄存器
											if((cy_receive_buf[2]==0)&&(cy_receive_buf[4]==0)&&(cy_receive_buf[3]<WORD_NUM)\
												&&(cy_receive_buf[5]<WORD_NUM)&&((cy_receive_buf[3]+cy_receive_buf[5])<WORD_NUM))  ////地址分析
												{
													for(cy_s=0;cy_s<cy_receive_buf[6];cy_s++)
														{
															iy_wdata[cy_receive_buf[3]]=cy_receive_buf[cy_s+7]*0x100+cy_receive_buf[cy_s+8];//更改指定数据
															cy_s++;
															generic_crc(6);
															frame_send(8);
														}
												}
										break;
								     }								
								RTS_485=!RTS_485;
								EA=1;
						    }
				cy_uartcomplete=0;
				cy_uartnumber=0;
				ES=1;
			}
	}			   
//-----------------------------------------------------------------------------
void uart_int(void)  interrupt 4  using 2
 	{
		cy_receive_buf[cy_uartnumber]=SBUF;
		RI=0;
		TH0=TH0_VALUE; 
              TL0=TL0_VALUE;
		TR0=1;
		cy_uartnumber++;
		
		if((cy_uartnumber>=128)||((cy_uartnumber==1)&&(cy_receive_buf[0]!=MOD_ADDR)))
			cy_uartnumber=0;
	}
//-----------------------------------------------------------------------------
void timer0(void) interrupt 1 using 3
	{	
		TR0=0;
		ES=0;
		cy_uartcomplete=UART_COMPLETE;
		RUN_FLAG=1;
	}



main()
{
uart_timer_set();
ES=1;
ET0=1;
EA=1;
while(1)
	{
uart_run();
	}

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -