Forum: Compiler & IDEs Baudrate umschalten


von Markus (Gast)


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:
1
#define Bd4800 0x67 // 4800Bd @ 8 MHz
2
#define Bd9600 0x33 // 9600Bd @ 8 MHz
3
4
5
void f_LINReq(void)
6
{
7
UBRR= Bd4800;
8
uart_putc(0x00);
9
asm volatile("nop"); // einfach mal zum Versuch etwas Zeit zu vertödeln.
10
asm volatile("nop"); // vieleicht braucht es etwas Zeit um sich "einzuschwingen" ??
11
UBRR= Bd9600;
12
asm volatile("nop");
13
asm volatile("nop"); 
14
uart_putc(0x55);
15
}

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ß!

von 6645 (Gast)


Lesenswert?

Waere nicht ein "Break" das Gewuenschte ?

von Markus (Gast)


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.

von Thomas W. (thomasw)


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

von Karl H. (kbuchegg)


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.

von holger (Gast)


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.

von Peter D. (peda)


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

von Simon K. (simon) Benutzerseite


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

von Markus (Gast)


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:
1
#define Bd4800 0x67  // 4800Bd @ 8 MHz
2
#define Bd9600 0x33 // 9600Bd @ 8 MHz
3
4
5
void f_LINReq(void)
6
{
7
8
UBRR= Bd4800;
9
uart_putc(0x00);
10
11
while(1)
12
{
13
uart_putc(0xAA);
14
}
15
  
16
UBRR= Bd9600;
17
uart_putc(0x55);
18
19
}

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?

von Karl H. (kbuchegg)


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?

von Markus (Gast)


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:
1
void f_LINReq(void)
2
{
3
StopTimer2;
4
5
UCR=0xD0;      //TX ausschalten
6
PORTD &= ~(1<<PD1);     //TxD auf logisch 0
7
_delay_us(1800);        //und 1,8ms so lassen
8
PORTD |= (1<<PD1);        //TxD auf logisch 1
9
_delay_us(220);    //und 220us so lassen
10
UCR=0xD8;      //TX einschalten
11
uart_putc(0x55);
12
uart_putc(0x42);
13
uart_putc(0x0F);
14
uart_putc(0x37);
15
16
loop_until_bit_is_set(USR,TXC); //warten bis alles gesendet ist
17
18
19
_delay_ms(11);
20
21
UCR=0xD0;      //TX ausschalten
22
PORTD &= ~(1<<PD1);     //TxD auf logisch 0
23
_delay_us(1800);        //und 1,8ms so lassen
24
PORTD |= (1<<PD1);        //TxD auf logisch 1
25
_delay_us(220);    //und 220us so lassen
26
UCR=0xD8;      //TX einschalten
27
uart_putc(0x55);
28
uart_putc(0x37);
29
30
StartTimer2;
31
32
}

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!

von Markus (Gast)


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:
1
void uart_putc(unsigned char data)
2
{
3
    unsigned char tmphead;
4
5
    
6
    tmphead  = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
7
    
8
    while ( tmphead == UART_TxTail ){
9
        ;/* wait for free space in buffer */
10
    }
11
    
12
    UART_TxBuf[tmphead] = data;
13
    UART_TxHead = tmphead;
14
15
    /* enable UDRE interrupt */
16
    UART0_CONTROL    |= _BV(UART0_UDRIE);
17
18
}/* uart_putc */

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

von Peter D. (peda)


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

von Simon K. (simon) Benutzerseite


Lesenswert?

Müsste von Peter Fleury sein.
http://www.jump.to/fleury

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.