ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

STM3流水灯综合实验

STM3流水灯综合实验 实验一 寄存器方式实现四路流水灯实验名称STM32F103C8T6寄存器编程实现四路LED流水灯一、实验目的1. 熟悉STM32F103最小系统板硬件理解GPIO端口功能与APB2外设时钟作用。​2. 掌握直接操作寄存器配置GPIO理解CRL、CRH、BSRR寄存器功能学会位操作。​3. 使用PA0、PB0、PB1外接LED结合板载PC13 LED实现四路流水灯间隔约1s轮流点亮。​4. 掌握Keil‑MDK工程创建、编译、ST‑Link下载调试流程。​5. 理解 volatile 关键字作用练习将工程上传Gitee撰写实验博客。二、实验器材1. STM32F103C8T6最小系统板​2. ST‑Link仿真下载器​3. 面包板红、绿、蓝LED各1只220Ω限流电阻杜邦线若干​4. 笔记本电脑Keil uVision5三、实验原理GPIO外设使用前必须开启对应总线时钟GPIOA、GPIOB、GPIOC挂载在APB2总线由 RCC-APB2ENR 控制时钟。- GPIOx‑CRL 管理引脚0‑7配置模式与输出速度PA0、PB0、PB1由CRL控制。​- GPIOx‑CRH 管理引脚8‑15PC13使用CRH寄存器。​- BSRR 置位复位寄存器低16位写1引脚输出高电平高16位写1引脚输出低电平无读改写风险。硬件电路外接LEDPA0、PB0、PB1串联220Ω电阻接LED阳极阴极接GND高电平点亮。板载PC13 LED硬件反向驱动低电平点亮高电平熄灭。延时采用双层for空循环软件延时会受编译器优化影响延时并不严格准确。表格寄存器 基地址 偏移地址RCC 0x40021000 0x18(APB2ENR)GPIOA 0x40010800 0x00(CRL)、0x10(BSRR)GPIOB 0x40010C00 0x00(CRL)、0x10(BSRR)GPIOC 0x40011000 0x04(CRH)、0x10(BSRR)四、程序设计思路1. 使用寄存器指针访问硬件寄存器 volatile 防止编译器优化读写。​2. 开启GPIOA、GPIOB、GPIOC的APB2外设时钟。​3. CRL、CRH对应位先清零再赋值配置PA0、PB0、PB1、PC13为50MHz推挽输出。​4. 初始化所有LED为熄灭状态。​5. 编写软件延时函数。​6. while死循环使用BSRR寄存器依次点亮单路LED其余熄灭延时后切换流水顺序PA0→PB0→PB1→PC13循环。五、实验代码while(1)#include stm32f10x.h//软件粗略延时volatile防止编译器优化void Soft_Delay(uint32_t t){volatile uint32_t i,j;for(i 0; i t; i){for(j 0; j 7200; j);}}int main(void){//开启GPIOA GPIOB GPIOC时钟RCC-APB2ENR | (1U 2) | (1U 3) | (1U 4);//PA0 50MHz推挽输出GPIOA-CRL ~(0x0FU 0);GPIOA-CRL | (0x03U 0);//PB0 50MHz推挽输出GPIOB-CRL ~(0x0FU 0);GPIOB-CRL | (0x03U 0);//PB1 50MHz推挽输出GPIOB-CRL ~(0x0FU 4);GPIOB-CRL | (0x03U 4);//PC13CRH寄存器50MHz推挽输出GPIOC-CRH ~(0x0FU 20);GPIOC-CRH | (0x03U 20);//全部LED初始熄灭GPIOA-BSRR (1U 0) 16;GPIOB-BSRR ((1U 0)|(1U 1)) 16;GPIOC-BSRR (1U 13);while(1){//点亮PA0GPIOA-BSRR 1U 0;GPIOB-BSRR ((1U0)|(1U1)) 16;GPIOC-BSRR 1U 13;Soft_Delay(1000);//点亮PB0GPIOA-BSRR (1U0)16;GPIOB-BSRR 1U 0;GPIOB-BSRR (1U1)16;GPIOC-BSRR 1U 13;Soft_Delay(1000);//点亮PB1GPIOA-BSRR (1U0)16;GPIOB-BSRR (1U0)16;GPIOB-BSRR 1U 1;GPIOC-BSRR 1U 13;Soft_Delay(1000);//点亮PC13板载LEDGPIOA-BSRR (1U0)16;GPIOB-BSRR ((1U0)|(1U1)) 16;GPIOC-BSRR (1U 13) 16;Soft_Delay(1000);}}六、实验步骤1. 硬件接线PA0、PB0、PB1串联220Ω电阻接LEDLED阴极接GNDST‑Link连接SWDIO、SWCLK、GND、3.3V。​2. Keil新建工程选择芯片STM32F103C8添加启动文件新建main.c粘贴代码。​3. 调试器选择ST‑Link设置下载后自动复位运行。​4. 编译工程无报错后下载程序。​5. 上电观察LED流水现象截图Keil界面、硬件实物。​6. 将工程Git上传Gitee仓库。七、实验现象上电后LED按照PA0→PB0→PB1→PC13顺序依次点亮同一时刻只亮一盏灯每盏灯维持约1s循环流水。软件延时存在误差间隔不是严格1秒。八、遇到的问题与解决1. 没有加 volatile 修饰延时变量编译器直接优化掉延时灯切换飞快。添加volatile后延时正常。​2. 一开始用ODR寄存器出现引脚互相干扰改用BSRR置位复位寄存器解决。​3. PC13错误操作CRL寄存器板载LED无反应修改操作CRH寄存器后正常。​4. ST‑Link下载失败是SWCLK杜邦线接触不良重新插紧即可下载。九、实验总结寄存器编程直接操作硬件地址可以深入理解GPIO底层工作原理但是要记住寄存器地址与每一位功能写代码比较繁琐。必须开启外设时钟GPIO才可以工作PC13属于CRH寄存器BSRR比ODR更加安全。软件延时只能粗略等待不能用于高精度时序。实验二 标准外设库实现四路流水灯实验名称STM32F103标准外设库流水灯实验一、实验目的1. 掌握Keil中搭建标准外设库工程添加库文件配置头文件路径与编译宏。​2. 学会使用标准库RCC、GPIO函数理解库对寄存器的封装。​3. 实现PA0、PB0、PB1、PC13四路流水灯间隔约1s轮流点亮。​4. 使用Keil逻辑分析仪仿真观察引脚波形分析软件延时误差。​5. 工程上传Gitee记录实验过程。二、实验器材1. STM32F103C8T6最小系统板​2. ST‑Link仿真下载器​3. 面包板LED×3220Ω电阻杜邦线​4. 电脑Keil uVision5STM32F10x标准外设库三、实验原理标准外设库将底层寄存器操作封装成C函数不用手动操作寄存器地址。- RCC_APB2PeriphClockCmd() 使能GPIO端口时钟。​- GPIO_InitTypeDef 结构体配置引脚模式、输出速度。​- GPIO_SetBits() 引脚输出高电平 GPIO_ResetBits() 输出低电平。硬件接线和实验一完全一致外接LED高电平点亮PC13板载LED低电平点亮。延时依旧使用软件双层循环定时精度有限。Keil逻辑分析仪可以仿真观察引脚电平变化测量实际延时。四、程序设计思路1. 工程导入标准库 stm32f10x_rcc.c 、 stm32f10x_gpio.c 配置编译宏 USE_STDPERIPH_DRIVER 。​2. 编写GPIO初始化函数开启GPIOA/GPIOB/GPIOC时钟配置引脚为50MHz推挽输出。​3. 编写软件延时函数。​4. main死循环依次点亮PA0→PB0→PB1→PC13其余熄灭延时循环。五、实验代码#include stm32f10x.hvoid Delay_ms(uint32_t ms){uint32_t i,j;for(i 0; i ms; i)for(j 0; j 7200; j);}void LED_Init(void){GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);//PA0??GPIO_InitStruct.GPIO_Pin GPIO_Pin_0;GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA,GPIO_InitStruct);//PB0 PB1??GPIO_InitStruct.GPIO_Pin GPIO_Pin_0|GPIO_Pin_1;GPIO_Init(GPIOB,GPIO_InitStruct);GPIO_SetBits(GPIOA,GPIO_Pin_0);GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_1);}六、实验步骤1. 硬件保持实验一接线不变ST‑Link连接开发板。​2. 新建Keil工程复制标准库inc、src文件夹到工程目录。​3. 新建工程分组User、StdPeriph_Driver、Startup添加main.c、rcc.c、gpio.c、启动文件。​4. 魔术棒配置头文件路径添加宏定义 USE_STDPERIPH_DRIVER,STM32F10X_MD 。​5. 调试器选择ST‑Link编译下载程序。​6. 打开Keil软件仿真调出逻辑分析仪添加PA0、PB0、PB1、PC13引脚观察波形。​7. 记录现象截图工程上传Gitee。七、实验现象下载完成LED按PA0→PB0→PB1→PC13顺序轮流点亮每个灯约1秒切换。逻辑分析仪观察引脚周期性翻转软件延时实际时间和理论1秒存在误差。八、遇到的问题与解决1. 编译报大量头文件找不到没有配置inc头文件路径添加路径后解决。​2. 忘记添加 USE_STDPERIPH_DRIVER 宏库函数全部未定义报错。​3. PC13电平逻辑搞反调用 GPIO_SetBits() 点亮板载LED灯反而熄灭修改为 GPIO_ResetBits() 。​4. 逻辑分析仪看不到波形没有切换到软件仿真模式修改工程仿真设置。​5. 把全部库文件加入工程编译速度很慢只添加rcc.c与gpio.c即可。九、实验总结标准外设库对寄存器进行封装不用记忆寄存器地址代码可读性高。使用结构体配置GPIO很方便但同样必须开启外设时钟。仿真波形直观看到软件延时精度不足如果需要精准定时需要使用定时器外设。实验三 HAL库外部中断按键控制流水灯暂停/继续实验名称HAL库外部中断实验按键控制四路流水灯暂停恢复一、实验目的1. 熟悉STM32CubeMX图形化配置生成HAL库工程。​2. 掌握外部中断配置理解中断回调函数运行机制。​3. 在四路流水灯基础上按键触发外部中断实现流水灯运行与暂停切换。​4. 理解中断编程规范回调函数只修改标志位耗时代码放在主循环。​5. 工程上传Gitee整理实验记录。二、实验器材1. STM32F103C8T6最小系统板​2. ST‑Link下载器​3. 面包板LED220Ω电阻按键杜邦线​4. 电脑STM32CubeMXKeil‑MDK三、实验原理外部中断EXTI引脚电平跳变触发中断CPU暂停主循环执行中断服务函数最终调用 HAL_GPIO_EXTI_Callback() 回调函数。本实验按键接PA0下降沿触发外部中断设置全局标志位 run_flag 中断中翻转标志位。主循环判断标志位 run_flag1 执行流水灯 run_flag0 停止流水LED保持当前状态。重要中断回调函数不能放置延时、循环等耗时代码仅允许简单变量修改。LED硬件电路和前面实验保持一致。按键一端接PA0一端接GND开启内部上拉。四、程序设计思路1. CubeMX配置系统时钟72MHzPA0配置外部中断下降沿触发开启上拉PA0、PB0、PB1、PC13配置为GPIO输出。​2. 生成Keil HAL工程。​3. 定义全局标志位 run_flag1 代表流水灯运行。​4. 在外部中断回调函数翻转run_flag。​5. while主循环判断标志位标志位为1执行流水灯逻辑为0不执行。​6. 软件延时下载调试观察现象。五、核心代码/* USER CODE BEGIN Header *//********************************************************************************* file : main.c* brief : Main program body******************************************************************************* attention** Copyright (c) 2026 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************//* USER CODE END Header *//* Includes ------------------------------------------------------------------*/#include main.h/* Private includes ----------------------------------------------------------*//* USER CODE BEGIN Includes *//* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*//* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*//* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*//* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV */uint8_t run_flag 1; //1流水灯运行0暂停/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/void SystemClock_Config(void);static void MX_GPIO_Init(void);/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*//* USER CODE BEGIN 0 *///外部中断回调函数PA2触发中断自动进入void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){if(GPIO_Pin GPIO_PIN_2){run_flag !run_flag; //翻转状态运行 ↔ 暂停}}/* USER CODE END 0 *//*** brief The application entry point.* retval int*/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();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){if(run_flag 1){//PA0亮1秒HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);HAL_Delay(1000);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);//PB0亮1秒HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);HAL_Delay(1000);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);//PB1亮1秒HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);HAL_Delay(1000);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);}//run_flag0时循环空转流水灯保持暂停}/* USER CODE END WHILE *//* USER CODE BEGIN 3 *//* USER CODE END 3 */}/*** brief System Clock Configuration* retval None*/void SystemClock_Config(void){RCC_OscInitTypeDef RCC_OscInitStruct {0};RCC_ClkInitTypeDef RCC_ClkInitStruct {0};/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL RCC_PLL_MUL9;if (HAL_RCC_OscConfig(RCC_OscInitStruct) ! HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(RCC_ClkInitStruct, FLASH_LATENCY_2) ! HAL_OK){Error_Handler();}}/*** brief GPIO Initialization Function* param None* retval None*/static void MX_GPIO_Init(void){GPIO_InitTypeDef GPIO_InitStruct {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|GPIO_PIN_1, GPIO_PIN_SET);/*Configure GPIO pin : PA0 */GPIO_InitStruct.Pin GPIO_PIN_0;GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull GPIO_NOPULL;GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, GPIO_InitStruct);/*Configure GPIO pin : PA2 */GPIO_InitStruct.Pin GPIO_PIN_2;GPIO_InitStruct.Mode GPIO_MODE_IT_FALLING;GPIO_InitStruct.Pull GPIO_PULLUP;HAL_GPIO_Init(GPIOA, GPIO_InitStruct);/*Configure GPIO pins : PB0 PB1 */GPIO_InitStruct.Pin GPIO_PIN_0|GPIO_PIN_1;GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull GPIO_NOPULL;GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOB, GPIO_InitStruct);/* EXTI interrupt init*/HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0);HAL_NVIC_EnableIRQ(EXTI2_IRQn);}/*** brief This function is executed in case of error occurrence.* retval None*/void Error_Handler(void){/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */}#ifdef USE_FULL_ASSERT/*** brief Reports the name of the source file and the source line number* where the assert_param error has occurred.* param file: pointer to the source file name* param line: assert_param error line source number* retval None*/void assert_failed(uint8_t *file, uint32_t line){/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf(Wrong parameters value: file %s on line %d\r\n, file, line) *//* USER CODE END 6 */}#endif /* USE_FULL_ASSERT */六、实验步骤1. 保留LED接线按键接PA0与GNDST‑Link连接开发板。​2. CubeMX选择芯片STM32F103C8T6配置外部晶振调试接口Serial Wire。​3. PA0设置为 GPIO_EXTI0 下降沿触发开启上拉PA0、PB0、PB1、PC13设置输出。时钟树配置72MHz。​4. 生成Keil工程。​5. 打开工程替换main.c业务代码编译。​6. ST‑Link下载程序按下按键观察流水灯暂停与继续效果。​7. 记录现象截图工程上传Gitee。七、实验现象八、遇到的问题与解决1. 按键偶尔多次触发缺少硬件消抖后续可以增加软件消抖代码。​2. 一开始在中断回调写延时程序运行异常老师提醒中断不能放耗时代码只修改标志位。​3. CubeMX没有开启引脚内部上拉按键电平不稳定开启上拉配置后按键识别正常。​4. 重新生成CubeMX工程把main.c代码覆盖需要保留用户代码段。九、实验总结HAL库配合CubeMX图形配置硬件不需要手写大量初始化代码开发效率高。外部中断不需要CPU轮询查询按键电平变化立刻响应。中断回调函数要尽量简短业务逻辑放到主循环处理。对比寄存器、标准库、HAL三种开发方式对GPIO、时钟、中断有了更加完整理解。
返回列表