代码呈现:
void USART1_Init(u32 bound){
GPIO_InitTypeDef GPIO_InitStructure; // 声明一个GPIO初始化结构体
USART_InitTypeDef USART_InitStructure; // 声明一个USART初始化结构体
NVIC_InitTypeDef NVIC_InitStructure; // 声明一个NVIC初始化结构体
// 启用USART1和GPIOA的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
// 配置PA9引脚为复用推挽输出,速度50MHz(USART1的TX引脚)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // 设置GPIO引脚为9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置GPIO速度为50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 设置GPIO模式为复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化GPIOA的引脚9
// 配置PA10引脚为浮空输入(USART1的RX引脚)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // 设置GPIO引脚为10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 设置GPIO模式为浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化GPIOA的引脚10
// 配置NVIC,启用USART1中断,并设置优先级为3
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // 设置中断通道为USART1
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 设置抢占优先级为3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 设置子优先级为3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 启用该中断通道
NVIC_Init(&NVIC_InitStructure); // 初始化NVIC配置
// 配置USART1参数:波特率、字长、停止位、奇偶校验、硬件流控制和模式
USART_InitStructure.USART_BaudRate = bound; // 设置USART1波特率
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_Rx | USART_Mode_Tx; // 设置为接收和发送模式
USART_Init(USART1, &USART_InitStructure); // 初始化USART1
// 启用USART1接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 使能USART1接收中断
// 启用USART1
USART_Cmd(USART1, ENABLE); // 使能USART1
}
想要理解以上的代码,需要理解一下几个概念:
1.USART:
USART是什么?
USART(Universal Synchronous Asynchronous Receiver Transmitter)是一个“通用同步异步接收发送器”。它是一种串行通信方式,用来让微控制器(比如STM32)和其他设备(比如电脑、传感器)进行数据传输。
USART的作用:
USART的主要作用是通过串行方式发送和接收数据。它可以工作在同步和异步两种模式下。
异步模式:
这是USART最常用的模式。在这种模式下,数据一位一位地发送,不需要时钟信号来同步发送和接收。
同步模式:
在这种模式下,USART会使用一个时钟信号来同步数据的发送和接收。
举个例子:
想象一下,USART就像一个人(微控制器)通过电话线(串行通信)和另一个人(电脑)对话(数据传输)。他们不需要见面,只需要通过电话线就可以互相发送和接收信息。
2.GPIO工作模式:
-
GPIO_Mode_AIN(模拟输入模式)
- 在这种模式下,GPIO引脚作为模拟输入。常用于ADC(模数转换器)输入引脚。这种模式不涉及数字信号的传输。
-
GPIO_Mode_IN_FLOATING(浮空输入模式)
- 在这种模式下,GPIO引脚作为输入引脚,没有上拉或下拉电阻。引脚的电平状态完全由外部电路决定,适用于输入信号已经稳定的场合。
-
GPIO_Mode_IPD(下拉输入模式)
- 在这种模式下,GPIO引脚作为输入引脚,并且内部连接了一个下拉电阻。当引脚悬空时,它会被拉低到低电平,防止引脚浮动。适用于默认状态为低电平的输入信号。
-
GPIO_Mode_IPU(上拉输入模式)
- 在这种模式下,GPIO引脚作为输入引脚,并且内部连接了一个上拉电阻。当引脚悬空时,它会被拉高到高电平,防止引脚浮动。适用于默认状态为高电平的输入信号。
-
GPIO_Mode_Out_OD(开漏输出模式)
- 在这种模式下,GPIO引脚作为输出引脚,具有开漏特性。引脚可以拉低电平(输出低电平),但不能拉高电平(输出高电平)。外部需要一个上拉电阻来拉高电平。常用于I2C总线等需要多设备共用同一条线路的通信。
-
GPIO_Mode_Out_PP(推挽输出模式)
- 在这种模式下,GPIO引脚作为输出引脚,具有推挽特性。引脚可以输出高电平或低电平。适用于需要驱动较大电流的场合,如驱动LED或其他外设。
-
GPIO_Mode_AF_OD(复用功能开漏输出模式)
- 在这种模式下,GPIO引脚具有复用功能,并且是开漏输出。引脚可以拉低电平,但不能拉高电平,外部需要一个上拉电阻来拉高电平。常用于I2C、SPI等需要复用功能的通信接口。
-
GPIO_Mode_AF_PP(复用功能推挽输出模式)
- 在这种模式下,GPIO引脚具有复用功能,并且是推挽输出。引脚可以输出高电平或低电平。常用于USART、SPI等需要复用功能的通信接口。
-
GPIO_Mode_IPU(上拉输入模式)
- 在这种模式下,GPIO引脚作为输入引脚,并且内部连接了一个上拉电阻。当引脚悬空时,它会被拉高到高电平,防止引脚浮动。适用于默认状态为高电平的输入信号。
使用示例
- 模拟输入模式:用于连接模拟传感器,如温度传感器等。
- 浮空输入模式:用于接收外部信号,信号源需要稳定。
- 下拉输入模式:用于默认状态为低电平的开关或按钮输入。
- 上拉输入模式:用于默认状态为高电平的开关或按钮输入。
- 开漏输出模式:用于I2C通信,多个设备共用一条数据线。
- 推挽输出模式:用于驱动LED等外设。
- 复用功能开漏输出模式:用于需要复用功能的I2C通信。
- 复用功能推挽输出模式:用于USART通信等。
3.波特率:
波特率是什么?
波特率(Baud Rate)是指在串行通信中,每秒钟传输的符号(数据)位数。简单来说,就是数据传输的速度。
具体解释:
在串行通信中,数据一位一位地传输。波特率就是指每秒钟能传输多少位数据。例如,如果波特率是9600,那么每秒钟就可以传输9600位数据。
举个例子:
想象一下,你在发短信。波特率就像是你每分钟可以发送多少个字。如果你每分钟可以发送100个字,那么你的“波特率”就是100字/分钟。
为什么波特率重要?
在通信的双方(比如两个微控制器或一个微控制器和电脑)必须使用相同的波特率,否则他们无法正确地理解对方发送的数据。就像两个人通电话,必须说话速度差不多,才能听懂对方在说什么。
4.NVIC:
NVIC是什么?
NVIC是一个专门用来管理中断的控制器,简称“中断控制器”。它的全称是“嵌套向量中断控制器”(Nested Vectored Interrupt Controller)。
什么是中断?
中断是一种机制,当外部设备(比如按键、定时器等)需要CPU(中央处理器)马上处理某个事情时,会发出一个中断信号,打断CPU当前正在做的工作,让CPU去处理这个紧急的事情。
NVIC的作用:
- 管理中断:当多个中断同时发生时,NVIC决定哪个中断先处理。
- 设置优先级:NVIC可以给不同的中断设置优先级,优先级高的中断会优先处理。
- 使能和屏蔽中断:NVIC可以打开(使能)或者关闭(屏蔽)某个中断,使它能不能打断CPU的工作。
- 中断处理:NVIC会找到对应中断处理函数,让CPU去执行。
举个例子:
想象一下,你正在写作业(CPU正在运行普通任务),这时候有人按门铃(一个外部中断发生)。NVIC就像一个管理员,它会决定这时候你应该先去开门(处理中断),还是继续写作业(继续当前任务)。如果你决定去开门,那么NVIC会记下你正在写的内容(保存上下文),等你开完门回来,再继续写作业。
解释为什么初始化代码这样写?
这种写法是根据硬件要求和官方库函数设计的标准初始化步骤。遵循这种写法可以确保代码的正确性、可读性和维护性,同时也符合STM32官方的建议和示例。
void USART1_Init(u32 bound){
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
- 定义结构体变量:声明GPIO、USART和NVIC的初始化结构体,用于配置相应的硬件模块。
- 启用时钟:USART1和GPIOA的时钟必须启用,否则这些外设无法工作。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
配置GPIO:配置USART1的TX引脚为复用推挽输出模式,速度为50MHz。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
配置GPIO:配置USART1的RX引脚为浮空输入模式。
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
配置NVIC:配置USART1的中断优先级,并启用中断。这样在接收到数据时能触发中断处理 函数。
USART_InitStructure.USART_BaudRate = bound;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
配置USART:设置波特率、数据位长度、停止位、奇偶校验、硬件流控制和模式(接收和发送)。
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
启用中断:启用USART1的接收中断。
USART_Cmd(USART1, ENABLE);
}
使能USART:使能USART1,使其开始工作。