hi3861 OpenHarmony PCA9685 舵机控制板

I2C通信协议控制,可以输出16路PWM(脉冲宽度调制)。

内部时钟是25MHz,要输出满足要求的频率需要进行设置转换。

以最常用的SG90舵机为例:

向信号端口发送20ms波长的信号,这个时候要用到一个频率的单位赫兹。

麦克斯韦理论上发现了电磁波的存在,赫兹通过实验证明了电磁波,然后用他的名字命名频率的单位。1s中一个震动周期就是1Hz,1s中1000个就是1KHz。

 SG90的接收一个工作波的周期是20ms,1s = 1000ms / 20ms = 50,  就是 50个赫兹, 50Hz。

PCA9685的2个主要控制寄存器:

MODE1

MODE1 地址: 0x00

[ 7 ]    重新启动               0* 已禁用重新启动 / 1 已启用重新启动
[ 6 ]    外部时钟选择        0* 使用内部时钟 / 1 使用EXTCLK引脚时钟
[ 5 ]    AI                          0* 寄存器自动增量已禁用 / 1 启用寄存器自动增量
[ 4 ]    睡眠                      0 正常模式 / 1* 低功率模式。

[ 3 ]    SUB1             0* PCA9685不响应I2C总线子地址1 / 1 PCA9685响应I2C总线子地址1
[ 2 ]    SUB2             0* PCA9685不响应I2C总线子地址2 / 1 PCA9685响应I2C总线子地址2。
[ 1 ]    SUB3             0* PCA9685不响应I2C总线子地址3 / 1 PCA9685响应I2C总线子地址3。
[ 0 ]    ALLCALL       0 PCA9685不响应 LED All Call I2C总线地址 / 1* PCA9685响应 LED All Call I2C总线地址

PRE_SCALE

PRE_SCALE 地址: 0xFE

设置工作频率,首先设置MODE1,设置成休眠状态,然后向PRE_SCALE写入频率。

PCA9685内部输出时钟是25MHz,需要通过计算公式换算出我们需要的频率。

prescale value = round ( osc_clock / (4096 * update_rate) ) - 1

预缩放值 = 整数 ( osc时钟 / (4096 * 更新速率) ) - 1

// 设置PWM频率
hi_u8 PCA9685_Set_PWM_Freq(hi_u8 freq)
{
    hi_float prescale = 25000000 / 4096 / (freq * 0.95) - 1;

    // 向上取整
    hi_u8 val = (hi_u8)(prescale + 0.5);    

    // 0x10  0001 0000  [7] = 0 已禁用重新启动  [4] = 1 休眠
    PCA9685_I2C_Write_Data(PCA9685_MODE1, 0x10); 

    // 输入频率
    PCA9685_I2C_Write_Data(PCA9685_PRE_SCALE, val);

    // 0xa1 1010 0001 [7] = 1 已启用重新启动 [5] = 1 启用寄存器自动增量 [0] = 1 PCA9685响应 LED All Call I2C总线地址
    PCA9685_I2C_Write_Data(PCA9685_MODE1, 0xa1);    
    hi_udelay(500);
}

freq * 0.95 是为了防过冲

MODE1 [4]  位休眠位 置0一定要等待500us,否者就会出错,然后模块就像失灵了一样,不要担心没有坏,改一下 I2C的工作频率100KHz,试试能不能通,通了以后再恢复到400K。

然后就是控制舵机

SG90, 转动范围是180度,

0.5ms ----  0 °  0.5ms / 20ms = 0.025

1.0ms ----  45 °  1.0ms / 20ms = 0.050

1.5ms ----  90 °  1.5ms / 20ms = 0.075

2.0ms ----  135 °  2.0ms / 20ms = 0.100

2.5ms ----  180 °  2.5ms / 20ms = 0.125

PCA9685设置占空比, 通过4个1组,共16组LED0_ON_L,LED0_ON_H,LED0_OFF_L,LED0_OFF_H,寄存器设置。

模块处理的数据是16位整数,1个寄存器长度不够,所以由2个寄存器组成1个数值,LED0_ON_L,LED0_ON_H,是开始时间,LED0_OFF_L,LED0_OFF_H,是结束时间。这种设计是非常好的,如果高精度控制舵机非常有帮助,通常不需要高的精度,一般舵机也没有太高精度,所以开始时间就简单设置为0,直接设置结束时间LED0_OFF_L,LED0_OFF_H。

// 设置PWM 占空比
hi_void PCA9685_Set_PWM(hi_u8 num, hi_u16 on, hi_u16 off)
{
    hi_u8 datas[5] = {0};

    datas[0] = PCA9685_LED0_ON_L + 4 * num;
    datas[1] = on & 0xff;
    datas[2] = (on >> 8) & 0xff;
    datas[3] = off & 0xff;
    datas[4] = (off >> 8) & 0xff;

    PCA9685_I2C_Write_Datas(datas, 5);
    hi_udelay(500);
}

SG90, 0 °  设置:

 0 °  = 0.5ms     0.5/20 = 0.025      4096 * 0.025    = 102.4 - 1 = 101

0端口,开始时间0,结束时间101

PCA9685_Set_PWM(0, 0, 101)

180 = 2.5ms     2.5/20 = 0.125      4096 * 0.125    = 512.0 - 1 = 511

(511 - 101) / 180 = 2.28  前面已经向上取整,这里就不要再取正了。

这样 任意角度设置 = 101 + 角度  * 2.28

// 设置 角度
hi_void PCA9685_Angle(hi_u8 num, hi_u8 ang)
{
    // (511 - 101) / 180 = 2.28  已经向上取整
    hi_u16 off = (hi_u16)(101 + ang * 2.28);     

    printf(" ang = %d, off = %d \n", ang, off);

    PCA9685_Set_PWM(num, 0, off);
}

最后结合sh1106 OLED,和 hx1838 红外遥控器 做个测试例子。

链接:https://pan.baidu.com/s/1RMh_MsFsD762RxWP8YcwbA?pwd=6ik4 
提取码:6ik4 

  • 23
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值