硬件资源

  • STM32F103C8T6 开发板

  • DAP-Link

最近的一个项目要用到 USART1,但其默认端口 PA9 和 PA10 拿去驱动电机了,所以得用 PB7 和 PB6 作为串口的端口。

原先用于串口通信的代码(修改自正点原子)在使用 PA9/10 时可以正常工作,但当我将端口改为 PB6/7 时就无法正常工作了,查了一下,发现是没有添加串口重映射的一行代码,但是添加之后还是无法工作。于是我用 STM32CubeMX 生成了一个串口重映射的新工程,经过对比,发现缺失的是以下两行代码:

__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_USART1_ENABLE();

将之前的代码和新工程的代码整合一下之后,完整代码如下,亲测可用:

graph TD A[HAL_Init]-->B[HAL_MspInit 使能端口复用时钟] B-->C[Uart1_Init 使能端口时钟 配置串口1] C-->D[HAL_UART_MspInit 使能串口时钟 初始化端口 配置串口重映射 初始化串口中断]
  • bsp_usart.h
#ifndef __BSP_USART_H
#define __BSP_USART_H

#include "stm32f1xx.h"
#include <stdio.h>

//串口波特率
#define USART_BAUDRATE                    115200

//引脚定义
/*******************************************************/
#define USARTx                             USART1
#define USART_CLK_ENABLE()                __HAL_RCC_USART1_CLK_ENABLE();
#define USART_CLK_DISABLE()                __HAL_RCC_USART1_CLK_DISABLE();

#define USART_RX_GPIO_PORT                GPIOB
#define USART_RX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOB_CLK_ENABLE()
#define USART_RX_PIN                      GPIO_PIN_7

#define USART_TX_GPIO_PORT                GPIOB
#define USART_TX_GPIO_CLK_ENABLE()        __HAL_RCC_GPIOB_CLK_ENABLE()
#define USART_TX_PIN                      GPIO_PIN_6

#define USART_REMAP_ENABLE()              __HAL_AFIO_REMAP_USART1_ENABLE()

#define USART_IRQHandler                  USART1_IRQHandler
#define USART_IRQ                         USART1_IRQn
/************************************************************/

//初始化串口,在主函数中调用
void Uart1_Init(void);

int fputc(int ch, FILE *f);
int fgetc(FILE *f);
extern UART_HandleTypeDef huart1;
#endif
  • bsp_usart.c
#include "./usart/bsp_usart.h"

UART_HandleTypeDef huart1;

void Uart1_Init(void){
  USART_TX_GPIO_CLK_ENABLE();
  USART_RX_GPIO_CLK_ENABLE();

  huart1.Instance = USARTx;
  huart1.Init.BaudRate = USART_BAUDRATE;//波特率:115200
  huart1.Init.WordLength = UART_WORDLENGTH_8B;//数据位长度:8
  huart1.Init.StopBits = UART_STOPBITS_1;//停止位长度:1
  huart1.Init.Parity = UART_PARITY_NONE;//校验位:无
  huart1.Init.Mode = UART_MODE_TX_RX;//通信模式:收发
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;//硬件流量控制:关闭
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;//过采样模式

  HAL_UART_Init(&huart1);
}

//被 HAL_UART_Init 调用
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(huart->Instance == USARTx)
  {
    USART_CLK_ENABLE();

    USART_TX_GPIO_CLK_ENABLE();
    USART_RX_GPIO_CLK_ENABLE();
    /**
    PB6     ------> USART1_TX
    PB7     ------> USART1_RX 
    */
    GPIO_InitStruct.Pin = USART_TX_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(USART_TX_GPIO_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = USART_RX_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(USART_RX_GPIO_PORT, &GPIO_InitStruct);

    USART_REMAP_ENABLE();

    /* 初始化串口中断 */
    HAL_NVIC_SetPriority(USART_IRQ, 0, 0);
    HAL_NVIC_EnableIRQ(USART_IRQ);
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
{
  if(huart->Instance == USARTx)
  {
    USART_CLK_DISABLE() ;

    /**
    PB6     ------> USART1_TX
    PB7     ------> USART1_RX 
    */
    HAL_GPIO_DeInit(USART_RX_GPIO_PORT, USART_RX_PIN | USART_TX_PIN);

    HAL_NVIC_DisableIRQ(USART_IRQ);
  }

}

//重定向c库函数printf到串口USART1,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
    /* 发送一个字节数据到串口DEBUG_USART */
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);        
    return (ch);
}

//重定向c库函数scanf到串口USART1,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{       
    int ch;
    HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, 1000); 
    return (ch);
}
  • stm32f1xx_hal_msp.c
#include "main.h"
//被 HAL_Init 调用
void HAL_MspInit(void)
{
  __HAL_RCC_AFIO_CLK_ENABLE();//开启端口复用时钟
  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_AFIO_REMAP_SWJ_NOJTAG();//SWD调试重映射
}
  • stm32f1xx_it.c
//串口中断服务函数
void USART1_IRQHandler(void)
{
  HAL_UART_IRQHandler(&huart1);
}
最后修改:2023 年 12 月 12 日
如果觉得我的文章对你有用,请随意赞赏