// Площадка для пользовательских микросхем
// Дополнительную информацию можно найти здесь: https://link.wokwi.com/custom-chips-alpha

// ======================= Скопированные Определения ====================
// Был скопирован код управления сервоприводами от Adafruit вместо импорта библиотеки — библиотека будет добавлена позже
// Это объясняет используемые ниже определения и др. детали...

#include <Wire.h>


// АДРЕСА РЕГИСТРОВ
#define PCA9685_MODE1 0x00      /**< Регистр Режима 1 */
#define PCA9685_PRESCALE 0xFE   /**< Делитель для частоты ШИМ-сигнала */

// Биты режима MODE1
#define MODE1_ALLCAL 0x01      /**< Реагировать на I2C-адрес "All Call" */
#define MODE1_SUB3 0x02        /**< Реагировать на I2C-подадрес 3 */
#define MODE1_SUB2 0x04        /**< Реагировать на I2C-подадрес 2 */
#define MODE1_SUB1 0x08        /**< Реагировать на I2C-подадрес 1 */
#define MODE1_SLEEP 0x10       /**< Режим низкого энергопотребления. Отключить осциллятор */
#define MODE1_AI 0x20          /**< Автоинкремент включен */
#define MODE1_EXTCLK 0x40      /**< Использовать внешний тактовый сигнал на пине EXTCLK */
#define MODE1_RESTART 0x80     /**< Перезапуск включен */

#define FREQUENCY_OSCILLATOR 25000000 /**< Частота внутреннего генератора согласно даташиту */

#define PCA9685_PRESCALE_MIN 3   /**< Минимальное значение делителя */
#define PCA9685_PRESCALE_MAX 255 /**< Максимальное значение делителя */

// ======================= Конец Скопированных Определений ====================

// Адрес микросхемы. Должен соответствовать подключению в diagram.json
const uint8_t _i2caddr = 0x5F;

// Функция для начальной настройки микросхемы PCA9685
static void begin(uint8_t prescale = 0);

// Функции для сброса и перезапуска микросхемы PCA9685
static void reset();
static void restart();

// Функция для установки частоты ШИМ
static void setPWMFreq(float f);

// Функция настройки микросхемы и инициализации соединения I2C
void setup() {
  Serial.begin(115200);
  Wire.begin();

  // Инициализация микросхемы PCA9685
  begin();
}
 

// Основной цикл программы
void loop() {
  sedServoAngel(_i2card,  0, 180);
  delay(1000);
  sedServoAngel(_i2card, 0, 0);
  delay(1000);
  reset ();
  restart();
  delay(1000);

  // Сброс микросхемы PCA9685
  reset();

  delay(1000);

  // Установка другого ШИМ для светодиода
  setPWM(_i2caddr, 0, 1000, 3000);
  delay(1000);

  // Перезапуск микросхемы PCA9685
  restart();

}

// Функция начальной настройки микросхемы PCA9685
void begin(uint8_t prescale = 0) {
  restart();
  // Установка значения частоты ШИМ по умолчанию
  setPWMFreq(1);
}

/*!
    @brief  Отправка команды сброса микросхеме PCA9685 по I2C
*/
void restart() {
  write8(PCA9685_MODE1, MODE1_RESTART);
  delay(10);
}

// Функция для установки частоты ШИМ
void setPWMFreq(float freq) {
  // Диапазон модуляции выходной частоты зависит от внутреннего генератора
  if (freq < 1)
    freq = 1;
  if (freq > 3500)
    freq = 3500; // Ограничение из даташита: 3052=50 МГц/(4*4096)

  // Рассчитываем значение делителя для заданной частоты
  float prescaleval = ((FREQUENCY_OSCILLATOR / (freq * 4096.0)) + 0.5) - 1;
  if (prescaleval < PCA9685_PRESCALE_MIN)
    prescaleval = PCA9685_PRESCALE_MIN;
  if (prescaleval > PCA9685_PRESCALE_MAX)
    prescaleval = PCA9685_PRESCALE_MAX;
  uint8_t prescale = (uint8_t)prescaleval;

  Serial.print("Итоговое значение делителя: ");
  Serial.println(prescale);

  // Считываем текущий режим
  uint8_t oldmode = read8(PCA9685_MODE1);
  // Формируем новый режим с установленным режимом сна и без флага перезапуска
  uint8_t newmode = (oldmode & ~MODE1_RESTART) | MODE1_SLEEP;
  // Устанавливаем новый режим (переходим в режим сна)
  write8(PCA9685_MODE1, newmode);
  // Устанавливаем значение делителя
  write8(PCA9685_PRESCALE, prescale);
  // Возвращаемся к предыдущему режиму
  write8(PCA9685_MODE1, oldmode);
  delay(5);
  // Устанавливаем режим с автоинкрементом
  write8(PCA9685_MODE1, oldmode | MODE1_RESTART | MODE1_AI);

  Serial.print("Текущий режим: 0x");
  Serial.println(read8(PCA9685_MODE1), HEX);
}

// Функция для установки ШИМ
void setPWM(int addr, int chan,  uint16_t on, uint16_t off ) {

  Serial.print("Установка ШИМ ");
  Serial.print(chan);
  Serial.print(": ");
  Serial.print(on);
  Serial.print("->");
  Serial.println(off);

  // Запускаем передачу данных по I2C на указанный адрес
  Wire.beginTransmission(addr);
  // Записываем адрес регистра для текущего канала
  Wire.write(6 + 4 * chan);
  // Записываем значение включения (низкие байты)
  Wire.write(on);
  // Записываем значение включения (высокие байты)
  Wire.write(on >> 8);
  // Записываем значение выключения (низкие байты)
  Wire.write(off);
  // Записываем значение выключения (высокие байты)
  Wire.write(off >> 8);
  // Завершаем передачу данных
  Wire.endTransmission();
}
void sedServoAngel(int addr, int channel, int angle){

  int pwn_val = map(angle , 0, 100, 102, 512) 
  sedPWM(addr, channel , 0 , set_val);
}

// Функция для чтения 8-битного значения по указанному адресу
uint8_t read8(uint8_t addr) {
  Wire.beginTransmission(_i2caddr);
  Wire.write(addr);
  Wire.endTransmission();

  Wire.requestFrom((uint8_t)_i2caddr, (uint8_t)1);
  return Wire.read();
}

// Функция для записи 8-битного значения по указанному адресу
void write8(uint8_t addr, uint8_t d) {
  Wire.beginTransmission(_i2caddr);
  Wire.write(addr);
  Wire.write(d);
  Wire.endTransmission();
}

// Функция для сброса микросхемы
void reset() {
  Wire.beginTransmission(0);
  Wire.write(6);
  Wire.endTransmission();
}
pca9685Breakout
D0D1D2D3D4D5D6D7GNDLOGIC