通信接口之UART

概念

UART——通用异步收发传输器,UART 作为异步串口通信协议的一种,工作原理是将传输数据的每个字符一位接一位地传输。在应用程序开发过程中使用频率较高的数据总线。

USART——通用同步异步收发器,是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。

串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通信的端口,这些参数必须匹配一致。
在这里插入图片描述

波特率
这是一个衡量符号传输速率的参数。指的是信号被调制以后在单位时间内的变化,即单位时间内载波参数变化的次数,如每秒钟传送240个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位),这时的波特率为240Bd,比特率为10位*240个/秒=2400bps。一般调制速率大于波特率,比如曼彻斯特编码。常见使用的波特率有4800、9600和115200

数据位
这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据往往不会是8位的,标准的值是6、7和8位。如何设置取决于你想传送的信息。比如,标准的ASCII码是0~127(7位)。扩展的ASCII码是0~255(8位)。如果数据使用简单的文本(标准 ASCII码),那么每个数据包使用7位数据。每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。

停止位
用于表示单个包的最后一位。典型的值为1,1.5和2位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。

奇偶校验位
在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位。例如,如果数据是011,那么对于偶校验,校验位为0,保证逻辑高的位数是偶数个。如果是奇校验,校验位为1,这样就有3个逻辑高位。高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。这样使得接收设备能够知道一个位的状态,有机会判断是否有噪声干扰了通信或者是否传输和接收数据是否不同步。

UART异步通信方式引脚连接方式

RXD:数据输入引脚。用于接受数据
TXD:数据发送引脚。用于发送数据

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

STM32串口通信过程

数据接收过程
在这里插入图片描述
数据发送过程
在这里插入图片描述

实现UART之固件库版

具有UART功能的引脚列表

在这里插入图片描述

UART中断请求

在这里插入图片描述

使用到的库函数(省略入口参数)

void USART_Init(); //串口初始化:波特率,数据字长,奇偶校验,硬件流控以及收发使能
void USART_Cmd(); //使能串口
void USART_ITConfig(); //使能相关中断

void USART_SendData(); //发送数据到串口,DR
uint16_t USART_ReceiveData(); //接受数据,从DR读取接受到的数据

FlagStatus USART_GetFlagStatus(); //获取状态标志位
void USART_ClearFlag(); //清除状态标志位
ITStatus USART_GetITStatus(); //获取中断状态标志位
void USART_ClearITPendingBit(); //清除中断状态标志位

在这里使用PD5和PD6引脚来实现USART2

1、配置GPIO_InitTypeDef结构体并且初始化

    GPIO_InitTypeDef GPIO_InitStructure;

    //TX发送端
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP; //复用推挽输出
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_5; //PD5
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置频率,不一定要设置为50MHz
	GPIO_Init(GPIOD, &GPIO_InitStructure); //初始化配置GPIO结构体
	
	//RX接收端
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_6; //PD6
	GPIO_Init(GPIOD, &GPIO_InitStructure); //初始化配置GPIO结构体
	
	GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE); //引脚复用映射
	

2、使能时钟


    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //使能USART2时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); //使能GPIOD时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //使能GPIO复用功能时钟
    

3、配置USART_InitTypeDef结构体并且初始化

USART_InitTypeDef结构体成员解释

typedef struct
{
  uint32_t USART_BaudRate;  //波特率          
  uint16_t USART_WordLength;  //字长       
  uint16_t USART_StopBits;  //停止位          
  uint16_t USART_Parity;  //奇偶校验位            
  uint16_t USART_Mode;  //模式              
  uint16_t USART_HardwareFlowControl;  //硬件流控制
  
} USART_InitTypeDef;

具体配置代码

    USART_InitTypeDef USART_InitStructure;

	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //模式配置为同时支持接收和发送
	USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
	USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止位
	USART_InitStructure.USART_BaudRate = bound; //波特率为初始化串口时,所传的参数
	USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长设置为8位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控制
	USART_Init(USART2, &USART_InitStructure); //初始化配置USART2结构体
	

4、配置NVIC_InitTypeDef结构体并且初始化(中断配置)

	NVIC_InitTypeDef NVIC_InitStructure;

	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //配置USART2为中断源
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢断优先级
	NVIC_Init(&NVIC_InitStructure); //初始化配置NVIC
	

5、开启USART2和使能USART2中断服务

	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //使能USART2中断服务
	USART_Cmd(USART2, ENABLE); //开启USART2

6、配置USART2中断服务函数

其中实现的是将接收到的消息又发送回去,即在串口调试助手中发送什么消息,就返回发送什么消息

