本帖最后由 wangyy@dianzi 于 2013-7-26 17:04 编辑
看到论坛有许多关于modbus的通信的程序,但是好多程序没有对3.5个字符贞的检测,这样做是不标准的。只有做好这个检测,才能一每贞的数据包形式接受,这样处理程序才会高校,而且减少误包率。仅此参考,欢迎交流!
状态机在通信中有很重要的作用,所谓状态机就是SWITCH case 语句的熟练应用
先说文件结构:board.h 是同文件,所有的宏定义和一些配置在里面。 modbus16.h 是modbus通信的命令解析和命令动作文件,是通信的核心 rs232.c 是串口驱动程序
board.h
#include "STC12C5A60S2.h" //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include <intrins.h>
/******************************/
#ifndef _board__h_
#define _board__h_
/********************************************/
#define UART0FRAMETESTMS 8 //侦测试时间
/********************************************/
/******声明被外部调用的变量*****************/
extern unsigned char SLAVEADDRESS; //从机地址
extern unsigned char xdata Modbus16_DataBuff[8];
extern unsigned char xdata uchTX_Buffer[];//串口发送数据缓冲区
extern unsigned char xdata uchTX_Buffer1[];//串口发送数据缓冲区
extern unsigned char xdata uchRX_Buffer[17];////串口接收数据缓冲区
extern unsigned char RXData_Counter1;//数据接收计数器
extern bit FlagRdyOK;//是否可以接收数据包标志位:0:可以接收 1:不可接收
/******声明被外部调用的函数*****************/
/*modbus16.c*/
extern void askComm0Modbus(void);//检查uart0数据
/*rs232.c*/
extern void TX_NByte(unsigned char *dat,unsigned char TXLen);//发送N字节数据
//extern void Delayms(unsigned int T);
extern void UART_INIT(void);//串口初始化
extern unsigned char Check_MasterCMD1(void);//MasterCMD1判断
#endif
#define UART0FRAMETESTMS 8 //侦测试时间 这个很重要,就是那个侦间隔的测试时间,毫秒级的。他必须根据你的硬件配置和实际测试进行调整,调到最小有效值。
按9600的波特率计算,3.5个字符的间隔是2.916ms,这个是理论计算值,但是这个值作为你的定时器设定值是不行的,因为加上硬件以及软件的通信延时会比这个值大,所以你要在这个值得基础上微调,调到他的最小有效率值。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
/*-----------------------------------------------
名称:串口通信
日期:2009.5
修改:无
内容:连接好串口或者usb转串口至电脑,下载该程序,打开电源
打开串口调试程序,将波特率设置为9600,无奇偶校验
晶振11.0592MHz,发送和接收使用的格式相同,如都使用
字符型格式,在发送框输入 hello,I Love MCU ,在接
收框中同样可以看到相同字符,说明设置和通信正确
------------------------------------------------*/
#include"board.h" //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include "SHT11.h"
/***************函数声明*************************************/
void UART_INIT(void);
void TXByte(unsigned char dat);
void TX_NByte(unsigned char *dat,unsigned char TXLen);
void Delayms(unsigned int T);
/***************定义数组*************************************/
unsigned char xdata uchTX_Buffer[13] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};//串口发送数据缓冲区
unsigned char xdata uchTX_Buffer1[14] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};//串口发送数据缓冲区1
unsigned char xdata uchRX_Buffer[17] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};//串口接收数据缓冲区
/***********定义变量**************************/
unsigned char RXData_Counter1 = 0;//数据接收计数器
bit FlagRdyOK = 0;//是否可以接收数据包标志位:0:可以接收 1:不可接收
/************************************/
/*
函数名称:void UART_INIT(void)
函数功能:串口初始化
入口参数:无
返回值:无
*/
void UART_INIT(void)
{
AUXR |= 0x11; //与传统8051兼容模式,串口1使用独立波特率发生器BRT
PCON |= 0x00; //波特率不加倍
IPH |= 0x10;
IP |= 0x10;
SCON |= 0x50; //工作方式1
BRT = 0xFD; //9600波特率
ES = 1; //开串口1中断
EA = 1; //开总中断
}
/*
函数名称:void UART_SER (void) interrupt 4
函数功能:串口接收中断
入口参数:无
返回值:无
*/
void UART1_ISR (void) interrupt 4
{
unsigned char DatBuffer = 0;
if(RI == 1)
{
DatBuffer = SBUF;
RI = 0;
if(FlagRdyOK == 0)//判断是否可以接收数据包:0:可以 1:不可以
{
uchRX_Buffer[RXData_Counter1] = DatBuffer;
++RXData_Counter1;
TH1 = (65536 - (int)((UART0FRAMETESTMS * 11.0592 * 1000)/12)) / 256; //定时4ms
TL1 = (65536 - (int)((UART0FRAMETESTMS * 11.0592 * 1000)/12)) % 256;
TR1 = 1;//开定时器
}//if(FlagRdyOK == 0)//判断是否可以接收数据包:0:可以 1:不可以
}//if(TR1 == 1)
}//void UART_SER (void) interrupt 4
/*
函数名称:void TXByte(unsigned char dat)
函数功能:发送一字节数据
入口参数:(unsigned char) dat:一字节的发送数据
返回值:无
*/
void TXByte(unsigned char dat)
{
SBUF = dat;
while(TI == 0);
TI = 0;
}
/*
函数名称:void TXByte(unsigned char dat)
函数功能:发送N字节数据
入口参数:(unsigned char) dat:发送数据指针
返回值:无
*/
void TX_NByte(unsigned char *dat,unsigned char TXLen)
{
unsigned char i;
for(i = 0; i < TXLen;i++)
{
TXByte(*dat);
++dat;
}
}
/*
函数名称:void Delayms(unsigned int T)
函数功能:延时函数
入口参数:(unsigned char) T:延时时间(T*1ms)
返回值:无
*/
//void Delayms(unsigned int T)
//{
// unsigned int i;
// unsigned char j;
// for(i = 0; i < T; i++)
// for(j = 0;j < 50;j++);
//}
void UART1_ISR (void) interrupt 4 这个中断中FlagRdyOK 是主要的,他是侦定时时间到是否可以进行协议解析的标志,0:无操作,继续把数据存入接受缓冲区的协议栈 1:可以进行解析,转转去处理协议中的数据,这个函数就说这么多吧
一周热门 更多>