Перейти к содержанию
    

Bill

Участник
  • Постов

    413
  • Зарегистрирован

  • Посещение

Весь контент Bill


  1. Все должно быть в документации. Но лучше вставками вообще не пользоваться, поскольку эффекта от них нет. Лучше сделать отдельный модуль на ассемблере и включить его в проект. Сам я пользуюсь IAR, как это сделать в CV не знаю.
  2. А преобразователь уровня зачем? У него пороговое напряжение 1В. Транзистор от контроллера должен нормально открываться. А Вообще проблема здесь в том, что транзистор при такой нагрузке не входит в режим насыщения и все его милиомы не работают. Постройте нагрузочную прямую (характеристики в DS имеютсч) и увидите сколько будет на транзисторе вольт падать. Ну и мощность, рассиваемую транзистором, тоже вычислите.
  3. До avr-libc весии 1.4.4 обработчики прерываний в которых были запрещены прерывания описывались с помощью SIGNAL, а в которых были разрешены прерывания описывались с помощью INTERRUPT. К сожалению новички очень часто не прочитав документацию и/или не поняв в чем разница использовали INTERRUPT ..... и получали граблями по лбу. Поэтому в avr-libc 1.4.4 SIGNAL был заменен на ISR (SIGNAL конечно же остался для совместимости, только не рекомендован для использования), а INTERRUPT удален, точнее перемещен в <compat/deprecated.h>. Если вам нужна функциональность INTERRUPT, значит .... вы уже профессиональный разработчик и знаете как описать такой обработчик прерываний. Анатолий. Спасибо за разъяснение. Сам я этим компилятором не пользовался, поэтому этих тонкостей не знал. Теперь буду знать. Или нет?
  4. Значит проблема не в прерываниях. Возможны три причины по которым МК у Вас сбрасывается: 1. запрограммирован сооветствующим Fuse-битом WDT, решение проблемы - оключить WDT или добавить в основной цикл программы asm("WDR"). 2. глючит BOD, решение проблемы - отключить BOD при знакомстве с МК. 3. помеха на Reset'е, решение - добавить конденсатор между землей и Reset'ом 0.1..1uF. Хм...Вроде бы автор топика глаголил, что "...Только вот столкнулся с проблемой, при отработке прерывания компилятор при выходе из него ставит RET вместо RETI..." ??? 2 Samodelkin - это на самом деле имеет место быть? Вы смотрели ассемблерный листинг Вашего творения? Насколько мне известно, в WinAVR функции обработки прерываний описываются при помощи квалификатора SIGNAL. Или нет?
  5. Компилятор в IAR

    Похоже Вы немного пошутили или не то имели ввиду. По сравнению с AVR в PC регистров почти нет. А если учитывать, что часть из них связано с определёнными функциями (CX - регистр счётчик, BX,EX -базы, AX - аккумулятор). То такая оптимизация вообще не имеет смысла. Да и при таком построении процессора, вопрос такой экономии не ставится. Там оптимизация строится на базе совершенно других принципов. Длина цикла - размер кэша - объём данных по работе с памятью, "грамотное обращение" к переферии и т.д. Не стоит забывать, что эти регистры 32-разрядные. И есть возможность использовать их и как 16-, и как 8-разрядные. К тому же, у AVR есть определенные проблемы с использованием младших 16 регистров. Так что реально используются только 16 старших регистров. А если требуются данные типа long или float, так их останется на все про все всего 4. И опять же, у PC инструкции позволяют оперировать с ячейками памяти как с регистрами (при увеличении длины инструкции и времени ее выполнения). Так что вопросы оптимизации программы за счет использования регистров остаются весьма актуальными.
  6. А как Вы процедуру прерывания описываете?
  7. Компилятор в IAR

    Борланд - это PC. Неужто в нем недостаток регистров? Ни разу не встречал в коде для Борланда (начиная с версий оного 4 и выше) подобных попыток оптимизаций. Имхо, уже давным давно прошла необходимость рулить такими оптимизациями из С-кода. Компилятор с этим разберется лучше. Программисту надо состредоточиться на алгоритме, а уж как по регистрам совать - тут все карты на руках у компилятора. Если хочется адекватного результата ручному контролю, то это ассемблер (вызов функции или вставки). Кроме IAR, еще несколько компиляторов не замечены во внимании к ключевому слову register: CCS/TMS320F28xx, VDSP++/Blackfin, avr-gcc (правда, с последним знакомство поверхностное). P.S. Посмотрел в доку на Билдер: В Borland C++ в проекте можно указания опции для использования регистровых переменных: None, Automatic и Register keyword. Т.е. в первом случае компилятор не будет размещать переменные в регистрах, во втором случае он будет размещать переменные в регистрах автоматически как только он сочтет это нужным. В третьем случае в регистрах будут размещаться только те переменные, для которых указан класс памяти register.
  8. Компилятор в IAR

    Может игнорировать если нельзя обеспечить. Причем игнорировать молча. Иными словами, если можно обеспечить, то и так задействует регистр, если нельзя, то не задействует, ничего не сообщая. Так сегодня поступает подавляющее большинство (если не все) компиляторов. От ключевого слова register ничего не зависит, оно является рудиментом и артефактом. Оставленным в языке для совместимости со старым кодом. Есть не просит, пусть будет. Это не совсем так. Просто в IAR сделано именно так. Где размещать переменные решает только компилятор. В других средах (например, в Borland) имеется возможность выбора: не размещать переменные в регистрах, размещать автоматически или размещать по ключевому слову register. Сейчас, когда ресурсов в PC предостаточно, компиляторы стали достаточно "умными", то необходимость в использовании register как бы отпадает. Но в контроллерах с ограниченными ресурсами иногда желательно дать возможность решать вопрос о размещении переменных самому программисту.
  9. Компилятор в IAR

    Если уж подсказывать, то подсказывать по полной программе: register char to=TimeOut; Вообще-то, IAR игнорирует ключевое слово register. Или нет?
  10. Настройки линкера тут ни причем. Просто эта функция отсутствует в проекте. Найдите исходный текст этой функции и включите ее в проект.
  11. CVAVR 1.25.2 beta

    Это у всех, кто что-то неправильно написал.
  12. void *func(); - это прототип функции. Указатель объявляется как void (* func)(); Вызов соответственно будет (*func)();
  13. Откуда ассемблерный код взялся?
  14. Для описанного случая нельзя :) setjmp() текущий pc и стек сохраняет а не устанавливает какой хочется. Я имел в виду переход между функцииями. setjmp() запоминает стек и PC точки перехода в буфере, переход в эту точку происходит путем вызова функции longjmp().
  15. Ну-ну область видимости меток ограничена :), по понятным причинам, и за пределы функции уж точно не выпрыгните. Можно использовать функции setjmp() и longjmp().
  16. ну так вроде и должно быть 4 ADC.MUX = 3; Array[3] = ++3; потому как после выборки ячейки ADC.MUX инкрементируется, и только потом присваивается значению ячейки хотя согласен с _Bill потому как компилятор может по разному выполнять такую конструкцию. Можно просто посмотреть сгенерированный код для разных случаев. Хотя лично мне непонятно чего именно хотел получить автор.
  17. Замечу вуругался на оба варианта, с ADC.MUX и с DDRD (точнее PORT.D.DIR.Value :) ), но второй, повторюсь, скампилировал верно! В чем проблема? Кстати, может кому понравится такой подход - организация регистров перефирии в смысловые структуры (ах как не хватает классов си++)? Если кто использует такой подход - поделитись опытом. Компилятор не выругался. Он просто сделал Вам предупреждение о том, что поведение компилятора непредсказуемо и результат может получится не тот, который Вы ожидали. Вообще, обе Ваши конструкции двусмысленны и интерпретировать их можно по-разному в зависимости от того, какая часть выражения (левая или правая) будет вычисляться первой.
  18. Компилятор в IAR

    И вот на этой приятной ноте и хочется спросить, - а стоит ли применять такие методы? Полазайте по форуму и Вы найдёте массу примеров таких ухищрений. Но в такой ситуации всегда остаётся вероятность того, что при смене версии компилятора или просто немного изменив окружающие операторы Вы, в следующей трансляции опять потеряете "золотую нить". Получается программирование на СИ с элементами ASMа. В том смысле что прога привязана к кристалу, сама к себе, к компилятору. Тут нельзя сказать однозначно. Во-первых, мы так или иначе привязаны как контроллеру, с одной стороны, так и к инстументам для его программирования. И то, и другое нужно знать как можно лучше. Поэтому всякие эксперименты, позволяющие лучше узнать то, с чем работаешь, безусловно необходимы. Но... Есть машинно-независимые способы оптимизации программ. Они всем известны. Это, прежде всего, более оптимальный алгоритм. Далее, выбор наиболее подходящей организации данных. Это и оптимизация программ на уровне ЯВУ. Опять же, понимание того, как компилятор генерирует код для тех или иных конструкций языка, даст возможность создать более оптимальную программу. Например, использование оператора do while является более оптимальным по сравнению с оператором while. Сравнение с нулем даст более оптимальный код, чем сравнении с константой. То есть while (--i != 0) ... более эффективно, чем while (++i != CONST) ... Таких примеров можно привести сколько угодно. Однако, эффективные программы часто получаются менее понятными и читабельными, особенно для посторонних людей. И если мы в погоне за оптимальностью напишем такой код, который будет труден для понимания и сопровождения, и (возможно) для переноса на другую платформу, а выигрыш даст лишь пару-другую инструкций, или пару микросекунд, то стоит ли тратить на это время? Если же скорость работы программы или ее размер являются критичными, то может лучше написать критичные по этим параметрам модули на ассемблере? И такие модули могут быть более понятными, поскольку программист использует все возможности архитектуры процессора. Ему не надо становиться на уши, чтобы описать с помощью инструкций процессора то, чего средствами Си описать или очень трудно, или вообще невозможно. Использование же всяких ассемблерных вставок, как правило, не дает той эффективности, какую желают получить, а программа становится бесформенной, трудной для понимания и сопровождения. Короче говоря, во всем нужна мера.
  19. Дело в том, что Билл написал просто чепуху про "естественную" свертку целочисленных констант перед вычислением выражения, а Вашего предложения я вообще почему-то не вижу в истории переписки. Так как так и не была озвучена информация про диапазоны операндов, хотелось бы все-таки увидеть, что именно Вы считаете "правильной" записью данного выражения, если это понятие "правильности" отличется от формальной правильности. Хотелось бы также узнать Ваше мнение по следующему вопросу: существует ли с точки зрения стандарта языка программирования С какая-либо разница между выражениями a * b * c / d и ((a * b) * c) / d ? И, кстати, считаете ли Вы что компилятор имеет право выражение a = b * 2 / 3; заменить на a = 0; ? Ну, я не думаю, что я написал чепуху. Дело в том, что операция умножения коммутативная операция, а операции умножения и деления имеют одинаковый уровень приоритета. Если взять Ваш пример, то в общем случае совершенно не важно в каком порядке производить вычисления, результат будет один и тот же. То есть b * c * d / e = (b * c * d) / e = b * c * (d / e) Проблема возникает именно потому, что появляются типы данных. Компилятор всегда производит перегруппировку выражения таким образом, чтобы код, вычисляющий данное выражения, был минимальным. Если в выражении имеются константы, то компилятор непременно выполнит все возможные вычисления с константами в соответствии с правилами арифметики. По умолчанию все константы имеют тип int, и если их тип не указан особо, то результат также будет иметь тип int. Естественно, что результат вычисления константного выражения может быть неверным, если программист специально об этом не позаботится. В данном случае, операнды d и e будут целыми константами и компилятор обязательно вычислит результат d/e, хотя он в общем случае будет некорректным. Если мы хотим получить корректный результат, то мы должны задать требуемый порядок вычислений явным образом с помощью скобок. Можно также изменить тип констант по умочанию с использованием соответствующих суффиксов.
  20. Компилятор в IAR

    Попробовал. Никакой разницы. Да оно в общем-то и понятно. Было бы удивительно, ведь с точки зрения "С" а--; и а -= 1; абсолютно идентичны. Все правильно. Только компиляторы разные семантически одинаковые конструкции иногда транслируют по-разному. Поэтому всегда имеет смысл "повертеть" такую конструкцию с тем, чтобы увидеть в каких случаях компилятор сгенерирует наиболее оптимальный код. Если, конечно, есть в этом необходимость.
  21. Компилятор в IAR

    Интересно мыслите, однако! Как вам такой пример, я честно говоря до сих пор не понимаю отчего IAR 4.11a так себя ведет. Оптимизация включена на максимум, окромя "cross-call" UCHAR TimeOut; // глобальная переменная __interrupt void TimerInt() { if(TimeOut) TimeOut--; }; Все это компилится в ледующий код: LDS R16, TimeOut TST R16 BREQ 0x392 LDI R30,0x9F LDI R31,0x02 LD R16,Z DEC R16 ST Z,R16 Сохраниение и восстановление стека я опустил. Что мы видим? Грузим переменную, проверяем ее, если условие выполняется, опять ее же грузим (ЗАЧЕМ?), причем засоряя адресные регистры, модифицируем и сохраняем. В результате имеем 3 лишних комманды + 4 для сохраниения-восстановления адресных регистров. Более чем в 2 раза, однако! Никак оптимальным такой код не назовешь. Что скажете..? Попробуйте так: if (TimeOut) TimeOut -= 1;
  22. Ну, так все правильно. Компилятор перед генерацией производит свертку констант, т.е. вычисляет значение PRODUCTIVITY / 20000. Естественно, оно будет вычисленно неточно. Поставьте в выражении скобки в нужных местах. Еще советую объявить константы как long, тогда погрешность в вычислении уменьшится.
  23. Умножение

    "Умножение без умножения"
×
×
  • Создать...