реклама на сайте
подробности

 
 
3 страниц V  < 1 2 3 >  
Reply to this topicStart new topic
> Программирование АЦП на atmega16L-16AI, Помогите разобраться с считыванием данных с АЦП
нечитатель
сообщение Apr 9 2011, 21:36
Сообщение #16


Местный
***

Группа: Участник
Сообщений: 235
Регистрация: 20-11-10
Пользователь №: 61 032



"Высокая точность не нужна" = "интересуют только младшие биты"?
Go to the top of the page
 
+Quote Post
abitwise
сообщение Apr 10 2011, 12:00
Сообщение #17





Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056



Именно так. Достаточно битов регистра ADCL.

Xenia, спасибо. Надо будет попробовать.
Если я правильно понял, то нужно читать полый результат преобразования АЦП.
Код
#define ADC_VREF_TYPE 0x00

unsigned char read_adc(unsigned char adc_input) // Считывание 8 МЗР
                                                                        // преобразования АЦП
{                                              
  ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
  delay_us(10);                                 // Задержка для стабилизации входного напряжения АЦП
  ADCSRA|=0b11100111;                           // Начало АЦП
  while ((ADCSRA & 0x10)==0);                   // Ожидание завершения преобразования
  ADCSRA|=0x10;                                 // Сброс фалга прерывания
  return ADC;                                  // Возвращает значение преобразования АЦП
}

Эта часть понятна.
Мне не очень ясно каким образом отчечь два бита старшего байта АЦП!?
Если я напишу:
Код
adc_data_l=read_adc(5); // Запись данных из АЦП с ноги PA5

То два бита старшего байта никуда не денутся ??? Или они автоматически уберутся???
Go to the top of the page
 
+Quote Post
нечитатель
сообщение Apr 11 2011, 06:09
Сообщение #18


Местный
***

Группа: Участник
Сообщений: 235
Регистрация: 20-11-10
Пользователь №: 61 032



"Участники форума обязаны: ... 2.1в высказываться понятно, полно... в противном случае пост может быть расценен как текстовый мусор (флуд)".

Опорное напряжение = 5 вольт. Такому напряжению на входе соответствовал бы максимальный код на выходе.
На входе АЦП 2 вольта.
Входное напряжение / опорное напряжение = выходной код / максимальный код, с точностью до http://electronix.ru/forum/index.php?showtopic=88341.
Выходной код = максимальный код (двоичный) 11.1111.1111 Х входное 2 / опорное 5 = 01.1001.1001 (двоичный).

[***] Высокая точность не нужна. Интересуют только младшие биты. Именно так. Достаточно битов регистра ADCL.
01.1001.1001 ~ 01.1001.1001
409 ~ 153
2 вольта ~ 0.75 вольта

... каким образом отчечь два бита старшего байта АЦП!? goto [***]

А в рублях бы это выглядело как "зарплата тридцать тысяч (30000) приблизительно равна зарплате ноль (30000)", зато "почти одинаковы зарплаты 8300 и 65300".

---

Надо ждать, пока кто-нибудь выскажется наконец понятно и полно. Если ещё актуально.
Или начиная с 204 220 страницы читать.

Сообщение отредактировал нечитатель - Apr 11 2011, 06:52
Go to the top of the page
 
+Quote Post
Палыч
сообщение Apr 11 2011, 08:06
Сообщение #19


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(abitwise @ Apr 10 2011, 16:00) *
Мне не очень ясно каким образом отчечь два бита старшего байта АЦП!? Если я напишу:
Код
adc_data_l=read_adc(5); // Запись данных из АЦП с ноги PA5

То два бита старшего байта никуда не денутся ??? Или они автоматически уберутся???
Зачем Вы старшие биты отсекаете? Если Вы собрались писать
Код
  return ADC; // Возвращает значение преобразования АЦП
то, уж, запишите
Код
unsigned int read_adc(unsigned char adc_input)
Измените также char на int и в описании переменной, которой присваивается измеренное значение
Go to the top of the page
 
+Quote Post
Xenia
сообщение Apr 11 2011, 09:17
Сообщение #20


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(abitwise @ Apr 10 2011, 16:00) *
Мне не очень ясно каким образом отчечь два бита старшего байта АЦП!?
Если я напишу:
Код
adc_data_l=read_adc(5); // Запись данных из АЦП с ноги PA5

То два бита старшего байта никуда не денутся ??? Или они автоматически уберутся???

Да, автоматически уберутся. Здесь работает стандартное правило языка C при конверсии типов. При присваивании двухбайтового значения int однобайтовому unsigned char старшая часть числа усекается. Аналогично можно было спросить, куда девается дробная часть после присвоения числа пи (3.14...) переменной типа int или unsigned char. В этом случае тоже произодйет конверсия типа числа, сопровождающаяся усечением до целого.

Правда бывают компиляторы, которые в подобных случаях выдают предупреждение (Warning) "значащая часть числа потеряна", но его можно либо отменить, либо записать конверсию в явном виде:
return (unsigned char)ADC;

Сейчас у вас конверсия (усечение int до unsigned char) происходит при возврате значения из функции read_adc(). А если бы вы сделали эту функцию типа int (по совету Палыча), то тогда конверсия протекала бы по месту присваивания выдаваемого значения байтовой переменной, т.е. вот здесь:
adc_data_l=read_adc(5);
И если бы компиллятор выдавал здесь Warning, то лучше было бы выполнить конверсию явно:
adc_data_l=(unsigned char)read_adc(5);

Но это только тогда, когда Warning раздражает, а работать правильно будет и так.
Go to the top of the page
 
+Quote Post
abitwise
сообщение Apr 11 2011, 09:19
Сообщение #21





Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056



Нашёл решение данной проблемы.
В даташите написано:
Цитата
Consequently, if the result is left adjusted and no more than 8-bit precision is required, it is sufficient to read ADCH. стр 218


Буду делать так:
Код
#define ADC_VREF_TYPE 0x20                      // Выравнивание влеворî, AREF pin


unsigned char read_adc(unsigned char adc_input) // Считывание 8 СЗР
                                                // преобразования АЦП
{                                              
  ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);    
  delay_us(10);                                 // Задержка для стабилизации входного напряжения АЦП
  ADCSRA|=0b11110111;                           // Начало АЦП
  while ((ADCSRA & 0x10)==0);                   // Ожидание завершения преобразования
  ADCSRA|=0x10;                                 // Сброс флага прерывания
  return ADCH;                                  // Возвращает значение 8СЗР
}
Go to the top of the page
 
+Quote Post
SysRq
сообщение Apr 11 2011, 09:37
Сообщение #22


Чайник, 1 литр
****

Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168



Цитата(abitwise @ Apr 11 2011, 13:19) *
Код
  ADCSRA|=0b11110111;                           // Начало АЦП
Уберите Bit 5 – ADATE: ADC Auto Trigger Enable, иначе запросто получите данные оцифровки предыдущего канала.
Go to the top of the page
 
+Quote Post
Палыч
сообщение Apr 11 2011, 09:55
Сообщение #23


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(abitwise @ Apr 11 2011, 13:19) *
Буду делать так
Коль решили довольствоваться восмью битами, то массив temp_range опишите как unsigned char
Go to the top of the page
 
+Quote Post
abitwise
сообщение Apr 11 2011, 09:56
Сообщение #24





Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056



Интересно. Я думал, что этот бит, совместно с комбинацией битов ADTS2:ADTS0 отвечают за режим преобразования.
Так, в книге "Микроконтроллеры AVR семейства Mega. Руководство пользователя" А.В. Евстифеева написано:"
Цитата
... Для выбора режима работы в этих моделях используется бит ADATE регистра ADCSRA и биты ADTS2:ADTS0 регистра SFIOR...
...Если бит ADATE сброшен в 0, АЦП работает в режиме одиночного преобразования. Если же бит ADATE установлен в 1, функционирование АЦП определяется содержимым битов ADTS2:ADTS0 согласно таблице...

У меня АЦП должен работать в непрерывном режиме. Поэтому, я следумаю написанному в книге поставил бит ADATE в 1, а биты ADTS2:ADTS0 в 0, потому что такая конфигурация соответствует непрерывному режиму преобразования АЦП.
Go to the top of the page
 
+Quote Post
Палыч
сообщение Apr 11 2011, 10:02
Сообщение #25


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(abitwise @ Apr 11 2011, 13:56) *
Интересно. Я думал, что этот бит, совместно с комбинацией битов ADTS2:ADTS0 отвечают за режим преобразования.
За старт преобразования (измерения)... Поскольку у Вас переключаются каналы измерения, то и старт преобразования должен быть "привязан" к этому переключению
Go to the top of the page
 
+Quote Post
Xenia
сообщение Apr 11 2011, 10:28
Сообщение #26


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(abitwise @ Apr 11 2011, 13:19) *
Нашёл решение данной проблемы.
В даташите написано:
Consequently, if the result is left adjusted and no more than 8-bit precision is required, it is sufficient to read ADCH. стр 218
Буду делать так:
return ADCH;

