新闻详情

新闻详情

首页 / 资讯中心 / 详情

流水灯控制实验

发布时间:2026/9/30 7:23:19来源:尧图网络
流水灯控制实验
实验1 流水灯控制实验一、实验目的掌握STM32 GPIO寄存器底层原理理解GPIO端口寄存器地址、配置参数。掌握寄存器方式编写GPIO输出驱动实现LED流水灯。学会STM32标准外设库工程建立、库文件添加方法标准库方式驱动LED。掌握HAL库外部中断实现按键控制流水灯暂停/继续。学会Keil软件仿真逻辑分析仪观测GPIO输出波形测量闪烁周期。二、实验环境硬件STM32F103C8T6最小系统板、3只红绿蓝LED、杜邦线、面包板软件Keil MDK5STM32标准外设库V3.5STM32CubeMXHAL库ST-Link下载器三、实验原理STM32F103的GPIO端口可配置为通用推挽输出模式输出高低电平控制LED亮灭。LED一端串联电阻接GPIO引脚另一端接GNDGPIO输出低电平LED点亮输出高电平LED熄灭。最小系统自带PC13LED原理一致PC13为推挽输出控制板载LED。GPIO关键寄存器以GPIOC为例GPIOC_CRL端口低8位配置寄存器引脚0~7GPIOC_CRH端口高8位配置寄存器引脚8~15PC13在此寄存器GPIOC_ODR端口输出数据寄存器置1输出高电平置0输出低电平RCC_APB2ENRAPB2外设时钟使能寄存器开启GPIO端口时钟任务1寄存器方式实现流水灯包含PC13板载LED1.1 程序设计思路开启GPIOA、GPIOB、GPIOC的APB2外设时钟。配置GPIOA、GPIOB、GPIOC对应LED引脚为推挽输出模式最大速度50MHz。循环依次点亮单个LED其余熄灭软件延时1s不断轮换实现流水灯。将板载PC13 LED加入流水灯序列与外接3个LED轮流闪烁。寄存器地址RCC基地址0x40021000RCC_APB2ENR偏移0x18GPIOA基地址0x40010800GPIOB基地址0x40010C00GPIOC基地址0x40011000寄存器偏移CRL0x00CRH0x04ODR0x0C1.2 寄存器版C代码带详细注释#includestm32f10x.h// 简单软件延时函数粗略延时1svoidDelay_s(uint32_ts){uint32_ti,j;for(i0;is;i)for(j0;j7200000;j);}voidLED_GPIO_Init(void){// 1.开启GPIOA/GPIOB/GPIOC时钟 RCC_APB2ENR*(volatileuint32_t*)(0x400210000x18)|(12)|(13)|(14);// bit2:GPIOA, bit3:GPIOB, bit4:GPIOC// PA0推挽输出 50MHzCRL寄存器*(volatileuint32_t*)(0x400108000x00)~(0x0F0);//清空PA0*(volatileuint32_t*)(0x400108000x00)|(0x030);//0011 推挽输出50M// PB0推挽输出 50MHz*(volatileuint32_t*)(0x40010C000x00)~(0x0F0);*(volatileuint32_t*)(0x40010C000x00)|(0x030);// PC13推挽输出 50MHzCRH寄存器(PC13对应bit20~23)*(volatileuint32_t*)(0x400110000x04)~(0x0F20);*(volatileuint32_t*)(0x400110000x04)|(0x0320);}intmain(void){LED_GPIO_Init();while(1){// PA0亮其余灭*(volatileuint32_t*)(0x400108000x0C)~(10);*(volatileuint32_t*)(0x40010C000x0C)|(10);*(volatileuint32_t*)(0x400110000x0C)|(113);Delay_s(1);// PB0亮其余灭*(volatileuint32_t*)(0x400108000x0C)|(10);*(volatileuint32_t*)(0x40010C000x0C)~(10);*(volatileuint32_t*)(0x400110000x0C)|(113);Delay_s(1);// PC13板载LED亮其余灭*(volatileuint32_t*)(0x400108000x0C)|(10);*(volatileuint32_t*)(0x40010C000x0C)|(10);*(volatileuint32_t*)(0x400110000x0C)~(113);Delay_s(1);}}任务2标准外设库版本流水灯2.1工程项目创建、添加标准库详细步骤1.打开 Keil MDK5新建Project选择芯片STM32F103C8T6创建工程文件夹命名LED_STDLIB。2.从 STM32F10x_StdPeriph_Lib 库中复制inc头文件文件夹、src源文件文件夹到工程目录。3.Keil 工程中点击Manage Project Items新建StdLib分组添加需要的库.c文件stm32f10x_gpio.c、stm32f10x_rcc.c。4.打开OptionsforTarget → C/C添加头文件路径..\inc添加宏定义STM32F10X_MD,USE_STDPERIPH_DRIVER。5.新建main.c添加用户代码编译工程。2.2标准库代码#includestm32f10x.hvoidDelay_s(uint32_ts){uint32_ti,j;for(i0;is;i)for(j0;j7200000;j);}voidLED_Init(void){GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);//PA0GPIO_InitStruct.GPIO_PinGPIO_Pin_0;GPIO_InitStruct.GPIO_ModeGPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_SpeedGPIO_Speed_50MHz;GPIO_Init(GPIOA,GPIO_InitStruct);//PB0GPIO_InitStruct.GPIO_PinGPIO_Pin_0;GPIO_Init(GPIOB,GPIO_InitStruct);//PC13GPIO_InitStruct.GPIO_PinGPIO_Pin_13;GPIO_Init(GPIOC,GPIO_InitStruct);}intmain(void){LED_Init();while(1){GPIO_ResetBits(GPIOA,GPIO_Pin_0);GPIO_SetBits(GPIOB,GPIO_Pin_0);GPIO_SetBits(GPIOC,GPIO_Pin_13);Delay_s(1);GPIO_SetBits(GPIOA,GPIO_Pin_0);GPIO_ResetBits(GPIOB,GPIO_Pin_0);GPIO_SetBits(GPIOC,GPIO_Pin_13);Delay_s(1);GPIO_SetBits(GPIOA,GPIO_Pin_0);GPIO_SetBits(GPIOB,GPIO_Pin_0);GPIO_ResetBits(GPIOC,GPIO_Pin_13);Delay_s(1);}}2.3软件延时周期Keil 逻辑分析仪仿真1.软件循环延时特点软件空循环延时不精确会受编译器优化、CPU 时钟影响只是粗略1秒。2.Keil 仿真步骤-开启 DebugUse Simulator进入 Debug 模式。-打开Logic Analyzer添加 GPIOA-ODR、GPIOB-ODR、GPIOC-ODR 信号。-运行仿真观测波形高低电平翻转时刻。3.时序分析 逻辑分析仪可以捕获 GPIO 引脚电平跳变测量高电平持续时间、低电平持续时间。 软件延时的实际周期不等于1s存在误差可根据波形读出真实闪烁周期。 任务3HAL 库外部中断按键控制流水灯暂停/继续#includestm32f1xx_hal.h//全局标志uint8_trun_flag1;//1运行0暂停GPIO_HandleTypeDef hgpio_led;GPIO_HandleTypeDef hgpio_key;voidSystemClock_Config(void);staticvoidMX_GPIO_Init(void);voidEXTI0_IRQHandler(void){HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);}//外部中断回调函数voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){if(GPIO_PinGPIO_PIN_0){run_flag!run_flag;//翻转启停状态}}voidDelay_ms(uint32_tms){HAL_Delay(ms);}intmain(void){HAL_Init();SystemClock_Config();MX_GPIO_Init();while(1){if(run_flag1){HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);Delay_ms(1000);HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);Delay_ms(1000);HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);Delay_ms(1000);}}}staticvoidMX_GPIO_Init(void){GPIO_InitTypeDef GPIO_InitStruct{0};__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();//LED输出GPIO_InitStruct.PinGPIO_PIN_0;GPIO_InitStruct.ModeGPIO_MODE_OUTPUT_PP;GPIO_InitStruct.SpeedGPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA,GPIO_InitStruct);HAL_GPIO_Init(GPIOB,GPIO_InitStruct);GPIO_InitStruct.PinGPIO_PIN_13;HAL_GPIO_Init(GPIOC,GPIO_InitStruct);//按键PA0 外部中断下降沿GPIO_InitStruct.PinGPIO_PIN_0;GPIO_InitStruct.ModeGPIO_MODE_IT_FALLING;GPIO_InitStruct.PullGPIO_PULLUP;HAL_GPIO_Init(GPIOA,GPIO_InitStruct);HAL_NVIC_EnableIRQ(EXTI0_IRQn);HAL_NVIC_SetPriority(EXTI0_IRQn,0,0);}voidSystemClock_Config(void){RCC_OscInitTypeDef RCC_OscInitStruct{0};RCC_ClkInitTypeDef RCC_ClkInitStruct{0};RCC_OscInitStruct.OscillatorTypeRCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEStateRCC_HSE_ON;RCC_OscInitStruct.HSEPredivValueRCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIStateRCC_HSI_ON;RCC_OscInitStruct.PLL.PLLStateRCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSourceRCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMULRCC_PLL_MUL9;if(HAL_RCC_OscConfig(RCC_OscInitStruct)!HAL_OK){Error_Handler();}RCC_ClkInitStruct.ClockTypeRCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSourceRCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDividerRCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDividerRCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDividerRCC_HCLK_DIV1;if(HAL_RCC_ClockConfig(RCC_ClkInitStruct,FLASH_LATENCY_2)!HAL_OK){Error_Handler();}}voidError_Handler(void){__disable_irq();while(1){}}#ifdefUSE_FULL_ASSERTvoidassert_failed(uint8_t*file,uint32_tline){}#endif/* USE_FULL_ASSERT */四、实验结果与分析1.![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7a02300e52404533994dcad8a9890e63.png)(https://i-blog.csdnimg.cn/direct/37bf46c6098f4511b3471e99dd40caca.png)(https://i-blog.csdnimg.cn/direct/735b791fd29e4e8eb518df89869671cc.png)寄存器版本程序下载后PA0、PB0、PC13 板载 LED 轮流点亮间隔约 1s流水灯正常运行验证寄存器配置正确。2.标准库版本调用库函数初始化 GPIO实现相同流水效果Keil 逻辑分析仪观测 GPIO 波形高低电平翻转对应 LED 亮灭。软件空循环延时存在误差实际周期和理论1s 有偏差。3.HAL 库外部中断版本按下按键流水灯暂停再次按下恢复流水实现启停控制。![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/98269a85014d47be8d803effcdb42527.png)(https://i-blog.csdnimg.cn/direct/564a56fccc6f40e8a25afa308a438ca2.png)(https://i-blog.csdnimg.cn/direct/c852b53fa86140dbb688ca8f973d3657.png)(https://i-blog.csdnimg.cn/direct/ebfb093e04cc4b8891f878bffdef447d.png)五、实验总结5.寄存器方式直接操作内存地址底层可控适合理解 STM32 硬件原理代码简洁但可读性差。6.标准外设库封装底层寄存器开发更快工程搭建需要手动添加库文件。7.HAL 库更抽象结合外部中断可以实现按键事件驱动中断不会阻塞主循环。8.软件延时精度低精确定时推荐使用定时器中断Keil 逻辑分析仪可以无硬件示波器情况下观测 GPIO 输出波形调试 GPIO 时序。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Windows 11禁用用户账户的四种方法与原理详解 2026/9/30 9:16:13

