modbusRTU的C单片机程序

合集下载

modbus rtu单片机范例

modbus rtu单片机范例

modbus rtu单片机范例1.引言1.1 概述概述部分:Modbus RTU是一种常用的串行通信协议,广泛应用于工业自动化领域。

本文将介绍Modbus RTU协议的基本原理和特点,并结合单片机的应用场景,探讨如何在单片机中实现基于Modbus RTU的通信。

在工业自动化领域,通信是各种设备之间进行数据交换和控制的重要手段。

Modbus RTU作为一种开放、简单、可靠的通信协议,被广泛应用于监控、控制和数据采集等应用场景。

其优势在于其使用简单、可扩展性好以及兼容性强。

文章的结构将从Modbus RTU的基本原理和数据帧结构入手,介绍其通信流程和通信方式。

并通过具体的单片机应用场景,展示如何利用Modbus RTU进行设备之间的数据交互和控制。

通过这些例子,读者将深入理解Modbus RTU的应用原理和具体操作。

本文旨在为读者提供一个Modbus RTU在单片机应用中的范例,并通过实际案例来展示如何利用该协议进行数据通信。

同时,本文也将探讨当前Modbus RTU在单片机应用中存在的问题和挑战,并提供一些未来研究方向的建议。

通过阅读本文,读者将能够全面了解Modbus RTU协议的基本原理和应用场景,掌握在单片机中实现Modbus RTU通信的方法,以及面临的挑战和未来的发展方向。

希望本文能对读者在工业自动化领域的学习和实践有所启发,为他们的项目开发提供一定的指导和帮助。

1.2 文章结构文章结构是指组织和安排文章内容的方式和顺序。

在本文中,文章结构按照以下方式组织:引言部分包括概述、文章结构和目的;正文部分包括Modbus RTU介绍和单片机应用场景;结论部分包括总结和下一步研究方向。

引言部分将首先提供一个概述,介绍Modbus RTU单片机范例的背景和重要性。

然后,进一步阐述文章的结构,显示读者整篇文章将如何组织和涵盖哪些方面。

最后,明确文章的目的,即讨论和探索有关Modbus RTU单片机范例的相关内容。

Modbus-RTU和Modbus-TCP协议模板(C语言)

Modbus-RTU和Modbus-TCP协议模板(C语言)

Modbus-RTU和Modbus-TCP协议模板(C语言)目录简介: (2)Modbus-RTU简介: (2)Modbus-TCP简介: (3)System.h: (4)CRC_Check.h (5)CRC_Check.c (5)Modbus_RTU.h (8)Modbus_RTU.c (10)Modbus_TCP.h (27)Modbus_TCP.c (27)第1页简介:在单片机内部实现modbus协议,可以简单地将变量的值映射到modbus寄存器地址,这种方法是高效的,但是有以下缺点:1、通常不支持一条指令操作多个变量(寄存器);2、可移植性较差。

本模板使用8位数组模拟modbus寄存器。

06,10指令均对数组进行写操作,同时记录寄存器的写入操作,在其他地方定时判断“写入标志”,将“写入标志”置位的“模拟寄存器”的值转移到相关变量,或进行其他操作。

03指令读取最新数据,要求定时将变量的值写入“模拟寄存器”。

本模板缺点是占用资源较多、效率较低,优点是完整支持了modbus的03,06,10指令。

Modbus-RTU简介:1、Modbus读寄存器指令(0x03)地址(1B) +功能码(1B) +起始地址(2B) +寄存器数量(2B) +CRC(2B)返回:地址(1B) +功能码(1B) +字节数(1B) +数据值(2*“寄存器数量” Bytes或者“字节数”) +CRC(2B)2、Modbus写单个寄存器指令(0x06)地址(1B)+功能码(1B)+寄存器地址(2B)+数据值(2B)+CRC(2B)返回:地址(1B)+功能码(1B)+寄存器地址(2B)+数据值(2B)+CRC(2B) (返回与发送的指令相同)3、Modbus写多个寄存器指令(0x10)地址(1B) +功能码(1B) +起始地址(2B) +写寄存器数量(2B n) +字节计数(1B n*2) +数据(n*2 B) +CRC(2B)返回:地址(1B) +功能码(1B) +起始地址(2B) +写寄存器数量(2B) +CRC(2B)第2页Modbus-TCP简介:在MODBUS-RTU前添加6个字节,并删除MODBUS-RTU的CRC校验。

STC单片机实现的ModBusRTU协议无线通信服务器

