www.mikrocontroller.net

Forum: Compiler & IDEs Baudrate umschalten


Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Zusammen,

Ich hab nach einiger Zeit wieder mal was Programiert und es funzt nicht 
so wie ich mir das vorstelle und ich weiß nicht mehr weiter.
Folgendes Problem: Ich möchte ein LIN Protokoll nachbilden und um die 
Aufmerksamkeit meiner LIN-Bus-Teilnehmer zu wecken muss ich mindestens 
13 byte hintereinander eine logische "0" auf den Bus legen. Zweimal 
hintereinander "uart_putc(0x00);" geht nicht, zwischen den beiden kommt 
immer ein kurzes "high" ...wegen stoppbit??
Dann dachte ich ok, clever, mach ich ein "uart_putc(0x00);" mit 4800 
baud und schalte dan auf 9600 baud um und mach den rest. Das Programm 
sieht so aus:
#define Bd4800 0x67 // 4800Bd @ 8 MHz
#define Bd9600 0x33 // 9600Bd @ 8 MHz


void f_LINReq(void)
{
UBRR= Bd4800;
uart_putc(0x00);
asm volatile("nop"); // einfach mal zum Versuch etwas Zeit zu vertödeln.
asm volatile("nop"); // vieleicht braucht es etwas Zeit um sich "einzuschwingen" ??
UBRR= Bd9600;
asm volatile("nop");
asm volatile("nop"); 
uart_putc(0x55);
}


Geht aber auch nicht, das Programm schikt beide Bytes mit 9600baud raus, 
die logische 0x00 dauert somit 920uS. Kommentiere ich aber die Zeile 
UBRR= Bd9600; aus dan sendet es beide Bytes mit 4800 baud. Ganz ehrlich 
ich versteh das nicht. Sieht hier jemand einen logischen Grund??

Danke und Gruß!

Autor: 6645 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Waere nicht ein "Break" das Gewuenschte ?

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn mir noch jemand erklär wie ein "Break" Programmiert wird und was er 
macht kann ich dir die Frage mit "ja" oder "nein" beantworten ;)

Ich bin mit allem zufrieden was mir ca. 1,8 ms den LIN- Bus auf logisch 
0 legt.

Allerdings hab ich es auch schon mit "PORTD=(1<<PD1)" -( Ich habe einen 
AT90S8535) und einer _delay_us(1800); versucht, geht aber auch nicht 
weil die delay funktionen überhaupt nicht funktionieren, warum weiß ich 
ebenfalls nicht.

