Baudrate umschalten

Gast #842813
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ß!
Gast #842870
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.
#842873
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.
Gast #842882
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.
#842888
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
Gast #843068
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?
#843199
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?
Gast #846213
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!
Gast #846217
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.
#846280
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren