文章不对介绍串口做介绍,该程序已在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才能正常使用