Свежие обсуждения
Не про радио

Всем, кого достал 1,2,3 ! Краткий курс.

1 2 5

Хотя, согласен, один хрен - что в тех демках с паскаля на си переучиваться, что в AVR-GCC.

 

Фото с девушкой и сигаретой - это 5 баллов !!!
Num Lock:
А вы это BASIC контроллер собрали ? И как работает ?

 

Нет, ещё не собирал.

 

BASIC-контроллер - аналог МК-85 что ли?

 

caddr: - Ужас-то какой, пользоваться под Linux демкой кривого виндового компилятора, когда есть родной avr-gcc : - )

+1, гнилая отмазка

 

Num Lock: то где он советы давать будет по своему курсу, если будет чё непонятно.

он на робофоруме сидит и на хоботе целая тема его

Num Lock: А я хотел демо-версии ПО из его курса проверить на совместимость с wine, и в случае успеха нАчать программирование МК изучать.

тебе же уже давно сказали, что все есть под линупс

 

Дык никто не спорит, что AVR-GCC круче, но у него недостаток один есть: по нему товарищ 123 консультировать не умеет.

 

Может быть мы вскорости устроим "Ликбез по AVR" здесь? Как уже был "Ликбез по PIC". Примерно по такому же принципу - техзадание, его обсуждение, граф и алгоритм, программа, её отладка, реализация в железе. С подробным обсуждением каждого шага. Есть желающие?

ИМХО - 12З мог бы оказать немалую помощь начинающим АВР-щикам, не будь он столь фанатичным маньяком своего курса, и не суй почти в каждое своё сообщение ссылки на него. Попытки договориться с ним по-хорошему оказались в своё время бесполезны...

 

picmaniac, так было уже такое. Лично я тему и замутил. "Наш ответ Чемберлену" называлась, если помните. В нее этот ... товарищ ... и влез. Больше рисковать не хочется

 

что нужно знать начинающему AVR-щику: ( найдено на просторах интернета)

1. В командах sbr и cbr нужно применять не номер бита, а маску, нужно писать (1<Bit) или exp2(Bit).

2. Для обращения к таблицам в памяти программ командой lpm указатель Z нужно загружать значением (метка * 2). Память программ организована как слова, а lpm работает с байтами. Нужно писать так: ldi ZL,low(Label*2) ldi ZH,high(Label*2).

3. Для сброса флага прерывания в него нужно записать "1".

4. Нет приоритетов прерываний. Прерывания автоматически запрещаются в начале обработки. Если требуются вложенные прерывания, в обработчик нужно добавить команду sei. Команда reti делает то же самое, что и ret, плюс разрешает прерывания.

5. Питание портов, на которых располложены входы АЦП, производится от AVCC/AGND. Если это питание не подать, порты работать не будут.

6. В EEPROM лучше не использовать ячейку с адресом 0, регистр адреса EEPROM лучше обнулять после операций с EEPROM. Для младших AVR, которые не имеют встроенного BOD, при использовании EEPROM обязательно нужен внешний супервизор. В современных AVR есть BOD, он должен быть включен фузом. Для таких AVR внешний супервизор лучше не использовать, может быть даже хуже - помехи на линии RESET могут вызвать даже порчу содержимого памяти программ. Вход RESET желательно подтянуть к питанию резистором порядка 4.7К и подключить конденсатор порядка 10 нФ на землю (программированию он обычно не мешает).

7. Команды с непосредственным операндом sbr, cbr, ldi, ori, andi, subi, sbci возможны только с регистрами R16 - R31.

8. Побитовая работа с портами sbi, cbi возможна только в диапазоне адресов 00 - 1F.

9. ADIW, SUBIW работают только с R24, 26, 28, 30.

10. movw работает с парами четный:нечетный регистр R0:R1 и т.д.

11. inc не устанавливает флаг C.

12. Команды с автоинкрементом/декрементом не изменяют старший байт указателя в устройствах с ОЗУ менее 256 байт. Его можно использовать для других целей. Команды ADIW, SUBIW - изменяют.

13. При определении таблиц в памяти программ за каждой директивой DB должно быть четное количество байт, иначе автоматически добавляется 0x00.

14. При переходе с AT90S1200 (без стека) на старшие AVR не забывать инициализировать стек.

15. Запись в EEPROM time-controlled, нужно запрещать прерывавания.

16. У некоторых AVR, например, mega8, нужно специальным битом разрешать не только выключение WDT, но и изменение его интервала.

17. Для 16-разрядных регистров периферии читать первым L, писать первым H.

18. Если есть JTAG, то его надо выключать фузом, иначе не работают соответствующие порты. Если есть фуз совместимости с Мегой103, его нужно не забывать убрать.

19. Чтение состояния внешнего сигнала, подключенного к порту, производится из PINx, а не из PORTx.

20. Mega64, 128 программируется через выводы RXD, TXD (а не MISO, MOSI).

21. Mega64, 128 OC2 и OC1C на одной ноге!

22. У новых мег UART имеет FIFO, в котором сохраняются данные и флаги ошибок (FE, DOR). Поэтому UDR нужно читать один раз на один принятый байт. Флаги ошибок нужно читать перед чтением UDR.

23. При использовании аппаратного SPI в режиме мастера вывод SS нельзя использовать в качестве входа.

24. У старших мег часть периферии находится не в адресном пространстве IO, а в адресном пространстве данных (например, порт F). В таких случаях доступ нужно осуществлять командами STS, LDS а не OUT, IN.

25. Внимательно изучите фузы, особенно типа тактового генератора и времени стартапа. Всегда желательно ставить Full Amplitude, иначе некачественные кварцы могут генерировать неустойчиво. Указать состояние фузов в исходном тексте программы нельзя, их нужно программировать отдельно (программаторы имеют такую возможность).

26. Некоторые программаторы (PonyProg, например) применяют инверсное обозначение состояния фузов. Будьте бдительны, распространенная ошибка - перевод AVR на внешнее тактирование. При этом он перестает отвечать программатору и выглядит совсем мёртвым. Выход из такой ситуации - подключение внешнего клока к XTAL1 на время программирования.

27. Не переключайте фузом вход RESET в режим обычного IO - контроллер невозможно будет дальше программировать последовательным программатором.

28. При чтении PINx нужно учитывать, что внешние сигналы синхронизируются в нутренней тактовой частотой, что приводит к задержке. Поэтому если мы что-то вывели на порт и хотим это же прочитать, нужно вставить команду NOP между OUT и IN. Хотя чтение собственного выходного сигнала требуется очень редко.

29. Линии, которые используются для внутрисхемного программирования (MISO, MOSI, SCK) можно использовать в проекте как порты ввода-вывода. Если используется вывод, то никаких дополнительных мер принимать не надо (только учтите, что в момент программирования будет "дергаться" подключенная периферия). Если используется ввод, то выход внешней схемы, подключенный к этому входу, надо развязать резистором порядка 470 ом.

1. Исходный текст лучше делить на модули, а не сваливать всё в один файл. Намного упрощается повторное использование кода, да и продуманные связи между модулями делают алгоритм понятнее. Например, программа управления усилителем. Я бы разбил текст римерно так:
main.asm - основная программа. Здесь размещаем инициализацию и основной цикл, где вызываем функции из других модулей.

header.asm - здесь размещаем описание портов, глобальных регистровых переменных, основных констант.

keyboard.asm - модуль обслуживания клавиатуры. Содержит как минимум две функции - инициализацию подсистемы клавиатуры и что-то типа Get_Scan_Code, которую нужно вызывать из основного цикла в main.

display.asm - модуль обслуживания дисплея. Опять содержит как минимум инициализацию и собственно индикацию.

menu.asm - модуль, содержащий логику меню, строковые константы и т.д.

hw.asm - модуль, содержащий функции работы с железом, которые могут вызываться из других модулей.

Структура каждого модуля чем-то напоминает структуру класса в духе ООП: функция инициализации - это как бы конструктор класса, есть набор методов, модули могут содержать какие-то поля данных. К сожалению, ассемблер не содержит поддержки областей видимости функций и переменных, всё это приходится отслеживать вручную. Очень может помочь система префиксов к именам. Но ООП-эшный стиль мышления очень помогает составлять простые для понимания программы даже на ассемблере. Пусть не наследование, так хоть подобие инкапсуляции Нужно отметить, что красота исходного текста ведет к увеличению объема кода и уменьшению скорости его выполнения. Что-то вроде плавного перехода на язык высокого уровня

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

Плохо:

DScPh: .byte 1

Лучше:

Display_Scan_Phase: .byte 1

3. Не следует в тексте применять константы в числовом виде. Все константы должны быть описаны в начале того файла, где они применяются.

Так писать нельзя:

ldi temp,220
sts Soft_Timer,temp

А так - уже лучше:

.equ ON_DELAY = 220 ;задержка включения усилителя