Autor: Thomas W. (thomasw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin!

Um welchen Controller geht es eigentlich?
Kannst du nicht die 13Byte manuell verschicken, also UART abschalten und 
die Pins manuell ansteuern? Anschließend für die "normale" Kommunikation 
UART wieder einschalten.

MfG

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

Bewertung
0 lesenswert
nicht lesenswert
Markus wrote:

> Allerdings hab ich es auch schon mit "PORTD=(1<<PD1)" -( Ich habe einen
> AT90S8535) und einer _delay_us(1800); versucht, geht aber auch nicht
> weil die delay funktionen überhaupt nicht funktionieren, warum weiß ich
> ebenfalls nicht.

* Du hast den Optimizer nicht eingeschaltet
* Du hast nicht beachtet, dass es eine Obergrenze für _delay_ms
  gibt. Die ist aber in delay.h dokumentiert.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nach uart_putc() solltest du schon warten bis das
geschriebene Byte auch weg ist bevor du einfach die
Baudrate umschaltest. Welches Register und Flag
musste man dazu noch abfragen ? Ich glaube das steht
im Datenblatt.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus wrote:
> Geht aber auch nicht, das Programm schikt beide Bytes mit 9600baud raus,
> die logische 0x00 dauert somit 920uS. Kommentiere ich aber die Zeile
> UBRR= Bd9600; aus dan sendet es beide Bytes mit 4800 baud. Ganz ehrlich
> ich versteh das nicht. Sieht hier jemand einen logischen Grund??

Ja, das ist o.k.

Dein putc wartet nur, bis der Sendepuffer frei ist.
Du kannst also 2 Bytes in den Sendepuffer stellen.
Das Wechseln der Baudrate erfolgt zeitlich betrachtet, noch vor dem 
Senden des ersten Bytes.
Die 2 NOPs bewirken garnichts. Ein Bit dauert bei 4800Baud 3333 NOPs.


Du mußt das Senden beeendet Bit abtesten, bevor Du ne neue Baudrate 
einstellst.


Peter

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger wrote:
> Du mußt das Senden beeendet Bit abtesten, bevor Du ne neue Baudrate
> einstellst.

Und das steht auch im Datenblatt in dem passenden Kapitel...

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke, das mit dem "Senden beendet Bit abtesten" habe ich verstanden und 
wollte es auch gleich umsetzten, aber irgendwie sind meine 
Programierkenntnisse wohl sehr eingerostet. Ich bekomm es nicht hin.
Ich wollte einfach eine "while-schleife" programmieren die auf diese Bit 
maskiert ist. Als ich die aber drin hatte kam gar nichts mehr raus aus 
dem TxD port. Ich hab sie dann zu debug zwecken runtergestrickt, das 
Programm sieht jetzt so aus:

#define Bd4800 0x67  // 4800Bd @ 8 MHz
#define Bd9600 0x33 // 9600Bd @ 8 MHz


void f_LINReq(void)
{

UBRR= Bd4800;
uart_putc(0x00);

while(1)
{
uart_putc(0xAA);
}
  
UBRR= Bd9600;
uart_putc(0x55);

}

Nach meinen (bescheidenen) Kenntnissen müsste das Programm jetzt in der 
while-Schleife hängen bleiben und ständig 0xAA senden. Es kommt aber gar 
nix. Ändere ich es hingegen um in:
while(0)
giebt das Programm wie zu erwarten 0x00 und 0x55 aus. Wieso springt es 
nicht in die while-schleife? Bin ich doof?

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

Bewertung
0 lesenswert
nicht lesenswert
Markus wrote:

> Nach meinen (bescheidenen) Kenntnissen müsste das Programm jetzt in der
> while-Schleife hängen bleiben und ständig 0xAA senden.

Richtig. Und zwar mit 4800 Baud

> Es kommt aber gar
> nix. Ändere ich es hingegen um in:
> while(0)
> giebt das Programm wie zu erwarten 0x00 und 0x55 aus. Wieso springt es
> nicht in die while-schleife? Bin ich doof?

Wie sieht deine uart_putc aus?

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So, danke bis dahin für allen Antworten! Ich bin nun schon etwas weiter 
aber noch nicht am Ziel.
Ich habe die 13 Byte mit logisch 0 anderst realisiert. Ich schalte den 
TX einfach aus und leg den Portpin einige Zeit auf 0. Das geht auch ganz 
gut.
Was immer noch nicht geht ist das Abfragen von TXC. Ich würde gerne 2 
Kommandos auf den Bus schiken mit etwas Pause dazwischen. Der Code dazu:
void f_LINReq(void)
{
StopTimer2;

UCR=0xD0;      //TX ausschalten
PORTD &= ~(1<<PD1);     //TxD auf logisch 0
_delay_us(1800);        //und 1,8ms so lassen
PORTD |= (1<<PD1);        //TxD auf logisch 1
_delay_us(220);    //und 220us so lassen
UCR=0xD8;      //TX einschalten
uart_putc(0x55);
uart_putc(0x42);
uart_putc(0x0F);
uart_putc(0x37);

loop_until_bit_is_set(USR,TXC); //warten bis alles gesendet ist


_delay_ms(11);

UCR=0xD0;      //TX ausschalten
PORTD &= ~(1<<PD1);     //TxD auf logisch 0
_delay_us(1800);        //und 1,8ms so lassen
PORTD |= (1<<PD1);        //TxD auf logisch 1
_delay_us(220);    //und 220us so lassen
UCR=0xD8;      //TX einschalten
uart_putc(0x55);
uart_putc(0x37);

StartTimer2;

}

So, das mit dem "warten auf TXC" geht wie gesagt nicht. So wie der code 
dasteht sehe ich einmal meine logisch 0 für 1800us und anschliesend 
nichts mehr. Nichteinmal die Zeichen vor dem Warten werden gesendet. Wo 
hängt das ganze?
Irgendwie bleibt das Programm in der Endlosschleife hängen. Was ich aber 
nicht verstehe wieso den nicht wenigstens die Zeichen vor der 
Warteschleife gesendet werden.
PS: Das TXCEN hab ich gesetzt aber noch keine ISR dafür geschrieben.

Danke für eure Hilfe!

Autor: Markus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
noch ein Nachtrag zu der Frage von Karl heinz Buchegger:
Ich habe die routine für uart_putc aus dem netz und die Funktion sieht 
so aus:
void uart_putc(unsigned char data)
{
    unsigned char tmphead;

    
    tmphead  = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
    
    while ( tmphead == UART_TxTail ){
        ;/* wait for free space in buffer */
    }
    
    UART_TxBuf[tmphead] = data;
    UART_TxHead = tmphead;

    /* enable UDRE interrupt */
    UART0_CONTROL    |= _BV(UART0_UDRIE);

}/* uart_putc */


Ich werd ehrlich nicht ganz schlau draus was er da macht. Vielleicht 
liegt das Problem auch hier.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Markus wrote:

> Ich werd ehrlich nicht ganz schlau draus was er da macht.

Das ist nicht gut.
Man sollte schon wissen, was man verwendet.


Diese Routine ist ein Teil einer SW-FIFO.
D.h. wenn die FIFO 100 Byte lang ist, kann man 100 Byte reinschreiben 
und die Funktion kehrt sofort zurück, ohne das auch nur ein Byte 
wirklich gesendet wurde.
Zu dieser Funktion müssen noch 2 weitere (FIFO-Init und FIFO-Send) 
gehören, das Senden ist ein Interrupthandler.


Peter

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Müsste von Peter Fleury sein.
http://www.jump.to/fleury

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.