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

STM32 MODBUS通讯源码 stm32 modbus 主机

yuyutoo 2024-12-19 17:33 3 浏览 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;}

}

相关推荐

史上最全的浏览器兼容性问题和解决方案

微信ID:WEB_wysj(点击关注)◎◎◎◎◎◎◎◎◎一┳═┻︻▄(页底留言开放,欢迎来吐槽)●●●...

平面设计基础知识_平面设计基础知识实验收获与总结
平面设计基础知识_平面设计基础知识实验收获与总结

CSS构造颜色,背景与图像1.使用span更好的控制文本中局部区域的文本:文本;2.使用display属性提供区块转变:display:inline(是内联的...

2025-02-21 16:01 yuyutoo

写作排版简单三步就行-工具篇_作文排版模板

和我们工作中日常word排版内部交流不同,这篇教程介绍的写作排版主要是用于“微信公众号、头条号”网络展示。写作展现的是我的思考,排版是让写作在网格上更好地展现。在写作上花费时间是有累积复利优势的,在排...

写一个2048的游戏_2048小游戏功能实现

1.创建HTML文件1.打开一个文本编辑器,例如Notepad++、SublimeText、VisualStudioCode等。2.将以下HTML代码复制并粘贴到文本编辑器中:html...

今天你穿“短袖”了吗?青岛最高23℃!接下来几天气温更刺激……

  最近的天气暖和得让很多小伙伴们喊“热”!!!  昨天的气温到底升得有多高呢?你家有没有榜上有名?...

CSS不规则卡片,纯CSS制作优惠券样式,CSS实现锯齿样式

之前也有写过CSS优惠券样式《CSS3径向渐变实现优惠券波浪造型》,这次再来温习一遍,并且将更为详细的讲解,从布局到具体样式说明,最后定义CSS变量,自定义主题颜色。布局...

柠檬科技肖勃飞:大数据风控助力信用社会建设

...

你的自我界限够强大吗?_你的自我界限够强大吗英文

我的结果:A、该设立新的界限...

行内元素与块级元素,以及区别_行内元素和块级元素有什么区别?

行内元素与块级元素首先,CSS规范规定,每个元素都有display属性,确定该元素的类型,每个元素都有默认的display值,分别为块级(block)、行内(inline)。块级元素:(以下列举比较常...

让“成都速度”跑得潇潇洒洒,地上地下共享轨交繁华
让“成都速度”跑得潇潇洒洒,地上地下共享轨交繁华

去年的两会期间,习近平总书记在参加人大会议四川代表团审议时,对治蜀兴川提出了明确要求,指明了前行方向,并带来了“祝四川人民的生活越来越安逸”的美好祝福。又是一年...

2025-02-21 16:00 yuyutoo

今年国家综合性消防救援队伍计划招录消防员15000名

记者24日从应急管理部获悉,国家综合性消防救援队伍2023年消防员招录工作已正式启动。今年共计划招录消防员15000名,其中高校应届毕业生5000名、退役士兵5000名、社会青年5000名。本次招录的...

一起盘点最新 Chrome v133 的5大主流特性 ?

1.CSS的高级attr()方法CSSattr()函数是CSSLevel5中用于检索DOM元素的属性值并将其用于CSS属性值,类似于var()函数替换自定义属性值的方式。...

竞走团体世锦赛5月太仓举行 世界冠军杨家玉担任形象大使

style="text-align:center;"data-mce-style="text-align:...

学物理能做什么?_学物理能做什么 卢昌海

作者:曹则贤中国科学院物理研究所原标题:《物理学:ASourceofPowerforMan》在2006年中央电视台《对话》栏目的某期节目中,主持人问过我一个的问题:“学物理的人,如果日后不...

你不知道的关于这只眯眼兔的6个小秘密
你不知道的关于这只眯眼兔的6个小秘密

在你们忙着给熊本君做表情包的时候,要知道,最先在网络上引起轰动的可是这只脸上只有两条缝的兔子——兔斯基。今年,它更是迎来了自己的10岁生日。①关于德艺双馨“老艺...

2025-02-21 16:00 yuyutoo

取消回复欢迎 发表评论: