Forum: Mikrocontroller und Digitale Elektronik UART und AD Wandler in kombination


von studiarbeit (Gast)


Lesenswert?

Hallo Männer,

wir stehen vor einem Problem bei unserer Studienarbeit und kommen 
absolut nicht weiter. Hauptaufgabe sind messwerte, die ein AD Wandler 
erfässt und über eine Schnittstelle weiter geben soll. Doch jedesmal, 
wenn wir AD und UART in kombination nutzen wird die Schnittstelle total 
langsam. Nach langem testen haben wir herausgefunden das alles wunderbar 
funktioniert wenn die Zeile

ADMUX |= (1<<REFS1) | (1<<REFS0);

auskommentiert ist. Wir brauchen jedoch die Interne Referenzspannung von 
2.56V.

Wer kann uns hier mal weiterhelfen ???

Ausführbarer Code für Atmega16:
1
#include <avr/io.h>
2
3
4
int AD_Lesen(unsigned char Kanal)
5
{
6
7
 int result;
8
9
 ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler
10
                              // setzen auf 8 (1) und ADC aktivieren (1)
11
12
 ADMUX = ADMUX | Kanal;                     // Kanal waehlen
13
14
15
//--> beim einkommentieren der zeile plötzlich langsames Wandeln (1sec)
16
 ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
17
18
19
 ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung
20
21
22
23
 while ( ADCSRA & (1<<ADSC) )
24
 {
25
       // auf Abschluss der Konvertierung warten
26
 };
27
28
 result = ADCW;  // ADCW muss einmal gelesen werden,
29
                 // sonst wird Ergebnis der nächsten Wandlung
30
                 // nicht übernommen.
31
32
return result;
33
}
34
35
36
void USART_Transmit(unsigned char data )
37
{
38
/* Wait for empty transmit buffer */
39
while ( !( UCSRA & (1<<UDRE)) );
40
/* Put data into buffer, sends the data */
41
UDR = data;
42
}
43
44
45
void USART_Init( unsigned int ubrr)
46
{
47
/* Set baud rate */
48
UBRRH = (unsigned char)(ubrr>>8);
49
UBRRL = (unsigned char)ubrr;
50
/* Enable receiver and transmitter */
51
UCSRB = (1<<RXEN)|(1<<TXEN);
52
/* Set frame format: 8data, 2stop bit */
53
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
54
}
55
56
#define FOSC 16000000// Clock Speed
57
#define BAUD 9600
58
#define MYUBRR FOSC/16/BAUD-1
59
60
61
62
63
int main(void)
64
{
65
USART_Init(MYUBRR);
66
  while(1)
67
  {
68
    PORTB = AD_Lesen(0x00);
69
    USART_Transmit('a');  
70
  }
71
}

von Karl H. (kbuchegg)


Lesenswert?

Wobei sich natürlich die Frage erhebt, welchen Sinn
es macht, den ADC für jede Messung neu zu initialisieren.
Die erste Messung nach einer Initialisierung dauert laut
Atmel immer etwas länger. Ich könnte mir durchaus vorstellen,
dass das damit zu tun hat, dass Atmel der Referenzspannung Zeit
geben will sich zu stabilisieren.

von studiarbeit (Gast)


Lesenswert?

Hallo,

Danke für die schnelle Antwort! Hast recht, im normalen Programm gibts 
auch ne init und ne lese:

funktioniert aber trozdem nicht. Kanns an der Hardware liegen, oder was 
ist falsch ????
1
void AD_Init(unsigned char Kanal)
2
{
3
   ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler
4
                              // setzen auf 8 (1) und ADC aktivieren (1)
5
   ADMUX = ADMUX | Kanal;                     // Kanal waehlen
6
   ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
7
     while ( ADCSRA & (1<<ADSC) )
8
     {
9
       
10
     }; 
11
} 
12
13
int AD_Lesen()
14
{
15
16
   int result;
17
18
19
     while ( ADCSRA & (1<<ADSC) )
20
     {
21
           // auf Abschluss der Konvertierung warten
22
     };
23
24
   result = ADCW;  // ADCW muss einmal gelesen werden,
25
                   // sonst wird Ergebnis der nächsten Wandlung
26
                   // nicht übernommen.
27
28
return result;
29
}

von Karl H. (kbuchegg)


Lesenswert?

void AD_Init(unsigned char Kanal)
{
   ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler
                              // setzen auf 8 (1) und ADC aktivieren (1)
   ADMUX = ADMUX | Kanal;                     // Kanal waehlen
   ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen
     while ( ADCSRA & (1<<ADSC) )
     {

     };
}

Wieso willst du zum Abschluss der Initialisierung auf
das Ende einer Wandlung warten, wenn noch gar keine
gestartet wurde?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Sowohl AD als auch UART werden mit Polling gemacht. Ich würde eine 
Umstellung auf einen interruptgesteuerten Programmablauf in Betracht 
ziehen.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Grunds.C3.A4tzlicher_Programmaufbau_eines_.C2.B5C-Programms

von Falk B. (falk)


Lesenswert?

@ studiarbeit

>Danke für die schnelle Antwort! Hast recht, im normalen Programm gibts
>auch ne init und ne lese:

>funktioniert aber trozdem nicht. Kanns an der Hardware liegen, oder was
>ist falsch ????

Dann poste den ORIGINALEN Quelltext und nicht irgendwelche 
zusammenkopierten Fragmente.

MfG
Falk

von studiarbeit (Gast)


Lesenswert?