ldi temp,ON_DELAY
sts Soft_Timer,temp

4. Не стесняйтесь загружать препроцессор транслятора вычислениями. К примеру, в программе используются какие-то временные задержки. Представьте, Вы захотели перейти на другую частоту кварца. Если не хотите при этом править в тексте десятки констант, вычисляйте все константы на этапе трансляции, используя константу тактовой частоты. Пример:

.equ FCLK = 11059200 ;тактовая частота, Гц
.equ BAUD = 115200 ;скорость передачи UART

.equ UBRRV = (((Fclk*10)/(16*Baud))-5)/10 ;рассчитываем (с округлением) константу для делителя UART

При таком расчете констант может случится, что результат "не влезает" в разрядную сетку результата. Хорошим тоном является сделать проверку:

.equ MAXWORD = 0xFFFF

.if UBRRV > MAXWORD
.error "out of range constant"
.endif

Если полученное значение окажется больше MAXWORD, транслятор дасть ошибку с текстом "out of range constant". Текст можно задать любой, например, "превед, красавчег!".

5. AVR не имеет прямой адресации бит (адресация есть только в пределах байта). Это уменьшает гибкость переопределения портов. Например, на макете сигнал Load_Relay был на порту PB0, а при разводке платы оказалось удобнее подключить его к порту PD2. Что делать? По всей программе искать и исправлять? Лучше для обращения к портам использовать макросы. В файле header.asm пишем:

.equ Load_Relay = PB0 ;управление реле нагрузки

.macro Port_Load_Relay_0 ;устанавливает линию Load_Relay в "0"
cbi PORTB,Load_Relay
.endm

.macro Port_Load_Relay_1 ;устанавливает линию Load_Relay в "1"
sbi PORTB,Load_Relay
.endm

Везде в программе обращение к этой линии порта делаем так:

Port_Load_Relay_0 ;включение реле
ldi temp,ON_DELAY
rcall Delay_ms ;задержка ON_DELAY
Port_Load_Relay_1 ;выключение реле

Любые перестановки портов тогда можно сделать корректировкой определений и макросов в одном местем (в header.asm).

Для входных линий порта макрос может быть таким:

.macro Skip_if_Protection_0 ;пропустить команду, если Protection = 0
sbic PIND,Protection
.endm

6. Если нужны разные варианты одной и той же программы, не делайте копий исходников (запутаетесь при изменениях!), а применяйте условную трансляцию. Например, в плату могут быть установлены индикаторы с общим анодом или общим катодом. Пишем так:

#define COMMON_ANODE

#ifdef COMMON_ANODE
Port_CT1_1 ;выключение линий сканирования
Port_CT2_1
Port_CT3_1
#else
Port_CT1_0
Port_CT2_0
Port_CT3_0
#endif

7. Все-таки добавлю. При настройке встроенной периферии не следует писать так:

ldi temp,0xd8
out UCSRB,temp
ldi temp,0x86
out UCSRC,temp

Мало того, что для этого нужно на бумажке собирать биты в байты, так и при переносе программы могут возникнуть трудности, если какой-то бит в другом контроллере изменит своё расположение.

А вот это - другое дело:

ldi temp,(1RXCIE) | (1TXCIE) | (1RXEN) | (1TXEN)
out UCSRB,temp
ldi temp,(1URSEL) | (1UCSZ1) | (1UCSZ0)
out UCSRC,temp

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

Ну и так далее в том же духе

MACRO - Начало макроса

С директивы MACRO начинается определение макроса. В качестве параметра директиве передаётся имя макроса. При встрече имени макроса позднее в тексте программы, компилятор заменяет это имя на тело макроса. Макрос может иметь до 10 параметров, к которым в его теле обращаются через @0-@9. При вызове параметры перечисляются через запятые. Определение макроса заканчивается директивой ENDMACRO.

По умолчанию в листинг включается только вызов макроса, для разворачивания макроса необходимо использовать директиву LISTMAC. Макрос в листинге показывается знаком +.
Синтаксис:
.MACRO макроимя

Пример:
.MACRO SUBI16 ; Начало макроопределения
subi @1,low(@0) ; Вычесть младший байт параметра 0 из параметра 1
sbci @2,high(@0) ; Вычесть старший байт параметра 0 из параметра 2
.ENDMACRO ; Конец макроопределения

.CSEG ; Начало программного сегмента
SUBI16 0x1234,r16,r17 ; Вычесть 0x1234 из r17:r16