Страница 1 из 2

АЦП в atmega8

Добавлено: Вт апр 09, 2013 18:00:15
kushman
Подключил к atmega8 датчик температуры, схема подлючения - делитель напряжения (опорный резистор и датчик температуры - каждый по 1 кОм), соответственно со средней точки снимается показание АЦП. Проблема в следующем - измеряю тестером напряжение на средней точке - 0.1 В, вытаскиваю атмегу8 из кроватки - все становится нормально, примерно 2.5 вольтра. Видимо какая-то проблема со входным сопротивлением АЦП, может его надо как-то настраивать?

Re: АЦП в atmega8

Добавлено: Вт апр 09, 2013 18:09:46
ChipKiller
Видимо какая-то проблема со входным сопротивлением АЦП, может его надо как-то настраивать?
как пример или так

Re: АЦП в atmega8

Добавлено: Вт апр 09, 2013 18:17:33
kushman
ChipKiller писал(а):
Видимо какая-то проблема со входным сопротивлением АЦП, может его надо как-то настраивать?
как пример или так
М, пардон, так и не понял, в чем хитрость?

Re: АЦП в atmega8

Добавлено: Вт апр 09, 2013 19:54:56
Kavka
"Ножка" контроллера, которая может работать входом АЦП, ещё может быть как цифровым входом, так и цифровым выходом (похоже оно у вас так и настроено и на выходе логический "0", близкий к 0 вольт). Вот её и надо в программе настроить как вход АЦП, а потом командовать АЦП "измерить" и т.д.

Re: АЦП в atmega8

Добавлено: Ср апр 10, 2013 16:30:28
Antifritz
Короче, соответствующий бит регистра DDRC в 0 сбросить.

Re: АЦП в atmega8

Добавлено: Ср апр 10, 2013 18:45:18
kushman
Да, действительно, настроил порт как вход, теперь все хорошо. Большое спасибо.
И еще такой вопрос, чтотбы темы не плодить. Пытаюсь вывести на дисплей измеряемое напряжение, код приведен ниже. А в ответ выводится лишь пустота. Что не так?

Код: Выделить всё

interrupt [ADC_INT] void ADC_ISR(void) {
  
   float voltage;                    
   voltage = (ADCH*2.56)/255;
   send_lcd_symbol(set_second_line, 'I');
   sprintf(lcd_buffer, "%f", voltage);
   send_lcd(set_first_line, lcd_buffer);   
   
}
Символ I использую как индикатор сработавшего прерывания.

Re: АЦП в atmega8

Добавлено: Ср апр 10, 2013 19:18:17
da-nie
А почему вы только ADCH читаете?
У вас прерывание вызывается? Может, вы их забыли включить ( sei() ) или не указали АЦП работать с прерыванием.

Я когда-то делал без прерывания так:

Код: Выделить всё


...

 //включаем АЦП на канале PC5 в режиме одиночного преобразования
 ADMUX=(0<<MUX3)|(1<<MUX2)|(0<<MUX1)|(1<<MUX0)|(0<<ADLAR)|(0<<REFS0)|(0<<REFS1);
 //MUX0-MUX3 - выбор входа (0101=PC5)
 //ADLAR -выравнивание преобразования (0=не нужно)
 //REFS0,REFS1-выбор опорного напряжения (0,0=внешний вход aref)
 ADCSR=(1<<ADEN)|(0<<ADSC)|(0<<ADFR)|(0<<ADIF)|(0<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
 //ADEN-включение преобразования АЦП (1=включено)
 //ADSC-запуск преобразования (0=выключено)
 //ADFR-режим работы АЦП (0=одиночное преобразование)
 //ADIF-флаг прерывания от компаратора (0=выключено)
 //ADIE-разрешение прерываний от компаратора (0=выключено)
 //ADPS0-ADPS2-выбор частоты преобразования (111=делитель 128)
 SFIOR=0;

...

//----------------------------------------------------------------------------------------------------
//получить показания АЦП
//----------------------------------------------------------------------------------------------------
unsigned short GetADC(void)
{
 if (ADCSR&(1<<ADIF)) ADCSR^=(1<<ADIF);
 ADCSR|=(1<<ADSC);//запускаем преобразование
 while((ADCSR&(1<<ADSC)));//ждём завершения преобразования
 //читаем полученное значение
 unsigned char l=ADCL;
 unsigned char h=ADCH;
 unsigned short value=((unsigned short)(h)<<8)|((unsigned short)(l));
 return(value);
}

Re: АЦП в atmega8

Добавлено: Ср апр 10, 2013 19:43:29
kushman
Все равно на дисплее пусто. Может с выводом что не так?
Прерывание да, срабатывает. А один байт обрабатываю, поскольку АЦП 10 разрядов, а 2 из них как правило прыгают.

Re: АЦП в atmega8

Добавлено: Ср апр 10, 2013 20:00:04
da-nie
Тогда действительно, дисплей не выводит. Попробуйте отдельно на него что-нибудь вывести.

Re: АЦП в atmega8

Добавлено: Ср апр 10, 2013 20:37:24
kushman
Хм..А что же тут не так. Этот дисплей с этим кодом прекрасно работал с ADuC845.
Может что не так с этой строчкой?

Код: Выделить всё

sprintf(lcd_buffer, "%f", value);

Вот функция вывода на дисплей, немного кривая, но хорошо работающая)

