Pull to refresh

Comments 26

Омг, какой говнокод. И лучше делать так.

mask = OUT1|OUT2|OUT3;
if(...) mask &= ~OUT1;
if(...) mask &= ~OUT2;
if(...) mask &= ~OUT3;

PORTx &= ~(OUT1|OUT2|OUT3);
PORTx |= mask;
Спасибо за конструктивную критику.
Хотелось бы не повторять своих ошибок в дальнейшем.
Как исправить, чтобы не был «говнокод»? Может, есть ссылки в загашнике, что почитать?
Говнокод везде — и в asm и в C?
Допустим, для одного из каналов выставлена длительность 192. На нулевом (по счету) переполнении таймера порт выставляется в единицу, на 192-м — в ноль.
А теперь представим, что на 128-ом интервале мы меняем значение длительности ШИМ со 192 на 64. Что произойдет? Условие установки порта в ноль не выполнится на данном периоде, и будет импульс высокого уровня длительностью 256+64.
Если «удачно» угадать с моментами изменения длительности, можно растянуть этот импульс на несколько периодов насколько угодно.

Как с этим бороться:
1) Самое простое — вместо «counter==buf_lev_ch1» писать «counter>=buf_lev_ch1»
2) Самое правильное — буферизовать значение длительности ШИМ. То есть на каждый канал использовать две переменные: первую юзер меняет, когда ему вздумается, вторая используется в обработчике прерывания, и ей значение присваивается один раз в начале каждого периода.
2) Самое правильное — буферизовать значение длительности ШИМ. То есть на каждый канал использовать две переменные: первую юзер меняет, когда ему вздумается, вторая используется в обработчике прерывания, и ей значение присваивается один раз в начале каждого периода.

но ведь именно так и сделано. при if (++counter==0) присваюваются значения буферным переменным.
Тогда примите мои извинения, не заметил.
так слишком много прерываний — лучше не так делать — отмерять время интервалами 128 64 32 16 8 4 2 1 тик таймера.при переходе через 0 включаем те каналы, у которых есть старший бит в значении яркости, таймер тикает до 128- оставляем только те, у которых установлен 7 бит, устанавливаем прерывание по сравнению на 192 и так далее — получается не шим, но для светодиодов более чем достаточно и даже лучше, чем шим — всего 8 прерываний таймера, никаких почти вычислительных затрат, несущая частота в таком случае будет выше, чем у шима — светодиоды будут меньше мерцать. у bsvi подробней статья на этот счет была
Спасибо за информацию. Интересная идея.
Делал RGB «лампу настроения» (mood-lamp) с подобным алгоритмом, только на PIC16.
Если не требуется, чтобы все ШИМ были синхронны, можно сделать проще.
Создаём для каждого ШИМ типовую структуру (период, вывод схемы и текущий счётчик).
Например, если нужно 9 ШИМ — берём массив из 9 структур.
Запускаем тактовый таймер со счётчиком и прерываниями.
По прерыванию таймера — берём значение счётчика по модулю количества ШИМов. Используя это значение как индекс массива, обрабатываем структуру (ну, как обычно — меняем счётчик, сравниваем с периодом, если нужно дёргаем вывод).

В отличие от вашего кода — тут чтобы добавить ШИМ нужно всего лишь его описать (назначить период и вывод; увеличить общее число ШИМов). Т.е. никакой хардкодной зависимости. Плюс — скорость обработки не зависит от количества ШИМ (покуда в каждое прерывание обрабатываем ровно один). Плюс — ВСЯ обработка находится в прерывании (т.е. в основной программе «вечный цикл» уже не нужен. Можно уйти в спячку).

