#include "driver/timer.h"
#include <soc/gpio_struct.h>
uint64_t prev = 0;
uint64_t pheriod = 0;
uint64_t count = 0;
uint64_t microscount = 0;
uint32_t PWM01 = 0, PWM02 = 0, PWM03 = 0, PWM04 = 0, PWM05 = 0, PWM06 = 0,
PWM07 = 0, PWM08 = 0, PWM09 = 0, PWM10 = 0, PWM11 = 0, PWM12 = 0,
PWM13 = 0, PWM14 = 0, PWM15 = 0, PWM16 = 0, PWM17 = 0, PWM18 = 0;
static void IRAM_ATTR timer0_ISR (void *arg) {
// очистка флагов прерываний
timer_group_clr_intr_status_in_isr (TIMER_GROUP_0, TIMER_0);
// перезапуск прерывания Alarm
timer_group_enable_alarm_in_isr (TIMER_GROUP_0, TIMER_0);
pheriod = millis() - prev;
prev = millis();
count = 0;
microscount = micros();
/*
NANO
GPIO48 PWM09 PWM18 GPIO21
GPIO1 PWM08 PWM17 GPIO18
GPIO2 PWM07 PWM16 GPIO17
GPIO3 PWM06 PWM15 GPIO10
GPIO4 PWM05 PWM14 GPIO9
GPIO11 PWM04 PWM13 GPIO8
GPIO12 PWM03 PWM12 GPIO7
GPIO13 PWM02 PWM11 GPIO6
GPIO14 PWM01 PWM10 GPIO5
*/
// поднимаем порты - начало импульса ШИМ
gpio_set_level(GPIO_NUM_14, HIGH);
gpio_set_level(GPIO_NUM_13, HIGH);
gpio_set_level(GPIO_NUM_12, HIGH);
gpio_set_level(GPIO_NUM_11, HIGH);
gpio_set_level(GPIO_NUM_4 , HIGH);
gpio_set_level(GPIO_NUM_3 , HIGH);
gpio_set_level(GPIO_NUM_2 , HIGH);
gpio_set_level(GPIO_NUM_1 , HIGH);
gpio_set_level(GPIO_NUM_48, HIGH);
gpio_set_level(GPIO_NUM_5 , HIGH);
gpio_set_level(GPIO_NUM_6 , HIGH);
gpio_set_level(GPIO_NUM_7 , HIGH);
gpio_set_level(GPIO_NUM_8 , HIGH);
gpio_set_level(GPIO_NUM_9 , HIGH);
gpio_set_level(GPIO_NUM_10, HIGH);
gpio_set_level(GPIO_NUM_17, HIGH);
gpio_set_level(GPIO_NUM_18, HIGH);
gpio_set_level(GPIO_NUM_21, HIGH);
bool wait01 = true, wait02 = true, wait03 = true, wait04 = true, wait05 = true, wait06 = true,
wait07 = true, wait08 = true, wait09 = true, wait10 = true, wait11 = true, wait12 = true,
wait13 = true, wait14 = true, wait15 = true, wait16 = true, wait17 = true, wait18 = true;
uint64_t value = 0;
while (value < 120000) {
count++;
// получение текущего значения таймера uint64_t value
timer_get_counter_value (TIMER_GROUP_0, TIMER_0, &value);
if (wait01) if (value > PWM01) { gpio_set_level(GPIO_NUM_14, LOW); wait01 = false; }
if (wait02) if (value > PWM02) { gpio_set_level(GPIO_NUM_13, LOW); wait02 = false; }
if (wait03) if (value > PWM03) { gpio_set_level(GPIO_NUM_12, LOW); wait03 = false; }
if (wait04) if (value > PWM04) { gpio_set_level(GPIO_NUM_11, LOW); wait04 = false; }
if (wait05) if (value > PWM05) { gpio_set_level(GPIO_NUM_4 , LOW); wait05 = false; }
if (wait06) if (value > PWM06) { gpio_set_level(GPIO_NUM_3 , LOW); wait06 = false; }
if (wait07) if (value > PWM07) { gpio_set_level(GPIO_NUM_2 , LOW); wait07 = false; }
if (wait08) if (value > PWM08) { gpio_set_level(GPIO_NUM_1 , LOW); wait08 = false; }
if (wait09) if (value > PWM09) { gpio_set_level(GPIO_NUM_48, LOW); wait09 = false; }
if (wait10) if (value > PWM10) { gpio_set_level(GPIO_NUM_5 , LOW); wait10 = false; }
if (wait11) if (value > PWM11) { gpio_set_level(GPIO_NUM_6 , LOW); wait11 = false; }
if (wait12) if (value > PWM12) { gpio_set_level(GPIO_NUM_7 , LOW); wait12 = false; }
if (wait13) if (value > PWM13) { gpio_set_level(GPIO_NUM_8 , LOW); wait13 = false; }
if (wait14) if (value > PWM14) { gpio_set_level(GPIO_NUM_9 , LOW); wait14 = false; }
if (wait15) if (value > PWM15) { gpio_set_level(GPIO_NUM_10, LOW); wait15 = false; }
if (wait16) if (value > PWM16) { gpio_set_level(GPIO_NUM_17, LOW); wait16 = false; }
if (wait17) if (value > PWM17) { gpio_set_level(GPIO_NUM_18, LOW); wait17 = false; }
if (wait18) if (value > PWM18) { gpio_set_level(GPIO_NUM_21, LOW); wait18 = false; }
}
// на всякий случай опускаем порты - гарантировано конец импульса ШИМ (если передадим импульс длиннее 120000)
gpio_set_level(GPIO_NUM_14, LOW);
gpio_set_level(GPIO_NUM_13, LOW);
gpio_set_level(GPIO_NUM_12, LOW);
gpio_set_level(GPIO_NUM_11, LOW);
gpio_set_level(GPIO_NUM_4 , LOW);
gpio_set_level(GPIO_NUM_3 , LOW);
gpio_set_level(GPIO_NUM_2 , LOW);
gpio_set_level(GPIO_NUM_1 , LOW);
gpio_set_level(GPIO_NUM_48, LOW);
gpio_set_level(GPIO_NUM_5 , LOW);
gpio_set_level(GPIO_NUM_6 , LOW);
gpio_set_level(GPIO_NUM_7 , LOW);
gpio_set_level(GPIO_NUM_8 , LOW);
gpio_set_level(GPIO_NUM_9 , LOW);
gpio_set_level(GPIO_NUM_10, LOW);
gpio_set_level(GPIO_NUM_17, LOW);
gpio_set_level(GPIO_NUM_18, LOW);
gpio_set_level(GPIO_NUM_21, LOW);
microscount = micros() - microscount;
}
void setup () {
pinMode(A7, OUTPUT);
pinMode(A6, OUTPUT);
pinMode(A5, OUTPUT);
pinMode(A4, OUTPUT);
pinMode(A3, OUTPUT);
pinMode(A2, OUTPUT);
pinMode(A1, OUTPUT);
pinMode(A0, OUTPUT);
pinMode(D13, OUTPUT);
pinMode(D2, OUTPUT);
pinMode(D3, OUTPUT);
pinMode(D4, OUTPUT);
pinMode(D5, OUTPUT);
pinMode(D6, OUTPUT);
pinMode(D7, OUTPUT);
pinMode(D8, OUTPUT);
pinMode(D9, OUTPUT);
pinMode(D10, OUTPUT);
// таймер опирается на 80mHz осцилятор!
timer_config_t config = {
.alarm_en = TIMER_ALARM_EN, // включение аларма таймера enum: 0 TIMER_ALARM_DIS | 1 TIMER_ALARM_EN
.counter_en = TIMER_PAUSE, // cостояние после инициализации enum: 0 TIMER_PAUSE | 1 TIMER_START
.intr_type = TIMER_INTR_LEVEL, // прерывание по уровню enum: 0 TIMER_INTR_LEVEL
.counter_dir = TIMER_COUNT_UP, // направление счетчика enum: 0 TIMER_COUNT_DOWN | 1 TIMER_COUNT_UP
.auto_reload = TIMER_AUTORELOAD_EN, // настройка автоматического рестарта прерывания enum: 0 TIMER_AUTORELOAD_DIS | 1 TIMER_AUTORELOAD_EN
.divider = 2 // предделитель uint16_t: 2..65535
};
// инициализация таймера
timer_init(TIMER_GROUP_0, TIMER_0, &config);
uint64_t value = 1;
uint64_t alarm_value = 800000;
// начальное значение счетчика uint64_t value: 0..4294967295
timer_set_counter_value (TIMER_GROUP_0, TIMER_0, value);
// значение, при достижении которого сработает прерывание uint64_t alarm_value: 0..4294967295
timer_set_alarm_value (TIMER_GROUP_0, TIMER_0, alarm_value);
// разрешение прерывания
timer_enable_intr (TIMER_GROUP_0, TIMER_0);
// привязка функции обработки перрывания
timer_isr_register (TIMER_GROUP_0, TIMER_0, timer0_ISR, NULL, 0, NULL);
// запуск таймера
timer_start (TIMER_GROUP_0, TIMER_0);
Serial.begin (9600);
Serial.println ("Hi!");
}
uint32_t val = 20000;
void loop() {
val++;
if (val > 180000) val = 20000;
uint32_t pwm = val > 100000 ? 200000 - val : val;
PWM01 = 60000;
PWM02 = pwm;
PWM03 = pwm;
PWM04 = pwm;
PWM05 = pwm;
PWM06 = pwm;
PWM07 = pwm;
PWM08 = pwm;
PWM09 = pwm;
PWM10 = pwm;
PWM11 = pwm;
PWM12 = pwm;
PWM13 = pwm;
PWM14 = pwm;
PWM15 = pwm;
PWM16 = pwm;
PWM17 = pwm;
PWM18 = pwm;
Serial.println ("pheriod: " + String(pheriod) + ", long: " + String(microscount) + ", iterations: " + String(count) + ", pwm: " + String(pwm) + ", on " + String(getCpuFrequencyMhz()) + "mHz");
}
Пока что только этот код выдает стабильный ШИМ. При цикле 3мс обеспечивает 1100-1300 дискретных состояний. Разумеется, т.к. у сервы импульсы короче 500 мкс ничего не решают, как и импульсы длиннее 2500 мкс, этот диапазон сокращается на треть. Итого метод гарантирует +/- 800 состояний. Такое себе разрешение, конечно. Но в целом, цифровая mg90d норм отрабатывает. Даже на скорости около 10 градусов в секунду рывки мало заметны, основном слышны. А если на ее канал давать фиксированное значение, меняя все остальные - держит стабильно, не джиттерит (не дергается), чего я больше всего боялся.
Но все равно осадок… Ощущение наиговеннейшей реализации