Forum: Compiler & IDEs ADC Wandlung, was mache ich Falsch


von Balou B. (baloubaer)


Lesenswert?

Hallo zusammen,

ich habe einige Fragen zur Benutzung des ACD bei dem ATMega32. Zudem 
muss ich sagen, dass ich bisher keinerlei Erfahrung mit dem ADC habe.

Ich möchte gern 8 Spannungen Messen, die da wären (rechnerisch): 0,45 V; 
0,9 V; 1,4V; 2,25 V; 3,1 V; 3,8 V; 4,3 V und 4,6 V.


Hardware:

Pollin Atmel Evaluations-Board Version 2.0.1 Best.Nr. 810 074
ATMEGA32 mit Fcpu = 16 MHz
AVCC = AREF = VCC = 5 V
AVCC beschaltet mit C = 100nF 
(http://www.pollin.de/shop/downloads/D810038B.PDF)


Software:

Eingestellt habe ich den ADC so:
1
//ADC Wandler einstellen:
2
3
  ADCSRA =  _BV ( ADEN ) |/* _BV ( ADIE ) |*/ _BV ( ADPS0 ) | _BV ( ADPS1 ) | _BV ( ADPS2 );  /*Aktivieren
4
  und einstellen des ADC Wandlers, hier Prescaler auf 128 bei CPU Takt 16 MHz, entspricht 125kHz Taktfrequenz, gern mit Interrupt oder Flag 
5
  für ADC*/
6
  /*ADMUX nicht gestzt, somit AREF extern (5V)& PIN ADC0 als eingang*/
7
8
// "Dummy-Readout" /*Erste Messung zur Kallibrierung*/
9
 
10
    ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
11
    while (ADCSRA & (1<<ADSC) ) 
12
  {         // auf Abschluss der Konvertierung warten
13
    }
14
  
15
    (void) ADCW; /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
16
     Wandlung nicht übernommen. */
17
  }

ich führe auch einen Dummy Readout durch, da dieser im Tutorial 
"AVR-GCC-Tutorial/Analoge Ein- und Ausgabe" empfohlen wird.


Nun zu meinen Fragen, die ich trotz mehrfachen Suchen nicht wirklich 
beantwortet sehe:

1. Führt der ADC immer zwei Messungen nach dem starten einer Wandlung 
(setzten des ADSC Bit auf 1) durch oder ist das wirklich nur bei der 
aller ersten Messung der Fall.

2. Wären die Einstellungen so OK?

3. Muss ich immer nach dem Starten der Wandlung die while - Schleife 
ausführen oder kann ich die Warteschleife durch das abfragen des ADIE 
Interrupt, bzw. das ADIF Bit entfallen lassen?

4. Muss ich den ADC noch Inizialisieren mit "ADC_Init();"

5. Um fest zu stellen ob ich eine Wandlung habe, kann ich das so machen? 
Also das ADIF Bit abfragen?
1
....
2
if ( ( pulseregen >= PULSEREGEN_LIMIT ) && ( timeregen == 0 ) )  //Abfrage der Pulse und der Zeit
3
    {
4
                        ....
5
      ADCSRA |= _BV ( ADSC ); // Start der ADC - Messung
6
                        //GGF. die while schleife
7
                        ....
8
    };
9
....
10
11
if ( ADIF == 1 )
12
    {
13
  PORTC ^= _BV(PC0);
14
     }


Ich bedanke mich für euere Mühen und verbleibe

mit freundlichen Grüßen

Balou Baer

von Uwe S. (de0508)


Lesenswert?

Hallo,

wie bei der ADC-Init.
1
ADCSRA |= (1<<ADSC);         // eine ADC-Wandlung starten
2
while ( ADCSRA & (1<<ADSC) ){ }

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Balou Baer schrieb:

> 1. Führt der ADC immer zwei Messungen nach dem starten einer Wandlung
> (setzten des ADSC Bit auf 1) durch oder ist das wirklich nur bei der
> aller ersten Messung der Fall.

Wenn du ADSC auf 1 setzt, dann macht der ADC 1 Wandlung. Nicht mehr und 
nicht weniger.

Die Sache ist die.
Wenn der ADC aktiviert wird, dann dauert die erste Messung etwas länger. 
Das ist aber etwas das die Hardware macht und was dich im Grunde nicht 
interessiert, weil du ja sowieso den ADC befragst, ob er fertig ist.

