follow_me 0 21 января, 2011 Опубликовано 21 января, 2011 · Жалоба В циклах кстати для приращения итератора стоит использовать ++i вместо i++ т.к. i++ выполняется за 3 такта а ++i за 1 итого выходит что только на итераторе 2* n итераций хотя опять же нужно смотреть как такое оптимизирует оптимизатор Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Pasha 0 21 января, 2011 Опубликовано 21 января, 2011 · Жалоба А при -Оs сколько? тоже где-то 317-325 было В циклах кстати для ... Это, как и предпочтения do{}while вместо for() - суетная часть. Где-то работает, где-то компилер умнее. Я вот, недавно бодаясь с МСС18, прогнулся так, что было стыдно. Потом перестал это делать - результат оказался хуже на 2-3 процента. Оно не надо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
defunct 0 23 января, 2011 Опубликовано 23 января, 2011 · Жалоба Концептуально можно ускорить код - если вместо проверки каждого канала в каждом "Loop'e" таймера, организовать всего 14+1 прерываний от таймера за период в 256 тиков. (Где 14 прерываний соответствуют 14-ти каналам PWM, 15-ое - сброс всех каналов в исходное состояние). Итого для 8-ми битной глубины у вас будет не 256 прерываний за период длительностью меньше 300 тактов на обработку каждого, а всего 14+1 с ресурсом 256 * 300 / 15 = 5120 тактов на каждое. Если время срабатывания расчитывать на цикл вперед, то обработчики прерывания будут очень короткими. Программировать время следующего срабатывания каждого из прерываний можно например при сбросе всех каналов в исходное состояние. код сведется к чему-то такому: Timer_CompA_ISR() { turn_off( CurrentChan++ ); if (CurrentChan > MAX_CHAN_COUNT) { CurrentChan = 0; return; } OCRA = ChanGetLifeTime( CurrentChan ); } Timer_OvrISR() { // врубить все turn_on( AllChannels ); // посчитать такт отключения каждого из каналов (время "жизни") UpdateLifeTime( ... ); // отсортировать каналы по времени жизни по-возрастанию SortChannelsByTimeAscending( ... ); } А можно и в основном цикле программы. Обработка частных случаев (кода время жизни нескольких каналов будет совадать) тоже большого труда не составит: Timer_CompA_ISR() { turn_off( CurrentChan++ ); if (CurrentChan > MAX_CHAN_COUNT) { CurrentChan = 0; return; } if (OCRA == ChanGetLifeTime( CurrentChannel ) ) Timer_CompA_ISR(); // запустить сл. канал прямо сейчас (лучше всего rjmp'ом) else OCRA = ChanGetLifeTime( CurrentChan ); // проапдейтить таймер на прерывание в нужное время } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
skyled 0 24 января, 2011 Опубликовано 24 января, 2011 · Жалоба Навскидку разумное зерно есть. Надо бдумать. А не получится ли, что за счет сортировки будет "шило на мыло"? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
pokos 0 24 января, 2011 Опубликовано 24 января, 2011 (изменено) · Жалоба У меня на 3 канала было вот так сделано: // Timer 0 overflow interrupt service routine interrupt [TIM0_OVF] void timer0_ovf_isr(void) { // Reinitialize Timer 0 value TCNT0=256-39+4; //PWM----------------------- pwr_cnt++; if (red_a>pwr_cnt) { PORTD.7=1;} else {PORTD.7=0;}; if (green_a>pwr_cnt) {PORTD.6=1;} else {PORTD.6=0;}; if (blue_a>pwr_cnt) {PORTD.5=1;} else {PORTD.5=0;}; } Оттранслировалось в: _timer0_ovf_isr: RCALL __SAVEISR ; 49 // Reinitialize Timer 0 value ; 50 TCNT0=256-39+4; LDI R30,LOW(221) OUT 0x32,R30 ; 51 //PWM----------------------- ; 52 pwr_cnt++; LDS R30,_pwr_cnt SUBI R30,-LOW(1) STS _pwr_cnt,R30 ; 53 if (red_a>pwr_cnt) {PORTD.7=1;} LDS R26,_red_a CP R30,R26 BRSH _0x2B SBI 0x12,7 ; 54 else {PORTD.7=0;}; RJMP _0x2C _0x2B: CBI 0x12,7 _0x2C: ; 55 if (green_a>pwr_cnt) {PORTD.6=1;} LDS R30,_pwr_cnt LDS R26,_green_a CP R30,R26 BRSH _0x2D SBI 0x12,6 ; 56 else {PORTD.6=0;}; RJMP _0x2E _0x2D: CBI 0x12,6 _0x2E: ; 57 if (blue_a>pwr_cnt) {PORTD.5=1;} LDS R30,_pwr_cnt LDS R26,_blue_a CP R30,R26 BRSH _0x2F SBI 0x12,5 ; 58 else {PORTD.5=0;}; RJMP _0x30 _0x2F: CBI 0x12,5 _0x30: ; 59 } RCALL __LOADISR RETI Изменено 24 января, 2011 пользователем pokos Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
defunct 0 24 января, 2011 Опубликовано 24 января, 2011 · Жалоба А не получится ли, что за счет сортировки будет "шило на мыло"? Должен быть выигрышь однозначно - если это будет сортировка массива из 14-ти указателей на цикл вперед. И сортировать лучше не в прерывании, а в основном цикле программы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
pokos 0 24 января, 2011 Опубликовано 24 января, 2011 · Жалоба Должен быть выигрышь однозначно... Выигрыш будет, если забить на разницу между каналами меньше времени обработки прерывания. Если не забивать, то там ещё тот гемор получается. С соответствующей потерей бытродействия, понятно. Поэтому, я просто уменьшил разрядность ШИМа до 6-ти, когда понадобилось моргать быстрее. На глаз это уменьшение было слабо заметно (в моём случае, понятно). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
skyled 0 25 января, 2011 Опубликовано 25 января, 2011 · Жалоба Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов. for(unsigned char i=0;i<14;i++) { if((a & (1<<i))&(b & (1<<i))) {pwm_ch[i]=255;}//1и1 if((a & (1<<i))&(!(b & (1<<i)))) {pwm_ch[i]=255;}//1и0 if((!(a & (1<<i)))&(b & (1<<i))) {pwm_ch[i]=0;}//0и1 if((!(a & (1<<i)))&(!(b & (1<<i)))) {pwm_ch[i]=0;}//0и0 } Даже если уменьшить разрядность ШИМ втрое... уже и не знаю как и быть. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kolobok0 0 25 января, 2011 Опубликовано 25 января, 2011 · Жалоба ...Оттранслировалось в: _timer0_ovf_isr: RCALL __SAVEISR .... RCALL __LOADISR RETI А теперь в азм листинге проставте тайминги. Только колл-рэт у вас 8 тактов. итого 16 ненужных тактов в плюсе. я не говорю у же о повторе одного и того же действия подряд аж 3 раза :) юзается один порт. результат = обнуление определённых пинов. и если необходимая переменная больше ... то выставляем в единичку. Вам подсказать как три пина одновременно можно обнулить? :) кстати можно не засовывать сразу в порт результат. ну надеюсь "куда копать" показал. думаю можно уложиться в 20-30 тактов. если в ущерб регистров - то и того меньше. короче говоря оптимизировать вагон и маленькую тележку можно ышо. хотите оптимально - пишите на азм-е. оптимизатор может "оптимизнуть" готовые функции из библиотеки - на 5+, а вот логику - тут уж сильно зависит от опыта того кто писал оптимизатор и за сколько вы его купили. чиссо ИМХО: собственно если пишите в одни руки, доводите проекты до коммерческого ума - то юзать выше чем азм не совсем в струю. удачи вам (круглый) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Bill 0 25 января, 2011 Опубликовано 25 января, 2011 · Жалоба У меня на 3 канала было вот так сделано: // Timer 0 overflow interrupt service routine interrupt [TIM0_OVF] void timer0_ovf_isr(void) { // Reinitialize Timer 0 value TCNT0=256-39+4; //PWM----------------------- pwr_cnt++; if (red_a>pwr_cnt) { PORTD.7=1;} else {PORTD.7=0;}; if (green_a>pwr_cnt) {PORTD.6=1;} else {PORTD.6=0;}; if (blue_a>pwr_cnt) {PORTD.5=1;} else {PORTD.5=0;}; } Попробуйте так // Timer 0 overflow interrupt service routine interrupt [TIM0_OVF] void timer0_ovf_isr(void) { char _tmp; // Reinitialize Timer 0 value TCNT0=256-39+4; //PWM----------------------- _tmp = ++pwr_cnt; if (red_a > _tmp) { PORTD.7=1;} else {PORTD.7=0;}; if (green_a > _tmp) {PORTD.6=1;} else {PORTD.6=0;}; if (blue_a > _tmp) {PORTD.5=1;} else {PORTD.5=0;}; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
pokos 0 25 января, 2011 Опубликовано 25 января, 2011 (изменено) · Жалоба А теперь в азм листинге проставте тайминги. Проставлял, было дело. Преехал на IAR по этому поводу. ...Вам подсказать как три пина одновременно можно обнулить? Спасибо, я в курсе. А как одновременно обнулить 14 пинов, не подскажете? Которые в разных портах. И чтобы при этом максимальный коэф. заполнения был ровно 1? Займитесь на досуге этими вопросами, увидите, что моё решение не самое плохое. хотите оптимально - пишите на азм-е. Не хочу писать на Асме, надоело. Оптимально - это когда задача выполнена за требуемое время. Потому и не хочу. Попробуйте так ..._tmp = ++pwr_cnt;... Да, конечно. В конечном варианте pwr_cnt и так в регистре сидит. Тогда присваивание - лишнее, только тормозит. Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов. Само собой. Индексация в массиве - это конь прожорливый. Цикл развернуть в линиию, указатель на массив сделать отдельным. Инкрементировать его. Помнится, IAR такие вещи правильно оптимизировал. Попробуйте. И я не очень понимаю, зачем этот странный наворот со сдвигами. В чём его цель? Изменено 25 января, 2011 пользователем pokos Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
xemul 0 25 января, 2011 Опубликовано 25 января, 2011 · Жалоба Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов. for(unsigned char i=0;i<14;i++) { if((a & (1<<i))&(b & (1<<i))) {pwm_ch[i]=255;}//1и1 if((a & (1<<i))&(!(b & (1<<i)))) {pwm_ch[i]=255;}//1и0 if((!(a & (1<<i)))&(b & (1<<i))) {pwm_ch[i]=0;}//0и1 if((!(a & (1<<i)))&(!(b & (1<<i)))) {pwm_ch[i]=0;}//0и0 } Даже если уменьшить разрядность ШИМ втрое... уже и не знаю как и быть. имхо, у Вас попутаны ! и ~. Эта жуть приводится к for(unsigned char i=0, unsigned int tmp = 1; i<14; i++) { if(a & tmp) pwm_ch[i]=255; //1и1, 1и0 else pwm_ch[i]=0; //0и1, 0и0 tmp <<= 1; } Можете ещё пооптимизировать в сторону unsigned char tmp = 1; и (high) a, (low) a (или как оно там в винавре) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 121 25 января, 2011 Опубликовано 25 января, 2011 · Жалоба Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов.Мама! 1) Вы на каждой итерации делаете сдвиг единицы на i разрядов. Для процессора без аппаратного сдвигателя это очень накладная операция. 2) Вы используете двоичное "И" (&) вместо логического (&&). 3) заметьте, что у вас результат не зависит от значения b uint8_t *ptr = &pwm_ch[13]; for(uint16_t mask = (1<<13); mask; mask >>= 1) { if(a & mask) *ptr-- = 255; else *ptr-- = 0; } P.S. Ой, xemul уже то же самое написал. Возможно, у него код даже лучше. P.P.S. ! и ~ у него не попутаны. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
pokos 0 25 января, 2011 Опубликовано 25 января, 2011 · Жалоба Чото не могу найти в закромах финальные исходники того случая. А было там 12 каналов ШИМ по 6 разрядов. Успевало ещё два фильтра второго порядка плюс херитель постоянной составляющей и АРУ. Но на Цоде Визион это не успевало. Только на ИАР. У ШИМа был принцип, что я изложил в сообщении 26. Сортировку и уменьшение колва прерываний пробовал. При минимальных зазорах мерцает неприятно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Pasha 0 25 января, 2011 Опубликовано 25 января, 2011 · Жалоба хотите оптимально - пишите на азм-е. оптимизатор может "оптимизнуть" готовые функции из библиотеки - на 5+, а вот логику - тут уж сильно зависит от опыта того кто писал оптимизатор и за сколько вы его купили. Поздно! Вот годика 4 назад, когда еще было много проблем с сями, тогда бы это звучало серьезно. Сейчас - увы. Мама! :crying: Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов. Ара щто ти здэляль со мной? Йа плакаль, перед женщин стидно.. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться