串口通讯时,为什么需要同时打开串口时钟和GPIO时钟

1. 项目:野火stm32f10指南者开发板,使用USART实现数据的发送和接收。

2. 代码

  •   主函数main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "stm32f10x.h"
#include "bsp_usart.h"
 
int main(void)
{      
    USART_Config();
    //发送一个字符
    Usart_SendByte(DEBUG_USARTx,'A');
    while(1)
    {
 
    }
 
}

  

  • bsp_usart.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include "bsp_usart.h"
 
static void NVIC_Config(void)
{
    NVIC_InitTypeDef    NVIC_InitStruct;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                 /*配置NVIC为优先级组2*/
    NVIC_InitStruct.NVIC_IRQChannel= DEBUG_USART_IRQ;               /*配置USART中断源*/
    NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;                          /*使能中断通道*/
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;        /*配置抢占优先级:1*/
    NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;                       /*配置子优先级:1*/
     
    NVIC_Init(&NVIC_InitStruct);    /*初始化配置NVIC*/
}
 
void USART_Config(void)
{
    GPIO_InitTypeDef        GPIO_InitStruct;
    USART_InitTypeDef       USART_InitStruct;
     
    //GPIO外设时钟使能
    DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
    //串口时钟使能
    DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
 
    //将USART Tx的GPIO配置为推挽复用模式
    GPIO_InitStruct.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DEBUG_USART_TX_GPIO_PORT,&GPIO_InitStruct);
     
    //将USART Rx的GPIO配置为浮空输入模式
    GPIO_InitStruct.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(DEBUG_USART_RX_GPIO_PORT,&GPIO_InitStruct);
     
    //配置串口的工作参数
    //配置波特率
    USART_InitStruct.USART_BaudRate = DEBUG_USART_BAUNDRATE;
    //配置针数据字长
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    //配置停止位
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    //配置校验位
    USART_InitStruct.USART_Parity = USART_Parity_No;
    //配置硬件流控制
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    //配置工作模式,收发一起
    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    //完成串口的初始化配置
    USART_Init(DEBUG_USARTx, &USART_InitStruct);
     
    //串口中断优先级配置
    NVIC_Config();
    //使能串口接收中断
    USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
    //使能串口
    USART_Cmd(DEBUG_USARTx,ENABLE);
     
}
 
//发送字节函数
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data)
{
    USART_SendData(pUSARTx, data);
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
     
}

 

 

  • bsp_usart.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef __bsp_usart_h
#define __bsp_usart_h
 
#include "stm32f10x.h"
//串口USART宏定义
#define DEBUG_USARTx                                USART1
#define DEBUG_USART_CLK                         RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd          RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUNDRATE               115200
 
//USART GPIO宏定义
#define DEBUG_USART_GPIO_CLK                (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd     RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT            GPIOA
#define DEBUG_USART_TX_GPIO_PIN             GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT            GPIOA
#define DEBUG_USART_RX_GPIO_PIN             GPIO_Pin_10
 
#define DEBUG_USART_IRQ                             USART1_IRQn
#define DEBUG_USART_IRQHandler              USART1_IRQHandler
 
 
void USART_Config(void);
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data);
 
