AVR. Учебный курс. Скелет программы

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

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

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

Суперцикл
Все программы на микроконтроллерах обычно зацикленные. Т.е. у нас есть какой то главный цикл, который вращается непрерывно.

Структура же программы при этом следующая:

  • Макросы и макроопредения
  • Сегмент ОЗУ
  • Точка входа — ORG 0000
  • Таблица векторов — и вектора, ведущие в секцию обработчиков прерываний
  • Обработчики прерываний — тела обработчиков, возврат отсюда только по RETI
  • Инициализация памяти — а вот уже отсюда начинается активная часть программы
  • Инициализация стека
  • Инициализация внутренней периферии — программирование и запуск в работу всяких таймеров, интерфейсов, выставление портов ввода-вывода в нужные уровни. Разрешение прерываний.
  • Инициализация внешней периферии — инициализация дисплеев, внешней памяти, разных аппаратных примочек, что подключены к микроконтроллеру извне.
  • Запуск фоновых процессов — процессы работающие непрерывно, вне зависимости от условий. Такие как сканирование клавиатуры, обновление экрана и так далее.
  • Главный цикл — тут уже идет вся управляющая логика программы.
  • Сегмент ЕЕПРОМ


Начинается все с макросов, их пока не много, если что по ходу добавим.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
	.include "m16def.inc"   ; Используем ATMega16
 
;= Start macro.inc ========================================
   	.macro    OUTI          	
      	LDI    R16,@1
   	.if @0 < 0x40
      	OUT    @0,R16       
   	.else
      	STS      @0,R16
   	.endif
   	.endm
 
   	.macro    UOUT        
   	.if	@0 < 0x40
      	OUT	@0,@1         
	.else
      	STS	@0,@1
   	.endif
   	.endm
;= End 	macro.inc =======================================

В оперативке пока ничего не размечаем. Нечего.

1
2
3
; RAM ===================================================
		.DSEG
; END RAM ===============================================

С точкой входа и таблицей векторов все понятно, следуя нашему давнему шаблону, берем его оттуда:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
; FLASH ======================================================
         .CSEG
         .ORG $000      ; (RESET) 
         RJMP   Reset
         .ORG $002
         RETI             ; (INT0) External Interrupt Request 0
         .ORG $004
         RETI             ; (INT1) External Interrupt Request 1
         .ORG $006
         RETI	      ; (TIMER2 COMP) Timer/Counter2 Compare Match
         .ORG $008
         RETI             ; (TIMER2 OVF) Timer/Counter2 Overflow
         .ORG $00A
         RETI	     ; (TIMER1 CAPT) Timer/Counter1 Capture Event
         .ORG $00C 
         RETI             ; (TIMER1 COMPA) Timer/Counter1 Compare Match A
         .ORG $00E
         RETI             ; (TIMER1 COMPB) Timer/Counter1 Compare Match B
         .ORG $010
         RETI             ; (TIMER1 OVF) Timer/Counter1 Overflow
         .ORG $012
         RETI             ; (TIMER0 OVF) Timer/Counter0 Overflow
         .ORG $014
         RETI             ; (SPI,STC) Serial Transfer Complete
         .ORG $016
         RETI    	     ; (USART,RXC) USART, Rx Complete
         .ORG $018
         RETI             ; (USART,UDRE) USART Data Register Empty
         .ORG $01A
         RETI             ; (USART,TXC) USART, Tx Complete
         .ORG $01C
         RETI	     ; (ADC) ADC Conversion Complete
         .ORG $01E
         RETI             ; (EE_RDY) EEPROM Ready
         .ORG $020
         RETI             ; (ANA_COMP) Analog Comparator
         .ORG $022
         RETI             ; (TWI) 2-wire Serial Interface
         .ORG $024
         RETI             ; (INT2) External Interrupt Request 2
         .ORG $026
         RETI             ; (TIMER0 COMP) Timer/Counter0 Compare Match
         .ORG $028
         RETI             ; (SPM_RDY) Store Program Memory Ready
 
	 .ORG   INT_VECTORS_SIZE      	; Конец таблицы прерываний

