6

STM32CubeMX串口通讯

 6 months ago
source link: https://blog.51cto.com/zyxfighting/9981906
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

串口的简单介绍

RS-232与TTL

根据通讯使用的电平标准不同,串口通讯可分为 TTL 标准及 RS-232 标准。而STM32的串口是TTL电平标准的。如果需要使用到RS-232则需要一个电平转换芯片。

单工通信、半双工通信和全双工通信

讲到串口,我们还需要具备这些基础概念。

(1)单工通讯特点很简单,就是只有一个发送端,一个接收端。从一开始发射端和接收端就已经确立,无法改变,数据传输只能从发送端向接收端发送。

(2)举个生活中的例子,你可以理解为某些霸道的家长,从一开始就已经确定了他是发射端,小孩只能被动接收。只能是家长教育孩子,不能孩子指正家长。

STM32CubeMX串口通讯_stm32

半双工通信

(1)半双工通信的特点就是,双方既可以是发送端又可以是接收端。不过问题在于,每一次数据传输过程中,任何一方只能为一种状态。如果你是接收端,就只能是接收端。如果你是发送端,那么就只能是发送端。

(2)以生活中能够见到的对讲机为例,当A在对讲机中说话的时候。B只能听,不能说话。如果B要说话了,那么需要等待A说话完成之后,B才能说话。

STM32CubeMX串口通讯_串口_02

全双工通信

(1)在全双工传输模式下,发送方和接收方之间的通信可以同时进行,我可以是发送端的同时,又是接收端。

(2)以我们打电话为例子。如果A打电话给B,B听到了与A不同的意见的时候,B可以在A说话的同时陈述自己的观点,也就是插嘴。(不礼貌,手动狗头)

(3)STM32的串口就是全双工的,不过一般都是使用半双工的方式收发信息

STM32CubeMX串口通讯_数据_03

串口作用以及需要配置的东西

(1)串口通讯作为最常用的通讯手段之一,作用许多。最常见的就是使用蓝牙模块或者是WIFI模块进行通讯,也可以实现与OpenMV实现通讯。

(2)串口一般都有波特率,数据位,校验位,停止位,流控需要配置。为什么需要配置这些东西呢?因为两个不同的设备进行交流的时候,需要在同一个频道上。就好比,一个只会说中文的人与一个只会说英文的人是无法进行沟通的。

STM32CubeMX串口通讯_嵌入式硬件_04

既然两个人要需要共同,那么只要说一种语言就行了,为什么还有这么多配置呢?接下来我一一介绍。 

(1)串口其实分为两种UART(异步通信)和USART(同步通讯)。这两者的区别是什么呢?

(2)同步通讯你可以理解为你打电话给别人,电话双方都是同时沟通交流的。

(3)而异步通讯,你可以理解为电话留言。我发一段话给你,你不在没关系,有时间的时候听就可以了。我们一般使用异步通讯。

数据位,决定了通信过程中传输的有效数据位数,数据位通常有5、6、7 、8 bit,根据需要进行相应的配置,一般配置为8bit,因为一个字节就是8bit

有时候,我们需要对接收到的数据进行判断是否正确。因为有时候进行数据交互过程中,可能受到一些外接干扰。一般来说会有4中校验方式。偶校验、奇校验、1校验和0校验。

偶校验:有效数据和校验位中“1”的个数为偶数。比如有效数据:11001010, 此时有效数据“1”的个数为 4 个,所以偶校验位为“0”。如果我们接收到的数据,查看偶校验位为1,表示数据受到干扰。

奇校验:有效数据和校验位中“1”的个数为奇数。比如有效数据:01101001, 此时总共有 4 个“1”,为达到奇校验效果,校验位为“1”。如果我们接收到的数据,查看奇校验位为0,表示数据受到干扰。

1校验:无论什么内容,校验位永远是1。如果受到的数据,校验位是0,表示数据受到干扰。

0校验:无论什么内容,校验位永远是0。如果受到的数据,校验位是1,表示数据受到干扰。

(1)停止位一般有1,1.5,2。因为不同设备的时钟可能有偏差,就好像即使是双胞胎也有不同一样。

(2)而微小的时钟偏差,会出现微弱的不同步现象。只进行一次数据传输还好,当我们进行多次数据传输之后,这个不同步会逐渐放大,最后导致数据传输有问题。所以停止位还提供了一次校正时钟同步的机会。

(3)这个过程就好像是一条笔直的路线,汽车一直往前开。假如司机不小心动了一点点方向盘,只走几十米可能看不出来偏差。但是假如再走个几百米,就能够看到明显偏移了路线。所以司机需要不断修正方向盘保持直行。

(1)这个对于很多刚入门的人不会关注,都是直接设置无流控的,我也没用过。还是简单介绍一下。

(2)因为两个不同的设备对数据的处理速度不同,可能导致丢失数据的情况。比如A向B发送数据,A的处理速度极快,不断给B发送数据。但是B处理速度可能慢一点,会接收不过来,导致数据丢失。

