【物联网】一文读懂UART通信协议

本文详细介绍了UART通信的过程,包括起始位、数据位、校验位和停止位的传输,以及STM32单片机上使用HAL库和标准库进行UART编程的示例。重点讲解了奇偶校验的作用及其在错误检测中的角色。
摘要由CSDN通过智能技术生成

UART传输的过程

  1. 起始位(Start Bit):传输开始前,发送线发送一个低电平作为起始位,表示数据的开始。接收线检测到低电平后,开始接收数据。

  2. 数据位(Data Bits):发送端将数据位逐位发送,从低位到高位,以二进制形式传输数据。接收端在时钟的边沿进行采样,以确定数据位的值。

  3. 校验位(Parity Bit):可选项,用于检测数据位传输过程中的错误。发送端在数据位后面发送校验位,其值与数据位的校验规则相关。接收端通过校验位来验证数据的正确性。

  4. 停止位(Stop Bit):传输完成后,发送线发送一个或多个高电平作为停止位,表示数据的结束。接收线检测到高电平后,完成数据的接收。

UART的传输速率由波特率(Baud Rate)决定,表示每秒传输的比特数。波特率确定了每个比特的持续时间,从而影响了数据的传输速度。并且发送端和接收端的波特率必须一致,才能正确地接收和解析数据。否则,数据可能会被错误地解析或丢失。

奇偶校验

上面讲到的校验位就是使用奇偶校验方法对uart传输的数据进行校验,奇偶校验是一种在UART通信中常用的校验方式,用于检测数据位传输过程中的错误。它可以通过校验位来验证数据的正确性。

奇偶校验的实现方式如下:

  1. 奇校验(Odd Parity):发送端在每个数据字节中已发送的数据位之后,追加一个校验位,使得整个数据字节中的1的数量(包括数据位和校验位)为奇数。例如,如果数据位中有偶数个1,发送端会在校验位中插入一个1,使得总数为奇数。

  2. 偶校验(Even Parity):发送端在每个数据字节中已发送的数据位之后,追加一个校验位,使得整个数据字节中的1的数量(包括数据位和校验位)为偶数。例如,如果数据位中有奇数个1,发送端会在校验位中插入一个1,使得总数为偶数。

在接收端,接收器会对接收到的数据进行校验,计算数据位和校验位中1的数量,然后与校验方式进行比较。如果接收到的1的数量与校验方式不匹配,则认为数据出现错误。

奇偶校验的原理是通过增加一个校验位来帮助检测单个位错误的可能性。当接收到的数据位发生错误时,校验位的值将发生变化,接收端可以通过比较校验位与数据位的奇偶性来检测错误。

奇偶校验可以提高数据传输的可靠性,但它只能检测出一位的错误,并不能纠正错误。如果发生多位错误,奇偶校验无法检测到或纠正。因此,在实际应用中,通常需要结合其他更强大的错误检测和纠正机制来保证数据的可靠性。

stm32单片机上代码实现

HAL库开发

#include "stm32f4xx_hal.h" // 包含HAL库的头文件

UART_HandleTypeDef huart2; // UART句柄对象

void SystemClock_Config(void);

int main(void) {
  // 初始化HAL库
  HAL_Init();
  
  // 配置系统时钟
  SystemClock_Config();
  
  // 使能串口时钟
  __HAL_RCC_USART2_CLK_ENABLE();

  // 配置串口参数
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 9600;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  HAL_UART_Init(&huart2);
  
  // 发送数据
  char txData[] = "Hello, World!";
  HAL_UART_Transmit(&huart2, (uint8_t*)txData, strlen(txData), HAL_MAX_DELAY);
  
  // 接收数据
  char rxData[50]; // 接收缓冲区
  HAL_UART_Receive(&huart2, (uint8_t*)rxData, sizeof(rxData), HAL_MAX_DELAY);
  
  while (1) {
    // 运行其他任务
  }
}

// 配置系统时钟
void SystemClock_Config(void) {

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
                              |RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}

上述代码使用了STM32的HAL库来简化UART通信的操作。首先,通过初始化HAL库和配置系统时钟来准备系统。然后,通过使能串口时钟、配置串口参数和初始化UART句柄对象来配置UART模块。接下来,可以使用HAL\_UART\_Transmit()函数发送数据,使用HAL\_UART\_Receive()函数接收数据。

标准库开发

#include "stm32f4xx.h"      // 包含STM32标准库的头文件

void USART2_Init(void);
void USART2_Write(char ch);
char USART2_Read(void);

int main(void) {
    USART2_Init();          // 初始化USART2
    
    // 发送数据
    USART2_Write('H');
    USART2_Write('e');
    USART2_Write('l');
    USART2_Write('l');
    USART2_Write('o');
    
    // 接收数据
    char received_data;
    while (1) {
        received_data = USART2_Read();
        // 处理接收到的数据
    }
}

// USART2初始化
void USART2_Init(void) {
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);         // 使能USART2时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);          // 使能GPIOA时钟
    
    // 配置USART2的引脚
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;        // PA2为USART2的TX引脚,PA3为USART2的RX引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;                  // 复用功能
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                // 推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;             // GPIO速度为50MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;                  // 上拉
    GPIO_Init(GPIOA, &GPIO_InitStructure);                        // 初始化GPIOA
    
    // 将引脚映射到USART2
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);     // 将PA2引脚映射到USART2的TX引脚
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);     // 将PA3引脚映射到USART2的RX引脚
    
    // 配置USART2的参数
    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate = 9600;                     // 波特率为9600
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;    // 数据位为8位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;         // 停止位为1位
    USART_InitStructure.USART_Parity = USART_Parity_No;            // 无奇偶校验
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  // 无硬件流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   // 使能接收和发送
    USART_Init(USART2, &USART_InitStructure);                      // 初始化USART2
    
    USART_Cmd(USART2, ENABLE);                                     // 使能USART2
}

// 发送数据到USART2
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数嵌入式工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

![img](https://img-blog.csdnimg.cn/img_convert/74fbd4479f4bd36aa348fd95e6738f29.png)

![img](https://img-blog.csdnimg.cn/img_convert/37ae760f70d331516bafbea3955cad72.jpeg)

![img](https://img-blog.csdnimg.cn/img_convert/875ef05dc11b653cfbd1a6734cc826df.png)

 **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**

![img](https://img-blog.csdnimg.cn/img_convert/7529173b85f5731cb251cf7c1327fb6e.png)

![img](https://img-blog.csdnimg.cn/img_convert/6fbce51541e1399dbee1a3884829024b.png)

 

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

**如果你觉得这些内容对你有帮助,可以+V:Vip1104z获取!!! (备注:嵌入式)**

<img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" />



# 最后

**资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~**

**你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!**



<img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" />



# 最后

**资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~**

**你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!**

**[更多资料点击此处获qu!!](https://bbs.csdn.net/topics/618376385)**
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值