stm32标准库和HAL库的对比学习5.《学习pwm输出和驱动舵机》
本人是大一的学生,学习了一段时间的stm32,此系列博客为个人的学习笔记,方便个人复习,如有错误或问题,非常非常欢迎大家来大力指正。
本篇默认有51单片机基础,所以pwm原理就不再赘述
与51单片机不同,stm32实现pwm的方法是通过定时器的“输出比较output compare(简称oc,不是超频)”来实现的。通过CNT(计时单元)与CRR(输入/捕获寄存器)的比较实现电平的反转。
先说CRR输入/捕获寄存器,顾名思义,他是有输入和输出的功能,输出功能就是输出pwm,输入功能就是对输入的pwm进行识别。而想要驱动舵机,就要用pwm输出来控制。
先讲pwm输出
stm32实现pwm的方法是CNT计数,然后和CRR比较,当CNT=CCR时,对电平产生变化。然后当CNT=ARR时,触发计数器中断,CNT置0,恢复以前的电平,重新计数。这样就是现实电平在一个周期内的有规律变化,通过调整CRR,就可以调整pwm的占空比。
CNT=CRR的电平变化由模式所决定,下面程序说
PWM freq=ck psc(单片机频率)/(psc+1)/(ARR+1)
pwm占空比 duty=ccr/(arr+1)
pwm分辨率 reso=1/(arr+1)
②标准库的代码实现
pwm的基本结构如图,要用到上节定时器的功能,所以要开启RCC时钟,定义时基单元,配置CCR。前两部像上一节一样配就行,但是不用设定NVIC中断。而定义CCR首先要看TIM_OCInitTypeDef structure结构体中所要定义的东西。
有很多都是高级定时器要用的,我们只需要写出我们需要用的进行,看下面代码
输出极性可以理解为“是否要将电平信号反转”
下面4个都是输出极性的定义,死区生成是防止互补输出时两个电路一起导通产生损耗,延迟下一个端口导通的时间
TIM_ocmode中有几个模式,配置输出比较控制器,当CCR=CNT时输出不同形式的电平
第一个为保持原状态
有效电平和无效电平就可以看作高电平和低电平,电平反转可以输出一个固定平衡率的波形
强制电平和第一个差不多,就是暂停后输出特定的电平
pwm模式是可以输出频率可变的波形.
void TIM_CtrlPWMOutputs(TIM_TypeDef* TIMx, FunctionalState NewState);高级寄存器要用这条使能。
第一步开启RCC,定义好TIM时基单元
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//因为一般的GPIO控制权是在寄存器上的,看原理图,OC1通道要接到引脚才能输出pwm,所以要用复用推挽,让引脚接入片上外设
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_Prescaler=720-1; //psc预分频器
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;//计数器模式
TIM_TimeBaseInitStructure.TIM_Period=100-1; //ARR自动重装器的初始值(周期)
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //滤波分频
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0; //重复计数器
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
第二步用结构体定义OC
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//注意事项,初始值赋值,防止未定义的函数产生错误
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//配置OC的输出模式
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//比较极性
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//输出使能
TIM_OCInitStructure.TIM_Pulse=50 ;//ccr的值
TIM_OC1Init(TIM2, &TIM_OCInitStructure);//注意OC后面是通道编号
TIM_Cmd(TIM2, ENABLE);
PWM已经定义完毕。
实现pwm的占空比变化不能像51单片机这样写,要用到专门改变占空比的
TIM_SetCompare1(TIM2, num);函数来改变CCR的值,从而改变占空比。
改变num的值,就是改变CCR,从而输出PWM。用上面的公式计算。
100hz:ARR:100-1.PSC:720-1
50hz(sg50):ARR:20000-1,PSC:72-1.接上对应接上通道的引脚,就可以输出pwm信号
③HAL库的实现:
我们可以按照标准库的定义开启选项
①开启RCC
②开启TIM,打开内部时钟,选择通道和输出模式,打开NVIC中断
③配置OC(跟着标准库数据配置就好)
然后生成代码
写上下面两条代码
HAL_TIM_Base_Init(&htim2);//初始化tim2
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1);//打开pwm输出
下面那条是比较输出的代码
__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_1,CCR的值);
和TIM_SetCompare1(TIM2, num);一样
驱动舵机:
根据上面来输出合适的pwm使电机转动特定的角度,通过上面几条公式,进行计算即可。
重映射复用端口的小知识:要看手册找到相应的复用端口,先开启RCC时钟(将gpio换为AFIO就可以)然后用gpio_pinremapconfig();来重映射引脚
Coldfall223: 你好能不能发个工程文件参考一下
CSDN-Ada助手: 恭喜您写了第10篇博客!您对于学习STM32HAL库和电控知识的热情令人钦佩。希望您可以继续分享关于CAN通信协议和GM6020电机驱动的学习心得,或者可以考虑加入一些实际案例或者应用场景的分析,这样可以更好地帮助读者理解和应用这些知识。期待您更多的创作,谢谢您的分享!
CSDN-Ada助手: 恭喜你写了第9篇博客!看到你在比较stm32标准库和HAL库的对比学习,并深入学习了spi通信协议,软件与硬件输出,真是让人钦佩。不过,我想提醒一下,在写作过程中,可以多加一些实际应用的例子,让读者更容易理解。希望你在接下来的创作中能够继续努力,加油!
CSDN-Ada助手: 恭喜作者第7篇博客的发布!学习iic(i2c)通信协议是一个很有意义的主题,谢谢你分享这些知识。希望你可以继续坚持创作,让更多的人受益。下一步,我建议你可以尝试探讨一些在实际项目中应用iic通信协议的案例,或者深入分析一些iic通信中的常见问题和解决方法。期待你的更多精彩内容!
CSDN-Ada助手: 恭喜您写了第四篇博客!标题看起来非常有趣,我相信学习pwm输出和驱动舵机一定是一个很有意义的主题。不仅仅是标题很吸引人,我也期待着能够读到您对stm32标准库和HAL库的对比学习的深入分析。在评论中,我想提供一些建议,希望对您的下一步创作有所帮助。首先,您可以分享一些与pwm输出和驱动舵机相关的实际应用案例,这将使读者更容易理解和应用相关知识。其次,您可以提供一些常见问题和解决方案,这将对初学者非常有帮助。最后,您可以考虑与读者互动,鼓励他们在评论区分享自己的经验和疑问,这将促进更深入的讨论。再次恭喜您,期待您未来更多优质内容的分享! 如何快速涨粉,请看该博主的分享:https://hope-wisdom.blog.csdn.net/article/details/130544967?utm_source=csdn_ai_ada_blog_reply5