阻塞非阻塞中断
一.四层架构

二.阻塞/非阻塞

阻塞,原地死等,事件不来 CPU 就卡在这一行,不能做别的任务
Delay_ms(1000); //阻塞延时,CPU卡在这1秒,LED、按键全部不响应
非阻塞,不断查询事件状态;没有事件就先去干别的活,过一会再来查一遍
裸机单片机没有操作系统,靠SysTick 滴答定时器做计时标记实现非阻塞。


三.中断

中断服务函数,中断函数




2.定时器中断


TIM 的 UIF 必须软件手动清零!不清就会一直反复进中断卡死
CNT 加到 ARR → CNT清零,溢出事件 → UIF 置 1 → 如果开了 UIE 中断允许 →进入中断,手动清除UIF
代码
#ifndef __TIM2_H
#define __TIM2_H
#include "stm32f10x.h"
void TIM2_Init(void);
#endif
#include "tim2.h"
#include "led.h"
void TIM2_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
NVIC_InitTypeDef NVIC_InitStruct;‘
// 1. 开启TIM2时钟,TIM2属于APB1
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 2. 时基配置
// 72M/(7199+1)=10000Hz,计数0.1ms一次;ARR=9999,(9999+1)*0.1ms=1000ms
TIM_TimeBaseStruct.TIM_Prescaler = 7199; // PSC
TIM_TimeBaseStruct.TIM_Period = 9999; // ARR
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStruct);
// 3. 使能更新中断(DIER.UIE=1)
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
// 4. NVIC配置
NVIC_InitStruct.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
// 5. 启动定时器!
TIM_Cmd(TIM2, ENABLE);
}
// TIM2中断服务函数,名字固定,启动文件定义好:TIM2_IRQHandler
void TIM2_IRQHandler(void)
{
// 判断是不是【更新中断】标志位
if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
LED_Toggle(); // 翻转LED
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // ✅ 清除UIF标志!!重点
}
}
#include "stm32f10x.h"
#include "led.h"
#include "tim2.h"
int main(void)
{
LED_Init();
TIM2_Init();//只要计时1000ms,产生一次中断,进入到中断函数里面,翻转led
while(1)
{
// 主循环可以跑别的任务,不受定时影响,非阻塞!
}
}

3.滴答定时器中断


#include "stm32f10x.h"
uint32_t systick_flag = 0;
// 配置SysTick,72MHz,1ms中断一次
void SysTick_Init(void)
{
// SysTick_Config 是内核库函数,参数:多少个时钟脉冲产生一次中断
// 72MHz → 72000个脉冲 = 1ms
SysTick_Config(72000);
// SysTick_Config内部自动:开TICKINT中断、开计数器、时钟源HCLK
}
// SysTick中断服务函数,名字固定 SysTick_Handler
void SysTick_Handler(void)
{
systick_flag = 1; // 打标记!中断里面尽量只置标志,不做复杂操作
}
int main(void)
{
SysTick_Init();
while(1)
{
if(systick_flag == 1)
{
systick_flag = 0;
LED_Toggle(); // 每隔1ms进来执行一次翻转
}
}
}

浙公网安备 33010602011771号