Страница 1 из 1
AtMega16 - Проблема с кодом АЦП
Добавлено: Вс ноя 11, 2012 03:38:44
stridemann
Первый раз делаю код с использованием АЦП. В принципе выучил все регистры и биты по части АЦП.. Но все же не работает..
Код: Выделить всё
#include <avr/io.h>
#include <avr/interrupt.h>
#define StartConvAdc() ADCSRA |= (1<<ADSC)
#define KEY_NULL 0
#define KEY_S1 1
#define KEY_S2 2
#define KEY_S3 3
#define KEY_S4 4
volatile unsigned char KeyBuf = 0;
int main(void)
{
DDRC = 0xff;
PORTC = 0xff;
unsigned char tmp;
ADMUX = (0<<REFS1)|(1<<REFS0)|(1<<ADLAR)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0); //
ADCSRA = (1<<ADEN)|(1<<ADSC)|(0<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // вкл. ацп, режим одиночного преобр., разрешение прер., частота преобр. = FCPU/128
StartConvAdc(); // Запустить преобразование
while(1)
{
tmp = KeyBuf;
if (tmp)
{
tmp--;
PORTC = ~(1<<tmp);
}
else
PORTC = 0xff;
}
return 0;
}
#pragma vector=ADC_vect
_AVR_INTERRUPT_H_ void adc_my(void)
void adc_my(void)
{ //Ошибку в этом месте выдает
sei();
unsigned char AdcBuf = ADCH;
if (AdcBuf > 240) //опеределяем в какой диапазон попадает его значение
KeyBuf = KEY_S4;
else if (AdcBuf > 180)
KeyBuf = KEY_S3;
else if (AdcBuf > 120)
KeyBuf = KEY_S2;
else if (AdcBuf > 35)
KeyBuf = KEY_S1;
else
KeyBuf = KEY_NULL;
StartConvAdc(); //запускаем преобразование и выходим
{
}
Взято с
http://chipenable.ru/index.php/programm ... ast-2.html
Схема подключения
Не смотря на ошибку со открытой скобкой в конце (которой вроде как не должно быть, но без нее ошибка), выдается ошибка
Error 2 expected '=', ',', ';', 'asm' or '__attribute__' before '{' token (обозначил это месте в коде).
В чем проблема?
Заменил только
__interrupt на
_AVR_INTERRUPT_H_, как в заголовочнике
avr/interrupt.h (ибо код был писан вроде как на CodeVisionAVR ). Правильно же?
Даже если этот interrupt заменить на sei(); , и код без ошибок компилится, то схема не работает. При подключении питания мигнут быстро 2 светодиода из всех и дальше тишина.. (не смотря на изменения напряжений на входе АЦП).
Re: AtMega16 - Проблема с кодом АЦП
Добавлено: Вс ноя 11, 2012 23:18:55
ibiza11
объясните, зачем в основном цикле декрементируется переменная tmp?
функцию вот так перепишите:
Код: Выделить всё
void adc_my(void)
{ //Ошибку в этом месте выдает
sei();
unsigned char AdcBuf = ADCH;
if (AdcBuf > 240) //опеределяем в какой диапазон попадает его значение
KeyBuf = KEY_S4;
else if (AdcBuf > 180)
KeyBuf = KEY_S3;
else if (AdcBuf > 120)
KeyBuf = KEY_S2;
else if (AdcBuf > 35)
KeyBuf = KEY_S1;
else
KeyBuf = KEY_NULL;
StartConvAdc(); //запускаем преобразование и выходим
}
по поводу
__interrupt вряд ли кто-то ответит точно, до того, как вы признаетесь каким компилятором пользуетесь.
Re: AtMega16 - Проблема с кодом АЦП
Добавлено: Пн ноя 12, 2012 03:05:01
stridemann
Спасибо за ответ!
Пардон, забыл написать что
исполюзую AVR Studio.
Такой код:
Не работает. Вообще молчит.
Код: Выделить всё
#include <avr/io.h>
#include <avr/interrupt.h>
#define StartConvAdc() ADCSRA |= (1<<ADSC)
#define KEY_NULL 0
#define KEY_S1 1
#define KEY_S2 2
#define KEY_S3 3
#define KEY_S4 4
volatile unsigned char KeyBuf = 0;
int main(void)
{
DDRC = 0xff;
PORTC = 0xff;
unsigned char tmp;
ADMUX = (0<<REFS1)|(1<<REFS0)|(1<<ADLAR)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0); //
ADCSRA = (1<<ADEN)|(1<<ADSC)|(0<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // вкл. ацп, режим одиночного преобр., разрешение прер., частота преобр. = FCPU/128
sei();
StartConvAdc(); // Запустить преобразование
while(1)
{
tmp = KeyBuf;
if (tmp)
{
tmp--;
PORTC = ~(1<<tmp);
}
else
PORTC = 0xff;
}
return 0;
}
#pragma vector=ADC_vect
void adc_my(void)
{ //Ошибку в этом месте выдает
sei();
unsigned char AdcBuf = ADCH;
if (AdcBuf > 240) //опеределяем в какой диапазон попадает его значение
KeyBuf = KEY_S4;
else if (AdcBuf > 180)
KeyBuf = KEY_S3;
else if (AdcBuf > 120)
KeyBuf = KEY_S2;
else if (AdcBuf > 35)
KeyBuf = KEY_S1;
else
KeyBuf = KEY_NULL;
StartConvAdc(); //запускаем преобразование и выходим
}
А вот такой код работает:
Код: Выделить всё
#include <avr/io.h>
#include <avr/interrupt.h>
ISR(ADC_vect)
{
PORTD = ADCH; // Output ADCH to PortD
ADCSRA |= 1<<ADSC; // Start Conversion
}
int main(void)
{
DDRD = 0xFF; // Configure PortD as output
DDRA = 0x00; // Configure PortA as input
// PA0 is ADC0 input
ADCSRA = 0x8F; // Enable the ADC and its interrupt feature
// and set the ACD clock pre-scalar to clk/128
ADMUX = 0xE0; // Select internal 2.56V as Vref, left justify
// data registers and select ADC0 as input channel
sei(); // Enable Global Interrupts
ADCSRA |= 1<<ADSC; // Start Conversion
while(1); // Wait forever
}
Re: AtMega16 - Проблема с кодом АЦП
Добавлено: Пн ноя 12, 2012 03:07:44
stridemann
Мне вот что посоветовали..
В модуле interrupts.h есть функции:
cli(); - глобально запрещает все прерывания.
sei(); - глобально разрешает все прерывания.
Тебе нужна вторая.
Вообще я рекомендовал бы тебе юзать эти функции в обработчике прерывания. То есть к примеру так:
SIGNAL(__vect_7)
{
cli();
...... //Что-то делаем
sei();
}
sei(); я использовал.. А вот с этим сигналом.. Не понимаю как его использовать..
Re: AtMega16 - Проблема с кодом АЦП
Добавлено: Пн ноя 12, 2012 03:25:16
stridemann
ibiza11 писал(а):объясните, зачем в основном цикле декрементируется переменная tmp?
Нуу.. Она содержит в себе данные с переменной KeyBuf.. Хотя если я Вас правильно понял, то можно и без нее..
немножко вырезать кода и получится:
PORTC = ~(1<<KeyBuf;);
if (AdcBuf > 240)
KeyBuf = KEY_S4;
else if (AdcBuf > 180)
KeyBuf = KEY_S3;
else if (AdcBuf > 120)
KeyBuf = KEY_S2;
else if (AdcBuf > 35)
KeyBuf = KEY_S1;
else
KeyBuf = KEY_NULL;
Только я не понимаю зачем
tmp--
UPD.
Крутил, мутил, так у меня ничего и не вышло..
Помогите плс с кодом..

Re: AtMega16 - Проблема с кодом АЦП
Добавлено: Пн ноя 12, 2012 05:02:23
stridemann
Прошу прощения за кучу постов, но я так разделяю свои... мыслы, скажем так..
PS.
Вот на этом коде работает.. На светодиоды выводятся значение рагистра ADCH Значит проблемы с кодом а не со схемой.. (на макетной плате собираю.. )
Код: Выделить всё
#include <avr/io.h>
#include <avr/interrupt.h>
int main(void)
{
DDRD = 0xFF;
PORTD = 0xFF;
PORTD = ADCH;
ADMUX = (0<<REFS1)|(1<<REFS0)|(1<<ADLAR)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0); //
ADCSRA = (1<<ADEN)|(1<<ADSC)|(0<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // вкл. ацп, режим одиночного преобр., разрешение прер., частота преобр. = FCPU/128
sei();
ADCSRA |= 1<<ADSC;
while(1);
}
Re: AtMega16 - Проблема с кодом АЦП
Добавлено: Пн ноя 12, 2012 10:29:39
ibiza11
в общем алгоритм программы такой:
1) инициализируем порты ввода/вывода
2) инициализируем АЦП, включаем прерывание окончания преобразования и запускаем преобразование
3) разрешаем глобальные прерывания
4) В безконечном цикле проверяем переменную KeyBuf ---> 4)
прерывание окончания преобразования АЦП:
1) чтение значения преобразования
2) сравнение его с границами значений
3) установка переменной KeyBuf
4) запуск очередного преобразования
5) выход
Вы разберитесь какой кусок кода за что из вышеприведенного списка отвечает и вставляйте последовательно в код. Вот и все)
Re: AtMega16 - Проблема с кодом АЦП
Добавлено: Вт ноя 13, 2012 18:25:36
stridemann
Спасибо за помощь!
Но сам код я знаю идеально, что и как делает. Ошибку в коде получилось найти.. Я решил сделать код попроще..
Код: Выделить всё
#include <avr/io.h>
#include <avr/interrupt.h>
int main(void)
{
DDRD = 0xFF;// Конфигурируем порт как выход
PORTD = 0xff; // Выключаем изначально светодиоды
ADMUX = (0<<REFS1)|(1<<REFS0)|(1<<ADLAR)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0); //питание AVcc с внешним кондером на AREF, дефолтная запись в реестр, данные с канала ADC0
ADCSRA = (1<<ADEN)|(1<<ADSC)|(0<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // вкл. ацп, режим одиночного преобр., разрешение прер., частота преобр. = FCPU/128
sei(); // разрешаем глобальные прерывания
//ADCSRA |= 1<<ADSC; // запускаем преобразование
unsigned char AdcBuf = ADCH; // чтение значения преобразования и запись в переменную AdcBuf
if (AdcBuf > 50) // Проверяем уровень сигнала и при совпадении включаем светодиод
PORTD = 0xff;
else
PORTD = 0x00;
//ADCSRA |= 1<<ADSC; // запуск очередного преобразования
while(1);
} // выход
Код идеально работает..
Последние 2 вопроса.
1) Если мне не достаточно первых 8 бит преобразования ( ADCH) и я хочу использовать и (ADCL) для точности, то как быть? Писать как-то типа
AdcBuf = ADCH+ADCL; ? Типа сумировать для более точной цифры..
2) Если у меня на одной микрухе будет и ШИМ, и АЦП и обычный код обрабатывается, то как сделать чтобы оно не тормозило? Ну то честь я читал что код запускается и обрабатывается последовательно (по порядку).. То есть должно быть если в коде ШИМ пауза стоит, то она будет останавливать (пока не пройдет пауза) весь ниже написанный код.. Или я не прав? Если и прав, то как сделать чтобы одно другого не тормозило? Писать всё не в main а разбить как-то на ф-ции.. Пфф.. Я не понимаю..
Спасибо.
Re: AtMega16 - Проблема с кодом АЦП
Добавлено: Вт ноя 20, 2012 21:42:46
svs39
stridemann писал(а):Писать как-то типа AdcBuf = ADCH+ADCL; ? Типа сумировать для более точной цифры..
Спасибо.
ADCH= старший байт, надо умножить на 256 (режим 10 бит)
Re: AtMega16 - Проблема с кодом АЦП
Добавлено: Вт ноя 20, 2012 23:03:12
stridemann
svs39 писал(а):ADCH= старший байт, надо умножить на 256 (режим 10 бит)
Дада, я это уже понял, спасибо
