一:实验目的
利用PWM信号控制电机速度
二:实验方法:
对于伺服电机或者步进电机,可以调节频率的大小,来调节电机速度
对于直流电机,可以调节占空比的大小,来调节电机速度
PWM知识介绍:
PWM(Pulse Width Modulation 脉宽调制)是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。它是一种对模拟信号电平进行数字编码的方法。是指在一定时间内波形的高电平(即 1 状态)所占用的时间比例。通过高分辨率计数器的使用,方波占空比被调制用来对一个模拟信号的电平进行编码。PWM 信号任然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有,要么完全无。比如我们的电压输出是 5V的,那么经过改变 PWM 的占空比,可以达到在一定时间内输出 3.3V 或者 1.3V 的效果。
MSPM0L系列一共有8个定时器,可以分为3种类型,通用计时器(TIM2、3、4、5)、高级控制计时器(TIM1、8)和基本定时器(TIM6、7)。而PWM功能就是在定时器的基础上实现的。从用户手册上可以了解到,高级定时器和通用定时器都支持PWM输出,但是基本定时器是不支持PWM输出,只能用作定时器计数使用。
PWM是脉冲宽度调制,具有两个非常重要的参数:频率和占空比。
频率:PWM的频率是整个周期的倒数。
占空比:占空比是指一个周期内高电平所占的比例。
MM32定时器的介绍:TIMx 由一个 16 位可实时编程预分频器和一个 16 位计数方向可调的自动重装载计数器组成,可以为用户提供便捷的计数定时功能,计数器时钟由预分频器分频得到。高级定时器具有多种用途,如输入功能(测量输入信号的脉冲宽度、频率, PWM 输入等),输出功能(PWM 输出、死区时间可编程的互补输出、单脉冲模式输出等)。
软件配置流程:
使能定时器1和相关IO口时钟。
使能定时器1时钟: 使能GPIOA时钟:
初始化IO口为复用功能输出。函数:GPIO_Init();
这里我们是要把PA8用作定时器的PWM输出引脚,所以要重映射配置,
需要开启AFIO时钟。同时设置重映射。 初始化定时器:ARR,PSC等
初始化输出比较参数,使能预装载寄存器:
使能定时器。
1:不断改变比较值CCRx,达到不同的占空比效果
1:不断改变比较值ARRx,达到输出不同频率的效果。
软件代码部分:
定时器初始化部分:
void TIM1_Configure(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
uint32_t TimerPeriod1 = 0, Channel1Pulse1 = 0, Channel2Pulse1 = 0, Channel3Pulse1 = 0;
/* Compute the value to be set in ARR regiter to generate signal frequency at 100 Khz */
TimerPeriod1 = TIM_GetTIMxClock(TIM1) / 10000;
/* Compute CCR1 value to generate a duty cycle at 75% for channel 1 */
Channel1Pulse1 = (uint32_t)100 * TimerPeriod1 / 1000;
/* TIM1 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStruct);
TIM_TimeBaseStruct.TIM_Prescaler = 0;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStruct.TIM_Period = TimerPeriod1;
TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_Div1;
TIM_TimeBaseStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStruct);
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse = 0;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStruct.TIM_Pulse = Channel1Pulse1;;
TIM_OC1Init(TIM1, &TIM_OCInitStruct);
TIM_OCInitStruct.TIM_Pulse = Channel3Pulse1;
TIM_OC3Init(TIM1, &TIM_OCInitStruct);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_1); /* TIM1_CH1 */
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_10;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStruct);
TIM_Cmd(TIM1, ENABLE);
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
频率自动更新代码:
/*更新频率输出值*/
void UpFreValue(int data)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
uint32_t TimerPeriod1 = 0;
uint32_t Channel1Pulse1 = 0 ;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
TimerPeriod1 = TIM_GetTIMxClock(TIM1) / data;
/* Compute CCR1 value to generate a duty cycle at 75% for channel 1 */
Channel1Pulse1 = (uint32_t)500 * TimerPeriod1 / 1000;
TIM_TimeBaseStructInit(&TIM_TimeBaseStruct);
TIM_TimeBaseStruct.TIM_Prescaler = 0;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStruct.TIM_Period = TimerPeriod1;
TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_Div1;
TIM_TimeBaseStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStruct);
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse = 0;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStruct.TIM_Pulse = Channel1Pulse1;;
TIM_OC1Init(TIM1, &TIM_OCInitStruct);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_1); /* TIM1_CH1 */
TIM_Cmd(TIM1, ENABLE);
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
更新占空比函数:
/*更新占空比*/
void UpDutyValue(int data)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
uint32_t TimerPeriod1 = 0;
uint32_t Channel1Pulse1 = 0 ;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
TimerPeriod1 = TIM_GetTIMxClock(TIM1) / 10000;
/* Compute CCR1 value to generate a duty cycle at 75% for channel 1 */
Channel1Pulse1 = (uint32_t)data * TimerPeriod1 / 1000;
TIM_TimeBaseStructInit(&TIM_TimeBaseStruct);
TIM_TimeBaseStruct.TIM_Prescaler = 0;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStruct.TIM_Period = TimerPeriod1;
TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_Div1;
TIM_TimeBaseStruct.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStruct);
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse = 0;
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set;
TIM_OCInitStruct.TIM_Pulse = Channel1Pulse1;;
TIM_OC1Init(TIM1, &TIM_OCInitStruct);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_1); /* TIM1_CH1 */
TIM_Cmd(TIM1, ENABLE);
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
利用串口输出当前占空比和频率自动改变的图片如下:
效果如下图:
视频如下:
[media=x,500,375][/media]
731.82 KB
:
---------------------
作者:聪聪哥哥
链接:https://bbs.21ic.com/icview-3389914-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。