Инструменты пользователя

Инструменты сайта


doc:1201:643.mgul.12013-01_12_01

Аннотация

В данном программном документе приведен текст программы «telemetry_rev1-1», предназначенной для опроса телеметрических датчиков, подключенных к микроконтроллеру Atmel Atmega328P, и отправки полученных данных по последовательному порту на бортовую ЭВМ. Текст программы реализован в виде символической записи на языке ассемблера AVR. Компилятором является консольная программа для UNIX-подобных операционных систем - avra.

Основной функцией программы telemetry_rev1-1 является опрос и отправка показаний следующих датчиков:

  1. по протоколу I2C:
    1. BMP180 - атмосферное давление и температура окружающей среды;
    2. BH1750 - освещенность;
  2. по протоколу 1-Wire:
    1. DS18B20 - температура элементной базы робота;
  3. аналоговые, с предварительной обработкой АЦП:
    1. ACS712-5A / MAX471 - потребляемый ток;
    2. Датчики напряжения собственного изготовления.

В процессе сбора данных происходит их перевод в двоично-десятичный код и отправка по USB-to-Serial протоколу с сохранением в памяти бортовой ЭВМ.

Программа состоит из основной программы, подключаемых модулей и файла объявления имен регистров:

  • telemetry_rev1-1.asm - основная программа;
  • 1wire.asm - работа с датчиками по 1-Wire протоколу;
  • hextobcd.asm - перевод чисел из шестнадцатеричной системы счисления в двоично-десятичный код;
  • iterrupts.asm - адреса прерываний микроконтроллера;
  • macr.asm - макросы, используемые в основной программе;
  • twi_lib.asm - работа с датчиками по I2C протоколу;
  • m328Pdef.inc - объявление имен регистров и ячеек памяти.

Текст программы telemetry_rev1-1.asm

развернуть

развернуть

  ;----------------------------------------------------
  ; 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); Инициализация стека
  out SPL, R16
  ldi R16, High(RAMEND)
  out SPH, R16
 
  .def try = r21
  .def temp = r16
  .def razr1 = r17
  .def razr2 = r18
  .def razr3 = r19
 
 
  .equ W1_DDR = DDRB ; Присваиваем псевдоним регистрам порта датчиков DS18B20
  .equ W1_PORT = PORTB 
  .equ W1_PIN = PINB 
  .equ W1_BIT = 0 ; Бит порта на котором датчики (8 цифровой контакт на плате Ардуино)
 
  .equ FREQ = 16000000 ; Частота процессора 
  .equ baudrate = 38400; Рассчитываем делитель бодрейта для UART
  .equ bauddivider = FREQ/(16*baudrate)-1
  .equ FreqSCL = 200000; Рассчитываем частоту работы шины TWI
  .equ FreqTWBR = ((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
 


Текст модуля 1wire.asm

развернуть

развернуть

  ;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_подпрограмм


Текст модуля hextobcd.asm

развернуть

развернуть

  .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


Текст модуля iterrupts.asm

развернуть

развернуть

  ;Векторы_прерываний
  ;-----------------------------------------------------------------------
 
  .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


Текст модуля macr.asm

развернуть

развернуть

  ;Макросы
  ;-----------------------------------------------------------------------
  .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


Текст модуля twi_lib.asm

развернуть

развернуть

  ;Библиотека_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
  ;=======================================================================================
doc/1201/643.mgul.12013-01_12_01.txt · Последние изменения: 2018/04/28 23:47 (внешнее изменение)