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

 
 
> Программирование АЦП на atmega16L-16AI, Помогите разобраться с считыванием данных с АЦП
abitwise
сообщение Apr 7 2011, 06:26
Сообщение #1





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



Доброго времени суток.
Поскольку я не профессиональный программист и до этого момента с микроконтроллерами общался постольку поскольку, то обращаюсь к знающим и опытным людям с просьбой помочь разобраться с поставленной передо мной задачей.

Исходные данные:

Есть - мк Atmega16L-16AI (TQFP)
- два вентилятора Jamicon (JF0825B1H), Evercool (EC6010H12B)
- два дачитка температуры типа NTC

Задача: необходимо считывать информацию с датчиков и выдавать на вентиляторы напряжения, соответствующие температурным диапазонам.
Так как я в этом деле новичок, то разбил задачу на три.
1) Научиться выдавать ШИМ на вентиляторы. С этим я худо бедно разобрался!

Вот код
Код
  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>

// Timer 1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
OCR1A=0x00;
OCR1B=0x00;
TCNT1L=0x00;  
PORTD=0b00110000;
}

//Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
   PORTD=0b00110000;

}

// Timer 1 output compare B interrupt service routine
interrupt [TIM1_COMPB] void timer1_compb_isr(void)

{
  PORTD=0b00110000;
    
}

void main(void)
{


// Input/Output Ports initialization
// Port A initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTA=0x00;
DDRA=0x00;

// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTB=0x00;
DDRB=0x00;

// Port C initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=In Func5=Out Func4=Out Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=0 State4=0 State3=T State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x30;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 8192,000 kHz
// Mode: Fast PWM top=00FFh
// OC1A output: Non-Inv.
// OC1B output: Non-Inv.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: On
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: On
TCCR1A=0xA1;
TCCR1B=0x09;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top=FFh
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x1C;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;

// ADC initialization
// ADC Clock frequency: 64,000 kHz
// ADC Voltage Reference: AREF pin
// ADC Auto Trigger Source: Timer1 Overflow
// Only the 8 most significant bits of
// the AD conversion result are used
//ADMUX=0b00000000;
//ADCSRA=0xF7;
//SFIOR&=0x1F;
//SFIOR|=0xC0;
SPCR=0x40;
SPSR=0x01;

#asm("sei")

while (1)
{
   OCR1B=100;
   OCR1A=100;
};
}


По части теории вопросов у меня пока что нет. Перед решением этой задачи были проведены расчёты и получены соответствующие значения регистров сравнения таймера/счётчика1, соответствующих температурным диапазонам. Также согласно формуле из даташита на атмегу получено число ADC.
Вот эти значения (приведу только один диапазон в целях экономии времени):

температура, С измерительное напряжение, В ADC OCR1A OCR1B
25 1.196 299 0 0
26 1.159 290 0 0
27 1.123 281 0 0
28 1.087 272 0 0
29 1.053 263 0 0
30 1.020 255 0 0

и т. д.
Со второй задачей справиться не получается. Заключается она в том, чтобы научиться работать с АЦП.
А именно как правильно считывать информацию из АЦП, где и какие прерывание нужны в данной задаче? То есть я хочу понять структуру кода на Си, которая позволяет это делать и как такую структуру писать.
Дело в том, что я пользуюсь CodeVisionAvr, который генерит код, если использовать Wizard. Это на мой взгляд удобно, но только в том, случае если есть полное понимание сгенеренного кода. У меня такого понимания нету.
Я пытался самостоятельно решить эту проблему и протестировать полученный результат в Протеус, как в решении первой задачи, но ничего не вышло
Вот код (всё тоже самое только с добавлением сгенеренного кода для АЦП):
Код


1-   #define ADC_VREF_TYPE 0x04                                
2-   // Read the 8 low significant bits
3-   // of the AD conversion result
4-   unsigned char read_adc(unsigned char adc_input)
5-   {
6-    ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);  
7-    Delay needed for the stabilization of the ADC input voltage
8-    delay_us(10);
9-    // Start the AD conversion
10-  ADCSRA=0b11100110;
11-  // Wait for the AD conversion to complete
12-  while ((ADCSRA & 0x40)==0);
13-  ADCSRA|=0x10;
14-  return ADCL;
15-  }





16-   // ADC interrupt service routine
17-   interrupt [ADC_INT] void adc_isr(void)
18-   {
19-   unsigned char adc_data_l;
20-   // Read the 8 low significant bits
21-   // of the AD conversion result
22-   adc_data_l = ADCL;

23-   if(adc_data_l==0xFF)
24-     {
25-       OCR1A = 255 - adc_data_l;
26-       OCR1B = 255 - adc_data_l;
27-     }
28-   else
29-     {
30-      OCR1A = adc_data_l;
31-      OCR1B = adc_data_l;
32-      };
33-   }


Хотелось бы узнать от опытных людей, для чего необходимо и что означают 1 и 6 строчки кода, а также 12 и 13.
Далее хотелось бы понять правильно ли я сделал, что в процедуре прерывания АЦП написал последовательность действий по присвоению значений регистрам сравнения ?

3) Третья задача пока вообще не рассматриволась. Заключается она в передаче данных из АЦП в процедуру сравнения полученного из АЦП числа.
У меня процедура сравнения выглядит следующим образом:
Код
int range[9]={299, 255, 217, 184, 132, 112, 95, 81};

if (range[0] <= adc_data_l)
  {
   OCR1AL=0;
   OCR1BL=0;
  };
if (range[1] <= adc_data_l)
  {
   OCR1AL=0;
   OCR1BL=0;
  };
if (range[2] <= adc_data_l < range[1])  
  {
   OCR1AL=128;
   OCR1BL=85;
  };
if (range[3] <= adc_data_l< range[2])  
  {
   OCR1AL=149;
   OCR1BL=96;
  };    
if (range[4] <= adc_data_l < range[3])  
  {
   OCR1AL=170;
   OCR1BL=106;
  };    
if (range[5] <= adc_data_l < range[4])  
  {
   OCR1AL=191;
   OCR1BL=138;
  };
if (range[6] <= adc_data_l < range[5])  
  {
   OCR1AL=213;
   OCR1BL=149;
  };  
if (range[7] <= adc_data_l < range[6])  
  {
   OCR1AL=234;
   OCR1BL=170;
  };
if (range[8] <= adc_data_l < range[7])  
  {
   OCR1AL=255;
   OCR1BL=255;
  };

Массив из значений регистров сравнения ввёл для удобства. Хотя может быть оно и сомнительное.
В какой части кода необходимо писать эту процедуру ? В бесконечном цикле while(1){}? Или в прерываниях? Поскольку переменная adc_data_l объявлена внутри функции, то использовать её как глобальную переменную нельзя. Как решается эта проблема?. То есть, допустим я прочитал АЦП и записал число в эту переменную, что нужно сделать чтобы можно было пользоваться этой переменной в процедуре сравнения?

Заранее благодарю за помощь! Если на форуме или в интернете уже есть идентичные темы, в которых предложены решения данных проблем, то прошу поделиться ссылкой. Я обыскался в инете на эту тему, но не нашёл ничего, чтобы мне объяснило или подсказало как решать и что делать.
Надеюсь на вашу помощь!
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
abitwise
сообщение Apr 10 2011, 12:00
Сообщение #2





Группа: Участник
Сообщений: 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
Xenia
сообщение Apr 11 2011, 09:17
Сообщение #3


Гуру
******

Группа: Модератор 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   Программирование АЦП на atmega16L-16AI   Apr 7 2011, 06:26
- - Палыч   Цитата(abitwise @ Apr 7 2011, 10:26) Хоте...   Apr 7 2011, 07:06
- - abitwise   Спасибо за ответ. Если я вас правильно понял, то ...   Apr 7 2011, 09:19
|- - Палыч   Цитата(abitwise @ Apr 7 2011, 13:19) Если...   Apr 7 2011, 09:50
- - abitwise   С каждым вашим ответом, ситуация в голове проясняе...   Apr 7 2011, 10:51
|- - Палыч   Цитата(abitwise @ Apr 7 2011, 14:51) биты...   Apr 7 2011, 14:42
- - abitwise   Ясно! Уже учёл. Спасибо! Вот код, которы...   Apr 7 2011, 17:37
|- - Палыч   Проверку на попадание в диапазон Вы записали в вид...   Apr 8 2011, 04:04
|- - Xenia   Цитата(abitwise @ Apr 7 2011, 21:37) По п...   Apr 9 2011, 20:29
- - XVR   Цепочка из if'ов - это жесть. Для кого в С ц...   Apr 8 2011, 08:56
- - abitwise   Можете предложить другой вариант решения ? Цепочка...   Apr 8 2011, 09:01
|- - Палыч   Цитата(abitwise @ Apr 8 2011, 13:01) Цепо...   Apr 8 2011, 09:34
|- - Палыч   Ещё обратите внимание, что Ваша программа "за...   Apr 8 2011, 11:21
- - abitwise   Спасибо. Уже обратил) Буду пробовать прошивать......   Apr 8 2011, 11:42
- - abitwise   Прошил атмегу. Но программа по заданному алгоритму...   Apr 9 2011, 18:36
- - нечитатель   "Высокая точность не нужна" = "инте...   Apr 9 2011, 21:36
|- - Палыч   Цитата(abitwise @ Apr 10 2011, 16:00) Мне...   Apr 11 2011, 08:06
- - нечитатель   "Участники форума обязаны: ... 2.1в высказыва...   Apr 11 2011, 06:09
- - abitwise   Нашёл решение данной проблемы. В даташите написан...   Apr 11 2011, 09:19
|- - Палыч   Цитата(abitwise @ Apr 11 2011, 13:19) Буд...   Apr 11 2011, 09:55
|- - Xenia   Цитата(abitwise @ Apr 11 2011, 13:19) Наш...   Apr 11 2011, 10:28
- - SysRq   Цитата(abitwise @ Apr 11 2011, 13:19) Код...   Apr 11 2011, 09:37
- - abitwise   Интересно. Я думал, что этот бит, совместно с ком...   Apr 11 2011, 09:56
|- - Палыч   Цитата(abitwise @ Apr 11 2011, 13:56) Инт...   Apr 11 2011, 10:02
- - abitwise   Не забыл. Код#define ADC_VREF_TYPE 0x20 и ADMUX=ad...   Apr 11 2011, 10:36
|- - Палыч   Цитата(abitwise @ Apr 11 2011, 14:36) Над...   Apr 11 2011, 11:36
- - SysRq   Цитата(abitwise @ Apr 11 2011, 13:56) У м...   Apr 11 2011, 11:45
- - abitwise   Спасибо за уточнения. Эту часть материала я усвои...   Apr 11 2011, 12:09
|- - Палыч   Цитата(abitwise @ Apr 11 2011, 16:09) С т...   Apr 11 2011, 12:24
- - abitwise   1. Мне нужно 8 разрядов. Насколько я понял, выйгр...   Apr 11 2011, 12:37
|- - Палыч   Цитата(abitwise @ Apr 11 2011, 16:37) 1. ...   Apr 11 2011, 12:59
- - abitwise   Ясно. То есть, чтобы не было этого конфликта нужно...   Apr 11 2011, 13:07
- - Палыч   Цитата(abitwise @ Apr 11 2011, 17:07) нуж...   Apr 11 2011, 13:15


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

 


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


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