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
}