当前位置:网站首页>STM32-串口常用寄存器和库函数及配置串口步骤

STM32-串口常用寄存器和库函数及配置串口步骤

2022-08-11 05:25:00 Archimedes' boat

目录

常用的串口相关寄存器

USART_SR状态寄存器:

那么可以用如下函数来查看:

USART_DR数据寄存器:

那么可以用如下两个函数来查看和写入:

USART_BRR波特率寄存器:

那么可以用如下函数来写入波特率:

串口配置

 串口配置的一般步骤:

①时钟使能

②引脚复用映射

③GPIO端口模式设置

④串口初始化

⑤开启中断并初始化NVIC

⑥使能串口

⑦、⑧、⑨

最后上总代码


常用的串口相关寄存器

(在中文参考手册26.6 USART寄存器里面):

USART_SR状态寄存器:

串口在运行过程中的一些状态由其设定,如,发送完成后其某位为0或1的标志位。

主要用到其0~9位。

 

那么可以用如下函数来查看:

FlagStatus USART_GetFlagStatus();//获取状态标志位

 加上定义:

typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;

加上函数全代码:

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)
{
  FlagStatus bitstatus = RESET;
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  assert_param(IS_USART_FLAG(USART_FLAG));

  /* The CTS flag is not available for UART4 and UART5 */
  if (USART_FLAG == USART_FLAG_CTS)
  {
    assert_param(IS_USART_1236_PERIPH(USARTx));
  } 
    
  if ((USARTx->SR & USART_FLAG) != (uint16_t)RESET)
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }
  return bitstatus;
}

还有USART_GetFlagStatus这个函数入口参数:

#define IS_USART_ALL_PERIPH(PERIPH) (((PERIPH) == USART1) || \
                                     ((PERIPH) == USART2) || \
                                     ((PERIPH) == USART3) || \
                                     ((PERIPH) == UART4)  || \
                                     ((PERIPH) == UART5)  || \
                                     ((PERIPH) == USART6) || \
                                     ((PERIPH) == UART7)  || \
                                     ((PERIPH) == UART8))

#define IS_USART_FLAG(FLAG) (((FLAG) == USART_FLAG_PE) || ((FLAG) == USART_FLAG_TXE) || \
                             ((FLAG) == USART_FLAG_TC) || ((FLAG) == USART_FLAG_RXNE) || \
                             ((FLAG) == USART_FLAG_IDLE) || ((FLAG) == USART_FLAG_LBD) || \
                             ((FLAG) == USART_FLAG_CTS) || ((FLAG) == USART_FLAG_ORE) || \
                             ((FLAG) == USART_FLAG_NE) || ((FLAG) == USART_FLAG_FE))

我们可以看到最后会返回SET或者RESET这两个值,SET就是1,RESET就是0

然后根据USARTx选择对应串口号,根据USART_FLAG选择相应的位数。

USART_DR数据寄存器:

写数据往其中写,读数据在其中读。

主要用到0~8位,就是一共9位。

那么可以用如下两个函数来查看和写入:

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

函数全代码:

void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
{
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  assert_param(IS_USART_DATA(Data)); 
    
  /* Transmit Data */
  USARTx->DR = (Data & (uint16_t)0x01FF);
}
uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
{
  /* Check the parameters */
  assert_param(IS_USART_ALL_PERIPH(USARTx));
  
  /* Receive Data */
  return (uint16_t)(USARTx->DR & (uint16_t)0x01FF);
}

USART_BRR波特率寄存器:

 

通过上篇笔记的USARTDIV分频系数由BRR寄存器控制可知: 

 DIV_Fraction就是小数部分,DIV_Mantissa就是整数部分(尾数部分)。

那么可以用如下函数来写入波特率:

USART_Init(上篇文章提到过)

串口配置

左边红圈的是PA9接上RXD(receive external data,即接收外部设备传来的数据,也称为接收数据的引脚),右边红圈的是PA10接上TXD(transmit external data,和RXD相反),都连接USB 232,可以通过USB 232进行串口通信。

 串口配置的一般步骤:

①时钟使能

根据PCLK1用于USART2~5,PCLK2用于USART1、6,比如我想配置USART1,就应该使用

APB2时钟:

调用:void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState); 

这个函数在stm32f4xx_rcc.c中。

使用示例:

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,  ENABLE);//使能UASRT1时钟

而GPIO的时钟初始化都用AHB1!

调用:RCC_AHB1PeriphClockCmd;
同样在stm32f4xx_rcc.h中。

使用示例:

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

②引脚复用映射

调用:GPIO_PinAFConfig;

stm32f4xx_gpio.h

使用示例:

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);//°ÑPA9Ó³Éäµ½´¿Ú1

③GPIO端口模式设置

调用:GPIO_Init();模式设置为GPIO_Mode_AF

stm32f4xx_gpio.h

使用示例:

	GPIO_InitTypeDef GPIO_InitStructure;

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//串口复用
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOF, &GPIO_InitStructure);

④串口初始化

调用:USART_Init();

stm32f4xx_usart.h

