Что сделать, чтобы оптимизировать этот код?

Я оптимизировал его настолько, насколько, по моему мнению, мог, и хочу знать, какие у вас есть предложения, которые могли бы сделать его более эффективным и т.д.

Примечание: я знаю, что массив продолжается вечно :)

volatile uint16_t IRCode[]={340,171,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,21,21,64,21,21,21,64,21,64,21,64,21,64,21,64,21,21,21,21,21,21,21,64,21,21,21,21,21,21,21,21,21,64,21,64,21,64,21,21,21,64,21,64,21,64,21,1556,340,86,21,3654}; // ProntoHex в uint16_t удаляет первые 4 номера массива.
volatile uint16_t MicrosPassed;
volatile uint8_t Array_Seq;
uint8_t State;

void setup() {
  Config(); // Config sketch установит рабочие настройки для разных микроконтроллеров.
  SendIRCode();
}

void loop() {

}

void SendIRCode() {
  switch(State) {
    case 1:
      TCCR1A&=63; // Противоположно случаю 0 -193 = 63
      State=0;
      break;

    case 0:
      TCCR1A|=192;
      State=1;
      break;
  }
}

void Config() {
  DDRB|=10;
  ICR1=416;
  OCR1A=9983;
  TCCR1A=2;
  TCCR1B=24;
  TCCR1B|=1;
  TIMSK1=1;
}

ISR(TIMER1_OVF_vect) {
  MicrosPassed++;
  if(MicrosPassed==IRCode[Array_Seq]) {
    SendIRCode();
    MicrosPassed=0;
    Array_Seq++;
       }
}

, 👍1

Обсуждение

IRCode[], MicrosPassed и Array_Seq используются только в ISR; вы можете объявить их как статические в ISR, IRCode[] также может быть const , и нет необходимости объявлять их как изменяемые, потому что только ISR их считывает / записывает. Однако я понятия не имею, поможет ли это компилятору оптимизировать скорость., @ocrdu

Для чего вы хотите оптимизировать? Чистый код? Или какое-то значение слова "скорость" (какая скорость)?, @chrisl

преобразуйте массив в фактические биты .. 0 равно 21, 21 ... 1 - это 21, 64 ... s - 340, 17 - начало ... и так далее .... массив будет иметь вид { s, 0, 0, 0, 1, 0 ......} ... вы могли бы даже хранить байты вместо отдельных битов, @jsotola

Может быть, исправить проблему @chrisl [mentioned](https://arduinoprosto.ru/q/78973/infrared-low-frequency-transmission#comment175438_78973 ) перед оптимизацией вашего кода., @Gerben


1 ответ


3

Как намекнул Крисл в комментарии, существуют различные критерии, которые вы, возможно , захотите оптимизировать: скорость, размер, удобочитаемость... Судя по текущему состоянию этого скетча, я бы сказал, что вашей первой целью на данном этапе должна быть оптимизация для удобства чтения.

Труднее всего разобраться в большинстве простых чисел. При настройке регистров, являющихся битовыми полями, не используйте десятичные значения: используйте либо шестнадцатеричные, либо двоичные. Или, что еще лучше, используйте имена битов. avr-libc определяет эти имена, а также макрос _BV(bit_position), который расширяется до (1 << bit_position) и предназначен для использования с этими именами:

void Config() {
  DDRB   |= _BV(PB1) | _BV(PB3);  // PB1 и PB3 в качестве выходных данных
  ICR1    =  416;        // период таймера = 417 циклов
  OCR1A   = 9983;        // ???
  TCCR1A  = _BV(WGM11);  // режим 14: быстрая ШИМ, TOP = ICR1
  TCCR1B  = _BV(WGM12) | _BV(WGM13);  // ... то же самое
  TCCR1B |= _BV(CS10);   // часы @ F_CPU
  TIMSK1  = _BV(TOIE1);  // включить прерывание TIMER1_OVF
}

Конечно, имена битов несколько неясны, но они облегчают чтение программы, если у вас есть таблица данных поблизости. Мне нравится иметь комментарии, которые делают код понятным даже без чтения таблицы.

Обратите внимание, что вычисление этих выражений не замедляет работу программы , так как они вычисляются во время компиляции.

Когда переменная используется в одной функции, лучше определить ее в этой функции. Сохранение определения близко к тому месту, где используется переменная, делает код более “локальным” и, следовательно, более удобным для чтения. Поскольку вы хотите , чтобы некоторые из этих переменных запоминали свои значения при вызовах функции, присвойте им статический квалификатор.

Возможно, вам не нужно оптимизировать эту программу для повышения скорости. Однако здесь есть низко висящий плод: удалите изменчивые ключевые слова. Это ключевое слово предназначено для явного отключения некоторых оптимизаций компилятора, которые небезопасны, когда переменная совместно используется между контекстами прерывания и без прерывания . Ни одна из переменных, которые вы используете, не нуждается в этом.

Если я правильно понял, функция SendIRCode() просто переключает пару битов в TCR1A. Вы можете упростить его следующим образом:

void SendIRCode() {
  TCCR1A ^= _BV(COM1A0) | _BV(COM1A1);  // переключить ШИМ-выход на OC1A
}

Наконец, я полагаю, что в этом наброске есть ошибка. Переменная Array_Seq непрерывно увеличивается и никогда не сбрасывается. Затем программа завершит чтение после конца массива IRCode.

,