【STM32】RS485 Modbus协议 采集传感器数据_stm32单片机采集rs485传感器数据-程序员宅基地

技术标签: stm32  modbus  传感器  MCU  

源码链接: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、采集线过长,要考虑使用屏蔽线

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_33033059/article/details/106935583

智能推荐

L1-014. 简单题_输出事实this-程序员宅基地

文章浏览阅读3.1w次。https://www.patest.cn/contests/gplt/L1-014这次真的没骗你 —— 这道超级简单的题目没有任何输入。你只需要在一行中输出事实:“This is a simple problem.”就可以了。#include &lt;iostream&gt;#include &lt;cstdio&gt;using namespace std;int main(){..._输出事实this

Multipathd Daemon was Unable to Set Options "fast_io_fail_tmo" or "dev_loss_tmo" Under UEK1 or RHCK_multipath rport failed to read dev_loss_tmo value -程序员宅基地

文章浏览阅读421次。Multipathd Daemon was Unable to Set Options "fast_io_fail_tmo" or "dev_loss_tmo" Under UEK1 or RHCK (文档 ID 1678794.1) APPLIES TO:Linux OS - Version Oracle Linux 5.7 with Unbreakable Enterprise Ker..._multipath rport failed to read dev_loss_tmo value error 2

Jython_Jython Development Tools (JyDT) for Eclipse_jythontools-程序员宅基地

文章浏览阅读729次。Installing JyDTThis section describes how to install JyDT by connecting to the JyDT update siteon the internet. If you have downloaded an update site to a computer on your network, please follow the_jythontools

验证结构中IMonitor的作用_验证 monitor组件的主要功能-程序员宅基地

文章浏览阅读922次。DUT 的 input 端口采用的monitor 是干嘛的呢?根据白书: 一,大型项目中,driver 根据协议发送数据,而monitor根据协议接收数据。如果driver和monitor由不同人实现,那么可以大大减少其中任意一方对协议理解的错误。二,便于复用???另外,我的一点理解是:用于判断是否真的将输入,打入了DUT。????就一般环境,IF与dri_验证 monitor组件的主要功能

kubernetes apiserver 报错 service-account-issuer is a required flag-程序员宅基地

文章浏览阅读1.8k次。k8s kube-apiserver 启动报错k8s 版本 1.24根据报错提示说的是是一个必须的参数我们来看一下这个参数是干啥的服务帐号令牌颁发者的标识符。 颁发者将在已办法令牌的 “iss” 声明中检查此标识符。 此值为字符串或 URI。 如果根据 OpenID Discovery 1.0 规范检查此选项不是有效的 URI,则即使特性门控设置为 true, ServiceAccountIssuerDiscovery 功能也将保持禁用状态。 强烈建议该值符合 OpenID 规范: https://_service-account-issuer

【CodeForces - 988C 】Equal Sums (思维,STLmap,STLset,tricks)_草莓^app^【755c.top】最新版-程序员宅基地

文章浏览阅读288次。题干:You are given kk sequences of integers. The length of the ii-th sequence equals to nini.You have to choose exactly two sequences ii and jj (i≠ji≠j) such that you can remove exactly one element ..._草莓^app^【755c.top】最新版

随便推点

Windows下Cygwin环境的Hadoop安装(4)- 在Eclipse中建立hadoop开发环境_hadoop class path 多个文件 cygwin-程序员宅基地

文章浏览阅读6.3k次。在使用hadoop的过程中,不可避免地遇到一些问题需要对hadoop代码进行改进,这就要求我们必须建立一个可修改hadoop代码的开发环境,下面的过程,我们就来建立一个基于Eclipse的hadoop开发环境。- 安装AntHadoop的编译需要Ant的支持,从这里下载并安装最新的Ant:http://ant.apache.org/bindownload.cgi。安装完成后,别忘了将_hadoop class path 多个文件 cygwin

VB:所有控件自适应窗口大小_控件随窗体大小变化改变 vb代码-程序员宅基地

文章浏览阅读1.1w次,点赞5次,收藏18次。Option ExplicitPrivate FormOldWidth As Long'保存窗体的原始宽度Private FormOldHeight As Long'保存窗体的原始高度'在调用ResizeForm前先调用本函数Private Sub ResizeInit(FormNameAs Form)Dim Obj As Control_控件随窗体大小变化改变 vb代码

Python学习笔记——pandas中get_dummies()的用法_python get_dummies-程序员宅基地

文章浏览阅读5.5k次,点赞5次,收藏14次。原文链接在此可以看到get_dummies默认就是所有变量都转了默认转了以后的变量用columns名_数值名表示其中参数predix:prefix : 给输出的列添加前缀,如prefix=“A”,输出的列会显示类似prefix_sep : 设置前缀跟分类的分隔符sepration,默认是下划线"_"df = pd.DataFrame([[‘green’ , ‘A’],[‘red’ , ‘B’],[‘blue’ , ‘A’]])pd.get_dummies(df,prefix = _python get_dummies

【政考网答疑】为什么公务员招录限制35岁以下?-程序员宅基地

文章浏览阅读934次。政考网每日一答,今日咱们讨论的问题是为什么公务员招录限制35岁以下?众所周知,无论是各地省考还是国考,均会要求考生年龄在18周岁以上、35周岁以下(应届硕士和博士经招录机关同意,可放宽到40岁),那么,公务员招录考试为何会限制35岁以下报考呢?这样的要求是否合理?1、高龄人员的可塑性相对不强相比较应届毕业生或者刚毕业不久的大学生,35以上的考生在身体素质上的优势并不明显,特别是一些基层岗位,条件艰苦,高龄考生的岗位匹配度相对较低。古语云,“三十而立,四十而不惑。”高龄考生已从过...

MySQL必知必会学习历程(一)_mysql编写新增教育经历-程序员宅基地

文章浏览阅读2.1k次,点赞5次,收藏27次。MySQL必知必会学习历程第1章 了解SQL1.1 关键术语介绍第2章 MySQL简介2.1 关键术语介绍2.2 安装mysql命令行实用程序(可选)2.3 安装mysql_community(最优)2.3.1 下载mysql_community2.3.2 安装过程第3章 使用MySQL3.1 连接到数据库3.2 建立样例数据库3.2.1 创建空的数据库3.2.2 下载样例表生成脚本3.2.3 使用样例表生成脚本3.3 选择数据库(USE)3.4 了解数据库和表(SHOW)3.5 命令及注释汇总第4章 检索_mysql编写新增教育经历

你都用 Python 来做什么?_你用python做什么-程序员宅基地

文章浏览阅读1.3w次,点赞42次,收藏158次。你们都用python做些什么呢?在开发中 python 这一个语言就像是小叮当,而 python 的第三方库则是“百宝箱”,你只要想着对某一个方向进行开发,那么这个“百宝箱”就会给你想要的东西。由于我是在开发多年后接触到的 python,对我来说自从接触 python 就打开了“新世界”的大门。(我正在求设计做一张图,还没做完,做完贴上在这里)一、做个自己玩游戏的程序在前几年,我有一个朋友是一个“游戏商人”,不过大多数他是手动进行商品处理。他有一天找到我,跟我说“嗨兄弟,会不会做外G?”!此时我_你用python做什么