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.