树莓派+TCA9548+PCA9685+舵机:wiringPi实现
参考:https://blog.csdn.net/weixin_38956024/article/details/95101686
上篇文章《树莓派+PCA9685+舵机控制:wiringPi实现》已讲解树莓派+PCA9685+舵机,本篇文章讲解树莓派+TCA9548+PCA9685+舵机wiringPi实现。
1接线
很简单,本图供参考:
2代码:
#include <stdbool.h>
#include <stdio.h>
#include "wiringPi.h"
#include <wiringPiI2C.h>
#include <unistd.h>
bool PCA9685Init();
void ResetPca9685();
void PCA9685SetPwmFreq(unsigned short freq);
void PCA9685SetPwm(unsigned char channel, unsigned short on, unsigned short value);
void SetServoPulse(unsigned char channel, unsigned short pulse);
#define TCA9548_ADDRESS 0x70 //tca9548地址
#define PCA9685_ADDRESS 0x40 //pca9685地址
#define PCA9685_CLOCK_FREQ 25000000 //PWM频率25MHz
#define PCA9685_MODE1 0x00
#define PCA9685_MODE2 0x01
#define PCA9685_PRE_SCALE 0xFE
#define PCA9685_LED0_ON_L 0x06
#define PCA9685_LED0_ON_H 0x07
#define PCA9685_LED0_OFF_L 0x08
#define PCA9685_LED0_OFF_H 0x09
#define PCA9685_LED_SHIFT 4
bool WriteByte(int fd, unsigned char regAddr, unsigned char data);
unsigned char ReadByte(int fd, unsigned char regAddr);
bool TCA9548AInit();
bool PCA9685_initSuccess = false;
int PCA9685_fd = 0;
int TCA9548_fd = 0;
int main()
{
wiringPiSetup();
TCA9548AInit();
PCA9685Init();
PCA9685SetPwmFreq(50);//50Hz
int PCA9865_channel = 15;
while (1)
{
for (int i = 500; i < 2500; i += 10)
{
SetServoPulse(PCA9865_channel, i);
usleep(20000);
}
}
return 0;
}
bool TCA9548AInit()
{
//初始化
TCA9548_fd = wiringPiI2CSetup(TCA9548_ADDRESS);
if (TCA9548_fd <= 0)
return false;
printf("TCA9548_fd:%d\n", TCA9548_fd);
if (wiringPiI2CWrite(TCA9548_fd, 1<<7) == -1)
{
printf("WriteByte TCA9548_fd failure!\n");
return false;
}
int i = 1;
while (i--)
{
int data = wiringPiI2CRead(TCA9548_fd);
printf("data = %x\n",data);
usleep(100000);
}
return true;
}
bool PCA9685Init()
{
//初始化
PCA9685_fd = wiringPiI2CSetup(PCA9685_ADDRESS);
if (PCA9685_fd <= 0)
return false;
printf("PCA9685_fd:%d\n", PCA9685_fd);
PCA9685_initSuccess = true;
WriteByte(PCA9685_fd, PCA9685_MODE1, 0x00);
WriteByte(PCA9685_fd, PCA9685_MODE2, 0x04);
usleep(1000);
//Delay Time is 0, means it always turn into high at the begin
WriteByte(PCA9685_fd, PCA9685_LED0_ON_L + PCA9685_LED_SHIFT * 0, 0);
WriteByte(PCA9685_fd, PCA9685_LED0_ON_H + PCA9685_LED_SHIFT * 0, 0);
WriteByte(PCA9685_fd, PCA9685_LED0_ON_L + PCA9685_LED_SHIFT * 1, 0);
WriteByte(PCA9685_fd, PCA9685_LED0_ON_H + PCA9685_LED_SHIFT * 1, 0);
WriteByte(PCA9685_fd, PCA9685_LED0_ON_L + PCA9685_LED_SHIFT * 2, 0);
WriteByte(PCA9685_fd, PCA9685_LED0_ON_H + PCA9685_LED_SHIFT * 2, 0);
WriteByte(PCA9685_fd, PCA9685_LED0_ON_L + PCA9685_LED_SHIFT * 3, 0);
WriteByte(PCA9685_fd, PCA9685_LED0_ON_H + PCA9685_LED_SHIFT * 3, 0);
usleep(1000);
return true;
}
void PCA9685SetPwmFreq(unsigned short freq)
{ //设置频率
unsigned char preScale = (PCA9685_CLOCK_FREQ / 4096 / freq) - 1;
unsigned char oldMode = 0;
printf("set PWM frequency to %d HZ\n", freq);
//read old mode
oldMode = ReadByte(PCA9685_fd, PCA9685_MODE1);
//setup sleep mode, Low power mode. Oscillator off (bit4: 1-sleep, 0-normal)
WriteByte(PCA9685_fd, PCA9685_MODE1, (oldMode & 0x7F) | 0x10);
//set freq
WriteByte(PCA9685_fd, PCA9685_PRE_SCALE, preScale);
//setup normal mode (bit4: 1-sleep, 0-normal)
WriteByte(PCA9685_fd, PCA9685_MODE1, oldMode);
usleep(1000); // >500us
//setup restart (bit7: 1- enable, 0-disable)
WriteByte(PCA9685_fd, PCA9685_MODE1, oldMode | 0x80);
usleep(1000); // >500us
}
void PCA9685SetPwm(unsigned char channel, unsigned short on, unsigned short value)
{
//设置各个通道的PWM
WriteByte(PCA9685_fd, PCA9685_LED0_ON_L + PCA9685_LED_SHIFT * channel, on & 0xFF);
WriteByte(PCA9685_fd, PCA9685_LED0_ON_H + PCA9685_LED_SHIFT * channel, on >> 8);
WriteByte(PCA9685_fd, PCA9685_LED0_OFF_L + PCA9685_LED_SHIFT * channel, value & 0xFF);
WriteByte(PCA9685_fd, PCA9685_LED0_OFF_H + PCA9685_LED_SHIFT * channel, value >> 8);
}
void SetServoPulse(unsigned char channel, unsigned short pulse)
{
pulse = pulse * 4096 / 20000;
PCA9685SetPwm(channel, 0, pulse);
}
bool WriteByte(int fd, unsigned char regAddr, unsigned char data)
{
if (wiringPiI2CWriteReg8(fd, regAddr, data) < 0)
{
printf("wiringPiI2CWriteReg8\n");
return -1;
}
return 0;
}
unsigned char ReadByte(int fd, unsigned char regAddr)
{
unsigned char data; // `data` will store the register data
data = wiringPiI2CReadReg8(fd, regAddr);
if (data < 0)
{
return -1;
}
return data;
}
3、Python版本,需要安装Adafruit_GPIO (有网友说官网安装包下载之后再安装不成功,我也作死了一天,最后放弃了,再安装建议直接sudo pip install Adafruit-GPIO==1.0.0,出现问题请自行百度解决)
from Adafruit_GPIO import I2C
import time
from pca9685 import PCA9685
tca = I2C.get_i2c_device(address=0x70)
def tca_select(channel):
if channel > 7:
return
tca.writeRaw8(1 << channel)
def tca_set(mask):
if mask > 0xff:
return
tca.writeRaw8(mask)
if __name__=='__main__':
tca_select(7)
channel = 15
pwm = PCA9685(0x40, debug=True)
pwm.setPWMFreq(50)
while True:
for i in range(500,2500,10):
pwm.setServoPulse(channel,i)
time.sleep(0.02)
# for i in range(2500,500,-10):
# pwm.setServoPulse(channel,i)
# time.sleep(0.02)