嵌入式进阶——舵机控制PWM

🎬 秋野酱:《个人主页》
🔥 个人专栏:《Java专栏》《Python专栏》

⛺️心若有所向往,何惧道阻且长

舵机最早用于船舶上实现转向功能,由于可以通过程序连续控制其转角,因而被广泛应用于智能小车转向以及机器人各类关节中.
工作电压:3V-7.2V(取决于具体型号)
工作电流:100mA(取决于具体型号)
在这里插入图片描述
舵机由直流电机、减速齿轮组、传感器和控制电路组成的一套自动控制系统.通过发送信号,指定输出轴旋转角度.舵机一般而言都有最大旋转角度(比如180度)
与普通直流电机的区别:
● 直流电机是一圈圈转动的
● 舵机智能在一定角度内转动,不能一圈圈转动
● 普通的直流电机无法反馈转动的角度信息,而舵机可以
用途也不相同:
● 普通直流电机一般是整圈转动做动力用
● 舵机是控制某物体转动一定角度用(比如机器人的关节)
在这里插入图片描述

舵机信号线

在这里插入图片描述

舵机的主要组成部分为伺服电机,所谓伺服就是服从信号的要求而动作。在信号来之前,转子停止不动;信号来到之后,转子立即运动。因此我们就可以给舵机输入不同的信号,来控制其旋转到不同的角度。 舵机接收的是PWM信号,当信号进入内部电路产生一个偏置电压,触发电机通过减速齿轮带动电位器移动,使电压差为零时,电机停转,从而达到伺服的效果。简单来说就是给舵机一个特定的PWM信号,舵机就可以旋转到指定的位置。 舵机上有三根线,分别是GND(棕线)、VCC(红线)和SIG(橙线),也就是地线、电源线和信号线,其中的PWM波就是从信号线输入给舵机的。
一般来说,舵机接收的PWM信号频率为50HZ,即周期为20ms。当高电平的脉宽在0.5ms-2.5ms之间时舵机就可以对应旋转到不同的角度。如下图。
在这里插入图片描述
在这里插入图片描述

代码示例

以P01对应的PWM6为例
配置PWM环境,这里需要使用修改后的,支持分频系数的PWM依赖库:

初始化PWM

#include "config.h"
#include "delay.h"
#include "GPIO.h"
#include "PWM.h"
#include "UART.h"
#include "Exti.h"
#include <stdio.h>

char putchar(char dat)
{
    TX1_write2buff(dat);
    return dat;
}

#define MOTOR P01

// 分频系数:可以是1~65535中的任意值
#define Prescaler 10

// 频率
#define PREQ 50

// 保证分母 >= 367
#define PERIOD (MAIN_Fosc / (PREQ * Prescaler))

void GPIO_config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;        // 结构定义
    GPIO_InitStructure.Pin = GPIO_Pin_1;        // 指定要初始化的IO,
    GPIO_InitStructure.Mode = GPIO_PullUp;      // 指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
    GPIO_Inilize(GPIO_P0, &GPIO_InitStructure); // 初始化

    GPIO_InitStructure.Pin = GPIO_Pin_2;        // 指定要初始化的IO,
    GPIO_InitStructure.Mode = GPIO_PullUp;      // 指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
    GPIO_Inilize(GPIO_P3, &GPIO_InitStructure); // 初始化
}

void PWM_config(void)
{
    PWMx_InitDefine PWMx_InitStructure;

    // 总配置
    // (MAIN_Fosc / 1000) - 1 周期计数值
    // 配置分频系数,必须使用改进后的PWM.h和PWM.C文件
    PWMx_InitStructure.PWM_Prescaler = Prescaler - 1;
    PWMx_InitStructure.PWM_Period = PERIOD - 1; // 周期时间,   0~65535
    PWMx_InitStructure.PWM_DeadTime = 0;        // 死区发生器设置, 0~255
    PWMx_InitStructure.PWM_EnoSelect = ENO6P;   // 输出通道选择,	ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
    PWMx_InitStructure.PWM_PS_SW = PWM6_SW_P01; // 切换端口

    // 具体PWM端口配置
    // pwm6
    PWMx_InitStructure.PWM6_Mode = CCMRn_PWM_MODE1; // 模式,		CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2
    PWMx_InitStructure.PWM6_Duty = 0;               // PWM4占空比时间, 0~Period

    // pwm6
    PWMx_InitStructure.PWM_CC6Enable = ENABLE; // 开启PWM6P输入捕获/比较输出,  ENABLE,DISABLE

    // PWM启动配置
    PWMx_InitStructure.PWM_MainOutEnable = ENABLE; // 主输出使能, ENABLE,DISABLE
    PWMx_InitStructure.PWM_CEN_Enable = ENABLE;    // 使能计数器, ENABLE,DISABLE
    PWM_Configuration(PWMB, &PWMx_InitStructure);  // 初始化PWM,  PWMA,PWMB
}

初始化UART打印日志


