ATmega328p und UART

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.

ATmega328p und UART

Beitragvon Mathias » 18. Okt 2017, 19:52 ATmega328p und UART

Ich habe aus der Datei Mega328pProject.zip die procedure UARTTinit rauskopiert.
Aber wen ich diese kompilieren will, wird kein Register ausser UBRR_VAL erkannt.
Woran liegt das ?
Code: Alles auswählen
Const
  f_CPU = 4000000; //Hertz
  Baud  = 9600;
 
procedure UARTInit;
Const
  UBRR_VAL   = ((F_CPU+BAUD*8) div (BAUD*16)-1);
begin
  //BaudRate
  UBRRL:= byte(UBRR_VAL);
  UBRRH:= byte(UBRR_VAL div 256);
  //Datenbit, Parität etc
  UCSRC:= (1 shl URSEL) or (1 shl UCSZ2) or (1 shl UCSZ); //8bit, 1Stopbit, keine Parität
  //UART aktivieren
  UCSRB:= (1 shl TXEN)   //TX aktivieren (Senden)
       or (1 shl RXEN)   //RX aktivieren (Empfangen)
       or (1 shl RXCIE); //Interrupt bei Empfang
  //Interrupts erlauben
  InterruptsEnable;
 
end;
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3188
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 18. Okt 2017, 21:51 Re: ATmega328p und UART

In der unit Atmega328P zumindest heissen die Register etwas anders:

Code: Alles auswählen
  UDR0 : byte absolute $00+$C6; // USART I/O Data Register
  UCSR0A : byte absolute $00+$C0; // USART Control and Status Register A
  UCSR0B : byte absolute $00+$C1; // USART Control and Status Register B
  UCSR0C : byte absolute $00+$C2; // USART Control and Status Register C
  UBRR0 : word absolute $00+$C4; // USART Baud Rate Register  Bytes
  UBRR0L : byte absolute $00+$C4; // USART Baud Rate Register  Bytes
  UBRR0H : byte absolute $00+$C4+1; // USART Baud Rate Register  Bytes
 


Hat jemand halt so gemacht, es gibt auch AVRs mit mehreren Uarts. Du kannst entweder die Register in der unit umbennen, die Register nochmal neu deklarieren, oder die Register in Deinem Programm anpassen, ich würde letzteres tun.
Timm Thaler
 
Beiträge: 430
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 19. Okt 2017, 17:37 Re: ATmega328p und UART

Ich habe folgendes probiert, aber es kommt nichts aus dem UART, es flackern nicht mal die RX/TX LEDs auf dem Arduino.
Einzig, die LED 13 blinkt, somit läuft die Schleife durch.
Klammere ich die Zeile mit UARTBusyWait; aus, dann bleibt die Schleife hängen.
Code: Alles auswählen
program Project1;.
const
  BP5 = 5; // Pin 13 des Arduino
  sl = 25000;
 
  procedure mysleep(t: int32);
  var
    i: Int32;
  begin
    for i := 0 to t do begin
      asm
               NOP;
      end;
    end;
  end;
 
Const
  f_CPU = 16000000; //Hertz
  Baud  = 9600;
 
procedure UARTInit;
Const
  UBRR_VAL   = ((F_CPU+BAUD*8) div (BAUD*16)-1);
begin
  //BaudRate
  UBRR0L:= byte(UBRR_VAL);
  UBRR0H:= byte(UBRR_VAL div 256);
  //Datenbit, Parität etc
  UCSR0C:= (1 shl UMSEL0) or (1 shl UCSZ02) or (1 shl UCSZ0); //8bit, 1Stopbit, keine Parität
  //UART aktivieren
  UCSR0B:= (1 shl TXEN0)   //TX aktivieren (Senden)
       or (1 shl RXEN0)   //RX aktivieren (Empfangen)
       or (1 shl RXCIE0); //Interrupt bei Empfang
  //Interrupts erlauben
//  InterruptsEnable;
end;
 