Чуть сложнее будет с частотой (очевидно — добавили к трём ШИМ четвёртый — и теперь каждому достаётся не каждое третье прерывание, а каждое четвёртое). Но это тоже обходится, при необходимости.
Ну не знаю, как на счет проще. Мне кажется сомнительной такая выгода.
Похоже, вы не совсем поняли что происходит в программе.
Обработка и так вся в прерывании. Можно смело идти в спячку. Бесконечный цикл лишь для демонстрации работы, в нём постепенно увеличивается коэффициет заполнения ШИМ по всем каналам. Если подключить к выходам светодиоды, то их яркость будет плавно увеличиваться, и гаснуть достигнув максимума. Начальные значения яркости даны со сдвигом, по-этому светодиоды будут разгораться и гаснуть по очереди.
В вашем случае: есть три ШИМ. Нужно добавить четвёртый.
Что будете делать? Добавлять по несколько строчек обработки в каждое зависимое место программы, перекомпилировать и перезаливать прошивку?

Ещё потенциальная проблема (может быть не актуальна на AVR, но в общем достаточно часта) — код с кучей условий (ветвлений) практически невозможно предсказать и правильно закэшировать. Линейная обработка может оказаться гораздо быстрее.

В моем конкретном коде — дa, добавить пару строк, ввести дополнительно две переменные, изменить строку с заданием маски выходов. Про применение массивов я упомянул, при большем числе каналов — есть смысл, и будет меньше манипуляций при добавлении каналов.
Перекомпилировать и перезалить прошивку. (а без этого никак, в любом случае).

Согласен.
Но если мы говорим о AVR, а тем более о Tiny, то тут, по большому счёту, даже использование высокоуровнего C — перебор. Для примера, если скомпилировать приведенный код, то C-прошивка займет 266 байт, а ассемблерная только 118. А на борту всего лишь 1 килобайт флеша.
> Перекомпилировать и перезалить прошивку. (а без этого никак, в любом случае)

не-не, если описание ШИМов в массиве — ничего перекомпилировать не придётся!
Дописываем в RAM новую структуру (в простейшем случае однобайтных счётчиков — 3 байта). И меняем байт, где хранится общее число структур. И всё! Никаких прошивок!
Идея понятна. Как-нибудь, на досуге, надо будет попробовать реализовать. Интересно, как оно будет по ресурсам.
а вообще — на самом деле проще купить микросхему — драйвер светодиодный и не париться — загружаешь в него по i2c или spi значения, а он уже свои шимы включает — можно по разному выходы настроить — тяни толкай, открытый коллектор и т.п., драйвер простенький протаскивает спокойно 500мА тока через одну ногу, разрядность 12бит, количество ног -16, а если это всё по i2c, то на одну шину вешается скока угодно таких микросхем и от контроллера хавается только 2 ноги и i2c, таймеры при этом свободны и процессор не занимается обработкой прерываний.Практического смысла особо нет реализовывать такое на контроллере напрямую, только ради обучения если
Может подскажешь несколько конкретных ходовых моделей?
PCA9685 — в халявных семлпах NXP например, в Российских магазинах вроде нет. Можно загуглить — шим драйвер светодиодов называется, ну и количество каналов еще указываешь, если мощные светодиоды — вешаешь еще сборки дарлингтона транзисторные дополнительно
Да, перед вопросом погуглил, единственное, что нашел, доступнoe — TLC5940 и PCA9635, и то только на ebay.
про 500мА я тут погорячился — просто давно делал свою платку с драйверами для 10 rgb светодиодов — 500мА это со сборками дарлингтона получилось — без них до 100мА протаскивают
А можно сделать чтобы ШИМ был не 8-ми битным а к примеру 7 битным? Тогда полагаю можно выиграть в частоте ШИМ.
Собственно это мне сейчас и нужно.
Можно. Почему бы и нет?
Нужно поменять настройки таймера чтобы прерывание генерилось при значении 128, использовать прерывание по совпадению, и, соответственно, подкорректировать значения в обработчике прерывания. Корректировать значения длительности два раза за оборот таймера if (++counter==0 || ++counter==128)
как-то так.
Sign up to leave a comment.

Articles