cubeIDE开发, stm32的RS485/232串口通信开发要点

news2024/11/16 23:33:41

一、stm32串口通信

         stm32串口通信一般是指通过UART(Universal Asynchronous Receiver/Transmitter)通用异步收发传输器传输数据,UART 作为异步串口通信协议的一种,工作原理是将传输数据的每个字符一位接一位地传输,其在应用程序开发过程中使用频率最高的数据总线。而MCU的UART 通信实际上是基于GPIO引脚电平信号实现的,因此,在预制UART外设不够时,也会可以采用GPIO引脚自行模拟UART串口通信。

        【1】硬件流控

        UART 串口的特点是将数据一位一位地顺序传送,只要 2 根传输线就可以实现双向通信,一根线发送数据的同时用另一根线接收数据。但是,数据在两个串口之间进行通讯的时候常常会出现丢失数据的现象,主要原因是数据处理及数据接收效率不一致引起的冲突,为了解决这种问题,引入了流控概念。流控的概念源于 RS232 这个标准,用来解决这个速度匹配的问题,通过新增传输线来控制数据传输数据线的流向、流速等,这就是简单的三线串口的通讯方式,如下图:

         在两条数据线基础上,增加两根控制线,一根叫 CTS(Clear To Send 为输入信号,一根叫 RTS(Require To Send 为输出信号),一个是接收控制,一个是发送控制。可以看到,数据线方向与流控线数据方向相反,因为流控的主要是协调接收数据和处理数据一致性,所以需要让发送端等待,接收端发出来的信号叫 RTS 信号,发送端检测管脚叫 CTS。

        数据接收与 RTS 信号标记如下图,接收端缓存没数据时,RTS是低电平状态,发送端可以发送数据;当接收端接收到数据后,RTS切换为高电平,就是告诉发送端,数据还没有被拿走,请发送端等待;RTS 信号在数据没有被读取之前都是保持在高电平状态,一旦数据被 DMA 或者 CPU 从 DR 寄存器读取之后,RTS 就释放高电平,变为低电平,这时候发送端又可以发送数据的了。另外,如果 USART 是FIFO 模式,即缓冲模式开启的时候,在 FIFO 满的时候才会去拉高 RTS 信号。

         相应的,发送数据和CTS信号类似,发送端在发送数据时,要实时监测 CTS 的电平状态,如果发现是高电平,就不会再发送新的数据,直到 CTS 检测发现已经没有高电平信号才会再次发送。

        我们在cubeIDE中,对应上述的就是勾选RS232流控制支持,就可以选择CTS/RTS引脚配置。

         如上面所述,由设想的两根数据线传输多出两根流控制线,这无形中增加硬件成本,因此,RS485出现后,RS232的CTS/RT合二为一DE ,STM32 上有一个 DE 管脚和 RS485 的接收器芯片直接相连,控制数据的收发,主要就是数据的方向的控制。因为 RS485 是一个半双工的通讯模式,它的数据收的时候就不能发,发的时候不能收。

         在cubeMX中,需要支持DE引脚开始,就需要勾选RS485流控制功能

         【2】软件流控

        上述的增加流控制线的做法都是属于硬件流控的实现,在实际项目开发过程,我们很多时候为了方便以及节省引脚,往往采用软流控。软件流控是以特殊的字符来代表从机已经不能再接收新的数据了,基本的流程就是从机在接收数据很多的时候或主动给发送端发送一个特殊字符,当发送端接收到这个特殊字符后就不能再发送数据了。

  软件流控很方便,不需要增加新的硬件,还是以前的TX、RX两根数据线实现,但是使用了软件流控,它本身的字符也是数据,这个数据只不过是说在软件里把它设置了一个特殊的含义。如果它是一个全双工的通讯,在给另一个串口发送数据的时候如果也包含了这样一个特殊字符,对方就会误以为我让它不要再发送数据了,会有一定的概率出现错误,而硬件流控就不需要考虑这方面,只需要使用 CTS 和 RTS,所有的数据都是由硬件来操作的,因此硬件流控在稳定性上更可靠。

       【3】串口通信参数

         UART 串口通信有几个重要的参数,分别是起始位、波特率、数据位、停止位和奇偶检验位(流控,按需),对于两个使用 UART 串口通信的端口,这些参数必须匹配,否则通信将无法正常完成。

        起始位:表示数据传输的开始,默认电平逻辑为 “0” 。

        波特率:串口通信时的速率,它用单位时间内传输的二进制代码的有效位(bit)数来表示,其单位为每秒比特数 bit/s(bps)。常见的波特率值有 4800、9600、14400、38400、115200等,数值越大数据传输的越快,波特率为 115200 表示每秒钟传输 115200 位数据。

        数据位:可能值有 5、6、7、8、9,表示传输这几个 bit 位数据。一般取值为 8,因为一个 ASCII 字符值为 8 位。

        停止位: 表示一帧数据的结束。默认电平逻辑为 “1”。

        奇偶校验位:用于接收方对接收到的数据进行校验,校验 “1” 的位数为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性,使用时不需要此位也可以。

二、新建RS485通信工程

        【1】项目实现背景信息

        本文采用的STM32L496VGTX-ali开发板,该开发板预留了扩展接口支持USART4通信,本文将USART4与USB转RS485(CH340)连接,进而与电脑通信。

         实物图:

         扩展接口原理框图如下:

         另外本人开发板标注背后扩展口标注的是PA0、PA1,查看其他描述,确定就是PA0、PA1引脚。

      现在基于本专栏前面已近实现的串口lpusart通信和及lcd亮屏工程为基础创建新工程,并移植了相关代码。

   cubeIDE开发, stm32调试信息串口通信输出显示_py_free的博客-CSDN博客

   cubeIDE开发, stm32的OLED点亮及字符显示设计(基于SPI通信)_py_free的博客-CSDN博客

        现将在该工程基础上,实现串口Usart4和lpusart通信,并lcd屏打印其发送数据;Usart4发送'A'/'B'可以点亮及熄灭LED0。

        【2】项目配置

        双击(.ioc)打开cubeMX配置界面,开启USART4串口功能,配置串口参数

        并开启usart4的中断支持

         点击保存生成输出代码。

        【3】在ICore目录下,新建rs485文件夹,并在该文件目录下,创建rs485.h和rs485.c源文件,其实现代码如下:

        rs485.h

#ifndef RS485_RS485_H_
#define RS485_RS485_H_

#include "stm32l4xx_hal.h" //HAL库文件声明

extern UART_HandleTypeDef huart4;//声明USART4的HAL库结构体
void RS485_printf (char *fmt, ...);  //RS485发送

#endif /* RS485_RS485_H_ */

        rs485.c

#include "../usart/usart.h"
#include "main.h"
#include <stdarg.h>
/*
RS485总线通信,使用UART4,这是RS485专用的printf函数
*/
void RS485_printf (char *fmt, ...)
{
    char buff[USART4_REC_LEN+1];  //用于存放转换后的数据 [长度]
    uint16_t i=0;
    va_list arg_ptr;
    va_start(arg_ptr,fmt);
    vsnprintf(buff, USART4_REC_LEN+1,fmt,arg_ptr);//数据转换
    i=strlen(buff);//得出数据长度
    if(strlen(buff)>USART4_REC_LEN)i=USART4_REC_LEN;//如果长度大于最大值,则长度等于最大值(多出部分忽略)
    HAL_UART_Transmit(&huart4,(uint8_t *)buff,i,0Xffff);//串口发送函数(串口号,内容,数量,溢出时间)
    va_end(arg_ptr);
}
//所有USART串口的中断回调函数HAL_UART_RxCpltCallback,统一存放在【USART.C】文件中。

        调整usart.h和usart.c文件,重新实现串口USART4的中断回调函数

        usart.h

#ifndef _USART_H_
#define _USART_H_

#include "stm32l4xx_hal.h" //HAL库文件声明
#include <string.h>//用于字符串处理的库
#include "../print/print.h"//用于printf函数串口重映射

extern UART_HandleTypeDef hlpuart1;//声明LPUSART的HAL库结构体
extern UART_HandleTypeDef huart4;//声明USART4的HAL库结构体

#define HLPUSART_REC_LEN  256//定义LPUSART最大接收字节数
#define USART4_REC_LEN 256

extern uint8_t  HLPUSART_RX_BUF[HLPUSART_REC_LEN];//接收缓冲,最大HLPUSART_REC_LEN个字节.末字节为换行符
extern uint16_t HLPUSART_RX_STA;//接收状态标记
extern uint8_t HLPUSART_NewData;//当前串口中断接收的1个字节数据的缓存

extern uint8_t USART4_RX_BUF[USART4_REC_LEN];
extern uint16_t USART4_RX_STA;
extern uint8_t USART4_NewData;

void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart);//串口中断回调函数声明

#endif /* _USART_H_ */

        usart.c

#include "usart.h"

uint8_t  HLPUSART_RX_BUF[HLPUSART_REC_LEN];//接收缓冲,最大HLPUSART_REC_LEN个字节.末字节为换行符
/*
 * bit15:接收到回车(0x0d)时设置HLPUSART_RX_STA|=0x8000;
 * bit14:接收溢出标志,数据超出缓存长度时,设置HLPUSART_RX_STA|=0x4000;
 * bit13:预留
 * bit12:预留
 * bit11~0:接收到的有效字节数目(0~4095)
 */
uint16_t HLPUSART_RX_STA=0;接收状态标记//bit15:接收完成标志,bit14:接收到回车(0x0d),bit13~0:接收到的有效字节数目
uint8_t HLPUSART_NewData;//当前串口中断接收的1个字节数据的缓存

uint8_t USART4_RX_BUF[USART4_REC_LEN];
uint16_t USART4_RX_STA=0;
uint8_t USART4_NewData;

void  HAL_UART_RxCpltCallback(UART_HandleTypeDef  *huart)//串口中断回调函数
{
	if(huart ==&hlpuart1)//判断中断来源(串口1:USB转串口)
    {
		if(HLPUSART_NewData==0x0d){//回车标记
     	  HLPUSART_RX_STA|=0x8000;//标记接到回车
		}else{
			if((HLPUSART_RX_STA&0X0FFF)<HLPUSART_REC_LEN){
				HLPUSART_RX_BUF[HLPUSART_RX_STA&0X0FFF]=HLPUSART_NewData; //将收到的数据放入数组
				HLPUSART_RX_STA++;  //数据长度计数加1
			}else{
				HLPUSART_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
			}
        }
       HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData,1); //再开启接收中断
    }
	if(huart ==&huart4)//判断中断来源(串口4:USB转串口)
    {
//		printf("%c",USART4_NewData);
		if(USART4_NewData==0x0d){//回车标记
			USART4_RX_STA|=0x8000;//标记接到回车
		}else{
			if((USART4_RX_STA&0X0FFF)<USART4_REC_LEN){
				USART4_RX_BUF[USART4_RX_STA&0X0FFF]=USART4_NewData; //将收到的数据放入数组
				USART4_RX_STA++;  //数据长度计数加1
			}else{
				USART4_RX_STA|=0x4000;//数据超出缓存长度,标记溢出
			}
        }
       HAL_UART_Receive_IT(&huart4,(uint8_t *)&USART4_NewData,1); //再开启接收中断
    }
}

   三、RS485驱动调用及测试

        在main.c文件中加入rs485.h头文件支持

