Engineer_Keen писал(а):Можно использовать табличный метод. Записать последовательно каждый шаг ШИМ в память и в цикле выдавать их на порты.
Engineer_Keen писал(а):Тогда можно получить частоту порядка 1-1.5 кГц при 24 каналах 8-битной ШИМ. (Проверено в протеусе)
Минус - величину одного из 24 каналов можно менять только за 1 полный цикл (256 отсчетов ШИМ). Или выполнять его отдельной процедурой, но она будет длится порядка 1000 тактов. Может еще как-то можно изменять, но уже мозг не варит...
Можно тупо сделать кучу сравнений счетчика с регистрами, тогда будет ШИМ с частотой в сотню герц, но можно менять все и сразу и не занимать 728 байт RAM. Большего из программной ШИМ думаю не вытянуть

Давно я себя таким тупым не чувствовал

Потому что я, кажись, ничего не понял, из того что вы сказали (и асм я тоже не очень понимаю).
Я сделал как - я сделал массив из 18-ти счетчиков, в которых хранится длительность импульсов (не в мкс, а в "квантах", один квант - это типо счетчик от нуля до OCR досчитал). И потом в каждом кванте всем счетчикам делал инкремент.
Как только счетчик доходит до нуля - на соответствующую ногу подается ноль.
(плюс каждые 10000 квантов делается проверка, не пришло ли по УСАРТу новое значение, это не важно, суть в том, что заранее неизвестно значение скважности для следующего периода).
Проблема в том, что вот эти счетчики и проверки сделаны вот так:
Код: Выделить всё
#define motor_0 PORTA, 0
#define motor_1 PORTA, 1
#define motor_2 PORTA, 2
#define motor_3 PORTA, 3
(и так далее до 18-ти, но по идее, они могут и не подряд идти)
Код: Выделить всё
#define _off(port, bit) port &= (~(1 << bit))
#define off(p) _off(p)
#define _all_motors_on() PORTA = 0xFF; PORTB = 0xFF; PORTC |= 3
Вот благодаря _all_motors_on они врубаются более-менее одновременно (и только те, которые на одном порту висят). (Хотя я сейчас проверил, и если врубать их тоже неодновременно, то разница поменьше %), мне, по факту, не нужна полная одновременность импульсов, мне нужна одинаковая длительность. Вот вы меня сейчас натолкнули на мысль, как сделать извращение извращения!)
А потом в цикле через каждый "квант" времени делается
Код: Выделить всё
if( Drive_Quants[0] == 0) off(motor_0);
if( Drive_Quants[1] == 0) off(motor_1);
if( Drive_Quants[2] == 0) off(motor_2);
if( Drive_Quants[3] == 0) off(motor_3);
if( Drive_Quants[4] == 0) off(motor_4);
if( Drive_Quants[5] == 0) off(motor_5);
и до 18.
Но если на всех каналах нужно сделать одинаковую длину импульса, то все счетчики превращаются в ноль одновременно и вот эти 18 ифов выполняются друг за другом. В результате, два соседних импульса прекращаются с разницей в ~5-10 микросекунд, а это уже слишком много.
Вот.
Если я правильно понимаю, это нечто наподобии вашего второго предложения, только реализованного через Ж -_-
Вы извините, что я на вас все вот это вываливаю, у меня уже ощущение, что я какого-то жуткого монстра-извращенца написал

UPD: Так вот, вы меня на мысль натолкнули, спасибо

Я переписал стартовые импульсы, чтобы они ТОЖЕ были неодновременными! И погрешность длины импульсов резко снизилась, муахахахахаха!! МУААХАХАХАХАХА!!
Простите, приступ.
Код: Выделить всё
on(motor_0);
PORTF = ~PORTF;
on(motor_1);
PORTF = ~PORTF;
on(motor_2);
PORTF = ~PORTF;
on(motor_3);
PORTF = ~PORTF;
on(motor_4);
PORTF = ~PORTF;
Теперь это почти идеально накладывается на те 18 ифов
(вместо инверсии порта наверное лучше какой-нибудь NOP, но я не знаю, как его в Си сделать
-_-)