串口 及 关于输出打印信息

串口的核心配置步骤:

  1. 使能 GPIO 和串口时钟。
  2. 配置 TX/RX 引脚为复用功能。
  3. 配置串口波特率、数据位等核心参数。
  4. 使能串口外设。
  5. (可选)配置中断和 NVIC,实现异步收发。
  6. 实现基本的收发函数(或使用中断处理)。

以下是详细的配置要点:

1. 使能外设时钟

串口通信依赖于GPIO 时钟串口外设时钟,需先在RCC(复位和时钟控制)中使能:

  • GPIO 时钟:根据串口使用的引脚所在端口(如 PA、PB 等)使能,例如
  • RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE)。
  • 串口时钟:根据串口编号(如 USART1、USART2 等)使能,其中:
//USART1 挂载在APB2总线(高速),需用
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE)。

//USART2/3、UART4/5 挂载在APB1总线(低速),需用
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE)。

2. 配置 GPIO 引脚

串口通信需要至少两根引脚:发送端(TX) 和接收端(RX),需将其配置为复用推挽输出(TX)和浮空输入 / 上拉输入(RX):

  • TX 引脚:复用功能推挽输出(保证能稳定输出高 / 低电平)。
  • RX 引脚:浮空输入(适用于外部有上拉电阻的场景)或上拉输入(避免无信号时电平不稳定)。
GPIO_InitTypeDef GPIO_InitStructure;

// 配置TX引脚(PA9)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

// 配置RX引脚(PA10)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入
// 或 GPIO_Mode_IPU; // 上拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure);

3. 配置串口核心参数(USART_InitTypeDef)

通过USART_InitTypeDef结构体配置串口的核心通信参数,包括:

  • 波特率:如 9600、115200 等(需与通信设备一致)。
  • 数据位:通常为 8 位(USART_WordLength_8b)。
  • 停止位:通常为 1 位(USART_StopBits_1)。
  • 校验位:无校验(USART_Parity_No)、奇校验或偶校验(要求数据帧(包括数据位)中 “1” 的总数为偶/奇数)。
  • 硬件流控:通常关闭(USART_HardwareFlowControl_None),如需使用 RTS/CTS 则需额外配置引脚。
  • 模式:使能发送(USART_Mode_Tx)和 / 或接收(USART_Mode_Rx)。
USART_InitTypeDef USART_InitStructure;

USART_InitStructure.USART_BaudRate = 115200; // 波特率115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 8位数据
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 1位停止位
USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件流控
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 同时使能发送和接收
USART_Init(USART1, &USART_InitStructure); // 初始化USART1

4. 使能串口

配置完成后,需通过USART_Cmd函数使能串口外设:

USART_Cmd(USART1, ENABLE); // 使能USART1

5. 中断配置(可选,用于异步收发)

若需要通过中断处理接收 / 发送(而非轮询),需额外配置:

  1. 使能串口中断:通过USART_ITConfig使能特定中断(如接收完成中断USART_IT_RXNE)。
  2. 配置 NVIC:设置中断优先级,确保中断能被 CPU 响应。
NVIC_InitTypeDef NVIC_InitStructure;

// 使能USART1接收中断(RXNE:接收缓冲区非空)
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

// 配置NVIC
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // USART1中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道
NVIC_Init(&NVIC_InitStructure);

之后需实现中断服务函数(如USART1_IRQHandler),在中断中处理接收 / 发送逻辑。

6. 收发数据函数实现

  • 发送数据:通过USART_SendData函数发送单个字节,需先判断发送缓冲区是否为空(USART_FLAG_TXE)。
  • 接收数据:通过USART_ReceiveData函数读取接收缓冲区数据,需先判断接收缓冲区是否非空(USART_FLAG_RXNE)。
// 发送一个字节
void USART_SendByte(USART_TypeDef* USARTx, uint8_t data) {
    while (USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET); // 等待发送缓冲区为空
    USART_SendData(USARTx, data);
}

// 接收一个字节
uint8_t USART_ReceiveByte(USART_TypeDef* USARTx) {
    while (USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) == RESET); // 等待接收完成
    return (uint8_t)USART_ReceiveData(USARTx);
}


关于通过串口打印

方法一:printf重定向【嵌入式学习笔记】---- printf重定向_printf 重定向 fputc putchar-CSDN博客

方法二:重新一个函数,结合va_list和vsprintf(关于printf,sprintf和vsprintf的区别见收藏)

对于传参中参数类型和个数不确定的格式转换,请使用 vsprintf。

1. printf是直接输出

2. sprintf是将发送格式化输出到指定数组。格式化用法与 printf一致,相当于把 printf输出的内容放入指定数组中。sprintf需要指定明确的可变参数的类型和个数(%d,%s...)

3. vsprintf算是对printf的封装,通过va_list 可以不用固定设置传入的可变参数,更为方便。

// 定义发送缓冲区,大小根据实际需求设置(例如200字节)
u8 USART1_TX_BUF[200];  // u8 通常是 unsigned char 的别名

void u1_printf(char *format,...)  
/*
	format:格式化字符串,例如 "Hello, %s! Age: %d\r\n"。
	...:可变参数列表,对应 format 中的占位符(如 %s, %d)。

	例如:调用 u1_printf("Hello, %s! Age: %d\r\n", "Alice", 25); 时:
	格式化字符串:vsprintf 生成 "Hello, Alice! Age: 25\r\n" 并存入 USART1_TX_BUF。
*/
{
	u16 i;
	va_list list_data;				//用于存储 可变参数的类型。需包含"stdarg.h"头文件
	va_start(list_data, format);	//将format后的 可变参数(如 %s, %d)存入list_data
	vsprintf((char *)USART1_TX_BUF, format, list_data);//将根据format格式化的字符串保存到字符数组
	va_end(list_data);						//与va_start成对出现
	
	for(i = 0; i < strlen((const char *)USART1_TX_BUF); i++)		//将字符串按字节发送
	{
		while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) != 1);
		
		USART_SendData(USART1, USART1_TX_BUF[i]);
	}
	
	while(USART_GetFlagStatus(USART1, USART_FLAG_TC) != 1);	//等发送完成
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值