also nochmal zurück zum Thema,

Der polling betrieb ist schon so in ordung ich möchte einfach kein 
Inerrupt. Vieleicht später wenn erst mal alles am laufen ist. Mir kommt 
es jetzt auch überhaupt nicht auf eine Performace steigerung oder 
Optimierung an. Deswegen die vereinfachung im code.

Ich glaube auch langsam nicht mehr an ein Programmierfeheler sondern 
eher was an der Hardware. Ich wäre überglücklich wenns doch bitte jemand 
mal testen könnte.

Beim Auskommentieren der Marke (A) funktioniert der UART und beim 
einkomme ntieren funktionierts eben nicht mehr. --> Vermutung UART 
greift auf AD Wandelrgister zu oder umgekehrt. Was aber nicht im 
Handbuch steht. Wäre über ein bischen hilfe total dankbar ....

1
void USART_Transmit(unsigned char data )
2
{
3
// Wait for empty transmit buffer 
4
while ( !( UCSRA & (1<<UDRE)) );
5
// Put data into buffer, sends the data 
6
UDR = data;
7
}
8
9
10
void USART_Init( unsigned int ubrr)
11
{
12
// Set baud rate 
13
UBRRH = (unsigned char)(ubrr>>8);
14
UBRRL = (unsigned char)ubrr;
15
// Enable receiver and transmitter 
16
UCSRB = (1<<RXEN)|(1<<TXEN);
17
// Set frame format: 8data, 2stop bit 
18
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
19
}
20
21
int AD_Lesen(unsigned char Kanal)
22
{
23
24
  int result;
25
 
26
  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler 
27
                               // setzen auf 8 (1) und ADC aktivieren (1)
28
 
29
  ADMUX = Kanal;                      // Kanal waehlen
30
  ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen 
31
 
32
  // nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
33
  //   also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" 
34
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung 
35
36
  while ( ADCSRA & (1<<ADSC) ) 
37
  {
38
        // auf Abschluss der Konvertierung warten 
39
  };
40
41
  result = ADCW;  // ADCW muss einmal gelesen werden,
42
                  // sonst wird Ergebnis der nächsten Wandlung
43
                  // nicht übernommen.
44
 
45
return result;
46
}
47
48
49
int main(void)
50
{
51
unsigned char c=0;
52
DDRB = 0xff;
53
USART_Init(MYUBRR);
54
55
  while(1)
56
  {
57
//  PORTB = AD_Lesen(0x00);
58
  USART_Transmit(c);
59
  c++;
60
61
  }
62
  return 0;
63
}

von studiarbeit (Gast)


Lesenswert?

natürlich marke A verbessen:

//  PORTB = AD_Lesen(0x00);

  PORTB = AD_Lesen(0x00);

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Triple lernresistent ;-(

Bin weg ;-)

von studiarbeit (Gast)


Lesenswert?

Hallo steffan du gehörst aber nicht zu den hilfsbereiten Wäre es nicht 
möglich das Prog mal bei dir zu testen ????

Grüße

von Axel R. (Gast)


Lesenswert?

Du verstehts aber schon, was der Code im einzelnen macht, oder?
1
int AD_Lesen(unsigned char Kanal)
2
{  int dummy;
3
   int result;
4
//Raus damit, gehört in ADC_INIT(); 
5
//  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler 
6
                               // setzen auf 8 (1) und ADC aktivieren (1)
7
// Kanal waehlen "oder ist gleich!", sonst ist ADMUX überschrieben und die INIT sinnlos. 
8
  ADMUX |= Kanal;                      
9
//Raus damit, gehört in ADC_INIT();
10
//  ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen 
11
 
12
  // nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
13
  //   also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" 
14
15
/*Also startest Du hier eine Wandlung, wartest auf "fertig" und liest einen Messwert aus. Wo ist denn jetzt der "dummy-Readout"???*/
16
17
/*Nehmen wir an, das es sich hier um den Dummyreadout handelt, dann musst Du die Wandlung nochmal anschubsen, um dein korrektes Messergebnis als Return zur Verfügung zu stellen.*/
18
19
//1. Dummyreadout
20
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung 
21
22
  while ( ADCSRA & (1<<ADSC) ) 
23
  {
24
        // auf Abschluss der Konvertierung warten 
25
  };
26
27
  dummy = ADCW;  // ADCW muss einmal gelesen werden,
28
                  // sonst wird Ergebnis der nächsten Wandlung
29
                  // nicht übernommen.
30
31
//2. "echte" Wandlung
32
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung 
33
34
  while ( ADCSRA & (1<<ADSC) ) 
35
  {
36
        // auf Abschluss der Konvertierung warten 
37
  };
38
39
  result = ADCW;  // ADC wird erneut gelesen und das Ergebnis
40
                  // übernommen
41
                  
42
return result;
43
}

ADC Takt ist so ok? Welche Taktfrequenz hat der Controller?
Kannst Du BITTE DEN KOMPLETTEN CODE posten?
Bzw. welches ist denn nun dein kompletter Code? (kurzer Link drauf 
genügt)

Was ist/soll "c++" in der UART-Transmitt Ruotine?

sollte eigentlich mit den gegebenen Hinweisen funktionieren, denke ich 
mal.
Gruß
AxelR.


Ich habe die Hinweise als Kommentar in die Quelle geschrieben. sieht man 
kaum...

von studiarbeit (Gast)


Lesenswert?

Problem hat sich gelöst mit einem anderen AVR Studio auf einem anderen 
Rechner ....

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.