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

10 通用同步异步收发器(USART)

10.1 通信基本概念

10.1.1 并行通信和串行通信

1、处理器与外部设备通信的两种方式:

串行通信有两种通信方式:

并行通信:
-传输原理:数据各个位同时传输。
-优点:速度快
-缺点:占用引脚资源多
并行通信

串行通信 -传输原理:
串行通信方式有 UART USB IIC SPI CAN 以太网等都是采用串行通信方式。
数据按位顺序传输。
-优点:占用引脚资源少
-缺点:速度相对较慢
串行通信
不过这两种通信方式是可以转换的,如图串行转并行:
串行转并行

有关两者优缺点:
对比

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

按照数据传送方向,分为:
单工:
数据传输只支持数据在一个方向上传输;
半双工:
允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;
全双工:
允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。

在这里插入图片描述

11.1.3 同步通信和异步通信

在这里插入图片描述

1、同步通信:带时钟同步信号传输。

在这里插入图片描述

2、 异步通信:不带时钟同步信号。

在这里插入图片描述

10.1.4 RS-232

1、RS232标准串口通讯结构图

在这里插入图片描述
在这里插入图片描述

2、原生的串口通信

在这里插入图片描述

10.1.5 串口数据帧格式

1、串口数据包的基本组成

在这里插入图片描述

2、奇偶校验

在这里插入图片描述

10.2 STM32F429 USART结构

10.2.1 概述


10.2.2 USART结构

在这里插入图片描述
在这里插入图片描述

2、数据通道

在这里插入图片描述

3、发送器

在这里插入图片描述
在这里插入图片描述

4、接收器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

10.2.3 波特率设置

在这里插入图片描述
在这里插入图片描述

10.2.4 DMA控制

接收缓冲区和发送缓冲区的DMA请求是独立的,它们分别对应于独立的DMA通道。

1.使用DMA进行发送

 将USART控制寄存器3(USART_CR3)中的DMAT位置1可以使能DMA模式进行发送。
 一旦使能了USART的DMA功能,当TXE 位置1时,
 控制器会将数据自动从SRAM区加载到USART_DR,启动发送过程。
 所有数据的发送不需要通过程序干涉。

2.使用DMA进行接收

将USART_CR3中的DMAR位置1可以使能DMA模式进行接收。一旦使能了USART的DMA功能,当接收数据时,RXNE
位置1时,控制器会将数据会从USART_DR自动加载到SRAM区域中。整个数据的接受过程不需要程序的干涉。

10.3 USART典型应用步骤及常用库函数

10.3.1 串口配置一般步骤

在这里插入图片描述
在这里插入图片描述

10.3.2 常用库函数说明

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

10.4 应用实例

10.4.1 通过串口向计算机传输100个字节

使用串口线把计算机和电路板的USART1连接在一起,如图11-15所示。编写程序,通过USART1向计算机发送100个字节,这一功能可以通过查询方式、中断方式或中断方式实现。这里以常用的查询方式实现这一功能。

USART1配置参数:
波特率=115 200、
有效数据位=8位、
停止位=1位、
不使用校验方式、
收发模式、
不使用硬件流控。
USART1的TXD和RXD分别使用PA9和PA10。

1.编程要点

(1)使能USART1和复用引脚GPIO的工作时钟。
(2)初始化USART1 相关GPIO引脚,并将引脚复用给USART1。

(3)根据要求,初始化USART1。使用查询方式发送数据。
(4)使能USART1。
(5)循环发送100个字节。

2.主程序

int main(void)
{	
    uint16_t  i;	
    /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
    USART1_Config();
    for(i=0;i<100;i++)//循环发送100个x
   {
      /*发送一个字符x*/
      USART_SendData(USART1, ‘x’);
      /*等待发送数据寄存器为空 ,只有在发送数据寄存器为空的情况下,才能发送下一个字符*/
      while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);	
   }
      while(1)}

3. 串口配置函数

void USART_Config(void)
{
 GPIO_InitTypeDef GPIO_InitStructure;
 USART_InitTypeDef USART_InitStructure;
 /*-------------------第1步--------------------*/
 /*使能 GPIOA时钟*/
 RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA,ENABLE);
 /*使能 UART1 时钟*/
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
 
 /*-------------------第2步--------------------*/
 /*复用PA9到USART1*/
 GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
 /*复用PA10到USART1*/
 GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
 /*配置TX引脚为复用功能*/
 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //复用模式
 GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
 GPIO_Init(GPIOA,&GPIO_InitStructure);
 
  /*配置RX引脚为复用功能*/
 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF ; 	//复用模式
 GPIO_Init(GPIOA,&GPIO_InitStructure);
 /*-------------------第3步--------------------*/
 /*配置USART1模式*/
 USART_InitStructure.USART_BaudRate = 115200; //波特率
 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(USART1, &USART_InitStructure); 	//初始化USART1
  /*因为使用查询方式发送数据,没有用到中断,因此没有中断相关配置,缺少第4步*/
 /*-------------------第5步--------------------*/
 USART_Cmd(USART1, ENABLE);//使能USART1
}

