文章目录[隐藏]
ESP8266与PCA9685通信I2C
Talk is cheap, show you code!
/**
* ESP8266与PCA9685通过I2C协议通信
* 功能:控制PCA9685上的16个舵机旋转0-180°,串口打印舵机id和角度
* 说明:本代码没有使用ESP8266自带的I2C,而是pin模拟输出
* 接线:
* SDA -> GPIO4(D2)
* SCL -> GPIO5(D1)
* 作者:锋 2022/1/22/18:43
*/
typedef unsigned char u8;
typedef unsigned short u16;
#define sda_pin 4//GPIO4->D2
#define scl_pin 5//GPIO5->D1
#define SDA_H digitalWrite(sda_pin,HIGH)
#define SDA_L digitalWrite(sda_pin,LOW)
#define SCL_H digitalWrite(scl_pin,HIGH)
#define SCL_L digitalWrite(scl_pin,LOW)
#define PCA9685_adrr 0x80// 1+A5+A4+A3+A2+A1+A0+w/r
#define PCA9685_SUBADR1 0x2
#define PCA9685_SUBADR2 0x3
#define PCA9685_SUBADR3 0x4
#define PCA9685_MODE1 0x00
#define PCA9685_PRESCALE 0xFE
#define LED0_ON_L 0x06
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09
#define ALLLED_ON_L 0xFA
#define ALLLED_ON_H 0xFB
#define ALLLED_OFF_L 0xFC
#define ALLLED_OFF_H 0xFD
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(sda_pin,OUTPUT);
pinMode(scl_pin,OUTPUT);
PCA9685_Init();
}
void loop() {
// put your main code here, to run repeatedly:
for(int angle=0;angle<=180;angle+=30)
{
//void servo_control(servo_id,angle)
servo_control(0,angle);
Serial.printf("servo id=0 angle=%d\n",angle);
delay(1000);
}
}
void IIC_init()
{
SDA_H;
delayMicroseconds(5);
SCL_H;
delayMicroseconds(5);
}
void IIC_start()
{
SDA_H;
delayMicroseconds(5);
SCL_H;
delayMicroseconds(5);
SDA_L;
delayMicroseconds(5);
SCL_L;
delayMicroseconds(5);
}
void IIC_stop()
{
SDA_L;
delayMicroseconds(5);
SCL_H;
delayMicroseconds(5);
SDA_H;
delayMicroseconds(5);
}
bool ACK()
{
u16 i;
SCL_H;
//pinMode(sda_pin,INPUT); //change pin mode to INPUT
delayMicroseconds(5);
if(digitalRead(sda_pin)==LOW) //
{
SCL_L;
//pinMode(sda_pin,OUTPUT); //change pin mode to OUTPUT
delayMicroseconds(5);
return true;
}
else
{
SCL_L;
//pinMode(sda_pin,OUTPUT); //change pin mode to OUTPUT
delayMicroseconds(5);
return false;
}
}
void write_byte(u8 byte_)
{
u8 i;
for(i=0;i<8;i++)
{
if(byte_&0x80)
{
SDA_H;
}
else
{
SDA_L;
}
delayMicroseconds(5);
SCL_H;
byte_<<=1;
delayMicroseconds(5);
SCL_L;
}
}
u8 read_byte()
{
u8 i,j,k;
SCL_L;
delayMicroseconds(5);
SDA_H;
delayMicroseconds(5);
//pinMode(sda_pin,INPUT); //change pin mode to INPUT
for(i=0;i<8;i++)
{
delayMicroseconds(5);
SCL_H;
delayMicroseconds(5);
if(digitalRead(sda_pin)==HIGH) //
{
j=1;
}
else j=0;
k=(k<< 1)|j;
SCL_L;
}
//pinMode(sda_pin,OUTPUT); //change pin mode to OUTPUT
delayMicroseconds(5);
return k;
}
void PCA9685_write(u8 address,u8 date)
{
IIC_start();
write_byte(PCA9685_adrr);
ACK();
write_byte(address);
ACK();
write_byte(date);
ACK();
IIC_stop();
}
u8 PCA9685_read(u8 address)
{
u8 data;
IIC_start();
write_byte(PCA9685_adrr);
ACK();
write_byte(address);
ACK();
IIC_start();
write_byte(PCA9685_adrr|0x01);
ACK();
data=read_byte();
IIC_stop();
return data;
}
void PCA9685_reset(void)
{
PCA9685_write(PCA9685_MODE1,0x0);
}
void setPWMFreq(float freq)
{
u16 prescale,oldmode,newmode;
float prescaleval;
freq *= 0.92; // Correct for overshoot in the frequency setting
prescaleval = 25000000;
prescaleval /= 4096;
prescaleval /= freq;
prescaleval -= 1;
prescale = floor(prescaleval + 0.5);
oldmode = PCA9685_read(PCA9685_MODE1);
newmode = (oldmode&0x7F) | 0x10; // sleep
PCA9685_write(PCA9685_MODE1, newmode); // go to sleep
PCA9685_write(PCA9685_PRESCALE, prescale); // set the prescaler
PCA9685_write(PCA9685_MODE1, oldmode);
delay(2);
PCA9685_write(PCA9685_MODE1, oldmode | 0xa1);
}
void servo_control(u8 servo_id, u16 angle)
{
u16 off = 102.4+2.275555556*angle;
PCA9685_write(LED0_ON_L+4*servo_id,0);
PCA9685_write(LED0_ON_H+4*servo_id,0);
PCA9685_write(LED0_OFF_L+4*servo_id,off);
PCA9685_write(LED0_OFF_H+4*servo_id,off>>8);
}
void PCA9685_Init()
{
IIC_init();
PCA9685_reset();
setPWMFreq(50);
}
版权声明:本文为CSDN博主「feng锋~」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_49597570/article/details/122642029
ESP8266与PCA9685通信I2C
Talk is cheap, show you code!
/**
* ESP8266与PCA9685通过I2C协议通信
* 功能:控制PCA9685上的16个舵机旋转0-180°,串口打印舵机id和角度
* 说明:本代码没有使用ESP8266自带的I2C,而是pin模拟输出
* 接线:
* SDA -> GPIO4(D2)
* SCL -> GPIO5(D1)
* 作者:锋 2022/1/22/18:43
*/
typedef unsigned char u8;
typedef unsigned short u16;
#define sda_pin 4//GPIO4->D2
#define scl_pin 5//GPIO5->D1
#define SDA_H digitalWrite(sda_pin,HIGH)
#define SDA_L digitalWrite(sda_pin,LOW)
#define SCL_H digitalWrite(scl_pin,HIGH)
#define SCL_L digitalWrite(scl_pin,LOW)
#define PCA9685_adrr 0x80// 1+A5+A4+A3+A2+A1+A0+w/r
#define PCA9685_SUBADR1 0x2
#define PCA9685_SUBADR2 0x3
#define PCA9685_SUBADR3 0x4
#define PCA9685_MODE1 0x00
#define PCA9685_PRESCALE 0xFE
#define LED0_ON_L 0x06
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09
#define ALLLED_ON_L 0xFA
#define ALLLED_ON_H 0xFB
#define ALLLED_OFF_L 0xFC
#define ALLLED_OFF_H 0xFD
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(sda_pin,OUTPUT);
pinMode(scl_pin,OUTPUT);
PCA9685_Init();
}
void loop() {
// put your main code here, to run repeatedly:
for(int angle=0;angle<=180;angle+=30)
{
//void servo_control(servo_id,angle)
servo_control(0,angle);
Serial.printf("servo id=0 angle=%d\n",angle);
delay(1000);
}
}
void IIC_init()
{
SDA_H;
delayMicroseconds(5);
SCL_H;
delayMicroseconds(5);
}
void IIC_start()
{
SDA_H;
delayMicroseconds(5);
SCL_H;
delayMicroseconds(5);
SDA_L;
delayMicroseconds(5);
SCL_L;
delayMicroseconds(5);
}
void IIC_stop()
{
SDA_L;
delayMicroseconds(5);
SCL_H;
delayMicroseconds(5);
SDA_H;
delayMicroseconds(5);
}
bool ACK()
{
u16 i;
SCL_H;
//pinMode(sda_pin,INPUT); //change pin mode to INPUT
delayMicroseconds(5);
if(digitalRead(sda_pin)==LOW) //
{
SCL_L;
//pinMode(sda_pin,OUTPUT); //change pin mode to OUTPUT
delayMicroseconds(5);
return true;
}
else
{
SCL_L;
//pinMode(sda_pin,OUTPUT); //change pin mode to OUTPUT
delayMicroseconds(5);
return false;
}
}
void write_byte(u8 byte_)
{
u8 i;
for(i=0;i<8;i++)
{
if(byte_&0x80)
{
SDA_H;
}
else
{
SDA_L;
}
delayMicroseconds(5);
SCL_H;
byte_<<=1;
delayMicroseconds(5);
SCL_L;
}
}
u8 read_byte()
{
u8 i,j,k;
SCL_L;
delayMicroseconds(5);
SDA_H;
delayMicroseconds(5);
//pinMode(sda_pin,INPUT); //change pin mode to INPUT
for(i=0;i<8;i++)
{
delayMicroseconds(5);
SCL_H;
delayMicroseconds(5);
if(digitalRead(sda_pin)==HIGH) //
{
j=1;
}
else j=0;
k=(k<< 1)|j;
SCL_L;
}
//pinMode(sda_pin,OUTPUT); //change pin mode to OUTPUT
delayMicroseconds(5);
return k;
}
void PCA9685_write(u8 address,u8 date)
{
IIC_start();
write_byte(PCA9685_adrr);
ACK();
write_byte(address);
ACK();
write_byte(date);
ACK();
IIC_stop();
}
u8 PCA9685_read(u8 address)
{
u8 data;
IIC_start();
write_byte(PCA9685_adrr);
ACK();
write_byte(address);
ACK();
IIC_start();
write_byte(PCA9685_adrr|0x01);
ACK();
data=read_byte();
IIC_stop();
return data;
}
void PCA9685_reset(void)
{
PCA9685_write(PCA9685_MODE1,0x0);
}
void setPWMFreq(float freq)
{
u16 prescale,oldmode,newmode;
float prescaleval;
freq *= 0.92; // Correct for overshoot in the frequency setting
prescaleval = 25000000;
prescaleval /= 4096;
prescaleval /= freq;
prescaleval -= 1;
prescale = floor(prescaleval + 0.5);
oldmode = PCA9685_read(PCA9685_MODE1);
newmode = (oldmode&0x7F) | 0x10; // sleep
PCA9685_write(PCA9685_MODE1, newmode); // go to sleep
PCA9685_write(PCA9685_PRESCALE, prescale); // set the prescaler
PCA9685_write(PCA9685_MODE1, oldmode);
delay(2);
PCA9685_write(PCA9685_MODE1, oldmode | 0xa1);
}
void servo_control(u8 servo_id, u16 angle)
{
u16 off = 102.4+2.275555556*angle;
PCA9685_write(LED0_ON_L+4*servo_id,0);
PCA9685_write(LED0_ON_H+4*servo_id,0);
PCA9685_write(LED0_OFF_L+4*servo_id,off);
PCA9685_write(LED0_OFF_H+4*servo_id,off>>8);
}
void PCA9685_Init()
{
IIC_init();
PCA9685_reset();
setPWMFreq(50);
}
版权声明:本文为CSDN博主「feng锋~」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_49597570/article/details/122642029
暂无评论