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

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


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 - объявление имен регистров и ячеек памяти.

1. Текст программы telemetry_rev1-1.asm на языке ассемблера AVR

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