Обработчики пока тоже пусты, но потом добавим

1
2
; Interrupts ==============================================
; End Interrupts ==========================================

Инициализация ядра. Память, стек, регистры:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Reset:   	LDI R16,Low(RAMEND)		; Инициализация стека
	  	OUT SPL,R16			; Обязательно!!!
 
	  	LDI R16,High(RAMEND)
	  	OUT SPH,R16
 
; Start coreinit.inc
RAM_Flush:	LDI	ZL,Low(SRAM_START)	; Адрес начала ОЗУ в индекс
		LDI	ZH,High(SRAM_START)
		CLR	R16			; Очищаем R16
Flush:		ST 	Z+,R16			; Сохраняем 0 в ячейку памяти
		CPI	ZH,High(RAMEND)		; Достигли конца оперативки?
		BRNE	Flush			; Нет? Крутимся дальше!
 
		CPI	ZL,Low(RAMEND)		; А младший байт достиг конца?
		BRNE	Flush
 
		CLR	ZL			; Очищаем индекс
		CLR	ZH
		CLR	R0
		CLR	R1
		CLR	R2
		CLR	R3
		CLR	R4
		CLR	R5
		CLR	R6
		CLR	R7
		CLR	R8
		CLR	R9
		CLR	R10
		CLR	R11
		CLR	R12
		CLR	R13
		CLR	R14
		CLR	R15
		CLR	R16
		CLR	R17
		CLR	R18
		CLR	R19
		CLR	R20
		CLR	R21
		CLR	R22
		CLR	R23
		CLR	R24
		CLR	R25
		CLR	R26
		CLR	R27
		CLR	R28
		CLR	R29
; End coreinit.inc

Всю эту портянку можно и нужно спрятать в inc файл и больше не трогать.

Секции внешней и внутренней инициализации переферии пока пусты, но ненадолго. Равно как и запуск фоновых программ. Потом я просто буду говорить, что мол добавьте эту ботву в секцию Internal Hardware Init и все :)

1
2
3
4
5
6
7
8
9
10
11
; Internal Hardware Init  ======================================
 
; End Internal Hardware Init ===================================
 
; External Hardware Init  ======================================
 
; End Internal Hardware Init ===================================
 
; Run ==========================================================
 
; End Run ======================================================

А теперь, собственно, сам главный цикл.

1
2
3
4
5
; Main =========================================================
Main:
 
		JMP	Main
; End Main =====================================================

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

1
2
3
; Procedure ====================================================
 
; End Procedure ================================================

Ну и вот тебе файлик с уже готовым проектом под этот шаблон

