PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Probleme mit UART und ATmega168, Dringend!



Nils Wenzler
02.12.2007, 17:42
Hallo
Ich muss um eine Projektarbeit fertigstellen zu können endlich den ATmega-168 mit meinem PC verbinden und Werte auf den Schirm senden. Also ich habe folgende Software im AVR:


//uart_tx:
// -Bedienen des UART-Hardware Modules
// -Hardware: -UART
//************************************************** *******************************************

#include <avr/io.h>
#include "uart_tx.h"
#include "avr/interrupt.h"
#include "stdlib.h"

#define F_CPU 8000000L
#define BAUD 9600L

// Berechnungen
#define UART_UBRR_CALC ((F_CPU)/((BAUD)*16L)-1)

//local
volatile uint8_t data;

//uart_init, Initialisiere UART

void uart_tx_init(){

UCSR0B |= (1<<TXEN0) | (1 << TXCIE0); // UART TX einschalten
UCSR0C |= (1<<UMSEL00)|(0<<UMSEL01); // Asynchron 8N1


UBRR0H =(uint8_t)(UART_UBRR_CALC>>8); //set baudrate
UBRR0L = UART_UBRR_CALC & 0xFF;


}

/* SENDEN*/

//uart_tx sendet ein Zeichen, uart_txs ein String, uart_txs_var einen ASCII Zeichensatz

void uart_tx(uint8_t c) {

SREG |= (0 << 7);
data=c ;
SREG |= (1 << 7);


}




//String senden
void uart_txs(uint8_t *s) {
while (*s)
{ // so lange *s != '\0' also ungleich dem "String-Endezeichen"
uart_tx(*s);
s++;
}

}


//Integer zu ASCII (Zeichen)
void uart_txs_var(uint16_t i){
char s[7];
i = -12345;

itoa( i, s, 10 ); // 10 fuer radix -> Dezimalsystem
uart_tx(*s);

}

ISR(USART_TX_vect){
UDR0 = data ;
}



Das Headerfile:


#ifndef uart_tx_H_
#define uart_tx_H_

void uart_tx_init();
void uart_tx(uint8_t c);
void uart_txs (uint8_t *s);
void uart_txs_var(uint16_t i);

#endif /*uart_tx_H_*/



Und im Main sieht das ganze mit dm Befehl so aus:


#include <avr/io.h>
#include "uart_tx.h"
#include "alog_digi.h"
#include "send.h"



int main(void) {


//Init
void ir_mod_init();
void uart_tx_init();
void alog_digi_init();

//Hauptschleife
while(1) {
uart_tx('v');
//send();

return 0;
}
}



