|
Как написать код на ассемблере AVR-на "С"-понятно. |
|
|
|
Sep 21 2013, 18:31
|
Участник

Группа: Участник
Сообщений: 29
Регистрация: 25-01-13
Из: Брянск
Пользователь №: 75 345

|
Цитата(_Pasha @ Sep 21 2013, 19:56)  Не учите людей плохому  Код ldi zL,low(constant1); загрузки по нормальному оформляют в виде макроса ldi zH,high(constant1);
in temp1,ADCL in temp2,ADCH cp temp1,zL cpc temp2,zH brge kakaya_to_metka; или brlo или что там еще Итд в таком же духе Авровский асм имеет много псевдонимов у команд, но они хорошо отражают смысл того, что происходит, поэтому можно не стесняться Здравствуйте Pasha,интересный код сейчас буду разбираться. По рекомендации zombi написал код,если не трудно проверьте пожалуйста. И сомневаюсь там где NOP нодо ли мне это делать.Спасибо. Код .include "m8def.inc" .def temp1 = R16 .def temp2 = R17
.equ cons1 = 256 .equ cons2 = 384
;----вершина стека , инициализация портов,АЦП и т.д
in temp1,ADCL ;младший байт результата АЦП in temp2,ADCH ;старший.................АЦП
cpi temp2,high(cons1) ;сравниваем ADCH с старшим байтом константы 256 breq metka1 ;если temp2 = high(cons1) флаг Z будет установлен и произойдёт переход на metka1
brcs metka2 ;если старший байт ADCH > старшего байта константы 256-high(cons1) то флага C не будет и out PORTD,0b00000011;перехода на metka2 не будет и включим 2 крайних светодиода
rimp step2 ;никчему проверять младшие байты-надо перепрыгнуть на проверку следующей константы
metka1: cpi temp1,low(cons1);в связи с тем ,что старшие байты равны - сравниваем младшие,если байт в ADCL >младшего breq metka3 ;байта константы то и перехода на metka3 не будет и соответственно out PORTD,0b00000011;включим два крайних светодиода
metka2: nop metka3: nop
step2: cpi temp2,high(cons2) ;сравниваем ADCH с старшим байтом константы 384 breq setka1
brcs setka2 out PORTD,0b00000111;включим три крайних светодиода
rimp step3
setka1: cpi temp1,low(cons2) breq setka3 out PORTD,0b00000111;включим три крайних светодиода
setka2: nop setka3: nop
step3:;и так далее в конце надо будет ещё задержку на таймере думать
Сообщение отредактировал serj32 - Sep 21 2013, 20:39
|
|
|
|
|
Sep 22 2013, 04:18
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Посмотрел. 1. out PORTD,0b00000011; - такой команды нет, есть две команды Код ldi r16, 0b00000011; загрузка регистра непосредственными данными out PORTD,r16; вывод в порт значения из регистра 2. Таки переделайте сравнение в то,что я написАл постом ранее, потому что вариант, предложенный Zombi путанный и методологически неправильный.
|
|
|
|
|
Sep 22 2013, 04:31
|
Участник
  
Группа: Свой
Сообщений: 462
Регистрация: 2-04-07
Из: Иркутск
Пользователь №: 26 695

|
Если я правильно понял о чём речь, то в итоге должно получиться что-то вроде индикатора уровня: чем больше значение в ADC, тем больше включено разрядов PORTD. Это можно сделать для 8 сравнений с разными константами и разными значениями для PORTD например так: Код .def temp =R16 .def uL =R20 .def uH =R21 ;--------------------------------- .macro inw ; чтение в RH:RL из ioadrH:ioadrL in @0L, @1L; RL <- ioadrL in @0H, @1H; RH <- ioadrH .endm ;--------------------------------- .macro cpiw ; сравнение RH:RL с 16-бит константой ldi temp, high(@1); используя временный регистр cpi @0L, low(@1); сравнить младшие байты cpc @0H, temp; сравнить старшие байты с учётом переноса .endm ;--------------------------------- .macro caseADC cpiw u, @0 ; сравнить значение u с 16-бит константой brlo skip ; перейти, если u < const ldi temp, @1; иначе загрузить в temp значение для вывода в PORTD rjmp done ; выход, пропустить все оставшиеся сравнения skip: ; перейти к следующему сравнению .endm ;--------------------------------- ; выше было только описание констант, макросов и регистров ; вот сама программа:
inw u, ADC ; прочитать в uH:uL значение из ADCH:ADCL caseADC 1001, 0b11111111; сравниваем от бОльших значений caseADC 701, 0b01111111; к меньшим caseADC 526, 0b00111111 caseADC 394, 0b00011111 caseADC 296, 0b00001111 caseADC 222, 0b00000111 caseADC 166, 0b00000011 caseADC 125, 0b00000001 ldi temp, 0b00000000; значение для PORTD в случае, когда ADC<min done: out PORTD, temp ; выводим в PORTD значение, соответствующее ADC
|
|
|
|
|
Oct 10 2013, 17:59
|
Участник

Группа: Участник
Сообщений: 29
Регистрация: 25-01-13
Из: Брянск
Пользователь №: 75 345

|
Считаю,что тема была бы не законченной не приведя законченный код индикатора.Спасибо всем за помощь. Не сомневаюсь,что не совсем хорошо,но я ещё только начинающий. Код ;****************************************** ;Автор: * ;Дата :10/10/2013 * ;Имя файла:indADC.asm * ;Для AVR : ATmega8A,в корпусе DIP28 * ;Тактовая частота:3.686 Мгц. * ;Исследование АЦП. Индикатор на * ;светодиодах.Прерывание .Однократный * ;режим преобразования АЦП. * ;****************************************** .include "m8Adef.inc" ;Файл определений для ATmega8A .list ;Включение листинга .def temp = r16 ;Временный регистр .def leder = r19 ;Регистр индикации .def temp1 = r20 ;**** Описание макроса ********************
.macro caseADC ldi temp1,high(@2) cpi zL,low(@2) cpc zH,temp1 brlo t@0 ldi leder,@1 out PORTD,leder t@0: .endm
;****Векторы прерываний ******************* .org $0 ;Установка текущего адреса на ноль по "RESET" rjmp init ;Переход на начало программы
.org $00E ;Вектор прерывания АЦП rjmp adca ;преобразование завершено ; ;****Модуль инициализации******************
init: ldi temp,low(RAMEND) ;Установка указателя стека out SPL,temp ;на последнюю ldi temp,high(RAMEND) ;ячейку out SPH,temp ;ОЗУ ldi temp,0b11111111 ;Порт PD на вывод out DDRD,temp ;используем выводы PD0...PD7 out PORTD,temp ;Погасим светодиоды на PD0...PD7
clr temp ;Аналоговые входы порта PC out DDRC,temp ;на выводе PC0 "сидит" канал ADC0 out PORTC,temp ;отключаем подтягивающие резисторы ;****Инициализация АЦП ********************* ldi temp,0b10001101 ;ADEN=1,ADIE=1,Fadc=Fclk/32,ADFR=0(режим однократного преобразования) out ADCSRA,temp ;Fadc=115 кГц при Fclk=3,69 МГц ldi temp,0b01000000 ;Выбираем канал ADC0 по выводу PC0 out ADMUX,temp ;Опорное напряжение AVCC=VCC равно напр.питания 5 вольт,ADLAR=0 (выравнивание по правому) sei ;Разрешение прерываний sbi ADCSRA,ADSC ;Запуск преобразования loop: rjmp loop ;Цикл ожидания прерываний ;****Обработка прерывания от АЦП ********** adca: in zL,ADCL ; in zH,ADCH ;
cbi ADCSRA,ADIE ;Запрет прерывания от АЦП ldi temp1,high(128) cpi zL,low(128) cpc zH,temp1 brlo t0 ldi leder,0b11111110 out PORTD,leder
rjmp t1 t0: ldi leder,0b11111111 out PORTD,leder
t1: caseADC 2,0b11111100,256 caseADC 3,0b11111000,384 caseADC 4,0b11110000,512 caseADC 5,0b11100000,640 caseADC 6,0b11000000,768 caseADC 7,0b10000000,896 caseADC 8,0b00000000,1020 sbi ADCSRA,ADIE ;Разрешение прерывания от АЦП sbi ADCSRA,ADSC ;Пуск преобразования reti
|
|
|
|
|
Oct 10 2013, 20:46
|
практикующий тех. волшебник
    
Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417

|
Цитата(serj32 @ Oct 10 2013, 21:59)  Код ..... .org $0 ;Установка текущего адреса на ноль по "RESET" rjmp init ;Переход на начало программы
.org $00E ;Вектор прерывания АЦП rjmp adca ;преобразование завершено ; ;****Модуль инициализации****************** ... ldi temp,0b11111111 ;Порт PD на вывод ...;****Обработка прерывания от АЦП ********** ... Код .org $00E и иже лучше писать как Код .org INT6addr где INT6addr это объявленное уже(!) смещение в файлики который вы с верху в исходнике заинклюдили, то биш "m8Adef.inc" код лучше расположить за таблицей векторов и сначала вставить обработчик прерывания АЦП, потом вспомогательные функции, а в конце основную программу, в задачи которой входит инициализация всего и всех. маски в регистр лучше загружать человекопонятными. Т.е. перед кодом (или в своём отдельном инклудники) делаете дефайны, а потом их юзаете на масках. Это если их нет в волшебном файлике "m8Adef.inc" (что редкость!). тогда код будет читаться более понятнее (даже через пару десяткофф лет). Как пример: Код ori tempA,((1 << LED_DIG1) | (1 << LED_DIG2) | (1 << LED_DIG3)) .... ori tempA,(1 << OCIE0) out TIMSK,tempA это так-же можно применять к портам и пинам вывода-ввода информации. Тогда вы получаете следующие профиты: 1) код легче портируем, наименование порта меняется в заголовке файла или инклудника. 2) код легче читаем - понятно что в порт(к примеру) дисплея вывели символ, или там выдали разрешение, или там синхросигнал... 3) код легче воспринимаем - т.к. идёт абстрагирование от конкретного порта, вольно или не вольно человек концентрируется на логике кода, а не названии порта и его соответствие со схемой.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|