本帖最后由 zlook119 于 2024-3-28 15:48 编辑
本帖最后由 zlook119 于 2024-3-28 15:41 编辑
【外设移植】SG90舵机Ai-M61开发板
一、外设介绍
产品名称:SG90 9g 塑料齿数字舵机
产品净重: 9g
产品尺寸: 23*12.2*29mm
产品扭矩: 1.5kg/cm
反应速度: 0.3sec/60degree
工作电压: 4.2V-6V
使用温度: 0-55度
动作死区: 10us
齿轮介质: 塑料
该舵机有三根线黑/灰色为GND,红色为VCC,橙色为信号线
SG90舵机分为180度和360度(连续旋转),本文仅仅讨论180度舵机 ,下图左侧为360度舵机,右侧为180度舵机。
二、舵机驱动信号分析
阅读相关资料得知,该舵机为PWM信号驱动,信号周期为20ms,既下图中T时间为20ms
下图为高电平持续时间t对应的旋转角度的关系
下面为逻辑分析仪采集的相关角度的直观数据
0度时驱动信号的图像
90度时驱动信号的图像
180度时驱动信号的图像
即,M61输出相关PWM波形到舵机信号线,舵机就会旋转相应角度。
三、移植过程
M61和舵机的连接
3V3---->红色
GPIO19---->信号线(橙色)
GND---->黑色/灰色
接下来编写程序生成指定的PWM信号,可以参考阅读,小泽哥的这篇文章
(九)零基础开发小安派-Eyes-S1【外设篇】——PWM
https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=622
(出处: 物联网开发者社区-安信可论坛)
这里粘贴一下bflb_servo.c的内容
#include "bflb_mtimer.h" //mtimer定时器头文件
#include "bflb_pwm_v2.h" //pwm_v2头文件
#include "bflb_clock.h" //系统时钟头文件
#include "board.h" //开发板头文件,包装的库
#include "bflb_gpio.h" //gpio头文件
#include "bflb_servo.h"
struct bflb_servo_attr bflb_servo_attach(uint8_t pin, uint8_t ch){
struct bflb_device_s *pwm; //创建LHAL外设库结构体,名称为pwm
struct bflb_device_s *gpio; //初始化一个结构体指针作为外设句柄
struct bflb_servo_attr servo_attr; // 创建要返回的结构体实例
gpio = bflb_device_get_by_name("gpio");
bflb_gpio_init(gpio, pin, GPIO_FUNC_PWM0 | GPIO_ALTERNATE | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1);
pwm = bflb_device_get_by_name("pwm_v2_0"); //给外设接口赋名pwm_v2_0
/* period = .XCLK / .clk_div / .period = 40MHz / 16000 / 50 = 50Hz */
struct bflb_pwm_v2_config_s cfg = {
.clk_source = BFLB_SYSTEM_XCLK,
.clk_div = 160,
.period = 5000,
}; //设置PWM的频率,选择时钟,分频,和周期。根据上面的公式算出最终的频率。
/*初始化PWM输出*/
bflb_pwm_v2_init(pwm, &cfg);
// bflb_pwm_v2_channel_positive_start 开启正向通道(CHxP)输出
// bflb_pwm_v2_channel_negative_start开启负向通道(CHxN) 从参数内可以查询
bflb_pwm_v2_channel_positive_start(pwm, ch); //IO19是正向通道3
bflb_pwm_v2_start(pwm); //将设置好的频率开启pwm输出
servo_attr.dev = pwm;
servo_attr.pin = pin;
servo_attr.ch = ch;
return servo_attr;
}
int angle_to_pwm(int angle) {
if (angle < SERVO_ANGLE_MIN) angle = SERVO_ANGLE_MIN;
if (angle > SERVO_ANGLE_MAX) angle = SERVO_ANGLE_MAX;
// 线性插值计算PWM值
int range = SERVO_ANGLE_MAX - SERVO_ANGLE_MIN;
int pwm_range = PWM_MAX - PWM_MIN;
int pwm_value = PWM_MIN + ((angle - SERVO_ANGLE_MIN) * pwm_range / range);
return pwm_value;
}
// 写入伺服角度值(以度为单位)
void bflb_servo_write(struct bflb_servo_attr *servo, int angle) {
// 将角度转换为PWM占空比
int pwm_value = angle_to_pwm(angle);
// 调用pwm修改占空比
bflb_pwm_v2_channel_set_threshold(servo->dev, servo->ch, 0, pwm_value);
}
void bflb_servo_stop(struct bflb_servo_attr *servo){
// 停止PWM信号发生
bflb_pwm_v2_channel_positive_stop(servo->dev, servo->ch);
}
bflb_servo.c
实现了三个函数,
struct bflb_servo_attr bflb_servo_attach(uint8_t pin, uint8_t ch);
传入引脚和PWM正向通道,生成servo设备,进行后续函数的操作。
void bflb_servo_write(struct bflb_servo_attr *servo, int value);
传入servo设备和角度值,使舵机旋转到指定角度
void bflb_servo_stop(struct bflb_servo_attr *servo);
传入设备,停止生成PWM信号
其中PWM的通道通过查 bl616_bl618_ds_zh_cn_1.4.pdf
手册获取,如图。
下面粘贴一下测试用例
#include "bflb_mtimer.h" //mtimer定时器头文件
#include "bflb_pwm_v2.h" //pwm_v2头文件
#include "bflb_clock.h" //系统时钟头文件
#include "board.h" //开发板头文件,包装的库
#include "bflb_gpio.h" //gpio头文件
#include "bflb_servo.h"
int main(void)
{
// int i;
board_init(); //板子初始化
struct bflb_servo_attr servo = bflb_servo_attach(GPIO_PIN_19, PWM_CH3); // 舵机初始化,此处只使用了正向通道,GPIO的正向通道可以从附件中查找
bflb_servo_write(&servo, 0);
bflb_mtimer_delay_ms(2000);
bflb_servo_write(&servo, 45);
bflb_mtimer_delay_ms(2000);
bflb_servo_write(&servo, 90);
bflb_mtimer_delay_ms(2000);
bflb_servo_write(&servo, 135);
bflb_mtimer_delay_ms(2000);
bflb_servo_write(&servo, 180);
bflb_mtimer_delay_ms(2000);
bflb_servo_stop(&servo);
while (0) {
// bflb_servo_write(&servo, 0);
// bflb_mtimer_delay_ms(2000);
// bflb_servo_write(&servo, 45);
// bflb_mtimer_delay_ms(2000);
// bflb_servo_write(&servo, 90);
// bflb_mtimer_delay_ms(2000);
// bflb_servo_write(&servo, 135);
// bflb_mtimer_delay_ms(2000);
// bflb_servo_write(&servo, 180);
// bflb_mtimer_delay_ms(2000);
}
}
测试的相关视频
<iframe src="https://player.bilibili.com/player.html?aid=1752273960&bvid=BV1vx421Q7rt&cid=1484810069&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"> </iframe>
最后,特特别注意
在驱动调试的过程中,可能因为PWM参数设置不正确,导致第一块M61烧坏了,后来又买了一块块儿,请大家确认程序运行完好后再给外设上电,最好上电前用逻辑分析仪测一下信号,谢谢大家看到这儿,小菜鸟给大家致敬啦。🫡