Hallo,
Ich habe hier ein kleines Gerät, was auf das Senden einer bestimmten
Zahl über USB mittels einem FT245R eine Reaktion, das Senden eines
Triggerpulses, reagieren soll.
Ich habe es so programmiert, dass er auf 128 reagiert. Nur dummerweise
reagiert er stattdessen auf alle Zahlen zwischen 64 und 127 ! Was zur
Hölle hab ich denn da verbockt? Ist mein erstes GCC Programm...
1
//Program to run the USB-Trigger box
2
3
#include<avr/io.h>
4
5
intmain(void){
6
7
unsignedcharstat=0;
8
unsignedchardat=0;
9
10
DDRD=0x00;//all input (Byte from FT245R)
11
DDRB=0b01000010;//only PB1 and PB6 are output
12
DDRC=0x03;//both BNC outputs enabled
13
14
PORTB|=(1<<PB1);//read strobe to high
15
PORTB&=~(1<<PB6);
16
17
while(1){
18
19
if(PINB&=(1<<PINB0)&&stat==1){//falling edge
20
21
PORTB&=~(1<<PB1);
22
dat=5*5;//waste some time
23
24
dat=~PIND;// read PORTD
25
26
PORTB|=(1<<PB1);//reset
27
28
if(dat==128){//trigger condition
29
PORTC|=(1<<PC0);//trigger pulse
30
PORTB|=(1<<PB6);//light LED
31
32
}
33
elsePORTB&=~(1<<PB6);//darken
34
35
};
36
stat=PINB0;//save last read status to compare in next cycle
Brauche ich da Pullups? Das sind doch Output Pins vom FT245, die müssten
doch einen definierten State haben. Wenn nix ankommt, sind sie
jedenfalls high.
So, ich habe etwas Fortschritt gemacht. Mit einem Bascom Programm geht
es, aber nicht in GCC. Hier ist der neue Code. Das Problem ist, er
durchläuft die if-Schleife nach der fallenden Flanke problemlos. Bei der
zweiten if-Abfrage if(dat==123) spinnt er rum. Wenn ich auf dat==0
teste, geht er bei jeder gesendeten Zahl an. Egal welche. Teste ich aber
auf eine von 0 verschiedene Zahl funktioniert es nicht mehr. Mit Bascom
erkennt er die Zahlen aber problemlos. Die Bascom Variante ist ganz
unten.
Mike Strangelove schrieb:
Du solltest noch beschreiben, was an welchem Pin hängt und wie die Logik
der einzelnen Pins lautet. Wenn du einen Ausganbepin auf High/Low setzt,
dann bewirkt das ja etwas. Nur was?
> #include <avr/io.h>>> int main (void) {>> unsigned char dat = 0;>> DDRD = 0x00; //all input (Byte from FT245R)> DDRB = 0b01000010; //only PB1 and PB6 are output> DDRC = 0x03; //both BNC outputs enabled>> PORTB |= (1<<PB1); //read strobe to high> PORTB &= ~(1<<PB6); //LED off>> while(1) {>> if(!(PINB & (1<<PB0))) { //falling edge
Das ist kein Flankendetektor.
Wenn der Körper deines if schneller abgearbeitet wird, als das externe
Gerät Zeit braucht um den Pin wieder auf high zu ziehen, dann wertest du
xxxx ein zweites mal aus
>> PORTB &= ~(1<<PB1); //read low
Startet das irgendeinen Vorgang?
>>> dat=PIND; // read PORTD
Woher weißt du, dass jetzt die Daten schon am PIND abholbereit
vorliegen?
>> PORTB |= (1<<PB1); //reset>> if(dat==123) { //trigger condition HIER IST PROBLEM
ziemlich sicher ist hier nicht das Problem.
Du siehst an dieser Stelle die Symptome, aber das bedeutet nicht das
hier das Problem liegt. Das wird wohl weiter oben schon sein, nur ohne
Datenblatt mit einem Timingdiagramm kann ich nicht sagen, ob du
Timingvorschriften verletzt hast, bzw. wie eigentlich das Zusammenspiel
der Pins funktionieren soll
(Und noch was: So was
dat=5*5; //waste some time
schmeisst dir jeder noch so grindige C Compiler raus. Wenn du ein wenig
warten willst, dann benutze die _delay_xx Funktionen. Dafür sind sie
da.)
Mike Strangelove schrieb:> PORTB &= ~(1<<PB1); //read low> dat=PIND; // read PORTD
Das kannst Du nicht machen. Damit ein Wert gültig eingelesen wird, muss
er zwischen einem halben und eineinhalb AVR-Takte vor dem Einlesen
angelegen haben. Du setzt aber Deinen Read-Puls low im ersten Takt und
liest bereits gleich danach im zweiten ein. Am einfachsten schreibst Du
die dat=PIND - Zeile zweimal hintereinander hin, dann sollte es passen.
Ansonsten ist der FT245R so schnell, dass ich die anderen Bedenken nicht
teile. Auch ist es nicht notwendig, eine RXF-Flanke zu erkennen; dort
ist der Kommentar falsch, nicht die Aktion.
Du hättest es uns allen viel leichter gemacht, wenn Du z.B. statt PB0
ein RXF hingeschrieben (und natürlich vorher #define'd) hättest, also
die Hardware-Bitnamen verwendet hättest. Auch ist Dein Quellcode
eingerückt wie Kraut und Rüben, statt die Blockstruktur erkennbar zu
machen.
Hallo,
VIelen Dank für Deine Hilfe!
> Du solltest noch beschreiben, was an welchem Pin hängt und wie die Logik> der einzelnen Pins lautet.
An PB6 hängt eine LED die bei 1 angeht
An PB0 kommt eine fallende Flanke wenn Daten abhlbereit sind
An PB1 muss ich eine fallende Flanke setzen um die Daten an PIND 8 bit
breit senden zu lassen. Wenn PB1 wieder high geht, wird der Ausgang
undefiniert und PB0 bekommt wieder high-Pegel vom FT245.
>> if(!(PINB & (1<<PB0))) { //falling edge>> Das ist kein Flankendetektor.> Wenn der Körper deines if schneller abgearbeitet wird, als das externe> Gerät Zeit braucht um den Pin wieder auf high zu ziehen, dann wertest du> xxxx ein zweites mal aus
Ich hatte erst einen Flankendetektor, hab den aber rausgenommen, da mit
PORTB |= (1<<PB1) der FT245 schnell wieder high zieht, bevor der ganze
Kram einmal durch ist.
>> PORTB &= ~(1<<PB1); //read low>> Startet das irgendeinen Vorgang?
Das schiebt das angekommene Byte an den 8-bit Port des FT245 der mit
PIND verbunden ist.
>> dat=PIND; // read PORTD>> Woher weißt du, dass jetzt die Daten schon am PIND abholbereit> vorliegen?
Das ist genau der Knackpunkt. Im Datenblatt stehen 20 ns, der MC läuft
mit 8 Mhz. Ich habe da noch eine sinnlose Multiplikation mit
reingepackt, um das Problem zu umgehen, hat aber nix genützt.
>> PORTB |= (1<<PB1); //reset>>>> if(dat==123) { //trigger condition HIER IST PROBLEM>> ziemlich sicher ist hier nicht das Problem.> Du siehst an dieser Stelle die Symptome, aber das bedeutet nicht das> hier das Problem liegt. Das wird wohl weiter oben schon sein, nur ohne> Datenblatt mit einem Timingdiagramm kann ich nicht sagen, ob du> Timingvorschriften verletzt hast, bzw. wie eigentlich das Zusammenspiel> der Pins funktionieren soll
Das ist möglich. Aber eben dieser Loop wird nicht korrekt abgearbeitet.
Entweder die Daten kommen nicht richtig zu PIND rein, oder da habe ich
den falschen Operator benutzt etc...
>> (Und noch was: So was>> dat=5*5; //waste some time>> schmeisst dir jeder noch so grindige C Compiler raus. Wenn du ein wenig> warten willst, dann benutze die _delay_xx Funktionen. Dafür sind sie> da.)
Hmm, das ist ein sehr guter Punkt. Danke, ich dachte der macht das
einfach mit und erzeugt einen Delay ohne dass ich _delay einbinden muss.
Angenommen Bascom schmeisst das nicht raus, könnte in diesem
Zeitunterschied das Problem liegen.
John Doe schrieb:>> Woher weißt du, dass jetzt die Daten schon am PIND abholbereit>> vorliegen?>> Das ist genau der Knackpunkt. Im Datenblatt stehen 20 ns,
Nur zur Verdeutlichung, wie man Datenblätter liest: Dort stehen zwei
Werte: min. 20 ns und max. 50 ns. Für Dich sind natürlich die 50 ns
maßgebend (denn erst dann hast Du garantiert Daten anliegen) und die 20
kannst Du vergessen.
Im vorliegenden Fall spielt der Unterschied nur deshalb keine Rolle,
weil die Zeit des AVR-Input-Synchronizers sowieso viel größer ist.