【STM32】RS485 Modbus协议 采集传感器数据

2023-05-16

源码链接:Modbus传感器采集协议

一、硬件

1、传感器:为液压传感器,12vDC,RS485数据输出,采用Modbus协议通信
2、电路:根据传感器属性,电路主要是两部分,通信电路和电源电源
(1)485电路:由于485是半双工通信,需要控制收发,所以索性在把电路设计成自动收发电路在这里插入图片描述
接跳线帽W1、W2即使用RS485收发,不接就是普通串口收发。RE和DE是收发使能,选择485模式:3_TXD常高,使能接受;当发送数据时,数据的起始位(下降沿)将3_TXD引脚电平拉低,将顺便使能发送。传感器接3_A、3_B。

(2)开关电路:主要是为了控制传感器开关,以降低功耗
在这里插入图片描述

二、测试485电路

1、485电路测试程序
对于单片机来说,其实仍然是串口通信,只不过经过485芯片实现了RS232电平→RS485电平。
(1)初始化串口3,并在初始化时开启串口接收中断

void MX_USART3_UART_Init(void)
{

  huart3.Instance = USART3;
  huart3.Init.BaudRate = 9600;
  huart3.Init.WordLength = UART_WORDLENGTH_8B;
  huart3.Init.StopBits = UART_STOPBITS_1;
  huart3.Init.Parity = UART_PARITY_NONE;
  huart3.Init.Mode = UART_MODE_TX_RX;
  huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart3.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart3) != HAL_OK)
  {
    Error_Handler();
  }
  Usart3RecIT();//开启串口3接收中断
  start_capture();//发送请求帧
}

(2)接收中断回调函数中保存串口数据

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{

	if(huart->Instance == USART3){//RS485设备
		HAL_UART_Receive_IT(&huart3, &uart3Data, 1);
        uart3WriteByte(uart3Data);//接收到的数据写入缓存
		uart3DataFlg = 1;
	}	
}

(3)缓存数据:环形队列,不啰嗦

#define SENSOR_485_DATA_BUFFER_MAX_LENGTH  60
typedef struct {
	uint16_t   front;
	uint16_t   rear;
	uint8_t*   buffer;
	uint32_t   maxSize;
}Buffer_t;
static Buffer_t sensor485Buffer;
uint8_t  sensor485DataBuffer[SENSOR_485_DATA_BUFFER_MAX_LENGTH];//缓存数组

void uart3WriteByte(uint8_t data)
{
	Buffer_Puts(&sensor485Buffer,&data,1);//入队
}

bool Buffer_Puts(Buffer_t* buffer, uint8_t* data, uint16_t length)
{
	if (buffer->maxSize - Buffer_Size(buffer) <= length)//队满
		return false;
	for (uint16_t i = 0; i<length; ++i)//队列未满
	{
		buffer->rear = (buffer->rear + 1) % buffer->maxSize;
		buffer->buffer[buffer->rear] = data[i];//进队
	}
	return true;
}

(4)这个接口,是为了向传感器发送指令,请求传感器数据,指令需要查看传感器指令定义,属于协议那部分,先测试

void start_capture()uint8_t TxData[10]= "1111111111";
	HAL_UART_Transmit(&huart3,TxData,10,0xffff);
    HAL_Delay(100);

2、在Keil中Debug,用串口助手向单片机发送数据,查看数组sensor485DataBuffer接收到了,接收是可以了
在这里插入图片描述

3、但是我遇到了问题,上位机没有接受到2-(4)发送的“1111111111”,单片机发送出现了问题

(1)分别检查TX、R15、R16都有信号出来
在这里插入图片描述
(2)第一反应是485芯片发送使能没有成功,检查RE和DE引脚,果然一直是低电平,说明三极管一直导通,没有阻塞过
在这里插入图片描述
(3)无奈之下,干脆用反相器替换了三极管
在这里插入图片描述
(4)然后,就可以了…

三、加入Modbus协议

