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

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


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

<code asm>;————————————————————————————————————– ; Program : telemetry_rev1-1 ; Compiler : AVRA ; Chip type : ATmega328P ; System Clock : 16 MHz ; Date : 18.01.2017 ;————————————————————————————————————– ;————————————Подключение_библиотек_и_резервация—————————————- ;——————————————–места_под_данные————————————————– ;————————————————————————————————————–

	.include "m328Pdef.inc"

;————————————————————————————————————–

.dseg

adc_data:

	.byte	8

Trm: ; Ячейки ОЗУ под показания датчиков DS18B20

	.byte	14	

bmp_temp: ; Ячейки ОЗУ под показания темп. датчика BMP180

	.byte	2

bmp_pres: ; Ячейки ОЗУ под показания давления датчика BMP180

      	.byte	2

bh_lux:

	.byte	2

;————————————————————————————————————–

.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				; Запрещаем прерывания в основном цикле
	;rcall	Board_timer

;———————-print_time——————-

	
	pushr
	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
	pushr
	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
	pushr
	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			; Запрещаем прерывания
	;rcall	Board_timer
	
	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
	;rcall	Board_timer
	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
	pushf			; На всякий случай отправляем в стек SREG
	ldi	ZL, LOW(Trm)	; Делаем косвенную адресацию на массив данных температуры датчиков DS18B20
	ldi	ZH, HIGH(Trm)
	clr	r20

print1: ; Цикл печати данных

	inc	r20
	pushr
	ld	r16,Z
	adiw	ZH:ZL,1
	ld	r17,Z
	adiw	ZH: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
	
	;lds	r16,TIFR2
	;andi	r16,0b00000001
	;sbrs	temp,TOV2
	;ret
	
	pushf
	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				; Запрещаем прерывания
	;rcall	Board_timer
	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: pop r16 ; Возвращаем 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: .db 0x28,0xFF,0x41,0x3,0xA3,0x15,0x1,0xBB ; Адреса датчиков DS18B20 Addr2: .db 0x28,0xFF,0xE2,0x1A,0xA2,0x15,0x4,0xF9 Addr3: .db 0x28,0xFF,0x91,0xF,0xA3,0x15,0x4,0xC8 Addr4: .db 0x28,0xFF,0x90,0x82,0xA3,0x15,0x4,0x41 Addr5: .db 0x28,0xFF,0xC6,0xB,0xA3,0x15,0x4,0x2 Addr6: .db 0x28,0xFF,0x9,0x5D,0xA3,0x15,0x4,0x9E Addr7: .db 0x28,0xFF,0x7F,0x83,0xA3,0x15,0x4,0x7B

Delay: ; Стандартная задержка

	pushf
	ldi	razr1, 50
	ldi	razr2, 10

Pdelay:

	dec	razr1
	brne	Pdelay
	dec	razr2
	brne	Pdelay
	popf
	ret

Delay1: ; Стандартная задержка 1

	pushf
	ldi	razr1, 50
	ldi	razr2, 50
	ldi	razr3, 1

Pdelay1:

	dec	razr1
	brne	Pdelay1
	dec	razr2
	brne	Pdelay1
	dec	razr3
	brne	Pdelay1
	popf
	ret

</code asm>

doc/1201/643.mgul.12013-01_12_01.1487027347.txt.gz · Последние изменения: 2018/04/28 23:47 (внешнее изменение)