void USART2_IRQHandler(void)
{
	while(USART_GetFlagStatus(USART2, USART_IT_RXNE) != RESET){//接收到消息时
		uint16_t messg;
		messg = USART_ReceiveData(USART2); //将接收到的消息赋值给messg
		
		USART_SendData(USART2, messg); //将messg发送出去
		while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET); //等待发送完成
		
		USART_ClearITPendingBit(USART2, USART_IT_RXNE); //清除USART2中断状态
	}
	
}

整体代码

void uartInit(u32 bound)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //使能USART2时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); //使能GPIOD时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //使能GPIO复用功能时钟

    //TX发送端
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP; //复用推挽输出
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_5; //PD5
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置频率,不一定要设置为50MHz
	GPIO_Init(GPIOD, &GPIO_InitStructure); //初始化配置GPIO结构体
	
	//RX接收端
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_6; //PD6
	GPIO_Init(GPIOD, &GPIO_InitStructure); //初始化配置GPIO结构体
	
	GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE); //引脚复用映射

	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //模式配置为同时支持接收和发送
	USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
	USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止位
	USART_InitStructure.USART_BaudRate = bound; //波特率为初始化串口时,所传的参数
	USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字长设置为8位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控制
	USART_Init(USART2, &USART_InitStructure); //初始化配置USART2结构体

	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //配置USART2为中断源
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢断优先级
	NVIC_Init(&NVIC_InitStructure); //初始化配置NVIC

	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //使能USART2中断服务
	USART_Cmd(USART2, ENABLE); //开启USART2
}

void USART2_IRQHandler(void)
{
	while(USART_GetFlagStatus(USART2, USART_IT_RXNE) != RESET){//接收到消息时
		uint16_t messg;
		messg = USART_ReceiveData(USART2); //将接收到的消息赋值给messg
		
		USART_SendData(USART2, messg); //将messg发送出去
		while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET); //等待发送完成
		
		USART_ClearITPendingBit(USART2, USART_IT_RXNE); //清除USART2中断状态
	}
	
}

测试demo

#include "stm32f10x.h"
#include "uart.h"

int main()
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	uartInit(115200);
	while(1)
	{
		
	}
	
}

实现自己的发送字符和字符串函数

void myUartSendByte(USART_TypeDef* USARTx, uint16_t Data)
{
	USART_SendData(USARTx, (u8)Data);
	while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) == RESET);
}

void myUartSend(USART_TypeDef* USARTx, const char* messg)
{
	uint16_t i;
	uint16_t len = strlen(messg);

	for(i=0; i<len; i++)
	{
		USART_SendData(USARTx, (u8)messg[i]);
		while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == RESET);
	}
	
}

重定向printf

由于printf本身就是在调用fputc函数,所以直接对fputc进行重定义即可

int fputc(int ch, FILE* f)
{
	USART_SendData(USART2, (u8)ch);
	while(USART_GetFlagStatus(USART2,USART_FLAG_TXE) == RESET);
	
	return ch;
}

记得勾选魔术棒->Target里的Use MicroLIB
在这里插入图片描述

正点原子接收字符串的中断代码

首先需要定义三个变量
#define USART2_REC_LEN 200 //自定义最大接收字节数
u8 USART2_RX_BUF[USART2_REC_LEN]; //接收缓冲
u16 USART2_RX_STA=0; //接受状态标记
在这里插入图片描述

其中的0x0d0x0a分别是回车和换行的符号:\r \n

void USART2_IRQHandler(void)
{
	u8 r;
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收中断
	{
		r =USART_ReceiveData(USART2);//(USART1->DR);	//读取接收到的数据
		if((USART2_RX_STA&0x8000)==0)//接收未完成
		{
			if(USART2_RX_STA&0x4000)//接收到了0x0d
			{
				if(r!=0x0a)USART2_RX_STA=0;//接受错误,重新开始
				else USART2_RX_STA|=0x8000;	//接收完成了
			}
			else //还未接收到0xd
			{	
				if(r==0x0d)USART2_RX_STA|=0x4000;
				else
				{
					USART2_RX_BUF[USART2_RX_STA&0X3FFF]=r;
					USART2_RX_STA++;

					//接收数据错误,重新接收  
					if(USART2_RX_STA>(USART2_REC_LEN-1))USART2_RX_STA=0;
				}		 
			}
		}   		 
	}
}

UART相关寄存器

1、**USART_GetITStatus()**函数(省去参数),就是对该寄存器进行访问
在这里插入图片描述
2、USART_ReceiveData()函数和USART_SendData()函数(省去参数),就是对该寄存器进行访问
在这里插入图片描述
3、用于
配置波特率
的寄存器
在这里插入图片描述
波特率的配置方法
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值