Auf dem Pc verwende ich Linux, angezeigt wird mit dem Minicom, die Baud ist korrekt auf 9600 eingestellt und der Port ttyS0 (RS232 Serieller Port) ist freigeschaltet. langsam verzweifle ich, da es Partout nicht funktionieren will. (Soll heissen ich habe auf dem Minicom keinerlei Reaktion.

Hat irgendwer ne Idee?

Danke
Gruss Nils Wenzler

Hubert.G
02.12.2007, 18:52
Ich würde sagen dein UCSRC Register stimmt nicht
UCSR0C |= (1<<UCSZ00)|(1<<UCSZ01); sollte das nicht so aussehen

Nils Wenzler
02.12.2007, 19:05
Danke viel mals!!!
Das ist ein Anfang!
Allerdings bekomme ich jetzt erst "Rubish" auf den Schirm...
Gibt es einen Fehler beim Senden, beim umrechnen in ASCII Zeichen oder so?
Probiert habe ich zb folgenden Befehl:
uart_tx('v');
uart_txs_var('v');
und das ganze noch mit 8-bit integern. Es kommt immer nur "Datenmüll auf dem Schirm an.)
(Irgendwas mit der Baud-Berechnung falsch o.ä?
Gruss Nils

askazo
02.12.2007, 19:06
Uh, das stimmt aber einiges nicht....
Das UCSRC-Register brauchst Du gar nicht anzupacken. Das steht in der Grundeinstellung schon auf Asynchron 8N1

Dein schlimmster Fehler ist es, das Senden über einen Interrupt machen zu wollen.
Deine uart_tx() kann so nicht funktionieren.

SREG |= (0 << 7);
Diese Zeile macht gar nix. Du veroderst das Global Interrupt Enable Bit mit 0 - völlig nutzlos. Wieso willst Du hier das Bit überhaupt anpacken?

Die Interruptroutine, in der Du das UDR-Register beschreibst, wird erst dann ausgeführt, wenn ein Byte gesendet wurde. Du beißt Dir hier also in den eigenen Schwanz. Der Interrut ist nicht dazu gedacht, eine Senderoutine aufzubauen, sondern um eine Reaktion auf ein gesendetes Byte zu generieren.

Kurz und bündig: Um Deine Sendung zum laufen zu bringen, müsste Deine uart_tx() einfach so aussehen:

void uart_tx(uint8_t c) {
UDR0 = c ;
}

Und lass die Interrupts ausgeschaltet - zum Senden brauchst Du die nicht.

askazo

Nils Wenzler
02.12.2007, 19:14
ok gemacht... allerdings kommt immer noch nur Datenmüll :(

askazo
02.12.2007, 19:29
Dann müsstest Du noch mal Deine Baudratenberechnung überprüfen - obwohl die eigentlich korrekt aussieht. Arbeitest Du mit internem Takt? Der kann durchaus schon mal ein ganzes Stück daneben liegen. Dann müsstest Du mal versuchen, den Wert für das UBRR0 Register manuell anzupassen und ein paar Werte nach oben bzw. unten korrigieren. Wenn Du ein Oszilloskop zu Hand hast, kannst Du das ganze auch mal nachmessen - würde die Sache sehr vereinfachen.

Eins habe ich noch vergessen: Ganz korrekt müsste die Senderoutine so aussehen. Eventuell ist das schon der Grund für Deinen Datenmüll:

void uart_tx(uint8_t c) {
while ( !(UCSR0A & (1<<UDRE0)) ) //warte, bis Senderegister leer ist
UDR0 = c ; //senden
}

askazo

Nils Wenzler
02.12.2007, 22:27
Also:
Der Code müsste jetzt korrekt sein. Ein Kollege hat ihn so getestet.
Allerdings habe och wohl noch n Hardware Problem! Das ganze sendet nur (Datenmüll) wenn ich den Pin mit dem Stecker des RS232 Kabels Berühre...
Ich bin echt am Verzweifeln...
Nun dachte ich das es an einem ungenauen internen Oszi liegt (8mhz), un dbin mittlerweile auf 1200 Baud runter, wo es auch mit dem gehen sollte...?
Gruss nils

Mr Bean
02.12.2007, 22:53
Hallo

Also ich hatte auch immer das Problem mit dem Datenmüll... bei mir lag es nach einigen anderen Fehlern auch noch an der Einstellung der Fusebits. Also der Einstellung des Taktes. Versuch erstmal die definitiv richtig zu stellen bevor Du die Baudrate runter drehst. 9600B sollten kein Problem sein. Was verwendest Du denn für einen Takt? Würde Dir empfehlen einen externen zu verwenden. Geht aber normal auch mit den internen.

Grüße!!

Bean

Nils Wenzler
02.12.2007, 23:13
Im datenblatt ist angegeben das er mit 8mhz internem Takt ausgeliefert wird. Damit betriebe ich ihn auch... Also ich habe nichts verstellt.
Auf was deutet denn das " Senden nur wenn man sozusagen einen Wackelkontakt am Pin generiert (immer wieder berühren)" hin?
Gruss Nils

izaseba
02.12.2007, 23:31
Im datenblatt ist angegeben das er mit 8mhz internem Takt ausgeliefert wird.

Es steht aber noch da, daß er mit einem /8 Teiler ausgeliefert wird :-$

Hubert.G
03.12.2007, 09:38
Das wackeln, Pin berühren könnte eine schlechte/fehlende Masseverbindung sein.