一、UART示例升级版
1. 升级1,优化工程生成
STM32CubeMX操作同样的步骤,升级后生成代码。
2. 升级2,用UART接收控制指令,控制LED亮灭
修改源码:
main.c
#include <stdio.h>
#include "main.h"
#include "usart.h"
#include "gpio.h"
void SystemClock_Config(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
printf("Hello from STM32 HAL UART!\r\n");
while (1)
{
//主循环不处理
}
}
usart.c(在此添加重定向和中断处理回调函数)
要记得在启动UART接收中断,此外全是CubeMX自动生成
#include <stdio.h>
#include <string.h>
uint8_t rx_data;
// 重定向printf和scanf到USART1
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
// 接收到数据后的中断回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
if (rx_data == '1') {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET); // 点亮LED
const char *msg = "LED ON\r\n";
HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
}
else if (rx_data == '0') {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET); // 熄灭LED
const char *msg = "LED OFF\r\n";
HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
}
else {
const char *msg = "Unknown command\r\n";
HAL_UART_Transmit(&huart1, (uint8_t *)msg, strlen(msg), HAL_MAX_DELAY);
}
// 再次启动接收
HAL_UART_Receive_IT(&huart1, &rx_data, 1);
}
}
现象展示
现在就可以用串口控制LED的亮灭了。升级结束。
二、Timer示例编程
回想一下UART的实例现象,是UART发送一条信息,LED每隔500ms亮灭翻转,实现闪烁。当时使用的是HAL_Delay(500)。
现在改为用定时器实现LED每隔500ms亮灭翻转,在LED每次状态翻转的同时,UART发送一条信息“Hello,Timer!”
1. 使用STM32CubeMX 生成工程
第一步:启动 CubeMX 工程
打开 STM32CubeMX;
点击 “New Project”;
搜索并选择芯片:STM32F407VET6;
点击 “Start Project”。
第二步:配置外设(重点)
配置RCC和SYS----很重要,很简单,不赘述
1. 配置 GPIO
在 Pinout 视图点击 PA6,设置为 GPIO_Output;
2. 配置 USART1
点击 PA9 设置为 USART1_TX,PA10 设置为 USART1_RX;
在 Peripherals > USART1 中设置:
Mode: Asynchronous
Baud Rate: 115200
Enable USART1 global interrupt(中断可选,printf 不需要)
定时器配置如图:(图中没有使能中断,还要在NVIC Settings中使能中断)
3. 配置定时器 TIM2
在 Peripherals > TIM2:
3.1. 在 Mode > Clock Source:Internal Clock(内部时钟)
3.2. 在 Configuration > Parameter Settings 中设置:
Prescaler = 7199(定时器分频系数)
Counter Period = 4999(自动重装载值Arr)
定时器溢出时间:T = (Prescaler+1)×(Arr+1) / 定时器时钟频率(Hz)
分频:72MHz / (7199 + 1) = 10KHz
重装一次:10KHz / (4999 + 1) = 2Hz
换算成时间:1/2 = 0.5s = 500ms
也就是每 500ms 中断一次,也可以代入公式去计算
3.3. 在 Configuration > NVIC Settings中设置:勾选中断使能
第三步:配置时钟(Clock Configuration)
同前
第四步:Project Settings
点击左上角菜单栏 Project > Settings
设置项目名:HAL_LedUsart_Timer
选择工具链:MDK-ARM
Code Generation 默认问题不大,但是建议如升级示例设置
第五步:生成代码
点击右上角的 “GENERATE CODE”
代码结构已就绪
2. 编写 main.c 测试代码
#include "main.h"
#include "stdio.h"
UART_HandleTypeDef huart1;
TIM_HandleTypeDef htim2;
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
int main(void)
{
HAL_Init();
SystemClock_Config(); // CubeMX 自动生成
MX_GPIO_Init(); // PA6
MX_USART1_UART_Init(); // PA9/PA10
MX_TIM2_Init(); // TIM2 1Hz
HAL_TIM_Base_Start_IT(&htim2); // 启动定时器中断
while (1)
{
// 主循环无需处理,交给中断完成
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM2) //判断中断来自TIM2
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6);
printf("Hello,Timer!\r\n");
}
}
3. 编译下载
使用 Keil 编译
勾选如开篇文尾的Tips2和Tips3
使用 DAP 调试下载(有什么用什么吧)
用串口助手SSCom(115200 8N1)查看串口输出(PA9, PA10 接 USB 转串口)
4. 现象展示
同时伴有LED闪烁。
今天HAL库的简单示例:定时器就到这里啦!
Gitee代码仓库分享:
https://gitee.com/jinjing616/HAL_Test.git
明天继续分享下一个小示例。