1、协议原理
(1)以上测试说明:链路层硬件协议√;
(2)但是问题来了,只有硬件协议可以和传感器通信吗? 当然不行,传感器又不是电脑,它没有上位机:你点一下发送就把数据发出去了。这个时候需要单片机来告知它发送。所以我们还需要:链路层软件协议Modbus协议√;
(3)我们选取Modbus协议中对我们编程有帮助的几点:

  • 以帧的形式通信,有ASCII和RTU两种模式,帧中的地址、功能码等都是一个或多个字节,每个字节是一个8位串口数据
    在这里插入图片描述

  • 如果一个串口连接多个4856设备,可以通过地址区分不同485设备,当然串口资源充足也可以挂载在多个串口上

  • RTU模式通过两帧数据的时间间隔,区分前后两帧数据,如果串口数据间隔大于3.5个字节,那么就认为一帧数据结束了,在9600bps/s波特率下,传输3.5个字节时间大概为4ms;ASCII模式读回车换行就行了

  • 如果要读取传感器状态、数据,都需要发送请求帧

  • 数据需要CRC校验

  • 具体指令规则需查看传感器指令文档

2、 根据传感器指令文档编程
在这里插入图片描述
(1)打开传感器开关

void open_sensor(){
	//控制电源开关的引脚拉高
}

(2)发送读取命令

void start_read(){
    uint8_t TxData[10]= "010300000001840A";
	HAL_UART_Transmit(&huart3,TxData,10,0xffff);
    HAL_Delay(100); 
}

(3)读取数据

  • 在串口接收中断中接收数据,如果下一个串口数据在4ms之内到来,那么重新计时,定时器中断不会生效;如果没来,则认为接收完一帧数据,程序会进入定时器中断,这个很关键
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
		if(huart->Instance == USART3){
			  HAL_TIM_Base_Stop_IT(&htim5);
			  HAL_UART_Receive_IT(&huart3, &uart3Data, 1);
              uart3WriteByte(uart3Data);
              HAL_TIM_Base_Start_IT(&htim5);//开始计时4ms,即modbus设备在9600波特率下传输一帧数据的时间间隔
			  uart3DataFlg = 1;
		}
}
  • 在定时器中断中进行处理数据
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if(htim==(&htim5))
  {
		//TIM_ClearITPendingBit(TIM5,TIM_IT_Update);  //标准库需要清除TIMx更新中断标志,HAL库不需要,直接写业务逻辑就行
		 HAL_TIM_Base_Stop_IT(&htim5);
		 Modbus_Work();//数据处理函数
		 Uart3BufClear();
		 RS485_RX_CNT++;
  }
}

(4)数据CRC校验

  • CRC原理就不啰嗦了
  • 不同种类的CRC校验的多项式并不统一,这里是0xA001,文档中会说明

int16_t CRC_16( int8_t *vptr, int8_t len)
{
    uint16_t MODBUSCRC = 0xffff;
    uint16_t POLYNOMIAL = 0xa001;
    uint8_t i, j;

    for (i = 0; i < len; i++)
    {
        MODBUSCRC ^= vptr[i] ;
        for (j = 0; j < 8; j++)
        {
            if ((MODBUSCRC & 0x0001) != 0)
            {
                MODBUSCRC >>= 1;
                MODBUSCRC ^= POLYNOMIAL;
            }
            else
            {
                MODBUSCRC >>= 1;
            }
        }
    }
    return MODBUSCRC;
}

(5)数据解析

int Modbus_Work(void)
{
	double depth;
	uint16_t  depth_high;
	uint16_t  depth_low;
	int len = strlen((char*)(sensor485DataBuffer+1));
	if(sensor485DataBuffer[1] == 0x01)//从机地址正确则进行换算
	{
		if((CRC_16((int8_t *)(sensor485DataBuffer+1),len))==0x0000){//CRC校验
			depth_high = sensor485DataBuffer[3];
			depth_low = sensor485DataBuffer[4];
			depth = (double)((depth_high << 8) + depth_low)/1000;
		}
	}memset(sensor485DataBuffer,0,len+1);
	return depth;//这就是水深值了
}

