![]() |
按键消抖了吗 |
Y_G_G 发表于 2025-5-15 16:23 谢谢,学到了很多知识 |
红花无常 发表于 2025-5-15 13:52 对于按键中断,并不是绝对需要的,可以不用中断,直接在主程序中扫描按键就可以了 但有时候是要中断的,比如按键级别要求要高的,或者是按键要唤醒单片机的,这个时候就会用到中断 而且,按键不是中断还是在主程序中扫描,都是需要去抖动和识别按键的 不然的话,你这个 if(KEY按下) { 按键处理相关代码; } 如果按键一直按着,程序就一直在执行 |
Y_G_G 发表于 2025-5-15 10:04 您说的这个意思我能明白,只是,如果这样的话,是不是中断都可以不要了,像下面这样就行了。我一直没搞清楚的就是这个。 main() { if(KEY按下) { 按键处理相关代码; } } |
红花无常 发表于 2025-5-14 21:35 假设你是按键触发,那么好,你全声明一个全局变量 u8 key_f = 0;//这个变量就是用来通知主程序的 在中断程序中 EXTI9-5中断 { key_f = 1; } 主程序中 main() { if(key_f) { key_f = 0; 按键处理相关代码; } } key_f 在中断记录, 在主程序中清除,这是提供一个思路,原理就大概是这么个原理 |
Y_G_G 发表于 2025-5-14 12:39 好的,谢谢。原则我明白了,具体是通过何种方式实现呢?比如,在触发中断后,有一连串的操作,耗时6-7秒。现在我知道,不能在中断中处理这么多任务,只能在主程序里处理。那么,该怎么通知主程序呢?是让主程序不断在while循环里扫描,看中断标志位是否为1吗?那样的话,是不是都可以不用外部中断了,直接在主程序里扫描那个IO口的电平判断按钮是否按下即可。 |
1,中断中不要做太多的任务,delay这种延时更加不要加,不管是按键也好,ADC也好,还是其它的什么,中断事件只要触发某个事件的标志就可以了,再在主函数中根据对应的标志进行处理 比如ADC,串口之类的,就只管把数据保存就可以了,不要在中断中处理,当然,STM32有DMA,那是以后的事了 2,长时间延时,可以用定时器来进行,类似于SysTick的方式,不要死等,让单片机500mS什么事都不做,这不是一个好习惯 |
lose2836 发表于 2025-5-14 00:06 谢谢!看来问题应该就是出在这里。主函数里有DELAY,主函数正在执行DELAY时,发生了中断,中断函数里也有DELAY,中断函数里执行完DELAY后,关闭了计时器,导致主函数里的DELAY也关闭了。 所以如果在中断函数里需要延时,最好是用定时计数器重新写一个。 |
红花无常 发表于 2025-5-13 10:40 void Delay_us(uint32_t xus) { SysTick->LOAD = 72 * xus; //设置定时器重装值 SysTick->VAL = 0x00; //清空当前计数值 SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器 while(!(SysTick->CTRL & 0x00010000)); //等待计数到0 SysTick->CTRL = 0x00000004; //关闭定时器 } 打个断点仿真下就看到了,中断运行后卡到了deay函数等待计数到0。感觉是在main中delay时,进入中断,中断delay后闭定时器,中断完回到main中的delay,这时的计数器已经关闭了。卡到“while(!(SysTick->CTRL & 0x00010000));”这一句。在while中添加个检测计数器是否关闭,如果关闭的,打开计时器。 while(!(SysTick->CTRL & 0x00010000)) //等待计数到0 { if(SysTick->CTRL == 0x00000004) { SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器 } |
中断里只要有延时函数,不论长短(即使几微秒),都会卡死;注释掉延时函数,就好了。 |
谢谢大家,我刚才把延时全部调整成了1毫秒,问题依然存在。估计是前面那个朋友说的,是延时函数的优先级问题。 |
嗯,一般人很少会在中断里面用放延时函数的,像你这种直接在中断里面放4个delay_ms(500)加一个delay_ms(100),更加少见,大概就像,你正常情况下每秒钟必须呼吸一次(中断需要要循环访问,后台自动控制决定的),然后你训练拳法,没呼吸一次要打300拳法(你一个中断占用了2秒多),你不管你的肺抗不扛得住,憋晕过去也要打完300拳法(你也不管其他中断会不会冲突是吧,),打完拳你也不呼气(按键中断的标签去除了,但是按键弹起来了吗) void EXTI9_5_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line8)==SET) { Delay_ms(100); if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8) == 0) { Buzzer_ON(); Delay_ms(500); Buzzer_OFF(); Delay_ms(500); Buzzer_ON(); Delay_ms(500); Buzzer_OFF(); Delay_ms(500); } } EXTI_ClearITPendingBit(EXTI_Line8); } |
应该是中断级别的我问题,高级中断里调用了更高级中断DELAY(SYSTICK). |
中断里面不要放软件延时函数,另外中断里面的代码一定要精简,最好控制在100us以内 |