/* USER CODE BEGIN Includes */
#include "../../ICore/key/key.h"
#include "../../ICore/led/led.h"
#include "../../ICore/print/print.h"
#include "../../ICore/usart/usart.h"
#include "../../ICore/rs485/rs485.h"
#include "../../ICore/oled/oled.h"
/* USER CODE END Includes */

        在主函数初始化中调整加入usart4初始化设定

  /* USER CODE BEGIN 2 */
  ResetPrintInit(&hlpuart1);
  HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断
  HLPUSART_RX_STA = 0;
  HAL_UART_Receive_IT(&huart4,(uint8_t *)&USART4_NewData,1); //开启串口4接收中断
  USART4_RX_STA = 0;
  //
  OLED_init();
  //设置OLED蓝色背景显示
  BSP_LCD_Clear_DMA(LCD_DISP_BLUE);
  printf("OLED_Clear_DMA\r\n");
  /* USER CODE END 2 */

        在主函数循环体中,修改代码实现对usart4接收数据处理

  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始
		  RS485_printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
		  OLED_printf(10,10,"%.*s",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
		  HLPUSART_RX_STA=0;//接收错误,重新开始
		  HAL_Delay(100);//等待
	  }
	  if(USART4_RX_STA&0xC000){//溢出或换行,重新开始
		  if(1==(USART4_RX_STA&0x0FFF))
		  {
			  switch (USART4_RX_BUF[0]){
			  case 'A':
				  set_led0_val(1);
				  break;
			  case 'B':
				  set_led0_val(0);
				  break;
			  default:
				  break;
			  }
		  }
  		  printf("%.*s\r\n",USART4_RX_STA&0X0FFF, USART4_RX_BUF);
  		  OLED_printf(10,42,"%.*s",USART4_RX_STA&0X0FFF, USART4_RX_BUF);
  		  USART4_RX_STA=0;//接收错误,重新开始
  		  HAL_Delay(100);//等待
  	  }
    /* USER CODE END WHILE */

        编译及下载及测试

         LED0在发送'A'字符是关闭(LED灯是低位有效)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/70784.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据库01_内存分页管理_分段管理_设备管理_IO处理_索引文件结构_文件目录_位示图---软考高级系统架构师008

可以看到数据库方面的考点.在架构里面考4,5分左右 这里只说比较重要的标红的考点. 然后我们来看ER图: 1.首先看一下实体的概念:实体是指的客观存在并相互区别的事物,可以举一个例子,比如一家超市,那么超市经理,员工,部门经理,业务员等等,这都是名词,都是属于实体. 2.然后…

知识图谱-KGE-语义匹配-双线性模型(打分函数用到了双线性函数)-2013:NTN(Neural Tensor Network)

【paper】 Reasoning With Neural Tensor Networks for Knowledge Base Completion 【简介】 本文是斯坦福大学陈丹琦所在团队 2013 年的工作&#xff0c;好像是发表在一个期刊上的。文章提出了用于知识库补全的神经网络框架 NTN&#xff08;Neural Tensor Network&#xff09…

Golang代码质量检查工具GolangCI-Lint(学习笔记)

Golang代码质量检查工具GolangCI-Lint 直接用下面go get的方式会出现报错 go get github.com/golangci/golangci-lint/cmd/golangci-lint解决方法 直接去 https://github.com/golangci/golangci-lint/releases 下载对应版本 go < 1.9 isn’t supported go1.9 is officia…

机器学习之数据分离与混淆矩阵

文章目录[TOC](文章目录)前言数据分离混淆矩阵實戰總結前言 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器学习这门技术也越来越重要&#xff0c;很多人都开启了学习机器学习&#xff0c;本文就介绍了机器学习的基础内容之数据分离与混淆矩阵。 数据分离 前面我们…

多线程间的同步控制和通信

用多线程并发处理&#xff0c;目的是为了让程序更充分地利用CPU &#xff0c;好能加快程序的处理速度和用户体验。如果每个线程各自处理的部分互不相干&#xff0c;那真是极好的&#xff0c;我们在程序主线程要做的同步控制最多也就是等待几个工作线程的执行完毕&#xff0c;如…

weston input 概述

weston input 概述 零、前言 本文描述了有关于 weston (基于 wayland 协议一种显示服务器的实现) 中有关于输入设备管理的部分;为了聚焦于此,本文不会对 weston 整体或 wayland 协议进行过多的阐述. 考虑到读者可能存在不同的需求,采用分层次的描述方式,主要面向以下两类人群…

Android Studio 导入opencv异常报错紧急救援

Download OpenCV from SourceForge.net 1、下载Android demo之后导入Android Studio 如下图所示 报错信息如下 A problem occurred configuring root project opencv_samples. > Could not resolve all artifacts for configuration :classpath.> Could not find org.j…

校园失物招领毕业设计,学生失物招领系统设计与实现,毕业设计怎么写论文源码开题报告需求分析怎么做

项目背景和意义 目的&#xff1a;本课题主要目标是设计并能够实现一个基于web网页的失物招领网站系统&#xff0c;整个网站项目使用了B/S架构&#xff0c;基于java的springboot框架下开发&#xff1b;管理员通过后台录入信息、管理信息&#xff0c;设置网站信息&#xff0c;管理…

8_4、Java基本语法之线程的通信

一、问题的引入 使用两个线程打印 1-100。线程1, 线程2交替打印&#xff1f; 二、解决问题涉及的方法 涉及到的三个方法&#xff1a; 1.wait():一旦执行此方法&#xff0c;那么调用此方法的线程就会进入阻塞状态&#xff0c;并释放同步监视器。 2.notify():一个线程…

如何使用htmlq提取html文件内容

htmlq能够对 HTML 数据进行 sed 或 grep 操作。我们可以使用 htmlq 搜索、切片和过滤 HTML 数据。让我们看看如何在 Linux 或 Unix 上安装和使用这个方便的工具并处理 HTML 数据。 什么是htmlq&#xff1f; htmlq类似于 jq&#xff0c;但用于 HTML。使用 CSS 选择器从 HTML 文…

[安装] HIVE搭建环境

一、生产环境hive集群架构 参考&#xff1a; hive2.3.7安装记录 hive基础入门与环境的搭建 基础篇七 Hive-2.3.9安装与配置 大数据之Hive 集群搭建 完整使用 数仓&#xff08;十&#xff09;hive的Metastore机制 二、前言快读 Hive安装分类 主要是metastore的服务搭建方…

[rsync] 基于rsync的同步

环境 Linux&#xff1a;CentOs7.5 rsync: 3.1.2 rsync安装 一般安装系统时会自带rsync&#xff0c;可通过如下命令查看已经安装的版本信息 rsync --version如果系统未安装&#xff0c;可通过如下方式安装 yum安装【建议】 使用root用户执行yum安装 yum install -y rsync安…

代码随想录刷题记录day37 0-1背包+分割等和子集

代码随想录刷题记录day37 0-1背包分割等和子集 0-1背包 问题&#xff1a;有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 例题&#xf…

操作系统实验五 进程间通信-管道通信

实验目的 1.掌握利用管道机制实现进程间的通信的方法 2.了解利用消息缓冲队列机制实现进程间的通信的方法 3..了解利用共享存储区机制实现进程间的通信的方法 五个题目如下 1. 函数int pipe(int fd[2])创建一个管道&#xff0c;管道两端可分别用描述字fd[0]以及fd[1]来描述。需…

多元宇宙算法求解电力系统多目标优化问题(Matlab实现)【电气期刊论文复现与创新】

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f389;作者研究&#xff1a;&#x1f3c5;&#x1f3c5;&#x1f3c5;本科计算机专业&#xff0c;研究生电气学硕…

SpringCloud项目使用Nacos进行服务的注册

本篇介绍Spring cloud项目使用Nacos作为注册中心来进行服务注册及服务发现&#xff0c;并进行简单的测试来验证。 一、简介 nacos是一个集服务发现、服务配置、服务元数据以及流量管理于一体的管理中心&#xff0c;能帮助我们更好的发现、配置和管理微服务。 注意&#xff1…

家政公司网站毕业设计,家政服务系统设计与实现,毕业设计论文源码开题报告需求分析

项目背景和意义 目的&#xff1a;本课题主要目标是设计并能够实现一个基于web网页的家政服务预约系统&#xff0c;整个网站项目使用了B/S架构&#xff0c;基于java的springboot框架下开发&#xff1b;管理员通过后台录入信息、管理信息&#xff0c;设置网站信息&#xff0c;管理…

JS项目打包之ROLLUP.JS入门

一、目的 Rollup是一个用于JavaScript的模块打包器&#xff0c;它将小块代码编译成更大、更复杂的东西&#xff0c;例如库或应用程序。它为JavaScript ES6版本中包含的代码模块使用了新的标准化格式&#xff0c;而不是以前的特殊解决方案&#xff0c;如CommonJS和AMD。ES模块可…

Win10安装Nacos

Win10安装Nacos 文章目录Win10安装Nacos前言下载Nacos安装Nacos验证前言 最近在学微服务的东西&#xff0c;使用的是 Spring Cloud Alibaba 生态&#xff0c;Nacos就是其中关键的一环。 这是 Nacos 的官网地址&#xff1a;https://nacos.io/zh-cn/index.html 官网的文档对于…

Python中用PyTorch机器学习神经网络分类预测银行客户流失模型

分类问题属于机器学习问题的类别&#xff0c;其中给定一组特征&#xff0c;任务是预测离散值。分类问题的一些常见示例是&#xff0c;预测肿瘤是否为癌症&#xff0c;或者学生是否可能通过考试。 最近我们被客户要求撰写关于银行客户流失的研究报告&#xff0c;包括一些图形和…