1. 任务目标
使用单片机定时器实现1s翻转LED验证开发板时钟晶振是否正确
2. 开发工具
STM32 支持的开发环境很多,我现在中意下面的组合:
• STM32CubeMX 图形化配置、生成工程;
• STM32CubeCLT 意法半导体退出的一体化、多操作系统支持的命令行工具,主要面向第三发集成开发环境提供商,允许他们在自己的IDE框架内集成对STM32微控制器的支持,包括代码编译、烧录、调试等功能;
• CLion 一个功能强大的且智能化的 C/C++ 开发环境,具有高效的代码编辑、调试和项目管理能力;
• STM32CubeIDE/Keil MDK/IAR 曾经非常流行的 STM32 开发环境,这里不做介绍;
分别安装 STM32CubeMX/STM32CubeCLT 以及 CLion,然后再 Clion 中新建 STM32CubeMX 工程。
在 CLion 中第一次新建 STM32CubeMX,还需要配置 STM32CubeMX 和 STM32CubeCLT 工具路径,下图中(2)出点击“编辑”分别选择对应的路径即可。
• 下图在 SDK 目录中新建一个工程;
• STM32CubeMX 和 STM32CubeCLT 工具检测OK;
• 启动 STM32CubeMX 配置工程,导出 CMake 工程即可
• 然后 CLion 打开刚才生成的工程目录即可,自动加载 CMakeLists.txt 并配置工程
第一次打开CMakeLists.txt 工程,弹出下面的配置对话框,一般选择 Debug 类型即可
3. ST-Link 固件升级
第一次调试工程,弹出 ST-Link 固件升级提示,按照下面的提示操作,升级固件通过。
点击右下角的 YES 开始升级固件
固件升级成功
升级后固件版本号变了
4. 用户 LED
LED 是指用户LED,即板子上的绿色 LD2 ,对应 PA5 ,原理图如下:
4.1 定时器
这里使用定时器1,配置如下:
• 时钟源,选择 Internal Clock (TIM1 位于 APB2 Timer Clock)
• 预分频为 1000-1
• 向上计数模式
• 计数周期 10000-1
4.2 为什么这么设置预分频和计数周期呢?
因为参考手册中 STM32F411xx 的 TIM1 位于 APB2 Timer clock 上,见下图。而且在时钟树中把 APB2 Timer Clock 设置为100MHz。
所以预分频 1000-1 把 TIM1 时钟频率配置为 100MHz/1000 = 100KHz
计数周期 10000-1 即 0.1 秒钟产生中断。【要实现1秒钟翻转LED,需要计数10次】
最后使能 TIM1 的中断,中断类型是 TIM1 update interrupt and TIM10 global interrupt,表示定时器溢出产生中断。
5. 流程
• 主流程中初始化硬件(GPIO、UART2、TIM1)然后已开启中断的方式启动TIM1
• 在TIM1的溢出中断服务函数中层层调用到 HAL_TIM_PeriodElapsedCallback() 函数,计数10次达到1秒钟,翻转用户LD2
6. 关键代码
6.1 主函数
int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART2_UART_Init(); MX_TIM1_Init(); // 配置定时器TIM1 /* USER CODE BEGIN 2 */ HAL_TIM_Base_Start_IT(&htim1); // 启动定时器 TIM1 /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { HAL_Delay(200); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }
6.2 TIM1定时溢出回调函数
tim.c 中新增加一个函数,定时器溢出回调函数 HAL_TIM_PeriodElapsedCallback() 中实现1秒钟翻转LED2
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == htim1.Instance) // 确保是特定的定时器实例(例如TIM1、TIM2等) { tim_elapsed_cnt++; if (tim_elapsed_cnt % 10 == 0) { HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); } } }
7. 实测演示
7.1 LD2闪烁
板子中心的绿色 LD 每隔一秒钟点亮、熄灭一次。