中断
中断程序在一个子函数中,不需要手动调用,当中断来临时自动调用
几乎所有的外设(EXIT TIM ADC USART SPI I2C RTC等)都能申请中断,使用NVIC内核外设【都不用开启时钟】(叫号系统)统一管理
中断优先级16个
一个外设可能占用多个中断通道(n)
抢占优先级:可抢占,嵌套
响应优先级:插队到第二个,等第一处理完后
优先级,值越小越高。若是优先级完全一样,则按照中断向量表里面的排序确认优先级
PA0与PB0 或 PB1与PA1不能同时使用
中断响应时到CPU,事件响应时到其他外设(ADC.DMA等)
EXTI与NVIC默认时钟就是打开的
AFIO复用IO口
外部中断处理那些转瞬即逝的事件,比如红外。 按键的话不推荐(因为不好处理抖动),可以用主循环读取,或者定时器中断读取,
旋转编码器,测位置、速度或旋转方向,
红外对射式的通过光栅格得到高低电平,方波的个数就是转过的角度,方波的频率就是转速,使用外部中断捕获方波的边缘就可以判断位置和速度,但是只有一路输出,就不能判断正转还是反转
旋转编码器,通过金属触点和栅格来产生高低电平,再通过两路的输出波形(相位相差90度的正交波形)来判断正反转 【适合速度慢的场合】
高速的可用霍尔传感器
代码实现
先开启AFIO与GPIO的时钟,EXTI与NVIC默认时钟就是打开的
初始化GPIO
void CountSensor_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14); //实际调用AFIO的函数来处理,将GPIOB的14号引脚设置成中断源,进入EXIT处理电路 EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line = EXTI_Line14; //对应14号引脚 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //使用中断模式 还有事件模式 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发 EXTI_Init(&EXTI_InitStructure); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //这个分组选择代码只执行一次,可放在主函数循环之前 NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //可以在stm32f10x.h中找到 STM32F10X_MD去查看可用的中断通道 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //问:有5-9 10-15 ,0-4的话可以直接EXTI0_IRQn (启动文件中可以查看相关的函数) NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级 NVIC_Init(&NVIC_InitStructure); }
void EXTI_DeInit(void); void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct); void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct); void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line); //软件触发 FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line); void EXTI_ClearFlag(uint32_t EXTI_Line);//建议主程序中用上面两个,中断程序中用下面两个 ITStatus EXTI_GetITStatus(uint32_t EXTI_Line); void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
void EXTI15_10_IRQHandler(void) //每个中断通道对应一个中断函数 { if (EXTI_GetITStatus(EXTI_Line14) == SET) //判断是不是我们需要的中断(可以进来很多个中断到这个函数) { /*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/ if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0) { CountSensor_Count ++; } EXTI_ClearITPendingBit(EXTI_Line14); //每次中断程序处理完毕就清除中断标志位 } }
使用 EXTI15_10_IRQHandler 是因为之前用的中断线14在这个区间内
pre-emption priority 抢占优先级 subpriority响应优先级
旋转编码器正负判断
上A下B, B下降沿触发进入中断,此时判断A低电平就是正转; A下降沿触发进入中断,判断B是低电平就是反转,因为芯片有处理的延迟,可以通过增加(冗余)高低电平判断来达到这个延迟。
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决
· 提示词工程——AI应用必不可少的技术