(3)举个例子。就像我们上模电课,老师思路敏捷,滔滔不绝。但是我们对这些知识的处理速度可能会慢一点。这样就会导致,做作业的时候,很奇怪,这个东西讲过吗?

(4)流控又分为硬件流控与软件流控。硬件流控就是 RTS (Require ToSend,发送请求)和CTS (Clear ToSend,发送允许)这两个引脚。这个时候串口通讯就不再是只有GND,TX,RX这三个了,将会增加RTS 和CTS 这两个引脚。

(5)一般不用流控。需要更深了解的,自行学习

最后强调一点!

TX(Transmit )发送数据,需要与另外一个MCU的RX连接(Receive )。两边的GND要连接,因为都需要知道对方的基准电压是多少!

STM32CubeMX串口通讯_嵌入式硬件_05

STM32CubeMX配置

还是和之前的一样步骤

STM32CubeMX串口通讯_stm32_06
STM32CubeMX串口通讯_数据_07
STM32CubeMX串口通讯_嵌入式硬件_08

UART配置

STM32CubeMX串口通讯_单片机_09
STM32CubeMX串口通讯_串口_10
STM32CubeMX串口通讯_数据_11
STM32CubeMX串口通讯_数据_12

Keil编程

查看 MX_USART1_UART_Init();

我发现我生成的串口文件里面没用进行串口使能,即使我再CubeMX里面设置了。

所以你们要看看__HAL_UART_ENABLE_IT()这个函数。

STM32CubeMX串口通讯_数据_13
STM32CubeMX串口通讯_stm32_14
void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 9600;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
 /*使能串口接收断 */
  __HAL_UART_ENABLE_IT(&huart1,UART_IT_RXNE);  

}

编写中断服务程序

在stm32f1xx_it.c中找到void USART1_IRQHandler(void)。

STM32CubeMX串口通讯_嵌入式硬件_15
void USART1_IRQHandler(void)
{
  uint8_t ch=0; 
  
	if(__HAL_UART_GET_FLAG( &UartHandle, UART_FLAG_RXNE ) != RESET)
	{		
    ch=( uint16_t)READ_REG(UartHandle.Instance->DR);
    WRITE_REG(UartHandle.Instance->DR,ch); 
 
	}
}

其实也没什么可以说的。就讲解一下中断服务函数部分。

__HAL_UART_GET_FLAG()

(1)因为串口中断由多种行为引起,比如主控发送数据可以引起,主控接收到数据也可以引起。所以我们需要知道到底是那种行为引起的中断。

(2)一般只要了解接收中断即可,所以我只讲接收中断部分。

if(__HAL_UART_GET_FLAG( &huart1, UART_FLAG_RXNE ) != RESET)
	{		

	}

(1)huart1就是你在串口初始化的时候STM32CubeMX定义的。你复制后面这个部分写在huart1位置即可。

(2)后面的UART_FLAG_RXNE表示接收中断。

(3)如果是接收中断,__HAL_UART_GET_FLAG()将会返回SET,如果不是接收中断返回RESET。这个if就是用来判断是否为接收中断,如果是接收中断进入if语句。

STM32CubeMX串口通讯_数据_16

READ_REG()和WRITE_REG()

这个不是函数,是宏定义。我们鼠标点击READ_REG,然后按F12。即可查看他的定义。

#define WRITE_REG(REG, VAL)   ((REG) = (VAL))

#define READ_REG(REG)         ((REG))

(1)其实这个就是直接寄存器操作,操作DR寄存器。

(2)无论是发送的数据还是接收的数据我们都存放在DR寄存器中,如果是发送数据,那么就让DR寄存器写入数据。如果是接收数据,那么就将DR寄存器的数据存入变量中。

(3)所以READ_REG()是读取数据,WRITE_REG()是发送数据。

STM32CubeMX串口通讯_嵌入式硬件_17

如果要更改发送接收数据的串口怎么办?

/*****usart.c*****/
UART_HandleTypeDef huart1;  //假如这个是串口1的结构体
UART_HandleTypeDef huart2;  //假如这个是串口2的结构体

/***stm32f1xx_it.c***/

void USART1_IRQHandler(void)  //串口1中断函数
{
  uint8_t ch=0; 
  
	if(__HAL_UART_GET_FLAG( &huart1, UART_FLAG_RXNE ) != RESET)
	{		
    ch=( uint16_t)READ_REG(huart1.Instance->DR);
    WRITE_REG(huart1.Instance->DR,ch); 
 
	}
}

void USART2_IRQHandler(void) //串口2中断函数
{
  uint8_t ch=0; 
  
	if(__HAL_UART_GET_FLAG( &huart2, UART_FLAG_RXNE ) != RESET)
	{		
    ch=( uint16_t)READ_REG(huart2.Instance->DR);
    WRITE_REG(huart2.Instance->DR,ch); 
 
	}
}

需要一个串口工具。 gitee仓库自取

 需要一个TTL转串口模块。TX——RX,GND——GND,3.3——3.3。

STM32CubeMX串口通讯_单片机_18

 电脑发送什么,单片机就回什么。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK