АЦП и внешнее прерывание в ATtiny13
- nightghost
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Вт фев 16, 2010 13:23:20
АЦП и внешнее прерывание в ATtiny13
Здравствуйте! Друзья помогите разобраться с причиной того, почему не работает, АЦП и внешнее прерывание в tiny13? Возможно я, что-то напортачил с настройкой.
При подключении переменника и вращении в определенный момент должен появляться высокий лог. уровень на PB4, тоже самое и с внешним прерыванием, при нажатии на кнопку.
#include <avr/io.h>
#define F_CPU 12000000UL
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/sfr_defs.h>
unsigned char s;
unsigned int RezultatACP;
ISR (ADC_vect)
RezultatACP = ADCW;
if (RezultatACP < 2046)
{
s=1;
}
else
{
s=0;
}
ADCSRA = ADCSRA | 0x40;
}
ISR (INT0_vect)
{
_delay_ms(20);
PORTB |= (1<<PB4);
}
int main(void)
{
DDRB |= (1<<PB2)|(1<<PB4);
PORTB |= (1<<PB0);
ADMUX = 3;
ADCSRA = 0xCE
MCUCR = (1<<ISC01)| (1<<ISC00);
GIMSK = (1<<INT0);
sei();
while(1)
{
if (bit_is_clear(PINB,PB0))
{
if (s==1)
{
PORTB|=(1<<PB4);
}
}
else
{
PORTB&=~(1<<PB4);
}
}
}
При подключении переменника и вращении в определенный момент должен появляться высокий лог. уровень на PB4, тоже самое и с внешним прерыванием, при нажатии на кнопку.
#include <avr/io.h>
#define F_CPU 12000000UL
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/sfr_defs.h>
unsigned char s;
unsigned int RezultatACP;
ISR (ADC_vect)
RezultatACP = ADCW;
if (RezultatACP < 2046)
{
s=1;
}
else
{
s=0;
}
ADCSRA = ADCSRA | 0x40;
}
ISR (INT0_vect)
{
_delay_ms(20);
PORTB |= (1<<PB4);
}
int main(void)
{
DDRB |= (1<<PB2)|(1<<PB4);
PORTB |= (1<<PB0);
ADMUX = 3;
ADCSRA = 0xCE
MCUCR = (1<<ISC01)| (1<<ISC00);
GIMSK = (1<<INT0);
sei();
while(1)
{
if (bit_is_clear(PINB,PB0))
{
if (s==1)
{
PORTB|=(1<<PB4);
}
}
else
{
PORTB&=~(1<<PB4);
}
}
}
- COKPOWEHEU
- Говорящий с текстолитом
- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Re: АЦП и внешнее прерывание в ATtiny13
"тонкий" намек: какие значения может принимать регистр ADCW с вашими настройками?RezultatACP = ADCW;
if (RezultatACP < 2046)
За такое (и за отсутствие форматирования в целом) по рукам бить надо. Хотя прерывание Int0 настроено по-человечески (случайность?).#define F_CPU 12000000UL
ADMUX = 3;
ADCSRA = 0xCE
ADCSRA = ADCSRA | 0x40;
Переменная RezultatACP (почему не назвать по-нормальному, adc_result хотя бы?..) объявлена глобальной, но используется только в прерывании. Логичнее было ее сделать локальной.
Переменная s (офигеть информативное название) объявлена глобально, используется в прерывании и в основной программе, но не объявлена volatile. Это ошибка!
Из описания непонятно чего вы пытаетесь добиться и что именно не получается.
Вчитываться в этот неформатированный ужас особого желания нет, но, похоже, дребезг не обрабатывается. Если так, у вас программа на пограничных значениях будет постоянно в прерывание заходить.
- nightghost
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Вт фев 16, 2010 13:23:20
Re: АЦП и внешнее прерывание в ATtiny13
[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=3152415#p3152415"]
Переменная RezultatACP (почему не назвать по-нормальному, adc_result хотя бы?..) объявлена глобальной, но используется только в прерывании. Логичнее было ее сделать локальной.
Переменная s (офигеть информативное название) объявлена глобально, используется в прерывании и в основной программе, но не объявлена volatile. Это ошибка!
Из описания непонятно чего вы пытаетесь добиться и что именно не получается.
Вчитываться в этот неформатированный ужас особого желания нет, но, похоже, дребезг не обрабатывается. Если так, у вас программа на пограничных значениях будет постоянно в прерывание заходить.[/uquote]
Какая разница как назвать переменные от этого по другому они работать не станут? Просто назвал как удобнее))
Тогда как правильно (форматированно) обработать дребезг в прерывании?
PS а намек понял...спасибо!)
"тонкий" намек: какие значения может принимать регистр ADCW с вашими настройками?RezultatACP = ADCW;
if (RezultatACP < 2046)
За такое (и за отсутствие форматирования в целом) по рукам бить надо. Хотя прерывание Int0 настроено по-человечески (случайность?).#define F_CPU 12000000UL
ADMUX = 3;
ADCSRA = 0xCE
ADCSRA = ADCSRA | 0x40;
Переменная RezultatACP (почему не назвать по-нормальному, adc_result хотя бы?..) объявлена глобальной, но используется только в прерывании. Логичнее было ее сделать локальной.
Переменная s (офигеть информативное название) объявлена глобально, используется в прерывании и в основной программе, но не объявлена volatile. Это ошибка!
Из описания непонятно чего вы пытаетесь добиться и что именно не получается.
Вчитываться в этот неформатированный ужас особого желания нет, но, похоже, дребезг не обрабатывается. Если так, у вас программа на пограничных значениях будет постоянно в прерывание заходить.[/uquote]
Какая разница как назвать переменные от этого по другому они работать не станут? Просто назвал как удобнее))
Тогда как правильно (форматированно) обработать дребезг в прерывании?
PS а намек понял...спасибо!)
- COKPOWEHEU
- Говорящий с текстолитом
- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Re: АЦП и внешнее прерывание в ATtiny13
Форматирование, комментарии и осмысленные названия переменных нужны не непосредственно для правильной работы программы, а чтобы упростить себе и другим анализ кода - где какой блок начинается и заканчивается, какая переменная для чего предназначена, чего автор хотел добиться тем или иным блоком кода. Туда же использование именованных битов в том же ADCSRA - я, например, не помню какой за что отвечает, но если бы было написано, скажем, ADCSRA = (1<<ADIE | 0b001<<ADPS0) была бы сразу заметна ошибка, а то и не одна.
Кажется, у Макконела было что-то вроде "если мне принесут посмотреть вот такой код я скажу сначала привести его в читаемый вид. Если вот сякой - посмотрю по настроению, поскольку глаза не режет, а если вот эдакий - прочитаю обязательно". Потому что можно сконцентрироваться на логике, а не на подробностях реализации.
Впрочем, я пока не представляю задачу в которой одновременно измеряется напряжение с помощью АЦП и приближенно оценивается его уровень с помощью внешнего прерывания. Требуется реакция на пересечение порога (угу, на IO выводе с неизвестным уровнем срабатывания и гистерезисом) со задержкой менее 30 мкс (что обеспечивается АЦП)? Даже если так, аналоговый компаратор точнее обычного прерывания.
В последнем проекте у меня фигурирует вот такой макрос
У всех входящих в него констант есть физический смысл - сопротивления резисторов (в Омах или миллиОмах), опорное напряжение АЦП (в милливольтах), разрядность каналов. Все их можно напрямую или косвенно измерить для конкретной платы и контроллера. Более правильно было бы хранить эту константу в EEPROM'e, но для одиночного изделия и так неплохо.
Кажется, у Макконела было что-то вроде "если мне принесут посмотреть вот такой код я скажу сначала привести его в читаемый вид. Если вот сякой - посмотрю по настроению, поскольку глаза не режет, а если вот эдакий - прочитаю обязательно". Потому что можно сконцентрироваться на логике, а не на подробностях реализации.
А нужно ли в прерывании? Опрос кнопок (хоть одной, хоть всех) проще делать по таймеру с интервалом 10 - 500 мс, либо в бесконечном цикле с тем же периодом: точность времени тут не важна.Тогда как правильно (форматированно) обработать дребезг в прерывании?
Впрочем, я пока не представляю задачу в которой одновременно измеряется напряжение с помощью АЦП и приближенно оценивается его уровень с помощью внешнего прерывания. Требуется реакция на пересечение порога (угу, на IO выводе с неизвестным уровнем срабатывания и гистерезисом) со задержкой менее 30 мкс (что обеспечивается АЦП)? Даже если так, аналоговый компаратор точнее обычного прерывания.
А зря, потому что в зависимости от настроек диапазон меняется: (0...255), (0...1023), (0...65472) и даже (0...3). Кстати, может вам и не надо все 10 бит, а хватит и 8? Работа с 8-битными переменными проще и быстрее. Ну и не стоит использовать магические числа, берущиеся непонятно откуда. Лучше объявить константу или макрос (в gcc-avr макрос обычно удобнее), напримерPS а намек понял...спасибо!)
Код: Выделить всё
#define MAX_TEMPERATURE_C 100 //максимальная температура, в градусах Цельсия
#define Temp2ADC(t) (1024*(t+273)) //например, такая формула. Взята от балды так что физический смысл коэффициентов не знаю, но в реальном коде его стоит расписать
...
if( ADC > Temp2ADC(MAX_TEMPERATURE) ){...}Код: Выделить всё
#define P_koeff ((uint32_t)( \
((( \
((( \
( ( (8* R_DL_Ohm*R_sh_mOhm*1024/ (R_DH_Ohm+R_DL_Ohm) )+1 )/2 ) \
*1024/U_ref_mV)+1)/2) \
*1000/U_ref_mV)+1)/2) \
))- nightghost
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Вт фев 16, 2010 13:23:20
Re: АЦП и внешнее прерывание в ATtiny13
[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=3152729#p3152729"]Форматирование, комментарии и осмысленные названия переменных нужны не непосредственно для правильной работы программы, а чтобы упростить себе и другим анализ кода - где какой блок начинается и заканчивается, какая переменная для чего предназначена, чего автор хотел добиться тем или иным блоком кода. Туда же использование именованных битов в том же ADCSRA - я, например, не помню какой за что отвечает, но если бы было написано, скажем, ADCSRA = (1<<ADIE | 0b001<<ADPS0) была бы сразу заметна ошибка, а то и не одна.
Кажется, у Макконела было что-то вроде "если мне принесут посмотреть вот такой код я скажу сначала привести его в читаемый вид. Если вот сякой - посмотрю по настроению, поскольку глаза не режет, а если вот эдакий - прочитаю обязательно". Потому что можно сконцентрироваться на логике, а не на подробностях реализации.
Впрочем, я пока не представляю задачу в которой одновременно измеряется напряжение с помощью АЦП и приближенно оценивается его уровень с помощью внешнего прерывания. Требуется реакция на пересечение порога (угу, на IO выводе с неизвестным уровнем срабатывания и гистерезисом) со задержкой менее 30 мкс (что обеспечивается АЦП)? Даже если так, аналоговый компаратор точнее обычного прерывания.
В последнем проекте у меня фигурирует вот такой макрос
У всех входящих в него констант есть физический смысл - сопротивления резисторов (в Омах или миллиОмах), опорное напряжение АЦП (в милливольтах), разрядность каналов. Все их можно напрямую или косвенно измерить для конкретной платы и контроллера. Более правильно было бы хранить эту константу в EEPROM'e, но для одиночного изделия и так неплохо.[/uquote]
О форматировании кода вы меня убедили, будем стараться))
Конечно можно было проще использовать и компаратор, и опрос кнопок в прерываниях, но это просто эксперимент и изучение attiny13 на будущее. Жаль мало информации на русском об этом МК, надо курить даташит на заграничном, а времени совсем мало, видать в этом-то и проблема
Как при 10 бит может быть (0...65472) (0...3)...?
И о каких магические числах вы имеете в виду?
Кажется, у Макконела было что-то вроде "если мне принесут посмотреть вот такой код я скажу сначала привести его в читаемый вид. Если вот сякой - посмотрю по настроению, поскольку глаза не режет, а если вот эдакий - прочитаю обязательно". Потому что можно сконцентрироваться на логике, а не на подробностях реализации.
А нужно ли в прерывании? Опрос кнопок (хоть одной, хоть всех) проще делать по таймеру с интервалом 10 - 500 мс, либо в бесконечном цикле с тем же периодом: точность времени тут не важна.Тогда как правильно (форматированно) обработать дребезг в прерывании?
Впрочем, я пока не представляю задачу в которой одновременно измеряется напряжение с помощью АЦП и приближенно оценивается его уровень с помощью внешнего прерывания. Требуется реакция на пересечение порога (угу, на IO выводе с неизвестным уровнем срабатывания и гистерезисом) со задержкой менее 30 мкс (что обеспечивается АЦП)? Даже если так, аналоговый компаратор точнее обычного прерывания.
А зря, потому что в зависимости от настроек диапазон меняется: (0...255), (0...1023), (0...65472) и даже (0...3). Кстати, может вам и не надо все 10 бит, а хватит и 8? Работа с 8-битными переменными проще и быстрее. Ну и не стоит использовать магические числа, берущиеся непонятно откуда. Лучше объявить константу или макрос (в gcc-avr макрос обычно удобнее), напримерPS а намек понял...спасибо!)
Код: Выделить всё
#define MAX_TEMPERATURE_C 100 //максимальная температура, в градусах Цельсия
#define Temp2ADC(t) (1024*(t+273)) //например, такая формула. Взята от балды так что физический смысл коэффициентов не знаю, но в реальном коде его стоит расписать
...
if( ADC > Temp2ADC(MAX_TEMPERATURE) ){...}Код: Выделить всё
#define P_koeff ((uint32_t)( \
((( \
((( \
( ( (8* R_DL_Ohm*R_sh_mOhm*1024/ (R_DH_Ohm+R_DL_Ohm) )+1 )/2 ) \
*1024/U_ref_mV)+1)/2) \
*1000/U_ref_mV)+1)/2) \
))О форматировании кода вы меня убедили, будем стараться))
Конечно можно было проще использовать и компаратор, и опрос кнопок в прерываниях, но это просто эксперимент и изучение attiny13 на будущее. Жаль мало информации на русском об этом МК, надо курить даташит на заграничном, а времени совсем мало, видать в этом-то и проблема
Как при 10 бит может быть (0...65472) (0...3)...?
И о каких магические числах вы имеете в виду?
- COKPOWEHEU
- Говорящий с текстолитом
- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Re: АЦП и внешнее прерывание в ATtiny13
Вся информация из даташита переведена Евстифеевым "Микроконтроллеры AVR семейства tiny"
Магические числа - 2048 с которым вы сравниваете результат АЦП, инициализирующие значения для ADCSRA и т.п.
Про разрядность АЦП - бит ADLAR, выравнивание либо по старшему, либо по младшему биту. При выравнивании по младшему, можно использовать только ADCH - будет 2 значащих бита, диапазон (0...3), если выравнивание по старшему - парный регистр ADC принимает значения (0...65472) - 10 старших битов. Не особо представляю, где эти диапазоны могут пригодиться, но теоретически - возможно.
Магические числа - 2048 с которым вы сравниваете результат АЦП, инициализирующие значения для ADCSRA и т.п.
Про разрядность АЦП - бит ADLAR, выравнивание либо по старшему, либо по младшему биту. При выравнивании по младшему, можно использовать только ADCH - будет 2 значащих бита, диапазон (0...3), если выравнивание по старшему - парный регистр ADC принимает значения (0...65472) - 10 старших битов. Не особо представляю, где эти диапазоны могут пригодиться, но теоретически - возможно.
- nightghost
- Первый раз сказал Мяу!
- Сообщения: 25
- Зарегистрирован: Вт фев 16, 2010 13:23:20
Re: АЦП и внешнее прерывание в ATtiny13
Понятно, спасибо, что просветили 
- Z_h_e
- Собутыльник Кота
- Сообщения: 2708
- Зарегистрирован: Сб май 14, 2011 21:16:04
- Откуда: г. Чайковский
Re: АЦП и внешнее прерывание в ATtiny13
Если не нужен точный АЦП, настраиваете выравнивание слева и считываете только ADCH. Получается 8ми битный АЦП без дополнительных операций.COKPOWEHEU писал(а): Не особо представляю, где эти диапазоны могут пригодиться
- COKPOWEHEU
- Говорящий с текстолитом
- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Re: АЦП и внешнее прерывание в ATtiny13
Невнимательно читаете: речь шла про режимы с выравниванием младшего бита и считыванием ADCH - диапазон (0...3) и с выравниванием по старшему с использованием обоих регистров - диапазон (0...65472). Впрочем, последнее может и пригодиться если где-то в вычислениях нужно умножение на 16-64.