void UART_config(void)
{
    COMx_InitDefine COMx_InitStructure;              // 结构定义
    COMx_InitStructure.UART_Mode = UART_8bit_BRTx;   // 模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
    COMx_InitStructure.UART_BRT_Use = BRT_Timer1;    // 选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
    COMx_InitStructure.UART_BaudRate = 115200ul;     // 波特率, 一般 110 ~ 115200
    COMx_InitStructure.UART_RxEnable = ENABLE;       // 接收允许,   ENABLE或DISABLE
    COMx_InitStructure.BaudRateDouble = DISABLE;     // 波特率加倍, ENABLE或DISABLE
    COMx_InitStructure.UART_Interrupt = ENABLE;      // 中断允许,   ENABLE或DISABLE
    COMx_InitStructure.UART_Priority = Priority_0;   // 指定中断优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
    COMx_InitStructure.UART_P_SW = UART1_SW_P30_P31; // 切换端口,   UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
    UART_Configuration(UART1, &COMx_InitStructure);  // 初始化串口1 UART1,UART2,UART3,UART4
}

初始化外部中断Exti

用于监听按钮P32的按下事件

void Exti_config(void)
{
    EXTI_InitTypeDef Exti_InitStructure;           // 结构定义
    Exti_InitStructure.EXTI_Interrupt = ENABLE;    // 中断使能,   ENABLE或DISABLE
    Exti_InitStructure.EXTI_Mode = EXT_MODE_Fall;  // 中断模式,   EXT_MODE_RiseFall,EXT_MODE_Fall
    Exti_InitStructure.EXTI_Priority = Priority_0; // 中断使能,   ENABLE或DISABLE
    Ext_Inilize(EXT_INT0, &Exti_InitStructure);    // 初始化
}

处理按钮按下事件


u16 duty_percent = 500; // 500us -> 2500us
void ext_int0_call()
{
    static int step = 500;
    float angle = 0;
    PWMx_Duty duty;
    //  500 ->   0°
    // 1000 ->  45°
    // 1500 ->  90°
    // 2000 -> 135°
    // 2500 -> 180°
    delay_ms(10);
    if (P32)
    {
        // 延时10ms后,依然低电平,才执行。消除抖动
        return;
    }

    // 修改占空比 0 -> 100
    duty_percent += step;
    if (duty_percent >= 2500)
    {
        step = -500;
    }
    else if (duty_percent <= 500)
    {
        step = 500;
    }

    // 计算不同的占空比对应的角度值,用于打印
    angle = (duty_percent - 500) * 180.0f / 2000;
    printf("duty_percent: %d angle: %.1f \r\n", (int)duty_percent, angle);
    // 设置占空比
    duty.PWM6_Duty = PERIOD * duty_percent / 20000;
    UpdatePwm(PWMB, &duty);
}

main函数

void main()
{
    PWMx_Duty duty;

    GPIO_config();
    UART_config();
    PWM_config();

    Exti_config();

    EA = 1;

    P32 = 1;
    duty.PWM6_Duty = PERIOD * duty_percent / 20000;
    UpdatePwm(PWMB, &duty);

    while (1)
    {
        delay_ms(10);
    }
}
  • 28
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
嵌入 PWM 是一种用于控制的有效技术。可以通过改变脉冲宽度来调整角度位置,因此使用 PWM 来模拟脉冲信号是非常合适的。 对于嵌入系统,我们可以使用 C 语言编写控制的代码。首先,我们需要初始化 PWM 模块,并设置频率和占空比。然后,我们可以使用一个循环来不断地修改占空比,从而控制的角度。 以下是一个简单的示例代码: ```c #include <msp430.h> #define PWM_PERIOD 1000 // PWM 周期 #define MIN_ANGLE 500 // 最小角度位置对应的占空比 #define MAX_ANGLE 2500 // 最大角度位置对应的占空比 void initPWM() { P1DIR |= BIT2; // P1.2 输出 P1SEL |= BIT2; // P1.2 使用 PWM 功能 TA0CTL = TASSEL_2 + MC_1; // 选择 SMCLK 作为时钟源,设置为增计数模 TA0CCR0 = PWM_PERIOD - 1; // 设置 PWM 周期 TA0CCTL1 = OUTMOD_7; // 设定输出模PWM TA0CCR1 = MIN_ANGLE; // 初始角度设为最小位置 } void setAngle(int angle) { if (angle < 0) { angle = 0; } else if (angle > 180) { angle = 180; } // 将角度转换成对应的占空比 int dutyCycle = (int)(MIN_ANGLE + (MAX_ANGLE - MIN_ANGLE) * angle / 180.0); TA0CCR1 = dutyCycle; // 设置占空比 } int main() { WDTCTL = WDTPW + WDTHOLD; // 关闭看门狗定时器 initPWM(); // 初始化 PWM while(1) { setAngle(90); // 将角度设为 90 度 __delay_cycles(1000000); // 延时 setAngle(0); // 将角度设为 0 度 __delay_cycles(1000000); // 延时 } } ``` 以上代码通过 MSP430 的 PWM 模块来控制的角度,其中使用了 `initPWM` 函数来初始化 PWM 模块,`setAngle` 函数用于设置的角度,`main` 函数则是一个简单的循环示例,用于不断地改变的角度。希望这个示例能够帮助您理解如何利用嵌入 PWM 控制的代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋野酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值