您的位置:首页 > 健康 > 美食 > 企业vi手册_小皮phpstudy快速搭建网站_安卓优化大师官网_企拓客软件多少钱

企业vi手册_小皮phpstudy快速搭建网站_安卓优化大师官网_企拓客软件多少钱

2025/4/2 20:04:18 来源:https://blog.csdn.net/qq_44114055/article/details/144828078  浏览:    关键词:企业vi手册_小皮phpstudy快速搭建网站_安卓优化大师官网_企拓客软件多少钱
企业vi手册_小皮phpstudy快速搭建网站_安卓优化大师官网_企拓客软件多少钱

智能车、机器人等需要PWM波驱动电机,输出比较功能就干这个的,它主要用来输出PWM波形

OC(Output Compare)输出比较
(另外还有IC全称是input capture输入捕获,CC全称是 capture / compare 表示 输入捕获和输出比较单元

输出比较可以通过比较CNT(时基单元的计数器)与CCR(R是register寄存器)寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形

输出比较的八种模式:
模式可以通过寄存器来进行配置
在这里插入图片描述

(电路结构学习暂且等以后完善)
学习参考江协科技STM32课程及博客
//
PWM脉冲宽度调制(Pulse Width Modulation)
在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速、开关电源等领域

PWM 的基本原理是通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟信号。在 STM32 中,定时器的一个通道可以产生 PWM 信号,通过改变比较寄存器的值来控制 PWM 的占空比。占空比是指在一个脉冲周期内,高电平持续时间与整个周期的比值,占空比越大,等效的模拟电压越高;占空比越小,等效的模拟电压越低。
在这里插入图片描述
通过这个PWM波形就可以实现。我们让led不断点亮熄灭,点亮熄灭。当这个点亮熄灭的频率足够大时,led就不会闪烁了,而是呈现出一个中等亮度。当我们调控这个点亮和熄灭的时间比例时,就能让led呈现出不同的亮度级别。对于电机调速也是一样,以一个很快的频率给电机通电断电,通电断电,电机的速度就能维持在一个中等速度,这就是PWM的基本思想

Ton的时间长Toff时间短电机会快,Ton的时间短Toff时间长电机会慢

在这里插入图片描述
在这里插入图片描述
因为计数器的计数周期时钟等于PWM波形输出的周期,所以PWM的频率就等于计数器的更新频率。
所以这个式子PWM频率:Freq = CK_PSC / (PSC + 1) / (ARR + 1)也就是计数器的更新频率公式。
这个式子PWM分辨率:Reso = 1 / (ARR + 1)定义的是占空比最小的变化步距,这个值越小越好。
也可以把CCR的范围定义成分辨率,那就是值越大越好。总之就是占空比变化的越细腻越好

//
下面进行说明机制:
在这里插入图片描述
设数值如下:
在这里插入图片描述
///
在这里插入图片描述
执行结构图的逻辑,这样一直持续下去,REF的电平就会不断变化,并且它的占空比是受CCR值调控的。如果CCR设置高一些,输出的占空比就变大。CCR设置低一些,输出的占用比就变小,这就是PWM模式的工作流程
REF就是一个频率可调,占空比也可调的PWM波形,最终再经过极限选择,输出是使能,最终通向GPIO口,这样就能完成PWM波形的输出


三个实验:
1、PWM驱动LED
在这里插入图片描述

2、PWM驱动舵机
在这里插入图片描述

3、PWM驱动直流电机
在这里插入图片描述

///
1、PWM驱动LED 代码
注意LED正极接GPIO口,这样使得高电平点亮;
第一步,配置RCC开启时钟,把我们要用的TIM外设和GPIO外设的时钟打开。
第二步,配置时基单元,包括这前面的时钟源选择;
第三步,配置输出比较单元,里面包括这个CCR的值,输出比较模式,极性选择,输出使能这些参数,在库函数里也是用结构体统一来配置的。
第四步,配置GPIO,把PWM对应的GPIO口初始化为复用推挽输出的配置。这个PWM和GPIO的对应关系可以参考一下引脚定义表
第五步,配置运行控制,启动计数器,这样就能输出PWM

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"uint8_t i;			//定义for循环的变量int main(void)
{/*模块初始化*/OLED_Init();		//OLED初始化PWM_Init();			//PWM初始化while (1){for (i = 0; i <= 100; i++){PWM_SetCompare1(i);			//依次将定时器的CCR寄存器设置为0~100,PWM占空比逐渐增大,LED逐渐变亮Delay_ms(10);				//延时10ms}for (i = 0; i <= 100; i++){PWM_SetCompare1(100 - i);	//依次将定时器的CCR寄存器设置为100~0,PWM占空比逐渐减小,LED逐渐变暗Delay_ms(10);				//延时10ms}}
}

PWM.h

#ifndef __PWM_H
#define __PWM_Hvoid PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);#endif

PWM.c

#include "stm32f10x.h"                  // Device header/*** 函    数:PWM初始化* 参    数:无* 返 回 值:无*/
void PWM_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟/*GPIO重映射*/
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);			//开启AFIO的时钟,重映射必须先开启AFIO的时钟
//	GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);			//将TIM2的引脚部分重映射,具体的映射方案需查看参考手册
//	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);		//将JTAG引脚失能,作为普通GPIO引脚使用/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;		//GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA0引脚初始化为复用推挽输出	//受外设控制的引脚,均需要配置为复用模式		/*配置时钟源*/TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;					//计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1;				//预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元/*输出比较初始化*/TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量TIM_OCStructInit(&TIM_OCInitStructure);							//结构体初始化,若结构体没有完整赋值//则最好执行此函数,给结构体所有成员都赋一个默认值//避免结构体初值不确定的问题TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				//输出比较模式,选择PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;		//输出极性,选择为高,若选择极性为低,则输出高低电平取反TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;	//输出使能TIM_OCInitStructure.TIM_Pulse = 0;								//初始的CCR值TIM_OC1Init(TIM2, &TIM_OCInitStructure);						//将结构体变量交给TIM_OC1Init,配置TIM2的输出比较通道1/*TIM使能*/TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}/*** 函    数:PWM设置CCR* 参    数:Compare 要写入的CCR的值,范围:0~100* 返 回 值:无* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比*           占空比Duty = CCR / (ARR + 1)*/
void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2, Compare);		//设置CCR1的值
}

