Делаю игрушку ребенку собственно апппаратная часть уже готова, осталось код... Суть устройства - РЖБ диод и 4 кнопки одна кнопка переключать "ручной" или "авто" режим работы 3 кнопки в "ручном" режиме включают соответствующие цвета в "авто" выполняют программы Всего в плане было запихнуть 16 вариантов работы, но влезло только 10... в качестве "мозга" тини 13, с 1кб памяти //Просьба не предлагать перейти на другой МК, знаю, что можно 25/45 или даже 85ю купить и не парится! но 13я уже есть, а за другими надо ехать... да и плата уже спаяна и корпус уже собран . --------- есть код, который у меня уже 1008 байт скушал но мне бы еще байт 250-300 выжать бы... Помогите, что в нем можно сократить без потери функциональности Код (C++): #include <avr/io.h> #include <stdlib.h> #include <avr/interrupt.h> #include <util/delay.h> #define LED1_OFF PORTB &= ~_BV(PB0) #define LED2_OFF PORTB &= ~_BV(PB1) #define LED3_OFF PORTB &= ~_BV(PB2) #define LED1_ON PORTB |= _BV(PB0) #define LED2_ON PORTB |= _BV(PB1) #define LED3_ON PORTB |= _BV(PB2) #define ANL_IN _BV(PB3) #define DIG_IN _BV(PB4) uint8_t counter=0, j=0, ci=0; uint8_t lev_ch[]={0,0,0}; uint8_t ch[3]; uint8_t mods = 0; // выбор режима uint8_t vol = 0; uint8_t levels[] = {0, 1, 3, 5, 7, 10, 13, 17, 21, 26, 32, 40, 48, 58, 68, 80, 92, 106, 120, 140, 164, 192, 224, 255}; //коррекция уровней видимой яркости ISR(TIM0_OVF_vect){ /*программный ШИМ*/ counter>=lev_ch[0]?LED1_OFF:LED1_ON; counter>=lev_ch[1]?LED2_OFF:LED2_ON; counter>=lev_ch[2]?LED3_OFF:LED3_ON; counter++; } ISR(ADC_vect){ //ЦАП для определения какая кнопка нажата (кнопки на резисторном делителе) vol = ADCH; if ( vol <= 95 ) mods=1; if (vol > 95 && vol <= 105 ) mods=2; if (vol > 105 && vol <= 120 ) mods=3; if (vol > 120 && vol <= 135 ) mods=4; if (vol > 135 && vol <= 155 ) mods=5; if (vol > 155 && vol <= 180 ) mods=6; if (vol > 180 && vol <= 225 ) mods=7; if (vol > 225 && vol <= 255 ) mods=8; } int main(void) { DDRB=0b00000111; // установка PortB пины 0 1 2 выходы PORTB |= DIG_IN; // Включаем подтягивающий (Pull-UP) резистор для пина TCCR0B = _BV(CS00); // таймер работает без предделителя TIMSK0 = _BV(TOIE0); // прерывания по переполнению таймера разрешены // Настройка АЦП: ADMUX = 0b00100011; ADCSRA = 0b11101111; ADCSRB = 0b00000000; DIDR0 |= ANL_IN; sei(); /*******************************************************************************************************/ while (1) //бесконечная шарманка { if( !(PINB & DIG_IN) ) { mods = mods+10; } /****************************************/ // Ручные режимы // синий зелены красный if (mods==1) { lev_ch[0]=60; lev_ch[1]=60; lev_ch[2]=60; } //белый 30% if (mods==2) { lev_ch[0]=0; lev_ch[1]=0; lev_ch[2]=255; } //красный if (mods==3) { lev_ch[0]=0; lev_ch[1]=255; lev_ch[2]=0; } //зеленый if (mods==4) { lev_ch[0]=0; lev_ch[1]=255; lev_ch[2]=255; } //желтый if (mods==5) { lev_ch[0]=255; lev_ch[1]=0; lev_ch[2]=0; } //синий if (mods==6) { lev_ch[0]=255; lev_ch[1]=0; lev_ch[2]=255; } //сиреневый if (mods==7) { lev_ch[0]=255; lev_ch[1]=255; lev_ch[2]=0; } //бирюзовый if (mods==8) { lev_ch[0]=255; lev_ch[1]=255; lev_ch[2]=255; } //белый // Авторежимы if (mods==11) { //переливы цветов с полными переходами if( ci==0) { lev_ch[0]=levels[j]; lev_ch[1]=0; lev_ch[2]=levels[23]; } if( ci==1) { lev_ch[0]=levels[23]; lev_ch[1]=0; lev_ch[2]=levels[23-j]; } if( ci==2) { lev_ch[0]=levels[23]; lev_ch[1]=levels[j]; lev_ch[2]=0; } if( ci==3) { lev_ch[0]=levels[23-j]; lev_ch[1]=levels[23]; lev_ch[2]=0; } if( ci==4) { lev_ch[0]=0; lev_ch[1]=levels[23]; lev_ch[2]=levels[j]; } if( ci==5) { lev_ch[0]=0; lev_ch[1]=levels[23-j]; lev_ch[2]=levels[23]; } if (++j>23) {j=0; ci++; if(ci==6) ci=0;} _delay_ms (250); } if (mods==12) { // радуга lev_ch[0]=0; lev_ch[1]=0; lev_ch[2]=0; _delay_ms (500); //- lev_ch[0]=0; lev_ch[1]=0; lev_ch[2]=255; _delay_ms (2500); //К lev_ch[0]=0; lev_ch[1]=64; lev_ch[2]=255; _delay_ms (2500); //О lev_ch[0]=0; lev_ch[1]=127; lev_ch[2]=255; _delay_ms (2500); //Ж lev_ch[0]=0; lev_ch[1]=255; lev_ch[2]=0; _delay_ms (2500); //З lev_ch[0]=127; lev_ch[1]=32; lev_ch[2]=32; _delay_ms (2500); //Г lev_ch[0]=255; lev_ch[1]=0; lev_ch[2]=0; _delay_ms (2500); //С lev_ch[0]=255; lev_ch[1]=0; lev_ch[2]=127; _delay_ms (2500); //Ф lev_ch[0]=0; lev_ch[1]=0; lev_ch[2]=0; _delay_ms (500); //- } if (mods==13) { // а на это мне уже не хватило памяти :( } if (mods==14) { // } if (mods==15) { // } if (mods==16) { // } if (mods==17) { // } if (mods==18) { // } } }
1. резисторы в кнопочном ЦАПе подобрать так, чтоб их отношение составляло степени двойки. Тогда нажатие каждой кнопки можно будет свести к включению в ADC соответсвующего бита и сложный IF для чтения кнопок можно будет переписать битовыми операциями в одну-две строчки. 2. В ручных режимах закодировать цвета в формате 222 - по три цвета в один байт - в итоге восемь IF для первых режимов можно бужет записать в одну строку.
Могу ошибаться, но это вроде как 'inline' функция. Если переписать, то можно сэкономить несколько десятков байт. Так же уверенности полной нет, но версия компилятора может помочь сэкономить память. Есть проект для ATtiny45, который avr-gcc компилятором версии < 7.0, давал код на две сотни байт больше, чем версии >= 7.0. При этом функциональность вся сохранялась.
Это в eeprom. Попробовать if заменить на switch. это нельзя простой арифметикой заменить? int main на void main. Хотя это только ОЗУ прибавляет либо в современных компиляторах вообще ничего не дает. На сайте микрочипа лежит апноут по эффективному программированию. На микросине есть отличный перевод.
попробуй заменить на: Код (C++): const uint8_t keyValues[] PROGMEM = { 95,105,120,135,155,180,225,255 }; uint8_t getKey(uint8_t avalue) { uint8_t valsize = sizeof(keyValues) / sizeof(keyValues[0]); for (uint8_t i = 0; i < valsize; i++) if (avalue <= keyValues[i]) return i; return 0xFF; // заглушка от варнингов, такого никогда не случится } ISR(ADC_vect) { //ЦАП для определения какая кнопка нажата (кнопки на резисторном делителе) mods=getKey(ADCH); } скока байт, интересно, выграеца. Я к тому, что твой код чуть более, чем полностью, состоит из таких рутинных операций, которые можно заменить простым выбором из таблиц.
Борьба идёт за каждый байт: Код (C++): const uint8_t keyValues[] PROGMEM = { 95,105,120,135,155,180,225 }; #define VALSIZE 7 uint8_t getKey(uint8_t avalue) { for (uint8_t i = 0; i < VALSIZE; i++) if (avalue <= keyValues[i]) return i; return 0xFF; } ISR(ADC_vect) { //ЦАП для определения какая кнопка нажата (кнопки на резисторном делителе) mods=getKey(ADCH); } И по поводу Степень двойки лишнее и не уверен, что будет работать стабильно. Скорее нужно подобрать резисторы так, что бы они гарантированно выдавали определённые старшие три бита регистра ADCH. Тогда простым сдвигом вправо на пять бит получим код режима без всяких 'if'.
Код (C++): const uint8_t keyValues[] PROGMEM = { 95,105,120,135,155,180,225 }; #define VALSIZE 7 uint8_t getKey(uint8_t avalue) { for (uint8_t i = 0; i < VALSIZE; i++) if (avalue <= keyValues[i]) return i; return 0x07; } ISR(ADC_vect) { //ЦАП для определения какая кнопка нажата (кнопки на резисторном делителе) mods=getKey(ADCH); } тогда, так правильнее
удалил часть повторных действий и привел обнуление переменных в вид Х=Y=Z=0 вместо обнуления каждой по отдельности еще сократился код на 2 десятка байт
delay_ms тоже надо на что-то заменить, пусть и с понижением опорной частоты. На каждом вызове delay_ms тратим 2 байта вместо одного.