Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer0 Overflow Interrupt löst nicht aus (ATmega16)
Weis gerade nicht mehr weiter.
Versuche die AppNote AVR304: Half Duplex Interrupt Driven Software UART
auf einem ATmega16 zu implementieren (Ich weis das ATmega16
Hardware-UART hat, muß aber später auf einen Tiny umsteigen)
Nun zu meinem Problem:
Ich kann weder Zeichen senden, noch empfangen. Zumindest erscheint am
Terminal nichts (habe Hyperterminal und Tera Term ausprobiert).
Einstellungen sind/waren jeweils 38400 Baud, 8 Datenbits, 1 Stopbit,
kein Paritätsbit, keine Flusssteuerung.
Für die Übertragung nutze ich die RXD/TXD Pins (richtig gesteckt ;-))
und den RS232 Spare Port auf dem STK500. Dann gehts weiter an den COM2 Port meines PC's.
Als Clock benutze ich jetzt die STK500 @3.686 MHz.
Fuse (Ext. Clock; Start-up time: 6 CK + 0 ms; [CKSEL=0000 SUT=00]) und
Jumper (XTAL1 Jumper mounted, OSCSEL auf default) auf dem STK500
sollten laut "Help" (AVR Tools User Guide) richtig gesetzt sein.
Nutze den mitgelieferten C-Code von Atmel und compile mit IAR Embedded Workbench Kickstart.
Die Software habe ich etwas anpassen müssen (Registerbezeichnungen,
etc.). Habe zusätzlich ein paar Zeilen, die LED auf dem STK500 blinken lässt (zum testen) geschrieben, welche in der Overflow Interrupt-Routine ausgeführt werden sollten.
Leider wird diese aus mir unerklärlichen Gründen nie ausgeführt.. bin mir aber eigentlich schon sicher, das ich den Timer0 richtig initialisiert habe.
Please Help, weis nicht mehr weiter O:)
Thx !
Hab den Quellcode mit angehängt !
In main() sollte testweise nur ein "Hallo" ans Terminal gesendet werden..
Ich schreibe normalerweise unter AVR-Gcc da werden anstelle von _interrupt die Makros SIGNAL verwendet. Evtl gibts die da auch?!
Ist __enable_interrupt eine Funktion der Lib? Hast du einen Max dazwischen? Sind Rx und Tx gedreht? Was kommt dabei raus wenn du ein Scope oder Fox anschliesst?Für meinen Geschmack ist die Interruptroutine tim0_ovf ein bisschen lang. Evtl kannst du das mit in die Hauptroutine nehmen...aber das nurso nebenbei ;-)
Gruss
Michael
Hi !
Das mit __interrupt und __enable_interrupt ist mit IAR schon ok so.
Ein Max ist auf dem STK500 Board mit drauf und RX bzw TX sind richtig rum. Oszi oder ähnliches hab ich leider nicht zur Verfügung.
Hab das Programm nochmals "Schritt für Schritt" aufgebaut und geschaut, wo es hängt. Sobald ich etwas ins TCNT0 Register lade (in der uart_transmit() die Zeile mit TCNT0 = (256-N+(14/C)); // Set timer delay to first bit) wird nicht mehr in die ISR gesprungen.
Kann sein, das die Interrupts einfach wieder disabled werden ???
Wenn ich die Zeile testweise auskommentiere wird die ISR durchlaufen allerdings auch nur einmal.
Kann mir jemand erklären warum dem so ist ?
Die Software sollte doch eigentlich einwandfrei laufen. Denke die Leute bei Atmel werden sich bei der AppNote schon was gedacht haben und nicht einfach fehlerbehaftete Software publizieren. Vom eigentlichen Ablauf und Aufbau des Codes sind für mich auch keine groben Fehler ersichtlich...
Fällt noch jemanden was diesbezüglich auf ??
Bin für jede Hilfe dankbar !
Gruß
schamp
Arexx-Henk
19.05.2005, 11:42
Hallo,
ich hab mal so ein bischen schnell die code durchgeguckt
GIFR = (1<<INTF0); // clear Interrupt Flag
GICR = (1<<INT0);
hier werden zB die ganze bytes geschrieben und nicht nur die einzelne bits!
sollte mann nicht '|=' nutzen statt '='?
GIFR |= (1<<INTF0); // clear Interrupt Flag
GICR |= (1<<INT0);
damit die andere 7 bits von GIFR und GICR ungeandert bleiben...
gruss
Henk
Hi !
Hab das jetzt mit GICR und GIFR ausprobiert, aber hat sich leider nichts geändert. Ich befürchte irgndwas stimmt nicht mit Timer0 und TCNT0...
Keine Idee wie man das lösen könnte...
Deine Konstanten solltest du vom Precompiler vorher ausrechnen lassen, so ist ja das Tierquälerei
EDIT Schau mal in der .Lss-File, was du dem armen Kerl damit antust
Datentypen: Der C neigt dazu, das Zielfeld als type für alles zu nehmen.
Also
TCNT0 = (256-N+(14/C));
Type ist char , also ist 256 schon mal nurmehr NULL
Arexx-Henk
19.05.2005, 14:26
Hallo,
da bin ich wieder...
dass mit
TCNT0 = (256-N+(14/C));
glaube ich nicht so direct dass es falsch ist, aber konnte so sein
innerhalb die timer0 overflow interrupt wird die overflow-interrupt-enable
wieder ausgeschaltet
TIMSK = 0;
weshalb? jetzt wird durch die timer0 kein neuer overflow-interrupt generiert.
Dass clearen der interrupt flag innerhalb die interrupt function
GIFR = (1<<INTF0)
braucht mann hier nicht den durch das nutzen/anwenden vom interrupt function wird diesen Flag hardwaremassig ge-cleared.
The flag is cleared when the interrupt routine is executed.
Seite 68 vom .pdf
gruss mal wieder
Henk
Laut Datsheet (wie du es sagst), macht er das selber (Wenn ISR-Routine)
Also nur den Counter refreshen.
Was er genau wie rechnet etc., kann man im Listing kontrollieren.
Laß es aber so oder so den Precompiler machen.
Jo das mit precompiler werd ich mir noch anschauen.
TIMSK = 0 in der ISR habe ich jetzt mal gelassen. Hab die TIMSK Initialisierung aus der uart_init() rausgeschmissen und dafür in die uart_transmit(). Somit dürfte es mit TIMSK = 0 in der ISR keine Probs geben.
Hab jetzt auch testweise Fuse auf int. RC Osz und 1 Mhz (anstatt die 3.686 MHz vom STK500) geändert und siehe da, die LEDs blinken....
Hyperterminal zeigt aber weiterhin nichts an, außer das der Cursor plötzlich nicht mehr gleichmäßig blinkt 8-[
Werden vielleicht die RX / TX Leitungen zu vertauschen sein (ausgekreuzt)
Denn wenn irgendwas reinkommt, schreibt er zumindest irgendeinen Müll auf den Schirm
Ich hab aber deine hand-made-uart nicht nachgecheckt, das geb' ich zu.
Geh mal mit der Baudrate runter, solange du die grauslichen Rechnungen noch in der ISR hast, sonst geht sich die ganze Geschichte nicht in der Zeit aus.
Irgendwas stinkt da ganz gewaltig :-s
Denn wenn ich nun mit der Baudrate auf 9600 @1MHz runter geh, funktioniert die ISR wieder nicht mehr... :cry:
Au weia, d.h. die diversen Routinen sind nicht richtig synchronisiert und kommen sich, je nach timing, gegenseitig in die Quere oder manchmal nicht.
Ich muß mir mal deinen Code genauer anschauen, hilft nix.
ogottogott. wieso straft die leute keiner ?
was soll das nu heissen... :?: :?:
Das heißt, daß in der Appnote äußerst seltsame Dinge stehen.
Beispiel:
Beim Transmitten setzt er
glob.u_status = (1<<BUSY)|(1<<TD);
(Und es ist ihm vollkommen wurst, ob er vielleicht gerade empfängt)
In der ISR fragt er aber ab:
if(!(glob.u_status & TD)) STATT
if(glob.u_status & (1<<TD))
wenn er senden will
*seufz* Wo find' ich die original AppNote ?
[/code]
Jo die Abfrage inner ISR fandsch auch scho etwas strange.. ist aber original so inner AppNote drinne. Habs nicht geändert!
siehe
http://www.atmel.com/dyn/resources/prod_documents/AVR304.zip
http://www.atmel.com/dyn/resources/prod_documents/DOC0941.PDF
Gut, ist verziehen, ich muß jetzt heim, vielleicht kann ich heut noch reinschauen. Sonst halt bis morgen.
(Die Beispiele in Appnotes sind manchmal nicht funktionsfähig)
pebisoft
19.05.2005, 17:33
es gibt eine einfache lösung.
lade dir die bascom-demo runter.
programmierst ein software-uart (geht in bascom) und wertest ihn mit avr-studio 4.0 aus. geht wunderbar. dann setzt du ihn in winavr-c . evtl kannst du die abgeänderte asm-datei direkt in winavr-c einbinden. geht auch klasse.
mfg pebisoft
Weis net mit bascom.. findst nich bissl umständlich ?? Würd ganz gern bei C bleiben, zumal ich mit Basic so gut wie nie gearbeitet hab.
Mich wundert auchn bissl, das hier sonst noch keiner die AVR304 AppNote versucht hat umzusetzen und auf die selben Probleme gestoßen ist... :-s
Naja irgndwie muß es doch eine Lösung dafür geben..
Guten Morgen !
Das spezielle an der Appnote ist die Interrupt-Lösung. BasCom arbeitet mit Zeitschleifen.
Ich hab mir die Asm-Version genau durchgelesen (meist besser ausgeführt als C), jetzt ahne ich, wessen Geistes Kind die Sache ist (etwas anders, als gedacht).
Ein grundsätzlichses Problem: Wenn du grad am senden / empfangen bist, killt die eine Funktion die andere, d.h der Host (Terminal) muß mitspielen mit der 1/2 Duplex Geschichte.
Also so locker im Hintergrund rennt das nicht.
Frage: Um was gehts denn in etwa auf dem eigentlichen Zielsystem (Tiny)?
Moin Moin !
Vorerst müßt ich eigntlich nur Daten Senden können, es ist aber durchaus für später vorgesehen auch mal was empfangen zu können (Mein erstes Ziel ist vorerst, die Daten, die ich später vom A/D Wandler bekomme ans Terminal zu schicken)
Hab grad eben auch nochmal angefangen die AppNote genauestens durchzulesen und es ist wirklich so vorgesehen, dass der externe Interrupt disabled ist, wenn gerade transmittet wird... (also kein Empfangen während Senden)
Meinst du Hyperterminal arbeitet Fullduplex und deswegen geht nix ??
Kann ich des irgndwie auf Halfduplex-Betrieb schalten ?
Aber wieso springt er bei manchen Einstellungen (Baud und Osc) in die ISR und wieso dann wieder nicht ?
EDIT:
Hab auch erst überlegt, ob ein polled Software UART sinnvoller wäre (gibt da auch eine AppNote) , aber ich kann ja net ständig abfragen ob ich was empfange..
Beim Senden isses egal, da ich die Werte in festen Intervallen senden werde.
Hi, ganz locker, keine Hypotenusen, solange wir nix wissen.
Ich schlag vor, wir ziehen auch mal das Senden durch (is einfacher) und sehen dann weiter.
Diese Art halfduplex müßten sich die UARTs untereinander ausmachen, da bleibt nur XON/XOFF, das geht immer und das kann auch jedes Terminal. (Oder Hardware-Handshake, ist aber unbequem, mehr Draht und mehr Arbeit)
Jetzt blasen wir mal "hello" rüber, ich bin drauf
Oki. Also die RX Routinen rausschmeissen und XON/XOFF probieren..
Ich will nicht verschweigen, daß da noch eine Ecke ist. Wenn du transparente Daten (binäre Meßwerte) überträgst, ist das mit der gleichzeitigen Verwendung von ASCII-Steuerzeichen nicht ganz trivial.
Egal, .---> "Hello" or bust
Versteh ich jetzt nicht so ganz, wie du das meinst mit den Steuerzeichen...
Hab die RX Routine mal rausgeschmissen. Auch die Initialisierung des externen Interrupts.
Die Zeile:
if(!(glob.u_status&TD)) // Transmit section
in der ISR hab ich ebenfalls raus, da ja nicht mehr geprüft werden muß, ob TX oder RX.
Funktionieren tuts trotzdem net, auch kein blinken oder so..
Steuerzeichen: Wenn du als Meßwert ein short ( 0- 1023) auf die Reise schickst, kannst du dir vorstellen, daß da bald mal ein Steuerzeichen drin vorkommt, das ja gar keins sein soll. Und eine Umwandlung short--> Ascii ist mühsam.
Ich schau mir timer0 gleich an
Es ist leider auch nirgends beschrieben, wie der TCNT0 und der Reload Wert zustande kommt... müßte man evtl anpassen ?? :|
Das steht in der AppNote.
Vorschlag: Step by Step
Machen wir mal nix, als irgendeinen Timer0-Interrrupt, der nix tut, außer LED blinken. Nix senden, garnix. Nur aufsetzen, enablen. In der ISR nur den TCNT0 nachladen, nix herumswitchen.
Prescaler --> 8
TCNT0 = 48
das gibt bei 16 MhZ eine frequenz von 9600
Oder andere XTAL ?
Auf jeden Fall muß mal der Timer schnackeln, das ist ja lächerlich
Sorry Mittagessen !! O:)
Mir wären die 3.686 MHz vom Board fürs erste lieber (kann leider keine 16 MHz)
D.h. also für die Einstellungen:
C = 8 (Prescaler)
XTAL = 3.686 MHz
Baudrate = 9600
--> N = Xtal / (BaudRate*C) = 3.686 MHz / ( 9600*8 ) = ~ 48
--> TCNT0 = 256 - N + (14/C) = 256 - 48 + 14/8 = ~ 210
Hier das simple Prog:
Die LED's blinken (noch... :wink:)
So. Ich hab' mal einfach dazugeschrieben, was ich meine.
Konzept: Pfeif' auf alle Extras. Back to the roots.
der Timer tickt einfach in der Baudrate, (9600 /sec)
(ev. basteln mit preload)
Will man was senden, schreibt man das Zeichen hin, und setzt einen Flag
und den Status "start"
Durch den Flag wird die ISR lebendig und macht je nach Status was anderes
1 x Start Bit
8 x Datenbit
1 x Stop
1 x stopbit stehenlassen, clear flag
Ich kann es hier nicht probieren, vielleicht fehlt wo ein semikolon, ein bißchen Liebe braucht das halt.
Is klar, wie's gemeint ist ?
Jo ist klar wie's gemeint ist, habs mir gerade angeschaut! THX !!
Wo hast das so schnell hergezaubert :-)
Beim compilieren gibts noch "expected an expression" wegen dem TX_M_SEND..
brauch ich doch bloß #define TX_M_SEND 0 ??
als Bit 0 von bTxFlag quasi..
Haltaus nein, _M_ ist eine Maske (privater standard)
#define TX_M_SEND 1 // oder 2 , 4, 8 etc.
Nix zu danken, erst wenn's funzt, gibt's du einen aus
pebisoft
20.05.2005, 18:06
kannst die asm-datei von bascom dann gedanklich in winavr-c umsetzen.
bisschen denken musste schon. so setze ich auch lösungen teilweise von bascom in c um wenns nichts anderes gibt.
mfg pebisoft
@schamp: Ich schau mir das am Wochenende mit dem Oszi an, das sind ein paar Sachen seltsam.
Laß es inzwischen gut sein.
Ich rühr mich zuverlässig
hm ok !! thanks a lot !! osci hab ich leider keines daheim.
wollt morgen nochmal weiter probieren
Hi, schamp, Zwischenbericht:
Ich hab bei meiner RNBFRA (Mega32) elegant die Hw-Uart deaktiviert und versuche, den Pin TxD zu Fuß zu bedienen. (dort hängt ja der Max drauf).
Super Idee, geht aber nicht, weil ich auf dem Pin den Pegel nicht auf Low bekomme, ergo geht das Ganze mal nicht. Auf einem Anderen ist das kein Problem, aber da ist kein Max drauf. Zum Mäusemelken !
Vom Timing etc. schaut das gut aus, TImer Interrupt macht kein Problem.
Auch die Rs232 Signale schauen ja nicht schlecht aus, d.h. der Weg stimmt, aber eben--> der Pegel.
Ich hab im Datasheet nix gefunden, warum das so sein könnte, hast du eine Idee ? Irgendwas funkt mir dazwischen.
*nerv*
Egal, von so einem Kistel laß' ich mich nicht verschaukeln, das ziehen wir durch.
Moin Moin !!
Und es läuft *juhuu* 8)
Bin das ganze Programm nochmals durchgegangen. 2 Zeilen geändert und dann isses gelaufen
beim case TX_C_START, das Startbit auf LOW
PORTD &=~(1<<PD4); // Set Start Bit (LOW)
und case TX_C_STOP, Stopbit auf HIGH
PORTD |=(1<<PD4); // Set Stopp Bit (High)
(siehe auch Atmel AppNote !)
Stells gleich online, kommentier es noch ein bissl ausführlicher
btw:
Jetzt könnt ma eigentlich eine eigene AppNote schreiben und diese veröffentlichen :mrgreen:
_C_ steht bei dir für CASE oder ?
nochwas: mit Hyperterminal funktionierts nicht... nehmt lieber Tera Term...
Moin ! Ich hab gehofft (befürchtet) daß daß ein Pseudoproblem ist ,d.h. nur bei mir, weil ich den TxD Pin verwende.
In der App-Note ist ein Durcheinander, was Hi und Lo betrifft. TTL ist ja active HIGH, Rs232 Active LOW, also start und stop genau verkehrt.
Das hast du ja Gottseidank gesehen. Freu mich auf deine Doku.
Jetzt brauchen wir nurmehr das Empfangen gescheit einzubauen.
Hyperterm ist die Strafe des Herrn für schwere Sünden.
Richtig gesehn, ich hab die Konvention
_C_ Konstante Zahl (z.b. für select u. vergleiche/Parameter 0 - juchuu)
_V_ für Bit-Offset 0-32
_M_ Bit maske ( MUH_M_KUH = (1<< MUH_V_KUH)
u. alles, was mit #define definiert ist, schreib ich in Uppercase
Sind so Hilfen, damit ich auch in einem Jahr meine Programme noch lesen (nachvollziehen) kann.
Ich freu mich !
So.. kurz Zeit gehabt zu kommentieren und ein paar Baudraten-Einstellungen zu testen. :)
Ab 38400 Baud macht er nimmer mit.. (reicht aber völlig aus, wie ich finde)
Mach mich dann an die Receive-Routinen ran.
Hab jetzt mal weiter programmiert...
ext. INT0 Initialisierung und sonstige Inits sollten eigentlich stimmen.
in main() will ich jetzt einfach ein character echo ausführen.
In der Receive-Routine (zu finden in der Timer0 ISR) hab ich aber noch ein Problem. Wie kann ich die Bits, die über die RX Leitung kommn und ext. Int0 auslösen zur Weiterverarbeitung einlesen/puffern ?? Steh grad auffer Leitung.. :shock:
Schau'n wir gleich rein.
Übrigens, meinen Pegel hab ich auch gefunden, Blödheit tut gottseidank nicht weh ( DDRD = Bit <> DDRC |= Bit).
Nja so einfach gehts irgndwie doch nicht mit Empfangen... 8-[
Einlesen funzt über PINx (nicht PORTx) soweit ich das jetzt feststellen konnte.
Bloß wie feststellen, welches empfangene Bit jetzt Datenbit, Start - bzw. Stopbit ?? Müsste man wieder mit "State" wie bei Senden machen oder ??
Aber müßte man das nicht auch gleich inner INT0 Routine auswerten, anstatt inner Timer0 ISR ??? (wär doch logisch, da mir sonst bits verloren gehen.. :-s)
Is mir gestern abend noch so durchn Kopf gegangen
Gruß schamp
Hi, ich grad in deinem Programm rumgekrixelt.
Die Int0-ISR zeigt, daß der Absender gerade mit dem Start-Bit anfängt.
Um mit der nächsten Time-ISR genau in die Mitte vom ersten Datenbit zu kommen, brauchen wir also einen Preload von 1.5 Bit. ab dann gehts wieder normal, auch das Stop Bit nehmen wir mit, aber dann re-enablen wir Int0 und setzen "daten da"
schau mal
Sicherheitstest: Beim INT0 alles in Ruhe lassen, nur ein Flag setzen, und in der Mainroutine aufgrund des Flags irgendwas senden.
Dadurch wissen wir, daß int0 überhaupt funktioniert
Hi, ich grad in deinem Programm rumgekrixelt.
Die Int0-ISR zeigt, daß der Absender gerade mit dem Start-Bit anfängt.
irgdnwie ist da was wahres dran *tehe* O:)
habs ma compiliert, raufgeladen und tera term angeschmissn. Also empfangen tut er (int0 wird ausgelöst) aber Zeichen stimmt noch net. Egal welche Taste man drückt es kommen immer zwei: ÿÿ
Ev. In der INT0-ISR nur aktiv werden, wenn RX_M_RECEIVE NICHT gesetzt ist.
Ev. In der INT0-ISR nur aktiv werden, wenn RX_M_RECEIVE NICHT gesetzt ist.
Aber in der INT0-ISR musst du doch RX_M_RECEIVE setzen sonst gehts im "Receive-Teil" vonner Timer0-ISR nicht weiter... :-s
Ja, ja. Aber aber vorher fragen, ob der Flag nicht schon vorher gesetzt wurde.
Weil dann läuft ja schon die Empfangs-Sequenz, und während der nächsten 9 Timer-Interrupts wollen wir ja nix mehr sehen oder hören.
du meinst so ?
#pragma vector=INT0_vect
__interrupt void ext_int0(void)
{
if(!(bRxFlag & RX_M_RECEIVE))
{
GICR = 0; // Disable external interrupt
bTxFlag &= ~TX_M_SEND; // Deactivate Transmit-Mode
bRxCount = 0; // Clear Receive Counter
TIFR |= (1<<TOV0); // clear T/C0 overflow flag
TIMSK |= (1<<TOIE0); // enable T/C0 overflow interrupt
TCNT0 = INT0_PRELOAD; // Set timer reload-value (to 1.5 bit len). 29 = time delay that
// have already been used in this
// interrupt plus the time
// that will be used by the time
// delay between timer interrupt request
// and the actual sampling of the first
// data bit.
bRxFlag |= RX_M_RECEIVE; // Activate Receive-Mode
}
}
edit: funkt trotzdem noch nicht
Ja, so mein' ich das. Ist auf jeden Fall gut, und würde das enablen/disablen des INT0 erübrigen, aber das klappt ja ohnehin ?
*murmel*
Dzt.Stand: Int0 spricht an, Timer offenbar auch,_M _DATA wird ja irgendwann gesetzt, aber es kommt auf ein Input-Zeichen üü irgendwas an. Stimmt das so ?
d.h. es kann beides fehlerhaft sein, Empfang & Senden, das ist nix
Also:
Sende irgendwas vor dich hin, bis _DATA kommt (+ECHO), und dann sende wieder irgendwas, so wie vorher
Ergebnis:
A Senden geht überhaupt nicht mehr ---> ?
B Senden geht, aber ab dem Moment, wenn daten kommen, geht's nicht mehr
C Nur das Echo ist falsch
Bitte machen sie ihr Kreuzchen
habs jetzt so in main():
__task void main(void)
{
uart_init();
__enable_interrupt(); // enable interrupts
while(1)
{
if(!(bTxFlag & TX_M_SEND))
{
send_one_byte('T');
}
if (bRxFlag & RX_M_DATA)
{
bRxFlag &= ~RX_M_DATA; // Acknowledge
send_one_byte(bRxByte); // Echo character
}
// __sleep(); // Sleep when waiting for next event
if(!(bTxFlag & TX_M_SEND))
{
send_one_byte('T');
}
}
}
Sendet vor sich hin, prüft ob Zeichen empfangen, sendet wieder vor sich hin.
Kann leider kein Kreuzchen machen...
Denn er sendet nur vor sich hin, unbeeindruckt davon ob am PC eine Taste gedrückt wurde.
So als wäre INT0 plötzlich gesperrt, was es aber nicht ist (außer wenn man schon in der INT0 ISR drinne ist)[/code]
Ui, na so gut gesichert sind wir noch nicht:
while(1)
{
if (bRxFlag & RX_M_DATA)
{
bRxFlag &= ~RX_M_DATA; // Acknowledge
send_one_byte(bRxByte); // Echo character
}
else
{
if ( !(bTxFlag & TX_M_SEND)
&& !(bRxFlag & RX_M_RECEIVE) )
{
send_one_byte('T');
}
}
}
Vergiß nicht, while läuft Bitweise mit
Jetzt siehts so aus... (siehe Bild)
die ü's sind durch willkürliches Tastendrücken entstanden.
Echo ist irgendwie falsch. 'T' wird richtig übertragen.
Könnts an dem Preload für INT0 liegen?
Würd' ich sagen. normal hast du 210 (glaub cih)
das sind also 46 bis 256
ein halber wären 23
sollten ja 187 sein, theoretisch also richtig.
praktisch hat er aber ein paar Statements auch noch zu erfüllen, bis er die Bits prüft.
könnt man versuchen, etwas raufzusetzen.
dieses y ist eigentlich 0xFD, also alles oben *think*
Setz einmal das Rxbyte bei der INT0-Routine auf NULL, ob er das Byte überhaupt angreift
Also ehrlich gsagt komm ich mit den Abschätzungen für die Preload Werte noch nicht ganz klar... So ausführlich is das garnich inner AppNote beschrieben...
z.B. über das Zustandekommen der Formel für INT0: 256-(N+N/2)+(29/C)
256 ist halt wegen 8 Bit Timer, C ist Prescaler-Wert (wie kann man das 29/C abschätzen ?) , N müsste 1/Bit sein (N*C ist die Anzahl der Cycles)
Hab in der INT0 - ISR ma das RxByte auf null gesetzt, hat sich aber nix aufs Ergebnis ausgewirkt
Hi, ich bin ein bißchen im Streß bis Sonntag.
Int-Preloads ist so:
normalerweise laden wir 210, da zählt er dann bis 256 und schnackelt.
256-210 = 46 ticks
wenn wir 1.5 Bit brauchen, wären das also 46 + 46/2 --> 69
also 256 - 69 --> 187 (?)
tja. mfg robert
Dann entsprechen also diese 46 Ticks genau einer Bitlänge.
Und diese "Ticks" bekomm man durch XTAL/Baudrate.
Jetzt hatts auch bei mir gschnackelt :P
Warum man einmal 1 Bitlänge benötigt und dann wieder 1.5 für Empfangen war mir schon klar.
Bloß hat jetzt jemand noch ne Idee, wieso Empfangen trotzdem net geht obwohl der Wert für 1.5 Bitlänge theoretisch richtig ist ??
Noch interessehalber:
Im asm-Code von der Atmel AppNote (im C-Code wurde das einfach weggelassen...) steht noch als Kommentar zu den 1.5 Bitlänge in der INT0-ISR folgendes:
29 = time delay that
have already been used in this
interrupt plus the time
that will be used by the time
delay between timer interrupt request
and the actual sampling of the first
data bit.
Wie kommen die drauf, das es ein Time Delay von 29 ist ?
Geht das durch Abschätzen der Cycles der einzelnen Instructions die während dem Programmablauf abgearbeitet werden ?
Woher weis ich dann wieviele Cycles eine Instruction braucht ?
Gruß schamp
Hi, die Atmel-Kollegen haben so richtig die Cpu-Cycles mitgezählt, während denen das Programm sozusagen blind ist. Das ist bei höheren Baudraten natürlich schon ein Faktor. Da muß man so richtig im Disassembler-Listing des C Compiler mitzählen.
Zur VErfügung stehen uns bei einem Bit
(46 Timer-Ticks) x (Vorteiler) --> Cpu Cycles
Was haben wir momentan genau XTAL / Vorteiler / Baudrate ?
Hatte jetzt immer folgende Einstellungen laufen:
// 9600 Baud @3.686MHz (STK500)
#define N 48 // Formula: N = Xtal / (BaudRate * Prescalingfactor)
#define C 8 // Prescalingfactor, NOTE: TCCR0 must also be set correct in
// timer0_init()
#define T0_TRANSMIT_PRELOAD 210 // Formula: 256-N+(14/C)
#define T0_PRELOAD 209 // Formula: 256-N+(8/C)
#define INT0_PRELOAD 188 // Formula: (256-(N+N/2)+(29/C))
Gruß schamp
Hab jetzt ein bischen an dem INT0_PRELOAD 188 "gedreht" und verschiedene Werte ausprobiert, ohne Erfolg... (die y kommen immer noch) :-k
Hi, was mich etwas verwundert, ist, daß immer genau das Gleiche daherkommt. Bei Timingfehlern würde man zwar Mist erwarten, aber differenzierten Mist.
Wenn du zb "blank" (0x20) schickst, ist grad mal 1 Bit gesetzt, der Rest null. da sollt' er doch mehr nuller erwischen.
Ob 8/C oder 29/C, da gehts doch nur um Zahlen von 1-4
Geh, nur um das dann vergessen zu können: dreh dich mal den Int0 von falling auf rising.
bringt auch nix.... :(
(INT0 auf rising)
Momemt, moment: bringt er genau das Gleiche ? (türkisches Ypsilon ?)
jo... das ist eben des komische...
seid neuestem auch ma nen Balken, mehrere y hintereinander oder Fragezeichen (wenn man auf der Taste bleibt).
(EDIT: nja nur y's, wenn man das Senden abschält und nur auf Zeicheneingabe wartet)
siehe Bild -->
Da gibt's nur eine Erklärung: da alle Müllzeichen offenbar > 128 sind und das Msb ja am Ende kommt, sind wir zu langsam.
Er nimmt den Pegel NACH dem Stop-Bit als Daten und kriegt da immer Einser, außer bei autorepeat, da kommt dann halt schon das nächste Byte.
Also irgendwie bringt der INT0 den Timer0 nicht rechtzeitig in Schwung.
Tscha, *grübel*
Aber dann würd ma trotzdem nicht immer die selbe "Kombination" bzw. Bitfolge bekommen (türk. y is 0x9fh, 10011111b).
Oder versteh ich dich jetzt irgendwie falsch ? :-s
Na gemeint ist, daß er das ganze Byte eigentlich versäumt und erst dann zum Lesen kommt, wenn der Pegel nach dem Stop-Bit schon wieder oben ist.
Wenn er irgendwas von dem Byte wirklich lesen täte, könnt's nicht immer das gleiche sein.
Probier' mal folgendes:
Laß den Timer0 immer enabled, tu' aber beim INT0 (falling) nur das Bit RX_M_RECEIVE setzen.
Hm Timer0 ist eigentlich immer enabled ? (uart_init())
Hab jetzt nur
// bTxFlag &= ~TX_M_SEND; // Deactivate Transmit-Mode
und
// TIFR |= (1<<TOV0); // clear T/C0 overflow flag
// TIMSK |= (1<<TOIE0); // enable T/C0 overflow interrupt
auskommentiert
Es wird nur das RX_M_RECEIVE gesetzt. Die y kommen immer noch...
#pragma vector=INT0_vect
__interrupt void ext_int0(void)
{
if(!(bRxFlag & RX_M_RECEIVE))
{
GICR = 0; // Disable external interrupt
// bTxFlag &= ~TX_M_SEND; // Deactivate Transmit-Mode
TCNT0 = INT0_PRELOAD; // Set timer reload-value (to 1.5 bit len). 29 = time delay that
// have already been used in this
// interrupt plus the time
// that will be used by the time
// delay between timer interrupt request
// and the actual sampling of the first
// data bit.
// TIFR |= (1<<TOV0); // clear T/C0 overflow flag
// TIMSK |= (1<<TOIE0); // enable T/C0 overflow interrupt
bRxCount = 0; // Clear Receive Counter
bRxFlag |= RX_M_RECEIVE; // Activate Receive-Mode
}
}
Morgen !
Ich denke, wir bellen irgendwie den falschen Baum an.
Wenn in der Timer-ISR zwar mit Baudrate, aber ansonsten willenlos der Rx-Pin abgefragt wird, kann nicht immer der gleiche Schrott rauskommen.
Zeit, den Kopf schief zu halten, damit das Hirn in einer Ecke zusammenläuft und man besser denken kann.
Da das Senden, so scheint's, ja funktioniert, könnten wir und auf das reine Echo beschränken, dann läuft der Schirm nicht immer voll.
Back to the roots: kommentiere das Echo senden mal aus.
1 In der Hauptschleife ignoriere alles, und kopiere einfach IMMER den RX -Pin in den TX-Pin (ohne timing, ohne Nix). Dann sollten wir doch ein tadelloses Echo senden können. DAS MUSS GEHEN
2 mach das gleiche, aber nur, während RX_M_RECEIVE gesetzt ist, dadurch kontrollieren wir unser Frame
zu 1
Du meinst inner Hauptschleife nur so:
while(1)
{
if (bRxFlag & RX_M_DATA)
{
bRxFlag &= ~RX_M_DATA; // Acknowledge
send_one_byte(bRxByte); // Echo character
}
}
Nein, ich mein
while(forever)
if (pinx.Rx) portx.Tx = 1; else portx.Tx = 0;
ganz brutal.
Und dann
while(forever)
if (bTxFlag & RX_M_REVEICE)
if (pinx.Rx) portx.Tx = 1; else portx.Tx = 0;
( RX_M_Receive wird ja vom int0 gesetzt und im Timer nach 9 Bit gelöscht, also theoretisch genau ein Byte lang )
--M_DATA is mal wurst
Echo mag jetzt, wenn ma's echt so brutal macht :D
while(1)
{
// if (PD2.Rx) PORTD4.Tx = 1; else PORTD4.Tx = 0;
if(PIND&(1<<PD2))
{
PORTD |=(1<<PD4);
}
else
{
PORTD &= ~(1<<PD4);
}
}
Jetzt probier ich gleich mit RX_M_RECEIVE
(muss das nich if(bRxFlag & RX_M_RECEIVE) sein ??)
if(bRxFlag & RX_M_RECEIVE)
{
if(PIND&(1<<PD2))
{
PORTD |=(1<<PD4);
}
else
{
PORTD &= ~(1<<PD4);
}
}
}
Geht auch... also wird sozusagen Frame eingehalten...
Irgendwo wird zuviel Zeit verbraten ?? :-s
Also in der INT0 - ISR hab ich Timer0 auch weggelassen
Ah ja.
Jetzt machen wir INT0 wieder scharf wie vorgesehen
d.h (fast) alles wir vorher, nur das eigentliche Pind.2 -> Byte lesen in der Timer-ISR lassen wir mal weg, das Echo bleibt in der while-schleife
sollt ja gehen
Next: In der echo-kopie im while setzen wir nicht nur das tx-Pin, sondern auch das bRxByte.7 (das MSB). rotieren lassen wir aber die Timer-iSR
Und dann schicken wir in der while schleife das nun entstandene Byte auch mit der sende-routine weg
haben wir jetzt ein echo o.k und wieder ein türk y ?
(war das verständlich ? )
Hm Step 1 ok. Einfach inner Timer-ISR auskommentieren. Funkioniert auch.
Aber das mit 7. Bit setzen (bRxByte |=0x80;) inner while-Schleife, versteh ich grad net so ganz.. also was es bringt...
Jetzt ists ja so, das alles was an Bits bei PD2 ankommt gleich wieder an PORTD4 rausgschickt wird.
EDIT: Meinst du den ganzen Receive-Block von der Timer-ISR in die while-Schleife ziehen ?
der Gedanke ist:
Wir können die Bits in der while schleife offenbar richtig erkennen
wir brauchen diese Bits aber im rxbyte an der RICHTIGEN Stelle.
in der while schleife setzten wir das 7 Bit, und der Timer rotiert das Bit nach rechts, wenn baudratenmäßig das nächste dran ist.
Das wird zwar nicht stimmen, sonst hätten wir ja kein Problem, aber vielleicht können wir durch Vergleich Bit-Kopie-Echo und timermäßiges Byte-Echo das Problem einkreisen.
Receive-Block inner Timer-ISR:
if (bRxFlag & RX_M_RECEIVE) // receive ?
{
if (bRxCount == 9) // is this the stop-Bit (9th)
{
bRxFlag &= ~RX_M_RECEIVE; // receiving sequence done
bRxFlag |= RX_M_DATA; // signal data
GICR |= 1<<INT0; // re-enable int0 for next
}
else
{
bRxByte >>= 1; // Shift right data
/* if(PIND&(1<<PD2)) set bit or leave it
{
bRxByte |=0x80;
bRxCount++;
} */
while-Schleife:
while(1)
{
if(bRxFlag & RX_M_RECEIVE)
{
if(PIND&(1<<PD2))
{
PORTD |=(1<<PD4);
bRxByte |=0x80;
bRxCount++;
}
else
{
PORTD &= ~(1<<PD4);
}
}
}
Alles perfekt, aber das rxCount++ bleibt in der ISR
Ok, Echo funktioniert immer noch einwandfrei.
Probier jetzt die send_one_byte() aus
Gut, aber was steht jetzt im bRxByte ?
(zusätzlich in der while)
if (bRxFlag & RX_M_DATA)
{
bRxFlag &= ~RX_M_DATA;
_send (bRxByte);
}
Wie fast erwartet...
Bit-Kopie Echo passt mit send_byte wieder y
Du, ich muß eine Stunde weg. ich meld' mich
*grüberl*
Sag mal, steht das noch so drin ? (in der timer-isr)
if (bRxFlag & RX_M_RECEIVE)
{
if (bRxCount & 0x080)
das ist katastophal falsch muß heißen :
if (bRxCount & 0x08)
EDIT: Seh grad, du hast jetzt if (rxcount == 9) das ist aber auch eines zu viel, wir haben ja nur 8 datenbits
Hab jetzt ein bischen rumgespielt mit der if-Abfrage
wenn du if(bRxCount & 0x08) machst passts mit der Bit-Kopie inner while() und die y kommen bzw. ab und zu auch mal ein þ.
Wenn du z.b. if(bRxCount & 0x09) oder 0x07 machst dann ist Bit-Kopie nicht mehr ok und y kommen immer noch..... :-s
Morgen, da sind wir wieder !
Wenn du z.b. if(bRxCount & 0x09) oder 0x07 machst dann ist Bit-Kopie nicht mehr ok und y kommen immer noch..... :-s
ist klar, das ist der Unterschied "&" und "==". Egal
Ein neues Spiel, ein neues Glück:
Wir machen die Counterei zu Fuß, vergleichen dann mit dem Timer-ISR Ergebnis und erhoffen Weisheiten.
Dazu senden wir immer nur das Zeichen 0x55, das ergibt mit start und stop genau das Muster 0 10101010 1, dadurch kriegen wir die Bitwechsel auch ohne Time genau mit. die erste Flanke zum Startbit kriegt ja der INT0, der setzt RX_M_RECEIVE, und dann geht's los
(dabei läuft die Timer0-ISR ganz normal, nur
RX_M_DATA setzt er NICHT und
RX_M_RECEIVE löscht er NICHT, das machen wir jetzt extra)
unsigned char bOld = 0; // wegen den Flanken
unsigned char bCnt = 0; // vergleichszähler
// in der INT0 ISR zusätzlich
bOld = 0;
bCnt = 0;
// in der while(1) -schleife
if (bRXFlag & RX_M_RECEIVE)
{
if ( ( PIND & (1<<PD2)) ^ bOld & (1<<PD2)) // any Flanke ?
{
if (bCnt & 0x08)
{
bRXFlag &= ~RX_M_RECEIVE;
bRXFlag |= RX_M_DATA;
}
else
{
bOld = PIND;
bCnt++;
bRxByte >>= 1;
}
}
if ( PIND & (1<<PD2))
{
PORTD |=(1<<PD4);
bRxByte |=0x80;
}
else
{
PORTD &= ~(1<<PD4);
}
}
if (bRXFlag & RX_M_DATA)
{
bRxFlag &= ~RX_M_DATA;
send_one_byte(bRxCount + 0x30);
}
send_one_byte(bRxCount + 0x30);
Wir senden den Byte-Zähler, den die Timer0-ISR zu diesem Zeitpunkt gerade hat. Der sollte ja eigentlich auch ca 8 oder 9 sein. Ist er weiter weg, können wir abschätzen, wo die Differenz liegt
( + 0x30) --> damit das ein druckbares zeichen wird und wir es lesen können.
0x30 ---> "0"
wie gesagt, kann nur funzen, wenn 0x55 = "U" geschickt wird, wegen des Bit musters
Verständlich ?
Aber wie is das dann mit RxByte in der Timer-ISR ?
Wird das dann net überschrieben, wenn du auch RxByte in while setzt ?
Versteh den Ablauf nicht mehr so ganz...
EDIT: 8en kommen wenn die Timer-ISR so aussieht
if (bRxFlag & RX_M_RECEIVE) // receive ?
{
if (bRxCount & 0x08) // is this the stop-Bit (9th)
{
bRxFlag &= ~RX_M_RECEIVE; // receiving sequence done
bRxFlag |= RX_M_DATA; // signal data
GICR |= 1<<INT0; // re-enable int0 for next
}
else
{
bRxByte >>= 1; // Shift right data
bRxCount++;
/* if(PIND&(1<<PD2)) //set bit or leave it
{
bRxByte |=0x80;
bRxCount++;
} */
}
}
nya wenn ich so ziemlich alles auskommentier auf Tastendruck immer u0
RxByte: was die TimerISR reinschreibt, wissen wir eh schon (y) daher ausgeliehen für die while-routine
Ich wollte wissen, wenn wir durch ein Spezialzeichen extra die Bits zählen, und nach der 8. Flanke den (parallel)Zähler der TimerISR anschauen, wieweit denn die Timer-Isr gekommen wäre (in der selben Zeit)
Übrigens: Großes (shift) "U" ist gefragt (0x55)
Wenn dir bei der beschriebenen Methode "u0" rauskommt, ("u" ist das Echo, und "0" der iSR-Counter zum selben Zeitpunkt) heißt das ja, daß die Timer-ISR nichteinmal zu zählen begonnen hat, obwohl das Byte schon aus war.
Das müssen wir sicherstellen. Bitte stell den ganzen Code rein.
Code while()
while(1)
{
if (bRxFlag & RX_M_RECEIVE)
{
if ( ( PIND & (1<<PD2)) ^ (bOld & (1<<PD2))) // any Flanke ?
{
if (bCnt & 0x08)
{
bRxFlag &= ~RX_M_RECEIVE;
bRxFlag |= RX_M_DATA;
}
else
{
bOld = PIND;
bCnt++;
bRxByte >>= 1;
}
}
if ( PIND & (1<<PD2))
{
PORTD |=(1<<PD4);
bRxByte |=0x80;
}
else
{
PORTD &= ~(1<<PD4);
}
}
if (bRxFlag & RX_M_DATA)
{
bRxFlag &= ~RX_M_DATA;
send_one_byte(bRxCount + 0x30);
}
}
Receive-Routine inner Timer-ISR:
if (bRxFlag & RX_M_RECEIVE) // receive ?
{
if (bRxCount & 0x08) // is this the stop-Bit (9th)
{
//bRxFlag &= ~RX_M_RECEIVE; // receiving sequence done
//bRxFlag |= RX_M_DATA; // signal data
GICR |= 1<<INT0; // re-enable int0 for next
}
else
{
bRxByte >>= 1; // Shift right data
bRxCount++;
/* if(PIND&(1<<PD2)) //set bit or leave it
{
bRxByte |=0x80;
bRxCount++;
} */
}
}
und INT0
if(!(bRxFlag & RX_M_RECEIVE))
{
GICR = 0; // Disable external interrupt
// bTxFlag &= ~TX_M_SEND; // Deactivate Transmit-Mode
TCNT0 = INT0_PRELOAD; // Set timer reload-value (to 1.5 bit len). 29 = time delay that
// have already been used in this
// interrupt plus the time
// that will be used by the time
// delay between timer interrupt request
// and the actual sampling of the first
// data bit.
TIFR |= (1<<TOV0); // clear T/C0 overflow flag
TIMSK |= (1<<TOIE0); // enable T/C0 overflow interrupt
bRxCount = 0; // Clear Receive Counter
bOld = 0;
bCnt = 0;
bRxFlag |= RX_M_RECEIVE; // Activate Receive-Mode
}
so wie ichs jetzt hab kommen nur U's (UUUUUUUU usw.)
das muß aus der ISR noch raus
bRxByte >>= 1; // Shift right data
In der Main-Routine, sicherheitshalber
if ( PIND & (1<<PD2))
{
PORTD |=(1<<PD4);
bRxByte |=0x80;
}
else
{
PORTD &= ~(1<<PD4);
bRxByte &=~0x80;
}
D.h bei der Methode wird offenbar RX_M_DATA garnicht gesetzt, sonst müßte er nach jedem "U" ja irgendwas ausgeben.
Da müssen wir kontrollieren, ob die while routine überhaupt die Flanken erkennt
while(1)
{
if (bRxFlag & RX_M_RECEIVE)
{
if ( ( PIND & (1<<PD2)) ^ (bOld & (1<<PD2))) // any Flanke ?
{
if (bCnt & 0x08)
{
bRxFlag &= ~RX_M_RECEIVE;
bRxFlag |= RX_M_DATA;
}
else
{
bOld = PIND;
bCnt++;
bRxByte >>= 1;
}
if ( PIND & (1<<PD2))
{
PORTD |=(1<<PD4);
bRxByte |=0x80;
}
else
{
PORTD &= ~(1<<PD4);
bRxByte &= ~0x80;
}
}
}
if (bRxFlag & RX_M_DATA)
{
bRxFlag &= ~RX_M_DATA;
send_one_byte(bRxCount + 0x30);
}
}
(es ist nur ein "}" anders)
in diesem Falle dürft jetzt GARKEIN echo kommen
in diesem Falle dürft jetzt GARKEIN echo kommen
tuts aber, wieder die UUUUUUUUUU (also halt nur die Bit-Kopie, so wie vorher) :(
andere Tasten nur irgendein Müll
(Müll ist klar, das geht nur mit 0x55)
Ja, aber wenn er RX_M_DATA auslöst,
send_one_byte(bRxCount + 0x30);
kann doch kein "U" sein ?
Hopperla, da pfuscht uns die INT0 rein.
Lösch' das RX_M_RECEIVE erst zusammen mit dem RX_M_DATA , aber VOR dem Send_one...
if (bRxFlag & RX_M_DATA)
{
bRxFlag &= ~RX_M_DATA;
bRxFlag &= ~RX_M_RECEIVE;
send_one_byte(bRxCount + 0x30);
}
U's kommn immer noch :shock:
Noch ne Frage, bei 8 Datenbit 10101010 müßtn das net 0xAA sein?
Nein, LSB is first, er fängt beim kleinsten Bit an, also gew. rechts nach links
Was mich jetzt wundert, wieso send-One_byte scheinbar nix schickt, zwischen den U's
Nein, LSB is first, er fängt beim kleinsten Bit an, also gew. rechts nach links
Stimmt auch wieder.. :-k
Aber eigentlich sollte doch das RX_M_DATA gesetzt werden oder nicht ?!?!
Ja, eben. das kann er doch nur versäumen, wenn er keine 8 Flanken erkennen kann ? Das kann er aber, sonst tät er ja nicht richtig kopieren (echo)
Da spuckt uns wer in die Suppe
Andere Strategie:
Du nimmst mal ganz normal die HW-UART zum senden und empfangen.
Den RxPin verbinden wir aber mit INT0 als Spion und der startet auch den Timer, der nix tut, außer bit zählen
Wenn beim empfangenen Byte das UDR signal gibt, müßte dieser Zähler ja unabhängig bis etwa 8 kommen. tut er das nicht, isser zu schnell oder langsam.
HW Uart stimmt no was net ganz.. Hab ich noch was vergessen zu initialisieren ??
Würd das dann mit unserem SW Uart kombinieren, so wie du meintest
INT0 mit dranhängen und in der Timer-ISR nur Bits mitzählen
__task void main()
{
hw_uart_init(11); // 19200 @3.686 MHz
while(1);
}
void hw_uart_init(unsigned char baudrate)
{
UBRRL = baudrate;
UCSRB |= (1<<RXEN) | (1<<TXEN) | (1<<RXCIE);
}
void transmit_byte(unsigned char data)
{
UDR = data;
}
#pragma vector=USART_RXC_vect
__interrupt void UART_RX_interrupt(void)
{
unsigned char data;
data = UDR; //receive data
transmit_byte(data); // echo data
}
Morgen, in voller Frische ?
UBRRL = LOW(baudrate);
UBRRH = HIGH(baudrate);
Mag er net.
Kann ich doch auch so schreiben:
UBRRL = 0x0B;
UBRRH = 0x00;
Geht imma no net
So gesehen hast du recht.
Ich kann aber eigentlich keinen Fehler sehen.
Sei () hast du ja drinnen ?
__task void main()
{
init_hw_uart(); // 19200 @3.686 MHz
__enable_interrupt();
while(1);
}
void init_hw_uart()
{
// Set Baudrate
UBRRH = 0x00;
UBRRL = 0x0B;
// Enable receiver and transmitter
UCSRB |= (1<<RXEN)|(1<<TXEN)|(1<<RXCIE);
// Set frame format: 8data bit , 1 Stop Bit
UCSRC |= (1<<UCSZ1)|(1<<UCSZ0);
}
void transmit_byte(unsigned char data)
{
// Put data into buffer, sends the data
UDR = data;
}
#pragma vector=USART_RXC_vect
__interrupt void UART_RX_interrupt(void)
{
DDRB |= (1<<PB0); // Status LED initialization
PORTB ^= (1<<PORTB0); // toggle status LED
unsigned char data;
data = UDR; //receive data
transmit_byte(data); // echo data
}
siehst du da irgndwo einen Fehler ? :-s
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
Geht jetzt.... ](*,)
ok dann ma sw-uart mit reinbasteln
Sollt eigentlich funzen (HW UART geht noch *gg*). Stell den Code schon ma online..
Muss nur noch die zusätzlichen Leitungen verbinden.
Der RxCounter-Stand vom Software UART wird wieder mit send_one_byte() ans Terminal geschickt.
So wars auch gedacht ?!
Schau ich mir gleich an.
Wir können für diesen Versuch auch mit der HW-Uart senden, es ist im Grunde egal.
Wenn das Echo mal prinzipiell getestet ist und funzt,
hw_transmit_byte(data); // echo data
reicht aber dann
hw_transmit_byte(bRxCount + 0x30); // return actual rxcounter
bin ich neugierig
HW-UART funzt, aber anscheinend wird nie RX_M_DATA gesetzt (siehe while-Schleife)
Denn im Terminal zeigts kein Counterstand an...
Habs jetzt so:
Mal schauen, ob INT0 überhaupt anspringt.
In der Hw Receive-ISR den Flag RX_M_RECEIVE prüfen
Isser gesetzt, ist INT0 offenbar angesprungen
wenn nicht, müssen wir klären, warum das so ist.
( mach einfach statt "send-one-byte( '0') oder ('1') )
Ist der Flag da, aber rxCount bleibt null, kommt die Timer-ISR nicht dran
(irgendein enable fehlt ?)
Schaust du mal ?
Sag ma sperren sich die Interrupts nicht gegenseitig ??
Meine damit INT0 und den USART_RXC...
Hab Status LED in INT0 und des springt net an...
Außerdem is ja INT0 PD2 und RXD ist PD0
Na ich hoff doch, du hast PD2 und PD0 verbunden ?
RX Pin aufm Board mit PD2 sollt ja auch gehn..
klaro, INT0 (PD2) muß mithören können
Das gibsch nich.. jetzt hab ich nochmal "umgepfrimelt" von PD0 auf PD2 anstatt glei von RX auf PD2
Und INT0 springt net an...
HW Uart geht *krise* :cry:
Also RX_M_RECEIVE wird in der INT0 definitiv nicht gesetzt, habs jetzt in der HW-UART ISR abgefragt..
keine Zeichen am Terminal
Wenn INT0 anspringt, setzt er auch _M_receive, da kommt er nicht vorbei.
Vielleicht ist da auch ein Gedankenfehler drin und INT0 wird irgendwie erst NACH der Uart ausgeführt.
Setz vielleicht in der HW-UART-ISR einen anderen Flag (RX_M_MUHKUH), frag den in der Mainroutine ab und schau, ob JETZT Receive gesetzt ist
Erstma so halbe Entwarnung.. wenn ich die Status LED jetzt in der INT0 drinne hab leuchtets, also schon ma gut.
Wenn ich se stattdessen jetzt inne Receive Routine in der Timer ISR reintu leuchtets net.
Anscheinend lösch ma irgndwo ausversehen RX_M_RECEIVE... ?!
while(1)
{
if(bRxFlag & RX_M_DATA)
{
bRxFlag &= ~RX_M_DATA;
//bRxFlag &= ~RX_M_RECEIVE;
hw_transmit_byte(bRxCount + 0x30);
}
}
So auskommentiert: //bRxFlag &= ~RX_M_RECEIVE; gehts..
Counter ist immer 0 im Terminal
Das wirklich sehr komische ist... RX_M_DATA wird vorher nie gesetzt.....
Count müßte daher eigentlich auf jedenfall > 0 sein (bzw. solltns eigentlich 8 sein...) bevor in der while-Schleife hw_transmit_byte(bRxCount + 0x30);
ausgeführt wird.
wenn int0 _M_receive setzt, kann die Timer routine was tun.
wenn sie zählt, könnte sie M_data setzen und ggf. wieder INT0 enablen.
der wiederum würde den count zurücksetzen, und nur _data bliebe über
Nimm aus der Timer routine mal alles raus, außer zählen
if (bRxCount & 0x08) // is this the stop-Bit (9th)
{
bRxFlag &= ~RX_M_RECEIVE; // receiving sequence done
bRxFlag |= RX_M_DATA; // signal data
GICR |= 1<<INT0; // re-enable int0 for next
}
Alles sehr sehr komisch....
Wenn ich alles aus der Timer-ISR rausschmeiss ausser dem bRxCount
Also so:
#pragma vector=TIMER0_OVF_vect
__interrupt void tim0_ovf(void)
{
TCNT0 = T0_PRELOAD; // Refresh preload
// ================================================== ========================
// receive
// ================================================== ========================
if (bRxFlag & RX_M_RECEIVE) // receive ?
{
DDRB |= (1<<PB2); // Status LED initialization
PORTB ^= (1<<PORTB2); // toggle status LED
/* if (bRxCount & 0x08) // is this the stop-Bit (9th)
{
bRxFlag &= ~RX_M_RECEIVE; // receiving sequence done
bRxFlag |= RX_M_DATA; // signal data
GICR |= 1<<INT0; // re-enable int0 for next
}
else */
// {
// bRxByte >>= 1; // Shift right data
bRxCount++;
bRxFlag |= RX_M_MUHKUH;
/* if(PIND&(1<<PD2)) //set bit or leave it
{
bRxByte |=0x80;
bRxCount++;
} */
// }
}
}
while-Schleife:
while(1)
{
if(bRxFlag & RX_M_MUHKUH)
{
//bRxFlag &= ~RX_M_DATA;
bRxFlag &= ~RX_M_RECEIVE;
bRxFlag &= ~RX_M_MUHKUH;
hw_transmit_byte(bRxCount + 0x30);
}
}
wird kein INT0 ausgelöst. d.h. nur HW-Uart Echo, kein bRxCounter Stand.
Kommentiere ich aber bRxFlag &= ~RX_M_RECEIVE; und bRxFlag &= ~RX_M_MUHKUH; aus, wird INT0 ständig ausgelöst (ein Tastendruck reicht...)
Was dann gesendet wird:
!+5?IS]gq{…™£*·ÁËÕßéóýCMWaku‰“§±»ÅÏÙãí÷
)3=GQ[eoyƒ—¡«µ¿ÉÓÝçñû#-7AKU_is}‡‘›¥¯¹Ã
also nur Müll halt...
Irgendwie glaub' ich, wir sind voll in einer Panikattacke und neigen zu sinnlosen Aktionen
Wir haben doch ein Programm gehabt, mit einem Timer, der offenbar in der richtigen Zeit mit der richtigen Baudrate auch längere Daten tadellos wegschicken konnte. (ich hab das zu Hause auch mit längeren Strings versucht).
Wenn der also prinzipiell im richtigen Bitraster tickert (TIM0_PRELOAD), geht's doch nurmehr darum, durch das Start-Bit das Lesen zu starten und die Ticks so zu verschieben (INT0_PRELOAD), daß die Timer-ISR immer die Mitte der Datenbits erwischt. Punkt.
Das hatten wir eigentlich auch, insofern, daß INT0 ausgelöst und TIME0 freigegeben hat, diese hat auch pipifein bis 9 gezählt und einen Flag gesetzt.
Also funktionell eigentlich alles richtig, bis auf das "y".
Was KANN denn falsch sein ?
Prescale u. normaler Preload muß wohl stimmen. (--> senden geht ja)
Es kann doch nur darum gehen, daß INT0 entweder
falsch getriggert wird
unerwünscht mehrfach getriggert wird
den TImer nicht richtig enabled
sein 1 1/2 Bit Preload falsch ist
den Timer funktionell irgendwie beeinflußt
Vielleicht sollten wir die ursprüngliche "y" Version wieder herstellen und uns das nochmal in Ruhe genau anschauen
Kannst du mir die HEX file dann mal posten, damit ich sie analysieren kann (ich hab da was spezielles)
"y"-Version wieder hergestellt.
Was dabei noch auffällt ist, das bei Sonderzeichen, Zahlen und Steuerzeichen statt nem "y" auch öfters ma ein "þ" kommt.
Bei Buchstaben dagegen nur "y".
Kannst du noch die HEX posten ?
Hexfile ist im Intel extended Format.
Was hast du da für ein Programm und wie kann man damit Hexfiles analysieren ?? :-s
args ich benenns ma schnell in *.txt um, dann gehts wahrscheinclih
ok geht... mußt dann wieder in *.a90 umbenennen
Das ist von mir eine Art Disassembler, der aber mehr nach logischen Aspekten angelegt ist und mehr parametrisierbar ist.
Ui, mit dem Format komm' ich und auch der AVR-Studio nicht zurecht.
Kannst du nicht das normale intel Hex erzeugen ?
Hm komisch mit AVR Studio programmier ich auch immer Hexfile aufn Controller..
Habs ma in Intel Standard erzeugt, vielleicht gehts jetzt
Ist allerdings auch wieder nen *.a90
Sodala.
Ich hab jetzt im Programm rumgezangelt und auch mit dem Datsheet abgematcht.
Es ist jetzt die SW- Echo Version, die wir in etwa haben wollen
Ein paar enables-disables haben nicht gestimmt
Zusatz: die Funktion send_one_byte kommt erst zurück, wenn senden fertig ist
Und erst NACH dem gesendeten Echo wird INT0 wieder enabled, damit uns keiner reinpfuscht.
Die INT0-ISR wird auch nur tätig , wenn NICHT gesendet UND NICHT empfangen wird. (für's erste mal)
Übrigens ich mußte doch erst die Hex mit dem Pony einlesen und dann wieder wegschreiben, weil AVR-Studio hat gemeint, das Zeugs wäre irgendwo Korrupt. is egal.
EDIT: noch was: das direkte echo ist ein bißchen im Programm verteilt,
Was für enables und disables warn des dann ?? :-k
Kannst du den Code noch posten ?
*ähem* irgendwie hast du recht :oops:
In der INT0-ISR hat er durch setzen statt löschen den Timer SOFORT ausgelöst, d.h. INT0-Preload ist unwirksam, wir lesen das Startbit mit
das ist woanders auch vorgekommen, daher hab ich mir diese enable-disable-orgien dann alle einzeln zur Brust genommen.
Naja, schau'n wir, ob wir vom Y wegkommen. Aber ab jetzt versuchen wir ruhig zu bleiben.
Lief nicht gleich auf Anhieb, hab aber noch geändert:
TCCR0 &= ~(1<<CS00);
und
TCCR0 &= ~(1<<CS02);
~ haben gefehlt
Und jetzt ganz ruhig bleiben: hÐÿâþaÿøþlÿlØÿoÞÿ 8-[
Tilde vergessen, pfui gack. :Haue
Keep cool: du mußt jetzt mal auf bestimmte Zeichen wechseln, damit wir die richtige Richtung kriegen
Probier mal einfach <ENTER> drücken, das ist 0x0D. und dann shauen wir, was rauskommt.
geht darum, hauptsächlich die LSBits zu setzen
In der INT0-ISR hat er durch setzen statt löschen den Timer SOFORT ausgelöst, d.h. INT0-Preload ist unwirksam,...
Damit meinst du schon das Overflow Flag oder ? Dachte erst man muss das durch setzen einer logisch 1 löschen, so stand glaubsch im Datenblatt..
Habs jetzt aber nicht nochmal geändert
Zur Taste ENTER --> da kommt genau ein ÿ
Eigentlich bei allen interrupts isses so, daß dann, wenn Global enable = 1 UND specific enable = 1 UND specific signal = 1 die ISR ausgelöst wird.
(datasheet)
ENTER jetzt sollt man wissen, aber welchen Zeichen NICHT y kommt.
EDIT interessant sind auch single Bit-Zeichen
<space> "@"
4x Space-Taste:
@þSPACEÿ`þSPACEÿ`þSPACEÿ@þSPACEÿ
also immer in 4er Päckchen
werd da nicht unbedingt schlau draus, vorallem läuft das net nach einem bestimmten Muster
Nochmal:
auf EINMAL <leertaste>
kriegst du z.B.
@þSPACEÿ
also 0x'40' und noch drei andere ?
by the way: hast du beim Terminal VT100 Mode eingestellt ?
Jep auf einmal Leertaste 4 Zeichen (0x20 eigntlich, im Post jetzt als SPACE angedeutet. Sorry wenns nicht ganz klar war/ist)
das @ (0x40) kommt ab und zu als erstes Zeichen
Jo beim Terminal ist VT100 eingestellt. Für was ist das gedacht ?
VT100 : wegen den Sonderzeichen. diese komischen "b" mit verlängerung find ich bei mir nicht
Wenn er 0x20 als 0x40 liest, ist er eigentlich zwei Bits zu weit. ( Hat zur Folge, daß er sofort ein neues Byte beginnt-und sendet-und ein paar Bytes braucht, bis er sich wieder erfangen hat)
Da T0-Preload ja wohl nicht auf einmal falsch sein kann, muß es einen anderen Grund geben.
ein falsches INT0-Preload würde das eigentlich nicht erklären.
*denk*
Halt, stop, retour: das erste Zeichen, das du siehst, ist ja das direkte echo. das TERMINAL ist schon beim 4.Bit
kannst du das direkte echo auskommentieren, das verwirrt jetzt
EDIT (und schauen, was jetzt auf <space> kommt ?
das komische verlängerte b ist 0xfe oder 0xde (nach der Tabelle http://www.manderby.com/informatik/allgemeines/ascii.php)
Tilden eingefügt, direkt-echo entfernt.
(wir produzieren ja damit einen 50% Baudraten fehler durch das 0.5 Bit
´Sorry musste wech vorhin..
Habs jetzt nomma ausprobiert:
HÿAÿLÿLÿOÿ ÿ?ÿ?ÿ?ÿ?ÿ?ÿ ÿtÿeÿsÿtÿ ÿ.ÿ.ÿ.ÿ.ÿ.ÿ ÿ@ÿ@ÿ@ÿ@ÿ@ÿ@ÿ@ÿ ÿ ÿ ÿ ÿ ÿ ÿ
waren jetzt meine Testeingaben.
Wenn ma aber Direkt-Echo entfernen sollt doch eigentlich nur noch 1 Zeichen kommen oder bin ich jetzt ganz doofy... :|
Traraaa !
Ich hab bei mir eine Teststellung aufgebaut und darf dir sagen, dass das Zeugs funktioniert. ich schick dir noch heute die adaptierte Source. Erläuterung folgt, zum Mäusemelken !
Cool !!! 8) \:D/
Aber an was hatts dann die ganze Zeit gelegen ??
Ich hab das eben so aufgebaut, daß ich PD2 u. PD0 (rx) verbunden habe und halt das ganze prescale u. preload f. 8 MHZ angepaßt habe. Senden hatt' ich ja schon ("hello, world") also habe ich das ganze INT0 -Zeugs eigentlich mit cut & paste aus unserem Programm übernommen. Und hatte auch bei der ersten Versuchen prompt ein ähnliches Ergebnis. Nämlich nix. d.h es schien so, als würde INT0 zwar anspringen, aber die TImer-ISR irgendwie nicht laufen (rxcount 0). Dann hab ich die ganze INT0 wieder auskommentiert und das Start-Bit in der Main-Schleife abgefragt. Und wieder war nix mit rxcount. Da ich die Timer-routine aber eigentlich nie disable, und senden ging ja immer, war das rätselhaft.
Dann stieg in mir ein Verdacht auf, und sieh, es ging auf einmal ruckartig.
und zwar hab ich rx- u. txflag zusammengelegt und die bit-names umdefiniert
TX_M_SEND 1
RX_M_RECV 4
RX_M_DATA 8
d.h mit edit replace hab ich aus bRxFlag ebenfalls bTxFlag gemacht.
ich hab zwar noch irgendwo den Fehler, daß mein echo immer zusätzlich ein zweites Zeichen ausgibt, aber das Problem find ich.
Jetzt hol ich mir nochmal dein HEX um auch dein Programm in der Richtung zu kontrollieren (wer rechnet mit sowas) also irgendwie ist das kein Beweis, daß das bei dir das gleiche Problem ist.
(die Timer-ISR kriegt den Flag RX_M_RECEIVE einfach nicht mit)
aber es ist mal eindeutig der Beweis da, daß das Programm-Konzept mit Timing, 1 u. 1.5 Bit und alles drumherum) stimmt und nur solche Idiotien der Grund für das Massaker sind.
Also die Version Sw-uart-2 von gestern paßt, nur eben die obige Änderung müßtest du mal versuchen.
Ich such mal jetzt den Grund für das doppel-Echo und versuch das ganze noch zu beweisen.
Hab die Änderungen jetzt auch vorgenommen. Bleibt so wie beim letzten Stand. Erst richtiges Echo und dann noch ein Zeichen mit. Wie sieht denn dein Doppel-Echo aus ?
Aber echt supi, das ma jetzt schon davon ausgehen können, das Timing etc. richtig ist.
Bei mir geht, scheinbar, einfach der Cursor einen schritt zu weit. So wie wenn man gesperrt schreiben würde. Wie gesagt, das erste Zeichen stimmt, dann sendet er wahrscheinlich ein (pseudo) Startbit zu viel oder sowas, also eigentlich kein wirkliches Zeichen.
Ich hab eine Terminalemulation, die würde auch binärcode darstellen, zeigt aber nix.
Das macht mir aber keine Sorgen, ich werd' das jetzt testen.
So. Ich mußte doch tatsächlich von dem 1.5 Bit umsteigen auf 0.5 Bit.
d.h. ich bin mitten im Startbit, wenn es eines ist. Erst wenn hier die Leitung auch low ist, gilt das ganze.
Eigentlich war es das. Ziemlich hartnäckiges Zeugs.
Ich habe meine Source attached, is für Winavr und Meg32 mit 8 MHZ.
Du bist so lieb, und übersetzt das selbst in deine Syntax und in deinen Quarz, mit graut aus begreiflichen Gründen schon vor allem, was mit "UA" anfängt.
Das Programm ist funktionsfähig und echoed was man schreibt
0.5 Bit --> bei dir , glaub ich (256 - 210) /2 --> 23
also TIM0_preload --> 210
INT0_preload --> 210 + 23 = 233 !!!!!
Versuch's mal und laß bitte hören.
Hi !
Funzt einwandfrei, nachdem ich nochn bischen mit dem INT0 Preload Wert rumgespielt hab !!
BIG THX FOR HELP !!! 8) \:D/
Hab selber viel gelernt dabei !
Tätarätääää !
Hört man gerne, war auch wirklich eine schwere Geburt und ein drei Meter langer Thread.
Lernen: Klar, am meisten lernt man bei dem, was NICHT geht.
also, keep codin' and let them robbies roll !
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.