/
2、PWM驱动舵机
用了serv.c/.h封装了PWM.c/.h

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "Key.h"uint8_t KeyNum;			//定义用于接收键码的变量
float Angle;			//定义角度变量int main(void)
{/*模块初始化*/OLED_Init();		//OLED初始化Servo_Init();		//舵机初始化Key_Init();			//按键初始化/*显示静态字符串*/OLED_ShowString(1, 1, "Angle:");	//1行1列显示字符串Angle:while (1){KeyNum = Key_GetNum();			//获取按键键码if (KeyNum == 1)				//按键1按下{Angle += 30;				//角度变量自增30if (Angle > 180)			//角度变量超过180后{Angle = 0;				//角度变量归零}}Servo_SetAngle(Angle);			//设置舵机的角度为角度变量OLED_ShowNum(1, 7, Angle, 3);	//OLED显示角度变量}
}

//
PWM.h

#ifndef __PWM_H
#define __PWM_Hvoid PWM_Init(void);
void PWM_SetCompare2(uint16_t Compare);#endif

PWM.c

#include "stm32f10x.h"                  // Device header/*** 函    数:PWM初始化* 参    数:无* 返 回 值:无*/
void PWM_Init(void)
{/*开启时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);			//开启TIM2的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA1引脚初始化为复用推挽输出	//受外设控制的引脚,均需要配置为复用模式/*配置时钟源*/TIM_InternalClockConfig(TIM2);		//选择TIM2为内部时钟,若不调用此函数,TIM默认也为内部时钟/*时基单元初始化*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数TIM_TimeBaseInitStructure.TIM_Period = 20000 - 1;				//计数周期,即ARR的值TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;				//预分频器,即PSC的值TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM2的时基单元/*输出比较初始化*/ TIM_OCInitTypeDef TIM_OCInitStructure;							//定义结构体变量TIM_OCStructInit(&TIM_OCInitStructure);                         //结构体初始化,若结构体没有完整赋值//则最好执行此函数,给结构体所有成员都赋一个默认值//避免结构体初值不确定的问题TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;               //输出比较模式,选择PWM模式1TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;       //输出极性,选择为高,若选择极性为低,则输出高低电平取反TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;   //输出使能TIM_OCInitStructure.TIM_Pulse = 0;								//初始的CCR值TIM_OC2Init(TIM2, &TIM_OCInitStructure);                        //将结构体变量交给TIM_OC2Init,配置TIM2的输出比较通道2/*TIM使能*/TIM_Cmd(TIM2, ENABLE);			//使能TIM2,定时器开始运行
}/*** 函    数:PWM设置CCR* 参    数:Compare 要写入的CCR的值,范围:0~100* 返 回 值:无* 注意事项:CCR和ARR共同决定占空比,此函数仅设置CCR的值,并不直接是占空比*           占空比Duty = CCR / (ARR + 1)*/
void PWM_SetCompare2(uint16_t Compare)
{TIM_SetCompare2(TIM2, Compare);		//设置CCR2的值
}

///
servo.h/.c

#ifndef __SERVO_H
#define __SERVO_Hvoid Servo_Init(void);
void Servo_SetAngle(float Angle);#endif

#include "stm32f10x.h"                  // Device header
#include "PWM.h"/*** 函    数:舵机初始化* 参    数:无* 返 回 值:无*/
void Servo_Init(void)
{PWM_Init();									//初始化舵机的底层PWM
}/*** 函    数:舵机设置角度* 参    数:Angle 要设置的舵机角度,范围:0~180* 返 回 值:无*/
void Servo_SetAngle(float Angle)
{PWM_SetCompare2(Angle / 180 * 2000 + 500);	//设置占空比//将角度线性变换,对应到舵机要求的占空比范围上
}

我舵机就在下载成功后动了一下,可能带不动,先不搞了

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com