Procedure UARTBusyWait;assembler;
label waitBusy;
asm
  waitBusy:  //Warten bis UDR für das nächste Byte bereit ist
    sbis 0x0B,5 //sbis UCSRA,UDRE
   rjmp waitBusy
end;
 
Procedure SendString(s: ShortString);
var
  i:Integer;
begin
  for i := 1 to length(s)-1 do begin
//    UARTBusyWait;            // Als Test entfernt.
    UDR0:= Byte(s[i]);
  end;
end;
 
begin
  UARTInit;
  DDRB := DDRB or (1 shl BP5);
  repeat
    SendString('Hello World');
    PORTB := PORTB or (1 shl BP5);
    mysleep(sl);
 
    PORTB := PORTB and not (1 shl BP5);
    mysleep(sl);
  until 1 = 2;
end.\0
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3188
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 19. Okt 2017, 20:09 Re: ATmega328p und UART

Code: Alles auswählen
  UBRR0L:= byte(UBRR_VAL);
  UBRR0H:= byte(UBRR_VAL div 256);

Erst UBBRH, dann UBBRL schreiben, weil mit Schreiben von UBBRL der Wert übernommen wird. Ist bei vielen 16bit-Registern so. Datenblatt Seite 195.

Code: Alles auswählen
  UCSR0C:= (1 shl UMSEL0) or (1 shl UCSZ02) or (1 shl UCSZ0); //8bit, 1Stopbit, keine Parität


UCSZ02 gehört in UCSR0B, und für 8bit wird das auch nicht gesetzt, sondern UCSZ01. Steht hier zufällig an der gleichen Stelle. Siehe Datenblatt Seite 194.

UMSEL0 setzt synchronen Uart, das macht man bei SPI oder DI. RS232 läuft eigentlich immer asynchron. Siehe Beispiel Datenblatt Seite 176.

Code: Alles auswählen
UCSR0B:= (1 shl TXEN0) or (1 shl RXEN0) or (1 shl RXCIE0);


Du schaltest mit RXCIE0 den Interrupt für Empfang ein, hast aber keine Interruptroutine. Wenn Du Pech hast und der Interruptvektor nicht mit einem ordentlichen Rücksprungbefehl versehen ist, kommt der Controller durcheinander. Nur aktivieren wenn auch verwendet. Stört aber hier nicht weil ja keine Daten empfangen werden.

UARTBusyWait kann mit in SendString. Der Sendebuffer ist nur ein Byte groß. Deswegen muss gewartet werden bis das Byte gesendet wurde, bevor Du das nächste Byte in den Buffer packst.

Code: Alles auswählen
  for i := 1 to length(s)-1 do begin
   while UCSR0A and (1 shl UDRE0) = 0 do;
    UDR0:= Byte(s[i]);
  end;


Ungetestet, sollte gehen. Der Kompiler ist recht intelligent und optimiert das dann schon zu sbis. Inline-Assembler hat den Nachteil, dass der Compiler da wenns blöd kommt ziemlich viel überflüssige Registersicherung betreibt.
Timm Thaler
 
Beiträge: 430
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 20. Okt 2017, 17:27 Re: ATmega328p und UART

UCSZ02 gehört in UCSR0B, und für 8bit wird das auch nicht gesetzt, sondern UCSZ01.

Nut gibt es kein UCSZ01 in der Unit Atmega328p.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3188
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Mathias » 20. Okt 2017, 19:34 Re: ATmega328p und UART

