本帖最后由 gmajvfhpa 于 2013-11-14 13:25 编辑
东拼西凑的程序。
STC12C5A60S2 单片机 24M晶振,别的单片机可能要更改 串口初始化函数中波特率相关代码 与中断0 中断时间相关的代码
总体思想:在串口中断中判断数据 是否接收到 完整的帧,是则关中断。在主循环中 处理接收到的帧,处理好后开口中断。
- #define OUTTIME 15//两数据帧最小间隔 毫秒
- #define MOD_ADDR 1 //本modbus 地址
- uint8 receCount; //接收到的字节个数
- uint8 idata receBuf[16]; //发送接收缓冲区
- uint8 idata receTimeOut; //接收超时
- // 串行中断程序
- void uartIntProc() interrupt 4
- {
- if(RI)
- {
- RI = 0;
-
- if(receTimeOut==0)//两次接收的间隔时间大于OUTTIME receTimeOut在中断中每隔1ms减1
- {
- if(receCount>3) //如已收到的字节大于3个, 则认为已接到一帧数据,关中断 等待解析函数处理 解析函数判断 接收到的字节数与 是否超时 就可确定是否有数据包
- { //解析完后,接到的到字节数receCount清零
- ES = 0; //关串口中断 如已收到一个数据包,则要到处理好之后 由处理函数打开
- return;
- }
- else
- receCount = 0;
- }
- receTimeOut = OUTTIME;//置计时寄存器 该寄存器 在中断0中,每隔1ms自动减1
- receBuf[receCount] = SBUF;
- // ACC = SBUF;
- // if(P != RB8)
- // checkoutError = 2; //偶校验出错
- receCount++; //已接收到的数据量加1
- receCount &= 0x0f; //最多一次只能接收16个字节
- }
- }
- /**************************************************************************************************
- NAME : function_MODBUS //检查与处理uart0数据
- INPUT : NO
- OUTPUT : NO
- FUNCTION :
- 执行MODBUS功能函数
- **************************************************************************************************/
- void function_MODBUS(void)
- {
- bit bt;
- if(receCount > 3) //接收到的数据大于4
- {
- if(receTimeOut==0) // 离上次接收到数据的最大间隔时 限 已等于0
- {
- bt = !checkPACK_MODBUS();// 校验接收数据包的正确性 正确返回零,错误返回非零值。
- if((receBuf[0] == MOD_ADDR) && bt ) //是本机地址
- {
- switch(receBuf[1])
- {
- case 1://读取线圈状态(读取点 16位以内)
- break;
- case 3://读取保持寄存器(一个或多个)
- read_reg();//读寄存器
- sendPACK_MODBUS( ); //将CRC加入数据尾部,并发送数据包
- break;
- case 5://强制单个线圈
- case 6://设置单个寄存器
- TX_NByte(receBuf,receCount);
- break;
-
- default:
- break;
- }
- }
- receCount =0;//处理好数据后,接收到的字节个数清零
- ES = 1; //开串口中断 如已收到一个数据包,则要到处理好之后才能再开接收数据
- }
- }
- }
复制代码代码基本调通,已可以与 Modbus调试精灵 通信。不过有一疑问 ,在波特率9600时,理论上 “OUTTIME 15//两数据帧最小间隔 毫秒”为3ms就够,实际要设到9以上才行,好久没搞懂
modbus已调通.rar
(111.63 KB, 下载次数: 339)
2013-11-14 12:58 上传
点击文件名下载附件
开缓冲区吧,中断一直接收,主程序读程序就行,不会丢数据,需要耗一些ram
一周热门 更多>