// Площадка для пользовательских микросхем
// Дополнительную информацию можно найти здесь: 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();
}