Hallo erstmal zusammen.
Ich recheriere hier schon länger im Board und bin sehr zufrieden mit der
Kompetenz einiger User (sehr gutes Wissen), was mir schon viel in der
Vergangenheit geholfen hatte, dafür Danke!
Jedoch stehe ich jetzt vor einem Problem:
Ich habe hier einen ATMega32 + 16MHz Quarz. -> AVR Studio 5 ("C").
Ich benutze den Timer1 für eine "PPM" (Ich benötige eine variable
Frequenz am PD5 mit fester positiven Pulsweite [26µs]).
Das tut auch ganz gut, gesteuert wird dies via RS232.
An den restlichen Pins des ATMega32 (ausser PD4) müssen jetzt I/O's
angeschlossen werden.
Darunter fällt u.a. auch SRAM etc.
Sollte alles kein Problem sein, jedoch stoße ich hier auf einen "Show
Stopper".
Sobald ich den Timer1 initialisiere + starte, sind die restlichen
doppelt belegten PIN vom µC fest für Timer vergeben.
Z.b. der Pin PD7(OC2).
Gibt es eine Möglichkeit den Timer1 zu nutzen UND alle restlichen Pins
(ausser PD4 & 5) als Ein und Ausgänge zu nutzen?
So bald ich den Timer1 ausschalte (Prescaler auf 0) kann ich z.B. den
Pin PD7 "High" oder "Low" setzen, jedoch nicht wenn der Timer1 läuft.
Ich wäre um jeden Tipp sehr dankbar!
Danke und Gruß
Hi
>Sobald ich den Timer1 initialisiere + starte, sind die restlichen>doppelt belegten PIN vom µC fest für Timer vergeben.>Z.b. der Pin PD7(OC2).
Da machst du etwas falsch. Zeig mal deine Initialisierungen.
MfG Spess
Hi zusammen!
Das ging ja flott! :)
Genau das wundert mich ja, warum, wenn ich nur den Timer1 verwende, Pins
vom Timer2 sich verstellen.
Anbei mal der C-Code.
Ich verwende den Timer1 um eine "PPM" zu erzeugen. Ich muss eine
variable Frequenz (~1KHz - 16KHz) erzeugen, jedoch mit einer
gleichbleibenden Pulsbreite (~26µs). Zudem sollte die Frequenz sehr fein
änderbar sein (daher 16Bit Timer).
Ich lasse den Timer im "normal Mode" laufen und schalte den direkten
Ausgang vom OC1A und OC1B auf PD5 & PD4 ab. Timer Top = 0xFFFF
Interrupt gesteuert.
Ich lasse die beiden 16Bit Register OCR1A & OCR1B mit TCNT1 vergleichen,
wenn "compare", dann löst es einen Interrupt aus. Dort wird dann ur der
PD5 einmal ein und dann wieder ausgeschaltet.
Wenn ich jetzt zu Testzwecken über RS232 die vorgeladenen Register
verändere, kann ich mit OCR1A die Frequenz und OCR1B die Pulsbreite
einstellen.
Im einschaltzustand wird am PD5 eine Frequenz von ~14KHz und einer
Pulsbreite von ~26µs erzeugt.
Wenn ich jetzt in der While Schleife "PORTD = (1 << PD7);" oder "PORTD =
(0 << PD7);" schalte, passiert nix, bleibt auf "LOW".
Kann sein, das die Kommentare nicht mehr ganz passen, habe seit dem
Fehler viel probiert.
Vielen Dank schonmal!!
Gruß
1
#include<avr/io.h>
2
#include<stdlib.h>
3
#include<avr/interrupt.h>
4
#include<avr/iom32.h>
5
#include<stdio.h>
6
#include<util/delay.h>
7
8
#define F_CPU 16000000
9
#define UART_BAUD 19200
10
#define MaxPuffer 2 //Maximaler Ringpuffer für USART (100 Zeilen á 8 Bit breit)
11
12
uint8_tpuffer[MaxPuffer];
13
uint8_t*read_ptr;
14
uint8_t*write_ptr;
15
uint8_tUSART_Byte;
16
17
18
voidcontroler_init()
19
{
20
//Zu Testzwecken Port A, B, C und D als Ausgang und alle Ausgänge auf LOW
TCCR1A=(0<<COM1A1)|(0<<COM1A0)|(0<<COM1B1)|(0<<COM1B0)|(0<<FOC1A)|(0<<FOC1B)|(1<<WGM11)|(1<<WGM10);//Normal port operation, OC1A/OC1B disconnected; Normal Timer Operation TOP = 0xFFFF
> PORTD = (1 << PD5);
Da kannst du gleich schreiben PORTD = 0b00100000.
Also alle anderen Pins außer PD5 werden auf 0V gesetzt.
Und hier:
> PORTD = (0 << PD5);
PORTD = 0b00000000
Thomas D. schrieb:> PORTA |= (0 << PA0) | (0 << PA1) | (0 << PA2) | (0 << PA3) | (0 << PA4) | (0 <<
PA5) | (0 << PA6) | (0 << PA7);
Scherzkeks, ein NOP geht auch einfacher.
Geh an die Tafel und schreibe 100 mal:
Ich lerne erst, was |= bedeutet, ehe ich es verwende!
Peter
schreiben, oder? :)
Manchmal sieht man vor lauter Bits das Byte nicht mehr...
Ok, sorry fürs stören.
Die Initialisierung sollte jedoch passen oder?
Ich muss an einer bestehenden PCB anknüpfen, dort sind alle Pins belegt
(Port C = Datenbus von SRAM, Port A & B = Adressbus SRAM, Port D =
Timer, 2 Bits für einen Multiplexer [für die umschaltung von den insg. 4
SRAMs]) etc.
Eine Frage hätte ich jedoch noch:
Warum "muss" ich in der While schleife ein delay von 1 µs (oder weniger
haben) damit die Daten von RS232 erkannt werden? Ich prüfe ja bei jedem
Durchgang ob der lesepupperPointer != schreibepufferPointer ist, wenn ja
= Datan vorhanden, wenn nicht, keine Daten vorhanden.
Das gleiche wenn ich stings senden will, wird wohl in der func
"uart_write" der Pointer überlaufen:
wenn ich ein String sende z.B. "Test" kommt der am Terminal an, wenn ich
jetzt nur ein Zeichen sende, kommt "Müll"+das Zeichen an. Leeren von der
Variable str in der func "uart_write" hat leider ncihts gebracht.
Gruß
Thomas
@peda
Lese mal mein Kommentar im ersten Code Beispiel. Da ich dem Fehler nicht
auf die schliche kam, probiert mal auch dinge die eigentlich einfacher
tun.
Ich werde mich natürlich gleich an die Strafarbeit setzen... :)
Thomas D. schrieb:> Da ich dem Fehler nicht> auf die schliche kam, probiert mal auch dinge die eigentlich einfacher> tun.
Nö, Du probierst Dinge, die garnichts tun.
"x |= 0;" ist Code ohne Effekt.
Sowas macht man nicht, erst recht nicht, um Fehler zu suchen.
Peter
Thomas D. schrieb:> Eine Frage hätte ich jedoch noch:> Warum "muss" ich in der While schleife ein delay von 1 µs (oder weniger> haben) damit die Daten von RS232 erkannt werden? Ich prüfe ja bei jedem> Durchgang ob der lesepupperPointer != schreibepufferPointer ist, wenn ja> = Datan vorhanden, wenn nicht, keine Daten vorhanden.
Da sehe ich direkt 2 Fehler:
1. Die globalen Variablen, die Du in der ISR änderst, müssen volatile
deklariert werden, damit Du sie in main() benutzen darfst.
2. Die Variable write_ptr besteht aus jeweils 2 Bytes.
Du musst in main() gewährleisten, dass der Zugriff atomar ist und
nicht durch die ISR, welche zwischendurch aufgerufen werden könnte,
geändert werden kann.
Dein Delay versteckt nur den Fehler.
Ich schlage vor, statt Pointer Indices zu verwenden. Dann kommst Du mit
1 Byte pro index aus (read_idx & write_idx) und kannst Punkt 2 abhaken.
Ausserdem geht der Zugriff auf Deinen Buffer über Indices im allgemeinen
flotter als mit Pointern - jedenfalls auf einem µC.
Ich weis, jedoch hatte ich mir alle Bits von den Ports einzeln
aufgeschrieben, um jeweils ein Bit zu ändern wenns nötig ist (also
einfach am entsprechenden Bit eine 1 statt der 0 eintragen).
Aber wurst, ich habs ja verstanden was Du meintest.
Hat einer eine Idee mit dem delay in der while, warum das dann erst tut?
Würde gerne komplett ohne delay arbeiten.
Gruß
@UKW
Danke für Deine Antwort!!
Klingt logisch was Du geschrieben hast. Ich werde mich mal in Indices
einlesen, bin da noch grün hinter den Ohren.
Zwecks den variablen und volatile.
Ich dachte ich brauche das nur, wenn ich eine Variable im Interrupt UND
in der Main ändere.
Hier tue ich das ja nicht, ich frage höchsten die beiden pointer auf
ungleichheut ab, oder irre ich mich damit?
Thomas D. schrieb:> Klingt logisch was Du geschrieben hast. Ich werde mich mal in Indices> einlesen, bin da noch grün hinter den Ohren.
Komisch, eigentlich lernt man erst den Umgang mit buffer[idx] statt mit
Pointern ;-)
> Zwecks den variablen und volatile.> Ich dachte ich brauche das nur, wenn ich eine Variable im Interrupt UND> in der Main ändere.
Nein, auch wenn Du lesend drauf zugreifst. Der Compiler könnte sonst
write_ptr in ein Register(-Paar) packen, wenn er sieht, dass main()
niemals beendet wird und keine Unterfunktion aufgerufen wird, die diese
Variable ändert. Die ISR() wird ja nirgends explizit aufgerufen.
> Hier tue ich das ja nicht, ich frage höchsten die beiden pointer auf> ungleichheut ab, oder irre ich mich damit?
read_ptr wird nicht in der ISR verwendet, ist daher kein Problem.
write_ptr aber schon.
Benutze aber besser:
1
uint8_tread_idx;
2
volatileuint8_twrite_idx;
3
...
4
ISR(USART_RXC_vect)
5
{
6
puffer[write_idx]=UDR;
7
write_idx++;
8
if(write_idx==MaxPuffer)write_idx=0;
9
}
Rest analog.
MaxPuffer würde ich als MAX_PUFFER schreiben - wie es sich für eine
Preprocessor-Konstante gehört. Ausserdem ist sie mit dem Wert 2
unterirdisch klein ;-)
Hi UKW!
Danke für Deine Hilfe!
Ich werde mir morgen mal das ganze anschauen und dann posten wie es
lief. :)
Immer toll wenn man ein Forum hat indem es Leute gibt die einem weiter
helfen, ich will ja kein code kopieren der komplett fertig ist o.ä. ich
will das lernen um selber damit arbeiten zu können.
Werde mir auch morgen mal Dein Beispiel dazu anschauen und versuchen das
zu verwenden.
Zwecks dem MAX_PUFFER und dem inhalt. Der lag eigentlich bei 100, habe
ihn vergessen wieder auf 100 zu setzen. Aber danke, hätte ich glatt
übersehen. :)
Gruß
Thomas
Die zweite Zeile ist hoffentlich nur ein Test-Echo??? Denn hier
schreibst Du in das Senderegister ohne Rücksicht auf Verluste. Wenn
USART_Byte tatsächlich gesendet werden soll, dann benutze bitte Deine(!)
Funktion uart_putchar(). Die ist dafür gedacht: Sie wartet, bis das
Senderegister frei ist und beschreibt erst dann UDR.
So, wie Du das oben machst, geht das in die Hose.