> 2. Wären die Einstellungen so OK?

Sieht nicht so schlecht aus.
ADMUX hast du aussen vor gelassen, weil du an der Referenzspannug nichts 
ändern willst (externe). Was ok ist.
Solange dir bewusst ist, dass in ADMUX auch die Bits sind, die steuern 
welcher Eingang überhaupt als ADC Eingang fungiert, und du dich darauf 
verlässt, dass die schon 0 sind, gibt es nichts daran auszusetzen.

> 3. Muss ich immer nach dem Starten der Wandlung die while - Schleife
> ausführen

Natürlich.
Woher will denn dein Programm sonst wissen, wann der ADC mit seiner 
Arbeit fertig ist?
Die Sache ist ganz einfach:
Du setzt ADSC im Register ADCSRA auf 1 und wenn der ADC fertig ist, dann 
setzt er das Bit wieder zurück auf 0.

Genau deshalb sieht die while Schleife so aus
1
  while( ADCSRA & _BV(ADSC) )  // solange das Bit auf 1 ist ...
2
    ;                          // ... mach nichts
oder, was dasselbe ist, weil sich ja hinter dem _BV Makro auch nichts 
anderes als die << Schreibweise versteckt
1
  while( ADCSRA & (1<<ADSC) )  // solange das Bit auf 1 ist ...
2
    ;                          // ... mach nichts

> oder kann ich die Warteschleife durch das abfragen des ADIE
> Interrupt, bzw. das ADIF Bit entfallen lassen?

Ja.
Persönlich mag ich die ABfrage des ADIF Flags nicht wirklich, weil es 
Mehrarbeit ist. Zum einen muss ich solange warten, bis das Flag gesetzt 
wird, zum anderen muss ich es aber selber zurücksetzen. Beim ADSC Bit 
brauch ich das alles nicht. Das Programm setzt es auf 1 um die Wandlung 
zu starten, der ADC setzt es wieder zurück auf 0, wenn er fertig ist.

> 4. Muss ich den ADC noch Inizialisieren mit "ADC_Init();"

Du hast ja die Initialisierung in deinem Code schon mit drinnen. Die 
Intialisierung ist ja nichts anderes als das Einstellen der 
Referenzspannung, des ADC Taktes und noch ein paar andere Dinge. Im 
Grunde ist die INitialisierung das Setzen bzw. Löschen von Bits in 
ADCSRA und ADMUX.

> 5. Um fest zu stellen ob ich eine Wandlung habe, kann ich das so machen?
> Also das ADIF Bit abfragen?
> ...
> if ( ADIF == 1 )

Wie fragt man denn ein bestimmtes Bit in einem bestimmten Register ab? 
Das solltest du jetzt aber eigentlich schon einigermassen sicher 
beherrschen!

Ich kann mich nur noch mal wiederholen: Es gibt Basisdinge, die musst du 
im Schlaf beherrschen! Nein, ich sag das nicht zu Spass. Das ist 
tatsächlich so! Du musst auf dem Kopf stehend um 3 Uhr früh ohne 
merkbare Reaktionszeit die Fragen nach
* wie setzt man ein Bit in einem Byte (Register)
* wie löscht man ein Bit in einem Byte (Register)
* wie stellt man fest, ob ein Bit in einem Byte (Register) auf 1 oder 0 
ist
beantworten können!
Es gibt keine Entschuldigung dafür, das nicht zu können. Es ist immer 
das gleiche Muster

Bit setzen
1
    variable |= ( 1 << Bitnummer );
2
oder
3
    variable |= _BV( Bitnummer );
Bit löschen
1
    variable &= ~( 1 << Bitnummer );
2
oder
3
    variable &= ~ _BV( Bitnummer );
Bit auf 1 abfragen
1
   if( variable & ( 1 << Bitnummer ) )
2
oder
3
   if( variable & _BV( Bitnummer ) )
Bit auf 0 abfragen
1
   if( !( variable & ( 1 << Bitnummer ) ) )
2
oder
3
   if( !( variable & _BV( Bitnummer ) ) )

Diese 4 immer wiederkehrenden Muster ziehen sich von Stunde 0 an durch 
die ganze µC-Programmiererei. Das beginnt mit dem gezielten 0 bzw. 1 
setzen von Portbits um damit LEDs ein bzw. aus zu schalten; geht über 
Pin Abfragen um damit die Stellung von Schaltern bzw. Tastendrücke zu 
detektieren und endet noch lange nicht beim ADC. Bits in einem Byte 
gezielt manipulieren zu können, ist absolute Basistechnik. Die muss 
sitzen. Das wäre so, wie wenn ein Chirurg kein Heftpflaster aufkleben 
kann.


