输出比较
输出比较就是通过定时器的外部引脚对外输出控制信号。
输出比较的模式有哪些
可以设置为以下几种不同的模式。
翻译如下:
000:冻结——输出比较寄存器TIMx_CCR1中的内容与计数器TIMx_CNT中的内容之间的比较对输出无影响。(此模式用于时基的生成)
001:当匹配时,设置通道1为有效电平。当计数器TIMx_CNT中的内容与捕捉/比较寄存器1(TIMx_CCR1)中的内容相匹配时,强行拉高OC1REF 信号。
010:当匹配时,设置通道1为无效电平。当计数器TIMx_CNT中的内容与捕捉/比较寄存器1(TIMx_CCR1)中的内容相匹配时,强行拉低OC1REF 信号。
011:翻转——当TIMx_CNT= TIMx_CCR1时,OC1REF信号取反。
100:强制无效电平——强行拉低OC1REF 信号。
101:强制有效电平——强行拉高OC1REF 信号。
110:PWM模式1——向上计数模式中,只要TIMx_CNT< TIMx_CCR1,通道1有效,反之无效。向下计数模式中,只要TIMx_CNT> TIMx_CCR1,通道1无效(OC1REF=0),反之有效(OC1REF=1)。
111:PWM模式2——向上计数模式中,只要TIMx_CNT< TIMx_CCR1,通道1无效,反之有效。向下计数模式中,只要TIMx_CNT> TIMx_CCR1,通道1有效,反之无效。
输出比较模式的配置
到输出比较模式和PWM模式比较部分查看。
输出比较模式的STM32CubeMx的配置
这里使用的是STM32F4的高级定时器TIM1,需要注意的是TIM1_CH2和TIM1_CH3,同时也是USART1_TX(PA9)和USART1_RX(PA10)。所以如果想要继续使用串口1的话,要么不使用TIM1_CH2和TIM1_CH3,要么使用复用功能,复用到PB6和PB7。
这里选择不使用TIM1_CH2和TIM1_CH3,继续使用(PA9)和(PA10)作为串口1的引脚。
Slave Mode是从模式,
Trigger Source是触发源,
这里都用不到,在使用外部时钟输入时可能会用到。
选择内部时钟源,使用TIM_CH1和TIM_CH4的输出比较功能。
由于不是产生互补输出,因此也不激活断路输入功能。
同样,这里也不使用单脉冲模式。
这里设置预分频值为168,计数模式为向上计数模式,计数周期设置为最大值65535,不使用内部时钟分频,也不使用重复计数器,也不设置自动重装载预装值。
触发输出TRGO功能和断路与死区功能没用到,所以也不需要关心。
配置输出比较通道1的模式为翻转模式,
翻转模式—当TIMx_CNT= TIMx_CCR1时,OC1REF信号取反。
TIMx_CNT也就是当前计数值,
TIMx_CCR1也就是设定的Pulse 比较值。
Pulse (比较值)= 50000,
CH Polarity为High,也就是CH的有效电平为高电平,一开始,通道输出低电平,当计数值与比较值相等时,输出信号翻转,首次翻转为高电平。
CH idle State为Reset,CH的空闲状态为低电平(Set为高电平),这个含义是当该通道输出被禁止时,输出为低电平,一般在设置了断路和死区时候才会用到,本次实验没用到。
接下来是中断与中断优先级的设置
本次实验的目的是想让比较值和计数时相等时产生比较中断的,然后在中断服务函数中重新设置比较值。所以这里我们选择最后一个。
对于第二个是更新中断,也就是当计数值计满这里设定的65535时,发生溢出中断。这里没用到。
设定完毕后,我们生成代码。
然后再对代码进行完善。
我们要在中断中做什么?
当发生中断时,首先获取当前计数值,然后判断触发中断的输出通道是哪一个通道,然后设置新的比较数值。
这里新的比较数值设定的为当前计数值加上该通道的初始比较值,这样设的目的在下面实验结果分析中会讨论。
中断回调函数如下:
/**
* @brief 定时器比较中断
* @param htim:定时器句柄指针
* @note 无
* @retval 无
*/
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
__IO uint16_t count;
/*获取当前计数*/
count = __HAL_TIM_GET_COUNTER(htim);
/*判断触发中断的输出通道并设置新的比较数值*/
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, count + OC_Pulse_num_Channel1);
printf("count = %d,c= %d.\r\n",count,count + OC_Pulse_num_Channel1);
}
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
{
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_4, count + OC_Pulse_num_Channel4);
}
}
为了配合在中断中设定新的比较数值,我们这里重新定义几个变量来存放每个通道的比较值,注意这里的这个比较值应与上面设置的比较值保持一致。(其实完全也可以不用重新定义这几个变量的值,只是为了方便)。
__IO uint16_t OC_Pulse_num_Channel1 = 50000; /* 通道1的比较值 */
__IO uint16_t OC_Pulse_num_Channel4 = 103; /* 通道4的比较值 */
为了看实际的计数值,我们想把实际的计数值给打印出来,这里就需要注意了,我们必须把比较值设置的非常的大,比如这里的50000,否则串口根本来不及打印,或者打印出来的值不准,而且还会产生的脉冲频率。
一开始,程序内设定的值和用Cube设定的值不一致,Cube设定的值为25.
结果打印效果如下:
按理说,产生中断时候的计数应为25,因为25太小了,串口根本来不及时间打印,所以打印出的是第二次进入中断后的计数值和重新 设定值。
这个是产生中断时的计数,以及重新设定的比较值为count + OC_Pulse_num_Channel1=50000+50000 = 100000。
看到这里,肯定还会有个疑问就是,不会溢出吗?
答案是肯定的,肯定会溢出的,请看下面的分析。
再看,通过串口打印出的每次产生中断的计数值和重新设定值
也就是波形会一直这样很平稳的以固定的频率和占空比产生,不会出现之前所担心的溢出之后会不会产生频率不一致的一小段脉冲的情况出现。
下面再来分析脉冲产生的频率和占空比。
占空比:
从上图中所分析的波形和理论分析可以得出:这样产上的占空比均为50%,跟计数周期arr的值没有关系。
脉冲频率:
我们使用的是内部时钟,TIM1使用的是APB1总线时钟为168MHz,分频值设定为168,所以计数频率就是1MHz,再者,产生的波形是每到比较值就翻转一次,所以产生的脉冲波形的每个周期应为所设定比较值的2倍,所以也就是2*50000 = 100000,从而产生波形的频率为1000000/100000 = 10Hz。
使用示波器查看后,与理论相差无几。