百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

STM32 MODBUS通讯源码 stm32 modbus 主机

yuyutoo 2024-12-19 17:33 9 浏览 0 评论

最近几年受口罩影响,工控产品的价格以是水涨船高。尤其是PLC,不管是高端还是低端的PLC,价格是早已翻了好几倍。价格高不说而且还缺货,所以很多公司为了降低成本,保证能够有充足的货源,都采取了用STM32自制电路板来替代。虽然STM32的价格也是翻了好几倍,但是这也只是单个芯片的价格而已,如果用产品去相比PLC仍然还是具有相当大的空间。其实如果没有复杂的总线控制的需求,只是简单的完成PLC的IO及通讯功能,实现起来还是挺简单的。IO我就不讲了,因为那确实太简单。下面分享给大家的是MODBUS-RTU的通讯源码,希望能给搞工控的朋友一些帮助。

【下面是MODBUS-RTU调度程序】

void ModbusRTU(u8 com,u8 *data, u16 len)

{

if(data[0]==1&&IF_ModbusCRC16(com,data,len )==1)

{

switch(data[1])//根据不同的功能码进行处理

{

case 01:{CMD01(com,data,len);break;}//读输出开关量

case 02:{CMD02(com,data,len);break;}//读输入开关量

case 03:{CMD03(com,data,len);break;}//读多个寄存器

case 05:{CMD05(com,data,len);break;}//写单个输出开关量

case 06:{CMD06(com,data,len);break;}//写单个寄存器

case 15:{CMD0F(com,data,len);break;}//写多个输出开关量

case 16:{CMD10(com,data,len);break;}//写多个寄存器

}

}

}

u8 M[1000];

u8 X[1000];

u8 Y[1000];

u16 D[1000];

u8 IS8BIT =0;

u16 OUTIM_A=0;

u16 OUTIM_B=0;

void SEND_DAT(u8 com,u8 *data, u16 len)//将数据从指定的串口发送出去

{

if(com==2){USART2_SendTxt(data,len);}

if(com==3){USART3_SendTxt(data,len);}

if(com==4){USART4_SendTxt(data,len);}

if(com==5){USART5_SendTxt(data,len);}

}

【下面是MODBUS-RTU从站模式】

void CMD01(u8 com,u8 *data, u16 len)

{

u8 U8BIT=0;

u8 U8BYTE=0;

u8 RDT[200];

int i=0;

int LEN=data[4];

int STARTADDR=data[2];

LEN=(LEN<<8) + data[5];

STARTADDR=(STARTADDR<<8)+data[3];

RDT[0]=data[0];

RDT[1]=data[1];

RDT[2]=LEN/8;

if(LEN%8){RDT[2]=RDT[2]+1;}

for(i=0;i<LEN;i++)

{

U8BIT=i%8;

if(M[STARTADDR+i])

{

U8BYTE=1;

RDT[3+i/8]=RDT[3+i/8]|(U8BYTE<<U8BIT);

}

else

{

U8BYTE=254;

RDT[3+i/8]=RDT[3+i/8]&(U8BYTE<<U8BIT);

}

}


ModbusCRC16(com,RDT,RDT[2]+3 );

RDT[4+LEN]=COMCRC16[com][0];

RDT[5+LEN]=COMCRC16[com][1];

SEND_DAT(com,RDT,LEN+5);

}

void CMD02(u8 com,u8 *data, u16 len)

{


}

void CMD03(u8 com,u8 *data, u16 len)

{


u8 RDT[200];

int i=0;

int LEN=data[5]*2;

int STARTADDR=data[2];

STARTADDR=(STARTADDR<<8)+data[3];

RDT[0]=data[0];

RDT[1]=data[1];

RDT[2]=LEN;

for(i=0;i<LEN;i++)

{

if(IS8BIT==0){if((i%2)==0){RDT[3+i]=D[STARTADDR+i/2]>>8;}else{RDT[3+i]=D[STARTADDR+i/2];}}

else{RDT[3+i]=D[STARTADDR+i];}

}

ModbusCRC16(com,RDT,LEN+3 );

RDT[3+LEN]=COMCRC16[com][0];

RDT[4+LEN]=COMCRC16[com][1];

SEND_DAT(com,RDT,LEN+5);

}

void CMD05(u8 com,u8 *data, u16 len)

