当前位置:文档之家› Modbus通信协议在C8051F单片机上实现

Modbus通信协议在C8051F单片机上实现

MODBUS通信协议 应用
/**********************************************
程序:周波控制器MODBUS通信程序3th最终版(成功)带通信故障检测实时监测
描述:默认内部时钟3.5M,关闭看门狗,9位UART,允许中断,波特率9570bps
功能:检测控制信号,使用MODBUS与周波控制块通信;
资源:
P0.4TX P0.5RX,
ENR485 P0.6
LED1 P0.7,
LED2 P1.0;
key P1.1,
relay P1.5;
RB80,TB80,TI0,RI0
SBUF0
编写: 日期:2009,12,03
修改: 日期:
修改内容:开关函数名,发送中断中的一个等号,加上rx_counter=0;接收第一个数据修改,偶校验使用硬件,命令位数修改,加CRC加发送位数
rx_total的判断修改了,添加checkerror标志请缓冲区也清错误;deal_rxdata换位置到接收完成里面,rb80==p修改,
请标志开中断放进中断里面,CRC用别人的,家继电器控制
删除key——check;修改了关断指令的位数,接收地址加了判断,偶校验删除,接收也CRC ,crc高高低位顺序修改
公司:********接口及测试:
经过优化:com_addr 重新初始化为8位模式,CRC还是高先发
************************************************/
/////////////////////////////////////
// Generated Initialization File //
/////////////////////////////////////

#include "C8051F330.h"

// Peripheral specific initialization functions,
// Called from the Init_Device() function
void PCA_Init()
{
PCA0MD &= ~0x40;
PCA0MD = 0x00;
PCA0CPL2 = 0xFF;
PCA0MD |= 0x40;
}

void Timer_Init()
{
TCON = 0x40;
TMOD = 0x20;
CKCON = 0x08;
TH1 = 0x60;
}

void UART_Init()
{
SCON0 = 0x10;
}

void Port_IO_Init()
{
// P0.0 - Unassigned, Open-Drain, Digital
// P0.1 - Unassigned, Open-Drain, Digital
// P0.2 - Unassigned, Open-Drain, Digital
// P0.3 - Unassigned, Open-Drain, Digital
// P0.4 - TX0 (UART0), Push-Pull, Digital
// P0.5 - RX0 (UART0), Push-Pull, Digital
// P0.6 - Unassigned, Push-Pull, Digital
// P0.7 - Unassigned, Push-Pull, Digital

// P1.0 - Unassigned, Push-Pull, Digital
// P1.1 - Unassigned, Open-Drain, Digital
// P1.2 - Unassigned, Open-Drain, Digital
// P1.3 - Unassigned, Open-Drain, Digital
// P1.4 - Unassigned, Open-Drain, Digital
// P1.5 - Unassigned, Push-Pull, Digital
// P1.6 - Unassigned, Open-Drain, Digital
// P1.7 - Unassigned, Open-Drain, Digital

P0MDOUT = 0xF0;
P1MDOUT = 0x21;
XBR0 = 0x01;
XBR1 = 0x40;
}

void Interrupts_Init()
{
IE = 0x90;
}

// Initialization function for device,
// Call Init_Device() from your main program
void Init_Device(void)
{
PCA_Init();
Timer_Init();
UART_Init();
Port_IO_Init();
Interrupts_Init();
}



/*************************************************/
/*********************************************

*****/
#define uchar unsigned char
#define uint unsigned int
/******与移植相关的****I/O定义******/
#define com_addr 0x01 //从站地址
sbit R485 = P0^6; //485控制端高电平接收
sbit GREEN = P0^7; //led
sbit RED = P1^0; //led
sbit KEY = P1^1; //开关检测
sbit RELAY = P1^5; //控制继电器
/*********变量声明***********/
bit crc_ok,send_ok,read_ok; //全局变量供观察用
bit action,com_ok;
uchar crch,crcl,flag;
uchar checkerror;
uchar rx_counter,tx_counter;
uchar rx_total,tx_total;
uchar xdata BUFFER[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00
};//缓冲区暂定为14字节

uchar xdata OPEN[] = {
com_addr,0x05,0x00,0x00,0xff,0x00,0x00,0x00
}; //启动命令末尾CRC
uchar xdata READ[] = {
com_addr,0x01,0x00,0x00,0x00,0x01,0x00,0x00
}; //读状态命令末尾CRC

/* CRC 高位字节值表 */
uchar code auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
} ;
/* CRC低位字节值表*/
uchar code auchCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
0xD5, 0x15, 0xD7, 0x17, 0x1

6, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40
} ;

/********函数声明*************/
void Init_Device(void); //系统初始化
void rx_data(void); //接收中断处理
void tx_data(void); //发送中断处理

void deal_rxdata(void); //处理收到的数据
void deal_rxdata(void); //处理要发送的数据

void crc16(uchar *puchMsg, uchar usDataLen); //CRC校验
void clear_buffer(void); //清空缓冲区

void turnon_pwm(void); //开启周波控制
void turnoff_pwm(void); //关闭周波控制
void read_pwm(void); //读控制器状态

void delay10ms(void);
uchar check_key(void); //检测开关
void check_com(void); //检测通信故障


/***********************************************************
函数功能:串口收发中断服务
应用范围:全局
调用函数:rx_data,tx_data
入口数据:中断
出口数据:无
服务函数:无
*************************************************************/
void UART0(void)interrupt 4
{
EA = 0; //关闭所有中断

if(RI0 == 1)
{
rx_data(); //接收中断处理
}
if(TI0 == 1)
{
tx_data(); //发送中断处理
}
EA =1;
}

/*****************************************************************
函数功能:处理接收到的数据
应用范围:
调用函数:deal_data
入口数据:中断调用
出口数据:rx_counter,check_error
服务函数:
******************************************************************/
void rx_data(void)
{
bit addr_ok ;

ACC =SBUF0;
RI0 =0;

if(RB80 ==1) //数据校验正确
{
if(SBUF0 ==com_addr)
{
addr_ok =1;
}
else
{
}
if(addr_ok ==1&&rx_counter{
rx_counter++;

BUFFER[rx_counter-1] = SBU

F0;
}
if(rx_counter==(rx_total-1)) //接收完成
{
addr_ok =0;
deal_rxdata();
}
}
else
{
checkerror = 2; //奇偶校验失败
}
}

/*****************************************************************
函数功能:发送中断服务
应用范围:
调用函数:clear_buffer
入口数据:tx——counter,缓冲区
出口数据:R485
服务函数:
******************************************************************/
void tx_data(void)
{
TI0 =0;
if(tx_counter<8) //未发送完
{
tx_counter++;

ACC =BUFFER[tx_counter-1];

TB80 =1;

SBUF0 =BUFFER[tx_counter-1];
}
else //发送完成
{
R485 =1;
tx_counter =0;
clear_buffer(); //清空缓冲区
}
}
/*************************************************************
函数功能:CRC校验
应用范围:全局
调用函数:无
入口数据:缓冲区首地址,数据字节数
出口数据:crc3,crc2,crc_Ok
服务函数:被调用
************************************************ok***********/
void crc16(uchar *puchMsg, uchar usDataLen)
{
uchar uchCRCHi = 0xFF ; /* 高CRC字节初始化 */
uchar uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */
uchar uIndex ; /* CRC循环中的索引 */
while (usDataLen--) /* 传输消息缓冲区 */
{
uIndex = uchCRCHi ^ *puchMsg++ ; /* 计算CRC */
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
uchCRCLo = auchCRCLo[uIndex] ;
}
crch = uchCRCHi;
crcl = uchCRCLo;
}

/*****************************************************************
函数功能:开启周波控制器
应用范围:
调用函数:crc16
入口数据:
出口数据:
服务函数:把开启命令送入发送缓冲区并启动发送
******************************************************************/
void turnon_pwm(void)
{
uchar x;
uchar *on = OPEN;
uchar *buf = BUFFER;
R485 =0;

for(x=0;x<6;x++)
{
*(buf+x) =*(on+x);
}
crc16(BUFFER,6);
*(buf+7) =crcl;
*(buf+6) =crch;
TI0 = 1;

}
/*****************************************************************
函数功能:关闭周波控制器
应用范围:
调用函数:crc16
入口数据:被调用
出口数据:R485,TI0
服务函数:把关闭命令送进发送缓冲区并启动发送
******************************************************************/
void turnoff_pwm(void)
{
uchar x;
uchar *on = OPEN;
uchar *buf = BUFFER;

R485 =0;

for(x=0;x<6;x++) //加载命令
{
*(buf+x) =*(on+x);
}

*(buf+4) = 0x00; //关闭命令
crc16(BUFFER,6);
*(buf+7) =crcl;
*(buf+6) =crch;
rx_total = 9;
TI0 = 1;
}
/*****************************************************************
函数功能:读周波控制器
应用范围:
调用函数:crc
入口数据:被调用
出口数据:r485,rx_total
服务函数:
******************************************************************/
void read_pwm(void)
{

uchar x;
uchar *on = READ;
uchar *buf = BUFFER;

R485 =0;

for(x=0;x<6;x++)
{
*(buf+x) =*(on+x);
}
crc16(BUFFER,6);
*(buf+7) =crcl;
*(buf+6) =crch;
rx_total = 7;
TI0 = 1;

}
/*****************************************************************
函数功能:处理从周波控制器返回的数据
应用范围:
调用函数:无
入口数据:缓冲区数据
出口数据:指示灯以及错误类型
服务函数:rx_data
**********************************************************要修改灯控********/
void deal_rxdata(void)
{
uchar temp6,temp7,temp8;
bit crc2ok;

com_ok =1;
flag = 0;

crc16(BUFFER,(rx_total-3));
temp6 =crcl;
temp7 =crch;

if(temp6==BUFFER[7]&&temp7==BUFFER[6])
{
crc_ok=1;
}
if(temp6==BUFFER[5]&&temp7==BUFFER[4])
{
crc2ok=1;
}

/*********************
if(BUFFER[1]== 0x05&&crc_ok==1) //自动返回的数据
{
send_ok =1;
crc_ok =0;
if(BUFFER[4] ==0xff) //运行状态绿灯亮
{
RED =1;
GREEN =0;
}
if(BUFFER[4] ==0x00) //关闭状态红灯亮
{
GREEN =1;
RED =0;
}
}
********************************************/
if(BUFFER[1]== 0x01&&crc2ok==1) //读回的数据
{
read_ok =1;
crc2ok =0;
if(BUFFER[2] ==0x01)
{
temp8 =BUFFER[3]&0x0f;
if(temp8==0) //未开启
{
GREEN =1;
RELAY =1; //输出开关闭合
}
else //开启
{
GREEN =0;
RELAY =0; //输出开关吸合
}
}
}
//如果是读回来的数据read_ok=1
R485 =0; //准备发送
rx_counter=0;
clear_buffer();
}
/*****************************************************************
函数功能:清空缓冲区
应用范围:全局
调用函数:无
入口数据:缓冲区数据,checkerror
出口数据:无
服务函数:
******************************************************************/
void clear_buffer(void)
{
uchar *buf =BUFFER;
uchar x;
for(x=0;x<14;x++)
{
*(buf+x) = 0x00;
}
checkerror =0;
}

/*****************************************************************
函数功能:检测按钮命令
应用范围:全局
调用函数:delay10ms
入口数据:无
出口数据:flag
服务函数:无
******************************************************************/
uchar check_key(void)
{
uchar flag = 0;

if(KEY ==1) //电平翻转
{
delay10ms();
if(KEY ==1) //保持翻转后的状态为接触
{
flag = 1; //置发信号标志
}
}
else
{
delay10ms();
if(KEY ==0) //保持翻转后的状态为接触
{
flag = 2; //置关信号标志
}
}
action =KEY;
return flag;
}
/************************修改******************/
void delay10ms(void)
{
uint x;
for(x=0;x<10000;x++)
{

};
PCA0CPH2 = 0x00;
}
/*************************/
void check_com(void)
{
if(com_ok==0)
{
RED =0;
}
else
{
RED =1;
}
}
/****************************************************************/
/*************************主函数*

********************************/
/****************************************************************/
main(void)
{
bit open,close;
Init_Device( );
action =KEY;
R485 =0; //处于发送状态
PCA0CPH2 = 0x00;
com_ok =1;
do{

com_ok =0;
flag = check_key(); //检测开关

if(flag ==1&&open==0) //要开启PWM
{
turnon_pwm();
com_ok =0;
delay10ms();
open =1;
close =0;
}

if(flag ==2&&close==0) //要关闭PWM
{
turnoff_pwm(); //周波控制
com_ok=0;
delay10ms();
open =0;
close =1;
}

read_pwm();
check_com();
}while(1);
}

相关主题