阻塞非阻塞中断

一.四层架构

二.阻塞/非阻塞

阻塞,原地死等,事件不来 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进来执行一次翻转

}

}

}

posted @ 2026-10-29 17:08  juzzz55  阅读(4)  评论(0)    收藏  举报