Bitmanipulation

von Balou B. (baloubaer)


Lesenswert?

Hallo zusammen,

ich bedanke mich für euere Unterstützung. Den ADC habe ich nun zum 
laufen bekommen.

Morgen werde ich mal versuchen die Ergebnisse der Wandlung heraus zu 
bekommen.

Muss ich eigentlich bei meiner Wandlung mit dem Variablen Typ float 
arbeiten???

Da ja die Schrittweite der Spannung 5 V / 1024 = 0,004882812 V beträgt.

Eine Messung mit dem Multimeter an PA0 ergabe eine Spannung von 0,298 V.
Wenn ich dieses Ergebniss jetzt umwandle 0,298 V / 0,004882812 V = 61
61 in Binäre würde doch dieses Bitmuster ergeben 0011 1101? Angezeigt 
bekomme ich aber 0101 1100 (Dec 92). Was dann aber 92 * 0,00488 = 0,449 
V entspräche?

Verstehe ich nicht?   Vielleicht ist es auch zu spät, ich versuche es 
morgen noch einmal.

Oder hat jemand von euch eine Idee?

Ich bedanke mich für euere HIlfe und verbleibe

Mit freundlichen Grüßen

Balou Baer

von PittyJ (Gast)


Lesenswert?

Die 5V sind auch wirklich 5 Volt?
Also 5.000000000 und nicht 5.2 oder 4.8?

von Balou B. (baloubaer)


Lesenswert?

Hallo zusammen,

ich verstehe meinen ADC - Wandler nicht.

zu der Spannung sei gesagt, ich verwende jetzt AREF = AVCC = 5,04 V,

egal ob ich AREF direkt selber auf VCC (5,04 V) verdrahte oder ich durch 
setzen des REFS0 Bits, die AVCC Spannung für AREF verwende, durch das 
ADMUX Register,
1
ADMUX = _BV ( REFS0 );

, ich bekomme immer andere Werte angezeigt als an den PINA0 anliegen 
habe.

Das ADCSRA Register ist wiefolgt gesetzt:
1
ADCSRA =  _BV ( ADEN ) | _BV ( ADPS0 ) | _BV ( ADPS1 ) | _BV ( ADPS2 );

Gemessen mit einem Messgerät wird eine Spannung von 462 mV und mit LED´s 
wird mir das Bitmuster von ADCL und ADCH wie folgt angezeigt: 00 
11011100

Rechne ich nun das Bitmuster in eine Dezimalzahl um erhalte ich den Wert 
220.
Diesen Wert muss ich ja dann mit der Schrittweite (AREF/1024 => 5,04V / 
1024 =) von 4,921875 mV multiplizieren, richtig? Dabei käm raus 209 * 
4,921875mV = ca. 1,08 V.

Was kann das sein?

Verwende ich einen anderen ATMega 32 habe ich wieder andere Werte, 
obwohl ich nur den einen vom Sockel entferne und den anderen aufstecke. 
Beide haben den gleichen Code, beide die gleichen Einstellungen, alles 
Identisch.

Gemessen wird über einen Spannungsteiler:

An R1 liegt auf der einen Seite VCC an und auf der anderen Seite gehe 
ich zum PINA0 UND zum R2, R2 wird dann auf GND gelegt.

VCC -> R1 = 10 kOhm -> PINA0 UND R2 = ( 1 k - 125 kOhm ) -> GND

VCC ------|
          |
          _
         | |  R1
         |_|
          |__________ PINA0
          |
          _
         | |  R2
         |_|
          |
          |
GND ------|



Wäre doch so OK oder?

Nur warum Spinnt der ADC - Wandler mit den Spannungen so rum?

DDRA ist komplett auf 0 gesetzt, da ich das Register bzw. PINA0 als 
Eingang sehe und nicht als Ausgang.