使用示例:

	USART_InitTypeDef USART_InitStruct;

	USART_InitStruct.USART_BaudRate=96000;
	USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//不用硬件流控制
	USART_InitStruct.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;//使能发送Rx或者接收Tx都行
	USART_InitStruct.USART_Parity=USART_Parity_Odd;
	USART_InitStruct.USART_StopBits=USART_StopBits_1;//停止位,有0.5个、1个、1.5个、2个
	USART_InitStruct.USART_WordLength=USART_WordLength_8b;//8位字长
	USART_Init(USART1,  &USART_InitStruct);//注意USART_InitStruct是取地址

⑤开启中断并初始化NVIC

调用:NVIC_Init();

misc.h

           USART_ITConfig();

stm32f4xx_usart.h

使用示例:

	NVIC_InitTypeDef  NVIC_InitStruct;
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//USART_IT_RXNE就是说只要stm32收到数据,就会产生一个中断
  NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;//注意是串口1
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;//使能串口1
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级是1
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;//响应优先级是1
	NVIC_Init(&NVIC_InitStruct);

⑥使能串口

调用:USART_Cmd();

stm32f4xx_usart.h

使用示例:

	USART_Cmd(USART1, ENABLE);

⑦、⑧、⑨

调用:

编写中断处理函数

USARTx_IRQHandler();

⑧串口数据收发:

void USART_SendData();//发送数据到串口,通过DR寄存器

uint16_t USART_ReceiveData();//接受数据,从DR寄存器读取接受到的数据

⑨串口传输状态获取:

FlagStatusUSART_GetFlagStatus();

void USART_ClearITPendingBit();

使用示例:

void 	USART1_IRQHandler(void)
{
	u8 res;
	if(USART_GetITStatus(USART1, USART_IT_RXNE))
	{
		res=USART_ReceiveData(USART1);//½ÓÊÕ´ÓµçÄÔÀ´µÄÊý¾Ý
		
		USART_SendData(USART1, res);//·¢ËÍÊý¾Ýµ½µçÄÔ
	}
}

这里编译会显示重复定义,原因是SYSTEM文件夹下有个usart.c里面已经定义了这个函数,可以直接删掉这个文件。

最后上总代码:

#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"

void My_USART1_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	USART_InitTypeDef  USART_InitStruct;
	NVIC_InitTypeDef  NVIC_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,  ENABLE);//ʹÄÜUSART1ʱÖÓ
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);//°ÑPA9Ó³Éäµ½´¿Ú1
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);//°ÑPA10Ó³Éäµ½´¿Ú1
	
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	USART_InitStruct.USART_BaudRate=9600;
	USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//²»ÓÃÓ²¼þÁ÷¿ØÖÆ
	USART_InitStruct.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;//ʹÄÜ·¢ËÍRx»òÕß½ÓÊÕTx¶¼ÐÐ
	USART_InitStruct.USART_Parity=USART_Parity_No;//ÆæżУÑéλÊÇÎÞ
	USART_InitStruct.USART_StopBits=USART_StopBits_1;//ֹͣ룬ÓÐ0.5¸ö¡¢1¸ö¡¢1.5¸ö¡¢2¸ö
	USART_InitStruct.USART_WordLength=USART_WordLength_8b;//8λ×Ö³¤
	USART_Init(USART1,  &USART_InitStruct);//×¢ÒâUSART_InitStructÊÇÈ¡µØÖ·
	
	USART_Cmd(USART1, ENABLE);//ʹÄÜ´¿Ú

	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//USART_IT_RXNE¾ÍÊÇ˵ֻҪstm32ÊÕµ½Êý¾Ý£¬¾Í»á²úÉúÒ»¸öÖжÏ
  NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;//×¢ÒâÊÇ´¿Ú1
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;//ʹÄÜ´¿Ú1
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;//ÇÀÕ¼ÓÅÏȼ¶ÊÇ1
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;//ÏìÓ¦ÓÅÏȼ¶ÊÇ1
	NVIC_Init(&NVIC_InitStruct);
	

}

void 	USART1_IRQHandler(void)
{
	u8 res;
	if(USART_GetITStatus(USART1, USART_IT_RXNE))
	{
		res=USART_ReceiveData(USART1);//½ÓÊÕ´ÓµçÄÔÀ´µÄÊý¾Ý
		
		USART_SendData(USART1, res);//·¢ËÍÊý¾Ýµ½µçÄÔ
	}
}

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//½øÐÐÓÅÏȼ¶·Ö×é
	
	My_USART1_Init();
	
	while(1);//µÈ´ýÆäËûÉ豸·¢ËÍÊý¾Ý£¬ÓÐÊý¾Ý¾Í½øÖжϣ¬¸úÖ÷Ñ­»·ÎÞ¹ØÁË
}

通过XCOM串口调试工具我们可以知道发给STM32什么,STM32就会发回来什么。

此处奇偶校验位只能填无,如果是奇校验或者偶校验返回值可能是乱码。

Fin.

原网站

版权声明
本文为[Archimedes' boat]所创,转载请带上原文链接,感谢
https://blog.csdn.net/m0_62722416/article/details/126251306