mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik PIN-Register mittels USART in festem Zeitintervall ausgeben


Autor: Lukas Bommes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Zusammen,

ich bastele mir gerade einen einfachen Logik-Analyser auf Basis eines 
AtMega2560.
Ziel ist es, das PINC-Register in einem konstanten Intervall von 1 
Mikrosekunde mittels des USARTs an den PC zu schicken, wo die Daten 
geloggt werden. Nun stellt sich die Frage, wie ich sinnvollerweise 
hierbei vorgehen könnte.
Meine Idee zur Umsetzung ist im untenstehenden Code zu erkennen. Mittels 
Timer 1, der im CTC-Modus bei 1 MHz betrieben wird, soll der 
TIMER1_COMPA-Interrupt ausgelöst werden, innerhalb dessen ISR das 
PINC-Register über den USART an den PC gesendet wird.

Verwende ich die auskommentierte Variante, d.h. werden die Daten so 
schnell wie möglich versendet (immer wenn das Sende-Register leer ist), 
funktioniert alles problemlos. Allerdings habe ich Probleme mit dem 
unten stehenden Code, d.h. der Kombination aus Timer und USART. Es 
kommen hierbei einfach keine Daten am PC (Putty) an.
Sieht zufällig jemand meinen Fehler? Oder habt ihr grundlegend andere 
Vorschläge, wie man Daten in einem festen Zeitintervall von 1 us über 
den USART zu verschicken könnte?

Vielen Dank schonmal!

Beste Grüße
Lukas
const float sample_rate = 1000000; // [Samples per sec.]

void setup() {
  cli();
  TIMSK0 &= ~(1<<TOIE0); // disable timer0 interrupt (Arduino specific)
  sei();
  
  // Todo: setup timer to send data in specific intervals
  // check, if bit UDRE0 in UCSR0A is set (data has been sent)
  // desired sample time 1 MSpS
  
  // Todo2: start measurement on external interrupt and let it
  // run for desired delta time, e.g. 1 second
  
  cli();
  // configure input pins
  DDRC = 0x00; // set port C as input
  PORTC = 0xff; // enable internal pullups
  
  // setup timer for sampling
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0; // initialise counter with 0
  OCR1A = (16000000.0/(sample_rate*2))-1.0; // (needs to be < 65536) // set compare match register
  TCCR1B |= (1 << WGM12); // ctc mode
  TCCR1B |= (1 << CS10); // set no prescaling
  TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
  
  // setup usart
  int ubrr = 1; // gives a baud rate of 1 Mbit/s, s. datasheet page 226
  UBRR0H = (unsigned char)(ubrr>>8); // baud rate
  UBRR0L = (unsigned char)ubrr;
  UCSR0A |= (1<<U2X0); // double transmission speed
  UCSR0B = (1<<TXEN0);// | (1<<UDRIE0); // Enable transmitter, enbale interrupt
  UCSR0C |= (1<<USBS0) | (1<<UCSZ00) | (1<<UCSZ01); // Frame format: 8 data bits, 2 stop bits
  sei();
}

// usart interrupt
/*
ISR(USART0_UDRE_vect)
{
  UDR0 = PINC;
}*/

// timer interrupt
ISR(TIMER1_COMPA_vec)
{
  //if(UCSR0A & (1<<UDRE0)) UDR0 = PINC; // send only, when data register is empty
  UDR0 = PINC;
}

void loop() {
}

Autor: Thomas Elger (picalic)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei der Datenrate von 1 MBit und zwei Stopbits dauert die Übertragung 
eines Bytes 11µs, da wirst Du wohl kaum jede µs ein neues Datenbyte 
verschicken können!

: Bearbeitet durch User
Autor: Wolfgang (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Lukas Bommes schrieb:
> ich bastele mir gerade einen einfachen Logik-Analyser auf Basis eines
> AtMega2560.

Du weißt, dass es von Cypress den CY7C68013a gibt und der einen 
wunderbaren, einfachen 8-Bit Logik-Analyser mit 24MHz Abtastrate abgibt?
Bei ebay gibt es den Chip fertig im Gehäuse für unter 7€ (z.B. 
331803014389).
Außer aus sportlichem Ehrgeiz gibt es da eigentlich keinen Grund, einen 
ATmega zu quälen, um mal ein paar Bits live auf die Finger zu schauen.

Autor: Lukas Bommes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo ihr beiden,

danken für eure Antworten!

@Thomas: Ich hatte nicht bedacht, dass pro Sendevorgang 11 bit 
verschickt werden müssen. Somit hast du natürlich vollkommen Recht. 
Allerdings erreicht der Mega 2560 damit bei 16 MHz Systemtakt nur knapp 
90 KHz Sampling-Rate, was ja nicht so viel ist.

@Wolfgang: Danke für den Tipp! Aber "sportlicher Ehrgeiz" ist das 
Stichwort. ;-) So ein Logik Analyzer ist ja ein ganz nettes Projekt, um 
mal ein bisschen zeitkritischeren Code zu schreiben.

Aber ich habe noch eine prinzipielle Frage, bei der ihr mir ja 
vielleicht weiterhelfen könnt. Und zwar kommt mir meine Lösung über den 
Timer etwas unelegant vor. Kann man stattdessen auf Basis der Kenntnis 
der Baud Rate von 1 Mbit pro Sekunde und der Größe eines Frames von 11 
bit eine exakte Aussage über die Zeit machen, in der in meinem Code oben 
das PINC-Register via UART versendet wird? (Bei Verwendung des 
USART0_UDRE-Interrupts.)
Sprich, darf ich davon ausgehen, dass alle gesendeten Messpunkte 
tatsächlich in einem Abstand von exakt 11 us liegen, oder ist mit 
Abweichungen zu rechnen?

Viele Grüße
Lukas

P.S. In meinem Code oben muss es übrigens TIMER1_COMPA_vect statt 
TIMER1_COMPA_vec heißen. Daher wurde die ISR auch nicht aufgerufen.

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, der Sendepuffer muss ja auch noch gelehrt werden.

Mach dir doch ein einfaches Programm, schick deinen Port direkt über UDR 
raus. Prüfe aber vorher ob der Sendepuffer auch leer ist (UDRE Bit im 
UCSRA Register). Und mess das ganze mal mit deinem Oszi nach.

Autor: c-hater (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lukas Bommes schrieb:

> Aber ich habe noch eine prinzipielle Frage, bei der ihr mir ja
> vielleicht weiterhelfen könnt. Und zwar kommt mir meine Lösung über den
> Timer etwas unelegant vor. Kann man stattdessen auf Basis der Kenntnis
> der Baud Rate von 1 Mbit pro Sekunde und der Größe eines Frames von 11
> bit eine exakte Aussage über die Zeit machen, in der in meinem Code oben
> das PINC-Register via UART versendet wird? (Bei Verwendung des
> USART0_UDRE-Interrupts.)

Natürlich. Da die USART double-buffered ist, kann man einen 
kontinuierlichen Datenstrom mit Vmax darüber verschicken. Jedes Byte 
wird dann exakt in dem Abstand versandt, der durch Bitrate und Bitzahl 
der Frames vorgegeben ist. Das gilt natürlich nur, so lange nix anderes 
(insbesondere konkurrierende längliche ISRs) den Ablauf stört und der µC 
deshalb nicht dazu kommt, schnell genug Daten nachzuliefern...

Übrigens: Wenn die einzige Aufgabe des Gerätes die Sache sein soll, die 
Eingabe eines 8Bit-Port per USART zu versenden, ist ein Mega2560 
natürlich massiv überdimensioniert, dafür reicht dann auch ein Tiny2313 
völlig aus.

Und man braucht dann auch keinen Interrupt, dann ist es wesentlich 
effizienter, die Sache in einer kleinen Endlosschleife in main() 
abzuwickeln. Es entfällt dann nämlich der Interrupt-Overhead, der gerade 
bei einem Mega2560 sogar deutlich grosser als bei den meisten anderen 
AVR8 ist (wegen des 22Bit-PC).

> tatsächlich in einem Abstand von exakt 11 us liegen

Warum eigentlich 11µs? Bei 8N1 wären es 10. Die runde Zahl kommt 
irgendwie viel cooler.

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also mich würde es extrem stören wenn ich bei einem Logikanalyzer keinen 
Trigger hätte ;-) Ansonsten ist das ganze nämlich bloß nen 8 Kanal / 
1Bit Oszilloskop - eben auch ohne Trigger.

Autor: c-hater (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Draco schrieb:

> Also mich würde es extrem stören wenn ich bei einem Logikanalyzer keinen
> Trigger hätte

Mich auch. Aber was hat das jetzt mit dem Thema des Threads zu schaffen?

Autor: Wolfgang (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Draco schrieb:
> Also mich würde es extrem stören wenn ich bei einem Logikanalyzer keinen
> Trigger hätte ;-)

Der Trigger kann doch auf dem empfangenden PC Laufen. Der µC streamt nur 
fortlaufend die Daten.

Autor: Thomas Elger (picalic)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wolfgang schrieb:
> Der Trigger kann doch auf dem empfangenden PC Laufen. Der µC streamt nur
> fortlaufend die Daten.

Das hat außerdem den Vorteil, daß man auch sehen kann, was kurz vor dem 
Triggerzeitpunkt passiert ist!

Autor: Zitronen Falter (jetztnicht)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man sollte mit einem Tracebuffer auf dem Mega arbeiten. Dort waehrend 
dem Trigger erwarten in einen ringbuffer aufzeichen, und erst 
uebertragen wenn der Trigger gekommen ist und der Tracebuffer die 
gewuenschten Daten enthaelt.

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.