STM32F103C8基于SysTick寄存器编程的LED按键控制代码验证
STM32F103C8寄存器级代码验证(按键无响应+LED闪烁需求)
需求与环境
- 硬件:STM32F103C8,系统时钟8MHz
- 外设连接:
- PA1:上拉输入(按键)
- PB8、PB9:推挽输出(LED)
- 功能要求:第一次按下按键,LED每秒闪烁;再次按下按键,关闭所有LED
- 问题:Proteus仿真中按键无响应,需验证代码正确性
原始代码
#include "stm32f10x.h" int main(void){ int S=0; RCC->APB2ENR|=0x0000000C; GPIOA->CRL=0; GPIOB->CRH=0; GPIOA->CRL|=0x00000880; GPIOA->ODR=1; GPIOB->CRH|=0x00000011; SysTick->LOAD=8000000; SysTick->VAL=0; SysTick->CTRL=5; while(1){ if(!(GPIOA->IDR&(1<<1))){ while(1){ if((SysTick->CTRL&(1<<16))){ if(S==0){ GPIOB->BSRR=(1<<8); GPIOB->BSRR=(1<<25); S=1; } else{ GPIOB->BSRR=(1<<24); GPIOB->BSRR=(1<<9); S=0; } } if(!(GPIOA->IDR&0x02)){ break; } } GPIOB->BSRR=(1<<24); GPIOB->BSRR=(1<<25); } } }
代码问题分析
1. GPIOA上拉配置错误
PA1配置为上拉输入时,需要将对应ODR位置1以启用内部上拉电阻。原始代码中GPIOA->ODR=1仅设置了PA0的上拉,PA1的上拉未启用,导致按键按下时电平检测异常。
2. SysTick延时周期错误
8MHz时钟下,SysTick要实现1秒延时,LOAD寄存器应设置为7999999(因为SysTick从LOAD值递减到0时触发计数,总周期为LOAD+1个时钟周期)。原始代码设置为8000000会导致实际延时略大于1秒。
3. 按键检测无消抖处理
按键按下/释放时存在机械抖动,直接检测电平会导致误触发(比如多次进入/退出闪烁逻辑),需要添加消抖延时。
4. 内部循环按键检测逻辑缺陷
内部循环中检测到按键按下直接退出,但未处理抖动,且没有等待按键释放,容易导致误操作。
修正后的代码
#include "stm32f10x.h" // 简单软件消抖函数 void Key_Delay(void){ uint32_t i; for(i=0; i<20000; i++); } int main(void){ int S=0; // 使能GPIOA和GPIOB时钟 RCC->APB2ENR |= 0x0000000C; // 配置PA1为上拉输入 GPIOA->CRL &= ~0x00000F00; // 清除PA1的CRL位[7:4] GPIOA->CRL |= 0x00000800; // PA1: CNF1=10(上拉输入), MODE1=00(输入) GPIOA->ODR |= (1<<1); // 启用PA1内部上拉 // 配置PB8、PB9为推挽输出 GPIOB->CRH &= ~0x000000FF; // 清除PB8、PB9的CRH位[7:0] GPIOB->CRH |= 0x00000011; // PB8/PB9: CNF=00(推挽输出), MODE=01(10MHz输出) // 配置SysTick为1秒周期 SysTick->LOAD = 7999999; // 8MHz时钟,LOAD=8000000-1 SysTick->VAL = 0; // 清除当前计数值 SysTick->CTRL = 5; // 使能SysTick,使用处理器时钟 while(1){ // 检测按键按下(带消抖) if(!(GPIOA->IDR & (1<<1))){ Key_Delay(); if(!(GPIOA->IDR & (1<<1))){ // 等待按键释放 while(!(GPIOA->IDR & (1<<1))); Key_Delay(); // 进入闪烁循环 while(1){ // 检测SysTick计数完成标志(自动清除) if(SysTick->CTRL & (1<<16)){ if(S == 0){ // PB8亮,PB9灭 GPIOB->BSRR = (1<<8); GPIOB->BSRR = (1<<25); S = 1; } else { // PB8灭,PB9亮 GPIOB->BSRR = (1<<24); GPIOB->BSRR = (1<<9); S = 0; } } // 检测按键按下退出闪烁(带消抖) if(!(GPIOA->IDR & (1<<1))){ Key_Delay(); if(!(GPIOA->IDR & (1<<1))){ // 等待按键释放 while(!(GPIOA->IDR & (1<<1))); Key_Delay(); break; } } } // 退出闪烁后关闭所有LED GPIOB->BSRR = (1<<24); GPIOB->BSRR = (1<<25); S = 0; } } } }
修正说明
- 启用PA1的内部上拉电阻,确保按键未按下时为高电平,按下时为低电平。
- 修正SysTick的LOAD值,保证1秒准确延时。
- 添加软件消抖函数,避免按键抖动导致的误触发。
- 优化按键检测逻辑,增加按键释放等待,确保单次按键触发一次操作。
内容的提问来源于stack exchange,提问作者Tchalago
相关产品推荐
相关产品推荐

