当前位置: 首页 > news >正文

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

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

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

文章目录

    • 舵机信号线
    • 代码示例
      • 初始化PWM
      • 初始化UART打印日志
      • 初始化外部中断Exti
      • main函数

舵机最早用于船舶上实现转向功能,由于可以通过程序连续控制其转角,因而被广泛应用于智能小车转向以及机器人各类关节中.
工作电压: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_PPGPIO_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_PPGPIO_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~65535PWMx_InitStructure.PWM_DeadTime = 0;        // 死区发生器设置, 0~255PWMx_InitStructure.PWM_EnoSelect = ENO6P;   // 输出通道选择,	ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8PPWMx_InitStructure.PWM_PS_SW = PWM6_SW_P01; // 切换端口// 具体PWM端口配置// pwm6PWMx_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_MODE2PWMx_InitStructure.PWM6_Duty = 0;               // PWM4占空比时间, 0~Period// pwm6PWMx_InitStructure.PWM_CC6Enable = ENABLE; // 开启PWM6P输入捕获/比较输出,  ENABLE,DISABLE// PWM启动配置PWMx_InitStructure.PWM_MainOutEnable = ENABLE; // 主输出使能, ENABLE,DISABLEPWMx_InitStructure.PWM_CEN_Enable = ENABLE;    // 使能计数器, ENABLE,DISABLEPWM_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_BRTxCOMx_InitStructure.UART_BRT_Use = BRT_Timer1;    // 选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate = 115200ul;     // 波特率, 一般 110 ~ 115200COMx_InitStructure.UART_RxEnable = ENABLE;       // 接收允许,   ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE;     // 波特率加倍, ENABLE或DISABLECOMx_InitStructure.UART_Interrupt = ENABLE;      // 中断允许,   ENABLE或DISABLECOMx_InitStructure.UART_Priority = Priority_0;   // 指定中断优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3COMx_InitStructure.UART_P_SW = UART1_SW_P30_P31; // 切换端口,   UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44UART_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或DISABLEExti_InitStructure.EXTI_Mode = EXT_MODE_Fall;  // 中断模式,   EXT_MODE_RiseFall,EXT_MODE_FallExti_InitStructure.EXTI_Priority = Priority_0; // 中断使能,   ENABLE或DISABLEExt_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 -> 100duty_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);}
}

相关文章:

  • 辐射度技术在AI去衣中的魅力与科学
  • 基于长短期记忆网络 LSTM 的送餐时间预测
  • 1960-2022年世界银行WDI面板数据(1400+指标)
  • 论文阅读--ActionCLIP
  • Leetcode.560.和为k的子数组
  • python基础(1) -- 基本数据类型与变量
  • SQL Server--死锁
  • SDK——如何快速上手一个接口驱动任务(以iic为例)
  • 基于springboot+vue的4S店车辆管理系统
  • vulnhub靶场之FunBox-8
  • 渗透工具CobaltStrike工具的下载和安装
  • 粤嵌—2024/5/20—三角形最小路径和(✔)
  • gRPC和ProtoBuf
  • LeetCode-105-岛屿的最大面积
  • 【Linux杂货铺】进程通信
  • 【个人向】《HTTP图解》阅后小结
  • 30秒的PHP代码片段(1)数组 - Array
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • Angular Elements 及其运作原理
  • E-HPC支持多队列管理和自动伸缩
  • ES6 ...操作符
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • passportjs 源码分析
  • REST架构的思考
  • spring cloud gateway 源码解析(4)跨域问题处理
  • sublime配置文件
  • vue 配置sass、scss全局变量
  • vue从入门到进阶:计算属性computed与侦听器watch(三)
  • 诡异!React stopPropagation失灵
  • 聚簇索引和非聚簇索引
  • 那些被忽略的 JavaScript 数组方法细节
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 如何在 Tornado 中实现 Middleware
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • 探索 JS 中的模块化
  • 我与Jetbrains的这些年
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • 回归生活:清理微信公众号
  • 如何在招聘中考核.NET架构师
  • ​如何使用QGIS制作三维建筑
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • # windows 安装 mysql 显示 no packages found 解决方法
  • #进阶:轻量级ORM框架Dapper的使用教程与原理详解
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (2)nginx 安装、启停
  • (24)(24.1) FPV和仿真的机载OSD(三)
  • (aiohttp-asyncio-FFmpeg-Docker-SRS)实现异步摄像头转码服务器
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (图)IntelliTrace Tools 跟踪云端程序
  • (转)VC++中ondraw在什么时候调用的
  • .bat批处理(九):替换带有等号=的字符串的子串
  • .NET BackgroundWorker