Rechnerisch müßte, wenn ich mich nicht vertue, ( R2 * 5,04 V / ( R1 + R2 
) = Ur2  rauskommen:

( 1 kOhm * 5,04 V ) / ( 10 kOhm + 1 kOhm ) = 450 mV

von Balou B. (baloubaer)


Lesenswert?

HALLO ZUSAMMEN!!!!

Ich habe meinen Fehler gefunden!!!!!!!

DIE LED´s sind auf meinem Experimentierboard nicht gleich den 
Steckkontakten für die Drahtbrücken!!!!!

DIe LED´s sind von links nach rechts aufsteigent und die Anschlussleiste 
ist von recht nach links steigent. Habe mich heute NAcht durch die 
Schaltpläne des Experimentierboards gearbeitet.

FAZIT:

ALLES LÄUFT SO WIE ES SOLL! Danke euch!!!!

Bis demnächst.

von Balou B. (baloubaer)


Lesenswert?

Hallo noch einmal. ;)

Nachdem die Messung mit dem ADC-Wandler im Programm selber lief, wollte 
ich die Initialisierung und das eigentliche Messen in eine Funktion 
umwandel. Doch irgendetwas scheint nicht ganz richtig zu sein. Der ADC 
mist nichts, bzw. immer das gleiche obwohl sich die Spannungen ändern.

Könnt ihr bitte mal drüber gucken, was da eventuell in der Funktion 
falsch sein könnte.

ich bedanke mich für euere Hilfe und verbleibe,

mit freunldichen Grüßen

Balou Baer

1
/*---------- Initialisierung und einstellen des ADC -----------*/
2
3
void adc_init ( void )
4
{
5
  //ADC Wandler einstellen:
6
7
  ADCSRA =  _BV ( ADEN ) | _BV ( ADPS0 ) | _BV ( ADPS1 ) | _BV ( ADPS2 );  /*Aktivieren
8
  und einstellen des ADC Wandlers, hier Prescaler auf 128 bei CPU Takt 16 MHz, entspricht 125kHz Taktfrequenz 
9
  für ADC*/
10
  ADMUX = _BV ( REFS0 ); //AVCC als REFERENZSPANNUNG
11
12
// "Dummy-Readout" /*Erste Messung zur Kallibrierung*/
13
 
14
    ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
15
    while (ADCSRA & (1<<ADSC) ) 
16
  {         // auf Abschluss der Konvertierung warten
17
    }
18
     (void) ADCW; /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
19
     Wandlung nicht übernommen. */
20
}
21
22
/*-------------- Werte am ADC messen ---------------*/
23
24
uint16_t adc_read ( uint8_t channel )
25
{
26
  ADMUX &= ~ ( _BV ( MUX0 ) | _BV ( MUX1 ) | _BV ( MUX2 ) | _BV ( MUX3 ) | _BV ( MUX4 ) ) ;
27
  channel &= ( _BV ( MUX0 ) | _BV ( MUX1 ) | _BV ( MUX3 ) ) ;  /*Maskieren der Variable Channel, damit keine falschen
28
  übergeben werden können */
29
  ADMUX |= channel ; 
30
  ADCSRA |= _BV ( ADSC ) ;  //Start der Messung
31
  while (ADCSRA & (1<<ADSC) )  // auf Abschluss der Messung warten
32
  {
33
    }
34
  return ADCW ;  //Wert aus ADCW zurückgeben
35
}

von Captain Blaubaer (Gast)


Lesenswert?

Nimm doch einen Arduino. Das ist einfacher. Besonders wenn man keine 
Ahnung hat oder keine Lust sich mit dem Thema anhand von Literatur 
intensiv zu beschäftigen.

von Balou B. (baloubaer)


Lesenswert?

Captain Blaubaer schrieb:
> Nimm doch einen Arduino. Das ist einfacher. Besonders wenn man keine
> Ahnung hat oder keine Lust sich mit dem Thema anhand von Literatur
> intensiv zu beschäftigen.

SORRY ABER:

Das sind Antworten .......   ich schenke mir den Kommentar.... 
Kopfschüttel


Nimm doch ein Boot, wenn du keine Lust hast Auto zu fahren oder ein 
Ticket für Bus, Bahn oder Flugzeug zu kaufen.

Mhhhh.... Leider fließt kein Fluß da, wo ich hin will.


Mhhhh.... Leider habe ich kein Arduino und bingt mich auch nicht da hin, 
wo ich hin möchte.


Mit freundlichen Gruß

Balou Baer

von Rahul D. (rahul)


Lesenswert?

Balou Baer schrieb:
> Könnt ihr bitte mal drüber gucken, was da eventuell in der Funktion
> falsch sein könnte.

Bis auf die komische "_BV"-Formulierung sieht es gut aus (ich gehe davon 
aus, dass du die Programmteile einfach aus deinem funktionieren den 
Programm kopiert hast).
Demnach muss der Fehler an der aufrufenden Stelle sein...

von Balou B. (baloubaer)


Lesenswert?

Das mit dem kopieren ist nur zu 90% geschehen.

Die Initialisierung ist komplett kopiert, also was vorher im Programm 
stand steht jetzt in der Funktion.

Die eigentliche Messung (adc_read) ist angepasst worden. Vorher war im 
Programm fest der ADMUX auf Kanal 0 gesetzt. Jetzt möchte / muss ich 
mehrere Messungen an verschiedenen Kanälen durchführen. Daher habe ich 
jetzt eine Kanalübergabe und die Maskierung des Kanals ergänzt. 
Maskierung deshalb, damit nicht z.B. Kanal 9 übergeben werden kann.

Ich kann so auch keinen Fehler erkennen. Progcode unten.

Das mit dem _BV kam hier aus dem Forum und gefällt mir besser als 
1<<XXXX
1
#include .....
2
3
/*----------- Einbinden von Funktionen ------------*/
4
5
void DDR_config ( void ) ;
6
void TIMER_config ( void ) ;
7
void INTERRUPT_config ( void ) ;
8
void adc_init ( void ) ;
9
uint16_t adc_read ( uint8_t ) ;
10
11
.........
12
13
int main ( void )
14
{
15
        uint8_t LICHTSENSOR1 = 2, LICHTSENSOR2 = 4 ; //Variablenwert = Kanal
16
        uint16_t lichtsensor1 = 0, lichtsensor2 = 0 ;
17
        DDR_config ( ) ;  //Aufruf des Daten Richtungs Registers zur 
18
....
19
  adc_init ( );
20
....
21
        while ( 1 )
22
        {
23
            ..............
24
            lichtsensor1 = adc_read ( LICHTSENSOR1 ) ;
25
            lichtsensor2 = adc_read ( LICHTSENSOR2 ) ;
26
            ..............
27
         lcd_gotoxy ( 0 , 0 ) ; 
28
         LCD_putf ( lichtsensor1 ) ;
29
         ...........
30
         usw.
31
         }
32
}
33
34
/*---------- Initialisierung und einstellen des ADC -----------*/
35
36
void adc_init ( void )
37
{
38
  //ADC Wandler einstellen:
39
40
  ADCSRA =  _BV ( ADEN ) | _BV ( ADPS0 ) | _BV ( ADPS1 ) | _BV ( ADPS2 );  /*Aktivieren
41
  und einstellen des ADC Wandlers, hier Prescaler auf 128 bei CPU Takt 16 MHz, entspricht 125kHz Taktfrequenz 
42
  für ADC*/
43
  ADMUX = _BV ( REFS0 ); //AVCC als REFERENZSPANNUNG
44
45
// "Dummy-Readout" /*Erste Messung zur Kallibrierung*/
46
 
47
    ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
48
    while (ADCSRA & (1<<ADSC) ) 
49
  {         // auf Abschluss der Konvertierung warten
50
    }
51
     (void) ADCW; /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
52
     Wandlung nicht übernommen. */
53
}
54
55
/*-------------- Werte am ADC messen ---------------*/
56
57
uint16_t adc_read ( uint8_t channel )
58
{
59
  ADMUX &= ~ ( _BV ( MUX0 ) | _BV ( MUX1 ) | _BV ( MUX2 ) | _BV ( MUX3 ) | _BV ( MUX4 ) ) ;
60
  channel &= ( _BV ( MUX0 ) | _BV ( MUX1 ) | _BV ( MUX3 ) ) ;  /*Maskieren der Variable Channel, damit keine falschen
61
  übergeben werden können */
62
  ADMUX |= channel ; 
63
  ADCSRA |= _BV ( ADSC ) ;  //Start der Messung
64
  while (ADCSRA & (1<<ADSC) )  // auf Abschluss der Messung warten
65
  {
66
    }
67
  return ADCW ;  //Wert aus ADCW zurückgeben
68
}

von Uwe S. (de0508)


Lesenswert?

Hi,
1
ADMUX &= ~ ( _BV ( MUX0 ) | _BV ( MUX1 ) | _BV ( MUX2 ) | _BV ( MUX3 ) | _BV ( MUX4 ) ) ;
2
  channel &= ( _BV ( MUX0 ) | _BV ( MUX1 ) | _BV ( MUX3 ) );