Код: Выделить всё

void send_lcd(unsigned char line,unsigned char *txt) {
       unsigned int i=0;
    while(txt[i]!=NULL) {
    send_lcd_symbol(line+i, txt[i]);
    i++;
    }
} 

Re: АЦП в atmega8

Добавлено: Ср апр 10, 2013 21:09:53
da-nie
Так вы на дисплей уже что-нибудь выводили этой вашей функцией?

Re: АЦП в atmega8

Добавлено: Ср апр 10, 2013 21:17:24
kushman
Да, с помощью sprinf выводил строчку. А вот с переменной она что-то отказывается работать.

Re: АЦП в atmega8

Добавлено: Чт апр 11, 2013 05:12:06
da-nie
В обе строки дисплея выводили? А из прерывания выводили? Я не встречал, чтобы sprintf глючила...

Re: АЦП в atmega8

Добавлено: Чт апр 11, 2013 12:03:03
kushman
Да, в обе строки все выводится.

Re: АЦП в atmega8

Добавлено: Чт апр 11, 2013 16:36:11
da-nie
Тогда вы покажите, как у вас lcd_buffer объявлен.

Re: АЦП в atmega8

Добавлено: Чт апр 11, 2013 20:20:24
kushman
da-nie писал(а):Тогда вы покажите, как у вас lcd_buffer объявлен.
LCD_Buffer объявлен таким образом:
unsigned char lcd_buffer[LCD_BUFFER_SIZE];

Re: АЦП в atmega8

Добавлено: Пт апр 12, 2013 06:23:20
da-nie
Тогда чудеса... :?
А вы всю программу приведите, если не трудно. Это очень странно...

Re: АЦП в atmega8

Добавлено: Пт апр 12, 2013 21:28:27
kushman
Вот код программы:

Код: Выделить всё

#include <mega8.h>
#include <delay.h>
#include <stdio.h>

#define set_first_line 0x80
#define set_second_line 0xC0

#define LCD_BUFFER_SIZE 16

unsigned char lcd_buffer[LCD_BUFFER_SIZE]; //Buffer for LCD

#define RS PORTB.2
#define RW PORTB.1
#define En PORTB.0

void send_lcd_4bit(unsigned char send_data) {   

   PORTD=send_data;
   En=1;
   delay_ms(30);
   En=0;
}

void send_lcd_cmd(unsigned char send_data) {

   RS=0;
   send_lcd_4bit(send_data);
   send_data=(send_data << 4);
   send_lcd_4bit(send_data);
}

void send_lcd_data(unsigned char send_data) {
   RS=1;
   send_lcd_4bit(send_data);
   send_data=(send_data << 4);
   send_lcd_4bit(send_data);
}

void LCD_Init(void) {

   send_lcd_4bit(0x30);
   delay_ms(30);
   send_lcd_4bit(0x30);
   delay_ms(30);
   send_lcd_4bit(0x30);
   delay_ms(30);
   send_lcd_4bit(0x20);
   delay_ms(30);
   send_lcd_cmd(0x28);
   delay_ms(30);
   send_lcd_cmd(0x0C);
   delay_ms(30);
   send_lcd_cmd(0x06);
   delay_ms(30);
   send_lcd_cmd(0x01);
}

void send_lcd_symbol(unsigned char adress, unsigned char send_data) {
     send_lcd_cmd(adress);
     send_lcd_data(send_data);   
     
}

void send_lcd(unsigned char line,unsigned char *txt) {
       unsigned int i=0;
    while(txt[i]!=NULL) {
    send_lcd_symbol(line+i, txt[i]);
    i++;
    }
}    

void ADC_Init(void) {

    ADMUX=0x0E; 
    ADCSRA=0x9F;
                              
}

interrupt [ADC_INT] void ADC_ISR(void) {
  

   unsigned char l,h, value;                
   send_lcd_symbol(set_second_line, 'I');
   l=ADCL;
   h=ADCH;
   value=((unsigned short)(h)<<8)|((unsigned short)(l));    
   sprintf(lcd_buffer, "%f", value);
   send_lcd(set_first_line, lcd_buffer); 
   
}
void main(void) {

   DDRB=0xFF;
   DDRD=0xFF;
   DDRC=0x00;
   LCD_Init();
   ADC_Init(); 
   SREG.7=1; 
   ADCSRA.6=1;
   while(1) {}          
}

Re: АЦП в atmega8

Добавлено: Пт апр 12, 2013 21:40:11
da-nie
А где вы включаете прерывания с помощью sei()? :?

Я, правда, не знаю, как в вашем IDE и компиляторе это сделано. Я использую WinAVR.

Re: АЦП в atmega8

Добавлено: Сб апр 13, 2013 08:42:04
kushman
В функции main разрешаются все прерывания и прерывания от АЦП. В регистрах SREG и ADCSRA. Вот код:

Код: Выделить всё

 
SREG.7=1; //разрешение всех прерываний 
ADCSRA.6=1; //разрешение прерываний от АЦП