stc单片机做modbus server rtu通信,已封装好库函数

modbus server 库文件 基于stc8单片机测试

硬件平台是基于stc8系列单片机进行的测试,这个函数目前只能实现整数类型的数据读取与写入,没法做浮点数通信,且进行数据写入的时候最好是一个地址一个地址的写入,测试是上位机使用modscon进行的测试,数据读取以及一个地址的数据写入都没有问题

头文件

#ifndef __MODBUS_H__
#define __MODBUS_H__

#include <stc8.h> //头文件定义,串口发送函数中,SBUF寄存器的头文件

/*  需要在主文件中定义这些变量 然后参照参数写入说明,对modbus函数填入参数即可
uchar xdata getdata[10]={0}; //串口收取的存储区间,接收报文一般是八个字节,所以这里定义了10个区间
uchar xdata putdata[100]={0x01}; //串口发送的存储区间
uchar xdata datacache[100]={0}; //数据存储区间,[0]和[1]累加16位的值就是address的地址。
uint address=0; //数据的开始地址,0就代表40001地址
uchar num,flag=0; //一些标志位的定义
*/

#ifndef __MODBUS_H__
#define __MODBUS_H__

#include <stc8.h> //头文件定义,串口发送函数中,SBUF寄存器的头文件

/*  需要在主文件中定义这些变量 然后参照参数写入说明,对modbus函数填入参数即可
uchar xdata getdata[10]={0}; //串口收取的存储区间,接收报文一般是八个字节,所以这里定义了10个区间
uchar xdata putdata[100]={0x01}; //串口发送的存储区间
uchar xdata datacache[100]={0}; //数据存储区间,[0]和[1]累加16位的值就是address的地址。
uint address=0; //数据的开始地址,0就代表40001地址
uchar num,flag=0; //一些标志位的定义
*/

#define uchar unsigned char //宏定义
#define uint unsigned int

uint u16(uchar u8h,u8l);  //八进制转16进制
void put(uchar *ff,uint lenth); //串口发送函数
uint crc(uchar *ff,uint lenth); //crc校验计算函数 
void clear(uchar *ff,lenth); //清除数组存取的值
uchar crccheck(uchar *getdata); //crc校验
void readhold(uchar deviceaddress,uchar *getdata,uchar *putdata,uchar *datacache,uint address); //读取保持寄存器
void writehold(uchar deviceaddress,uchar *getdata,uchar *putdata,uchar *datacache);  //写入保持寄存器
void modbus(uchar deviceaddress,uchar *getdata,uchar *putdata,uchar *datacache,uint address); //入口函数

/* 入口函数中,第一个参数是设备的设备地址。第二个参数是串口接收到数据的数组存放区,第三个是要发送的数组存放区,第四个是
数据的缓存区,这个数组里面存放了具体的数据。第五个值是数据存储区的起始地址。
*/

#endif

.c文件

#include <modbus.h>

void put(unsigned char *ff,unsigned int lenth) 
{
	unsigned int i;
	for(i=0;i<lenth;i++)
	{
		SBUF=ff[i];
		while(!TI);
		TI=0;
	}
}

uint u16(uchar u8h,u8l) 
{
	uint cache;
	cache = u8h;
	cache=cache<<8;
	cache = cache|u8l;
	return cache;
}

uint crc(uchar *ff,uint lenth) 
{
	uint cache=0xffff;
	uchar aa,j;
	for(aa=0;aa<lenth;aa++)
	{
		cache = ff[aa] ^ cache;
		for(j=0;j<8;j++)
		{
			if(cache & 0x01)
			{
				cache = cache>>1;
				cache = cache ^ 0xa001;
			}
			else
			{
				cache = cache>>1;
			}
		}
	}
	return cache;
}



void clear(uchar *ff,lenth) 
{
	uchar aa;
	for(aa=0;aa<lenth;aa++)
	{
		ff[aa]=0x00;
	}
}

