Это старая версия документа!
Александр Викторович, я попробовал добавить текст программы в виде файла, чтобы не загромождать страницу, но dokuwiki ругается на недопустимое расширение файла |
АННОТАЦИЯ
В данном программном документе приведен текст программы «telemetry_rev1-1», предназначенной для опроса телеметрических датчиков, подключенных к микроконтроллеру Atmel Atmega328P, и отправки полученных данных по последовательному порту на бортовую ЭВМ. Текст программы реализован в виде символической записи на языке ассемблера AVR. Компилятором является консольная программа для UNIX-подобных операционных систем - avra.
Основной функцией программы telemetry_rev1-1 является опрос и отправка показаний следующих датчиков:
В процессе сбора данных происходит их перевод в двоично-десятичный код и отправка по USB-to-Serial протоколу с сохранением в памяти бортовой ЭВМ.
Программа состоит из основной программы,подключаемых модулей и файла объявления имен регистров:
1. Текст программы telemetry_rev1-1.asm на языке ассемблера AVR
;-------------------------------------------------------------------------------------------------------------- ; Program : telemetry_rev1-1 ; Compiler : AVRA ; Chip type : ATmega328P ; System Clock : 16 MHz ; Date : 18.01.2017 ;-------------------------------------------------------------------------------------------------------------- ;Подключение библиотек и резервация места под данные .include "m328Pdef.inc " .dseg adc_data: .byte8 Trm:; Ячейки ОЗУ под показания датчиков DS18B20 .byte14 bmp_temp:; Ячейки ОЗУ под показания темп. датчика BMP180 .byte2 bmp_pres:; Ячейки ОЗУ под показания давления датчика BMP180 .byte2 bh_lux: .byte2 .cseg .include "iterrupts.asm"; Библиотека векторов прерываний .include "macr.asm"; Библиотека макросов .include "twi_lib.asm"; Библиотека работы шины TWI .include "hextobcd.asm"; Библиотека перевода чисел в неупаковынный 2-10 код .include "1wire.asm"; Библиотека 1-wire устройств ;-------------------------------------------------------------------------------------------------------------- RESET: ;Начальная_инициализация ;-------------------------------------------------------------------------------------------------------------- ldi R16, Low(RAMEND); Инициализация стека outSPL, R16 ldiR16, High(RAMEND) out SPH, R16 .deftry = r21 .deftemp = r16 .def razr1 = r17 .def razr2 = r18 .def razr3 = r19 .equ W1_DDR = DDRB ; Присваиваем псевдоним регистрам порта датчиков DS18B20 .equ W1_PORT = PORTB .equW1_PIN = PINB .equ W1_BIT = 0 ; Бит порта на котором датчики (8 цифровой контакт на плате Ардуино) .equ FREQ = 16000000 ; Частота процессора .equ baudrate = 38400; Расчитываем делитель бодрейта для UART .equ bauddivider = FREQ/(16*baudrate)-1 .equFreqSCL = 200000; Расчитываем частоту работы шины TWI .equFreqTWBR = ((FREQ/FreqSCL)-16)/2 ldi R16, low(bauddivider); Инициализация UART sts UBRR0L,R16 ldi R16, high(bauddivider) sts UBRR0H,R16 ldi R16,0 sts UCSR0A, R16 sts UCSR0B, R16 sts UCSR0C, R16 LDI R16, (1<<RXEN0)|(1<<TXEN0)|(0<<RXCIE0)|(0<<TXCIE0)|(0<<UDRIE0) sts UCSR0B, R16 ldi r16,0 LDI R16, (0<<USBS0)|(0<<UMSEL0)|(0<<UMSEL1)|(1<<UCSZ00)|(1<<UCSZ01) sts UCSR0C, R16 ldi r16,0b01000000; Инициализация АЦП sts ADMUX,r16 ldi r16,0b11011111 sts ADCSRA,r16 ldi r25,0 rcall W1_Sbros; Сбрасываем шину 1-Wire rcall W1_Init_12bit; Перестраиваем конфигурационный байт на 12 битную схему работы rcall W1_Sbros; Вновь сбрасываем ldi r16,0b00000101; Инициализация работы прерывания по таймеру для отправки показаний sts TCCR2B,r16; датчиков DS18B20 по шине 1-Wire ldi r16,0b00000001 sts TIMSK2,r16 sts TIFR2,r16 ldi r16,0xF0 sts TCNT2,r16 ldi r16,0b00000101; Инициализация работы прерывания по таймеру для отправки показаний sts TCCR1B,r16; датчиков DS18B20 по шине 1-Wire ldi r16,0b00000001 sts TIMSK1,r16 sts TIFR1,r16 ldi r16,0xA0 sts TCNT1H,temp sts TCNT1L,temp ldi R16, 0b00110000; Инициализация шины TWI out PORTC, R16 ldi r16,FreqTWBR sts TWBR,r16 ldi r16,0x00 sts TWSR,r16 clr try clr r2 clr r3 clr r4 clr r5 ldi r24,0x00 ldi R16, 0b00000000 out PORTD, R16 ldi R16, 0b00000100 out DDRD, R16 rcall i2c_start ldi r16,0x46; Если нет, то остаемся этой процедуре rcall i2c_send ldi r16,0x11 rcall i2c_send rcall i2c_stop sei; Разрешаем прерывания rjmp main ;-------------------------------------------------------------------------------------------------------------- ;Конец_начальной_инициализации ;Основная_подпрограмма ;-------------------------------------------------------------------------------------------------------------- main: cli; Запрещаем прерывания в основном цикле push r mov r17,r5 mov r16,r4 rcall bin2ASCII15 mov r17,r3 mov r16,r2 rcall bin2ASCII15 popr tabulate rcall W1_ConvTemp; Говорим датчикам конвертировать температуры push r16 lds r16,bh_lux+1 cpi r16,0x82 brlo light brsh no_light light: lds r16,bh_lux cpi r16,0x01 brsh light_exit ldi r16,0b00000100 out PORTD,r16 jmp light_exit no_light: ldi r16,0b00000000 out PORTD,r16 jmp light_exit light_exit: pop r16 ldi ZL, LOW(adc_data); Производим косвенную адресацию на показания АЦП, чтобы потом их ldi ZH, HIGH(adc_data); последовательно отправить по UART clr r20 print_adc:; Цикл отправки показаний АЦП inc r20 push r ld r17,Z adiw ZH:ZL,1 ld r16,Z adiw ZH:ZL,1 rcall bin2ASCII15 popr tabulate cpi r20,4 brne print_adc; Закончили цикл tabulate push r lds r17,bmp_temp; Выводим показания датчика BMP180 lds r16,bmp_temp+1 rcall bin2ASCII15 tabulate lds r17,bmp_pres lds r16,bmp_pres+1 rcall bin2ASCII15 tabulate lds r17,bh_lux lds r16,bh_lux+1 rcall bin2ASCII15 popr inc r24; Увеличили счетчик кадров и отправили его значение по UART newline rcall i2c_start ldi r16,0x47 rcall i2c_send rcall i2c_receive sts bh_lux,r16 rcall i2c_receive_last sts bh_lux+1,r16 rcall i2c_stop sei; Разрешили прерывания, чтобы микроконтроллер смог обработать ; новые показания АПЦ, термометров и датчика BMP180 rcall i2c_start rjmp main ;-------------------------------------------------------------------------------------------------------------- ;Конец_основной_подпрограммы ;Прерывание_АЦП ;-------------------------------------------------------------------------------------------------------------- adc_conv: cli; Запрещаем прерывания lds r17,ADCL; Снимаем показания сделанные во время нашего отсутствия в прерывании lds r18,ADCH cpi r25,0; Смотрим, какое число содержится в r25 breq adc0; Переходим по метке для этого числа cpi r25,1 breq adc1 cpi r25,2 breq adc2 cpi r25,3 breq adc3 cpi r25,4 breq adc4 adc0: sts adc_data+6,r18; Записываем снятые в начале показания АЦП sts adc_data+7,r17 ldi r16,0b01000000; Запускаем новое преобразования в зависимости от пина АЦП sts ADMUX,r16 rjmp adc_ex; Переходим на выход adc1: sts adc_data,r18 sts adc_data+1,r17 ldi r16,0b01000001 sts ADMUX,r16 rjmp adc_ex adc2: sts adc_data+2,r18 sts adc_data+3,r17 ldi r16,0b01000010 sts ADMUX,r16 rjmp adc_ex adc3: sts adc_data+4,r18 sts adc_data+5,r17 ldi r16,0b01000011 sts ADMUX,r16 rjmp adc_ex adc4: clr r25; Если r25 = 4, очищаем его и прыгаем на adc0 rjmp adc0 adc_ex:ldi r16,0b11011111; Каждый раз повторно инициализируем АЦП sts ADCSRA,r16 inc r25 sei reti ;-------------------------------------------------------------------------------------------------------------- ;Конец_прерывания_АЦП ;Прерывание_таймера1 ;-------------------------------------------------------------------------------------------------------------- W1_timer: cli ldi r16,0x54 check1 r16 tabulate rcall W1_Sbros; Сбрасываем шину и проверяем есть ли датчик ldi YL, LOW(Trm) ldi YH, HIGH(Trm) ldi ZL,LOW(Addr1*2) ldi ZH,HIGH(Addr1*2) rcall W1_ReadMem; Читаем в ОЗУ текущую температуру ldi ZL,LOW(Addr2*2) ldi ZH,HIGH(Addr2*2) rcall W1_ReadMem ldi ZL,LOW(Addr3*2) ldi ZH,HIGH(Addr3*2) rcall W1_ReadMem ldi ZL,LOW(Addr4*2) ldi ZH,HIGH(Addr4*2) rcall W1_ReadMem ldi ZL,LOW(Addr5*2) ldi ZH,HIGH(Addr5*2) rcall W1_ReadMem ldi ZL,LOW(Addr6*2) ldi ZH,HIGH(Addr6*2) rcall W1_ReadMem ldi ZL,LOW(Addr7*2) ldi ZH,HIGH(Addr7*2) rcall W1_ReadMem push f; На всякий случай отправляем в стек SREG ldi ZL, LOW(Trm); Делаем косвенную адресацию на массив данных температуры датчиков DS18B20 ldi ZH, HIGH(Trm) clr r20 print1:; Цикл печати данных inc r20 push r ld r16,Z adiwZH:ZL,1 ld r17,Z adiwZH:ZL,1 rcall bin2ASCII15 tabulate popr cpi r20,7 brne print1 newline ; Задаем число с которого таймер начнет считать до следующего прерывания ldi r22,0xA0 sts TCNT1H,r22 sts TCNT1L,r22 popf; Возвращаем SREG из стека sei; Разрешаем прерывания reti ;-------------------------------------------------------------------------------------------------------------- ;Конец_прерывания_таймера1 ;Прерывание_таймера0 ;-------------------------------------------------------------------------------------------------------------- Board_timer: cli push f mov r16,r2 cpi r16,0xFF breq r2cap inc r2 jmp btim_exit r2cap: clr r2 mov r16,r3 cpi r16,0xFF breq r3cap inc r3 jmp btim_exit r3cap: clr r3 mov r16,r4 cpi r16,0xFF breq r4cap inc r4 jmp btim_exit r4cap: clr r4 mov r16,r5 cpi r16,0xFF breq r5cap jmp btim_exit inc r5 r5cap: clr r5 jmp btim_exit btim_exit: ldi r22,0xE9 sts TCNT2,r22 popf sei reti ;-------------------------------------------------------------------------------------------------------------- ;Конец_прерывания_таймера0 ;Прерывание_TWI ;-------------------------------------------------------------------------------------------------------------- TWI_int: cli; Запрещаем прерывания push r16; Отправляем в стек r16 lds r16,TWSR; Сравниваем Статус-регистр TWI andi r16,0xF8 cpi r16,0x08; Если он равен 0x08, то нам надо запустить вычисление breq TWI_start_samples_1 cpi r16,0x10; Если он равен 0х10, то нам надо считывать показания breq TWI_read_samples_1 TWI_exit:popr16; Возвращаем r16 из стека sei; Разрешаем прерывания reti TWI_start_samples_1:; Запускаем вычисление некомпенсированной температуры ; Проверяем содержимое переменной try cpi try,1; Если 1, то прыгаем на запуск вычисления давления breq TWI_start_samples_2 ldi r16,0xEE; Если нет, то остаемся этой процедуре rcall i2c_send ldi r16,0xF4 rcall i2c_send ldi r16,0x2E rcall i2c_send rcall i2c_start rjmp TWI_exit TWI_start_samples_2:; Запускаем вычисление некомпенсированного давления ldi r16,0xEE rcall i2c_send ldi r16,0xF4 rcall i2c_send ldi r16,0x34 rcall i2c_send rcall i2c_start rjmp TWI_exit TWI_read_samples_1:; Считываем показания некомпенсированной температуры ; Снова проверяем try cpi try,1 breq TWI_read_samples_2 ldi r16,0xEE rcall i2c_send ldi r16,0xF6 rcall i2c_send rcall i2c_start ldi r16,0xEF rcall i2c_send rcall i2c_receive sts bmp_temp,r16 rcall i2c_receive_last sts bmp_temp+1,r16 ldi try,0b00000001 rcall i2c_stop rjmp TWI_exit TWI_read_samples_2: ldi r16,0xEE rcall i2c_send ldi r16,0xF6 rcall i2c_send rcall i2c_start ldi r16,0xEF rcall i2c_send rcall i2c_receive sts bmp_pres,r16 rcall i2c_receive_last sts bmp_pres+1,r16 ldi try,0b00000000; Уменьшаем try до 0 rcall i2c_stop rjmp TWI_exit ;-------------------------------------------------------------------------------------------------------------- ;Конец_прерывания_TWI Addr1:.db0x28,0xFF,0x41,0x3,0xA3,0x15,0x1,0xBB; Адреса датчиков DS18B20 Addr2:.db0x28,0xFF,0xE2,0x1A,0xA2,0x15,0x4,0xF9 Addr3:.db0x28,0xFF,0x91,0xF,0xA3,0x15,0x4,0xC8 Addr4:.db0x28,0xFF,0x90,0x82,0xA3,0x15,0x4,0x41 Addr5:.db0x28,0xFF,0xC6,0xB,0xA3,0x15,0x4,0x2 Addr6:.db0x28,0xFF,0x9,0x5D,0xA3,0x15,0x4,0x9E Addr7:.db0x28,0xFF,0x7F,0x83,0xA3,0x15,0x4,0x7B Delay: ; Стандартная задержка push f ldi razr1, 50 ldi razr2, 10 Pdelay: dec razr1 brne Pdelay dec razr2 brne Pdelay popf ret Delay1: ; Стандартная задержка 1 push f ldi razr1, 50 ldi razr2, 50 ldi razr3, 1 Pdelay1: dec razr1 brne Pdelay1 dec razr2 brne Pdelay1 dec razr3 brne Pdelay1 popf ret
2. Текст модуля 1wire.asm на языке ассемблера AVR
;1-wire_подпрограммы ;-------------------------------------------------------------------------------------------------------------- W1_Sbros: ; Сброс шины и проверка датчик на месте ли lds r16, W1_BIT ; Записываем в r16 ножку где датчик sbi W1_DDR, W1_BIT ; Ногу на выход cbi W1_PORT, W1_BIT ; Опрокидываем вывод на землю rcall W1_DelayH ; Задержка 480 мкс, для сброса cbi W1_DDR, W1_BIT ; Ногу на вход rcall W1_DelayI ; Ждем тайм слот 70 мкс sbis W1_PIN, W1_BIT ; Пропускаем следующую строку, если бит порта в 1 ldi r17, 1 ; И установим сигнальный регистр в 1 sbic W1_PIN, W1_BIT ; Пропускаем следующую строку, если бит порта в 0 ldi r17, 0 ; И установим сигнальный регистр в 0 rcall W1_DelayJ ; Ждем тайм слот 410 мкс ret ; Если датчик на месте, в r17 по выходу отсюда будет 1, в противном случае 0 W1_Address: clr r20 read: inc r20 ; Процедура считывания адреса датчиков DS18B20 in r10,SREG push r10 lpm r16,Z rcall ds_byte_wr pop r10 out SREG,r10 adiw ZH:ZL,1 cpi r20,8 brne read ret W1_ReadMem: ; Чтение памяти регистров температуры ldi r16, 0x55 ; Пошлем команду 0x55, это сравнить уникальный номер датчика rcall ds_byte_wr ; Так как он у нас один на проводе rcall W1_Address ; Отправляем адрес датчика ldi r16, 0xBE ; Говорим датчику, что мы сейчас будем читать rcall ds_byte_wr ; Запуливаем байт rcall ds_byte_rd ; А тут уже начинаем читать, прочитали первый st Y, r16 ; И запулили его в память, по метке Trm adiw YH:YL,1 rcall ds_byte_rd ; Читаем второй st Y, r16 ; И запулили его в память, по метке Trm+1 adiw YH:YL,1 rcall W1_Sbros ; Сбрасываем шину и проверяем есть ли датчик ;ldi ZL,LOW(Addr2*2) ;ldi ZH,HIGH(Addr2*2) ;clr r20 ret W1_ConvTemp: ; Подпрограмма конвертирования температуры ldi r16, 0xCC ; Пропускаем уникальный номер датчика rcall ds_byte_wr ldi r16, 0x44 ; Говорим что надо бы сконвертировать температуру, этот процесс занимает 750 rcall ds_byte_wr ; миллисекунд, поэтому идем что-то делать, или ленится ret W1_Init_12bit: ; Подпрограмма перестройки на 12 бит температуры ldi r16, 0xCC ; Пропускаем уникальный номер датчика rcall ds_byte_wr ; Спуливаем в датчик ldi r16, 0x4E ; Говорим что сейчас будем писать в RAM регистры датчика rcall ds_byte_wr ; Спуливаем в датчик ldi r16, 0xFF ; 0xFF записываем в первые 2 регистра, это регистры температуры, он нам не rcall ds_byte_wr ; нужен, поэтому их оставляем в стандартном состоянии ldi r16, 0xFF ; 0xFF второй байт температуры rcall ds_byte_wr ; Спуливаем на порт ldi r16, 0x7F ; А вот тут говорим что 12 бит - 7F, или 1F - 9бит, 3F - 10 бит, 5F - 11 бит rcall ds_byte_wr ; Спуливаем на порт ret ds_byte_rd: ; Подпрограмма чтения данных в регистр r16 с 1 Wire ldi r17, 8 ; Пишем в r17 - 8, т.к. у нас в бит в регистре clr r16 ;Чистим r16, сюда будем читать данные ds_byte_rd_0: sbi W1_DDR, W1_BIT ; Вывод на выход cbi W1_PORT, W1_BIT ; Опрокидываем вывод на землю rcall W1_DelayA ; Ждем 6 микросекунд cbi W1_DDR, W1_BIT ; Вывод на вход rcall W1_DelayE ; Ждем 9 микросекунд sbis W1_PIN, W1_BIT clc ; Очищаем бит C = 0 sbic W1_PIN, W1_BIT sec ; Очищаем бит C = 1 ror r16 ; Производим циклический сдвиг вправо через С rcall W1_DelayF ; Ждем 55 микросекунд dec r17 ;Понижаем на 1 регистр r17 brne ds_byte_rd_0 ; если не равен 0 вращаемся в цикле ret ds_byte_wr: ; Подпрограмма записи данных из регистра r16 в датчик ldi r17, 8 ; Пишем в r17 - 8, т.к. у нас в бит в регистре ds_byte_wr0: sbi W1_DDR, W1_BIT ; Вывод на выход cbi W1_PORT, W1_BIT ; Опрокидываем вывод на землю sbrc r16, 0 ; Проверим, в r16 бит 0 очищен или установлен rjmp ds_byte_write_1 ; Если установлен перейдем по этой метке rjmp ds_byte_write_0 ; Если очищен перейдем по этой метке ds_byte_wr1: lsr r16 ; Логический сдвиг вправо dec r17 ; Понижаем r17 на 1 brne ds_byte_wr0 ; Если не равен 0, вращаемся в цикле ret ; Выход из подпрограммы ds_byte_write_0: ; Запись 0 rcall W1_DelayC ; Ждем 60 микросекунд cbi W1_DDR, W1_BIT ; Вывод на вход rcall W1_DelayD ; Ждем 10 микросекунд rjmp ds_byte_wr1 ds_byte_write_1: ; Запись 1 rcall W1_DelayA ; Ждем 6 микросекунд cbi W1_DDR, W1_BIT ; Вывод на вход rcall W1_DelayB ; Ждем 64 микросекунд rjmp ds_byte_wr1 W1_DelayA: ; Задержка 6 mcs ldi XH, high(FREQ/2000000) ldi XL, low(FREQ/2000000) rcall W1_Delay ret W1_DelayB: ; Задержка 64 mcs ldi XH, high(FREQ/130000) ldi XL, low(FREQ/130000) rcall W1_Delay ret W1_DelayC: ; Задержка 60 mcs ldi XH, high(FREQ/136000) ldi XL, low(FREQ/136000) rcall W1_Delay ret W1_DelayD: ; Задержка 10 mcs ldi XH, high(FREQ/1000000) ldi XL, low(FREQ/1000000) rcall W1_Delay ret W1_DelayE: ; Задержка 9 mcs ldi XH, high(FREQ/1200000) ldi XL, low(FREQ/1200000) rcall W1_Delay ret W1_DelayF: ; Задержка 55 mcs ldi XH, high(FREQ/150000) ldi XL, low(FREQ/150000) rcall W1_Delay ret W1_DelayH: ; Задержка 480 mcs ldi XH, high(FREQ/16664) ldi XL, low(FREQ/16664) rcall W1_Delay ret W1_DelayI: ; Задержка 70 mcs ldi XH, high(FREQ/116000) ldi XL, low(FREQ/116000) rcall W1_Delay ret W1_DelayJ: ; Задержка 410 mcs ldi XH, high(FREQ/19512) ldi XL, low(FREQ/19512) rcall W1_Delay ret W1_Delay: ; Подпрограмма воспроизведения задержки sbiw XH:XL, 1 ; Вычитаем единицу из регистровой пары brne W1_Delay ; Если не равно 0 крутимся в цикле ret ; Выход из подпрограммы ;-------------------------------------------------------------------------------------------------------------- ;Конец_1-wire_подпрограмм
3. Текст модуля hextobcd.asm на языке ассемблера AVR
.def fASCIIL =r16 .def tASCII0 =r16 .def fASCIIH =r17 .def tASCII2 =r25 .def tASCII3 =r19 .def tASCII4 =r20 .def tASCII1 =r21 .def cnt16a =r21 .def tmp16a =r22 .def tmp16b =r23 ;***** Код print_ascii: check1 r20 check1 r19 check1 r25 check1 r21 check1 r16 ret bin2ASCII15: ldi tmp16a, low(10000) ldi tmp16b, high(10000) rcall bin2ASCII_digit mov tASCII4, cnt16a ldi tmp16a, low(1000) ldi tmp16b, high(1000) rcall bin2ASCII_digit mov tASCII3, cnt16a ldi tmp16a, low(100) ldi tmp16b, high(100) rcall bin2ASCII_digit mov tASCII2, cnt16a ldi tmp16a, low(10) ldi tmp16b, high(10) rcall bin2ASCII_digit ldi r17,0x30 add r16,r17 add r21,r17 add r25,r17 add r19,r17 add r20,r17 rcall print_ascii ret bin2ASCII_digit: ldi cnt16a, -1 bin2ASCII_digit_loop: inc cnt16a sub fASCIIL, tmp16a sbc fASCIIH, tmp16b brsh bin2ASCII_digit_loop add fASCIIL, tmp16a adc fASCIIH, tmp16b ret
4. Текст модуля iterrupts.asm на языке ассемблера AVR
;Векторы_прерываний ;----------------------------------------------------------------------- .org 0x0000 ; Reset jmp RESET .org 0x0002 ; External Interrupt Request 0 reti .org 0x0004 ; External Interrupt Request 1 reti .org 0x0006 ; Pin Change Interrupt Request 0 reti .org 0x0008 ; Pin Change Interrupt Request 1 reti .org 0x000A ; Pin Change Interrupt Request 2 reti .org 0x000C ; Watchdog Time-out Interrupt reti .org 0x000E ; Timer/Counter 2 Compare Match A reti .org 0x0010 ; Timer/Counter 2 Compare Match B reti .org 0x0012 ; Timer/Counter 2 Overflow jmp Board_timer .org 0x0014 ; Timer/Counter 1 Capture Event reti .org 0x0016 ; Timer/Counter 1 Compare Match A reti .org 0x0018 ; Timer/Counter 1 Compare Match B reti .org 0x001A ; Timer/Counter 1 Overflow rjmp W1_timer ;reti .org 0x001C ; Timer/Counter 0 Compare Match A reti .org 0x001E ; Timer/Counter 0 Compare Match B reti .org 0x0020 ; Timer/Counter 0 Overflow reti .org 0x0022 ; SPI Serial Transfer Complete reti .org 0x0024 ; USART, Rx Complete reti .org 0x0026 ; USART, UDR Empty reti .org 0x0028 ; USART, Tx Complete reti .org 0x002A ; ADC Conversion Complete jmp adc_conv .org 0x002C ; EEPROM Ready reti .org 0x002E ; Analog Comparator reti .org 0x0030 ; Two-wire Serial Interface jmp TWI_int ;reti .org 0x0032 ; Store Program Memory Read reti .org INT_VECTORS_SIZE
5. Текст модуля macr.asm на языке ассемблера AVR
;Макросы ;----------------------------------------------------------------------- .macro pushf push r10 in r10,SREG push r10 .endm .macro popf pop r10 out SREG,r10 pop r10 .endm .macro pushr push r10 in r10,SREG push r10 push r16 push r17 push r18 push r19 push r20 push r21 push r22 push r23 push r25 push r26 push r27 push r28 push r29 .endm .macro popr pop r29 pop r28 pop r27 pop r26 pop r25 pop r23 pop r22 pop r21 pop r20 pop r19 pop r18 pop r17 pop r16 pop r10 out SREG,r10 pop r10 .endm .macro check push @0 lds @0,@1 sts UDR0,@0 check_loop: ldi @0,UCSR0A sbrs @0,TXC0 rjmp check_loop pop @0 rcall Delay .endm .macro check_kosv push @0 ld @0,@1 sts UDR0,@0 check_loop1: ldi @0,UCSR0A sbrs @0,TXC0 rjmp check_loop1 pop @0 rcall Delay .endm .macro check1 sts UDR0,@0 check_loop1: ldi @0,UCSR0A sbrs @0,TXC0 rjmp check_loop1 rcall Delay .endm .macro tabulate push r16 ldi r16,0x09 check1 r16 pop r16 .endm .macro newline push r16 ldi r16,0x0D check1 r16 ldi r16,0x0A check1 r16 pop r16 .endm
6. Текст модуля twi_lib.asm на языке ассемблера AVR
;Библиотека_TWI ;----------------------------------------------------------------------- ;======= Стартовая посылка по шине i2c ================================================= i2c_start: push r16 ldi r16,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)|(1<<TWIE) ; Выполняем посылку стартовой комбинации sts TWCR,r16 ; Посылаем полученный байт в TWCR rcall i2c_wait ; Ожидание формирования start в блоке TWI pop r16 ; Возвращаем данные в r16 из стека ret ;======= Стоповая посылка по шине i2c ================================================== i2c_stop: push r16 ldi r16,(1<<TWINT)|(1<<TWSTO)|(1<<TWEN) ; Отправляем стоповую посылку sts TWCR,r16 ; Посылаем полученный байт в TWCR pop r16 ; Возвращаем данные в r16 из стека ret ;======= Посылка байта информации по шине i2c ========================================== i2c_send: push r16 sts TWDR,r16 ; Записываем передаваемый байт в регистр TWDR ldi r16,(1<<TWINT)|(1<<TWEN)|(1<<TWIE) ; Формируем байт, отвечающий ; за пересылку информационного байта sts TWCR,r16 ; Посылаем полученный байт в TWCR rcall i2c_wait ; Ожидание окончания пересылки байта pop r16 ; Возвращаем данные в r16 из стека ret ;======= Приём информационного байта по шине i2c ======================================= i2c_receive: ; Принятый байт помещается в регистр r16, поэтому рекомендуется ; продумать программу так, чтобы в этот момент в нём не было ; важной информации, байт не сохраняется в стеке в коде данной ; процедуры ldi r16,(1<<TWINT)|(1<<TWEN)|(1<<TWEA)|(1<<TWIE) ; Формируем байт, отвечающий за прием sts TWCR,r16 ; Посылаем полученный байт в TWCR rcall i2c_wait ; Ожидание окончания приёма байта lds r16,TWDR ; Считываем полученную информацию из TWDR ret ;======= Приём последнего байта (NACK) ================================================= i2c_receive_last: ; Принятый байт помещается в регистр r16, поэтому рекомендуется ; продумать программу так, чтобы в этот момент в нём не было ; важной информации, байт не сохраняется в стеке в коде данной ; процедуры ldi r16,(1<<TWINT)|(1<<TWEN)|(1<<TWIE) ; Формируем байт, отвечающий за прием информационного байта sts TWCR,r16 ; Посылаем полученный байт в TWCR rcall i2c_wait ; Ожидание окончания приёма байта lds r16,TWDR ; Считываем полученную информацию из TWDR ret ;======= Ожидание готовности TWI ======================================================= i2c_wait: lds r16,TWCR ; Загружаем значение из TWCR в r16 sbrs r16,TWINT ; Функция ожидания выполняется до тех пор, пока поднят флаг ; прерывания в 1 rjmp i2c_wait ret ;=======================================================================================