Подскажите как правильнее реализовать 4-хканальный программный ШИМ на 400 Гц на AVR наиболее рационально. Дело в том, что контроллеры с 4-мя аппаратными ШИМами слишком круты для моей задачи (и как следствие дороги, имеют кучу лишних ножек, большой корпус и т. п.), либо отсутствуют в местном магазине радиодеталей.
Находил вот эту статью: http://habrahabr.ru/post/152299/
Но там на мой взгляд слишком ресурсоёмкий алгоритм - прерывание каждые 256 тактов. Это ведь не позволит контроллеру нормально ничего делать кроме собственно выдачи ШИМ-сигнала.
Пока есть такая идея: настраиваем таймер на срабатывание через 25 мс. В обработчике выводим логическую единицу на все каналы. Затем надо перенастраивать таймер и каждое его срабатывание выключать очередной канал. Когда все будут выключены, установить срабатывание через 25 мс за вычетом времени ушедшего на ШИМ. И повторять цикл. Меня только вот волнует необходимость каждое срабатывание таймера искать минимальный по времени включенного сигнала канал - не будет ли это слишком затратно.
Вот прототип:
Насколько он хорош?
Раздел: AVR
Находил вот эту статью: http://habrahabr.ru/post/152299/
Но там на мой взгляд слишком ресурсоёмкий алгоритм - прерывание каждые 256 тактов. Это ведь не позволит контроллеру нормально ничего делать кроме собственно выдачи ШИМ-сигнала.
Пока есть такая идея: настраиваем таймер на срабатывание через 25 мс. В обработчике выводим логическую единицу на все каналы. Затем надо перенастраивать таймер и каждое его срабатывание выключать очередной канал. Когда все будут выключены, установить срабатывание через 25 мс за вычетом времени ушедшего на ШИМ. И повторять цикл. Меня только вот волнует необходимость каждое срабатывание таймера искать минимальный по времени включенного сигнала канал - не будет ли это слишком затратно.
Вот прототип:
#include <avr/io.h>
#include "pwm.h"
#define PWM_PORT PORTB
#define PWM_DDR DDRB
#define PWM_BASE_PIN 1
unsigned char pwm[4];
signed char cur_pwm = -1, prev_pwm;
void init_pwm() {
PWM_DDR |= (1 << PWM_BASE_PIN) | (2 << PWM_BASE_PIN) | (4 << PWM_BASE_PIN) | (8 << PWM_BASE_PIN);
//Установить таймер на срабатывание через 25 мс
}
void pwm_timer() {
unsigned char i, min = 255, min_i;
prev_pwm = cur_pwm;
if (cur_pwm == -1) {
PWM_PORT |= (1 << PWM_BASE_PIN) | (2 << PWM_BASE_PIN) | (4 << PWM_BASE_PIN) | (8 << PWM_BASE_PIN);
for (i = 0; i < 4; i++) {
if (pwm[i] < min) {
min_i = i;
min = pwm[i];
}
}
cur_pwm = min_i;
} else {
min_i = -1;
for (i = 0; i < 4; i++) {
if ((pwm[i] < min) && (pwm[i] > pwm[cur_pwm])) {
min_i = i;
min = pwm[i];
} else if (pwm[i] <= pwm[cur_pwm]) {
PWM_PORT &= ~(1 << (PWM_BASE_PIN + i));
}
}
cur_pwm = min_i;
}
if (cur_pwm == -1) {
//Установить таймер на срабатывание через 25 мс - pwm[prev_pwm] тактов
} else {
//Установить таймер на срабатывание через pwm[cur_pwm] - pwm[prev_pwm] тактов
}
}
Насколько он хорош?
Раздел: AVR