А вы не забыли переключить АЦП в режим "left adjusted"? А то по умолчанию биты прижаты к правому краю, и в ADCH находится не младшая, а старшая часть числа.
Go to the top of the page
 
+Quote Post
abitwise
сообщение Apr 11 2011, 10:36
Сообщение #27





Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056



Не забыл.
Код
#define ADC_VREF_TYPE 0x20
и
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff)

Если я конечно правильно всё сделал_)
То, что в скобках даёт 0010 0000. То есть бит ADLAR я установил в 1. Далее всё зависит от adc_input. Если adc_input = 4, то ADMUX=00100100, если adc_input=5, то ADMUX=00100101.
Надеюсь, что я правильно понял ?!)))
Go to the top of the page
 
+Quote Post
Палыч
сообщение Apr 11 2011, 11:36
Сообщение #28


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(abitwise @ Apr 11 2011, 14:36) *
Надеюсь, что я правильно понял ?
Правильно. А строчку
Код
ADCSRA|=0x10;                                 // Сброс флага прерывания
можно убрать, она лишняя - это делается и так двумя строками выше


Цитата(Xenia @ Apr 11 2011, 14:28) *
А то по умолчанию биты прижаты к правому краю, и в ADCH находится не младшая, а старшая часть числа.
Уточню: Ксения говорит о том, что в регистре ADCH всегда находится старшая часть результата, но по умолчанию (ADLAR=0) - два старших разряда, а при ADLAR=1 в этом регистре находятся восемь старших разрядов результата.
Go to the top of the page
 
+Quote Post
SysRq
сообщение Apr 11 2011, 11:45
Сообщение #29


Чайник, 1 литр
****

Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168



Цитата(abitwise @ Apr 11 2011, 13:56) *
У меня АЦП должен работать в непрерывном режиме.
Ну и оставили бы код из генератора CodeVision целиком, он там так и работает. Либо не стоило вообще его брать за основу.
Go to the top of the page
 
+Quote Post
abitwise
сообщение Apr 11 2011, 12:09
Сообщение #30





Группа: Участник
Сообщений: 14
Регистрация: 1-04-11
Пользователь №: 64 056



Спасибо за уточнения. Эту часть материала я усвоил.
С учётом перечисленных замечаний, код получился такой

Код
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.5 Professional
Automatic Program Generator
© Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date    : 03.04.2011
Author  : F4CG                            
Company : F4CG                            
Comments:


Chip type           : ATmega16L
Program type        : Application
Clock frequency     : 8,00000 MHz
Memory model        : Small
External SRAM size  : 0
Data Stack size     : 256
*****************************************************/


#include <mega16.h>
#include <delay.h>


interrupt [TIM1_OVF] void timer1_ovf_isr(void) // Прерывание по переполнению Т/C1
{
    OCR1A=0x00;
    OCR1B=0x00;
// TCNT1L=0x00;  
// PORTD=0b00110000;
}


interrupt [TIM1_COMPA] void timer1_compa_isr(void) // Прерывание по совпадению события А
{
   PORTD=0b00100000;
}

interrupt [TIM1_COMPB] void timer1_compb_isr(void) // Прерывания по совпадению события Б
{
   PORTD=0b00010000;
}



#define ADC_VREF_TYPE 0x20                      // Aref pin, выравнивание влево


