当前位置:   article > 正文

hi3861 OpenHarmony PCA9685 舵机控制板

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

  1. // 设置PWM频率
  2. hi_u8 PCA9685_Set_PWM_Freq(hi_u8 freq)
  3. {
  4. hi_float prescale = 25000000 / 4096 / (freq * 0.95) - 1;
  5. // 向上取整
  6. hi_u8 val = (hi_u8)(prescale + 0.5);
  7. // 0x10 0001 0000 [7] = 0 已禁用重新启动 [4] = 1 休眠
  8. PCA9685_I2C_Write_Data(PCA9685_MODE1, 0x10);
  9. // 输入频率
  10. PCA9685_I2C_Write_Data(PCA9685_PRE_SCALE, val);
  11. // 0xa1 1010 0001 [7] = 1 已启用重新启动 [5] = 1 启用寄存器自动增量 [0] = 1 PCA9685响应 LED All Call I2C总线地址
  12. PCA9685_I2C_Write_Data(PCA9685_MODE1, 0xa1);
  13. hi_udelay(500);
  14. }

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。

  1. // 设置PWM 占空比
  2. hi_void PCA9685_Set_PWM(hi_u8 num, hi_u16 on, hi_u16 off)
  3. {
  4. hi_u8 datas[5] = {0};
  5. datas[0] = PCA9685_LED0_ON_L + 4 * num;
  6. datas[1] = on & 0xff;
  7. datas[2] = (on >> 8) & 0xff;
  8. datas[3] = off & 0xff;
  9. datas[4] = (off >> 8) & 0xff;
  10. PCA9685_I2C_Write_Datas(datas, 5);
  11. hi_udelay(500);
  12. }

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

  1. // 设置 角度
  2. hi_void PCA9685_Angle(hi_u8 num, hi_u8 ang)
  3. {
  4. // (511 - 101) / 180 = 2.28 已经向上取整
  5. hi_u16 off = (hi_u16)(101 + ang * 2.28);
  6. printf(" ang = %d, off = %d \n", ang, off);
  7. PCA9685_Set_PWM(num, 0, off);
  8. }

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/398943
推荐阅读
相关标签
  

闽ICP备14008679号