嵌入式进阶——舵机控制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_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);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/647171.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Go使用结构体实现类(面向对象)

前置 package main ​ import ("fmt" ) ​ // 矩形结构体 type Rectangle struct {Length intWidth int } ​ // 计算矩形面积 func (r *Rectangle) Area() int {return r.Length * r.Width } ​ func main() {r : Rectangle{4, 2}// 调用 Area() 方法&#xff0c;计…

BUUCTF-WEB3

[极客大挑战 2019]Knife1 1.打开附件链接 一句话木马eval($_POST["Syc"]); 2.中国蚁剑 用中国蚁剑连接 在根目录下找到一个名为flag的文件 3.得到flag [极客大挑战 2019]Upload1

gcc g++不同版本切换命令

sudo update-alternatives --config g sudo update-alternatives --config gcc ubuntu20.04 切换 gcc/g 版本_ubuntu降低g版本-CSDN博客

Python零基础-中【详细】

接上篇继续&#xff1a; Python零基础-上【详细】-CSDN博客 目录 十、函数式编程 1、匿名函数lambda表达式 &#xff08;1&#xff09;匿名函数理解 &#xff08;2&#xff09;lambda表达式的基本格式 &#xff08;3&#xff09;lambda表达式的使用场景 &#xff08;4&…

Linux -- 进程间通信的五种方式

IPC&#xff08;InterProcess Communication&#xff09;的方式通常有管道&#xff08;包括无名管道和命名管道&#xff09;、消息队列、信号量、共享存储、Socket、Streams等。其中Socket和Stream支持不同主机上的两个进程IPC。 管道&#xff08;Pipes&#xff09;&#xff1a…

【数据库】基于PyMySQL连接并使用数据库(代码示例)

这里写目录标题 前言1、安装PyMySQL2、打开要连接的数据库3、创建数据库连接4、获取数据库版本5、新建数据库表6、向表中插入数据7、查询表中的相关记录8、更新表中的相关记录9、删除表中的相关记录10、关闭游标和连接完整代码 前言 本文演示了如何基于PyMySQL使用代码来创建数…

线性模型--普通最小二乘法

线性模型 一、模型介绍二、用于回归的线性模型2.1 线性回归&#xff08;普通最小二乘法&#xff09; 一、模型介绍 线性模型是在实践中广泛使用的一类模型&#xff0c;该模型利用输入特征的线性函数进行预测。 二、用于回归的线性模型 以下代码可以在一维wave数据集上学习参…

java内存模型介绍

Java内存模型&#xff08;Java Memory Model&#xff0c;JMM&#xff09;是一种规范&#xff0c;它定义了Java虚拟机&#xff08;JVM&#xff09;如何在内存中存储和访问Java对象的方式&#xff0c;以及多个线程如何访问这些对象时的规则。它的主要目标是定义程序中的各个线程如…

Python语言绘制好看的小提琴图、箱形图、散点图、山脊图和柱状图等等

废话不多说&#xff0c;今天给大家分享一个&#xff0c;使用python绘制小提琴图、箱形图、散点图、山脊图和柱状图等等 图中的数据是随机生成的&#xff0c;图例&#xff0c;图注以及坐标题目各种信息&#xff0c;具体内容大家可以自己修改~ 效果图如下所示 &#x1f447;&a…

ML307R OpenCPU 数据保存文件系统fs使用

