www.mikrocontroller.net

Forum: Compiler & IDEs Abbruch beim Senden mit USART, Atmega16


Autor: Witali G. (witali)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen!!!

ich versuche mit dem dem unteren Code ein String bei Input Capture 
Interrupt über USART auszugeben, zunächst mal mit dem Simulator. Was mir 
völlig unverständlich ist, nach dem schreiben des zweiten Buchstaben des 
Strings (also "a") wird UDRE zurückgesetzt und das Senden geht nicht 
weiter. Was mir noch unklar ist, UDRE wird nicht zurückgesetzt wenn die 
ersten beiden Buchstaben in UDR reingeschrieben werden. Soll UDRE nicht 
nur dann auf high sein wenn UDR wirklich leer ist.

Ich wäre euch für jeden Hinweis dankbar!
#include <avr/io.h>
#include <avr/interrupt.h>

#ifndef F_CPU

#warning "F_CPU war noch nicht definiert, wird nun nachgeholt mit 4000000"
#define F_CPU 4000000L    // Systemtakt in Hz, das L am Ende ist wichtig, NICHT UL verwenden! 
#endif
 
#define BAUD 9600L          // Baudrate, das L am Ende ist wichtig, NICHT UL verwenden!
 
// Berechnungen
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     // Reale Baudrate
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000) // Fehler in Promille 
 
#if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))
  #error Systematischer Fehler der Baudrate gr?sser 1% und damit zu hoch! 
#endif
 
int main(void)
{
    UCSRB |= (1<<TXEN);                // UART TX einschalten
    UCSRC |= (1<<URSEL)|(3<<UCSZ0);    // Asynchron 8N1 
 
    UBRRH = UBRR_VAL >> 8;
    UBRRL = UBRR_VAL & 0xFF;

    
  TIMSK = 1 << TICIE1;
  TCCR1B = ((1 << ICNC1) | (1 << CS10));
  DDRB = 0x00;
  PORTB = 0xff;
  sei();
//  while (1)  { }
  while(1) {
    asm volatile ("nop");
  }

  return 0;
}

int uart_putc(unsigned char c)
{
    while (!(UCSRA & (1<<UDRE)))  /* warten bis Senden moeglich */
    {
    }                             
 
    UDR = c;                      /* sende Zeichen */
    return 0;
}

void uart_puts (char *s)
{
    while (*s)
    {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
        uart_putc(*s);
        s++;
    }
}

ISR(TIMER1_CAPT_vect)
{
  DDRD = 0xff;
  PORTD = 0x60;
  char a[] = "Hallo!";
  uart_puts(a);
}

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du bist zu ungeduldig.

Du musst simulierte 1027 µs (4 MHz, 9600 Baud) warten, bis die beiden 
(Atmega8: UART puffert 2 Byte) ersten Zeichen "raus" sind und das dritte 
Zeichen per UART gesendet werden kann.

Vielleicht gibt dir das eine Idee, dass UART Senden im Timer-Interrupt 
keine gute Idee ist, wenn man einen genauen Timer braucht ;-)

Autor: Witali G. (witali)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für die Antwort!

> Du musst simulierte 1027 µs (4 MHz, 9600 Baud) warten


Aha! Und wie berechnet man diese Zeit aus dem Takt und der Baudrate?


> Vielleicht gibt dir das eine Idee, dass UART Senden im Timer-Interrupt
> keine gute Idee ist, wenn man einen genauen Timer braucht ;-)

Danke! Das war nur ein Lernprogramm. Ich habe es aus einem anderen 
zusammengebastelt, mit dem ich früher was mit dem Timer ausprobiert 
habe.

Autor: Witali G. (witali)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und noch etwas würde ich gerne wissen, wo erfahre ich denn solche 
Details wie, dass UART beim Atmega8  2 Byte puffert? Steht das im 
Datenblatt irgendwo?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Witali Gustschin wrote:
> Vielen Dank für die Antwort!
>
>> Du musst simulierte 1027 µs (4 MHz, 9600 Baud) warten
>
>
> Aha! Und wie berechnet man diese Zeit aus dem Takt und der Baudrate?

Mist! Erwischt ;-)

Ich habe es nicht berechnet, sondern mit der Stopwatch im AVR Studio 
beim Simulieren mitgestoppt. Breakpoint auf das return in uart_putc und 
Autostep ALT+F5 laufen lassen. Dann Input Capture auslösen auf PB0... 
Wenn es beim zweiten auszugebenden Zeichen dort stoppt, die Stoppuhr auf 
0 resetten und weiter mit Autostep oder Run laufen lassen, bis das 
dritte Zeichen ankommt. Dann sind 1027undpaarzerquetschte µs vergangen.

Berechnen... 2 Bytes sind 2x (1 Startbit, 8 Datenbits, 0 Paritybit und 1 
Stopbit) = 20 Bits. Bei 9600 Bits/s dauert die Ausgabe also 20/9600 s = 
2,08 ms.

2.08 ms bis der 2 Byte UART Puffer komplett leer ist, du brauchst aber 
nur ein Byte freien Puffer für das nächste Zeichen, also 1/2*2,08 ms = 
1,04 ms = 1042 µs. Dass der simulierte Wert etwas geringer ist, liegt 
vielleicht an der Lage des Breakpoints.

Die Taktrate spielt keine wesentliche Rolle. Ich habe sie automatisch 
mit angegeben, um meine Simulationsparameter (Atmega8, 4 MHz...) 
festzuhalten, falls wir länger an dem Fall arbeiten sollten oder wenn du 
das nachvollziehen willst, was ich gemacht habe.

>> Vielleicht gibt dir das eine Idee, dass UART Senden im Timer-Interrupt
>> keine gute Idee ist, wenn man einen genauen Timer braucht ;-)
>
> Danke! Das war nur ein Lernprogramm. Ich habe es aus einem anderen
> zusammengebastelt, mit dem ich früher was mit dem Timer ausprobiert
> habe.

Sollte auch keine Kritik in dem Sinn sein, sondern ein 
Denkanstoss/Reminder, die ISR grundsätzlich so klein wie möglich zu 
halten.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Witali Gustschin wrote:
> Und noch etwas würde ich gerne wissen, wo erfahre ich denn solche
> Details wie, dass UART beim Atmega8  2 Byte puffert? Steht das im
> Datenblatt irgendwo?

Im Datenblatt ist das Diagramm "Figure 61: USART Block Diagramm". In dem 
Transmitter-Teil ist das UDR (Transmit) Register und das Transmit Shift 
Register. Schreibst du ein Zeichen nach UDR (Transmit), wird es komplett 
nach Transmit Shift Register geschrieben und von dort aus Bit für Bit 
rausgeschickt. UDR ist dann wieder frei für das nächste Zeichen. Solange 
Transmit Shift Register noch nicht leer ist, stauen sich bei deinem 
nächsten UDR beschreiben zwei Zeichen. Also hast du einen 2 Byte 
"FIFO-Puffer". Puffer ist in Anführungszeichen zu sehen oder als 
Pseudopuffer, weil du nicht direkt auf das Transmit Shift Register 
zugreifen kannst. Die echte Pufferung beim Receive ist auf der folgenden 
Seite im Datenblatt erklärt.

Autor: Witali G. (witali)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Besten Dank für die ausführlichen Erklärungen!!!

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.