PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : UART mit Atmega8535 Problem



booty
06.10.2007, 14:11
Hallo!
Ich habe mit dem programmieren von Mikrocontrollern erst vor kurzem angefangen, doch
jetzt habe ich ein Problem. Ich benutze zum Programmieren das STK500 und den Mikrocontroller
ATMEGA8535.
Mit dem unten stehenden Programm möchte ich, den Buchstaben x über rs232 an den PC senden, doch da
kommt nix an. Könnt Ihr mir anhand des Programmes sagen was ich falsch mache.
Danke!




#include <stdint.h>
#include <avr/io.h>




#ifndef F_CPU
#define F_CPU 4000000
#endif
#define UART_BAUD_RATE 9600



UBRR = F_CPU / (UART_BAUD_RATE * 16L) - 1;




int main(void)
{
UCSRB |= (1<<TXEN);
UCSRC |= (1<<URSEL)|(3<<UCSZ0);


while (!(UCSRA & (1<<UDRE)));
UDR = 'x';
return 0;
}

izaseba
06.10.2007, 14:52
Hallo,
Auf den ersten Blick(ohne in Dattenblatt geguckt zu haben) sieht es schonmal nicht schlecht aus, aber
1. Bei dir fehlt eine Endlosschleife machmal vor return 0;
while(1);
2. Ich beobachte immerwieder, daß Leute Ausdrücke wie


UCSRB |= (1<<TXEN);

toll finden.
Irgendeiner hat damit angefangen, und alle machen das nach...
UCSRB wird hier zum ersten mal angesprochen, und Du willst ja nur den Transmiter einschalten, lass diesen OR weg, welchen Wert hat UCSRB nach der Initialisierung?
Ist er sicher 0?
wenn nicht kommt nur Käse raus, ich hoffe, das ist verständlich...
3. Wenn es immernoch nicht klappt
3a. Läuft der Kontroller wirklich mit 4 Mhz ?
3b. hat das Terminalprogramm am PC die gleichen Einstellungen, wie µC ?

Schaumal, sonst nochmal melden ;-)

Gruß Sebastian

booty
07.10.2007, 16:24
Danke für deine Antwort!
Es funktioniert jetzt alles.
Eine Frage habe ich noch. Wie sieht der Quellcode aus, wenn ich die ganze Sache per Interrupt auslösen möchte?

kater
07.10.2007, 16:34
2. Ich beobachte immerwieder, daß Leute Ausdrücke wie


UCSRB |= (1<<TXEN);

toll finden.
Irgendeiner hat damit angefangen, und alle machen das nach...
UCSRB wird hier zum ersten mal angesprochen, und Du willst ja nur den Transmiter einschalten, lass diesen OR weg, welchen Wert hat UCSRB nach der Initialisierung?
Ist er sicher 0?

Laut Datenblatt ist der Wert des Registers nach dem Start 0. Das sollte wohl genügen. Die werden das auch sicher nicht ins Datenblatt schreiben wenn es nicht so wäre.

izaseba
07.10.2007, 18:24
Hallo,


Es funktioniert jetzt alles.
Schön :-) woran lag es jetzt ? Endlosschleife ?


Wie sieht der Quellcode aus, wenn ich die ganze Sache per Interrupt auslösen möchte?

Schau mal hier (https://www.roboternetz.de/phpBB2/viewtopic.php?t=34533)
hab ich schon was dazu geschrieben, eh, die 2 letzten Beiträge würde ich einfach ignorieren, sowas nennt man Spam ;-)

@kater,
Gut, ich meine aber, daß nach einem Softreset die Registerinhalte bleiben, es ist allgemein besser für klare Inhalte zu sorgen, mir persönlich ist es aber egal, wie die Leute das machen, nur bevor sowas als Fehlerquelle vorkommt...

Gruß Sebastian

kater
07.10.2007, 18:47
@kater,
Gut, ich meine aber, daß nach einem Softreset die Registerinhalte bleiben, es ist allgemein besser für klare Inhalte zu sorgen, mir persönlich ist es aber egal, wie die Leute das machen, nur bevor sowas als Fehlerquelle vorkommt...

Gruß Sebastian

Ahja, da haben wir es schon. Ich bin von einem Reset über den Pin RESET ausgegangen. Also sozusagen ein Hardwarereset ;)
Was ist jetzt ein Softreset? Sowas hab ich noch nie gelesen.

izaseba
07.10.2007, 18:53
Ja, also softwarereset wäre z.B. ein Sprung nach 0x0000

Gruß Sebastian

kater
07.10.2007, 19:17
Ah Ok. Ja ich denke, dass die wenigsten einen Softwarereset machen, aber wenn, dann sollte man sicher gehen, dass die Register geleert sind.

izaseba
07.10.2007, 19:30
Ja das stimmt, das ist ein ziemlicher Hack mit dem softreset, es ging sich aber darum, daß man die Register mal ruhig direkt beschreiben soll und nicht immer mit dem altem Inhalt verodern, es gibt da weitere Architekturen, wo es vielleicht nicht üblich ist daß die Register default 0 sind.

Gruß Sebastian

kater
08.10.2007, 09:32
Wie sieht es denn aus, wenn der Wachdog den reset verübt? Ich würde wetten, dann sind die Register wieder per default alle auf 0 :)

izaseba
08.10.2007, 18:55
Hallo Kater,
Da ich eher ein praktischer Mensch bin, habe ich das eben auf meinem Dragon ausprobiert, die Wette hättest Du gewonnen, egal welche Werte man in die Register reinschreibt, nach einem Watchdog Reset sind sie wieder auf 0 :-)

