
配置详情:
树莓派4b控制pca9685模块,地址是0x41 ,在pca9685模块的0和1号输出口接入mg90s舵机
示例代码:
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <stdio.h>
#include <unistd.h>
// PCA9685 registers
#define MODE1 0x00
#define PRESCALE 0xFE
#define LED0_ON_L 0x06
#define LED_ON_STEP 4
// PCA9685 constants
#define PCA9685_ADDRESS 0x41
#define FREQUENCY 50
#define PWM_RANGE 4096
// MG90S constants
#define MG90S_MIN_PULSE_WIDTH 600
#define MG90S_MAX_PULSE_WIDTH 2400
#define MG90S_DEGREE_RANGE 180
// Function to initialize PCA9685
int initPCA9685(int fd) {
wiringPiI2CWriteReg8(fd, MODE1, 0x00); // Reset PCA9685
usleep(10000);
int prescaleval = (25000000 / (PWM_RANGE * FREQUENCY)) - 1;
wiringPiI2CWriteReg8(fd, MODE1, 0x10); // Sleep mode
wiringPiI2CWriteReg8(fd, PRESCALE, (prescaleval & 0xFF)); // Set the prescaler
wiringPiI2CWriteReg8(fd, MODE1, 0x00); // Wake up
return fd;
}
// Function to set the PWM pulse for a specific servo
void setServoPulse(int fd, int channel, int pulse) {
int on = 0;
int off = pulse * PWM_RANGE / 20000; // 20ms base
wiringPiI2CWriteReg8(fd, LED0_ON_L + LED_ON_STEP * channel, on & 0xFF);
wiringPiI2CWriteReg8(fd, LED0_ON_L + LED_ON_STEP * channel + 1, on >> 8);
wiringPiI2CWriteReg8(fd, LED0_ON_L + LED_ON_STEP * channel + 2, off & 0xFF);
wiringPiI2CWriteReg8(fd, LED0_ON_L + LED_ON_STEP * channel + 3, off >> 8);
}
// Function to move the servo to a specific degree
void moveServo(int fd, int channel, int degree) {
if (degree < 0) {
degree = 0;
} else if (degree > MG90S_DEGREE_RANGE) {
degree = MG90S_DEGREE_RANGE;
}
int pulseWidth = MG90S_MIN_PULSE_WIDTH + (degree * (MG90S_MAX_PULSE_WIDTH - MG90S_MIN_PULSE_WIDTH) / MG90S_DEGREE_RANGE);
setServoPulse(fd, channel, pulseWidth);
}
int main() {
wiringPiSetup();
int fd = wiringPiI2CSetup(PCA9685_ADDRESS);
if (fd == -1) {
printf("Error initializing I2C\n");
return 1;
}
initPCA9685(fd);
while (1) {
// Move servo on channel 0
moveServo(fd, 0, 0);
usleep(1000000); // Wait for 1 second
moveServo(fd, 0, 180);
usleep(1000000); // Wait for 1 second
// Move servo on channel 1
moveServo(fd, 1, 0);
usleep(1000000); // Wait for 1 second
moveServo(fd, 1, 180);
usleep(1000000); // Wait for 1 second
}
return 0;
}
代码详解:
寄存器详解:
PCA9685 模块的寄存器地址,每个寄存器存储着不同的配置信息。以下是这些寄存器的简要解释:
子地址寄存器:
PCA9685_SUBADR1 (0x2)
PCA9685_SUBADR2 (0x3)
PCA9685_SUBADR3 (0x4)
这些寄存器用于设置 PCA9685 模块的从设备地址。你可以通过配置这些寄存器,使 PCA9685 响应多个 I2C 地址。
控制模式寄存器:
PCA9685_MODE1 (0x0)
这个寄存器用于配置 PCA9685 的控制模式。通过设置不同的位,你可以控制 PCA9685 的工作模式,比如启用/禁用自动递增、设置输出驱动能力等。
预分频器寄存器:
PCA9685_PRESCALE (0xFE)
通过设置这个寄存器,可以调整 PCA9685 的时钟预分频器,从而影响 PWM 的频率。
LED寄存器:
LED0_ON_L (0x6)
LED0_ON_H (0x7)
LED0_OFF_L (0x8)
LED0_OFF_H (0x9)
这些寄存器用于配置每个 PWM 通道的 PWM 脉冲宽度。每个通道有两个寄存器,分别用于设置 PWM 脉冲的开始和结束位置。
全局 LED寄存器:
ALLLED_ON_L (0xFA)
ALLLED_ON_H (0xFB)
ALLLED_OFF_L (0xFC)
ALLLED_OFF_H (0xFD)
这些寄存器用于配置所有通道的 PWM 脉冲宽度。与单个通道的寄存器类似,每个通道有两个寄存器,分别用于设置 PWM 脉冲的开始和结束位置。
在控制 PCA9685 进行舵机控制时,通常会用到 LED0_ON_L、LED0_ON_H、LED0_OFF_L 和 LED0_OFF_H 这几个寄存器,因为它们控制单个通道的 PWM 脉冲。
pca9685各个工作模式的不同详解:
在 PCA9685 模块中,工作模式主要通过控制模式寄存器(MODE1)的设置来实现。下面详细解释 PCA9685 模块的不同工作模式:
MODE1 寄存器(0x00)
MODE1 寄存器控制 PCA9685 的各种配置和工作模式。下面是 MODE1 寄存器中各个位的含义:
Bit 7 (SLEEP):
0: PCA9685 处于正常工作模式。
1: PCA9685 进入睡眠模式。在睡眠模式下,所有 PWM 输出将被关闭,设备进入低功耗状态。
Bit 6 (SUB1):
用于启用/禁用 PCA9685 的 I2C 从设备地址 1。
Bit 5 (SUB2):
用于启用/禁用 PCA9685 的 I2C 从设备地址 2。
Bit 4 (SUB3):
用于启用/禁用 PCA9685 的 I2C 从设备地址 3。
Bit 3 (ALLCALL):
0: 禁用 PCA9685 的全局 I2C 地址。
1: 启用 PCA9685 的全局 I2C 地址。启用后,I2C 总线上的所有设备都可以响应这个地址。
Bits 2-0 (AI2, AI1, SLEEP):
这些位控制自动递增功能和外部时钟源的选择。
自动递增功能详解:
PCA9685 模块的自动递增功能允许你按顺序递增 PWM 通道寄存器的地址。通过配置 MODE1 寄存器中的 AI(Auto-Increment)位,可以控制是否启用这一功能。
在 PCA9685 模块中,MODE1 寄存器的 AI 位是第 5 位(从右数第 3 位)。以下是该位的含义:
Bit 2 (AI):
0: 禁用自动递增功能。
1: 启用自动递增功能。
如果启用了自动递增功能,写入 PWM 通道寄存器时,PCA9685 将自动递增到下一个 PWM 通道寄存器的地址。这对于依次设置多个 PWM 通道非常方便,而不必每次都手动指定地址。
在初始化 PCA9685 模块时,如果你想使用自动递增功能,可以将 MODE1 寄存器的 AI 位设置为 1。在示例代码中,这是在设置预分频器之前进入睡眠模式之后的操作:
参数#define PRESCALE 0xFE含义:
在PCA9685模块中,PRESCALE
寄存器用于设置时钟预分频器的值,从而影响PWM输出的频率。PRESCALE
寄存器的地址是 0xFE
。
具体来说,时钟频率是通过以下公式计算的:
Clock frequency=Oscillator frequency/(4096×(prescale value+1))
其中:
- Oscillator frequency 是 PCA9685 内部振荡器的频率,通常为 25MHz。
- Prescale value 是
PRESCALE
寄存器的值。
通过调整 PRESCALE
寄存器的值,你可以改变时钟频率,从而影响 PWM 输出的频率。在示例代码中,时钟频率被设置为 50 Hz50Hz,对应的 PRESCALE
值通过以下计算得到:
prescale value= Oscillator frequency/(4096×desired PWM frequency)−1
将 PRESCALE
设置为计算得到的值,就可以使 PCA9685 产生期望的 PWM 频率。
在代码中,有以下行用于设置 PRESCALE
寄存器的值:
wiringPiI2CWriteReg8(fd, PRESCALE, (prescaleval & 0xFF)); // Set the prescaler
其中 (prescaleval & 0xFF)
确保只有低8位的值被写入寄存器,因为 PRESCALE
寄存器只占一个字节。
修改运动模式为反复摆动:
while (1) {
// Move servo on channel 0 from 0 to 180 degrees
for (int degree = 0; degree <= 180; degree++) {
moveServo(fd, 0, degree);
usleep(10000); // Small delay between steps, adjust as needed
}
// Move servo on channel 0 from 180 to 0 degrees
for (int degree = 180; degree >= 0; degree--) {
moveServo(fd, 0, degree);
usleep(10000); // Small delay between steps, adjust as needed
}
// Move servo on channel 1 from 0 to 180 degrees
for (int degree = 0; degree <= 180; degree++) {
moveServo(fd, 1, degree);
usleep(10000); // Small delay between steps, adjust as needed
}
// Move servo on channel 1 from 180 to 0 degrees
for (int degree = 180; degree >= 0; degree--) {
moveServo(fd, 1, degree);
usleep(10000); // Small delay between steps, adjust as needed
}
}