stm32 HAL库 重映射UART1与printf

文章不对介绍串口做介绍,该程序已在stm32f103zet6的开发板测试通过,可正常使用,如果串口输出中文有乱码问题,请看下一章。

uart.c

#include "uart.h"

//串口结构体,中断服务函数需要调用
UART_HandleTypeDef huart1;
//printf指向不同串口时的通用指针
UART_HandleTypeDef *cur_huart_p = &huart1;

void UART1_Init(uint32_t baud)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	
	__HAL_RCC_USART1_CLK_ENABLE();
	/*
		原型		重映射
		PA9 		PB6     ------> USART1_TX
		PA10 		PB7     ------> USART1_RX
	*/
    //1:不映射,使用PA9和PA10
    //0:重映射,使用PA6和PA7
	#if 0
		__HAL_RCC_GPIOA_CLK_ENABLE();
		GPIO_InitStruct.Pin = GPIO_PIN_9;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

		GPIO_InitStruct.Pin = GPIO_PIN_10;
		GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
	
	#else
		//重映射 UART1
		//开启复用总线时钟 hal库一般放在HAL_MspInit()函数调用复用总线的时钟
		__HAL_RCC_AFIO_CLK_ENABLE();
		//开启UART串口1的复用时钟
		__HAL_AFIO_REMAP_USART1_ENABLE();
		//GPIOB组开启时钟 供电
		__HAL_RCC_GPIOB_CLK_ENABLE();
		
		GPIO_InitStruct.Pin = GPIO_PIN_6;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

		GPIO_InitStruct.Pin = GPIO_PIN_7;
		GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
	#endif

	/* USART1 中断 */
	HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(USART1_IRQn);
  //8 N 1格式
  huart1.Instance = USART1;
  huart1.Init.BaudRate = baud;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_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中预留了一个HAL_UART_MspInit弱声明的函数给我们的,类似于回调函数,需要自己实现函数内容,这个HAL_UART_MspInit函数一般是用来初始化串口GPIO和对应的时钟的,这些初始化内容我已经把他写在前面了。
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
	//打印文件名称,函数名,行号
    //Error_Handler();
  }
	cur_huart_p = &huart1;
}

//串口发送数据函数(1字节)
void Uart_Send_Byte(char tx_dat)
{
	while( !(__HAL_UART_GET_FLAG(cur_huart_p, USART_SR_TC)) ){};
	cur_huart_p->Instance->DR = tx_dat;
}

//字符串方式,遇到\0会停止发送
void Uart_Send_Str(UART_HandleTypeDef *temp,char* str)
{
	cur_huart_p = temp;
	while(*str)
	{
		USARTx_Send_Byte(*str);
		str++;
	}
}

//指定长度发送,遇到\0也不会停止发送,适合含有0x00的数据包
void Uart_Send_Len(UART_HandleTypeDef *temp,char* str,int len)
{
	cur_huart_p = temp;
	for(u8 i = 0;i < len;i++)
	{
		USARTx_Send_Byte(str[i]);
	}
}

//将printf映射至串口
//cur_huart_p不能为空必须指向串口结构体变量,比如cur_huart_p = &huart1;cur_huart_p = &huart2;等等
int fputc(int ch,FILE *f)
{
	/*
     //调用库函数 阻塞方式发送,函数内部多逻辑判断,稍微慢一些,但有各种返回值,适合调试使用,获取返回值
     uint8_t temp[1] = {ch};
	 HAL_UART_Transmit(cur_huart_p,temp,1,2);
    */
    //直接寄存器方式发送,优点速度快
    USARTx_Send_Byte(ch);
    //防止编译一直提醒警告
	UNUSED(*f);
	return ch;
}

void USART1_IRQHandler(void)
{
	HAL_UART_IRQHandler(&huart1);
}

 uart.h

#ifndef __UART_H
#define	__UART_H

#include <stdio.h>

#include "stm32f1xx_hal_gpio.h"
#include "stm32f1xx_hal_dma.h"
#include "stm32f1xx_hal_uart.h"
#include "stm32f1xx_hal_rcc.h"
#include "stm32f1xx_hal_cortex.h"


#define DBG_FUNC 

#ifdef DBG_FUNC
    //打印文件名称,函数名,行号
	#define Error_Handler() 	printf("%s\n%s\n%d\n",__FILE__,__func__,__LINE__)
#endif

//更换串口
#define REPLACE_SERIAL_PORT(HUART)       do{ cur_huart_p = (HUART);}while(0)
//二次封装使用
#define UARTx_PRINTF(HUART,...) do{ cur_huart_p = (HUART);printf(__VA_ARGS__);}while(0)
//指定长度发送纯字符串(非\0 字符串)
#define UARTx_SEND_LEN(HUART,STR) do{Uart_Send_Len((HUART),STR,sizeof(STR));}while(0)

//外部变量声明
extern UART_HandleTypeDef huart1,*cur_huart_p;
//初始化函数
void UART1_Init(uint32_t baud);
void Uart_Send_Byte(char tx_dat);
void Uart_Send_Str(UART_HandleTypeDef *temp,char* str);
void Uart_Send_Len(UART_HandleTypeDef *temp,char* str,int len);

#endif

main.c

#include "stm32f1xx_hal.h"
#include "uart.h"

int main(void){
	
	//上电main函数执行的第一个函数
	//内部默认8MHz
	HAL_Init();
	//重新配置系统时钟为 64MHz
	//RCC_HSI_PLL_64MHz_Clk_Init();
	//PA8 检测芯片时钟工作频率是否正常
	//Get_Clk_test();
	//设置串口1的波特率为115200
	UART1_Init(115200);

	while(1)
	{
        //库函数
        HAL_UART_Transmit(&huart1,(uint8_t*)"hello world 1\n",6,50);

        //指定串口1
        REPLACE_SERIAL_PORT(&huart1)

        //单字符
        Uart_Send_Byte('H');
        Uart_Send_Byte('i');
        Uart_Send_Byte('\n');

        
        Uart_Send_Str(&huart1,"hello world 2\n");
        
        //发送定长14个字符
        Uart_Send_Len(&huart1,"hello world 3\n",14);
        //发送定长15个字符,包括了'\0'结束符
        UARTx_SEND_LEN(&huart1,"hello world 4\n");

		
		UARTx_PRINTF(&huart1,"hello world %d\n",5);

        printf("hello world %d\n",6);

		printf("uart is perfect!\n");

		HAL_Delay(1000); 
		
	}
	return 0;
}

要选上这个,printf才能正常使用

c0427c49c6934d6dbd44769b8e3625c7.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值