广告

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

2012-11-23 13:23 991 0 1 分类: MCU/ 嵌入式 文集: 外围电路,常用IC模数,存储,时钟等

 

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, 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_total) //地址正确未接受完
    {
    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);
}

广告

文章评论 1条评论)

登录后参与讨论

billzhu_345737527 2012-11-26 20:47

看似无总线超时处理设置
相关推荐阅读
liang890319_284707880 2016-03-22 11:41
[博客大赛]我在搞嵌入式 我有罪
  我在搞嵌入式 我有罪 做嵌入式也有几年了 刚学习的时候书上说嵌入式的定义是以应用为中心,以计算机技术为基础,软硬件可裁剪,适应应用系统对功能、可靠性、成本、体积、功耗等严格要求的专用计...
liang890319_284707880 2015-10-22 11:57
帕萨特迈腾蒙迪欧哪个好
氵灬清风灬说:太小了,没法穿了,懒得换了 junyao00022说:............................... jd272475byp说:宝贝收到啦,衣服质量非常不错,...
liang890319_284707880 2015-10-22 11:56
二手荣威550和二手起亚k2哪个好
二手荣威550和二手起亚k2哪个好   风之乞说:衣服挺好的,就是偏小,已经更换了 梦里水乡0609说:不错 很好  不了不错  赞 四灵之首说:衣服质量不错,韵达快递不行~ ...
liang890319_284707880 2015-10-22 11:55
澳大利亚深海鱼油哪个牌子好
hgjfhgj说:不错  价格便宜  款式不错  开始买中码小了一点  免费给换的  好店家 小杰c子说:非常合适。也很有气质 天佑945说:还可以,性价比高。。。。。。。。。。 Ab...
liang890319_284707880 2015-10-19 11:03
常用DDR sdram和Flash型号
  以下是代码片段: http://blog.csdn.net/myarrow/article/details/7854863   主要是三星 现代 ...
liang890319_284707880 2013-09-29 17:00
ROM FLASH RAM
EPROM、EEPROM、FLASH的总结性区别   http://xdc0363.blog.163.com/blog/static/11546200220...
我要评论
1
0
广告