uchar crccheck(uchar *getdata) 
{
	uint crccache;
	crccache = crc(getdata,6);
	if(getdata[6]==crccache|0Xff00)
	{
		if(getdata[7]==crccache>>8)
		{
			return 1; 
		}
		else
		{
			return 0; 
		}
	}
	else
	{
		return 0;
	}
			
}

void readhold(uchar deviceaddress,uchar *getdata,uchar *putdata,uchar *datacache,uint address) 
{
	uint dataaddress,putcrc,putcrccache,datalenth;
	uint j;
			ES=0; 
			if(crccheck(getdata)) 
			{
					datalenth=u16(getdata[4],getdata[5])*2; 
					dataaddress=u16(getdata[2],getdata[3])*2; 
					putdata[0] = deviceaddress;  //返回设备地址
					putdata[1]=0x03; 
					putdata[2]=datalenth; 
					for(j=0;j<datalenth;j++)
					{
						putdata[j+3]=datacache[j+dataaddress-address*2]; 
					}
					putcrc=crc(putdata,datalenth+3); 
					putcrccache=putcrc;
					putdata[datalenth+3]=putcrc|0xff00;
					putdata[datalenth+4]=putcrc>>8;					
					put(putdata,datalenth+5); 
					ES=1;
			}
			else 
			{
				ES=1;
			}
}

void writehold(uchar deviceaddress,uchar *getdata,uchar *putdata,uchar *datacache)
{
	uint dataaddress;
	uint j;
	ES=0;
			if(crccheck(getdata)) 
			{
					dataaddress=u16(getdata[2],getdata[3])*2; 
					datacache[dataaddress]=getdata[4]; 
					datacache[dataaddress+1]=getdata[5];
					for(j=0;j<8;j++) 
					{
						putdata[j]=getdata[j];
					}
					putdata[0] = deviceaddress; //返回设备地址
					put(putdata,8);
					ES=1;
				
			}
			else
			{
				ES=1;
			}
}

void modbus(uchar deviceaddress,uchar *getdata,uchar *putdata,uchar *datacache,uint address) 
{

	if(getdata[0]==deviceaddress) //设备地址进行判断
		{
			switch(getdata[1])
			{
				case 0x03: 
					readhold(deviceaddress,getdata,putdata,datacache,address);
					break;
				case 0x06:
					writehold(deviceaddress,getdata,putdata,datacache);
					break;
				default: 
					clear(getdata,8);
					ES=1;
			}
		}
		else if(getdata[0]!=deviceaddress) 
		{
			clear(getdata,8);
			ES=1;
		}
}

例子

这是主文件

#include "modbus.h"
	
uchar xdata getdata[10]={0}; //串口收取的存储区间,接收报文一般是八个字节,所以这里定义了10个区间
uchar xdata putdata[100]={0x01}; //串口发送的存储区间
uchar xdata datacache[100]={0}; //数据存储区间,[0]和[1]累加16位的值就是address的地址。
uint address=0; //数据的开始地址,0就代表40001地址
uchar num,flag=0; //一些标志位的定义

void UartInit()		//9600bps@24.0MHz
{
	SCON = 0x50;		//串口初始化函数,这里设置的是9600,是基于24mhz的频率设置的
	AUXR |= 0x40;		//根据自己的参数设置,替换掉这个初始化函数即可。
	AUXR &= 0xFE;		
	TMOD &= 0x0F;		
	TL1 = 0x8F;		
	TH1 = 0xFD;	
	ET1 = 0;		
	TR1 = 1;		
	ES = 1;
	EA = 1;
}

void main() 
{
	UartInit(); 
	while(1)
	{   
		if(num == 1)
		{
			//modbus调用函数,填入参数,然后取消标志位。
			modbus(0x01,getdata,putdata,datacache,address); 
			num = 0;
		}
	}
}


void ser() interrupt 4 //接收中断函数
{
		if(RI)
		{
			getdata[flag] = SBUF;
			RI=0;
		}
		flag++;
		if(flag >=8) //判断是否累计接收达到八个字节,触发标志位。
		{
			num=1;
			flag=0;
		}
//01 03 04 00 00 00 00 FA 33 		
}

  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值