四、注意事项
1、RS485通信,一定要A接A,B接B,不是反接
2、采集线过长,要考虑使用屏蔽线

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【STM32】RS485 Modbus协议 采集传感器数据 的相关文章

  • rt-thread studio中新建5.02版本报错

    先吐槽一下 rt thread studio出现BUG真多 好多时间都是在找BUG 但里面用好多控件还是挺好用的 真是又爱又恨 所以一般使用功能不多的话还是用keil多一点 创建5 02版本工程之后直接进行编译 直接会报下面这个错误 资源
  • Push_back() 导致程序在进入 main() 之前停止

    我正在为我的 STM32F3 Discovery 板使用 C 进行开发 并使用 std deque 作为队列 在尝试调试我的代码 直接在带有 ST link 的设备上或在模拟器中 后 代码最终在 main 中输入我的代码之前在断点处停止 然
  • SHT10温湿度传感器——STM32驱动

    实验效果 硬件外观 接线 3 3V供电 IIC通讯 代码获取 查看下方 END
  • [MM32硬件]搭建灵动微MM32G0001A6T的简易开发环境

    作为学习单片机的经典 自然是通过GPIO点亮LED 或者是响应按钮的外部中断例程 这我们看看SOP8封装的芯片MM32G0001A6T得引脚 除了VDD和GND固定外 我们可以使用PA14 PA1 PA13 PA15 PA2 PA3这六个G
  • VS Code 有没有办法导入 Makefile 项目?

    正如标题所说 我可以从现有的 Makefile 自动填充 c cpp properties json 吗 Edit 对于其他尝试导入 makefile 的人 我找到了一组脚本 它们完全可以实现我想要实现的目标 即通过 VS Code 管理
  • STM32 暂停调试器时冻结外设

    当到达断点或用户暂停代码执行时 调试器可以停止 Cortex 中代码的执行 但是 当皮质停止在暂停状态下执行代码时 调试器是否会冻结其他外设 例如 DMA UART 和定时器 您只能保留时间 r 取决于外围设备 我在进入主函数时调用以下代码
  • STM32F4XX的12位ADC采集数值超过4096&右对齐模式设置失败

    文章目录 一 前言 二 问题1 数值超过4096 三 问题1的排错过程 四 问题2 右对齐模式设置失败 五 问题2的解决方法 5 1 将ADC ExternalTrigConv设置为0 5 2 使用ADC StructInit 函数 一 前
  • systick定时器

    systick定时器 文章目录 前言 一 前期疑惑 二 解答 1 关于systick是阻塞的吗 2 非阻塞 三 软件编写 总结 前言 这边记录systick相关知识点 一 前期疑惑 在学习systick志气啊 其实对于systick还是一脸
  • STM32 Nucleo 上的上升沿中断多次触发

    我正在使用 STM32 NUCLEO F401RE 微控制器板 我有一个扬声器 经过编程 当向上 向下推操纵杆时 可以按设定的量改变频率 我的问题是 有时 通常 当向上 向下推动操纵杆时 频率会增加 减少多次 这意味着 ISR 正在执行多次
  • 将两个原始值转换为 32 位 IEEE 浮点数

    我正在尝试通过 TCP modbus 解码来自 Shark 100 功率计的一些数据 我已经成功地拉下了我需要的寄存器 并从寄存器中留下了两个原始值 如下所示 17138 59381 从手册中 我知道我需要将这两个数字转换为32位IEEE浮
  • 我可以在输入寄存器中写入吗? MODBUS

    我已经在一家公司工作了两个月MODBUS项目现在我发现了一个问题 我的客户要求我写入输入寄存器 地址 30001 到 40000 我认为这对我来说不是什么问题 因为每个modbus文档说 30001 到 40000 寄存器是只读的 甚至可以
  • STM32 上的 ADC 单次转换

    我正在研究 STM32 F103x 上的 ADC 编程 并从最简单的情况 单次转换开始 测量内部温度传感器 连接到 ADC1 的值 并使用 USART 将其发送到 COM 端口 目标似乎很明确 但是当我尝试将源代码下载到闪存时 它不会向 C
  • Modbus 错误:[无效消息] 收到的消息不完整,预计至少 2 个字节(收到 0 个字节)

    Problem pymodbus 主站 客户端可以向从站 服务器发送请求 从属 服务器准备好返回的东西 并等待主控 客户端来接收它们 尽管服务器 从站已准备就绪 但主站 客户端仅返回错误 Modbus 错误 输入 输出 Modbus 错误
  • 使用 STM32 USB 设备库将闪存作为大容量存储设备

    我的板上有这个闪存IC 它连接到我的STM32F04 ARM处理器 处理器的USB端口可供用户使用 我希望我的闪存在通过 USB 连接到 PC 时被检测为存储设备 作为第一步 我在程序中将 USB 类定义为 MSC 效果很好 因为当我将主板
  • 使用 STM32F0 ADC 单独读取不同的输入

    STM32F072CBU 微控制器 我有多个 ADC 输入 并且希望单独读取它们 STMcubeMX 生成样板代码 假设我希望按顺序读取所有输入 但我无法弄清楚如何纠正这个问题 这篇博文 http blog koepi info 2015
  • 哪些变量类型/大小在 STM32 微控制器上是原子的?

    以下是 STM32 微控制器上的数据类型 http www keil com support man docs armcc armcc chr1359125009502 htm http www keil com support man d
  • STM32 传输结束时,循环 DMA 外设到存储器的行为如何?

    我想问一下 在以下情况下 STM32 中的 DMA SPI rx 会如何表现 我有一个指定的 例如 96 字节数组 名为 A 用于存储从 SPI 接收到的数据 我打开循环 SPI DMA 它对每个字节进行操作 配置为 96 字节 是否有可能
  • stm32l0: 执行MI命令失败。使用 vFlashErase 数据包擦除闪存时出错

    我正在使用 Nucleo STM32L031 和 AC6 STM32 工作台 eclipse 我编写应用程序并进入调试模式 一切正常 直到我在应用程序中添加另一个功能 我注意到当我删除 评论 新函数 软件可以再次进入调试模式 但是当我添加
  • GCC 变量映射和 MISRA-C

    我主要知道两种使用 GCC 声明内存映射寄存器的方法 有许多变体 使用双字段 每个外设的数据结构等 要么使用初始化为正确地址的指针 例如volatile uint32 t pMyRegister uint32 t 0xDEADBEEFUL
  • .NET 中有处理 Modbus 协议的好库吗? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 有谁知道有一个好的 最好是开源的 库来处理 Modbus 协议 我看过一些图书馆 但我正在寻找一些人的

