当前位置: 首页 > news >正文

一文学会标准库USART

USART全解

提示:本文使用开发板是STM32f103vet6,本文使用代码承接上一张


`

文章目录

  • USART全解
  • 题目重述
    • 1. USART模块简介
      • 4,USART 通信
    • 2. USART的基本用法
    • 3. 移位寄存器和串并转换
    • 4. 数据帧格式的设置方法
    • 5. 波特率的设置方法
    • 6. 编程接口
        • 7,USART 框图
        • 8,USART 常用 API
        • 9,软件设计流程
        • 10,代码模块(usart串口输入)
        • 11,代码模块(usart数据处理)
      • 12,开发板链接


题目重述

请根据提供的目录内容,逐步简单解释如何理解串口(USART)的使用,包括发送和接收数据,以及奇校验和偶校验的设置。


1. USART模块简介

4,USART 通信

USART 通用同步、异步收发。如果芯片支持时钟同步,则称 USART,如果没有就是 UART。

UART 包含 TxD 发送线,RxD 接收线两根数据线,TxD 与 RxD 交叉连接。全双工、异步、串行通信。

一帧包含:起始位 + 数据位 + 奇偶校验位 + 停止位。
在这里插入图片描述

起始位:信号由高变到低并且维持一个位的低电平,称为起始位。

数据位:LSB 低位先出,0 低电平,1 高电平,逐位发送。有 8 位和 9 位。

奇偶校验位:用于检验数据是否出错。分奇校验、偶校验、无校验。

​ 奇校验是指数据位中 1 的个数如果是奇数个,则为 0,否则为 1;

​ 偶校验是指数据位中 1 的个数如果是偶数个,则为 0,否则为 1。

​ 无校验即不使用校验位。

停止位:数据位和奇偶校验位结束后,总线变为高电平,并且维持 1 位、1.5 位、2 位等位数的高电平。

空闲状态:总线处于高电平定义为空闲状态。

波特率:每秒传输的位数,单位 bps。常见的 9600,115200。

硬件流控:

接收方的 nRTS 引脚与发送方的 nCTS 连接,当接收方将 nRTS 拉高电平时,发送方检测到 nCTS 高电平就暂停发送;

当接收方将 nRTS 拉低电平,发送方检测到 nCTS 低电平就继续发送。

这样即可实现总线上数据流量的控制。流控是由接收方控制的。
在这里插入图片描述

串口的配置:

在这里插入图片描述


2. USART的基本用法

要使用串口通信,需配置以下内容:

  • 设置数据传输的波特率(如9600、115200,表示每秒传多少位)
  • 设定数据长度(通常是8位)
  • 选择是否启用校验位(奇校验或偶校验)
  • 设置停止位个数(1或2)

发送和接收通过TX(发送引脚)和RX(接收引脚)完成。


3. 移位寄存器和串并转换

  • 并行数据:多个位同时传输(如8根线一起传)
  • 串行数据:一位一位传(只需1根线)

移位寄存器负责转换:

  • 发送时:把并行数据(如一个字节)→ 一位位移出(串行)
  • 接收时:把收到的串行数据 → 汇集成一个字节(并行)

4. 数据帧格式的设置方法

数据帧是一次传输的基本单位,结构如下:

起始位数据位(8位)校验位(可选)停止位
1位D0~D71位1~2位

设置示例:8-N-1 表示 8位数据、无校验、1位停止位
若为8-E-1:表示偶校验;8-O-1:奇校验


5. 波特率的设置方法

波特率 = 每秒传输的位数(如115200 bit/s)

  • 双方设备必须设置相同波特率才能正确通信

  • 单片机通过内部定时器或波特率发生器生成该时钟

  • 计算公式:
    分频值=系统时钟16×波特率\text{分频值} = \frac{\text{系统时钟}}{16 \times \text{波特率}} 分频值=16×波特率系统时钟


6. 编程接口

这是软件如何控制USART的方式:

  • 初始化配置(波特率、数据位、校验位等)
  • 发送函数:将数据写入发送寄存器,硬件自动发送
  • 接收函数:从接收寄存器读取收到的数据
  • 中断或轮询方式处理数据

7,USART 框图

数据从 TDR 移入 发送移位寄存器后,硬件就将 TXE 标志置 1,此时并不表示数据发送完成,只表示 TDR 空了,可以发送下一个数据了。

什么时候才发送完成?当停止位发送完成后,TC 标志置 1。TC 标志表示数据发送完成。

当接收移位寄存器中收满数据后,硬件自动将数据移入 RDR 寄存器,并将 RXNE 标志置 1,表示接收到了数据。

当一帧数据传输完毕,没有下一帧数据要继续发送,此时总线处于空闲状态,产生一次空闲标志 IDLE。之后持续空闲,不会重复产生空闲标志。除非下一次传输完毕空闲,才会再次产生空闲标志。

在这里插入图片描述

8,USART 常用 API
// 初始化
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
// 使能/禁用
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);// DMA 使能/禁用
void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState);// 发送、接收数据
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);// 中断配置
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);
// 获取/清除状态
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
9,软件设计流程

在这里插入图片描述

10,代码模块(usart串口输入)
//main.c#include "stm32f10x.h"
#include <stdio.h>
#include "gpio.h"
#include "delay.h"
#include "exti.h"
#include "usart.h"uint8_t SendData[] = {"指针跳跃!\r\n"};int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);MX_GPIO_Init();delay_Init();MX_EXTIO_Init( 3, 3);MX_USART1_Init(115200);MX_USART1_NVIC_Init(2,0);for(uint16_t i=0;i<sizeof(SendData);i++){USART_ClearFlag(USART1, USART_FLAG_TC); //清楚发送完成标志位USART_SendData(USART1,SendData[i]);     //按位发送while(USART_GetFlagStatus( USART1, USART_FLAG_TC ) == RESET){} //等待发送}while(1)
{GPIO_WriteBit(GPIOC,GPIO_Pin_6  ,Bit_RESET);//输出低电平delay_ms(300);	GPIO_WriteBit(GPIOC,GPIO_Pin_6 ,Bit_SET);  //输出高电平delay_ms(300);	}}
//usart.h
#ifndef _USART_H_
#define _USART_H_#include "stm32f10x.h"
#include <stdio.h>void MX_USART1_Init(uint32_t Baud);
void MX_USART1_NVIC_Init(uint8_t Preemption,uint8_t Sub);#endif
//usart.c
#include "usart.h"void MX_USART1_Init(uint32_t Baud)
{
//-------------------------------------GPIO Init-------------------------------------------//GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  ,ENABLE);      //使能時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 ,ENABLE);     //使能時鐘//PA0  TXGPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;              //輸出复用推挽GPIO_InitStruct.GPIO_Pin =  GPIO_Pin_9;                    //選擇PINGPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,  &GPIO_InitStruct);//PA10   RXGPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;                 //上拉模式GPIO_InitStruct.GPIO_Pin =  GPIO_Pin_10;                   //選擇PINGPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,  &GPIO_InitStruct);USART_Cmd(USART1,ENABLE);																	//使用串口//-------------------------------------USART Init-------------------------------------------//USART_InitTypeDef USART_InitStruct;USART_InitStruct.USART_BaudRate              = Baud;                            //波特率USART_InitStruct.USART_HardwareFlowControl   = USART_HardwareFlowControl_None; //硬件流控制USART_InitStruct.USART_Mode                  = USART_Mode_Rx | USART_Mode_Tx;  //使用串口收发模式USART_InitStruct.USART_Parity                = USART_Parity_No;                //不校验USART_InitStruct.USART_StopBits              = USART_StopBits_1 ;              //停止位1位USART_InitStruct.USART_WordLength            = USART_WordLength_8b;            //数据位为8位USART_Init(USART1, & USART_InitStruct);USART_Cmd( USART1, ENABLE);}void MX_USART1_NVIC_Init(uint8_t Preemption,uint8_t Sub)
{//-------------------------------------NVIC Init-------------------------------------------//NVIC_InitTypeDef NVIC_InitStruct;USART_ITConfig( USART1, USART_IT_RXNE ,ENABLE);USART_ITConfig( USART1,  USART_IT_RXNE, ENABLE);NVIC_InitStruct.NVIC_IRQChannel                    = USART1_IRQn; //外部中断线0NVIC_InitStruct.NVIC_IRQChannelCmd								 = ENABLE;   //使能中断NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority  = Preemption; //抢占优先级NVIC_InitStruct.NVIC_IRQChannelSubPriority         = Sub;  //响应优先级NVIC_Init(& NVIC_InitStruct);}void USART1_IRQHandler(void)
{uint8_t res;if (USART_GetITStatus( USART1,USART_IT_RXNE) != RESET){res = USART_ReceiveData(USART1);USART_SendData(USART1,res);    //按下发送}}
11,代码模块(usart数据处理)
//main.c
#include "stm32f10x.h"
#include <stdio.h>#include "gpio.h"
#include "delay.h"
#include "exti.h"
#include "usart.h"uint8_t SendData[] = {"指针跳跃!\r\n"};int main(void)
{uint32_t Led_ts = 0;BitAction BitVal = Bit_SET;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);MX_GPIO_Init();delay_Init();MX_EXTIO_Init( 3, 3);MX_USART1_Init(115200);MX_USART1_NVIC_Init(2,0);//		for(uint16_t i=0;i<sizeof(SendData);i++)
//		{
//			USART_ClearFlag(USART1, USART_FLAG_TC); //清楚发送完成标志位
//			USART_SendData(USART1,SendData[i]);     //按位发送
//			while(USART_GetFlagStatus( USART1, USART_FLAG_TC ) == RESET){} //等待发送
//		}printf("%s",SendData);while(1)
{if(U1RX_IDLE_FLAG == 1 ){printf("Recv[%d];%s",U1RX_LEN,U1RX_DATA);if(strncmp(U1RX_DATA,"启动蜂鸣器",10) == 0){GPIO_WriteBit(GPIOC ,GPIO_Pin_9, Bit_RESET);}else if(strncmp(U1RX_DATA,"关闭",4) == 0){GPIO_WriteBit(GPIOC ,GPIO_Pin_9, Bit_SET);}if(strncmp(U1RX_DATA,"启动绿灯",8) == 0){GPIO_WriteBit(GPIOC ,GPIO_Pin_7 , Bit_RESET);}else if(strncmp(U1RX_DATA,"关绿灯",6) == 0){GPIO_WriteBit(GPIOC ,GPIO_Pin_7, Bit_SET);}if(strncmp(U1RX_DATA,"启动红灯",8) == 0){GPIO_WriteBit(GPIOC ,GPIO_Pin_8 , Bit_RESET);}else if(strncmp(U1RX_DATA,"关红灯",6) == 0){GPIO_WriteBit(GPIOC ,GPIO_Pin_8, Bit_SET);}memset(U1RX_DATA,0,U1RX_MAX_LEN);U1RX_IDLE_FLAG = 0;U1RX_LEN = 0;}if((GetTick() - Led_ts) > 1000){BitVal = (BitAction)! BitVal;GPIO_WriteBit(GPIOC,GPIO_Pin_6 , BitVal);Led_ts = GetTick();}}}
//usart.h
#ifndef _USART_H_
#define _USART_H_#include "stm32f10x.h"
#include <stdio.h>
#include <stdbool.h>
#include <string.h>void MX_USART1_Init(uint32_t Baud);
void MX_USART1_NVIC_Init(uint8_t Preemption,uint8_t Sub);#define  U1RX_MAX_LEN  128extern char  U1RX_DATA[ U1RX_MAX_LEN ];
extern uint8_t U1RX_LEN;
extern bool U1RX_IDLE_FLAG ;#endif
//usart.c
#include "usart.h"char U1RX_DATA[ U1RX_MAX_LEN] = { 0 };
uint8_t U1RX_LEN;
bool U1RX_IDLE_FLAG = 0;void MX_USART1_Init(uint32_t Baud)
{
//-------------------------------------GPIO Init-------------------------------------------//GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  ,ENABLE);      //使能時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 ,ENABLE);     //使能時鐘//PA0  TXGPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;              //輸出复用推挽GPIO_InitStruct.GPIO_Pin =  GPIO_Pin_9;                    //選擇PINGPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,  &GPIO_InitStruct);//PA10   RXGPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;                 //上拉模式GPIO_InitStruct.GPIO_Pin =  GPIO_Pin_10;                   //選擇PINGPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,  &GPIO_InitStruct);USART_Cmd(USART1,ENABLE);																	//使用串口//-------------------------------------USART Init-------------------------------------------//USART_InitTypeDef USART_InitStruct;USART_InitStruct.USART_BaudRate              = Baud;                            //波特率USART_InitStruct.USART_HardwareFlowControl   = USART_HardwareFlowControl_None; //硬件流控制USART_InitStruct.USART_Mode                  = USART_Mode_Rx | USART_Mode_Tx;  //使用串口收发模式USART_InitStruct.USART_Parity                = USART_Parity_No;                //不校验USART_InitStruct.USART_StopBits              = USART_StopBits_1 ;              //停止位1位USART_InitStruct.USART_WordLength            = USART_WordLength_8b;            //数据位为8位USART_Init(USART1, & USART_InitStruct);USART_Cmd( USART1, ENABLE);       //闭合总开关}void MX_USART1_NVIC_Init(uint8_t Preemption,uint8_t Sub)
{//-------------------------------------NVIC Init-------------------------------------------//USART_ITConfig( USART1, USART_IT_RXNE ,ENABLE);//配置中断RXNEUSART_ITConfig( USART1, USART_IT_IDLE ,ENABLE); //配置中断IDLE//配置中断USART_ITConfig( USART1,  USART_IT_RXNE, ENABLE);//配置NVICNVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel                    = USART1_IRQn; //外部中断线0NVIC_InitStruct.NVIC_IRQChannelCmd								 = ENABLE;   //使能中断NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority  = Preemption; //抢占优先级NVIC_InitStruct.NVIC_IRQChannelSubPriority         = Sub;  //响应优先级NVIC_Init(& NVIC_InitStruct);}void USART1_IRQHandler(void)
{if (USART_GetITStatus( USART1,USART_IT_RXNE) != RESET){uint8_t res= USART_ReceiveData(USART1);if( U1RX_LEN <U1RX_MAX_LEN){U1RX_DATA [U1RX_LEN++] =USART_ReceiveData(USART1);}else{U1RX_IDLE_FLAG = 1;                 //超过最大接受长度。强制处理接收数据}}if(USART_GetITStatus( USART1,USART_IT_IDLE) != RESET){USART1 ->SR;                         //先读  SR   清楚IDEL中断标志位USART1->DR;			                     //再度DR    清楚IDEL中断标志位U1RX_IDLE_FLAG = 1;                  //置位空闲中断接受标志位,以处理数据}		
}//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ int handle; 
}; FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ x = x; } //重定义fputc函数 
int fputc(int ch, FILE *f)
{      while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   USART1->DR = (u8) ch;      return ch;
}
#endif 

12,开发板链接

本文章所使用开发板链接:https://pointerleap.taobao.com/

http://www.dtcms.com/a/515649.html

相关文章:

  • 5-6〔OSCP ◈ 研记〕❘ SQL注入攻击▸自动化工具SQLMap
  • Linux进程间通信:深入解析PV操作及其同步机制
  • Servlet 实例详解
  • 个人备案网站盈利动画制作网页
  • 网站建设饱和了吗上海市建设市场信息服务平台
  • 个人备案域名做企业网站wow slider wordpress
  • 【OPENGL ES 3.0 学习笔记】第九天:缓存、顶点和顶点数组
  • 2510rs,rust,1.85
  • 深度学习(13)-PyTorch 数据转换
  • rocketmq实现取消超时订单?兜底方案?
  • Linux如何安装使用Rust指南
  • 田块处方图可视化(PyQt5)
  • Rust算法复杂度-大O分析
  • 2510rs,rust清单4
  • 大型网站开发考试移动商城的推广方法
  • FastAPI之 自动化的文档
  • 日常开发20251022,传统HTML表格实现图片+视频+预览
  • 标题:鸿蒙Next音频开发新篇章:深入解析Audio Kit(音频服务)
  • 湖滨区建设局网站app开发公司排行榜做软件的公司
  • UDP实现客服与客户的咨询对话
  • 学习HAL库STM32F103C8T6(实时时钟项目、WIFI天气预报项目)
  • npm、yarn、pnpm的对比和优略
  • 离散卷积,小demo(小波信号分析)
  • Java 大视界 -- Java 大数据在智能教育学习社区互动模式创新与用户活跃度提升中的应用(426)
  • 建设比较好网站服务器用来做网站和数据库
  • C# iText7与iTextSharp导出PDF对比
  • HARDWARE 属性的Bitmap与普通Bitmap,GPU与RenderThread渲染与处理方式异同比较,Android
  • 东营市做网站的公司h5学习教程
  • 不同类型的金融产品(如股票、期货、加密货币)双时间尺度优化的差异化调整
  • xtuoj Repeat One