Ассемблер (ASM) для AVR в вопросах и ответах
Можно во флэше хранить четверть периода, а перед началом выполнения программы сгенерить полный период в ОЗУ и оттуда херачить. Быстродействие + экономия памяти.
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
- Реклама
- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Выигрыш в быстродействии ровно на 1 такт. ld занимает 2 такта, lpm - 3.
Выигрыш во флэше.
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Зато потеря в оперативке, которой обычно меньше.
Для какого-то круга задач лучше этот метод, для какого-то - хранение всей таблицы во флеше, а для какого-то даже вычисление на лету. Спорить на тему, какой из них самы-самый лучший во всех ситуациях мне неохота.
Для какого-то круга задач лучше этот метод, для какого-то - хранение всей таблицы во флеше, а для какого-то даже вычисление на лету. Спорить на тему, какой из них самы-самый лучший во всех ситуациях мне неохота.
Здравствуйте! Косяк вылез при работе с АЦП на Атмега8. Задача состоит в том чтобы произвести последовательно два замера, первый с одной ножки, и через некоторое время второй, с другой ножки АЦП. И так по циклу, типа меряем два напряжения. По одному оно меряется, а два вместе ну ни в какую! Начинает мерить какое то левое скачущее напряжение, вроде помех каких то.
И после 2-го замера получаю цикличный мусор на обеих входах. Ребята чего делаю не так?
Код: Выделить всё
;включаем модуль АЦП и разрешаем прерывания по замеру
ldi R16, 0b01000000 ;AD_Converter ADMUX byte, включаем опорное напряжение +5в, АЦП выв.0
out ADMUX, R16
ldi R16, 0b10001011 ;AD_Converter ADCSRA byte, делитель 125kHz, и прерывание ЦП по замеру
out ADCSRA, R16
sei ;вкл. прерывания в ЦП
...
;делаем замер включая бит замера АЦП
sbi ADCSRA,6 ;старт замера АЦП
...
ldi R16, 0b01000001 ;меняем ножку АЦП на "1"
out ADMUX, R16 ;ставим на вход ножку АЦП "1"
sbi ADCSRA,6 ;старт 2-го замера АЦП
Немного файлов по зажиганию: ФУОЗ 2.2 + программа правки таблиц 0.987, монтажка
- Реклама
Задержку хорошо бы между переключением каналов поставить чтобы напряжение успело устаканиться.
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Ввел временную задержку и ...немножко подафигел. При малых временных задержках происходит неверный замер. Опытным путем, получил минимальную задержку, на переключение входа АЦП около 1.8сек...
Мне становится жутко, а какое время переключения между входами по мануалу? Может чего либо не допаял на входах АЦП?
Немного файлов по зажиганию: ФУОЗ 2.2 + программа правки таблиц 0.987, монтажка
От части решилась проблема, как всегда гугл и программатор в помощь...
На одном с сайтов написанно:
Получилось где-то вот так:
У меня АЦП работает на 125кГц, получается 8мкс, и пока не пройдет примерно 20 тактов генератора, около 160мкс, корректные данные не замерятся. Может что то допаять на входе АЦП(ATMega8), и будет лучше?
От себя добавлю, что нужно добавить еще и временную задержку, после первого "неточного" замера, и задержка эта, не менее 20 циклов генератора-делителя АЦП... Жуть......При переключении на дифференциальный канал первое преобразование будет характеризоваться плохой точностью из-за переходного процесса в схеме автоматической регулировки смещения. Следовательно, первый результат такого преобразования рекомендуется игнорировать.
Получилось где-то вот так:
Код: Выделить всё
...
ldi R16, 0b01000000 ;AD_Converter ADMUX byte, АЦП ножка 0
out ADMUX, R16
sbi ADCSRA,6 ;старт "ложного" замера АЦП
rcall delay40mks ;задержка, уже была раньше для ЖК, ну и юзаю ту же самую подпрограмму
rcall delay40mks
rcall delay40mks
rcall delay40mks ; всего задержек на 20 циклов генератора АЦП
sbi ADCSRA,6 ;старт "нормального" замера АЦП
...
ldi R16, 0b01000001 ;AD_Converter ADMUX byte, АЦП ножка 1
out ADMUX, R16
sbi ADCSRA,6 ;старт "ложного" замера АЦП
rcall delay40mks
rcall delay40mks
rcall delay40mks
rcall delay40mks
sbi ADCSRA,6 ;старт "нормального" замера АЦП
...
Немного файлов по зажиганию: ФУОЗ 2.2 + программа правки таблиц 0.987, монтажка
- Сообщения: 39
- Зарегистрирован: Пн дек 31, 2012 13:16:59
Так ты же не используешь дифференциальный вход по этому должен быть пофигу этот переходной процесс, которого нет.
У меня все работает без задержек, так же переключаю 2 входа и забираю результат после сброса флага ADIF
может у тебя другая подпрограмма в прерывании портит регистры, в которые забираешь результат ?
У меня все работает без задержек, так же переключаю 2 входа и забираю результат после сброса флага ADIF
может у тебя другая подпрограмма в прерывании портит регистры, в которые забираешь результат ?
Может и не использую, но он не пофигу... Процесс идет вот так:
Старт:
затем инициализация АЦП:
Срабатывает условие старта замера в главной программе
При этом прога идет по прерыванию АЦП adc_complete
Если не переключаю порт АЦП при замерах, то мерить можно без задержек. Четко и гладко. Но если идет переключение входа АЦП в коде, то первый замер будет со сбоем даже через 1.5 секунды
Единственное чего нашел, это сделать пустой первый замер, и задержку в 20 тактов генератора АЦП. Тогда все нормально. Может у меня контроллер паленый или паяльником его перегрел, но с задержкой все нормально. Правда еще не проверяд переключение на 3-4 ножки))
Старт:
Код: Выделить всё
.org 0 ;начало кода
rjmp start
.org 9 ;вектор прер. timer0
rjmp timer ;подпрограмма таймера 4Гц
.org 14 ;вектор прер. АЦП
rjmp adc_complete ;подпрограмма АЦП (срабатывает редко)
Код: Выделить всё
ldi R16, 0b01000000 ;AD_Converter ADMUX byte
out ADMUX, R16
ldi R16, 0b10001011 ;AD_Converter ADCSRA byte, 125kHz
out ADCSRA, R16
sei ;вкл. прерывания в ЦПКод: Выделить всё
sbi ADCSRA,6 ;старт замера АЦПКод: Выделить всё
;====АЦП замер сделан====
adc_complete:
in R9, ADCL
in R8, ADCH
retiНе опрашиваю флаги, использую вектор прерывания, АЦП сам вызывает подпрограмму и возвращается в точку кода.*скрыто* писал(а):...забираю результат после сброса флага ADIF...
Немного файлов по зажиганию: ФУОЗ 2.2 + программа правки таблиц 0.987, монтажка
- Сообщения: 39
- Зарегистрирован: Пн дек 31, 2012 13:16:59
Судя по даташиту, внутрений мультиплексор переключается не после обновления admux, а спустя 1 такт после установки бита ADSC . По этому нет никаких причин делать задержки.
Да, в даташите описано, что смена канала происходит непосредственно при старте преобразования. Это сделано для того, чтобы можно было менять каналы не дожидаясь конца преобразования. Единственный случай, когда требуется задержка - включение запитка Ацп от внутреннего ИОН. И то, только перед первым запуском и если данный ИОН не был включен ранее другой периферией (схемой BOD, например).
А так смотрите, может где-то у Вас большая емкость по входу повисла, либо подаете измеряемый сигнал через большое сопротивление.
А так смотрите, может где-то у Вас большая емкость по входу повисла, либо подаете измеряемый сигнал через большое сопротивление.
Fucking static initialization order fiasco
Напишем маленькую подпрограмму для задержки:
То есть записываем число в два регистра, оно в течении цикла инкрементируется. Это понятно. Но как так получается, что эту подпрограмму можно вызывать много раз и она будет работать? То есть команда subi записывает результат обратно в регистр, после первого вызова переменные delay1 и delay2 будут обнулены, верно?
Код: Выделить всё
DELAY:
ldi delay1,0x80 ; записываем нужное число в переменные, младший разряд
ldi delay2,0x1A ; старший разряд
subi delay1,1 ; создаем цикл уменьшения этого числа на 1
sbci delay2,0 ; вычитаем 1 из старшего разряда, если был перенос
brcc DELAY ; переход, если не было переноса
ret
Полный чайник.
Не думаю, что программа будет корректно работать. Обычно делают такneoneon писал(а):Напишем маленькую подпрограмму для задержки:
То есть записываем число в два регистра, оно в течении цикла инкрементируется. Это понятно. Но как так получается, что эту подпрограмму можно вызывать много раз и она будет работать? То есть команда subi записывает результат обратно в регистр, после первого вызова переменные delay1 и delay2 будут обнулены, верно?
Код: Выделить всё
DELAY:
ldi delay1,0x80 ; записываем нужное число в переменные, младший разряд
ldi delay2,0x1A ; старший разряд
LOOP:
subi delay1,1 ; создаем цикл уменьшения этого числа на 1
sbci delay2,0 ; вычитаем 1 из старшего разряда, если был перенос
brcc LOOP ; переход, если не было переноса
;brcc DELAY ; переход, если не было переноса
retХорошее замечание
Но суть не меняется - вызываем Loop, а после первого вызова переменные delay уже обнулены 
Полный чайник.
Да обнулены. В этом и суть программной задержки. При следующем входе в пп DELAY эти переменные сначала будут установлены, а затем LOOP опять обнулены. Можно ведь делать переменную задержку. Установить сначала переменные, а затем войти в пп LOOP.
Например
Например
Код: Выделить всё
LDI XH,HIGH(5555)
LDI XL,LOW(5555)
RCALL LOOP
.
.
.
LOOP:
SBIW XH:XL,1
BRNE LOOP
RET
Последний раз редактировалось akl Вс янв 04, 2015 18:39:00, всего редактировалось 1 раз.
Обнулены они были бы в том случае, если бы условие проверки было brne, а у Вас получится, что разряды будут равны 0xFF
Fucking static initialization order fiasco
Да, верно. Условие brcc будет выполняться до 0xFFFF.
Спасибо, разобрался
Только не понял про brcc и 0xFF. Если поставить brсс, то когда subi сделает операцию (0-1), получит -1 (то есть FF), команда sbci выполнит операцию (0-1), тоже получит -1 (FF), установится флаг переноса С=1, то программа не перейдет по метке и выйдет из цикла. Если поставить brne, то когда в delay2 установится 00, т.е. сбросится полностью (а в delay1 еще будет FF), установится флаг нулевого результата Z=1, программа выйдет из цикла. Так? 
Полный чайник.
Совершенно верно. При использовании brne будет необходимо проверять отдельно старшую часть и потом отдельно младшую. Иначе программа будет меньше циклов выполняться, чем надо. Обычно делают вложенным циклом проверки младшей части в цикл проверки старшей части.
Fucking static initialization order fiasco


