一、串口
- 在 STM32 中,串口(UART,通用异步收发传输器)是用于串行通信的外设。它在嵌入式系统中的作用非常广泛,主要包括几个方面
- 数据通信
串口用于微控制器与其他设备之间的数据传输。这些设备可以是其他微控制器、传感器、计算机或通信模块(例如蓝牙、Wi-Fi 模块等)。串口以异步方式传输数据,不需要时钟信号,因此实现起来相对简单。 - 调试功能
UART 在嵌入式开发中常用于打印调试信息。在 STM32 开发过程中,程序员可以使用 printf 函数将调试信息通过串口输出到计算机终端。 - 固件升级
在嵌入式设备的维护过程中,UART 可以用于通过串口线对设备进行固件升级。 - 外部模块通信
GPS模块,蓝牙模块
- UART通信的主要参数
- 波特率(Baud Rate):数据传输速率,以每秒传输的比特数表示。常见波特率有9600、115200等。发送和接收设备的波特率必须相同。
- 数据位(Data Bits):每次传输的数据位长度,通常是8位。
- 停止位(Stop Bits):用于标识数据传输结束。可以选择1位或2位停止位。
- 校验位(Parity Bit):用于检测数据传输错误,可以是无校验、偶校验或奇校验。
- 串口配置的主要步骤
选择波特率:设定发送和接收双方的波特率。
选择数据位、停止位和校验位:根据应用需求配置传输帧格式。
配置GPIO引脚:使用STM32的GPIO复用功能,将UART的TX和RX引脚连接到相应外设。
启用UART中断或DMA:用于非阻塞传输,避免阻塞主程序。
初始化并启动UART:通过配置UART外设,使其进入工作状态。
UART 串口的主要特点
- 异步通信,全双工通信,易于实现,传输效率较快。
调试软件
www.mcuisp.com下载即可
串口的发送(调试功能)
-
设置RCC的high SPeed CLock的模式为Crystal/Ceramic
-
找到电路板的串口,看清楚串口连接的是哪一个,我的电路板串口启用的是UART1
-
UART1挂载到APB2总线上,设置APB2为64MHZ即可。
-
对USART1模式设置为Asynchronous,即为异步通信方式,当然你也可以在这里设置串口的具体参数
-
通常将 printf 函数的输出重定向到 UART,这样你可以使用 printf 在终端上输出调试信息。需要实现 __io_putchar 函数来将字符发送到 UART
-
实际上是对__io_putchar的改写
int __io_putchar(int ch)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
参数:
int ch:传入的字符,将要通过串口输出的单个字符。
功能:
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY):这个函数使用 STM32 的 HAL 库,通过 huart1(UART1 的句柄)发送数据。
&huart1:表示使用 UART1,也可以换成串口2。
(uint8_t *)&ch:将字符 ch 的地址转换为 uint8_t* 类型,因为 UART 通常处理的是 8 位数据(字符)。
1:发送 1 个字节的数据。
HAL_MAX_DELAY:设置为最大等待时间,表示发送数据时系统会等待直到传输完成。
返回值:
return ch;:函数返回发送的字符 ch,这是为了和标准的 putchar 函数兼容,通常不用于实际逻辑。
- 代码示例
#include "main.h"
UART_HandleTypeDef huart1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
// 主函数
int main(void)
{
// 初始化HAL库
HAL_Init();
// 配置系统时钟
SystemClock_Config();
// 初始化GPIO
MX_GPIO_Init();
// 初始化USART1
MX_USART1_UART_Init();
// 无限循环,用于发送测试信息
while (1)
{
// 打印当前天气信息
printf("today is sunshine,temp=45,shidu=35.\r\n");
// 打印欢迎信息
printf("hello world---------------->");
// 延迟500毫秒
HAL_Delay(500);
}
}
// 重定向printf函数,使其可以通过USART1发送字符
int __io_putchar(int ch)
{
// 通过USART1发送字符
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
// 配置系统时钟
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {
0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {
0};
// 配置时钟源
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON; // 启用外部高速时钟 (HSE)
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; // HSE预分频值为1
RCC_OscInitStruct.HSIState = RCC_HSI_ON; // 启用内部高速时钟 (HSI)
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // 启用锁相环 (PLL)
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // PLL时钟源为HSE
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL8; // PLL倍频因子为8
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
// 如果时钟配置失败,则进入错误处理
Error_Handler();
}
// 配置时钟树
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 系统时钟源为PLL
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB时钟不分频
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; // APB1时钟分频为2
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // APB2时钟不分频
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
// 如果时钟配置失败,则进入错误处理
Error_Handler();