实验5: 串口通信实验 实验任务: 任务1:编写必要的函数,实现将printf和scanf重定向至串口1 任务2:利用重定向后的printf和scanf,按照用户选择(1或2),读取STM32F103ZET6的产品序列号或闪存容量,并通过串口发送在pc端显示。
时间: 2025-06-25 07:04:13 浏览: 17
### STM32F103ZET6 串口通信实现 `printf` 和 `scanf` 的重定向
为了将 `printf` 和 `scanf` 重定向到 USART1 并读取 STM32F103ZET6 的产品序列号和闪存容量,可以通过以下方法完成:
#### 配置步骤说明
STM32 的每个串口都具有独立的波特率寄存器 `USART_BRR`,其中包含整数部分 `DIV_Mantissa` (bit4-bit15) 和小数部分 `DIV_Fraction` (bit0-bit3)[^1]。配置这些参数可以设置合适的波特率。
以下是完整的代码示例,用于实现 `printf` 和 `scanf` 的重定向以及读取设备信息的功能。
---
#### 示例代码
```c
#include "stm32f1xx.h"
#include <stdio.h>
// 定义全局变量存储用户输入的选择
char userChoice;
// 初始化系统时钟
void SystemClock_Config(void) {
RCC->CR |= RCC_CR_HSEON; // 启用外部高速晶振
while (!(RCC->CR & RCC_CR_HSERDY)); // 等待HSE稳定
RCC->CFGR &= ~RCC_CFGR_SW; // 清零SW字段
RCC->CFGR |= RCC_CFGR_SW_1; // 设置SYSCLK为HSE
}
// 初始化USART1
void UART_Init(void) {
// 启用GPIOA和UART1时钟
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN;
// 配置PA9作为TX, PA10作为RX
GPIOA->CRL |= GPIO_CRL_MODE9_1 | GPIO_CRL_CNFPD9_1;
GPIOA->CRL &= ~(GPIO_CRL_MODE9_0 | GPIO_CRL_CNFPD9_0);
GPIOA->CRL |= GPIO_CRL_MODE10_1 | GPIO_CRL_CNFPD10_2;
// 配置波特率为115200
USART1->BRR = 0x0683; // 波特率计算基于72MHz SYSCLK
// 启用发送和接收功能
USART1->CR1 |= USART_CR1_TE | USART_CR1_RE;
// 启用USART1
USART1->CR1 |= USART_CR1_UE;
}
// 发送字符函数
int fputc(int ch, FILE *f) {
while (!(USART1->SR & USART_SR_TXE));
USART1->DR = (ch & 0xFF);
return ch;
}
// 接收字符函数
int fgetc(FILE *f) {
while (!(USART1->SR & USART_SR_RXNE));
return USART1->DR;
}
// 获取产品序列号模拟函数
const char* GetProductSerial() {
return "ABCDEF12345"; // 假设这是产品的序列号
}
// 获取闪存容量模拟函数
const char* GetFlashSize() {
return "512KB"; // 假设这是芯片的闪存大小
}
int main(void) {
SystemClock_Config(); // 配置系统时钟
UART_Init(); // 初始化USART1
printf("\r\nWelcome to the STM32 Serial Communication Example!\r\n");
printf("Enter 'S' to read Product Serial Number or 'F' to read Flash Size:\r\n");
scanf("%c", &userChoice);
if (userChoice == 'S') {
const char* serialNumber = GetProductSerial();
printf("Product Serial Number: %s\r\n", serialNumber);
} else if (userChoice == 'F') {
const char* flashSize = GetFlashSize();
printf("Flash Size: %s\r\n", flashSize);
} else {
printf("Invalid Input! Please enter 'S' or 'F'.\r\n");
}
while (1); // 主循环保持运行状态
}
```
---
#### 功能描述
1. **初始化系统时钟**: 使用 HSE(外部高速晶振)作为系统时钟源,并将其频率设置为 72 MHz。
2. **初始化 USART1**: 将 GPIOA 的 PA9 和 PA10 分别配置为 TX 和 RX 模式,并设置波特率为 115200 bps[^1]。
3. **重定向标准 I/O 函数**:
- 使用 `fputc` 函数将数据写入 USART1 数据寄存器,从而实现 `printf` 输出到串口。
- 使用 `fgetc` 函数从 USART1 数据寄存器读取数据,从而实现 `scanf` 输入来自串口的数据。
4. **获取设备信息**:
- 用户可以选择输入 `'S'` 来读取产品序列号或输入 `'F'` 来读取闪存容量。
- 设备信息通过预定义字符串返回并打印到 PC 端。
---
#### 注意事项
- 上述代码中的 `GetProductSerial()` 和 `GetFlashSize()` 是简化版的模拟函数,在实际应用中可能需要调用 HAL 库或其他驱动程序来访问硬件特定的信息。
- 如果使用其他开发环境(如 Keil 或 STM32CubeIDE),需确保正确链接 C 标准库以支持 `printf` 和 `scanf`。
---
阅读全文
相关推荐


