一、函数介绍 二、实现数据保存 三、代码下载地址 一、函数介绍 以下是cm_fs.h里面的函数介绍 /*** brief 文件指针定位** param [in] fd 文件描述符* param [in] offset 指针偏移量* param [in] base 偏移起始点&#xff0c;CM_FS_SEEK_SET&#xff1a;文件开头 CM_FS…

Keras深度学习框架第二十讲:使用KerasCV中的Stable Diffusion进行高性能图像生成

1、绪论 1.1 概念 为便于后文讨论&#xff0c;首先进行相关概念的陈述。 Stable Diffusion&#xff1a;Stable Diffusion 是一个在图像生成领域广泛使用的技术&#xff0c;尤其是用于文本到图像的转换。它基于扩散模型&#xff08;Diffusion Models&#xff09;&#xff0c;这…

leecode 637 二叉树的层平均值

leetcode 二叉树相关-层序遍历专题 二叉树的层序遍历一般来说&#xff0c;我们是利用队列来实现的&#xff0c;先把根节点入队&#xff0c;然后在出队后将其对应的子节点入队&#xff0c;然后往复此种操作。相比于二叉树的遍历递归&#xff0c;层序遍历比较简单&#xff0c;有…

AlexNet论文解析—ImageNet Classification with Deep Convolutional Neural Networks

AlexNet论文解析—ImageNet Classification with Deep Convolutional Neural Networks 2012 研究背景 认识数据集&#xff1a;ImageNet的大规模图像识别挑战赛 LSVRC-2012&#xff1a;ImageNet Large Scale Visual Recoanition Challenge 类别训练数据测试数据图片格式Mnist1…

word 全文中 英文字体 和 样式的字体 莫名奇妙地 被改成 “等线”

word全文中英文字体和样式的字体莫名奇妙地被改成“等线” sm word又抽风了&#xff0c;改完论文保存后打开突然发现全文字体都不对劲&#xff0c;吓得冷汗直冒&#xff1a;虽然我用git管理了论文版本&#xff0c;但是只有比较大的修改我才上传了&#xff0c;刚刚修了几个小时…

Excel必知必会

文章目录 基础概念数据格式选择区域内指定格式数据多行筛选数据转换数据格式固定首行和首列在滚动时一直显示指定列数据符合预期批量填充公式 函数VLOOKUP函数 基础概念 数据格式 文本&#xff0c;数值&#xff08;默认值0&#xff09;&#xff0c;&#xff08;逻辑值&#x…

OceanBase的存储架构与传统LSM-Tree架构的异同|OceanBase数据转储合并技术解读(二)

前篇博文将OceanBase的存储架构巧妙地与自然界中的“水生态”进行了类比&#xff0c;今日我们转变视角&#xff0c;聚焦在与拥有相同LSM-Tree架构的其他产品的比较&#xff0c;深入探讨OceanBase相较于它们所展现出的独特性能。 众所周知&#xff0c;OceanBase数据库的存储引擎…

HQL面试题练习 —— 合并数据

题目来源&#xff1a;京东 目录 1 题目2 建表语句3 题解 1 题目 已知有数据 A 如下&#xff0c;请分别根据 A 生成 B 和 C。 数据A ------------ | id | name | ------------ | 1 | aa | | 2 | aa | | 3 | aa | | 4 | d | | 5 | c | | 6 | aa…

mac操作系统下,docker登录nexus私库,提示不支持https协议的错误

一、背景 我们使用nexus搭建了一个Docker Registry私有仓库&#xff0c;在Mac操作系统&#xff0c;在推送本地镜像到私库前&#xff0c;要求我们登录私库&#xff0c;报错如下&#xff1a; docker login 192.168.5.6:8086 -u username -p passwordWARNING! Using --password …

Python轻松玩转excel操作指导

目录 一、一图概览 二、表格操作 三、内容操作 四、单元格操作 五、Pandas实现表格操作 六、常见场景示例 一、一图概览 ​ ​本文主要对openpyxl库的常用表格操作进行了梳理&#xff0c;熟练的运用后可极大地提升工作效率。 二、表格操作 #创建一个表格sheet.xlsx #…

[论文阅读笔记31]Mamba (Selective Structured State Space Model) 及其应用

最近想学一下Mamba模型&#xff0c;奈何看了很多视频还是感觉一知半解&#xff0c;因此做一篇笔记&#xff0c;顺便介绍一下Mamba结构作为CV backbone和时间序列预测领域的应用。 论文1. Mamba: Linear-Time Sequence Modeling with Selective State Spaces 0. Abstract 现有…