67 thoughts on “AVR. Учебный курс. Скелет программы”

  1. «Суть в том, чтобы в автоматическом режиме, каждые несколько миллисекунд вызывать прерывание, в котором происходит подсчет импульсов от одометров»

    Очень сложный, и неудачный подход.
    Для подсчета импульсов с энкодеров в разы проще и эффективнее использовать прерывание по изменению состояния входа.
    Пришел импульс — сгенерировалось прерывание, посчитали его быстренько и работаем спокойно дальше. Итого: 1 импульс на энкодере — одно прерывние, а не постоянная беготня с проверкой порта и сравнением с предыдущим состоянием :)

    1. Да можно и так. Я подумал об этом в последний момент, но у меня на инты повешан драйвер движка, когда я его туда вешал я даже не думал про энкодеры на редуктор, Точнее у меня на них был собрана макетка, и я решил оставить обратную совместимость и ничего не менять. Так что чистейшая ошибка планирования, когда итоговая конструкция допридумывается походу дела такое сплошь и рядом :))))) Но зато появился кусок извратского кода для изучения. Тоже полезно, заодно показал как логика работает. :)

      1. «на инты повешан драйвер движка»
        Пора на Атмегу88 переходить :) У нее все порты (B, C, D) умеют внешние прерывания обслуживать, 24 входа для прерываний — с ума можно сойти.

          1. У нас тоже не продают. Приходится заказывать из Москвы, хорошо еще что удается «прицепляться» к заказам для фирмы и не платить за доставку.

      2. Не разобрался: прерывание по изменению состояния входа на ATMega8 можно только на 4 и 5 (INT0 и INT1) ноге делать?

  2. Я что-то недопонял, или у вас тут
    ANDI R16,11<<LGEAR ; Побитовое И регистра R16 и числа “00010000″
    и тут
    ANDI R17,11<<ODOL ; Побитовое И регистра R17 и числа “00010000″
    опечатка?
    11 вместо 1.

  3. Народ, проясните пожалуйста следующий момент про одометры:
    У DI HALT’а на схеме фотодиоды непосредственно к ногам МК подходят. На фотодиоды меня жаба задушила, взял фототранзисторы подешевле =) А они, злыдни, нужного эффекта не дают. Светишь, не светишь, все равно сигнал на МК не приходит. Кроме того, на разных ресурсах все норовят ОУ использовать для подобных датчиков. (Уточнение, буду использовать именно как датчик отражения.)
    Собственно вопрос: Можно ли фотодатчик подключать напрямую к ногам МК? Если «да» то какие характеристики у него должны быть?

    P.S. Тихо радуюсь за себя =) За месяц с нуля при отсутствии радиолюбительского опыта удалось из радиоуправляемой машинки сделать робота с контактными датчиками, управляемого с установленного на нем КПК и удаленно по WiFi с компа. В целом все живет, сейчас занимаюсь отладкой. Платформа (р/у машинка)оказалась неудачной: моторчик фиговый и без датчика оборотов предсказать, сколько он проезжает за одно и то же время — нереально. А без этого нормального управления не сделать.

    Кстати, попутный вопрос: Какие бы максимально просто определять положение передних (рулевых) колес? Сложность: конкретного положения им не задать — поворачиваться они могут только постепенно в процессе движения вперед или назад. Т.о. хочется знать, а в каком они положении в каждый момент времени. Пока пришла только одна мысль: переменный рез. и к АЦП но это как-то… не просто. К тому же движения рулевой рейки там минимальные (меньше 1 см в каждую сторону). В общем буду рад идеям.

    1. Ты бы замерил его характеристики (хотя бы сопротивление) на свету и не на свету. Возможно ты пытаешься светить ему не тем спектром. Мои, например, совершенно не реагируют на зеленый и синий светодиоды, но вот зато на красный сразу же.

      1. Спасибо за ответ.
        Не поверишь — замерял =)
        Транзистор ИК, свечу я на него тоже ИК-диодом. Сопротивление меняется от 15-11 кОм до 7-4 кОм. Пробовал мерять напряжение — не меняется 8-[ ] Стабильно показывает 5 с копейками, которые через него бегут.
        Доп. инф.: Стоит он между ногой МК и землей. Если ему ноги закоротить — МК сигнал принимает. Видимо, все-таки сопротивление у него дюже большое. М.б. постоянный резистор параллельно воткнуть? Вот только не соображу, как посчитать. Или как-то по-другому надо?

        1. Изменения очень невелики. ПОэтому у тебя и не хватает. Варианты тут такие:

          1. Подобрать делитель так, чтобы малейшее изменение вызывало переход через логический уровень.
          2. Смасштабировать через ОУ.
          3. Можно попробовать измерительный мост приспособить, но не уверен.

          1. Спасибо огромное.
            Извини, еще попристаю.
            Можно для идиотов чуть поподробнее:
            1) Какие изменения будут достаточными для Atmega8?
            2) Если взять не транзистор, а диод, станет ли лучше?
            3) Мне казалось, что транзистор и диод — бинарные элементы. Т.е. ток либо идет и идет весь либо не идет. С чего оно ведет себя, как фоторезистор?
            4) Делитель, это параллельный резистор? А можно формулу расчета или конкретный номинал для меня?
            5) Что есть «измерительный мост»?
            6) М.б. порекомендуешь конкретные ИК-диоды/транзисторы, которые можно ставить между МК и землей без танцев? Если прямо из каталога Ч&Д — вообще будет супер.
            7) Твой-то робот как? С момента последней статьи год прошел.

            P.S. Понимаю, что Гугл рулит, но во-первых от живого человека ответы приятнее. Во-вторых, большей частью в результатах валится промышленная реклама. В третьих, стиль у тебя понятный.

            1. В даташите есть раздел:
              Pin Thresholds and Hysteresis: там график зависимости лог уровня от напряжения питания. Так вот на 5 вольтах все что ниже 1.4 вольт — это ноль. А все что выше 1.8 вольт единица. Между ними граничное значение где может считываться и так и так.

              Так вот, твой транзистор и резистор должны образовать делитель напряжения. Читай основы на пальцах в 1…4 части про делитель было расписано. В общем, сопроитивление должно быть подобрано так, чтобы изменение верхнего плеча делителя (твой транз) таскало напругу через эту границу в 1.8-1.4 вольта.

              5) таки в гугл

              6) модели не помню, я их обычно выпаиваю из старых дисководов.

              7) стоит :)

              1. И еще раз спасибо.
                Делитель помог — заработало. Завтречка вместо трех последовательных прикуплю один и запихаю наконец в робота.

              2. Похвастаюсь немного =)
                Одометр довел до рабочего состояния и вставил в платформу. Работает на отражении от метки на колесе.
                Сегодня добил софтовые задачи:
                1) Поддержки заданной скорости (задаю желаемую скорость, а прошивка рулит ШИМОМ)
                2) Проезда заданного расстояния.
                Все стало ездить гораздо предсказуемее =)
                Надо еще китайский магнит на руле на серву поменять и будет мне счастье.

  4. Все это хорошо, хоть и весьма усложнено. Но это теория. На практике будет «дребезг контактов» , датчик может оказаться в пограничном положении. Надо писать функцию проверки истинности импульса. Вообще-то не пойму, зачем вам для простого счета импульсов нужны именно прерывания?? В каждом цикле можно опрашивать порты, как обычные входы. Есть сигнал > процедура проверки > подтвердился факт импульса > установился флаг события, уложился в РАМ (либо сразу вызвался счетчик), далее счетчик проверил флаг импульса.Если флаг установлен > добавил себе единичку или вычел, смотря в какую сторону ехал.. В следующем цикле этот флаг сбросился там же, где и устанавливался или в самом счетчике после счета.. Счетчики тоже проще организовать РАМ. Опрос порта займет несколько микросекунд, остальное время можно МК нагружать чем хочешь. А по вашему методу у вас очень скоро просто закончатся и регистры и счетчики.))

    1. А если мы делаем что то медленное и опрос пропустит пару импульсов? Это же критично!

      Дребезга тут нет, т.к. датчик работает быстро и весь остальной цикл это дело сглаживает

  5. Что можно делать настолько медленное? Может и неправильно с «академической» точки зрения (я не программист), но у меня большинство внешних событий вызывает установку соответствующего флага в РАМ, а в основной программе в каждом цикле проверяется его состояние. Так очень удобно — если у меня по , скажем, импульсу_Х происходит и счет в счетчике, и проверка выхода счетчика за пределы переполнения, и зашиты всевозможные. Так же в дальнейшем к этому флажку можно легко подвязаться любой подпрограммой. Получается очень удобно добавлять новые возможности. Есть флаги, которые устанавливаются и сбрасываются основной логикой программы, а уж опираясь на них можно ыешать кучу , так сказать «сервисных» и контрольных функций. Если все эти программы обработок и контроля вызывать сразу после прихода импулься, то получится достаточно громоздкая и неуклюжая конструкция. Конечно, если нужна очень высокая скорость, то импульсы надо считать по прерываниям. Но вот где взять в Меге8 8 внешних прерываний, да так чтобы и осталось еще что полезное из периферии свободным.
    В моем случае, импульс успевает 50 раз проверится на истинность, посчитаться, еще 50 раз провериться на заднем фронте (спаде). А

    1. В данном случае это трудно представить. Но если поставить оптический энкодер с частотой выдачи импульсов в килогерцы? Тогда проблема вылазит в полный рост.

      1. Можно просто чаще опрашивать входа, скажем за цикл не один раз, а десять.
        Опрос-то всего-ничего:
        sbis pinX, x
        rjmp a1

        a1: sbis pinX, x
        rjmp a2

        a2: …..
        Это практически не занимает ни время МК, ни его ресурсы. Понятно, что это до определенного потолка быстродействия, ну так и по прерывания такая же картина. Вроде бы примитивно, но зато удобно, и регистры все свободны. У меня на программу в 18кБ из регистров занято штук шесть. Да и вся периферия практически свободна, можно еще функций навешивать и навешивать.

        1. Но есть риск прозевать событие. Неважно по какой причине. Не попало в опрос и все тут. С прерываниями такого не выйдет.

          А чего жалеть регистры? Вот когда будет поджимать тогда и разберемся :)

  6. Di, кстати, а как проверить истинность импульса (в смысле, что не короткая помеха проскочила) если считать их по прерываниям? Как я понимаю, после перехода в обработчик прерывания, флаг прерывания сбрасывается, и что дальше? Как проверить, что это именно импульс? Обычно перепроверяют либо через некоторый промежуток времени, либо N-ное кол-во раз. А с прерыванием что-то не могу придумать. Сдается мне, что никак. Ну для машинки такой метод годится, а как быть, если до датчика 20 м кабеля? Там же помехи, наводки могут такого «насчитать», что за голову схватишься! Прошу прощения за въедливость, просто
    всегда интересно мнение более опытного товарища, а то у меня ведь — так, самодеятельность.

    1. Если есть риск того, что это помеха то только повторной проверкой.

      Из прерывания можно по таймеру сделать через некоторое время проверку. Т.е. суть прерывания поиметь событие в любом случае. А уж как оно будет обрабатываться потом это дело другое.

  7. DI HALT, я заметил, что в твоем коде ты (вроде) не делаешь задержек после того, как поймал нажатие кнопки. Она у тебя не дребезжит? Или ты как-то борешся с этим аппаратно? Триггер? Вообщем, мне интересно)

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

      1. А сколько времени (в среднем) примерно длится дребезг при «нормальном» нажатии у «нормальной» кнопки?

        1. Нормальной это какой? У китайской SWT я дребезг не смог увидеть даже не осциллографе 40мгц. А у советской ТМ-2 успокивать приходилось чуть ли не в 3мс.

          1. Нормальной — это значит средьненькой такой по цене кнопочки в магазине. Твоей советской ТМ-2 наверняка уже больше 20ти лет и использовалась она не раз. Но то что у новых зарубежных кнопок дребезга практически нет, радует. Не так все плохо оказывается, как пугают в книжках.

                1. Ну валяться на складе с 89 года можно было без особых проблем. По крайней мере она была не паяная, не окисленная, а на корпусе клеймо 89 год. =))))

  8. DIHALT привет. Почему например файл с макросами располагается вначале? Например можно ли его расположить после прерываний? На что это повлияет? И вообще если поменять структуру расположения вложенный файлов, это допускается? Или только так как указано выше?

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

  9. Секции внешней и внутренней инициализации переферии пока пусты, но ненадолго.
    Далее идет разметка кода:

    ; Internal Hardware Init ======================================

    ; End Internal Hardware Init ===================================

    ; External Hardware Init ======================================

    ; End Internal Hardware Init ===================================

    ; Run ==========================================================

    ; End Run ======================================================

    в 4-ой строке должно быть не End Internal Hardware Init, а End External Hardware Init.
    в файле проекта также

  10. у Белова перед циклом программы идет инициализация портов. у Ревича тоже. инициализацию пихать в секцию
    ; Internal Hardware Init ======================================

    ; End Internal Hardware Init ===================================
    ?
    и еще совсем уж глупый вопрос — что произойдет если порты вообще не инициализировать?

    1. Что такое инициализация? Это настройка периферии в нужный режим работы. Только и всего. Ну и избавление от умолчаний. Т.е. если после сброса порт находится уже в нужном нам режиме, то это совсем не значит, что его не нужно заново в этот режим выставить. Кто знает как отработает схема сброса и будет ли при следующем сбросе или сбое порт в нужном режиме? Поэтому то все каждый раз заново и выставляют при старте. Чтобы точно знать, что у нас все настроено правильно

      1. DI HALT, подскажите, пожалуйста, где можно почитать про инициализацию USB в AVR (1286, 1287, …) на ассемблере. На Вашем сайте (за сайт — огромное спасибо) я этого что-то не нашел. Так, чтобы было достаточно подробно описано:
        1. Включение внутреннего стабилизатора напряжения
        2. Настройка интерфейса блока PLL
        3. Разрешение работы блока PLL и ожидание входа его в состояние захвата (lock)
        4. Разрешение работы USB-интерфейса
        5. Настройка USB-интерфейса (скорость, настройка конечных точек и др.)
        6. Ожидание информационного подключения USB VBUS
        7. Присоединение к шине
        На сайте Atmel примеры есть на Си (не всегда работающие, несмотря что фирменные), а вот на Asm — нет.

  11. Добрый день!

    У меня снова повился вопрос: Делаю схему на ATtiny13A (ATtiny13V) питание +2 В. В даташите для питания 1,8-2,7В рекомендованно использовать тактовую частоту <=4МГц. Внутренний генератор можно настроить только на 4,8 МГц. Как сделать 4 МГц? С помощью OSCCAL? Ток я не понял, что это за зверь и как он работает. Объясните пожалуйста… если можно с примером..

    Заранее спасибо. :)

    1. Можешь попробовать через oscal загнать в минус. Просто вписав туда минимальное значение.

      либо через CLKPRE поделить частоту. Тебе надо точно 4мгц или 2х хватит?

      1. Добрый день продолжается!

        Спасибо за подсказку. Я пропустил описание CLKPR когда смотрел описание. В запаре был. Мне достаточно м 2 МГц. Но тут дилема. Два варианта реализации:
        1. При программировании установить FUSE биты CKSEL 01 получив тем самым 4,8 МГц, а потом при запуске МК в системе программно задать CLKPR — 0001 поделить 4,8/2 = 2,4 МГц.

        2. Не париться с Фьюзами (ещё ни разу с ними дела не имел) и сразу в программе задать CLKPR — 0010 поделив 9,6/4 = 2,4 МГц.

        А дилема в чём? Прокатит ли вариант 2 при питании 2 вольта? Я, в общем, склоняюсь к варианту 1.

  12. Имеются опечатки, возможно, это метки для защиты копирайта, например, на
    http://shop.easyelectronics.ru/index.php?productID=147
    адптера
    мы можешь

    Имхо,логическая опечатка:
    Хотя в разделе
    http://easyelectronics.ru/category/avr-uchebnyj-kurs Стартовая инициализация
    «убиваем все регистры от первого до последнего» в цикле,
    в разделе
    http://easyelectronics.ru/avr-uchebnyj-kurs-vtoraya-programma.html#more-30
    это не используется, идет тупой перебор регистров.

    Вопрос по существу, можете сделать сравнительный анализ программаторов отладчиков
    (расхвалить свой товар)
    Отладочная плата PinBoard http://shop.easyelectronics.ru/index.php?productID=147
    http://www.electronshik.ru/card/otladochniy-komplekt-stk500-dlya-avr-59500
    http://www.new-technik.ru/product/stk500/

    1. у STK500 очень хороший программатор с возможностью HVPROG. И возможность втыкать разные МК.

      Больше там ничего особо нет. JTAG отладчик придется покупать отдельно, дисплей отдельно. На самой плате из органов управления только кнопочки и светодиоды. Был бы он за 1500 еще можно было купить, но не за 5000.

      Тот что по второй ссылке — это просто программатор, но весьма неплохой.

  13. RunningWolf 25 Ноя 2009 16:16
    Народ, проясните пожалуйста следующий момент про одометры:
    У DI HALT’а на схеме фотодиоды непосредственно к ногам МК подходят. На фотодиоды меня жаба задушила, взял фототранзисторы подешевле =)=
    ==================
    извините за дурацкий вопрос.. но разве к этой статье схема приложена??

    1. Когда то давно статья была существенно другой. Потом была почти полностью переписана под другую платформу

  14. Чтобы обнулялась последняя ячейка RAM, в текст программы и в файл шаблона надо внести исправления, на которые указывал Andriy в предыдущей статье, а именно заменить:

    CPI ZL,Low(RAMEND) на CPI ZL,Low(RAMEND+1)

  15. У меня вопрос. Скорее всего он тупой)) просто я изучаю весь курс поп порядку. В макросах ты используешь конструкцию if-then-else. Но на скока я понял в ассемблере нет таких команд. ведь у тебя целая статья про типовые конструкции и про то как создать if then else через БРАНЧИ. я посмотрел файл m16def.inc но там ничего не написано про это. это случайно не ммакросы (.if и .else)? И вообще что озночает точка перед командой?

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

  16. ОК. этот момент я понял. т.е в случае сооружения структуры из бранчей в код будет прописано и ИФ и ЭЛСЕ. а здесь в нашем случае пропишется либо ИФ, либо ЭЛСЕ, в зависимости от начальных условий. В данном случае от переменных, которые мы подставляем в макрос. ок. ТОГДА ОПЯТЬ ТУПОЙ ВОПРОС. нам же главное результат, так? почему я не могу соорудить такой макрос, который бы мне , к примеру сравнивал величины. и делал бы либо то, либо другое. Я понимаю, что получается не совсем программа, а, по большому счету код будет прописан «в лоб», только пишем не мы а компилятор. т.е не будет логики. прокатит только для отдельно взятого случая. ток вот ни пофигу ли нам??? в частных случаях прокатило бы и это. или чего то изначально не понимаю?)) заранее спасибо

    1. Макросы оперируют только тем, что можно вычислить на этапе компиляции. Если у тебя масса логики решается уже тут — то ее надо тут и сделать. Т.к. появляется читаемость программы, а все что надо посчитать будет посчано компилером. Но это же все только константы. Ты можешь не пользуя макросами все сам посчитать и подставить.

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

  17. DI HALT, доброго времени суток.
    Я тут пытаюсь соорудить одно устройство на ATtiny2313, использую этот шаблон, но авр студия ругается, пишет вот такие замечания:
    error: Overlap in.cseg: addr=0x14 conflicts with 0x14:0x15 (это на строку: «OUT SPL,R16»)
    error: Overlap in.cseg: addr=0x16 conflicts with 0x16:0x17 (это на строку: «OUT SPH,R16»)

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

    1. 1. Убедись, что адрес который пихается в SPL указан как RAMEND и инклюдник от тини2313 взят, а не от чего то другого.
      2. У тини2313 нет SPH регистра. Ее озу укладывается в 255 байт.

  18. В коде «Инициализация ядра. Память, стек, регистры» есть ошибка. Когда чистим SRAM от начала (SRAM_START) до конца (RAMEND), то последняя ячейка (RAMEND) не очищается. Почему? Да потому, что выполнилось сравнение что Z=RAMEND и заканчиваем цикл без обнуления этой ячейки памяти RAMEND. Поэтому надо вставить после цикла еще одну строку для обнуления.
    =====================================
    ; Start coreinit.inc
    RAM_Flush: LDI ZL,Low(SRAM_START) ; Адрес начала ОЗУ в индекс
    LDI ZH,High(SRAM_START)
    CLR R16 ; Очищаем R16
    Flush: ST Z+,R16 ; Сохраняем 0 в ячейку памяти
    CPI ZH,High(RAMEND) ; Достигли конца оперативки?
    BRNE Flush ; Нет? Крутимся дальше!

    CPI ZL,Low(RAMEND) ; А младший байт достиг конца?
    BRNE Flush
    ========еще одна строка для обнуления ячейки памяти RAMEND
    ST Z,R16 ; Сохраняем 0 в последнюю ячейку памяти (RAMEND)
    ;========еще одна строка для обнуления ячейки памяти RAMEND
    Предлагаю автору проверить и поправить в коде источника.

  19. Что-то большинство коментов от какой-то другой статьи. Ты бы их посносил, всё равно бессмысленны без контекста. И название «Скелет программы», а ссылка /avr-uchebnyj-kurs-vtoraya-programma.html — не соответствует :)

  20. Решил писать програмку по данному шаблону, все куски кода из статьи вписывал в тойже последовательности, инклюдка для меги8, но на кусок с таблицей прерываний авр-студия выдает при компиляции матюки
    …..\Kom2x2_14.asm(144): error: Overlap in .cseg: addr=0x14 conflicts with 0x14:0x15
    и так далее до ….\Kom2x2_14.asm(171): error: Overlap in .cseg: addr=0x28 conflicts with 0x28:0x29
    При убивании строчки .ORG INT_VECTORS_SIZE компилит без ошибок.
    Собственно немогу понять чего он на нее ругается?

    1. У тебя где то ORGи наложились друг на друга. Проверь это внимательно. Они должны быть строго по порядку возрастания, а у тебя где то перепутались. В результате возникла ошибка перекрытия Overlap.

      1. Странно — кроме этой таблички там пока нет никаких ORGов, перепроверил инклюдки — там вообще нет ORGов
        Собственно строка .ORG INT_VECTORS_SIZE мне не совсем понятна — «INT_VECTORS_SIZE» это должен быть адрес в памяти? и этим именем он должон гдето быть назван с помощью .def ? или я ошибаюсь?

        1. Либо ORG возник после физического кода, т.е. ты навтыкал кода (тех же векторов) скажем на 10 байт, а ORG предписывает на 9 и возникло перекрытие.

          Да это адрес в памяти, он для каждого контроллера свой и прописан где то в def файлах. Если не найдешь, то проверь ,что используешь assembler2 и файлы из него, т.к. в ассемблер1 таких дефайнов много меньше (да и сам ассемблер1 намного слабей чем версия 2)

          Таблицу векторов правильно нарисовал? А то если ты ее копипастнул откуда-то, то там может быть больше векторов чем есть на самом деле, т.к. она может быть с другого контроллера. Вот тебе и оверлап вылез.

          1. Спасибо за терпение Di, разобрался — копипастнул табличку из статьи — а она под мегу16 — у меня-же мега8 — вот и матюкалось — исправил — работает, учим дальше RTOS. ))

  21. Не очень понимаю зачем так самозабвенно обнуляются регистры? Есть там мусор, ну и хер с ним. А берётся регистр в оборот так всё равно туда либо что то предварительно грузится. Или это чисто академический пример?

  22. Di доброго времени. Могли бы помочь перенсти RTOS на mega328? Вектора поправил, uart поправил, а вот с таймерами разобраться не могу.

Добавить комментарий

Ваш e-mail не будет опубликован.

Перед отправкой формы:
Human test by Not Captcha