10.4.2 串口与计算机回显功能实现

回显功能就是把计算机发送给电路板上微控制器的数据通过串口原样返回给计算机,并显示在串口显示软件中。
USART1配置参数:
波特率=115 200、
有效数据位=8位、
停止位=1位、
不使用校验方式、
收发模式、
不使用硬件流控。

USART1的TXD和RXD分别使用PA9和PA10。

1.编程要点

(1)使能USART1和复用引脚GPIO的时钟。
(2)初始化USART1 相关GPIO引脚,并将引脚复用给USART1。
(3)根据要求初始化USART1。
(4)初始化NVIC的USART1串口中断通道,并使能USART1的读取数据寄存器不为空中断(RXNE)。
(5)使能USART1。
(6)编写中断服务程序。

2.主程序

int main(void)
{
 USART_Config(); //初始化USART1
 printf("这是一个串口中断接收回显实验\n");//注意只有对printf函数进行重定向才能使用
 while(1);
}

3. 串口配置函数

void USART_Config(void)
{
 GPIO_InitTypeDef GPIO_InitStructure;
 USART_InitTypeDef USART_InitStructure;
 /*-------------------第1步--------------------*/
 /*使能 GPIOA时钟*/
 RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA,ENABLE);
 /*使能 UART1 时钟*/
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
 
 /*-------------------第2步--------------------*/
 /*复用PA9到USART1*/
 GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
 /*复用PA10到USART1*/
 GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
 /*配置TX引脚为复用功能*/
 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //复用模式
 GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
 GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
 GPIO_Init(GPIOA,&GPIO_InitStructure);
 
  /*配置RX引脚为复用功能*/
 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF ; 	//复用模式
 GPIO_Init(GPIOA,&GPIO_InitStructure);
 /*-------------------第3步--------------------*/
 /*配置USART1模式*/
 USART_InitStructure.USART_BaudRate = 115200; //波特率
 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(USART1, &USART_InitStructure); 	//初始化USART1
 /*-------------------第4步--------------------*/
 //初始化NVIC中的USART1中断通道
 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //选择NVIC组2
 NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn; //配置USART为中断源
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; //抢占优先级为1
 NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;	//响应优先级为1
 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; 	//使能中断 
 NVIC_Init(&NVIC_InitStructure); //初始化配置NVIC 
 //使能串口的RXNE中断
 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //使能串口的RXNE中断
 
 /*-------------------第5步--------------------*/
 USART_Cmd(USART1,ENABLE);		//使能USART1
}

4.串口中断服务函数

void USART1_IRQHandler(void)
{
    uint8_t ucTemp;
    if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) //检测RXNE标志位
    {		
      ucTemp = USART_ReceiveData( USART1 ); //读取接收数据
      USART_SendData(USART1,ucTemp);  //把数据发送给计算机,实现回显功能  
    }	 
}

5. printf函数重定向

使用printf函数通过USART1向计算机的串口调试助手打印数据,需要将printf函数内部实现功能重定向到微控制器的USART1。
(1)设置Keil MDK软件中的Use MicroLIB选项。
(2)重定向fputc函数。

2)重定向fputc函数。
int fputc(int ch, FILE* stream)
{
//通过串级发送数据ch
USART_SendData(USART1, (uint8_t) ch);      

while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送完毕 

return ch;
}

10.4.3 利用DMA通过串口向计算机1000个字节

利用DMA通过USART1向计算机传输1000个字节,一旦配置好USART1和DMA数据流,在启动DMA传输之后,不需要程序的干预,即可完成数据传输

USART1配置参数:波特率=115 200、有效数据位=8位、停止位=1位、不使用校验方式、收发模式、不使用硬件流控。

1.编程要点

(1)使能USART1、复用引脚GPIO及DMA2的时钟。
(2)初始化USART1相关GPIO引脚,并将引脚复用给USART1。
(3)根据要求,初始化并使能USART1。
(4)初始化DMA2数据流7的通道4,并使能DMA2数据流7。
(5)使能USART1的DMA发送功能,启动DMA数据传输。

2、主程序

uint8_t Send_Buff[1000]; //DMA传输数据源存储区
int main(void)
{
  uint16_t i;
  USART_Config();  			//初始化USART1
  DMA_Config();  					//初始化DMA
  for(i=0;i<SENDBUFF_SIZE;i++) 	//初始化DMA传输数据源存储区
  {
    Send_Buff [i]	 = 'Z';
  }
  /*使能USART1的DMA发送,启动DMA数据传输*/
  USART_DMACmd(USART1, USART_DMAReq_Tx,ENABLE);	//关键
  while(1);  			//无须CPU干涉,实现数据传输
}

3. 串口配置函数