unsigned int read_adc(unsigned char adc_input) // Считывание 8 СЗР
                                                // преобразования АЦП
{                                              
  ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);    
  delay_us(10);                                 // Задержка для стабилизации входного напряжения АЦП
  ADCSRA|=0b11010111;                           // Начало АЦП, сброс флага прерывания
  while ((ADCSRA & 0x10)==0);                   // Ожидание завершения преобразования
  return ADCH;                                  // Возвращение 8 СЗР
}


                    
void main(void)
{
int temp_range[9] = {299, 255, 217, 184, 156, 132, 112, 95, 81};
  
PORTA=0x30; // Инициализация порта А  
DDRA=0x00;  // РА4, РА5 - входы с подключенным резистором

PORTB=0x00; // Инициализация порта Б
DDRB=0x00;

PORTC=0x00; // Инициализация порта С
DDRC=0x00;

PORTD=0x00; // Инициализация порта Д  
DDRD=0x30;  // PD4, PD5 выходы с низким логическим уровнем

TCCR0=0x00; // Инициализация Т/C0
TCNT0=0x00;
OCR0=0x00;


TCCR1A=0xA1; // Инициализация T/C1
TCCR1B=0x0B; //
ICR1H=0x00;  // Тактирование системное
ICR1L=0x00;  // Частота: 8000,000 kHz
             // Режим: Fast PWM top=00FFh
             // OC1A : не инвертирующий
             // OC1B : не инвертирующий
            
ASSR=0x00;   // Инициализация  Т/C2
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
              
MCUCR=0x00;
MCUCSR=0x00;

TIMSK=0x1C;  // Инициализация прерываний таймера счётчика

ACSR=0x80;   // Аналоговый компаратор выключен
SFIOR=0x00;  


ADMUX=0b00000000;    
ADCSRA=0b00000000;    
                    

SPCR=0x40;   // Инициализация SPI
SPSR=0x01;
#asm("sei")  // Разрешение прерываний

for (;;)    
{
   unsigned int adc_data_l;
  
   TCNT1H=0x00; //  Обнуление Т/С1
   TCNT1L=0x00;
  
   OCR1AH=0x00; // Обнуление регистров сравнения
   OCR1AL=0x00;
   OCR1BH=0x00;
   OCR1BL=0x00;

   adc_data_l=0; // Обнуление переменной                    
  
   adc_data_l=read_adc(5); // Запись данных из АЦП с PA5
  
   if(temp_range[0] <= adc_data_l)  // Процедура сравнения значения АЦП с
     {                              // температурными диапазонами и
      OCR1A=0;                      // выдача ШИМ на вентилятор
     }
   else if(temp_range[1] <= adc_data_l)
     {
      OCR1A=0;
     }
   else if((temp_range[2] <= adc_data_l) && (adc_data_l < temp_range[1]))
     {
      OCR1A=128;
     }
   else if((temp_range[3] <= adc_data_l) && (adc_data_l < temp_range[2]))
     {
      OCR1A=149;
     }        
   else if((temp_range[4] <= adc_data_l) && (adc_data_l < temp_range[3]))
     {
      OCR1A=170;
     }
   else if((temp_range[5] <= adc_data_l) && (adc_data_l < temp_range[4]))
     {
      OCR1A=191;
     }
   else if((temp_range[6] <= adc_data_l) && (adc_data_l < temp_range[5]))  
     {
      OCR1A=213;
     }
   else if((temp_range[7] <= adc_data_l) && (adc_data_l < temp_range[6]))  
     {
      OCR1A=234;
     }
   else if((temp_range[8] <= adc_data_l) && (adc_data_l < temp_range[7]))  
     {
      OCR1A=255;
     }
   else if(adc_data_l < temp_range[8])
     {
      OCR1A=255;
     }  
  
   adc_data_l=read_adc(4); // Запись данных АЦП с PA4

   if(temp_range[0] <= adc_data_l)  // Процедура сравнения значения АЦП с
     {                              // температурными диапазонами и
      OCR1B=0;                      // выдача ШИМ на вентилятор
     }
   else if(temp_range[1] <= adc_data_l)
     {
      OCR1B=0;
     }
   else if((temp_range[2] <= adc_data_l) && (adc_data_l < temp_range[1]))
     {
      OCR1B=128;
     }
   else if((temp_range[3] <= adc_data_l) && (adc_data_l < temp_range[2]))
     {
      OCR1B=149;
     }        
   else if((temp_range[4] <= adc_data_l) && (adc_data_l< temp_range[3]))
     {
      OCR1B=170;
     }
   else if((temp_range[5] <= adc_data_l) && (adc_data_l < temp_range[4]))
     {
      OCR1B=191;
     }
   else if((temp_range[6] <= adc_data_l) && (adc_data_l < temp_range[5]))  
     {
      OCR1B=213;
     }
   else if((temp_range[7] <= adc_data_l) && (adc_data_l < temp_range[6]))  
     {
      OCR1B=234;
     }
   else if((temp_range[8] <= adc_data_l) && (adc_data_l < temp_range[7]))  
     {
      OCR1B=255;
     }                
   else if(adc_data_l < temp_range[8])
     {
      OCR1B=255;
     }  
};
}


С типами данных у функции read_adc, массива temp_range и переменной adc_data_l ничего не напутал ? Всё верно ?
Go to the top of the page
 
+Quote Post

3 страниц V  < 1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 00:52
Рейтинг@Mail.ru


Страница сгенерированна за 0.01542 секунд с 7
ELECTRONIX ©2004-2016