2015-06-25 4 views
2

Я использую контроллер AVR atmega328. Мне нужно проверить состояние двух бит. У меня есть два подхода, но не знаю, какой из них наиболее эффективен. В первом случае в приведенном ниже коде я читаю порт с помощью команды PIND дважды (выполняется два раза PIND-доступ). Так это проблема, или мне нужно идти со вторым if-выражением?Эффективная проверка бит во встроенной программе C

#define SW1 2 
#define SW2 5 
//check if both are high 
if((PIND&(1<<SW1))&&(PIND&(1<<SW2))) 
//Or 
if((PIND&((1<<SW1)|(1<<SW2)))==((1<<SW1)|(1<<SW2))) 
+0

Обратите внимание, что память программ одинакова в обоих случаях. Я проверил вывод в Atmel Studio –

+1

, ваш оба препроцессора - 'SW1', он не даст ожидаемого результата. –

+0

О, извините, нужно быть SW2. Не заметил ошибку. Спасибо, что вытащил его. Исправление. –

ответ

4

Я полагаю PIND является периферийным регистр (что вы имеете в виду под «командой»?).

Первая проверка будет прочитана один или два раза, в зависимости от первого сравнения. Это может вызвать сбой, если SW1 изменяется между первым и вторым чтением.

Предполагая, что SW? являются коммутаторами: в общем, лучше один раз прочитать такой регистр (возможно, переменную) и проверить бит. Это гарантирует, что вы получите мгновенный снимок всех входных битов в то же время.

Кроме того, вторая версия не обязательно медленнее, так как она защищает ветвь (IIRC AVR не имеет условных инструкций, кроме ветвей/прыжков).

+0

'переключатели: [чтение такой один раз] гарантирует, что вы получите мгновенный снимок всех входных битов в одно и то же время» - который защищает от «опасности изменения ключа». Если вы делаете ** программный де-отскок ** (например, с помощью кнопок), просто сделайте это первым. – greybeard

+0

@greybeard: Во-первых? Какова ваша позиция? – Olaf

+0

1. debounce 2. поместить значение в другое место для манипулирования - не оценивать какое-то сложное условие снова и снова до стабильного в течение выбранного периода времени. – greybeard

1

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

В случае 2 вы избегаете чтения регистров дважды, но вы выполняете 2 дополнительные операции.

Если бы я сделал предположение, я бы сказал, что вариант 1, скорее всего, будет быстрее, поскольку PIND является реестром AVR, а стоимость чтения будет меньше.

Сказав, что я хотел бы предложить использовать первый вариант, как его более читаемым даже его не нашел, чтобы быть быстрее, чем вариант 2.

+0

Это совсем не сложно. Регистры портов нестабильны, поэтому чтение их дважды в одном выражении - плохая идея.А во втором случае все оценивается во время компиляции до чтения порта. – Lundin

3

Первый считывает PIND дважды, поэтому он менее эффективен и потенциальен для ошибки - время между чтением может быть значительным, если вмешательство прерываний или переключателей контекста потока.

Второе оценивает (1<<SW1)|(1<<SW2) два раза, но в этом случае это постоянная времени компиляции, поэтому не должна влиять на производительность. Но, честно говоря, вы, вероятно, вспотеваете по мелочам, слишком сильно беспокоясь о коде на этом уровне. Если вам действительно нужно знать; взгляните на код, который генерирует компилятор (в разборке отладчика или при получении компилятора для вывода списка сборок), но для написания кода потребуется много времени, если вы намерены второй раз угадать каждую строку, подобную этой,

Смежные вопросы