使用key使用外部中断,只要key被按下,就触发中断回调函数。led灯是推挽输出模式。
发生中断——》HAL_GPIO_EXTI_IRQHandler——》回调函数。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
static uint32_t tick = 0;
static uint32_t count = 0;
/* 非阻塞消抖 */
if(HAL_GetTick() - tick < 300)
//HAL_GetTick():当前系统时间
//tick:上次记录的时间
return;
tick = HAL_GetTick();//避免因按键抖动造成的多次中断。
HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(LED_G_GPIO_Port, LED_G_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(LED_B_GPIO_Port, LED_B_Pin, GPIO_PIN_SET);
if(GPIO_Pin == KEY_Pin) {
switch(count++ % 4) {
case 0: HAL_GPIO_TogglePin(LED_R_GPIO_Port, LED_R_Pin); break;
case 1: HAL_GPIO_TogglePin(LED_G_GPIO_Port, LED_G_Pin); break;
case 2: HAL_GPIO_TogglePin(LED_B_GPIO_Port, LED_B_Pin); break;
default: break;
}
}
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
while (1)
{
}
}
20240919 一直弄不出来的原因是:没有外部中断函数,估计是当时把头文件的该函数删掉了。后面补在main就可以了。
这个注释掉:蓝-绿-红
// LED0(1);
//LED1(1);
// LED2(1);
放出来: 蓝—绿蓝—蓝红——红
stm32vet6的板子是低电平触发,所以这里置1,即给高电平没有反应
LED0(0);
LED1(1);
LED2(1);
- 灯依次亮起(成功)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
static uint32_t tick = 0;
static uint32_t count = 0;
static uint32_t flash_tick = 0;
static uint32_t is_flashing = 0; // 标志位,用于切换闪烁状态
/* 非阻塞消抖 */
if(HAL_GetTick() - tick < 300)
//HAL_GetTick():当前系统时间
//tick:上次记录的时间
return;
tick = HAL_GetTick();//避免因按键抖动造成的多次中断。
LED0(1);
LED1(1);
LED2(1);
//灯依次亮
if(GPIO_Pin == KEY_Pin) { // 确保是按下指定的按键
is_flashing = !is_flashing; // 切换闪烁状态
}
/* 如果是闪烁状态 */
if(is_flashing) {
if(HAL_GetTick() - flash_tick >= 500) { // 每500ms切换一次LED状态
flash_tick = HAL_GetTick(); // 更新闪烁时间
/* 依次切换LED */
LED0(0);
HAL_Delay(500);
LED0(1);
HAL_Delay(500);
LED1(0);
HAL_Delay(500);
LED1(1);
}
} else {
/* 如果不处于闪烁状态,确保LED全部关闭 */
LED0(1);
LED1(1);
LED2(1);
}
}
- 基本定时器实现灯的闪烁(已成功)
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(85, 2, 2, 4, 8); /* 设置时钟,170Mhz */
delay_init(170); /* 延时初始化 */
led_init(); /* 初始化LED */
btim_timx_int_init(5000 - 1, 17000 - 1); /* 10Khz的计数频率,计数5K次为500ms */
while (1)
{
LED0_TOGGLE(); /* LED0(红灯) 翻转*/
delay_ms(200);
}
}
-
外部按键中断+基本定时器+灯闪烁
需要使用基本定时器(btim.c)的中断回调函数那里编写。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static uint8_t led_state = 0;
if (htim->Instance == BTIM_TIMX_INT)
{
switch(led_state){
case 0: {
LED0(0);
LED1(1);
LED2(1);
led_state ++;
break;}case 1: { LED0(1); LED1(0); LED2(0); led_state ++; break;} default: { LED0(0); LED1(0); LED2(0); led_state =0; break;} }
}
} -
外部按键中断+通用定时器+灯闪烁(成功)
-
通用定时器有无PWM的区别
3.1 开启的代码不同:
无PWM: HAL_TIM_Base_Start_IT(&g_timx_handle2);
有PWM: HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY); /* 开启对应PWM通道 */
3.2初始化代码不同:
HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle); //初始化PWM /* 初始化PWM */
HAL_TIM_Base_Init(&g_timx_handle2);
3.3PWM 多的代码:
timx_oc_pwm_chy.OCMode = TIM_OCMODE_PWM1; /* 模式选择PWM1 */
timx_oc_pwm_chy.Pulse = ( arr + 1 ) / 2; /* 设置比较值,此值用来确定占空比 */
/* 默认比较值为自动重装载值的一半,即占空比为50% */
timx_oc_pwm_chy.OCPolarity = TIM_OCPOLARITY_LOW; /* 输出比较极性为低 */
HAL_TIM_PWM_ConfigChannel(&g_timx_pwm_chy_handle, &timx_oc_pwm_chy, GTIM_TIMX_PWM_CHY); /* 配置TIMx通道y */
3.4PWM 还多了MSP
HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
4.PWM本质:改变占空比
5.PWM 的ARR:设置为 500 - 1,即每个周期有 500 个计数单位(对应频率 2kHz)。
ledrpwmval 用作比较值:决定占空比
6.PWM的频率=定时器时钟频率/(ARR+1)(PSC+1)
定时器时钟频率=系统时钟频率/(预分频器值+1)
这里,设置了预分频器值170-1,系统时钟频率170MHZ
计算得定时器时钟频率=170MHZ/170=1MHZ
,即每秒计数1000 000次
ARR设置为500-1,PWM频率=1MHZ/(500)=2kHZ
PWM周期:1/2KHZ=500us
7.分析代码:这里的ledrpwmval最多300,那么可以控制最大的占空比为300/500=60%,
t 是用来控制 LED0 闪烁频率的计数器。由于delay_ms(10),所以实际运行时间为50*10=500ms即0.5s,故t=5s时,0.5s亮 0.5s灭
总结:PWM输出实验
代码:
int main(void)
{
uint8_t t = 0;
uint8_t dir = 1;
uint16_t ledrpwmval = 0;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(85, 2, 2, 4, 8); /* 设置时钟,170Mhz */
delay_init(170); /* 延时初始化 */
led_init(); /* 初始化LED */
gtim_timx_pwm_chy_init(500 - 1, 170 - 1); /* 1MHz的计数频率,2KHz PWM频率 */
while (1)
{
if (dir)ledrpwmval++; /* dir==1 ledrpwmval递增 */
else ledrpwmval--; /* dir==0 ledrpwmval递减 */
if (ledrpwmval > 300)dir = 0; /* ledrpwmval到达300后,方向为递减 */
if (ledrpwmval == 0)dir = 1; /* ledrpwmval递减到0后,方向改为递增 */
/* 修改比较值控制占空比 */
__HAL_TIM_SET_COMPARE(&g_timx_pwm_chy_handle, GTIM_TIMX_PWM_CHY, ledrpwmval);
t++;
if (t > 50)
{
t = 0;
LED0_TOGGLE(); /* 控制LED0闪烁, 提示程序运行状态 */
}
delay_ms(10);
}
}
- sys_stm32_clock_init(85, 2, 2, 4, 8);
系统时钟频率170mhz,
2.gtim_timx_pwm_chy_init(500 - 1, 170 - 1); /* 1MHz的计数频率,2KHz PWM频率 */
这里自动重装载值为500-1,预分频器为170-1
由公式:定时器时钟频率=系统时钟频率/(预分频器值+1)
PWM频率=定时器时钟频率/(自动重装载+1)
计算得到 pwm周期为500us
3.这里的ledrpwmval控制占空比,能控制的最大占空比为300/500=60%,ledrpwmval先增加 然后再减少,所以占空比先增加再减少
t 控制灯亮的时间,即闪烁的频率
结果: