ATmega8 - ADC kezelés

2013-02-05

 

Az ATmega8 analóg-digitál konverterét próbáltam ki. Az áramkörre szépen feltettem egypár kapacot, de igazából nélkülük sem ugrált az AD kimenete. Lehet, hogy egy ipari zajosabb környezetben azért nem lenne ennyire szép a kép, bár a műhely asztalom felett azért rendesen termeli a zajt a kompakt fénycsöves lámpám (legalábbis a földeletlen oszcilloszkóp mérőzsinórom tanúsága szerint). Az AVcc-re hirtelenjében egy 51R ellenálláson keresztül vezettem a tápfeszt (40mV esett rajta), a doksi fojtótekercset javasol. A mérendő jelet egy 1k trimmer potival generáltam. A kapcsolás:

Az asztalon a megszokott kuszaság.

A programnak csak az érdekesebb elejét tettem fel ide, a végén letölthető csomagban az LCD kezelő rutinok is benne vannak. A uC úgy van beállítva, hogy a belső 2,56V-os referenciához képest mér az ADC. Az ADC-t úgy állítottam be, hogy a mért érték felső 8 bit-je jelenjen meg az ADCH regiszterben. Engedélyezve van az ADC megszakítás. A megszakítás kezelő függvény olvassa ki az ADC-ből a 8 bit-es eredményt, majd hexadecimálisan (így volt könnyű) kiirja az LCD-re. Az ADC nem szabadonfutó módban mér, hanem a main()-ban fél másodpercenként indítom el a mérést. Talán még annyit fontos leírni, hogy az ADC számára is kell órajel, ezt a uC órajeléből egy előosztón keresztül áll elő. Az előosztást nekünkkell megválasztani úgy, hogy az órajel 50-200kHz közé essen.

Gondolom, lesz akit elgondolkodtat, miért 8 bit, ha az ADC 10 bit-et tud? Egy kézi műszer is 0..2000 tartományban írja ki a mért értékeket, az persze legalább 11 bit :). Ha elolvassuk annak a kéziműszernek a prospektusát is, hamar kiderül, hogy milyen pontosan mér az a készülék. Arra akarok kilyukadni, hiába a négyszámjegyű kiírás, ha mondjuk a műszer pontossága csak 1%. Én úgy gondolom, hogy 1%-os alkatrészeket felhasználva (ami nem rossz!) 7 bit-es pontosság lehet reális. Ha tényleg 10 bit pontossággal akarunk mérni, ahhoz bizony már 0.1% pontosságú alkatrészek, precíz analóg áramkörök is dukálnának (érdemes rákukkantani az árakra, már ha találunk megfelelő alkatrészeket).



/*******************************************************************************
*   Author       -  Kiraly Tibor
*                   http://www.tkiraaly.hu
*   Date         -  2013.02.04.
*   Chip         -  Atmel ATmega8 & HD44780
*   Compiler     -  avr-gcc (WinAVR)
*
*   ATmega8 ADC kezeles
*   
********************************************************************************
*    LCD bekotese:
*
*    14   LCD D7       - AVR PD7  - 13
*    13   LCD D6       - AVR PD6  - 12
*    12   LCD D5       - AVR PD5  - 11
*    11   LCD D4       - AVR PD4  -  6
*    10   LCD D3
*     9   LCD D2
*     8   LCD D1
*     7   LCD D0
*     6   LCD E        - AVR PC2  - 25
*     5   LCD RW       - GND
*     4   LCD RS       - AVR PC3  - 26
*     3   LCD KONTR    - 10 kOhm trim.
*     2   LCD VDD      - +5V
*     1   LCD VSS      - GND
*
*
*    Analog resz:
*
*                        AVR AVCC - 20 - 100nF - GND / 51R - VCC 
*                        AVR AREF - 21 - 100nF - GND
*                        AVR ADC0 - 23 - 100nF - GND / 1K poti VCC/GND
*
*******************************************************************************/

#define F_CPU                4000000             // orajel (MHz)




#include "tkiraaly_atmega8.h"
#include 
#include 




#define LED                  0
#define LED_ENABLE           BS( DDRB, LED)
#define LED_BE               BC( PORTB, LED)
#define LED_KI               BS( PORTB, LED)

#define LCD_E                2
#define LCD_E_ENABLE         BS( DDRC,  LCD_E)
#define LCD_E_0              BC( PORTC, LCD_E)
#define LCD_E_1              BS( PORTC, LCD_E)

#define LCD_RS               3
#define LCD_RS_ENABLE        BS( DDRC,  LCD_RS)
#define LCD_RS_UTASITAS      BC( PORTC, LCD_RS)
#define LCD_RS_ADAT          BS( PORTC, LCD_RS)

#define LCD_PORT             PORTD               // felso 4 bit+ E, RS
#define LCD_PORT_ENABLE      DDRD= 0B11110000




// ADMUX beallitasai
#define VREF_AREF            0                   // kulso referencia feszultseg
#define VREF_AVCC            0B01000000          // az analog tapfesz a referencia
#define VREF_INT_2_56V       0B11000000          // belso 2,56V referencia
#define ADC_8BIT             0B00100000          // 8 bit felbontas ADCH-bol
#define ADC_10BIT            0                   // 10 bit felbontas, ADCH+ ADCL
#define IN_ADC0              0                   // bemenet valasztas
#define IN_ADC1              0B00000001
#define IN_ADC2              0B00000010
#define IN_ADC3              0B00000011
#define IN_ADC4              0B00000100
#define IN_ADC5              0B00000101
#define IN_ADC6              0B00000110
#define IN_ADC7              0B00000111
#define IN_VBG               0B00001110
#define IN_GND               0B00001111




// ADCSRA  beallitasai
#define ADC_ENABLE           0B10000000          // ADC engedelyezes
#define ADC_START            0B01000000          // AD meres inditasa
#define ADC_FREE_RUN         0B00100000          // AD folyamatos meres
#define ADC_IT_FLAG          0B00010000
#define ADC_IT_ENABLE        0B00001000          // ADC megszakitas engedelyezese
#define ADC_CP2              0B00000001          // F_CPU/ osztas - 50-200kHZ beallitando
#define ADC_CP4              0B00000010
#define ADC_CP8              0B00000011
#define ADC_CP16             0B00000100
#define ADC_CP32             0B00000101
#define ADC_CP64             0B00000110
#define ADC_CP128            0B00000111
#define START_ADC            ADCSRA|= ADC_START  // AD merest indito macro 




void lcd_init4( void);                           // LCD inicializalasa 4 bitre
void lcd_putc( UC);                              // betu kiirasa
void lcd_putcmd( UC);                            // parancskod kiadasa
void lcd_yx( UC, UC);                            // kurzor pozicioja 0..3/0..15
void lcd_cls( void);                             // kepernyo torles
void lcd_puts( const char *);                    // string kiirasa
void lcd_hex( UC);                               // LCD 1 byte kiirasa hexadecimalisan
UC num2hexc( UC);                                // szam hexadecimalis szamjeggye alakitasa




ISR( ADC_vect)			                             // IT, ha AD meres lefutott
{
   lcd_yx( 1, 7);
   lcd_hex( ADCH);
}



int main( void)
{
   lcd_init4();
   lcd_cls();
   lcd_yx( 0, 1);
   lcd_puts( PSTR( "ATmega8 - ADC"));

   ADMUX= VREF_INT_2_56V+ ADC_8BIT+ IN_ADC0;
   ADCSRA= ADC_ENABLE+ ADC_IT_ENABLE+ ADC_CP64;  

   LED_ENABLE;
   LED_BE;

   IT_ENABLE;

   for(;;)
   {
      START_ADC;                                 // meres 0,5 sec-enkent
      _delay_ms( 500);
   }
   return 0;
}




void lcd_init4( void)                            // LCD inicializalasa 4 bitre
{
   LCD_PORT_ENABLE;
   LCD_E_ENABLE;
   LCD_RS_ENABLE;
   _delay_ms( 15);
   LCD_RS_UTASITAS;
   LCD_PORT= 0B00100000;                         // 4 bit interface
   LCD_E_1;
   LCD_E_0;
   _delay_ms( 5);
   LCD_E_1;
   LCD_E_0;
   _delay_us( 120);
   lcd_putc( 0B00101000);                        // 4 bit interface, 2 sor, 5x8 pontos betu
   lcd_putc( 0B00101000);                        // 2x kell kiadni, vagy LCD D3-t VDD-re kell kotni
   lcd_putc( 0B00001100);                        // kijelzes be, cursor ki
   lcd_putc( 0B00000110);                        // kiiras jobbra
   LCD_RS_ADAT;
}




void lcd_putcmd( UC cmd)                         // parancskod kiadasa
{
   LCD_RS_UTASITAS;
   lcd_putc( cmd);
   LCD_RS_ADAT;
}




void lcd_putc( UC c)                             // egy betu kiiras
{
   LCD_E_1;                                      // felso 4 bit
   LCD_PORT= ( LCD_PORT & 0x0F) | ( 0xF0 & c);
   LCD_E_0;
   LCD_E_1;                                      // also 4 bit
   LCD_PORT= ( LCD_PORT & 0x0F) | ( 0xF0 & c << 4);
   LCD_E_0;
   _delay_us( 37);                               // var 37 usec  
}




void lcd_yx( UC sor, UC betu)                    //  kurzor pozicionalasa 0..3/0..15
{
   UC cim= 0x80;                                 // parancs kodja
   if (sor & 0B00000001) cim+= 64;               // 1. es 3. sor
   if (sor & 0B00000010) cim+= 20;               // 2. es 3. sor
   cim+= betu & 0x0F; 
   lcd_putcmd( cim);
}




void lcd_cls( void)                              // kepernyo torles
{
   lcd_putcmd( 0x01);
   _delay_ms( 2);
}




void lcd_puts( const char *s)                    // string kiiras
{
   register unsigned char c;
   while ( ( c= pgm_read_byte( s++))) lcd_putc( c);
}




void lcd_hex( UC c)                              // LCD 1 byte kiirasa hexadecimalisan
{
   lcd_putc( num2hexc(c >> 4));
   lcd_putc( num2hexc(c));
}



 
UC num2hexc( UC c)                               // szam hexadecimalis szamjeggye alakitasa
{
   c&= 0x0F;
   if( c < 10) c+= '0';
   else  c+= 'A'- 10;
   return c;
}

Itt a vége, fuss el véle, legytek az én vendégeim, innen letölthetitek a hozzávalókat összecsomagolva.