随机推荐

  • Vmware Esxi在线管理虚拟机

    目录 特征 占地面积小 可靠的性能 增强的安全性 生态系统卓越 用户友好的体验 管理截图 登录系统 主机虚拟机 虚拟机操作 What is ESXI Bare Metal Hypervisor ESX VMware 特征 通过将多台服务器整
  • 孤立森林(Isolation Forest)

    最近正好在做孤立森林的项目 xff0c 写下这篇推文记录下项目进程 xff0c 也给需要做这个项目的同学一点参考 1 什么叫异常点 图中红色的点偏离大部分的数据 xff0c 可以发现这些点分布稀疏且离密度高的群体较远 xff0c 这样的点称
  • 修改docker容器端口映射

    大家都知道docker run可以指定端口映射 xff0c 但是容器一旦生成 xff0c 就没有一个命令可以直接修改 通常间接的办法是 xff0c 保存镜像 xff0c 再创建一个新的容器 xff0c 在创建时指定新的端口映射 有没有办法不
  • MaxWelll常用命令

    文章目录 1 启动maxwell xff1a 1 1 控制台为输出 xff1a 1 2 kafka为输出 xff1a 1 3 配置指定某些表输出 xff1a 1 4 配置输出到kafka 分区规则为表的主键 xff1a 1 5 配置文件启动
  • Linux系统--进程与线程的区别

    看了一遍排在前面的答案 xff0c 类似 进程是资源分配的最小单位 xff0c 线程是CPU调度的最小单位 这样的回答感觉太抽象 xff0c 都不太容易让人理解 做个简单的比喻 xff1a 进程 61 火车 xff0c 线程 61 车厢 线
  • 关于锁的理解

    本文打算写一些和锁有关的东西 xff0c 谈一谈我对锁的原理和实现的理解 xff0c 主要包含以下方面 信号量互斥量条件变量 同步与互斥 其实同步与互斥都是计算机科学里面概念性的东西 xff0c 它们和什么编程语言 操作系统其实都没什么关系
  • Android 适配ipv6

    Android8 0开始支持ipv6 okhttp支持ipv6 glide支持ipv6方法 ijkplayer
  • java自我学习第一阶段的收获和感受

    1 首先对于编程的学习第一步都是基本语法的学习 xff0c 语法学习的特点有 xff1a 所有编程语言的语法定义都大体相似 xff0c 大概的是编程发展的延续 xff0c 没有人语言设计人员会标新立异 xff0c 只有站在别人的肩上不断完善
  • docker常用命令及配置

    最近使用了docker xff0c 像是发现了新大陆 真是简洁好用的东西 xff0c 为啥原来没发现 docker的安装不再赘述 xff0c 在此记录一下常用的命令 xff0c 以便于将来查询 查看docker容器版本 docker ver
  • 数字图像处理读后感

    数字图像处理读后感 前言 初步写完比赛代码后 看了机器学习看了数字图像处理还有其他的一些乱七八糟的东西 然后又觉得如果只是看完没有总结回顾那就是很失败的一件事情 所以就想写一写自己的读后感 我自己看得是B站的视频 这是西安电子科技大学的任老
  • 第七天 树莓派+计算棒配置过程

    一 xff1a 安装过程参考 xff1a https blog csdn net qqqzmy article details 85213414 1 材料硬件 树莓派3B 43 intel movidius 神经元计算棒2代显示器 鼠标键盘
  • Docker镜像推送(push)到Docker Hub

    镜像构建成功后 xff0c 只要有docker环境就可以使用 xff0c 但必须将镜像推送到Docker Hub上去 我们之前创建的镜像不符合Docker Hub的tag要求 xff0c 因为 在Docker Hub注册的用户名是boony
  • Altera FPGA 远程更新

    文章目录 1 概述2 如何生成factory jic xff1f 3 如何使用ASMI IP4 如何使用Remote updata IP xff1f 5 UART命令 以下内容均参考自官方手册 手册下载地址 xff1a ug altremo
  • 将ros的深度图像 转换成 opencv的图像 并求距离

    将ros的图像 转换成 opencv的图像并求距离 参考的博客概念将ROS图像消息转换为OpenCV图像示例计算距离 参考的博客 ROS学习笔记47 xff08 ROS图像和OpenCV图像之间的转换 xff08 C 43 43 xff09
  • ROS入门总结(二):Python定义发布器Publisher与订阅器Subscriber

    节点ROS通信系统中就是一个可执行的程序 xff0c 这边博客主要记录如何在Python代码节点中定义发布器和订阅器 发布器 xff1a import rospy from std msgs msg import String 载入Stri
  • 计算机视觉中的传统特征提取方法总结(转载)

    前言 本文对计算机视觉传统方法中的一些特征提取方法进行了总结 xff0c 主要包括有 xff1a SIFT 尺度不变特征变换 HOG 方向梯度直方图 SURF ORB LBP HAAR 目录 1 SIFT xff08 尺度不变特征变换 xf
  • docker源码分析(1)(持续更新)

    docker源码分析 xff08 1 xff09 xff08 持续更新 xff09 daemondocker DaemonClient的启动内部函数分析newAPIServerConfigloadListenersinitContainer
  • JS实现图片切割

    lt DOCTYPE html gt lt html lang 61 34 en 34 gt lt head gt lt meta charset 61 34 UTF 8 34 gt lt title gt Title lt title g
  • GPS、RTK、PPK三种定位技术的原理及应用

    一 GPS技术 1 原理 之前做过集成GPS功能的产品 xff0c 对这种不以定位为主要功能的产品 xff0c 精度是没有要求的 xff0c 例如我只是用它来得到当前社区的位置 xff0c 一般的GPS模块都能满足要求 理论上 xff0c
  • 【STM32】RS485 Modbus协议 采集传感器数据

    源码链接 xff1a Modbus传感器采集协议 一 硬件 1 传感器 xff1a 为液压传感器 xff0c 12vDC xff0c RS485数据输出 xff0c 采用Modbus协议通信 2 电路 xff1a 根据传感器属性 xff0c