mikrocontroller.net

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


Autor: studiarbeit (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <avr/io.h>


int AD_Lesen(unsigned char Kanal)
{

 int result;

 ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler
                              // setzen auf 8 (1) und ADC aktivieren (1)

 ADMUX = ADMUX | Kanal;                     // Kanal waehlen


//--> beim einkommentieren der zeile plötzlich langsames Wandeln (1sec)
 ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen


 ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung



 while ( ADCSRA & (1<<ADSC) )
 {
       // auf Abschluss der Konvertierung warten
 };

 result = ADCW;  // ADCW muss einmal gelesen werden,
                 // sonst wird Ergebnis der nächsten Wandlung
                 // nicht übernommen.

return result;
}


void USART_Transmit(unsigned char data )
{
/* Wait for empty transmit buffer */
while ( !( UCSRA & (1<<UDRE)) );
/* Put data into buffer, sends the data */
UDR = data;
}


void USART_Init( unsigned int ubrr)
{
/* Set baud rate */
UBRRH = (unsigned char)(ubrr>>8);
UBRRL = (unsigned char)ubrr;
/* Enable receiver and transmitter */
UCSRB = (1<<RXEN)|(1<<TXEN);
/* Set frame format: 8data, 2stop bit */
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}

#define FOSC 16000000// Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1




int main(void)
{
USART_Init(MYUBRR);
  while(1)
  {
    PORTB = AD_Lesen(0x00);
    USART_Transmit('a');  
  }
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: studiarbeit (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ????
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) )
     {
       
     }; 
} 

int AD_Lesen()
{

   int result;


     while ( ADCSRA & (1<<ADSC) )
     {
           // auf Abschluss der Konvertierung warten
     };

   result = ADCW;  // ADCW muss einmal gelesen werden,
                   // sonst wird Ergebnis der nächsten Wandlung
                   // nicht übernommen.

return result;
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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-Tu...

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: studiarbeit (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ....

void USART_Transmit(unsigned char data )
{
// Wait for empty transmit buffer 
while ( !( UCSRA & (1<<UDRE)) );
// Put data into buffer, sends the data 
UDR = data;
}


void USART_Init( unsigned int ubrr)
{
// Set baud rate 
UBRRH = (unsigned char)(ubrr>>8);
UBRRL = (unsigned char)ubrr;
// Enable receiver and transmitter 
UCSRB = (1<<RXEN)|(1<<TXEN);
// Set frame format: 8data, 2stop bit 
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}

int AD_Lesen(unsigned char Kanal)
{

  int result;
 
  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler 
                               // setzen auf 8 (1) und ADC aktivieren (1)
 
  ADMUX = Kanal;                      // Kanal waehlen
  ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen 
 
  // nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
  //   also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" 
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung 

  while ( ADCSRA & (1<<ADSC) ) 
  {
        // auf Abschluss der Konvertierung warten 
  };

  result = ADCW;  // ADCW muss einmal gelesen werden,
                  // sonst wird Ergebnis der nächsten Wandlung
                  // nicht übernommen.
 
return result;
}


int main(void)
{
unsigned char c=0;
DDRB = 0xff;
USART_Init(MYUBRR);

  while(1)
  {
//  PORTB = AD_Lesen(0x00);
  USART_Transmit(c);
  c++;

  }
  return 0;
}

Autor: studiarbeit (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
natürlich marke A verbessen:

//  PORTB = AD_Lesen(0x00);

  PORTB = AD_Lesen(0x00);

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Triple lernresistent ;-(

Bin weg ;-)

Autor: studiarbeit (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Axel R. (axelr) Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du verstehts aber schon, was der Code im einzelnen macht, oder?
int AD_Lesen(unsigned char Kanal)
{  int dummy;
   int result;
//Raus damit, gehört in ADC_INIT(); 
//  ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // Frequenzvorteiler 
                               // setzen auf 8 (1) und ADC aktivieren (1)
// Kanal waehlen "oder ist gleich!", sonst ist ADMUX überschrieben und die INIT sinnlos. 
  ADMUX |= Kanal;                      
//Raus damit, gehört in ADC_INIT();
//  ADMUX |= (1<<REFS1) | (1<<REFS0); // interne Referenzspannung nutzen 
 
  // nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
  //   also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" 

/*Also startest Du hier eine Wandlung, wartest auf "fertig" und liest einen Messwert aus. Wo ist denn jetzt der "dummy-Readout"???*/

/*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.*/

//1. Dummyreadout
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung 

  while ( ADCSRA & (1<<ADSC) ) 
  {
        // auf Abschluss der Konvertierung warten 
  };

  dummy = ADCW;  // ADCW muss einmal gelesen werden,
                  // sonst wird Ergebnis der nächsten Wandlung
                  // nicht übernommen.

//2. "echte" Wandlung
  ADCSRA |= (1<<ADSC);              // eine ADC-Wandlung 

  while ( ADCSRA & (1<<ADSC) ) 
  {
        // auf Abschluss der Konvertierung warten 
  };

  result = ADCW;  // ADC wird erneut gelesen und das Ergebnis
                  // übernommen
                  
return result;
}

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...

Autor: studiarbeit (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Problem hat sich gelöst mit einem anderen AVR Studio auf einem anderen 
Rechner ....

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.