So jetzt läuft es, sogar in beide Richtungen.
Beim Empfang von [Space], wird "Hello Wordl !" gesendet.
UCSZ01 wurde anscheinend in der Atmega328p vergessen, ich habe in der Arduino iom328p.h nachgeguckt und hat auch "2", der gleiche Wert wie UCSZ02.
Mir ist in den Sinn gekommen, das ich dies schon mal unter C++ gemacht hatte, somit habe ich die Lösung. 8)
Code: Alles auswählen
program Project1;
const
  f_CPU  = 16000000; // Hertz
  Baud   = 9600;
  UCSZ01 = 2;
 
  procedure UARTInit2;
  var
    teiler: integer;
  begin
    teiler := f_CPU div (2 * Baud) - 1;
    UBRR0H := teiler shr 8;
    UBRR0L := teiler;
 
    UCSR0A := UCSR0A or (0 shl U2X0);
    UCSR0B := UCSR0B or (1 shl TXEN0) or (1 shl RXEN0);
    UCSR0C := UCSR0C or (1 shl UMSEL0) or (1 shl UCSZ01) or (1 shl UCSZ0);
 
    DDRD := DDRD or (1 shl 4);
  end;
 
  procedure SendChar(c: char);
  begin
    while UCSR0A and (1 shl UDRE0) = 0 do ;
    UDR0 := byte(c);
  end;
 
  function ReadChar: char;
  begin
    while UCSR0A and (1 shl RXC0) = 0 do ;
    Result := char(UDR0);
  end;
 
  procedure SendString(s: ShortString);
  var
    i: integer;
  begin
    for i := 1 to length(s) do
    begin
      SendChar(s[i]);
    end;
  end;
 
begin
  UARTInit2;
  repeat
    if ReadChar = #32 then
      SendString('Hello World !'#13#10);
  until 1 = 2;
end.

Was mich verwundert, es wird zum Senden und Empfangen das Register UDR0 benutzt. Ich dachte immer die COM-Schnittstelle sei bilddirektional ?
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3188
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 20. Okt 2017, 21:14 Re: ATmega328p und UART

Mathias hat geschrieben:UCSZ01 wurde anscheinend in der Atmega328p vergessen, ich habe in der Arduino iom328p.h nachgeguckt und hat auch "2", der gleiche Wert wie UCSZ02.


Nein, nicht vergessen, das war nur ein fauler Sack. ;-)

UCSZ01 und UCSZ00 bilden ja zusammen ein "Doppelbit", binär %11. (1 shl UCSZ01) or (1 shl UCSZ00) ist also gleich (%11 shl UCSZ00), und das ist gleich (3 shl UCSZ00). Man kann also, wenn man beide Bits setzen will (3 shl UCSZ00) schreiben, oder (%11 shl UCSZ00). Wenn man nur das höhere setzen will (2 shl UCSZ00), oder ganz übersichtlich (%10 shl UCSZ00).

Da diese "Einsparmaßnahme an mehreren Stellen in der Unit zum 328p und ich nehme an auch in Units anderer Controller vorkommt, solltest Du Dir das gleich angewöhnen. Hier einfach ein anderes Kürzel zu nehmen - viel Spaß bei der Fehlersuche, wenn Du die Routine mal mit einem anderen Controller verwenden willst, bei dem die Bitfolge anders ist.

Was mich immer noch wundert: Warum setzt Du UMSEL0? Damit schaltest Du synchrone Übertragung ein, das brauchst Du nur, wenn Du das als SPI-Interface nutzen willst.

Mathias hat geschrieben:Was mich verwundert, es wird zum Senden und Empfangen das Register UDR0 benutzt. Ich dachte immer die COM-Schnittstelle sei bilddirektional ?


Ich verweise ja ungern schon wieder auf das Datenblatt, Seite 191. Das sind zwei physische Register, die sich eine Adresse teilen. Genaugenommen ist es noch etwas komplizierter:

Beim Senden wird UDR0 (Byte 1) in ein Shiftregister kopiert und dieses dann rausgeschoben. Währenddessen können wieder Daten (Byte 2) in UDR0 geschrieben werden, müssen dann aber warten, bis die Daten (Byte 1) aus dem Shiftregister komplett raus sind, was bei 9600baud etwa 1msec dauert. Erst dann werden diese Daten (Byte 2) in das Shiftregister kopiert, und Du kannst die nächsten Daten (Byte 3) in UDR0 schreiben. Deswegen musst Du, wenn Du mehrere Bytes hintereinander schreibst immer auf UDRE0 warten.