STC单片机实现的ModBusRTU协议无线通信服务器
2004 年湛江市自来水公司寸金加压站无人值守 控制系统就是利用上述方法成功地实现了远程无线 遥控加压站的机泵操作 经 3 年时间的实践证明 基 于 STC 单片机实现的 ModBus-RTU 主站协议的无线 通信服务器是实用可行的
本文创新点 能够以一种低成本的方式实现无线 通信服务器 并实现两种不同厂家的 PLC 通信互联 从系统设计角度给出通信服务器的具体实现
口最好是按电脑的 COM 口来设计 这样修改或调试 程序时只要用一根对接的串口线把电脑的 COM 口和 需下载的单片机相连接就能把程序下载到单片机中
5 通信协议及功能
在本通信服务器中共涉及了三个通信协议 一为 自编写的 ASCII 协议 二为 Modbus-RTU 协议 三为 SPI 协议
Key words: STC Micro-control Unit; Modbus Agreement; ASCII Code Aagreement; SPI
作者简介: 许文辉 男 1974 年生 工程师 高级程序员 学士 主要从事工业控制及自动化
26 万方数据
2007 年第 1 期自动化与信息工程 25
万方数据
操作码说明 0=读 128=写 64=从站读/写数据 地址寄存器 ADDR 65=启动 COM2 口写操作 66= 提高从站读优先级 0~63 为从站各区的字节地址
6 程序设计
1 系统功能及划分 本系统共有 2 个串口及 2 块 STC89C516RD 与 主站 PLC 连接的串口称为 COM1 实现 COM1 功能 的 STC89C516RD 称为主 MCU 与电台连接的串口 称为 COM2 实现 COM2 功能的 STC89C516RD 称为 从 MCU 主 MCU 运行自编 ASCII 协议 通过自编 ASCII 协议可以实现读 写通信服务器里的信息 主要有主 从 MCU 的程序时间 定义通信服务器中各从站 PLC 的数据结构 如通信地址 起始地址 数据个数等 读写各从站 PLC 的数据 从 MCU 运行 Modbus-RTU 主站协议 主要负责 完成对各从站 PLC 的数据交换 纠错 可通过 COM1 及 COM2 分别对主 从 MCU 进 行 ISP 方式的程序下载 非常容易 利用从 MCU 的 IAP 功能 当主 MCU 接收到从 站 PLC 的数据结构时 把此信息写入从 MCU 的 Flash 中 确保了重要数据的掉电保护

modbusRTU的C单片机程序

modbusRTU的C单片机程序

