刚开始学单片机做项目时,一直用不到且不会用中断,后来听学长指点,对于复杂的项目如果不用中断的话会出现很多问题,比如说延迟高。且在RTOS中不用中断和其他线程并行,无法做出更复杂的项目,所以这次我准备把之前做过的两个项目拿过来再修改一下,加入定时器中断并修改程序架构。
一.定时器
其中最重要的莫过于石基单元
首先系统时钟频率在预分频器(PSC)中进行分频,可按1到65535之间的任意值进行分频,随后驱动计数器(CNT)进行向上计数、向下计数或者中心对齐计数,当计数器的值超出自动重装载寄存器(ARR)的值后产生溢出条件时,会更新事件。这里为什么要将系统时钟频率进行分频处理呢?如果不进行分频,系统将以72MHZ的频率使CNT计数器的值自增,由于频率太高计数非常快,CNT很快便达到ARR的值,而ARR最大为65535,这时如果想定一个1s的时间,由公式:TIMx溢出时间 = (重装载值 + 1)* (分频系数 + 1)/ TIMx的输入时钟,分频系数为0,那么重装载值得为72M,这远大于65535,所以要进行分频处理,且通过使用预分频器,我们可以得到一个相对较低频率、精度可控的定时器时钟,从而更好地实现定时和中断等操作,并且避免了高速时钟对系统资源的消耗,提高了系统的稳定性和可靠性。PWM频率 = TIMx的输入时钟 / ((重装载值 + 1)* (分频系数 + 1 )),PWM频率跟分频系数和重装载值也有关系,重转载值和分频系数越小,PWM频率越高,而更高的PWM频率可以提供更多的计数周期,从而增加PWM信号的分辨率和精度,也可以减小机械、电磁等方面的噪音干扰。
二.程序部分
1.功能修改
在程序上我准备将之前的松开按键发送数据停车改成松开按键后进入定时器中断停车
定时器将溢出时间设置为500ms,按下按键后会进入USART中断服务函数,并将计数器CNT的值清零,因进入USART的时间间隔远小于500ms,所以CNT的值会一直被清零无法达到ARR的值。当松开按键后不再进入USART中断服务函数,CNT的值不再被清零,当达到500ms后进入定时器中断服务函数,取得标志位tim4_flat=1,并在主函数中执行停车函数。
2.程序架构
听学长说工程里不能有太多的全局变量,于是上网查了一下
于是将不需要对外使用的一些变量全部改成了局部变量,而需要对外使用的变量则仍为全局变量,比如说上面的标志位tim4_flat,使用外部声明。或者在.c文件中将变量使用函数封装,可直接到其他文件引用。
三.所遇问题
1.
因为有两个中断,所以得配置中断优先级,采用优先级分组2:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);两位抢占优先级,两位响应优先级,将改函数放在主函数中。USART抢占优先级为1,定时器抢占优先级为2。
2.
由于配置了USART的中断函数,在开启中断后,接收中断标志位会被自动清除,并由中断服务程序(ISR)处理接收数据,当使用USART_GetFlagStatus(USART1, USART_FLAG_RXNE)(用于获取USART的状态标志位,判断是否接收到了数据)来判断是否接收到数据时,该函数无法获取中断标志位,从而无法执行程序。为了正确检查接收中断标志位,需要使用USART_GetITStatus(USART1, USART_IT_RXNE)函数,这个函数用于查询接收中断是否已经被触发,而不受中断标志位被清除的影响。
四.效果对比
将MPU6050获取角度数据的函数放入定时器中断中,每100ms刷新一次,使得精度可控。而如果放入while循环中,会导致程序在等待获取数据时被阻塞,从而出现延迟过高的现象。以下是两者对比视频:
放入while中:
放入定时器中断中:
很明显,放入while循环中舵机云台延迟高,而放入定时器中断中则很丝滑。
五.程序源码
stm32小车:链接:https://pan.baidu.com/s/1MjPHx3eW_vHWLaucDGDa6w?pwd=6jn2
提取码:6jn2
手控舵机云台:链接:https://pan.baidu.com/s/1jPwXgM57NsyMwRts2zl1xw?pwd=rnsd
提取码:rnsd