Gruß Sebastian

kater
09.10.2007, 05:34
Dankeschön :) .

booty
09.10.2007, 17:02
Hallo!
Ich brauche mal nochmal Hilfe. Ich habe versucht über rs232 vom PC auf den Controller eine 1 zu senden und dann soll eine LED ausgehen. Das habe ich per Interrupt versucht, doch es funbktioniert leider nicht.
Kann einer mal den Quelltext anschauen und sagen was ich falsch gemacht habe?
Danke!

#include <avr/io.h>
#include <avr/interrupt.h>
#define USART_RXC_vect _VECTOR(14)


#define F_CPU 1000000UL
#define BAUD 9600UL
#define UBRR_BAUD ((F_CPU/(16L*BAUD))-1)

uint8_t buffer;

void uart_init(void)
{

UBRRH = (uint8_t) (UBRR_BAUD>>8);
UBRRL = (uint8_t) (UBRR_BAUD & 0xFF);
UCSRB = (1<<TXEN) | (1<<RXEN);
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}


ISR(USART_RXC_vect)
{
UCSRB = (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
while (!(UCSRA & (1<<RXC)))
buffer = UDR;
}


void led_init(void)
{
if(buffer==0x31)
PORTA=0x01;

else
PORTA=0x00;
}


int main(void)
{
sei();
DDRA = 0xff;
led_init();
uart_init();

}

izaseba
09.10.2007, 17:57
Hallo booty,
eigentlich steht alles in dem Link, den ich Dir gepostet habe drin, aber egal, ich erkläre es nochmal

1. Problem:


#define USART_RXC_vect _VECTOR(14)

Das ist unnötig, kann eventuell schaden, lass das weg, das ist Aufgabe von Compiler (Präprozessor) den Vektor richtig zuzuordnen.
2. Problem:


uint8_t buffer;

buffer muß als volatile deklariert werden, warum, sehe link oben


volatile uint8_t buffer;
3. Problem


UCSRB = (1<<TXEN) | (1<<RXEN);
Ja, hier mußt Du noch den Interrupt einschalten, sonst wird er nie ausgeführt, also


UCSRB = (1<<TXEN) | (1<<RXEN)|(1<<RXCIE);

4. Problem, der Interrupt sollte etwa so aussehen:


ISR(USART_RXC_vect)
{
buffer = UDR;
}
Du brauchst hier keine flags mehr setzen, oder auf irgendwas warten.
5. Problem, es fehlt wieder die Endlosschleife, mach das etwa so:


int main(void)
{
DDRA = 0xff;
uart_init();
sei();
for(;;){
led_init();
}
return 0;
}

So dann schaumal...
Anmerkung noch Du kannst auch anstatt von 0x31 '1' schreiben, ist vielleicht einfacher zu lesen(wenn man die ASCII Werte nicht im Kopf hat.

Viel Erfolg

@kater,
Kein Problem, der Dragon hat sich auch gefreut mal ein paar Bytes schaufeln zu dürfen, außerdem wollte ich es auch wissen...
Gruß Sebastian

booty
09.10.2007, 18:15
Danke für deine schnelle Hilfe!!!!!!!!

booty
09.10.2007, 18:54
Hallo!

Ich habe alles geändert, so wie es beschrieben ist, doch es funktioniert immer noch nicht. Hat einer noch ne Idee?
Danke!

Hier noch mal der geänderte Quellcode:

#include <avr/io.h>
#include <avr/interrupt.h>


#define F_CPU 1000000UL
#define BAUD 9600UL
#define UBRR_BAUD ((F_CPU/(16L*BAUD))-1)

volatile uint8_t buffer;

void uart_init(void)
{

UBRRH = (uint8_t) (UBRR_BAUD>>8);
UBRRL = (uint8_t) (UBRR_BAUD & 0xFF);
UCSRB = (1<<TXEN) | (1<<RXEN)|(1<<RXCIE);
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}


ISR(USART_RXC_vect)
{
buffer = UDR;
}


void led_init(void)
{
if(buffer==0x31)
PORTA=0x01;

else
PORTA=0x00;
}


int main(void)
{
DDRA = 0xff;
uart_init();
sei();
while(1){
led_init();
}
return 0;
}

mogel
11.10.2007, 12:16
Moin,


Ich habe alles geändert, so wie es beschrieben ist, doch es funktioniert immer noch nicht. Hat einer noch ne Idee?
überprüf mal ob Du auch wirklich 0x31 sendest und nicht 0x01




ISR(USART_RXC_vect)
{
buffer = UDR;
}


void led_init(void)
{
if(buffer==0x31)
PORTA=0x01;

else
PORTA=0x00;
}

bevor in led_init() buffer ausgelesen werden kann, kann ein andere Interrupt buffer wieder geändert haben (ja ich weis - wird bei diesem kleinen Programm nicht passieren)

also - entweder



ISR(USART_RXC_vect)
{
led_init(UDR)
}
void led_init(char value)
{
PORTA = value
}


oder die kurze Variante ... da es nur ein Testprogramm ist



ISR(USART_RXC_vect)
{
PORTA = (UDR == 0x31) ? 0x01 : 0x00;
// PORTA = UDR;
}


um als Alternative zu sehen ob überhaupt was am UART/Interrupt ankommt


ISR(USART_RXC_vect)
{
static char dummy = 0;
PORTA = dummy++;
if (dummy == 255) dummy = 0;
}


Detailänderung



int main(void)
{
DDRA = 0xff;
uart_init();
sei();
while(1) {
// CPU schlafen legen ... spart Akkus
}
return 0;
}


hand, mogel