[原创] 【 STM32WB55 测评】_05_UART寄存器配置实验

lvxinn2006   2019-5-22 22:53 楼主
本次活动测评开发板STM32WB55 Nucleo Pack由ST意法半导体提供,感谢意法半导体对EEWorld测评的支持!
【实验目的】
· 熟悉STM32WB55的串口模块的配置与使用。

【实验环境】
· NUCLEO-WB55 Nucleo Pack开发板
· Keil MDK-ARM(Keil uVision 5.25.2.0)
· Keil.STM32WBxx_DFP.1.0.0.pack

【实验资料】
· NUCLEO-WB55 Nucleo Pack开发板原理图
· STM32WB55xx Data Sheets
· STM32WB55xx Reference manual(参考手册)
【实验分析
· 查看原理图
在NUCLEO-WB55中,最方便使用的UART串口就是USART,直接连接到了ST_LINK的虚拟串口,原理图如下:
图片1.png
STM32WB55中,有两组串口模块:LPUARTUSART,通过查询手册STM32WB55xx Data Sheets,可知这两个引脚对应着USART1功能模块,如下图所示:
图片2.png
· 查看STM32WB55xx Reference manual
1. 启用GPIO时钟
与前面实验一样,使用GPIO端口之前,需要先开启时钟,这里使用了GPIOB,所以需要将RCC->AHB2ENR[1]位置1,原理如下图所示:
图片3.png
2. 设置GPIO引脚功能
开启GPIOB的时钟以后,设置GPIO的功能,即设置GPIOB_MODER寄存器,根据参考手册,MODER寄存器定义如下:
图片4.png
对应PB6PB7引脚的位置分别位于[13:12][15:14]四个位中,在位段的描述说明中,可以看到00为输入模式,01为通用输出模式,10为复用功能模式,根据应用需求,我们需要把PB6PB7作为UARTTxRx来使用,所以我们需要把MODER[15:14][13:12]都配置成10,即复用功能模式(AF
MODER寄存器配置为AF模式时,需要使用AFRLAFRH两个寄存器对引脚功能进行进一步设置,寄存器定义如下:
图片5.png
在这个寄存器中,每4个位控制一个引脚的功能,PB6引脚的功能位于[27:24]四个位中,PB7引脚的功能位于[31:28]四个位中,每4个位中0000~01118个组合表示引脚的8种功能,这里把对应的值用AF0~AF8来表示,每个引脚对应的值,所对应的功能也不同,下表描述的是引脚AF值所对应功能,其中PB6AF7表示USART1_TXPB7AF7表示USART1_RX功能
图片6.png
图片7.png
至此,我们基本就确定了AF寄存器的配置方法,需要把[27:24]配置为0x7 (0111:AF7)[31:28]也配置为0x7 (0111:AF7)
这样,PB6PB7的引脚功能就配置好了,接下来就需要配置USART外设模块了。
3. 启用USART1时钟
USART连接在系统的APB2总线,所以USART的时钟控制,在APB2ENR中,如下图所示:
图片8.png
需要把寄存器的[14]位置位,即可开启USART1的时钟。
4. 使能USART1模块
USART寄存器比较多,但是大多数默认参数已经满足需求,我们需要设置的寄存器并不多,首先要配置CR1寄存器,重点要设置下图所示的三个数据位:
图片9.png
图片10.png
图片11.png
图片12.png
寄存器中的[3][2]两个位用来使能TxRx[0]位用来使能USART设备,[5]位用来启用接收数据中断。
5. 设置波特率
BRR寄存器
图片13.png
波特率的计算方法
图片14.png
计算方法详见文档。
本人根据文档,总结了一个公式,可以直接用在代码中:
        //Baudrate         = Fclk/(16*USARTDIV)
        //USARTDIV        = Fclk / Baudrate / 16
        //                                        = SystemCoreClock / 115200 / 16
        temp = SystemCoreClock * 100 / baud / 16;
        brr = ((temp / 100)<<4) | ((temp%100) * 16 / 100) + (((temp%100) * 16 / 100)%100)/50;
        USART2->BRR = brr;
6. 串口的初始化函数实现
  1. void USART1_Init(int baud)
  2. {
  3.         uint64_t temp;
  4.         uint32_t brr;
  5.         RCC->AHB2ENR |= (1<<1);        //使能GPIOB时钟
  6.        
  7.         GPIOB->MODER &= ~((0x3<<12) | (0x3<<14));
  8.         GPIOB->MODER |= (0x2<<12) | (0x2<<14); //设置PB6 PB7为功能模式
  9.         GPIOB->AFR[0] &= ~((0xFUL<<24) | (0xFUL<<28));
  10.         GPIOB->AFR[0] |= (0x7<<24) | (0x7<<28);        //PB6 Tx  PB7 Rx
  11.        
  12.         RCC->APB2ENR |= (1<<14);
  13.         //Baudrate         = Fclk/(16*USARTDIV)
  14.         //USARTDIV        = Fclk / Baudrate / 16
  15.         temp = (uint64_t)SystemCoreClock * 100 / baud / 16;
  16.         brr = ((temp / 100)<<4) | ((temp%100) * 16 / 100) + (((temp%100) * 16 / 100)%100)/50;
  17.         USART1->BRR = brr;
  18.        
  19.         USART1->CR1 |= (1<<29);
  20.         USART1->CR1 |= (1<<0)         //UE=1 USART Enable
  21.                         | (1<<3)                                                 //TE=1 Transmitter Enable
  22.                         | (1<<2);                                                //RE=1 Revicer Enable
  23.                        
  24.         USART1->CR1 |= (1<<5);        //enable RXNEIE
  25.         NVIC_EnableIRQ(USART1_IRQn);
  26. }


7. 数据的发送
数据的发送,主要使用了TDR寄存器,当往TDR寄存器写数据时,数据会通过TxD引脚发送出去,并且一旦发送完成,会把完成状态体现在ISR寄存器中,封装发送函数如下:
  1. void UART1_PutChar(int data)
  2. {
  3.         while((USART1->ISR&(1u<<7)) == 0);        //Wait TXE=1
  4.         USART1->TDR = data;
  5. }


8. 启用USART中断
启用中断,直接使用CMSIS提供的NVIC_EnableIRQ()函数
NVIC_EnableIRQ(USART1_IRQn);
9. 数据的接收
RxD引脚收到数据时,数据会保存在RDR寄存器中,如果在CR1中设置了RXNE位,收到数据时会触发中断,在中断处理函数中可以处理收到的数据,
  1. #define UART1_RBUF_SIZE         64
  2. volatile uint32_t UARTStatus;
  3. volatile uint8_t  UARTTxEmpty = 1;
  4. volatile uint8_t  UARTBuffer[UART1_RBUF_SIZE];
  5. volatile uint32_t UARTCount = 0;
  6. volatile uint32_t UART_op = 0;

  7. void USART1_IRQHandler(void)
  8. {
  9.         if (USART1->ISR & (1<<5)){ //收到数据
  10.                   UARTBuffer[UARTCount++] = USART1->RDR;
  11.       if (UARTCount >= UART1_RBUF_SIZE)
  12.       {
  13.         UARTCount = 0;                /* buffer overflow */
  14.       }       
  15.         }
  16. }

  17. int UART2_GetChar(uint8_t *ch)
  18. {
  19.   if(UART_op != UARTCount)
  20.   {
  21.     *ch = UARTBuffer[UART_op];
  22.         UART_op ++;
  23.         if(UART_op >= UART1_RBUF_SIZE)
  24.           UART_op = 0;
  25.                 return 1;
  26.   }
  27.   return 0;
  28. }


10. 主函数
  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include "uart.h"

  4. int main(void)
  5. {
  6.         uint8_t ch;
  7.         USART1_Init(115200);
  8.         printf ("Welcome to EEWORLD!\n");
  9.         printf ("Your input will be echo!\n");
  10.         while(1){
  11.                 if (USART1_GetChar(&ch)){
  12.                         USART1_PutChar(ch);
  13.                 }
  14.         }
  15. }


【实验现象】
· 开发板复位以后会打印输出两句话,然后在发送区发送任何数据,都会反显到接收区,效果如下:
图片15.png
下一个实验用串口+ADC实现光照强度检测。


此内容由EEWORLD论坛网友lvxinn2006原创,如需转载或用于商业用途需征得作者同意并注明出处

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复