ESP8266与PCA9685通信I2C

文章目录[隐藏]

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

生成海报
点赞 0

feng锋~

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

基于STM32F103的智能门锁系统

基于STM32F103的智能门锁系统 直接说明实现了什么效果 1 指纹解锁(基于AS608) 2 RFID解锁(基于RC522) 3 密码解锁 (基于LCD电容屏触摸控制) 4 蓝牙解锁

ESP8266与PCA9685通信I2C

ESP8266与PCA9685通信I2C Talk is cheap, show you code! /*** ESP8266与PCA9685通过I2C协议通信* 功能:控制PCA9685上的16个舵机旋转0-18