Was ist mit MUX2 passiert ?

von Balou B. (baloubaer)


Lesenswert?

UPS!

MUX 3 sollte eigentlich MUX2 sein. Tippfehler! Danke aber im Programm 
ist es richtig gewesen.

von holger (Gast)


Lesenswert?

>Tippfehler! Danke aber im Programm ist es richtig gewesen.

Sprich: Du zeigst uns hier nicht deinen wirklichen Code.
Was soll das? Glaubst du hier sind Hellseher unterwegs?
Da kann man doch nur noch mit dem Kopf schütteln
und diesen Thread am besten ignorieren.

von Balou B. (baloubaer)


Lesenswert?

@Holger
OK, hier ist der Code.
1
//Einbinen von Headerdateien
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
//#include "C:\Users\patricke21\Documents\warten.h"
5
6
// Taktfequenz der CPU
7
#define F_CPU 16000000UL
8
9
10
11
//Zentrale eingabe der Maximalwerte
12
13
/*______________________________________________________________________________________________________________________________*/
14
15
#define LIMIT_SPEED 2 // <- Hier die gewünsche MAXIMALE Windgeschwindigkeit in km/h eingeben!
16
17
#define MELDEVERZOEGERUNG_WIND 0  // <- Hier die gewünschte Meldeverzögerung für Wind in Minuten eingeben!
18
19
#define PULSEREGEN_LIMIT 2  // <- Hier die gewünschte Regenmenge eingeben!
20
21
#define TIMEREGEN 10  // <- Hier Zeit, in Sekunden, zur Messung der Regenmenge eingeben!
22
23
/*______________________________________________________________________________________________________________________________*/
24
25
26
27
//Umrechnung der oben eingegebenen Werte:
28
29
#define PULSEWIND_LIMIT ( (LIMIT_SPEED * 1800 ) / 60 / 2 )  //Berechung der MAXIMALEN Pulse für 15 Sekunden
30
31
#define WARTEZEIT_WIND ( MELDEVERZOEGERUNG_WIND * 4 )  //Umrechung der MELDEVERZÖGERUNG für den Wind 
32
33
34
35
/*------------------------------------------------------------------------------------------------------------------------------*/
36
//Variablen deklaration:
37
38
volatile uint8_t timewind = 0, timeregen = 0/*, Messungfertig = 0, Merker2 = 0*/;
39
40
uint8_t vorherwind, jetztwind, wartezeitwind, vorherregen, jetztregen, pulseregen = 0, wind = 0;
41
42
uint8_t Windrichtung = 0, Lichtsensor1 = 1, Lichtsensor2 = 2, Lichtsensor3 = 3, Lichtsensor4 = 4, Lichtsensor5 = 5, Spannung = 6, Strom = 7;
43
44
uint16_t pulsewind;
45
46
float windrichtung;
47
48
/*------------------------------------------------------------------------------------------------------------------------------*/
49
50
/*----------- Einbinden von Funktionen ------------*/
51
52
void DDR_config ( void ) ;
53
void TIMER_config ( void ) ;
54
void INTERRUPT_config ( void ) ;
55
void adc_init ( void ) ;
56
uint16_t adc_read ( uint8_t ) ;
57
58
59
60
/*------------------------------------------------------------------------------------------------------------------------------*/
61
//Timer ISR zur Zeitmessung
62
63
ISR(TIMER1_COMPA_vect)
64
{
65
  if ( timewind > 0 )
66
  {
67
    timewind--;
68
  }
69
  if ( timeregen > 0 )
70
  {
71
    timeregen--;
72
  }
73
}
74
/*------------------------------------------------------------------------------------------------------------------------------*/
75
76
77
/*------------------------------------------------------------------------------------------------------------------------------*/
78
//ISR Regenerkennung:
79
80
ISR(INT0_vect)
81
{
82
  pulseregen++;  //Aufaddieren der Pulse vom PIND2
83
}
84
/*------------------------------------------------------------------------------------------------------------------------------*/
85
86
87
/*------------------------------------------------------------------------------------------------------------------------------*/
88
//ISR zur Windrichtungsauslesung
89
90
ISR(INT1_vect)
91
{
92
//  PORTB ^= ( 1 << PB5 );
93
}
94
/*------------------------------------------------------------------------------------------------------------------------------*/
95
96
97
// Hauptprogramm:
98
99
int main (void)
100
101
{
102
103
  DDR_config ( ) ;  //Aufruf des Daten Richtungs Registers zur Konfiguration der Ein- u. Ausgänge
104
  TIMER_config ( ) ;  //Interner Timer1 konfigurieren
105
  INTERRUPT_config ( ) ;  //Externe Interrupts ( INT0 bis INT2 ) konfigurieren
106
  sei ( ) ;  //Interrupts AKTIVIEREN!!!!
107
108
109
//  adc_init ();
110
111
112
/*------------- Zeiteinstellungen -------------*/
113
  
114
  //Zeit für Wind:
115
    timewind = 15;
116
117
  //Zeit für Regen:
118
    timeregen = TIMEREGEN;
119
120
/*------------------------------------------------------------------------------------------------------------------------------*/
121
//Definieren der ersten Zustände für Flankenerkennung:
122
  
123
  vorherwind = ( PIND & ( 1 << PD0 ) );
124
/*------------------------------------------------------------------------------------------------------------------------------*/
125
  
126
  
127
//Ständig laufendes Programm:  
128
  
129
  while(1)
130
  {
131
132
/*------------------------------------------------------------------------------------------------------------------------------*/
133
//Ermittlung der Windgeschwindigkeit:
134
    
135
    jetztwind = ( PIND & ( 1 << PD0 ) );  //Abfrage ob Taster gedrückt und Abfrage speichern
136
137
    if ( jetztwind != vorherwind )   //Vergleich der beiden Vaiablen, wenn ungleich dann weiter
138
        {
139
          vorherwind = jetztwind;  //aktueller Wert speichern 
140
141
      if ( jetztwind ) 
142
        {
143
            pulsewind++;  //Wird um 1 erhöht, wenn steigende Flanke am Eingang PD0 erkannt
144
         }
145
    };
146
        
147
    if ( timewind == 0 )  //Abfrage der Zeit
148
    {
149
          if ( pulsewind > PULSEWIND_LIMIT )  //Abfrage der Pulse
150
          {
151
        wind++;
152
153
        if ( wind >= WARTEZEIT_WIND )
154
        {
155
          PORTD |= ( 1 << PD1 );  // Ausgang zum Haupt uC an PIND2 INT0
156
          PORTB |= ( 1 << PB0 );  // Anzeige LED
157
          wind = 0;
158
        }
159
      }
160
161
      else
162
      {
163
            PORTD &= ~( 1 << PD1 ); //Ausgang zum Haupt uC an PIND2 INT0
164
        PORTB &= ~( 1 << PB0 );  //Anzeige LED
165
        wind = 0;
166
      }  
167
168
          pulsewind = 0;  //Zurücksetzen der Werte
169
          timewind = 15;  //Zurücksetzen der Werte
170
    }
171
/*------------------------------------------------------------------------------------------------------------------------------*/
172
173
174
/*------------------------------------------------------------------------------------------------------------------------------*/
175
// Ermittlung der Regenmenge 
176
177
    if ( ( pulseregen >= PULSEREGEN_LIMIT ) && ( timeregen == 0 ) )  //Abfrage der Pulse und der Zeit
178
    {
179
      //Einschalten der Ausgänge
180
181
      PORTD |= ( 1 << PD4 );  //Ausgang zum Haupt uC an PIND3 INT1
182
      PORTB |= ( 1 << PB1 );  //Anzeige LED
183
184
//      windrichtung = adc_read ( Windrichtung );/*ADCW;  //Auslesen des Ergebnisses der ADC Wandlung*/
185
      
186
      /* Ergebnisse für die Himmelsrichtungen:
187
      N = 788, NO = 464, O = 93, SO = 186, S = 288, SW = 634, W = 946, NW = 889*/
188
189
      pulseregen = 0;  //Zurücksetzen der Werte
190
      timeregen = TIMEREGEN;  //Zurücksetzen der Werte
191
    };
192
193
    if ( ( pulseregen < PULSEREGEN_LIMIT ) && ( timeregen == 0 ) )  //Abfrage der Pulse und der Zeit
194
    {
195
      //Ausschalten der Ausgänge
196
197
      PORTD &= ~( 1 << PD4 );  //Ausgang zum Haupt uC an PIND3 INT1
198
      PORTB &= ~( 1 << PB1 );  //Anzeige LED
199
200
      pulseregen = 0;  //Zurücksetzen der Werte
201
          timeregen = TIMEREGEN;  //Zurücksetzen der Werte
202
    };
203
  }
204
  return 0;
205
}
206
207
208
209
/*---------- Konfigurieren des DDRA Register ----------*/
210
211
void DDR_config ( void )
212
{
213
//  DDRA = _BV ( PB );  //Konfiguration der Ein und Ausgänge an Pord A; 0=Eingang, 1=Ausgang
214
  DDRB = _BV ( PB1 ) | _BV ( PB0 );  //Konfiguration der Ein und Ausgänge an Pord B; 0=Eingang, 1=Ausgang
215
//  DDRC = _BV ( PB );  //Konfiguration der Ein und Ausgänge an Pord C; 0=Eingang, 1=Ausgang
216
  DDRD = _BV ( PD4 ) | _BV ( PD1 );  //Konfiguration der Ein und Ausgänge an Pord D; 0=Eingang, 1=Ausgang
217
}
218
219
220
/*---------- Initialisierung und einstellen des ADC ----------*/
221
222
void adc_init ( void )
223
{
224
  //ADC Wandler einstellen:
225
226
  ADCSRA =  _BV ( ADEN ) | _BV ( ADPS0 ) | _BV ( ADPS1 ) | _BV ( ADPS2 );  /*Aktivieren
227
  und einstellen des ADC Wandlers, hier Prescaler auf 128 bei CPU Takt 16 MHz, entspricht 125kHz Taktfrequenz 
228
  für ADC*/
229
  ADMUX = _BV ( REFS0 ); //AVCC als REFERENZSPANNUNG
230
231
// "Dummy-Readout" /*Erste Messung zur Kallibrierung*/
232
 
233
    ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
234
    while (ADCSRA & (1<<ADSC) ) 
235
  {         // auf Abschluss der Konvertierung warten
236
    }
237
     (void) ADCW; /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
238
     Wandlung nicht übernommen. */
239
}
240
241
242
/*---------- Werte am ADC messen ----------*/
243
244
uint16_t adc_read ( uint8_t channel )
245
{
246
  ADMUX &= ~ ( _BV ( MUX0 ) | _BV ( MUX1 ) | _BV ( MUX2 ) | _BV ( MUX3 ) | _BV ( MUX4 ) ) ;
247
  channel &= ( _BV ( MUX0 ) | _BV ( MUX1 ) | _BV ( MUX2 ) ) ;  /*Maskieren der Variable Channel, damit keine falschen
248
  übergeben werden können */
249
  ADMUX |= channel ; 
250
  ADCSRA |= _BV ( ADSC ) ;  //Start der Messung
251
  while (ADCSRA & (1<<ADSC) )  // auf Abschluss der Messung warten
252
  {
253
    }
254
  return ADCW ;  //Wert aus ADCW zurückgeben
255
}  
256
257
258
/*---------- Timer einstellen----------*/
259
260
void TIMER_config ( void )
261
{
262
  TCCR1B = _BV ( WGM12 ) | _BV ( CS12 ) | _BV ( CS10 ) ;  //Timer1 konfigurieren
263
  OCR1A = 15624 ;  //Vergleichsregister setzten
264
  TIMSK = _BV ( OCIE1A ) ;  //Timer1 CompA-Interrupt AKTIVIEREN
265
}
266
267
268
/*---------- Interrupts einstellen----------*/
269
270
void INTERRUPT_config ( void )
271
{
272
  MCUCR = _BV ( ISC11 ) | _BV ( ISC01 );  // 0b00001010;    //Externe Interrupts konfigurieren (Fallende Flanke)
273
  GICR = _BV ( INT1 ) | _BV ( INT0 );  // 0b11000000;    //Freigeben der Externen Interrups
274
}

von holger (Gast)


Lesenswert?

>OK, hier ist der Code.

In dem nicht ein Stück ADC verwendet wird.
Das wird hier nichts mehr. Zwecklos.

von Thomas H. (Firma: CIA) (apostel13)


Lesenswert?

Captain Blaubaer schrieb:
> Nimm doch einen Arduino. Das ist einfacher. Besonders wenn man keine
> Ahnung hat oder keine Lust sich mit dem Thema anhand von Literatur
> intensiv zu beschäftigen.

Dem kann ich mich nur anschließen!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.