Beim Empfangen werden die Daten in einem Register gesammelt. Ist das voll (Byte 1), bekommst Du die Meldung, dass Daten empfangen wurden, und die folgenden Daten (Byte 2) werden in einem zweiten Register gesammelt. In der Zeit musst Du die Daten aus dem ersten Register abholen, sonst geht das dritte Byte verloren. Umgeschalten wird immer durch einen Lesevorgang, Du kannst also nicht zweimal das gleiche Byte aus UDR0 auslesen.

Vorteil ist, Du hast immer ein Byte lang Zeit, UDR0 zu lesen, was bei 9600baud 1msec ist. Allerdings hat Deine Leseroutine ReadChar den Nachteil: Kommen keine Daten an, bleibt der Controller an dieser Stelle hängen. Deswegen macht man sowas gern in einem Interrupt, die Daten werden zeitnah ausgelesen, aber der Controller wird nicht blockiert.
Timm Thaler
 
Beiträge: 430
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 21. Okt 2017, 18:53 Re: ATmega328p und UART

Was mich immer noch wundert: Warum setzt Du UMSEL0? Damit schaltest Du synchrone Übertragung ein, das brauchst Du nur, wenn Du das als SPI-Interface nutzen willst.
Wen ich des lösche, dann funktioniert das Ganze nicht mehr.

Du schaltest mit RXCIE0 den Interrupt für Empfang ein, hast aber keine Interruptroutine.
Könnte ich, wen dieses Register gesetzt ist, ein Interuptroutine schreiben, welche die Daten in eine Puffer schreibt, und dann diese später bei Bedarf abholen ?
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3188
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 21. Okt 2017, 20:11 Re: ATmega328p und UART

Mathias hat geschrieben:Könnte ich, wen dieses Register gesetzt ist, ein Interuptroutine schreiben, welche die Daten in eine Puffer schreibt, und dann diese später bei Bedarf abholen ?


Ja, das ist der Sinn dabei. Unter C sieht das etwa so aus, Achtung ist für ATmega32:

Code: Alles auswählen
// für ATmega32!!!
#define Crxlen   64         // Länge Rx Buffer 64 Byte
char         Rxbuf[Crxlen];   // Rx Buffer
uint8_t      rxread, rxwrite  // Position Read/Write in Buffer
 
#define Cbaud    57600L      // Baudrate
#define Cubrrval ((F_CPU + Cbaud * 8) / (Cbaud * 16) - 1)
 
/**** Init RS232 ****/
 
void      init_serial(void) {
   UBRRH = Cubrrval >> 8;
   UBRRL = Cubrrval & 0xFF;
 
   UCSRC = (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);   // Asynchron 8N1
   UCSRB = (1<<RXCIE) | (1<<RXEN) | (1<<TXEN);      // UART RX und TX, RX Interrupt einschalten
}
 
/**** Rx Interrupt ****/
 
ISR(USART_RXC_vect) {
   char tchr;
   tchr = UDR;      // Daten lesen
   if (tchr != '\0') {
      Rxbuf[rxwrite] = tchr;      // Daten in Rx Buffer
      rxwrite++;
      if (rxwrite >= Crxlen) {
        rxwrite = 0;
      }
   }
}
 
/**** RS232 Empfang prüfen ****/
 
void   serial_sample(void) {
   char tchr;
   cli();      // Interrupts aus wegen rxwrite
   while (rxwrite != rxread) {
      tchr = Rxbuf[rxread];      // Daten aus Buffer
      rxread++;
      if (rxread >= Crxlen) {
         rxread = 0;
      }
      // mach was mit tchr, aber nicht zu lange wegen Interrupt
   }
   sei();   // Interrupts ein
}


Der Interrupt schreibt ankommende Daten in einen Ringbuffer. In der Mainloop muss serial_sample regelmäßig aufgerufen werden. Dabei wird geprüft, ob Schreibzeiger ungleich Lesezeiger, wenn das der Fall, sind unbearbeitete Daten im Buffer. Je nachdem was das für Daten sind kann man damit dann was anstellen. Das darf aber nicht zu lange dauern, denn solange Interrupts aus sind, werden auch keine neuen Daten in den Ringbuffer geschrieben. Eventuell muss man die cli / sei etwas anders schachteln, das ist aber unter C nicht so einfach wie in Assembler, weil man nicht weiss, was der Compiler zwischendurch mit rxwrite macht. Eventuell sollte man das in eine temporäre Variable schreiben.
Timm Thaler
 
Beiträge: 430
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 21. Okt 2017, 20:30 Re: ATmega328p und UART

Danke für den Code.

Aber bevor ich diesen Code in Pascal umsetzen kann, muss ich zuerst mal wissen wie man die ISR(USART_RXC_vect) in Pascal umsetzt.
Dazu habe ich schon ein Thema für den Timer Interrupt eröffnet.

Ich denke mal, mit einer kleinen Änderung, kann man dann auch abfragen ob oder wie viele Zeichen sich im Puffer befinden.
Ich sehe der Weg zu der Arduino Serial ist nicht mehr weit.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3188
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 21. Okt 2017, 22:29 Re: ATmega328p und UART

Mathias hat geschrieben:Aber bevor ich diesen Code in Pascal umsetzen kann, muss ich zuerst mal wissen wie man die ISR(USART_RXC_vect) in Pascal umsetzt.


Sorry, ich hab da auch nix Fertiges, weil RS232 bei mir gerade nicht gebraucht wird. In ein paar Wochen will ich mir nochmal meine Heizungssteuerung vornehmen, da schreib ich die Uart-Routinen auf Pascal um.

Es ist bestimmt eine gute Idee, im Winter an der Heizung rumzuprogrammieren. Was kann da schon schiefgehen?

Mathias hat geschrieben:Ich sehe der Weg zu der Arduino Serial ist nicht mehr weit.


Sag doch nicht immer Arduino. Das klingt so nach Basteln. ;-)

Mit Pascal kannst Du viel mehr als die Arduino-Sketches Dir bieten.
Timm Thaler
 
Beiträge: 430
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 21. Okt 2017, 22:46 Re: ATmega328p und UART

Es ist bestimmt eine gute Idee, im Winter an der Heizung rumzuprogrammieren. Was kann da schon schiefgehen?

Nicht viel, wen es einen Schalter "Handbetrieb" hat. :mrgreen:

Sag doch nicht immer Arduino. Das klingt so nach Basteln.

So ein Bastelding ist dies auch wieder nicht. Bei uns in der Firma werkelt so ein Nano mit einem ADS1115 ca. 2 Jahren. Ein Top-Messkarte für nicht mal 10€. :wink:
Zuerst wollten sie eine fertige Messkarte für mehrere 100€ einsetzen, welch unbrauchbar war. (Zu starkes Rauschen.)

Mit Pascal kannst Du viel mehr als die Arduino-Sketches Dir bieten.

Was sollte Pascal da mehr bieten, ausser das die Sprache viel komfortabler ist ?
Sloeber bietet da viel mehr, ausser das es mit C++ programmiert wird.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3188
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Timm Thaler » 22. Okt 2017, 00:10 Re: ATmega328p und UART

Mathias hat geschrieben:Was sollte Pascal da mehr bieten, ausser das die Sprache viel komfortabler ist ?


Zum Beispiel sind die meisten Sketches einfache Statemachines: Du willst einen AD-Wert einlesen? Der Arduino stößt die Messung an und rödelt dann solange in der Schleife, bis die Messung fertig ist. Du willst Daten vom Uart einlesen? Der Arduino wartet solange, bis Daten da sind, und wehe die kommen nicht.

Oder einen ganzen Port parallel als Byte einlesen? Als ich das letzte Mal geschaut habe, konnte der Arduino nur einzelne Pins einlesen oder setzen.

Interrupts, Timeslots? Ja, bekommt man vielleicht auch irgendwie hin. Aber da kommt dann meistens: Nimm gleich C. Und C ist häßlich.
Timm Thaler
 
Beiträge: 430
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Timm Thaler » 22. Okt 2017, 16:34 Re: ATmega328p und UART