#endif /*bsp_usart_h*/

 

 

  • stm32f10x_it.c函数添加中断函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    /* Includes ------------------------------------------------------------------*/
    #include "stm32f10x_it.h"
    #include "bsp_usart.h"
     
    /** @addtogroup STM32F10x_StdPeriph_Template
      * @{
      */
     
    /* Private typedef -----------------------------------------------------------*/
    /* Private define ------------------------------------------------------------*/
    /* Private macro -------------------------------------------------------------*/
    /* Private variables ---------------------------------------------------------*/
    /* Private function prototypes -----------------------------------------------*/
    /* Private functions ---------------------------------------------------------*/
     
    /******************************************************************************/
    /*            Cortex-M3 Processor Exceptions Handlers                         */
    /******************************************************************************/
     
    /**
      * @brief  This function handles NMI exception.
      * @param  None
      * @retval None
      */
    void NMI_Handler(void)
    {
    }
     
    /**
      * @brief  This function handles Hard Fault exception.
      * @param  None
      * @retval None
      */
    void HardFault_Handler(void)
    {
      /* Go to infinite loop when Hard Fault exception occurs */
      while (1)
      {
      }
    }
     
    /**
      * @brief  This function handles Memory Manage exception.
      * @param  None
      * @retval None
      */
    void MemManage_Handler(void)
    {
      /* Go to infinite loop when Memory Manage exception occurs */
      while (1)
      {
      }
    }
     
    /**
      * @brief  This function handles Bus Fault exception.
      * @param  None
      * @retval None
      */
    void BusFault_Handler(void)
    {
      /* Go to infinite loop when Bus Fault exception occurs */
      while (1)
      {
      }
    }
     
    /**
      * @brief  This function handles Usage Fault exception.
      * @param  None
      * @retval None
      */
    void UsageFault_Handler(void)
    {
      /* Go to infinite loop when Usage Fault exception occurs */
      while (1)
      {
      }
    }
     
    /**
      * @brief  This function handles SVCall exception.
      * @param  None
      * @retval None
      */
    void SVC_Handler(void)
    {
    }
     
    /**
      * @brief  This function handles Debug Monitor exception.
      * @param  None
      * @retval None
      */
    void DebugMon_Handler(void)
    {
    }
     
    /**
      * @brief  This function handles PendSVC exception.
      * @param  None
      * @retval None
      */
    void PendSV_Handler(void)
    {
    }
     
    /**
      * @brief  This function handles SysTick Handler.
      * @param  None
      * @retval None
      */
    void SysTick_Handler(void)
    {
    }
     
    void DEBUG_USART_IRQHandler(void)
    {
        uint8_t ucTemp;
        if (USART_GetITStatus(DEBUG_USARTx, USART_IT_RXNE) != RESET)
        {
            ucTemp = USART_ReceiveData(DEBUG_USARTx);
            USART_SendData(DEBUG_USARTx,ucTemp);
        }
         
    }

 Keil5编程总览:

 

 

3. 执行结果:

    打开串口调试助手,配置好串口、波特率等参数。按下开发板上的复位键,接收区域显示A 

             

 

 

4. 参考资料

  •   原理图
  •  

     

     

     

  •   编程要点
    • 使能RX和TX引脚GPIO时钟和USART时钟;
    • 初始化GPIO,并将GPIO复用到USART上;
    • 配置USART参数;
    • 配置中断控制器并使能USART接收中断;
    • 使能USART;
    • 在USART接收中断服务函数实现数据接收和发送。
  •   

5. 总结

  • 串口时钟使能与控制器使能的关系:为何USART时钟使能了,还需要在配置USART控制器的时候再使能一次?(为什么需要同时打开串口时钟和GPIO时钟)
    • 转自:STM32之串口通信 (bbsmax.com)
    • //打开GPIO时钟
      DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
      //打开串口USART时钟
      DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);

  • (1)USART的时钟使能
    • Note: 当外部时钟没有被激活时,外设寄存器值可能不可读,并且返回值为0x0.

 

  • (2)USART控制器使能
  • 寄存器内部控制关系图
    • RCC_APB2ENR:  控制APB2时钟是否供应给USART控制器

      USART_CR1:   控制USART控制器的分频器和输出是否工作

    • USART1要用到GPIOA的复用管脚输入输出功能,不使能的话只能内部串口外设工作,但是没办法与外界(即串口线)通信。也就是说只使
    • 能USART1的话就只是让USART1这个外设工作,GPIOA作为一个USART1与外界通信的桥梁没有打通,所以不行。

6. 常见的几种通讯协议的参数

转自:

(71条消息) 通信方式梳理:GPIO,I2C,SPI,UART,USART,USB的区别_步印的博客-CSDN博客_gpio i2c spi uart

 

 

 

 

posted @   JRS077  阅读(1601)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示