modbus RTU 的 C51 单片机程序modbus.cinclude "main.h"//字地址 0 - 255 只取低8位//位地址 0 - 255 只取低8位/ CRC 高位字节值表 /const uint8 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低位字节值表/const uint8 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} ;uint8 testCoil; //用于测试位地址1uint16 testRegister; //用于测试字址址16uint8 localAddr = 1; //单片机控制板的地址uint8 sendCount; //发送字节个数uint8 receCount; //接收到的字节个数uint8 sendPosi; //发送位置uint16 crc16uint8 puchMsg; uint16 usDataLen {uint8 uchCRCHi = 0xFF ; / 高CRC字节初始化 / uint8 uchCRCLo = 0xFF ; / 低CRC 字节初始化 / uint32 uIndex ; / CRC循环中的索引 /while usDataLen-- / 传输消息缓冲区 /{uIndex = uchCRCHi ^ puchMsg++ ; / 计算CRC / uchCRCHi = uchCRCLo ^ auchCRCHiuIndex ;uchCRCLo = auchCRCLouIndex ;}return uchCRCHi << 8 | uchCRCLo ;}//uint16 crc16uint8 puchMsg; uint16 usDataLen //开始发送void beginSendvoid{b485Send = 1; //设为发送sendPosi = 0;ifsendCount > 1sendCount--;ACC = sendBuf0;TB8 = P;SBUF = sendBuf0;}//void beginSendvoid//读线圈状态void readCoilvoid{uint8 addr;uint8 tempAddr;uint8 byteCount;uint8 bitCount;uint16 crcData;uint8 position;uint8 i;k;uint8 result;uint16 tempData;uint8 exit = 0;//addr = receBuf2<<8 + receBuf3; //tempAddr = addr & 0xfff;addr = receBuf3;tempAddr = addr;//bitCount = receBuf4<<8 + receBuf5; //读取的位个数bitCount = receBuf5;byteCount = bitCount / 8; //字节个数ifbitCount%8 = 0byteCount++;fork=0;k<byteCount;k++{//字节位置position = k + 3;sendBufposition = 0;fori=0;i<8;i++{getCoilValtempAddr;&tempData;sendBufposition |= tempData << i;tempAddr++;iftempAddr >= addr+bitCount{ //读完exit = 1;break;}}ifexit == 1break;}sendBuf0 = localAddr;sendBuf1 = 0x01;sendBuf2 = byteCount;byteCount += 3;crcData = crc16sendBuf;byteCount; sendBufbyteCount = crcData >> 8; byteCount++;sendBufbyteCount = crcData & 0xff; sendCount = byteCount + 1; beginSend;}//void readCoilvoid//读寄存器void readRegistersvoid{uint8 addr;uint8 tempAddr;uint16 result;uint16 crcData;uint8 readCount;uint8 byteCount;uint8 finsh; //1完成 0出错uint16 i;uint16 tempData = 0;//addr = receBuf2<<8 + receBuf3;//tempAddr = addr & 0xfff;addr = receBuf3;tempAddr = addr;//readCount = receBuf4<<8 + receBuf5; //要读的个数 readCount = receBuf5;byteCount = readCount 2;fori=0;i<byteCount;i+=2;tempAddr++{getRegisterValtempAddr;&tempData;sendBufi+3 = tempData >> 8;sendBufi+4 = tempData & 0xff;}sendBuf0 = localAddr;sendBuf1 = 3;sendBuf2 = byteCount;byteCount += 3;crcData = crc16sendBuf;byteCount;sendBufbyteCount = crcData >> 8;byteCount++;sendBufbyteCount = crcData & 0xff; sendCount = byteCount + 1;beginSend;}//void readRegistersvoid//强制单个线圈void forceSingleCoilvoid{uint8 addr;uint8 tempAddr;uint16 tempData;uint8 onOff;uint8 i;//addr = receBuf2<<8 + receBuf3;//tempAddr = addr & 0xfff;addr = receBuf3;tempAddr = addr;//onOff = receBuf4<<8 + receBuf5;onOff = receBuf4;//ifonOff == 0xff00ifonOff == 0xff{ //设为ONtempData = 1;}//else ifonOff == 0x0000else ifonOff == 0x00{ //设为OFFtempData = 0;}setCoilValtempAddr;tempData; fori=0;i<receCount;i++{sendBuf = receBuf;}sendCount = receCount; beginSend;}//void forceSingleCoilvoid//设置多个寄存器void presetMultipleRegistersvoid {uint8 addr;uint8 tempAddr;uint8 byteCount;uint8 setCount;uint16 crcData;uint16 tempData;uint8 finsh; //为1时完成为0时出错uint8 i;//addr = receBuf2<<8 + receBuf3;//tempAddr = addr & 0xfff;addr = receBuf3;tempAddr = addr & 0xff;//setCount = receBuf4<<8 + receBuf5; setCount = receBuf5;byteCount = receBuf6;fori=0;i<setCount;i++;tempAddr++{tempData = receBufi2+7<<8 + receBufi2+8; setRegisterValtempAddr;tempData;}sendBuf0 = localAddr;sendBuf1 = 16;sendBuf2 = addr >> 8;sendBuf3 = addr & 0xff;sendBuf4 = setCount >> 8;sendBuf5 = setCount & 0xff;crcData = crc16sendBuf;6;sendBuf6 = crcData >> 8;sendBuf7 = crcData & 0xff;sendCount = 8;beginSend;}//void presetMultipleRegistersvoid//检查uart0数据void checkComm0Modbusvoid{uint16 crcData;uint16 tempData;ifreceCount > 4{switchreceBuf1{case 1://读取线圈状态读取点 16位以内case 3://读取保持寄存器一个或多个case 5://强制单个线圈case 6://设置单个寄存器ifreceCount >= 8{//接收完成一组数据//应该关闭接收中断ifreceBuf0==localAddr && checkoutError==0{crcData = crc16receBuf;6;ifcrcData == receBuf7+receBuf6<<8 {//校验正确ifreceBuf1 == 1{//读取线圈状态读取点 16位以内 readCoil;}else ifreceBuf1 == 3{//读取保持寄存器一个或多个readRegisters;}else ifreceBuf1 == 5{//强制单个线圈forceSingleCoil;}else ifreceBuf1 == 6{//presetSingleRegister; }}}receCount = 0;checkoutError = 0;}break;case 15://设置多个线圈tempData = receBuf6;tempData += 9; //数据个数ifreceCount >= tempData{ifreceBuf0==localAddr && checkoutError==0{crcData = crc16receBuf;tempData-2;ifcrcData == receBuftempData-2<<8+ receBuftempData-1 {//forceMultipleCoils;}}receCount = 0;checkoutError = 0;}break;case 16://设置多个寄存器tempData = receBuf4<<8 + receBuf5;tempData = tempData 2; //数据个数tempData += 9;ifreceCount >= tempData{ifreceBuf0==localAddr && checkoutError==0{crcData = crc16receBuf;tempData-2;ifcrcData == receBuftempData-2<<8+ receBuftempData-1 {presetMultipleRegisters;}}receCount = 0;checkoutError = 0;}break;default:break;}}}//void checkComm0void//取线圈状态返回0表示成功uint16 getCoilValuint16 addr;uint16 tempData {uint16 result = 0;uint16 tempAddr;tempAddr = addr & 0xfff;//只取低8位地址switchtempAddr & 0xff{case 0:break;case 1:tempData = testCoil;break;case 2:break;case 3:break;case 4:break;case 5:break;case 6:break;case 7:break;case 8:break;case 9:break;case 10:break;case 11:break;case 12:break;case 13:break;case 14:break;case 15:break;case 16:break;default:break;}return result;}//uint16 getCoilValuint16 addr;uint16 data //设定线圈状态返回0表示成功uint16 setCoilValuint16 addr;uint16 tempData {uint16 result = 0;uint16 tempAddr;tempAddr = addr & 0xfff;switchtempAddr & 0xff{case 0:break;case 1:testCoil = tempData;break;case 2:break;case 3:break;break; case 5:break; case 6:break; case 7:break; case 8:break; case 9:break; case 10: break; case 11: break; case 12: break; case 13: break; case 14: break;break;case 16:break;default:break;}return result;}//uint16 setCoilValuint16 addr;uint16 data//取寄存器值返回0表示成功uint16 getRegisterValuint16 addr;uint16 tempData {uint16 result = 0;uint16 tempAddr;tempAddr = addr & 0xfff;switchtempAddr & 0xff{case 0:break;case 1:break;case 2:case 3:break; case 4:break; case 5:break; case 6:break; case 7:break; case 8:break; case 9:break; case 10: break; case 11: break; case 12: break; case 13:case 14:break;case 15:break;case 16:tempData = testRegister;break;default:break;}return result;}//uint16 getRegisterValuint16 addr;uint16 &data //设置寄存器值返回0表示成功uint16 setRegisterValuint16 addr;uint16 tempData {uint16 result = 0;uint16 tempAddr;tempAddr = addr & 0xfff;switchtempAddr & 0xff{case 0:case 1: break; case 2: break; case 3:break; case 4:break; case 5:break; case 6:break; case 7:break; case 8:break; case 9:break; case 10: break; case 11:case 12:break;case 13:break;case 14:break;case 15:break;case 16:testRegister = tempData;break;default:break;}return result;}//uint8 setRegisterValuint16 addr;uint16 data。

stm32modbusrtu代码

stm32modbusrtu代码

STM32 Modbus RTU 代码简介Modbus是一种通信协议,常用于工业自动化领域中的设备间通信。

STM32是一系列由意法半导体(STMicroelectronics)开发的32位微控制器。

在本文中,我们将探讨如何使用STM32微控制器编写Modbus RTU代码。

Modbus RTU 协议Modbus RTU是Modbus协议的一种变体,它使用二进制编码来进行数据传输。

RTU代表”Remote Terminal Unit”,是指远程终端单元,也就是Modbus网络中的从设备。

Modbus RTU协议使用串口通信,并且以字节为单位进行数据传输。

每个字节都包含8位数据位和1位奇偶校验位。

STM32 微控制器STM32微控制器是一款高性能、低功耗的32位ARM Cortex-M内核微控制器。

它具有丰富的外设和强大的处理能力,非常适合用于工业自动化等领域。

STM32微控制器支持多个串口接口,并且具有强大的时钟和计时功能,非常适合用于实现Modbus RTU通信。

编写 STM32 Modbus RTU 代码要编写STM32 Modbus RTU代码,我们需要以下步骤:1. 硬件连接首先,我们需要将STM32微控制器与Modbus RTU从设备进行硬件连接。

通常,我们会使用串口接口来进行通信。

确保正确连接了串口的TX和RX引脚。

2. 配置串口在STM32的代码中,我们需要配置串口接口的参数,如波特率、数据位、校验位等。

根据Modbus RTU协议的要求,通常使用9600波特率、8个数据位和无校验位。

以下是一个配置串口的示例代码:// 配置串口void UART_Config(void){// 初始化结构体USART_InitTypeDef USART_InitStruct;// 使能串口时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);// 配置波特率、数据位和停止位USART_ART_BaudRate = 9600;USART_ART_WordLength = USART_WordLength_8b;USART_ART_StopBits = USART_StopBits_1;// 配置校验位为无校验USART_ART_Parity = USART_Parity_No;// 配置硬件流控制为无流控制USART_ART_HardwareFlowControl = USART_HardwareFlowControl_Non e;// 使能接收和发送功能USART_ART_Mode = USART_Mode_Rx | USART_Mode_Tx;// 初始化串口USART_Init(USART1, &USART_InitStruct);// 使能串口USART_Cmd(USART1, ENABLE);}3. 实现 Modbus RTU 功能接下来,我们需要实现Modbus RTU的功能代码。

MODBUS通讯协议及编程(VC)

MODBUS通讯协议及编程(VC)

MODBUS通讯协议及编程ModBus通讯协议分为RTU协议和ASCII协议。

下面就ModBus RTU协议简要介绍如下:一、通讯协议(一)、通讯传送方式:通讯传送分为独立的信息头,和发送的编码数据。

以下的通讯传送方式定义也与MODBUS RTU 通讯规约相兼容:编码8位二进制起始位1位数据位8位奇偶校验位1位(偶校验位)停止位1位错误校检CRC(冗余循环码)初始结构= ≥4字节的时间地址码= 1 字节功能码= 1 字节数据区= N 字节错误校检= 16位CRC码结束结构= ≥4字节的时间地址码:地址码为通讯传送的第一个字节。

