STM32(六)串口通信-UART

一、STM32串口简介

    串口作为 MCU 的重要外部接口,同时也是软件开发重要的调试手段,其重要性不言而喻。现在基本上所有的 MCU 都会带有串口,STM32 自然也不例外。
    STM32 的串口资源相当丰富的,功能也相当强劲。ALIENTEK MiniSTM32 开发板所使用的 STM32F103RCT6 最多可提供 5 路串口,有分数波特率发生器、支持同步单线通信和半双工单线通讯、支持 LIN、支持调制解调器操作、智能卡协议和 IrDA SIR ENDEC 规范、具有 DMA等。

二、串口设置的一般步骤

1) 串口时钟使能,GPIO 时钟使能
2) 串口复位
3) GPIO 端口模式设置
4) 串口参数初始化
5) 开启中断并且初始化 NVIC(如果需要开启中断才需要这个步骤)
6) 使能串口
7) 编写中断处理函数

三、步骤详解

1. 串口时钟使能。串口是挂载在 APB2 下面的外设,所以使能函数为: 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1); 
2. 串口复位。当外设出现异常的时候可以通过复位设置,实现该外设的复位,然后重新配置,这个外设达到让其重新工作的目的。一般在系统刚开始配置外设的时候,都会先执行复位该外设的操作。复位的是在函数 USART_DeInit()中完成: 
    void USART_DeInit(USART_TypeDef* USARTx);//串口复位 
比如我们要复位串口 1,方法为: 
    USART_DeInit(USART1); //复位串口 1 
3. 串口参数初始化。串口初始化是通过 USART_Init()函数实现的, 
    void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct); 
这个函数的的第一个入口参数是指定初始化的串口标号,这里选择 USART1。 
第二个入口参数是一个 USART_InitTypeDef 类型的结构体指针,这个结构体指针的成员变量用来设置串口的一些参数。一般的实现格式为: 
    USART_InitStructure.USART_BaudRate = bound; //波特率; 
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为 8 位数据格式 
    USART_InitStructure.USART_StopBits = USART_StopBits_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); //初始化串口 
    从上面的初始化格式可以看出初始化需要设置的参数为:波特率,字长,停止位,奇偶校验位,硬件数据流控制,模式(收,发)。 
4. 数据发送与接收。STM32 的发送与接收是通过数据寄存器 USART_DR 来实现的,这是一个双寄存器,包含了 TDR 和 RDR。当向该寄存器写数据的时候,串口就会自动发送,当收到收据的时候,也是存在该寄存器内。 
STM32 库函数操作 USART_DR 寄存器发送数据的函数是: 
    void USART_SendData(USART_TypeDef* USARTx, uint16_t Data); 
通过该函数向串口寄存器 USART_DR 写入一个数据。 
STM32 库函数操作 USART_DR 寄存器读取串口接收到的数据的函数是: 
    uint16_t USART_ReceiveData(USART_TypeDef* USARTx); 
通过该函数可以读取串口接受到的数据。 
5. 串口状态。读取串口状态的函数是: 
    FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG); 
这个函数的第二个入口参数非常关键,它是标示我们要查看串口的哪种状态,操作库函数的方法是:USART_GetFlagStatus(USART1, USART_FLAG_RXNE); 
我们要判断发送是否完成(TC),操作库函数的方法是: USART_GetFlagStatus(USART1, USART_FLAG_TC); 
6. 串口使能。串口使能是通过函数 USART_Cmd()来实现的,使用方法是: 
    USART_Cmd(USART1, ENABLE); //使能串口 
7. 开启串口响应中断。有些时候当我们还需要开启串口中断,那么我们还需要使能串口中断,使能串口中断的函数是: 
    void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState) 
这个函数的第二个入口参数是标示使能串口的类型,也就是使能哪种中断,因为串口的中断类型有很多种。比如在接收到数据的时候(RXNE 读数据寄存器非空),我们要产生中断,那么我们开启中断的方法是: 
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断,接收到数据中断我们在发送数据结束的时候(TC,发送完成)要产生中断,那么方法是: USART_ITConfig(USART1,USART_IT_TC,ENABLE); 
8. 获取相应中断状态。当我们使能了某个中断的时候,当该中断发生了,就会设置状态寄存器中的某个标志位。经常我们在中断处理函数中,要判断该中断是哪种中断,使用的函数是:ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT) 
    比如我们使能了串口发送完成中断,那么当中断发生了, 我们便可以在中断处理函数中调用这个函数来判断到底是否是串口发送完成中断,方法是: 
    USART_GetITStatus(USART1, USART_IT_TC) 
返回值是 SET,说明是串口发送完成中断发生。

四、代码驱动

#include "stm32f10x.h"
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "LED.h"

void My_Uart_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);	//时钟使能

	GPIO_InitTypeDef GPIO_InitStruct;
	//uart_tx  PA9
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	//uart_rx  PA10
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;	//浮空输入
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;	//USART1中断优先级管理
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;	
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 3;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3;
	NVIC_Init(&NVIC_InitStruct);
	
	USART_InitTypeDef USART_InitStruct;
	USART_InitStruct.USART_BaudRate = 115200;		//波特率
	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_ITConfig(USART1,USART_IT_RXNE,ENABLE);	//开启接收中断
	
	USART_Cmd(USART1,ENABLE);	//串口使能
	
}

void USART1_IRQHandler(void)
{
	u8 res;
	if(USART_GetITStatus(USART1,USART_IT_RXNE))
	{
		res = USART_ReceiveData(USART1);
		USART_SendData(USART1,res);
		LED1=!LED1;
		LED0=!LED0;
		delay_ms(100);
	}
}

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断分组
	delay_init();
	LED_Init();
	My_Uart_Init();
	while(1)
	{
		LED0=!LED0;
	}
}

猜你喜欢

转载自blog.csdn.net/qq_40818798/article/details/79463569