/**********************************************
程序:周波控制器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, 0x16, 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] = SBUF0;
}
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);
}