Главная » Микроконтроллеры
Призовой фонд
на август 2019 г.
1. 1000 руб
Паяльник
2. Тестер компонентов MG328
Паяльник
3. 200 руб.
От пользователей

Структура программы

Рассмотрим синтаксические особенности ассемблера AVR на примере небольшой тестовой программы для микроконтроллера ATmega8, приведенной ниже. Программа формирует на выводе PB2 импульсы с частотой следования ≈ 2.5 Гц при частоте внутреннего RC-генератора 1 МГц.

1. ;  Тестовая программа для ATmega8.
2. // Светодиод подключен к выводу PB0 микроконтроллера.        
3. /* Биты конфигурации:  
        Low Fuse                     High Fuse     
      BODLEVEL = 1                  RSTDISBL = 1      
      BODEN    = 1                  WDTON    = 1
      SUT1     = 1                  SPIEN    = 1   
      SUT0     = 0                  CKOPT    = 1   
      CKSEL3   = 0 |                EESAVE   = 1   
      CKSEL2   = 0 |_ RC-генератор  BOOTSZ1  = 1         
      CKSEL1   = 0 |     1 МГц      BOOTSZ0  = 1      
      CKSEL0   = 1 |                BOOTRST  = 1   */ 
    
4.        .nolist  ;подключение стандартного заголовочного файла
5.        .include "m8def.inc"
6.        .list 
                     
7.        .equ PAUSE  = 50000 ;задержка времени
8.        .equ LED    = PB2   ;вывод для подключения светодиода
            
9.        .def temp   = R16  ;регистр для промежуточных операций
10.       .def buffer = R17  ;регистр для чтения порта

11.              .cseg
12.             .org 0
13.          rjmp  initial                                          ;0xC01F
14.          rjmp  0 ;rjmp  service_INT0 ;внешнее прерывание 0      0xCFFE
15.          rjmp  0 ;rjmp  service_INT1 ;внешнее прерывание 1     0xCFFD
16.          rjmp  0 ;rjmp  service_OC2  ;совпадение TCNT2 и OCR2   0xCFFC
17.          rjmp  0 ;rjmp  service_OVF2 ;переполнение TCNT2        0xCFFB
18.          rjmp  0 ;rjmp  service_ICP1 ;захват в ICP1           0xCFFA
19.          rjmp  0 ;rjmp  service_OC1A ;совпадение TCNT1 и OCR1A  0xCFF9
20.          rjmp  0 ;rjmp  service_OC1B ;совпадение TCNT1 и OCR1B  0xCFF8
21.          rjmp  0 ;rjmp  service_OVF1 ;переполнение TCNT1       0xCFF7
22.          rjmp  0 ;rjmp  service_OVF0 ;переполнение TCNT0         0xCFF6
23.          rjmp  0 ;rjmp  service_SPI  ;прерывание от модуля SPI  0xCFF5
24.          rjmp  0 ;rjmp  service_URXC ;получение байта по USART   0xCFF4
25.          rjmp  0 ;rjmp  service_UDRE ;опустошение UDR в USART    0xCFF3
26.          rjmp  0 ;rjmp  service_UTXC ;передача байта по USART    0xCFF2
27.          rjmp  0 ;rjmp  service_ADCC ;прерывание от АЦП          0xCFF1
28.          rjmp  0 ;rjmp  service_ERDY ;завершение записи в EEPROM 0xCFF0
29.          rjmp  0 ;rjmp  service_ACI  ;прерывание от компаратора  0xCFEF
30.          rjmp  0 ;rjmp  service_TWI  ;прерывание от модуля TWI   0xCFEE
31.          rjmp  0 ;rjmp  service_SPMR ;завершение выполнения spm  0xCFED

32.             .org 0x20
33. initial: ldi   temp,low(RAMEND)                                   ;0xE50F        
34.          out   SPL,temp                                           ;0xBF0D
35.          ldi   temp,high(RAMEND)                                  ;0xE004
36.          out   SPH,temp                                           ;0xBF0E
37.          cbi   PORTB,LED                                          ;0x98C2
38.          sbi   DDRB,LED                                           ;0x9ABA
39.          ldi   temp,1«LED                                         ;0xE004

40. main:    in    buffer,PORTB                                       ;0xB318        
41.          eor   buffer,temp                                        ;0x2710
42.          out   PORTB,buffer                                       ;0xBB18
43.          rcall delay                                              ;0xD001
44.          rjmp  main                                               ;0xCFFB

45. delay:   ldi   XH,high(PAUSE)                                     ;0xECB3
46.          ldi   XL,low(PAUSE)                                      ;0xE5A0
47.          sbiw  XH:XL,1                                            ;0x9711
48.          brne  PC-1                                               ;0xF7F1
49.          ret                                                      

В строках 1…3 приведено 3 возможных варианта оформления комментариев. Комментарий в строке 1, начинающийся со знака “;”, распознается любым ассемблером и поэтому является наиболее предпочтительным. Комментарии в строках 2 и 3 подобны тем, которые используются в нотациях языков высокого уровня. Последний из них дает возможность выделить сразу несколько строк (маркерами начала и конца фрагмента текста является “/*” и “*/” соответственно).