Windows 11禁用用户账户的四种方法与原理详解

1. 禁用用户帐户不是“删除”,而是精准控制访问权限 在Windows 11里,很多人一看到“禁用用户帐户”就下意识点开“设置→账户→家庭和其他用户”,然后找“删除”按钮——结果发现灰色不可点,或者点了之后弹出“此帐户与Microsoft账…

阅读更多 →
Linux Java环境配置四层契约:JDK选型、环境变量、多版本共存与验证闭环 2026/9/30 9:16:13

Linux Java环境配置四层契约:JDK选型、环境变量、多版本共存与验证闭环

1. 为什么在Linux上装Java环境不是“点下一步”那么简单很多人第一次在Linux上配Java开发环境,心里想的是:“不就是下载个JDK,解压,配个PATH,完事?”——我当年也是这么想的,直到被三类问题轮番…

阅读更多 →
云原生架构白皮书落地实践:从容器到微服务的避坑指南 2026/9/30 9:16:12

云原生架构白皮书落地实践:从容器到微服务的避坑指南

简介:《云原生架构白皮书》(70页)由阿里云发布,面向企业架构师、开发者与技术决策者,系统阐述云原生作为数字化转型最短路径的价值,以及容器、微服务、Serverless、Service Mesh、DevOps、OAM等关键技术&am…

阅读更多 →
8GB显存如何跑35B大模型:量化与分层卸载实战指南 2026/9/30 9:16:06

8GB显存如何跑35B大模型:量化与分层卸载实战指南

先说结论:8GB显存跑35B级别模型,这事听起来确实有点反常识,但真的可行。核心不是把模型塞进显存,而是让显存、内存和推理框架各司其职,该卸载的卸载,该量化的量化,该换代的换代。我这次用一张RT…

阅读更多 →
云原生架构白皮书:从70页PDF到生产落地的完整指南 2026/9/30 9:16:06

云原生架构白皮书:从70页PDF到生产落地的完整指南

简介:由阿里云发布的《云原生架构白皮书》(70页)系统阐述了云原生架构的概念、关键技术及其在企业数字化转型中的应用,面向企业技术决策者、架构师与开发者,也适合正在规划技术演进路径的团队。内容涵盖容器、微服务、…

阅读更多 →
C++依赖分析实战:从物理设计到工程治理,根治编译与耦合问题 2026/9/30 9:16:06

C++依赖分析实战:从物理设计到工程治理,根治编译与耦合问题

搭建C项目时,依赖分析是绕不开的一关。很多人把依赖分析当成看头文件里include了啥,或者用工具生成一张调用图就完事。实际上,真正决定项目能否长期演进、多人协作、性能可控的关键,在于通过合适的头文件与编译依赖拆分&#xff0…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