UART und AD Wandler in kombination

Gast #546784
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
}
#546799
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.
Gast #546806
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
}
#546810
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?
#546815
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
Gast #546832
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
}
Gast #546867
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...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren