|
1 |
| -/*** |
2 |
| - * author : FENN MAI |
3 |
| - * last modified date: 30/05/2024 |
| 1 | +/** |
| 2 | + * @file Emakefun_MotorDriver.cpp |
| 3 | + * @brief 控制舵机和直流齿轮电机 |
4 | 4 | *
|
5 |
| - * Basic 3.0, date: 29/05/2024 |
6 |
| - * changed the code from wiringPi to pigpio to control the servo and DC gear motor |
| 5 | + * @author FENN MAI |
| 6 | + * @date 30/05/2024 |
| 7 | + * @version Basic 3.0 |
7 | 8 | *
|
| 9 | + * Version: Basic 3.0 |
| 10 | + * 修改日期:2024年5月29日 |
| 11 | + * 变更内容:将代码从wiringPi改为pigpio,以控制舵机和直流齿轮电机。 |
8 | 12 | */
|
| 13 | + |
9 | 14 | #include "Emakefun_MotorDriver.h"
|
10 | 15 | #include <cmath>
|
11 | 16 | #include <pigpio.h>
|
12 |
| -// addr = 0x60 |
13 |
| -Emakefun_MotorDriver::Emakefun_MotorDriver(uint8_t addr) { _i2caddr = addr; } |
14 | 17 |
|
| 18 | +/** |
| 19 | + * @brief 构造函数,初始化I2C地址。 |
| 20 | + * @param addr I2C地址,默认值为0x60。 |
| 21 | + */ |
| 22 | +Emakefun_MotorDriver::Emakefun_MotorDriver(uint8_t addr) { |
| 23 | + _i2caddr = addr; |
| 24 | +} |
| 25 | + |
| 26 | +/** |
| 27 | + * @brief 初始化I2C通信并重置PCA9685设备。 |
| 28 | + */ |
15 | 29 | void Emakefun_MotorDriver::begin(void) {
|
16 |
| - Raspi_I2C::init(_i2caddr); |
17 |
| - reset(); |
| 30 | + Raspi_I2C::init(_i2caddr); // 初始化I2C通信 |
| 31 | + reset(); // 重置PCA9685设备 |
18 | 32 | }
|
19 | 33 |
|
20 |
| -void Emakefun_MotorDriver::reset(void) { write8(PCA9685_MODE1, 0x00); } |
| 34 | +/** |
| 35 | + * @brief 重置PCA9685设备。 |
| 36 | + */ |
| 37 | +void Emakefun_MotorDriver::reset(void) { |
| 38 | + write8(PCA9685_MODE1, 0x00); |
| 39 | +} |
21 | 40 |
|
| 41 | +/** |
| 42 | + * @brief 设置PWM频率。 |
| 43 | + * @param freq 频率值。 |
| 44 | + */ |
22 | 45 | void Emakefun_MotorDriver::setPWMFreq(float freq) {
|
23 |
| - // printf("Attempting to set freq :%lf \n",freq); |
24 |
| - |
25 |
| - // freq *= 0.9; // Correct for overshoot in the frequency setting (see issue |
26 |
| - // #11). |
27 |
| - |
28 |
| - float prescaleval = 25000000; |
29 |
| - prescaleval /= 4096; |
30 |
| - prescaleval /= freq; |
31 |
| - prescaleval -= 1; |
32 |
| - uint8_t prescale = floor(prescaleval + 0.5); |
33 |
| - |
34 |
| - uint8_t oldmode = read8(PCA9685_MODE1); |
35 |
| - uint8_t newmode = (oldmode & 0x7F) | 0x10; // sleep |
36 |
| - write8(PCA9685_MODE1, newmode); // go to sleep |
37 |
| - write8(PCA9685_PRESCALE, prescale); // set the prescaler |
38 |
| - write8(PCA9685_MODE1, oldmode); |
39 |
| - gpioDelay(5000); |
40 |
| - write8(PCA9685_MODE1, |
41 |
| - oldmode | 0xa1); // This sets the MODE1 register to turn on auto increment. |
42 |
| - // This is why the beginTransmission below was not working. |
43 |
| - // Serial.print("Mode now 0x"); Serial.println(read8(PCA9685_MODE1), HEX); |
| 46 | + float prescaleval = 25000000.0f; // 固定时钟频率 |
| 47 | + prescaleval /= 4096.0f; // 分辨率 |
| 48 | + prescaleval /= freq; // 频率 |
| 49 | + prescaleval -= 1.0f; |
| 50 | + uint8_t prescale = static_cast<uint8_t>(floor(prescaleval + 0.5f)); |
| 51 | + |
| 52 | + uint8_t oldmode = read8(PCA9685_MODE1); |
| 53 | + uint8_t newmode = (oldmode & 0x7F) | 0x10; // 进入睡眠模式 |
| 54 | + write8(PCA9685_MODE1, newmode); // 进入睡眠模式 |
| 55 | + write8(PCA9685_PRESCALE, prescale); // 设置预分频器 |
| 56 | + write8(PCA9685_MODE1, oldmode); // 退出睡眠模式 |
| 57 | + gpioDelay(5000); // 等待5ms |
| 58 | + write8(PCA9685_MODE1, oldmode | 0xA1); // 开启自动递增 |
44 | 59 | }
|
45 | 60 |
|
| 61 | +/** |
| 62 | + * @brief 设置PWM输出。 |
| 63 | + * @param num PWM通道号。num(0,15) |
| 64 | + * @param on PWM开启时间。PWM 开始时间(0-4095),表示 PWM 周期中信号从低到高的时间点。 |
| 65 | + * @param off PWM关闭时间。PWM 结束时间(0-4095),表示 PWM 周期中信号从高到低的时间点。 |
| 66 | + */ |
46 | 67 | void Emakefun_MotorDriver::setPWM(uint8_t num, uint16_t on, uint16_t off) {
|
47 |
| - // Serial.print("Setting PWM "); Serial.print(num); Serial.print(": "); |
48 |
| - // Serial.print(on); Serial.print("->"); Serial.println(off); |
49 |
| - |
50 |
| - // write8(LED0_ON_L + (num << 2), on & 0xFF); |
51 |
| - // write8(LED0_ON_H + (num << 2), on >> 8); |
52 |
| - // write8(LED0_OFF_L + (num << 2), off & 0xFF); |
53 |
| - // write8(LED0_OFF_H + (num << 2), off >> 8); |
54 |
| - |
55 |
| - uint8_t data[] = {static_cast<uint8_t>(LED0_ON_L + (num << 2)), static_cast<uint8_t>(on & 0xFF), |
56 |
| - static_cast<uint8_t>(on >> 8), static_cast<uint8_t>(off & 0xFF), static_cast<uint8_t>(off >> 8)}; |
57 |
| - Write(data, sizeof(data)); |
| 68 | + uint8_t data[] = { |
| 69 | + // LED0_ON_L 是 PCA9685 寄存器的基地址,用于设置通道 0 的 LED 开始时间低字节。 |
| 70 | + // num << 2 将通道号左移两位,这是因为每个通道有四个寄存器(ON_L、ON_H、OFF_L、OFF_H)。 |
| 71 | + // LED0_ON_L + (num << 2) 计算得出通道 num 的 ON_L 寄存器地址。 |
| 72 | + static_cast<uint8_t>(LED0_ON_L + (num << 2)), |
| 73 | + // on & 0xFF 获取 on 的低 8 位。 |
| 74 | + // on >> 8 获取 on 的高 8 位。 |
| 75 | + static_cast<uint8_t>(on & 0xFF), |
| 76 | + static_cast<uint8_t>(on >> 8), |
| 77 | + // off & 0xFF 获取 off 的低 8 位。 |
| 78 | + // off >> 8 获取 off 的高 8 位。 |
| 79 | + static_cast<uint8_t>(off & 0xFF), |
| 80 | + static_cast<uint8_t>(off >> 8) |
| 81 | + }; |
| 82 | + Write(data, sizeof(data)); // 写入数据 |
58 | 83 | }
|
59 | 84 |
|
60 |
| -uint8_t Emakefun_MotorDriver::read8(uint8_t addr) { return ReadReg8(addr); } |
| 85 | +/** |
| 86 | + * @brief 读取8位寄存器的值。 |
| 87 | + * @param addr 寄存器地址。 |
| 88 | + * @return 寄存器的8位值。 |
| 89 | + */ |
| 90 | +uint8_t Emakefun_MotorDriver::read8(uint8_t addr) { |
| 91 | + return ReadReg8(addr); |
| 92 | +} |
61 | 93 |
|
62 |
| -void Emakefun_MotorDriver::write8(uint8_t addr, uint8_t d) { WriteReg8(addr, d); } |
| 94 | +/** |
| 95 | + * @brief 向8位寄存器写入数据。 |
| 96 | + * @param addr 寄存器地址。 |
| 97 | + * @param d 写入的数据。 |
| 98 | + */ |
| 99 | +void Emakefun_MotorDriver::write8(uint8_t addr, uint8_t d) { |
| 100 | + WriteReg8(addr, d); |
| 101 | +} |
0 commit comments