同10.4.1串口配置函数。

4. DMA配置函数

extern uint8_t Send_Buff[1000]; //DMA传输数据源存储区
void DMA_Config(void)
{
 DMA_InitTypeDef  DMA_InitStructure;
 /*-------------------第1步--------------------*/
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE); //使能DMA2时钟
  
 /*-------------------第2步--------------------*/
 DMA_DeInit(DMA2_Stream7); 	//复位,禁止DMA2数据流7
  while (DMA_GetCmdStatus(DMA2_Stream7)!= DISABLE); //确保DMA数据流禁止成功
  /*-------------------第3步--------------------*/
 /*初始化DMA2数据流7*/
  DMA_InitStructure.DMA_Channel=DMA_Channel_7; //选择通道
  DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t) SRC_Buffer;//目标地址
  DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t) Send_Buff; //源数据地址
  DMA_InitStructure.DMA_DIR=DMA_DIR_MemoryToPeripheral; //存储器到外设模式
  DMA_InitStructure.DMA_BufferSize=1000; 	//DMA传输数据数目
  //禁止自动递增功能
  DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;          
  DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable; //使能自动递增功能
  //8位数据宽度
  DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize=DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_Mode=DMA_Mode_Normal; //正常模式,不循环,只传输一次 
DMA_InitStructure.DMA_Priority=DMA_Priority_High;//设置DMA2数据流7优先级为高
DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable; //禁用FIFO模式 
//此时这一参数无用
DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single; 	//单次模式
DMA_InitStructure.DMA_PeripheralBurst=DMA_MemoryBurst_Single; //单次模式
DMA_Init(DMA2_Stream7,&DMA_InitStructure); //完成DMA2数据流7配置 
/*-------------------第4步--------------------*/
 DMA_Cmd(DMA2_Stream7,ENABLE); 	//使能DMA2数据流7,启动DMA数据传输
  
 /*-------------------第5步--------------------*/
 while (DMA_GetCmdStatus(DMA2_Stream7)!=ENABLE);   //检测DMA数据流是否有效
}

相关文章:

  • AI绘图—对中文拟合度很高,值得一试
  • 【 C++11 】包装器
  • 【动手学深度学习PyTorch版】13 卷积层的填充和步幅
  • 第十三届蓝桥杯C++B组国赛H题——机房 (AC)
  • django框架技术沉淀
  • 血的教训---入侵redis并远程控制你的机器场景复现
  • 基于javaweb的养老院管理系统(java+springboot+thymeleaf+html+js+mysql)
  • 【CV】第 6 章:图像分类的实际方面
  • HazelEngine 学习记录 - Shader Asset Files
  • 网络安全—DDoS攻防
  • 【JavaWeb】之富文本编辑器
  • Synchronized底层核心原理
  • 基于JSP的房屋销售系统设计与实现
  • Arduino UNO 可视化GT-24工业级无线透传
  • 【QT 自研上位机 与 STM32F103下位机联调>>>通信测试-基础样例-联合文章】
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • 【个人向】《HTTP图解》阅后小结
  • CNN 在图像分割中的简史:从 R-CNN 到 Mask R-CNN
  • Docker 1.12实践:Docker Service、Stack与分布式应用捆绑包
  • Docker 笔记(2):Dockerfile
  • flutter的key在widget list的作用以及必要性
  • Golang-长连接-状态推送
  • hadoop集群管理系统搭建规划说明
  • Spring核心 Bean的高级装配
  • SSH 免密登录
  • unity如何实现一个固定宽度的orthagraphic相机
  • vue2.0开发聊天程序(四) 完整体验一次Vue开发(下)
  • webpack+react项目初体验——记录我的webpack环境配置
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 前端临床手札——文件上传
  • 少走弯路,给Java 1~5 年程序员的建议
  • 设计模式(12)迭代器模式(讲解+应用)
  • 实现简单的正则表达式引擎
  • 使用Gradle第一次构建Java程序
  • 为什么要用IPython/Jupyter?
  • 移动端唤起键盘时取消position:fixed定位
  • 整理一些计算机基础知识!
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • #pragma multi_compile #pragma shader_feature
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (145)光线追踪距离场柔和阴影
  • (2020)Java后端开发----(面试题和笔试题)
  • (done) NLP “bag-of-words“ 方法 (带有二元分类和多元分类两个例子)词袋模型、BoW
  • (八十八)VFL语言初步 - 实现布局
  • (二)Linux——Linux常用指令
  • (附源码)php新闻发布平台 毕业设计 141646
  • (附源码)计算机毕业设计ssm电影分享网站
  • (接口封装)
  • (七)MySQL是如何将LRU链表的使用性能优化到极致的?
  • (四)Android布局类型(线性布局LinearLayout)
  • (四)docker:为mysql和java jar运行环境创建同一网络,容器互联
  • (四)模仿学习-完成后台管理页面查询
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (正则)提取页面里的img标签