В строке 5 директивой .include к программе подключается стандартный заголовочный файл "m8def.inc". Необязательные директивы .nolist и .list (строки 4 и 6 соответственно) запрещают вывод содержимого подключаемого файла в файл листинга.

Все директивы допускается размещать в одной строке. Так, например, можно было бы записать
.nolist .include "m8def.inc" .list

Несмотря на это, желательно придерживаться правильного стиля программирования, в соответствии с которым в одной строке должна быть расположена только одна директива ассемблера.

Объявление констант находится в строках 7 и 8. Константе LED присваивается номер линии ввода-вывода PB2 = 2, описание которой находится в заголовочном файле. В строках 9 и 10 двум рабочим РОНам назначаются пользовательские имена.

Секция рабочего кода открывается директивой .cseg в строке 11. Директива .org 0 (строка 12) устанавливает начальный адрес в памяти программ. В строке 13 должна находиться инструкция перехода на метку начала основной программы initial.

Метка представляет собой адрес в пределах секции кода или данных. В ассемблере AVR она должна быть записана в начале строки и завершаться в конце двоеточием.

Конечно, адрес в команде может быть указан и явно. В данном примере его можно задать безошибочно (rjmp 0x20 вместо rjmp initial). Но, это возможно только потому, что директива .org 0x20 (строка 32) заставляет компилятор поместить команду в строке 33 по адресу 32-го слова FLASH-памяти программ. Однако, в большинстве случаев, адрес размещения той или иной команды заранее неизвестен и, кроме того, он может изменяться по мере того, как в программу будут вноситься изменения. Именно поэтому предпочтительней использовать метки. Назначение их адресов производится автоматически на этапе компиляции. Да и символьные имена меток, предоставляют об объектах намного больше информации, чем просо какие-то числа.

На месте каждого неиспользуемого в программе прерывания желательно поставить “заглушки” в виде команды возврата rjmp 0 или reti, как это сделано в строках 14…31.

В строках 33…39 производится инициализация ресурсов микроконтроллера. Любая программа обязательно должна начинаться с установки начального значения указателя стека (если он имеется). В строках 33…36 в SPH:SPL заносится значение RAMEND = 0x045F (вершина стека перемещается в самый верх SRAM). Для выделения младшего и старшего полубайтов константы RAMEND используются встроенные функции low(RAMEND)=0x5F и high(RAMEND)=0x04 соответственно.   

Далее разряд LED в регистре данных порта B сбрасывается на 0 (стока 37), а сама линия управления светодиодом настраивается на вывод (стока 38). В строке 39 в регистр temp заносится константа 1<

 ldi temp,(1«PB0)|(1«PB5) или ldi temp,(1«PB0)+(1«PB5)    ;temp <- 0b00100001  
 out DDRB,temp                                            ;DDRB <- temp  

Код в строках 40…44 представляет собой тело основной программы. В регистр buffer считывается текущее состояние порта данных PORTB (строка 40). Далее между содержимым buffer и temp производится операция “Исключающее ИЛИ” (строка 41), после чего модифицированное содержимое buffer снова выводится в порт (строках 42). В результате такого действия логический уровень на линии PB2 изменится на противоположный. В строке 43 происходит вызов подпрограммы задержки времени delay (≈200 мс), а в строке 44 расположена инструкция перехода на метку main. Так образуется основной цикл программы, в котором происходит постоянное повторение операторов в строках 40…44: инвертирование уровня на выводе LED, задержка, затем снова инвертирование и т.д.

Внутри подпрограммы delay в регистровую пару XH:XL заносится число PAUSE = 50000, определяющее длительность задержки времени (строки 45, 46). В строке 47 из содержимого XH:XL вычитается 1. Команда условного перехода в строке 48 проверяет, значение флага Z из SREG. Если Z = 1 (результат предыдущей операции не равен нулю), то управление передается на строку 47. Так будет повторяться до тех пор, пока не выполнится условие XH:XL = 0 (т.е. пока не пройдет 50000 циклов вычитания). Команда выхода ret в строке 49 возвращает управление в то место основной программы, с которого произошел вызов delay.

Отдельно стоит обратить внимание на встроенную в ассемблер переменную PC в строке 48. Она представляет собой текущее содержимое программного счетчика. Адрес PC-1 будет указывать на предыдущее слово в памяти программ микроконтроллера. В данном случае в этом слове находится команда sbiw XH:XL,1. Использовать PC очень удобно для программных переходов в небольших пределах. Однако здесь всегда необходимо помнить, что у микроконтроллеров AVR имеются команды, которые имеют размер в 2 16-разрядных слова программ (lds Rd,k, jmp k и др.), из-за чего при вычислении смещения необходимо будет добавлять\отнимать к PC значение 2 вместо 1 на каждую такую инструкцию.

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

Перейти к следующей части:

Теги:

Котов Игорь Юрьевич Опубликована: 2012 г. 0 0
Я собрал 0 0
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 0 Проголосовало: 0 чел.

Комментарии (0) | Я собрал (0) | Подписаться

Статью еще никто не комментировал. Вы можете стать первым.
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется напряжение?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

AVR-программатор USB ASP
AVR-программатор USB ASP
Металлоискатель MD3010II DC-DC регулируемый преобразователь 1.5-37В 2А с индикатором
вверх