Свежие обсуждения
Микроконтроллеры

Ликбез по С для микроконтроллеров PIC

1 23 64

Тело цикла можно бы переписать вот так:

...
if ((lDATABYTE ^ gCRCPIC) & 0x01)
gCRCPIC = ((gCRCPIC ^ 0x18) >> 1) | 0x80;
else gCRCPIC >>= 1;
...

Дело в том, что при операциях "по месту" (типа |=, >>= и т.д.) компилятор обязан сгенерировать код таким образом, чтобы после окончания выполнения каждого такого оператора в gCRCPIC оказалось то, что требуется по смыслу операции. Это, как минимум, три лишних movwf CRCPIC. Если выбран достаточно высокий уровень оптимизации кода, компилятор, не исключено, что эти лишние команды выкинет, но это далеко не факт. Конструкция ... & 0x01 вместо bit_test более универсальна, хотя код будет немножко длиннее (что, впрочем, тоже не факт - AVR GCC, например, такие ситуации легко распознает, и заменяет их на команды проверки бита). Условие цикла можно было бы переписать вот так:

...
while (!--lCOUNTER);

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

Я бы переписал весь этот кусок вот в таком виде:

for (iCounter = 8; iCounter--; lDATABYTE >>= 1)
if ((lDATABYTE ^ gCRCPIC) & 0x01)
gCRCPIC = ((gCRCPIC ^ 0x18) >> 1) | 0x80;
else gCRCPIC >>= 1;

Код, может быть, получился бы не самый оптимальный, но был бы более логичен - циклы while традиционно применяют тогда, когда момент окончания цикла достаточно непредсказуем, а в нашей-то ситуации он всегда выполняется ровно 8 раз Впрочем, близко к сердцу сказанное не принимайте - кто-нибудь другой запишет этот кусок совсем по-третьему, и также найдет убедительные аргументы в обоснование своего выбора В программировании правильны любые способы, кроме неправильных

 

Спасибо за инфу, буду размышлять дальше... Генерируемый компилятором ассемблерный листинг я внимательно просматриваю и по возможности использую для оптимизации своего кода на С. Попробую разные варианты, сравню. Тем временем здесь ещё что-либо подскажут, надеюсь.

 

picmaniac
Генерируемый компилятором ассемблерный листинг я внимательно просматриваю и по возможности использую для оптимизации своего кода на С
- Неблагодарное занятие это. Заточите свой код под один компилятор -- не факт, что он будет оптимален под другим, тем более -- на другом процессоре. Если каждый раз оглядываться на ассемблерный листинг -- весь смысл использования высокоуровневых языков пропадает.

Смею предположить, что 99% опытных программистов на Си написали бы код, идентичный предложенному выше chav1961.

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

Ещё совет -- не злоупотребляйте глобальными переменными, это значительно усложняет восприятие программы.
Например, функцию подсчета CRC можно было бы объявить как:
unsigned char next_crc(unsigned char byte, unsigned char prev_crc);
Не буду утверждать что в данном случае это нужно и оправдано, но в общем -- лишние глобальные переменные это зло. Особенно в больших программах. Особенно если они не статические : - )

 

caddr: Неблагодарное занятие это ... оглядываться на ассемблерный листинг -- весь смысл использования высокоуровневых языков пропадает

Всё равно полезно посмотреть. Не оглядываться, а посмотреть и принять к сведению. А то поначалу явные ляпсусы у меня бывают, которые для любого компилятора можно лучше сделать, и в листинге я их вижу. Да и интересно к тому ж. Я уже несколько интересных заметок для себя сделал.

А объявить функцию как unsigned char мысль была, но так мне показалось лучше на этом этапе. Тут я ещё подумаю.

 

Прошу небольшого совета. Есть некая функция:
//Отображение сегментов с управлением двоичными разрядами
void BinaryControl(unsigned BinaryShow)
{
LedT=LedO=LedP=LedO2=LedC=LedR=LedS=0; // Уровень яркости
// TOPOC
#opt 0
if((BinaryShow&&0b00000001==1)&&(LAT==1)) LedS=255;
if((BinaryShow&&0b00000001==1)&&(LAT==0)) LedC=255;
if (BinaryShow&&0b00000010==1) LedO2=255;
if (BinaryShow&&0b00000100==1) LedP=255;
if((BinaryShow&&0b00000100==1)&&(LAT==1))LedR=255;
if (BinaryShow&&0b00001000==1) LedO=255;
if (BinaryShow&&0b00010000==1) LedT=255;
}

но компилятор PICC слишком оптимизирует код и оставляет только первых 2 оператора IF, остальные игнорирует (это видно и в ассемблерном листинге и при пошаговом выполнении).
Пробовал выключать оптимизацию командой "#opt 0", но результата это никакого не дало.

Сама подпрограмма делает следующее: проверяет установлен ли нужный байт и в положительном случае устанавливает максимальную яркость (переменная=255) или "нулевая" яркость (переменная=0).
....
что еще более удивительно - если взять пару IF-ов из конца и перенести их вверх, то они ве равно игнорируются и "рассписываются" только те два, которые были первыми изначально (до установки перед ними IF-ов из конца).
опять у меня мистика (или ошибка)...

 

Сергей К
- Правильно компилятор делает, потому что вместо проверки битов Вы написали чего-то совсем не то : - ) Все условия неправильные, причем, кроме первых двух, никогда не выполняются (поэтому компилятор их и выкинул).

Разберитесь с двумя вещами:
1) В чем разница между операторами & и &&
2) Учите приоритеты операторов или ставьте скобки, если не уверены.

PS. Запись двоичных чисел в виде 0b является отклонением от стандарта языка Си (не всеми компиляторами поддерживается).

 

Сергей, к сказанному caddr можно только добавить, что опция #opt Вам бы и не помогла. Дело в том, что в условии if-ов есть константные выражения (в двух первых фактически ...&& TRUE, а в остальных - фактически ...&& FALSE). Если хочется,чтобы if-ы остались, надо отключать не уровень оптимизации, а вычисление булевых выражений по "короткой" схеме

 

Спасибо! Разобрался и исправил обе ошибки! Все заработало!
Про вторую я даже не догадывался, т.к. думал, что он вначале вычисляет выражние и лиш затем проверяет логическое условие...

 

Подскажите пожалуйста кто в курсе! Установил последние версии PIC C и MPLABa, все прекрасно, но
1. У PIC C есть классный редактор, но он позволяет отлаживать код только на hardware-отладчике которого нет
2. MPLAB все делает, но в режиме отладки не останавливается на брейк-поинтах, не дает пошагово отлаживаться. Короче, отладчик не работает.

Хотелось бы понять как отлаживать код в редакторе PIC C если это возможно. И как активировать нормальную отладку в MPLAB.
Еще есть последний Proteus. Но с ним я буду разбираться несколько позже.

 

Удалось запустить пошаговую в MPLAB