这个字节表明由用户设定地址码的从机将接收由主机发送来的信息。

并且每个从机都有具有唯一的地址码,并且响应回送均以各自的地址码开始。

主机发送的地址码表明将发送到的从机地址,而从机发送的地址码表明回送的从机地址。

功能码:通讯传送的第二个字节。

ModBus通讯规约定义功能号为1到127。

本仪表只利用其中的一部分功能码。

作为主机请求发送,通过功能码告诉从机执行什么动作。

作为从机响应,从机发送的功能码与从主机发送来的功能码一样,并表明从机已响应主机进行操作。

如果从机发送的功能码的最高位为1(比如功能码大与此同时127),则表明从机没有响应操作或发送出错。

数据区:数据区是根据不同的功能码而不同。

数据区可以是实际数值、设置点、主机发送给从机或从机发送给主机的地址。

CRC码:二字节的错误检测码。

(二)、通讯规约:当通讯命令发送至仪器时,符合相应地址码的设备接通讯命令,并除去地址码,读取信息,如果没有出错,则执行相应的任务;然后把执行结果返送给发送者。

返送的信息中包括地址码、执行动作的功能码、执行动作后结果的数据以及错误校验码。

如果出错就不发送任何信息。

1.信息帧结构地址码功能码数据区错误校验码8位8位N × 8位16位地址码:地址码是信息帧的第一字节(8位),从0到255。

这个字节表明由用户设置地址的从机将接收由主机发送来的信息。

STC单片机实现的ModBus-RTU协议无线通信服务器

STC单片机实现的ModBus-RTU协议无线通信服务器
具有在系统编程的 ISP/IAP 功能 可以采用 IAP 功能 把需要掉电保存的数据写入 Flash 内 也可以 在完全不改动或拿出单片机芯片 利用 ISP 功能对单
24
片机的程序进行修改 DIP-40 封装的 STC89C516RD 可以完全兼容
AT89C51 或 AT89C52 其管脚如图 2
Key words: STC Micro-control Unit; Modbus Agreement; ASCII Code Aagreement; SPI
作者简介: 许文辉 男 1974 年生 工程师 高级程序员 学士 主要从事工业控制及自动化
26
STC单片机实现的ModBus-RTU协议无线通信服务器
线通信中的数据纠错和自动对多个从站的数据巡测 功能 进一步减少主站 PLC 与通信服务器的信息量
通信服务器工作原理如图 1
主站 PLC 通信服务器
电台
自编 ASCII 协议 Modbus-RTU 主站协议
图 1 通信服务器工作原理图
3 STC 单片机的介绍
在通信服务器中选用了两片 STC89C516RD 以 下重点介绍 STC89C516RD 的基本情况
参考文献
[1] MODICON.Inc,Modicon Modbus.Protocol Reference Guide, 1996:1~70
[2] 许文辉,周宇航. 利用 Modbus 协议实现无线通信. 微计算 机信息,2004,121(8):23~24
[3] 宏晶科技公司. STC89C516RD 用户手册,2004, 6: 1~86 [4] Allen-Brladley. 增强型 PLC5 可编程序控制器使用手
STC89C516RD 是一款增强型的 8 位 8051 系列的 MCU 它的性能特征如下

modbus-RTU-的-C51-单片机-程序

modbus-RTU-的-C51-单片机-程序

modbus RTU 的C51 单片机程序本文转自:新势力单片机[url]http://www.XinShiLi.n et[/url]modbus.c#include "main.h"//字地址0 - 255 (只取低8位) //位地址0 - 255 (只取低8位)/* CRC 高位字节值表*/ const uint8 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,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, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40} ;/* CRC低位字节值表*/ const uint8 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,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,0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,0x43, 0x83, 0x41, 0x81, 0x80, 0x40} ;uint8 testCoil; //用于测试位地址1uint16 testRegister; //用于测试字址址16uint8 localAddr = 1; //单片机控制板的地址uint8 sendCount; //发送字节个数uint8 receCount; //接收到的字节个数uint8 sendPosi; //发送位置uint16 crc16(uint8 *puchMsg, uint16 usDataLen){uint8 uchCRCHi = 0xFF ; /* 高CRC字节初始化*/uint8 uchCRCLo = 0xFF ; /* 低CRC 字节初始化*/uint32 uIndex ; /* CRC循环中的索引*/while (usDataLen--) /* 传输消息缓冲区*/{uIndex = uchCRCHi ^ *puchMsg++ ; /* 计算CRC*/uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ; uchCRCLo = auchCRCLo[uIndex] ;}return (uchCRCHi << 8 | uchCRCLo) ;}//uint16 crc16(uint8*puchMsg, uint16 usDataLen)//开始发送void beginSend(void){b485Send = 1; //设为发送sendPosi = 0;if(sendCount > 1) sendCount--;ACC = sendBuf[0];TB8 = P;SBUF = sendBuf[0];}//void beginSend(void) //读线圈状态void readCoil(void) {uint8 addr;uint8 tempAddr;uint8 byteCount;uint8 bitCount;uint16 crcData;uint8 position;uint8 i,k;uint8 result;uint16 tempData;uint8 exit = 0;//addr = (receBuf[2]<<8) +receBuf[3];//tempAddr = addr & 0xfff;addr = receBuf[3]; tempAddr = addr;//bitCount = (receBuf[4]<<8) + receBuf[5]; //读取的位个数bitCount = receBuf[5];byteCount = bitCount / 8; //字节个数if(bitCount%8 != 0) byteCount++;for(k=0;k<byteCount;k++) {//字节位置position = k + 3; sendBuf[position] = 0; for(i=0;i<8;i++){getCoilVal(tempAddr,&tem pData);sendBuf[position] |= tempData << i; tempAddr++;if(tempAddr >= addr+bitCount){ //读完exit = 1;break;}}if(exit == 1) break;}sendBuf[0] = localAddr;sendBuf[1] = 0x01; sendBuf[2] = byteCount; byteCount += 3;crcData = crc16(sendBuf,byteCount); sendBuf[byteCount] = crcData >> 8;byteCount++;sendBuf[byteCount] =crcData & 0xff; sendCount = byteCount + 1;beginSend();}//void readCoil(void)//读寄存器void readRegisters(void) {uint8 addr;uint8 tempAddr;uint16 result;uint16 crcData;uint8 readCount;uint8 byteCount;uint8 finsh; //1完成0出错uint16 i;uint16 tempData =0;//addr = (receBuf[2]<<8) + receBuf[3];//tempAddr = addr & 0xfff;addr = receBuf[3];tempAddr = addr;//readCount =(receBuf[4]<<8) + receBuf[5]; //要读的个数readCount = receBuf[5];byteCount = readCount * 2;for(i=0;i<byteCount;i+=2,t empAddr++){getRegisterVal(tempAddr, &tempData);sendBuf[i+3] = tempData >> 8;sendBuf[i+4] = tempData& 0xff;}sendBuf[0] = localAddr;sendBuf[1] = 3;sendBuf[2] = byteCount;byteCount += 3;crcData =crc16(sendBuf,byteCount);sendBuf[byteCount] = crcData >> 8;byteCount++;sendBuf[byteCount] = crcData & 0xff;sendCount =byteCount + 1;beginSend();}//void readRegisters(void) //强制单个线圈void forceSingleCoil(void) {uint8 addr;uint8 tempAddr;uint16 tempData;uint8 onOff;uint8 i;//addr = (receBuf[2]<<8) + receBuf[3];//tempAddr = addr & 0xfff;addr = receBuf[3]; tempAddr = addr;//onOff = (receBuf[4]<<8)+ receBuf[5];onOff = receBuf[4];//if(onOff == 0xff00)if(onOff == 0xff){ //设为ONtempData = 1;}//else if(onOff == 0x0000) else if(onOff == 0x00){ //设为OFFtempData = 0;}setCoilVal(tempAddr,temp Data);for(i=0;i<receCount;i++) {sendBuf = receBuf;}sendCount = receCount; beginSend();}//void forceSingleCoil(void)//设置多个寄存器void presetMultipleRegisters(vo id){uint8 addr;uint8 tempAddr;uint8 byteCount;uint8 setCount;uint16 crcData;uint16 tempData;uint8 finsh; //为1时完成为0时出错uint8 i;//addr = (receBuf[2]<<8) + receBuf[3];//tempAddr = addr & 0xfff;addr = receBuf[3]; tempAddr = addr & 0xff; //setCount = (receBuf[4]<<8) + receBuf[5];setCount = receBuf[5]; byteCount = receBuf[6]; for(i=0;i<setCount;i++,te mpAddr++){tempData = (receBuf[i*2+7]<<8) + receBuf[i*2+8];setRegisterVal(tempAddr,t empData);}sendBuf[0] = localAddr; sendBuf[1] = 16; sendBuf[2] = addr >> 8; sendBuf[3] = addr & 0xff; sendBuf[4] = setCount >> 8;sendBuf[5] = setCount & 0xff;crcData = crc16(sendBuf,6); sendBuf[6] = crcData >> 8; sendBuf[7] = crcData & 0xff;sendCount = 8; beginSend();}//void presetMultipleRegisters(vo id)//检查uart0数据voidcheckComm0Modbus(void ){uint16 crcData;uint16 tempData;if(receCount > 4){switch(receBuf[1]){case 1://读取线圈状态(读取点16位以内)case 3://读取保持寄存器(一个或多个)。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

m o d b u s R T U的C单片机程序集团文件版本号:(M928-T898-M248-WU2669-I2896-DQ586-M1988)modbus RTU 的 C51 单片机程序modbus.c#include "main.h"//字地址 0 - 255 (只取低8位)//位地址 0 - 255 (只取低8位)/* CRC 高位字节值表 */const uint8 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低位字节值表*/const uint8 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} ;uint8 testCoil; //用于测试位地址1uint16 testRegister; //用于测试字址址16uint8 localAddr = 1; //单片机控制板的地址uint8 sendCount; //发送字节个数uint8 receCount; //接收到的字节个数uint8 sendPosi; //发送位置uint16 crc16(uint8 *puchMsg, uint16 usDataLen) {uint8 uchCRCHi = 0xFF ; /* 高CRC字节初始化 */ uint8 uchCRCLo = 0xFF ; /* 低CRC 字节初始化 */ uint32 uIndex ; /* CRC循环中的索引 */while (usDataLen--) /* 传输消息缓冲区 */{uIndex = uchCRCHi ^ *puchMsg++ ; /* 计算CRC */ uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;uchCRCLo = auchCRCLo[uIndex] ;}return (uchCRCHi << 8 | uchCRCLo) ;}//uint16 crc16(uint8 *puchMsg, uint16 usDataLen) //开始发送void beginSend(void){b485Send = 1; //设为发送sendPosi = 0;if(sendCount > 1)sendCount--;ACC = sendBuf[0];TB8 = P;SBUF = sendBuf[0];}//void beginSend(void)//读线圈状态void readCoil(void){uint8 addr;uint8 tempAddr;uint8 byteCount;uint8 bitCount;uint16 crcData;uint8 position;uint8 i,k;uint8 result;uint16 tempData;uint8 exit = 0;//addr = (receBuf[2]<<8) + receBuf[3]; //tempAddr = addr & 0xfff;addr = receBuf[3];tempAddr = addr;//bitCount = (receBuf[4]<<8) + receBuf[5]; //读取的位个数bitCount = receBuf[5];byteCount = bitCount / 8; //字节个数if(bitCount%8 != 0)byteCount++;for(k=0;k<byteCount;k++){//字节位置position = k + 3;sendBuf[position] = 0;for(i=0;i<8;i++){getCoilVal(tempAddr,&tempData);sendBuf[position] |= tempData << i;tempAddr++;if(tempAddr >= addr+bitCount){ //读完exit = 1;break;}}if(exit == 1)break;}sendBuf[0] = localAddr;sendBuf[1] = 0x01;sendBuf[2] = byteCount;byteCount += 3;crcData = crc16(sendBuf,byteCount); sendBuf[byteCount] = crcData >> 8; byteCount++;sendBuf[byteCount] = crcData & 0xff; sendCount = byteCount + 1;beginSend();}//void readCoil(void)//读寄存器void readRegisters(void){uint8 addr;uint8 tempAddr;uint16 result;uint16 crcData;uint8 readCount;uint8 byteCount;uint8 finsh; //1完成 0出错uint16 i;uint16 tempData = 0;//addr = (receBuf[2]<<8) + receBuf[3];//tempAddr = addr & 0xfff;addr = receBuf[3];tempAddr = addr;//readCount = (receBuf[4]<<8) + receBuf[5]; //要读的个数readCount = receBuf[5];byteCount = readCount * 2;for(i=0;i<byteCount;i+=2,tempAddr++){getRegisterVal(tempAddr,&tempData);sendBuf[i+3] = tempData >> 8;sendBuf[i+4] = tempData & 0xff;}sendBuf[0] = localAddr;sendBuf[1] = 3;sendBuf[2] = byteCount;byteCount += 3;crcData = crc16(sendBuf,byteCount);sendBuf[byteCount] = crcData >> 8;byteCount++;sendBuf[byteCount] = crcData & 0xff; sendCount = byteCount + 1;beginSend();}//void readRegisters(void)//强制单个线圈void forceSingleCoil(void){uint8 addr;uint8 tempAddr;uint16 tempData;uint8 onOff;uint8 i;//addr = (receBuf[2]<<8) + receBuf[3];//tempAddr = addr & 0xfff;addr = receBuf[3];tempAddr = addr;//onOff = (receBuf[4]<<8) + receBuf[5]; onOff = receBuf[4];//if(onOff == 0xff00)if(onOff == 0xff){ //设为ONtempData = 1;}//else if(onOff == 0x0000)else if(onOff == 0x00){ //设为OFFtempData = 0;}setCoilVal(tempAddr,tempData);for(i=0;i<receCount;i++){sendBuf = receBuf;}sendCount = receCount;beginSend();}//void forceSingleCoil(void)//设置多个寄存器void presetMultipleRegisters(void) {uint8 addr;uint8 tempAddr;uint8 byteCount;uint8 setCount;uint16 crcData;uint16 tempData;uint8 finsh; //为1时完成为0时出错uint8 i;//addr = (receBuf[2]<<8) + receBuf[3];//tempAddr = addr & 0xfff;addr = receBuf[3];tempAddr = addr & 0xff;//setCount = (receBuf[4]<<8) + receBuf[5]; setCount = receBuf[5];byteCount = receBuf[6];for(i=0;i<setCount;i++,tempAddr++){tempData = (receBuf[i*2+7]<<8) + receBuf[i*2+8]; setRegisterVal(tempAddr,tempData);}sendBuf[0] = localAddr;sendBuf[1] = 16;sendBuf[2] = addr >> 8;sendBuf[3] = addr & 0xff;sendBuf[4] = setCount >> 8;sendBuf[5] = setCount & 0xff;crcData = crc16(sendBuf,6);sendBuf[6] = crcData >> 8;sendBuf[7] = crcData & 0xff;sendCount = 8;beginSend();}//void presetMultipleRegisters(void)//检查uart0数据void checkComm0Modbus(void){uint16 crcData;uint16 tempData;if(receCount > 4){switch(receBuf[1]){case 1://读取线圈状态(读取点 16位以内) case 3://读取保持寄存器(一个或多个)case 5://强制单个线圈case 6://设置单个寄存器if(receCount >= 8){//接收完成一组数据//应该关闭接收中断if(receBuf[0]==localAddr && checkoutError==0) {crcData = crc16(receBuf,6);if(crcData == receBuf[7]+(receBuf[6]<<8)){//校验正确if(receBuf[1] == 1){//读取线圈状态(读取点 16位以内)readCoil();}else if(receBuf[1] == 3){//读取保持寄存器(一个或多个)readRegisters();}else if(receBuf[1] == 5){//强制单个线圈forceSingleCoil();}else if(receBuf[1] == 6){//presetSingleRegister();}}}receCount = 0;checkoutError = 0;}break;case 15://设置多个线圈tempData = receBuf[6];tempData += 9; //数据个数if(receCount >= tempData){if(receBuf[0]==localAddr && checkoutError==0){crcData = crc16(receBuf,tempData-2);if(crcData == (receBuf[tempData-2]<<8)+ receBuf[tempData-1]){//forceMultipleCoils();}}receCount = 0;checkoutError = 0;}break;case 16://设置多个寄存器tempData = (receBuf[4]<<8) + receBuf[5];tempData = tempData * 2; //数据个数tempData += 9;if(receCount >= tempData){if(receBuf[0]==localAddr && checkoutError==0){crcData = crc16(receBuf,tempData-2);if(crcData == (receBuf[tempData-2]<<8)+ receBuf[tempData-1]){presetMultipleRegisters();}}receCount = 0;checkoutError = 0;}break;default:break;}}}//void checkComm0(void)//取线圈状态返回0表示成功uint16 getCoilVal(uint16 addr,uint16 *tempData) {uint16 result = 0;uint16 tempAddr;tempAddr = addr & 0xfff;//只取低8位地址switch(tempAddr & 0xff){case 0:break;case 1:*tempData = testCoil;break;case 2:break;case 3:break;case 4:case 5:break; case 6:break; case 7:break; case 8:break; case 9:break; case 10: break; case 11: break; case 12: break; case 13: break; case 14: break; case 15:case 16:break;default:break;}return result;}//uint16 getCoilVal(uint16 addr,uint16 *data) //设定线圈状态返回0表示成功uint16 setCoilVal(uint16 addr,uint16 tempData) {uint16 result = 0;uint16 tempAddr;tempAddr = addr & 0xfff;switch(tempAddr & 0xff){case 0:break;case 1:testCoil = tempData;break;case 2:case 3:break; case 4:break; case 5:break; case 6:break; case 7:break; case 8:break; case 9:break; case 10: break; case 11: break; case 12: break; case 13:break;case 14:break;case 15:break;case 16:break;default:break;}return result;}//uint16 setCoilVal(uint16 addr,uint16 data)//取寄存器值返回0表示成功uint16 getRegisterVal(uint16 addr,uint16 *tempData) {uint16 result = 0;uint16 tempAddr;tempAddr = addr & 0xfff;switch(tempAddr & 0xff){case 0:break;break; case 2: break; case 3:break; case 4:break; case 5:break; case 6:break; case 7:break; case 8:break; case 9:break; case 10: break; case 11: break;break;case 13:break;case 14:break;case 15:break;case 16:*tempData = testRegister;break;default:break;}return result;}//uint16 getRegisterVal(uint16 addr,uint16 &data) //设置寄存器值返回0表示成功uint16 setRegisterVal(uint16 addr,uint16 tempData) {uint16 result = 0;uint16 tempAddr;tempAddr = addr & 0xfff;switch(tempAddr & 0xff) {case 0:break;case 1:break;case 2:break;case 3:break;case 4:break;case 5:break;case 6:break;case 7:break;case 8:break;case 9:break;case 10:break;case 11:break;case 12:break;case 13:break;case 14:break;case 15:break;case 16:testRegister = tempData;break;default:break;}return result;}//uint8 setRegisterVal(uint16 addr,uint16 data)。

相关文档
最新文档