Mathias hat geschrieben:Wen ich des lösche, dann funktioniert das Ganze nicht mehr.

Code: Alles auswählen
    UCSR0C := UCSR0C or (1 shl UMSEL0) or (1 shl UCSZ01) or (1 shl UCSZ0);

Da stimmt was nicht. UMSEL0 gehört hier definitiv nicht gesetzt.

Mach mal die Zuweisung ohne das Register vorher einzulesen:
Code: Alles auswählen
    UCSR0C := (1 shl UCSZ01) or (1 shl UCSZ0);

Eigentlich ist das Einlesen nur nötig, wenn im Register vorher Werte stehen können, die nicht verändert werden sollen.

Aus dem Tutorial:
Code: Alles auswählen
  procedure UARTInit;
  var
    Teiler: integer;
  begin
    teiler := CPU_Clock div (2 * Baud) - 1;

Keine gute Idee! Der Compiler baut hier eine Software-Division ein, die reichlich Speicher und auch etwas Zeit benötigt. Und weil CPU-Clock sehr groß ist, wird das auch noch eine 32bit-Division.

Besser die Baudrate direkt als Konstante berechnen zu lassen:
Code: Alles auswählen
const
  CPU_Clock = 16000000; // Taktfrequenz Arduino, default 16MHz.
  Baud      = 9600;     // Baudrate
  UCSZ01    = 2;        // Gibt es nicht in der Unit Atmega328p.
  teiler = CPU_Clock div (2 * Baud) - 1;

Dann berechnet der Compiler den Wert während des Compilierens und setzt ihn direkt ein.
Timm Thaler
 
Beiträge: 430
Registriert: 20. Mär 2016, 22:14
OS, Lazarus, FPC: Win7-64bit Laz1.6 FPC3.0.0, Raspbian Jessie Laz1.6 FPC3.0.0 | 
CPU-Target: Raspberry Pi 3
Nach oben

Beitragvon Mathias » 22. Okt 2017, 17:07 Re: ATmega328p und UART

Keine gute Idee! Der Compiler baut hier eine Software-Division ein, die reichlich Speicher und auch etwas Zeit benötigt. Und weil CPU-Clock sehr groß ist, wird das auch noch eine 32bit-Division.
Die Idee dahinter war mal, das man UARTInit(Baud); aufrufen könnte. Es kann ja mal sein, das man den Baud aus eine DIP-Schalter ausliest.
Ich habe es geändert, so muss er zur Laufzeit gar nichts mehr rechnen:
Code: Alles auswählen
const
  CPU_Clock = 16000000; // Taktfrequenz Arduino, default 16MHz.
  Baud = 9600;          // Baudrate
  UCSZ01 = 2;           // Gibt es nicht in der Unit Atmega328p.
  teiler = CPU_Clock div (2 * Baud) - 1;
  teilerH = teiler shr 8;
  teilerL = teiler mod $100;
 
  procedure UARTInit;
  begin
    UBRR0H := teilerH;
    UBRR0L := teilerL;
Das mit dem teilerH und L spart nochmals 8Byte. 8)

Dies funktioniert nicht:
Code: Alles auswählen
//    UCSR0C := UCSR0C or (1 shl UMSEL0) or (1 shl UCSZ01) or (1 shl UCSZ0);
    UCSR0C := (1 shl UCSZ01) or (1 shl UCSZ0);


Du willst Daten vom Uart einlesen? Der Arduino wartet solange, bis Daten da sind, und wehe die kommen nicht.

Für sowas gäbe es:
Code: Alles auswählen
Serial.available()
Aber ich stimme dir zu, wen man es selbst macht, dann weis man was passiert.

So wie es scheint bist du ein richtiges AVR-Genie. :shock: :wink:

Irgendwie setzt mich der AVR in das 8088er-Zeitalter zurück, da hatte man auch jedes Byte optimiert. :wink:
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 3188
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

» Weitere Beiträge siehe nächste Seite »
Nächste

Zurück zu Sonstiges



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast

porpoises-institution
accuracy-worried