ModBus--RTU学习心得(含MB从机stm32工程)


ModBus入门学习篇(含MB-RTU从机stm32工程)


Modbus是一种比较常用的工业通讯协议(协议也可以称为约定),它对传输介质的要求并不高,基本上可用实现通讯链接就可以(rs232、rs485、网线等电器通讯均可),这可能也是它比较常用的原因之一,重要的是这个协议它是免费的而且也是一个普遍认可的协议,所有学习一下还是有必要的。
学习modbus(以下简称MB)之前需要搞清楚一个概念“协议”,协议到底是什么呢?
说到协议一般来说大家应该都听说过TCP/IP这个网络协议,tcp/ip是一个大型网络协议相对来说是比较复杂的,但是并不代表协议就是一个复杂的东西。
协议其实就是一种约定。
例如:甲方跟乙方约定好,当乙方接到甲方的信息aa时,乙方给甲方寄出一个东西并回复一个信息bb,这就是协议的模型,协议就是双方都能按照规定来进行交流和执行。
下面以单片机通讯做一简单的协议
协议:1、规定数据格式: 帧头-0x3e 地址 指令 数据 帧尾-0x3f,这个是通讯双方的通讯数据包格式。
2、规定功能指令:A–控制电机正转 B–控制电机反转 C–电机停止转动。
当单片机接收到数据:0x3e 0x01 A 03 0x3f 根据以上规定的协议,接收到这帧数据之后单片机将会执行正转3圈的动作,这就是一个简单的协议。

对协议有一个初步的理解之后,再看看modbus协议。
一、Modbus简介
Modbus 协议是应用于电子控制器上的一种通用语言。通过此协议,控制器相互之间、控制器经由网络(例如以太网)和其它设备之间可以通信。它已经成为一通用工业标准。有了它,不同厂商生产的控制设备可以连成工业网络,进行集中监控。

此协议定义了一个控制器能认识使用的消息结构,而不管它们是经过何种网络进行通信的。它描述了一控制器请求访问其它设备的过程,如果回应来自其它设备的请求,以及怎样侦测错误并记录。它制定了消息域格局和内容的公共格式。

当在一Modbus网络上通信时,此协议决定了每个控制器须要知道它们的设备地址,识别按地址发来的消息,决定要产生何种行动。如果需要回应,控制器将生成反馈信息并用Modbus协议发出。在其它网络上,包含了Modbus协议的消息转换为在此网络上使用的帧或包结构。这种转换也扩展了根据具体的网络解决节地址、路由路径及错误检测的方法。
 
ModBus是一种主从问询式的通讯方式,由主机(或者client)发起询问从机接收到问询之后响应主机服务。
在这里插入图片描述
二、传输方式与数据帧格式
MB有两种传输模式:ASCII或RTU
ASCII消息帧格式
使用ASCII模式,消息以冒号(:)字符(ASCII码 3AH)开始,以回车换行符结束(ASCII码 0DH,0AH)。
在这里插入图片描述
在这里插入图片描述RTU消息帧格式
在这里插入图片描述在这里插入图片描述
这两个传输模式的区别:
1、数据帧的格式不同,ASCII模式下有帧头、帧尾而RTU模式下是没有帧头和帧尾的,RTU模式下数据帧的第一个数据就是地址。
2、数据校验的方式不一样,ASCII模式使用的是LRC校验 ,RTU使用的是crc校验
3、数据的表示方式不同,ASCII使用一个ASCII字符表示一位十六进制数,RTU模式下是用4bit二进制表示一位16进制数,因此RTU模式的数据帧长度是要小于ASCII模式的,所有RTU模式的传输速率大于ASCII模式。

以上是关于modbus协议的一个简介,详细介绍网上很多这里就不多讲了,具体内容了解可以看Modbus协议中文版(GB),和Modbus协议详解这个博客。


STM32-modbus rtu 从机程序


modbu功能处理c文件

#include "modbus.h"
#include "usart.h"
#include "modbus_timer.h"
#include "modbus_crc.h"

MODBUS modbus;


u16 DataReg[30] ={
   0}; //¶¨Òå30¸ö16λµÄ¼Ä´æÆ÷
u8 OX[20];			//¶¨ÒåÊä³öÏßȦ±äÁ¿


void modbus_err_response(u8 cmd, u8 err)
{
   
	u16 crc;
	u8 i=0;
	modbus.tx_buf[i++] = modbus.local_addr;//±¾»úµØÖ·
	modbus.tx_buf[i++] = cmd|0x80;        //·µ»Ø¹¦ÄÜÂë=¹¦ÄÜÂë+0x80
	modbus.tx_buf[i++] = err;
	crc = Modbus_CRC16(modbus.tx_buf,i);    //¼ÆËãCRC
	modbus.tx_buf[i++] = crc/256;
	modbus.tx_buf[i++] = crc%256;
	Modbus_Uart_Send(modbus.tx_buf,i);
}



// Modbus³õʼ»¯º¯Êý
void Modbus_Init(void)
{
   
	u8 i;
	modbus.local_addr = 0x01; //É豸µØַΪ0x01
	modbus.rx_flag = 0;
	Modbus_Uart_Init(9600);
	Modbus_TIM_Init();
	for(i=0;i<30;i++) DataReg[i]=i;
	for(i=0;i<20;i++) OX[i]=i;
}


//Modbus 1ºÅ¹¦ÄÜÂ뺯Êý£¬¶ÁÏßȦ״̬
void Modbus_Fun1(void)
{
   
	u16 ox_addr,ox_cnt,crc;
	u8 i,j;
	
	ox_addr = modbus.rx_buf[2]*256+modbus.rx_buf[3];
	ox_cnt =  modbus.rx_buf[4]*256+modbus.rx_buf[5];
	
	if(ox_cnt<1 || ox_cnt>0x7d0)		//ÅжÏÏßȦ¸öÊýÊÇ·ñÔڹ涨ÇøÓòÄÚ£¬Èç¹û²»ÔÚ·¶Î§ÄÚÔò·µ»ØÒì³£3
	{
   
		modbus_err_response(modbus.rx_buf[1],ERROR_2);
		return;
	}
	
	if( ox_addr>1600)
	{
   
		modbus_err_response(modbus.rx_buf[1],ERROR_3);
		return;
	}
	
	i=0;
	modbus.tx_buf[i++] = modbus.local_addr;      //·¢Ëͱ¾»úµØÖ·
	modbus.tx_buf[i++] = 0x01;              //¹¦ÄÜÂë
	
	if(ox_cnt%8 != 0)  //Åж϶ÁÈ¡ÏßȦ¸öÊýÊÇ·ñÊÇ8µÄÕûÊý±¶£¬Èç¹û²»ÊÇ8µÄÕûÊý±¶Ôò·µ»Øox_cnt/8+1¸ö×Ö½ÚÊý¾Ý
	{
   
		modbus.tx_buf[i++] = (u8)(ox_cnt/8)+1;  //·µ»Øox_cnt/8+1×Ö½ÚÊý¾Ý
		if(ox_addr%8)          //ÅжϵØÖ·ÊÇ·ñÊÇ8µÄÕûÊý±¶£¬Ò»¸öu8µÄ±äÁ¿´æ´¢8¸öÏßȦµÄ¿ª¹ØÖµ£¬Èç¹û²»ÊÇÕûÊý±¶ÔòÐèÒªÒÆλÀ´½øÐÐλѰַ
		{
   
			for(j=0;j<ox_cnt/8;j++)
			{
   
				modbus.tx_buf[i++]=(OX[ox_addr/8+j]>>(ox_addr%8))|(OX[ox_addr/8+j+1]<<(8-ox_addr%8));   //¶ÁÈ¡ÏßȦ¿ª¹ØÖµ
			}
			modbus.tx_buf[i++]=((OX[ox_addr/8+j]>>(ox_addr%8))|(OX[ox_addr/8+j+1]<<(8-ox_addr%8)))&(0xff>>(8-ox_cnt%8));
		}
		else     //ÈôÊÇÕûÊý±¶Ôò°´×Ö½ÚÑ°Ö·¼È¿É£¬´ÓOX[20]ÖжÁÈ¡Õû¸ö±äÁ¿·µ»Ø¼´¿É
		{
   
			for(j=0;j<(ox_cnt/8);j++)
			{
   
				modbus.tx_buf[i++]=OX[ox_addr/8+j];
			}
			modbus.tx_buf[i++] = OX[ox_addr/8+j] & (0xff>>(8-ox_cnt%8));
		}
	}
	else          //¶ÁÈ¡¸öÊýÕýºÃÊÇ8µÄÕûÊý±¶Ôò·µ»Øox_cnt/8¸ö×Ö½ÚµÄÊý¾Ý
	{
   
		modbus.tx_buf[i++] = ox_cnt/8;
		if(ox_addr%8 != 0)
		{
   
			for(j=0;j<ox_cnt/8;j++)
			{
   
				modbus.tx_buf[i++]=(OX[ox_addr/8+j]>>(ox_addr%8))|(OX[ox_addr/8+j+1]<<(8-ox_addr%8));
			}
		}
		else
		{
   
			for(j=0;j<(ox_cnt/8);j
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值