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

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

2. 代码

  •   主函数main.c
#include "stm32f10x.h"
#include "bsp_usart.h"

int main(void)
{		
	USART_Config();
	//发送一个字符
	Usart_SendByte(DEBUG_USARTx,'A');
	while(1)
	{

	}

}

  

  • bsp_usart.c
#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
#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函数添加中断函数
    /* 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编程总览:

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

 

3. 执行结果:

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

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

 

 

4. 参考资料

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

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

     

     

     

  •   编程要点
    • 使能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);
      //打开串口外设时钟
      DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);

  • (1)USART的时钟使能
    • Note: 当外部时钟没有被激活时,外设寄存器值可能不可读,并且返回值为0x0.
    • 串口通讯时,为什么需要同时打开串口时钟和GPIO时钟

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

 

  • (2)USART控制器使能
    • 串口通讯时,为什么需要同时打开串口时钟和GPIO时钟
  • 寄存器内部控制关系图
    • 串口通讯时,为什么需要同时打开串口时钟和GPIO时钟

      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

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

 

 

 

上一篇:2-路归并排序


下一篇:线性表之-栈和队列