51单片机在工程中自己做的MODBUS通信程序

2020-01-17 19:06发布

本帖最后由 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,这个是理论计算值,但是这个值作为你的定时器设定值是不行的,因为加上硬件以及软件的通信延时会比这个值大,所以你要在这个值得基础上微调,调到他的最小有效率值。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
41条回答
wangyy@dianzi
2020-01-18 17:23
再说rs232.h



/*-----------------------------------------------
  名称:串口通信
  日期: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:可以进行解析,转转去处理协议中的数据,这个函数就说这么多吧

一周热门 更多>