输出比较功能就是用来输出PWM波形的。
OC(Output Compare)输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形,每个高级定时器和通用定时器都拥有4个输出比较通道,高级定时器的前3个通道额外拥有死区生成和互补输出的功能。
PWM(Pulse Width Modulation)脉冲宽度调制 在具有惯性的系统中(具有惯性的系统才能使用PWM,比如led灯,断电不会立马就熄灭,电机,断电不会立马就停止转动)
可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域 PWM参数:
频率 = 1 / TS 占空比 = TON / TS 分辨率 = 占空比变化步距
占空比就是高电平占整体周期的比例。
高电平是5V,低电平是0V,那50%占空比就相当于2.5V电压。
20%相当于1V。
分辨率就是占空比跳变的步距,比如百分之一,每一次占空比都变化百分之一。
输出比较电路部分是黄色框框的部分。
输出比较模式指的是根据输入的CNT以及CCR,输出模式控制器选择的输出比较模式,用来确定参考信号的输入是高电平还是低电平。
因为在输出比较器输出之后还能进行一次极性选择,所以PWM输出模式1的输出可以有两种,其中一种与PWM输出模式2的是一样的,无论是向上还是向下计数,其实也就是说用一种模式就可以了。
时基单元的左边是时钟控制,CNT不断自增,与CCR作比较,然后根据所选模式输出相应电平,如右上角所示,黄色ARR,红色是CCR,蓝色是CNT,根据设定的模式确定在每个大小关系的是偶输出什么电平。
改变CCR或者改变ARR都可以改变占空比,所以REF是一个频率可调占空比可调的信号,经过极性选择,输出使能就可以输出到GPIO口了。
PWM频率其实就是计数器更新的频率,就是到了99再更新变为0的频率。这个公式这样理解,每一次计数的时间乘以99,就是从0计数道99的时间,取倒数就是PWM的频率,每一次计数的时间就是输入频率,输入频率除以分频等于实际输入的频率,取倒数乘以ARR就等于每次更新的时间,再倒数就是PWM频率。
高电平导通,低电平断开,上下断开就是高阻态,这就是推完电路的输出模式,有两个这种电路就构成了H桥电路,H桥就可以控制直流电机的正反转了。三个这样的电路就构成三相无刷电机的驱动了。对于单片机来说,这样一个推挽电路,需要两个输入,而且是两个互补电路。上管导通下管断开,或者上管断开下管导通,但是有时候切换的时候来不及,会出现两者都处于导通的状态,就是直通状态,导致功率损耗,器件发热。所以就有个死区发生器,在导通的管断开瞬间,延迟一段时间,然后再让原本断开的二极管导通,避开直通现象。
PWM驱动舵机
PWM驱动舵机相当于一个通信协议,比如占空比多少就固定在什么角度。跟前面所说的把输出不同的占空比等效成模拟输出曲线不一样。舵机中自带驱动,而直流电机中没有驱动,需要外接驱动。
PWMA与AIN2,AIN1输入限功率信号,驱动会从VM汲取电压,然后给电机供电。这样就是用小功率信号对大功率器件供电啦,两块阴影部分功能是完全一样的,STBY是待机控制引脚, 接GND就是待机控制,接VCC就是工作。
至于驱动如何控制正转反转,看右下角的表。
转动的速度取决于占空比,因为占空比大的电压比较大,电流也比较大。
猜想:大概是驱动里面有两个H桥,四个输入引脚,其实就是对应两个IN,然后两个IN分别在两边,每一边因为硬件电路的不一样,一个导通一个断开,另外一边也是,所以就能决定电机转动的方向。
所以就确定了转动的方向,但是转还是不转,得看PWM波是否是高电平,以及其占空比,占空比决定电压的大小,从而影响转动速度,高电平才有电压,才会转。两个IN以及PWM影响O1O2两个输出的高电平低电平,从而确定点击的转动方向以及装懂速度。其实PWM可以看做是一个控制电压大小的量,根据占空比的大小等量于不同的电压大小,从而影响转动的速度。
有箭头的两头分别是s跟g,箭头对着的要大于没有箭头对着的电压才能导通,根在一起的二极管也跟箭头的方向一致。
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
//此四个函数是用来配置输出比较通道的,也就是下图的输出比较单元*4
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);//是给输出比较通道默认配置一个值的,具体是什么可以跳转查看,并且配置之后想要修改可以用别的函数单个修改覆盖。
void TIM_ForcedOC1Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC2Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC3Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
void TIM_ForcedOC4Config(TIM_TypeDef* TIMx, uint16_t TIM_ForcedAction);
第一个参数是输出模式,第二个参数是输出极性,第三个参数是输出使能,第四个参数是设定CCR,还有其他参数,带N的都是高级定时器具备的。我们一般不能只选择其中几个配置,会出现问题的,正确的做法是,先用另一个函数配置初始的值,然后再用上面这几个参数修改。
第一个参数就是冻结模式什么的里的。
第二个参数就是极性选择,高极性就是电平不翻转,低极性就是电平反转。
OC1也就是CH1,但是CH1是固定在PA0引脚上面的,要使用的话,只能使用PA0,其他的几个通道也是如此,但是可以经过重映射的功能就行修改,比如TIM_CH3对应PA2,在重定义功能可以对应PB10,所以可以经过重映射的功能更换端口,避免使用上的冲突。
用此函数:void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);
具体配置成什么,可以选择跳转查看。
在运用输出比较功能的时候,配备引脚的时候,选择输出模式的时候,应该使用复用输出,应为普通的输出都来自数据寄存器,想要用定时器输出的话,应该使用复用输出,这样才能让输入信号来自片上外设。根据上图,片上外设的那条线来自TIM_的CH引脚,然后从对应的I/O口输出PWM信号。
重映射:
开启AFIO的时钟
用GPIO中的这个函数:void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);进行引脚重映射配置
第一个参数根据使用手册8.3中进行选择。第二个参数就是使能失能。
对于下图的这几个调试端口,如果想要把他们当做普通端口或者进行复用,应该也先解除调试端口在进行,用这个函数解除:
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState
* @arg GPIO_Remap_SWJ_NoJTRST : 仅仅解除NJTRST
* @arg GPIO_Remap_SWJ_JTAGDisable : 解除JTAG的所有端口,也就是38.39.40
* @arg GPIO_Remap_SWJ_Disable :解除所有的端口,34,37,38,39,40都解除
SWJ的意思是SWD和JTAG,SWD 指的是34,37
注意自己的下载方式,不然把调试端口给解除掉了下载不进去,慎用。全接触了只能串口下载咯。
TIM_cmd启动定时器。
//这四个是强制改变输出模式,停止输出波形并且置为高电平或者低电平
void TIM_OC1PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC3PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_OC4PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
//这四个函数是配置预重装功能的,也就是影子寄存器
void TIM_ClearOC1Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC2Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC3Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
void TIM_ClearOC4Ref(TIM_TypeDef* TIMx, uint16_t TIM_OCClear);
//清除REF信号
void TIM_OC1PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC1NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC2PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC2NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC3PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
void TIM_OC3NPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCNPolarity);
void TIM_OC4PolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
//用来修改通道的输出极性,带N的就是用来修改高级定时器的相反的信号的那个通道,通道4没有相反的,在结构体之中其实也有配置极性的选项,两者是一样的,一般来说结构体的元素都有单独的函数配置修改。
void TIM_CCxCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCx);
void TIM_CCxNCmd(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_CCxN);
//修改使能控制的
void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode);
//选择输出比较模式
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);
//改变CCR的值
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);
//这个函数仅仅高级定时器使用,输出PWM的时候,需要用这个函数使能一下,不然不態正常输出
PWM可以相当于把它看成是一个控制电压的值,占空比越大,输出电压就越大,按照百分比分压。
在实现呼吸灯的这种时候,应该有个延时函数给单片机一点反应的时间,不然太快啦。
电机如果发出蜂鸣器费声响,可能是PWM频率在人耳范围内,20HZ到20KHz,把它改在范围之外就行了。
————————————————
版权声明:本文为CSDN博主「笔下觅封侯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_63148816/article/details/130417025