{

u8 RDT[200];

int i=0;

int STARTADDR=data[2];

STARTADDR=(STARTADDR<<8)+data[3];

RDT[0]=data[0];

RDT[1]=data[1];

RDT[2]=data[2];

RDT[3]=data[3];

RDT[4]=data[4];

RDT[5]=data[5];

RDT[6]=data[6];

RDT[7]=data[7];

M[STARTADDR+0]=data[5]?1:0;

SEND_DAT(com,RDT,8);

}

void CMD06(u8 com,u8 *data, u16 len)

{

u8 RDT[200];

int i=0;

int STARTADDR=data[2];

STARTADDR=(STARTADDR<<8)+data[3];

RDT[0]=data[0];

RDT[1]=data[1];

RDT[2]=data[2];

RDT[3]=data[3];

RDT[4]=data[4];

RDT[5]=data[5];

RDT[6]=data[6];

RDT[7]=data[7];

if(IS8BIT==0)

{

D[STARTADDR]=data[4];

D[STARTADDR]=(D[STARTADDR]<<8)+data[5];

}

else

{

D[STARTADDR+0]=data[4];

D[STARTADDR+1]=data[5];

}

SEND_DAT(com,RDT,8);

}

void CMD0F(u8 com,u8 *data, u16 len)

{

u8 U8BIT=0;

u8 U8BYTE=0;

u8 RDT[200];

int i=0;

int LEN=data[4];

int STARTADDR=data[2];

LEN=(LEN<<8)+data[5];

STARTADDR=(STARTADDR<<8)+data[3];

RDT[0]=data[0];

RDT[1]=data[1];

RDT[2]=data[2];

RDT[3]=data[3];

RDT[4]=data[4];

RDT[5]=data[5];

for(i=0;i<LEN;i++)

{

U8BIT=i%8;

U8BYTE=1<<U8BIT;

M[STARTADDR+i]=(data[7+i/8]&U8BYTE)?1:0;

}

ModbusCRC16(com,RDT,6);

RDT[6]=COMCRC16[com][0];

RDT[7]=COMCRC16[com][1];

SEND_DAT(com,RDT,8);

}

void CMD10(u8 com,u8 *data, u16 len)//写多个寄存器

{

u8 RDT[200];

int i=0;

int LEN=data[6];

int STARTADDR=data[2];

STARTADDR=(STARTADDR<<8)+data[3];

RDT[0]=data[0];

RDT[1]=data[1];

RDT[2]=data[2];

RDT[3]=data[3];

RDT[4]=data[4];

RDT[5]=data[5];

for(i=0;i<LEN;i++)

{

if(IS8BIT==0)

{

if((i%2)==0){D[STARTADDR+i/2]=data[7+i];D[STARTADDR+i/2]=D[STARTADDR+i/2]<<8;}else{D[STARTADDR+i/2]+=data[7+i];}

}

else

{

D[STARTADDR+i]=data[7+i];

}

}

ModbusCRC16(com,RDT,6);

RDT[6]=COMCRC16[com][0];

RDT[7]=COMCRC16[com][1];

SEND_DAT(com,RDT,8);

}


【下面是CRC效验程序】

#include "MODBUS_CRC16.h"

u8 COM2CRC16[2];

u8 COM3CRC16[2];

u16 IX, IY;

//CRC校验查表用参数 /* CRC 高位字节值表*/

static u8 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低位字节值表*/

static u8 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 ModbusCRC16(int com,u8 *data, u16 len)

{


u8 L=(u8)len;

u8 uchCRCHi=0xFF; /*高CRC字节初始化*/

u8 uchCRCLo=0xFF; /*低CRC字节初始化*/

u8 uIndex; /*CRC循环中的索引*/

while(L--) /* 传输消息缓冲区*/

{

uIndex = uchCRCHi ^ *data++; /* 计算CRC */

uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];

uchCRCLo = auchCRCLo[uIndex];

}

if(com==2)

{

COM2CRC16[0] =uchCRCHi;//高位置

COM2CRC16[1] =uchCRCLo; //低位置

}

else

{

COM3CRC16[0] =uchCRCHi;//高位置

COM3CRC16[1] =uchCRCLo; //低位置

}

}

u8 IF_ModbusCRC16(int com,u8 *data, u16 len )

