串口通讯时,为什么需要同时打开串口时钟和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函数添加中断函数
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
/* 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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律