{

u8 CRC16[2];

if(len>4)

{

ModbusCRC16(com,data,len-2);

if(com==2)

{

CRC16[0]=COM2CRC16[0];//高位置

CRC16[1]=COM2CRC16[1];//低位置

}

else

{

CRC16[0]=COM3CRC16[0];//高位置

CRC16[1]=COM3CRC16[1];//低位置

}

if(data[len-2]==CRC16[0]&&data[len-1]==CRC16[1])return 1;else return 0;

}

else{return 0;}

}

相关推荐

电脑 CMD 命令大全:简单粗暴收藏版

电脑CMD命令大全包括了许多常用的命令,这些命令可以帮助用户进行各种系统管理和操作任务。以下是一些常用的CMD命令及其功能:1、系统信息和管理...

电脑维修高手必备!8个神奇DOS命令,自己动手不求人

我相信搞电脑维修或者维护的基本都会些DOS的命令。就算Windows操作系统是可视化的界面,但很多维护检查是离不开DOS命令的。掌握好这些命令,你不仅能快速诊断问题,还能解决90%的常见电脑故障。下...

一个互联网产品总监的设计技巧总结 - 技术篇

古语:工欲善其事必先利其器。往往在利其器后我们才能事半功倍。从这个角度出发成为一个合格的产品经理你需要的是“利其器”,这样你才能产品的设计过程中如鱼得水,得心应手。有些产品经理刚入职,什么都感觉自己欠...

超详解析Flutter渲染引擎|业务想创新,不了解底层原理怎么行?

作者|万红波(远湖)出品|阿里巴巴新零售淘系技术部前言Flutter作为一个跨平台的应用框架,诞生之后,就被高度关注。它通过自绘UI,解决了之前RN和weex方案难以解决的多端一致性...

瑞芯微RK3568|SDK开发之环境安装及编译操作

1.SDK简介一个通用LinuxSDK工程目录包含有buildroot、app、kernel、device、docs、external等目录。其中一些特性芯片如RK3308/RV1108/R...

且看L-MEM ECC如何守护i.MXRT1170从核CM4

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是恩智浦i.MXRT1170上Cortex-M4内核的L-MEMECC功能。本篇是《简析i.MXRT1170Cortex-M7F...

ECC给i.MXRT1170 FlexRAM带来了哪些变化?

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是恩智浦i.MXRT1170上Cortex-M7内核的FlexRAMECC功能。ECC是“ErrorCorrectingCode”...

PHP防火墙代码,防火墙,网站防火墙,WAF防火墙,PHP防火墙大全

PHP防火墙代码,防火墙,网站防火墙,WAF防火墙,PHP防火墙大全资源宝整理分享:https://www.htple.net...

从零开始移植最新版本(2023.10)主线Uboot到Orange Pi 3(全志H6)

本文将从零开始通过一步一步操作来实现将主线U-Boot最新代码移植到OrangePi3(全志H6)开发板上并正常运行起来。本文从通用移植思路的角度,展现是思考的过程,通过这种方式希望能让读者一通百...

可视化编程工具Blockly——定制工具箱

1概述本文重点讲解如何定制Blocklytoolbox上,主要包含如下几点目标:如何为toolbox不同类别添加背景色如何改变选中的类别的外观如何为toolbox类别添加定制化的css如何改变类别...

用户界面干货盘点(用户界面的基本操作方法)

DevExpressDevExpressWPF的DXSplashScreen控件在应用加载的时候显示一个启动界面。添加DXSplashScreen后,会默认生成一个XAML文件,当然,你也可...

Vue3+Bootstrap5整合:企业级后台管理系统实战

简洁而不简单,优雅而不失强大在当今快速发展的企业数字化进程中,高效、美观的后台管理系统已成为企业运营的核心支撑。作为前端开发者,我们如何选择技术栈,才能既保证开发效率,又能打造出专业级的用户体验?答案...

什么?这三款i.MXRT型号也开放了IAP API?

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是i.MXRT1050/1020/1015系列ROM中的FlexSPI驱动API使用。今天痞子衡去4S店给爱车做保养了,...

OneCode基础组件介绍——表格组件(Grid)

在企业级应用开发中,表格组件是数据展示与交互的核心载体。OneCode平台自研的Grid表格组件,以模型驱动设计...

开源无线LoRa传感器(光照温湿度甲醛Tvoc)

本开源项目基于ShineBlinkC2M低代码单片机实现,无需复杂单片机C语言开发。即使新手也可很容易用FlexLua零门槛开发各种功能丰富稳定可靠的IoT硬件,更多学习教程可参考Flex...

取消回复欢迎 发表评论: