Forum: Mikrocontroller und Digitale Elektronik [AVR] Controller reagiert auf falsche Zahl.


von Mike S. (drseltsam)


Lesenswert?

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
int main (void) {            
6
7
unsigned char stat = 0;
8
unsigned char dat = 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
    else PORTB &= ~(1<<PB6); //darken 
34
  
35
  };
36
  stat=PINB0; //save last read status to compare in next cycle
37
  PORTC &= ~(1<<PC0);; //reset trigger channel
38
39
   
40
   } 
41
 
42
   
43
   return 0;
44
}

von Albert .. (albert-k)


Lesenswert?

Du hast keine Pullups für die Output Pins bei PORTB aktiviert.
1
PORTB |= ~((1<<PB0) | (1<<PB6)); //activate all Pullups except PB1 and PB6
Dasselbe für PORTD. Oder hat es im FT245 an den Ausgängen welche?

von Mike S. (drseltsam)


Lesenswert?

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.

von holger (Gast)


Lesenswert?

>  if(PINB &= (1<<PINB0) && stat==1) { //falling edge

Da ist ein = zuviel drin.

von Albert .. (albert-k)


Lesenswert?

Und zwar das "=" bei "&=". Du willst ja eine UND-Verknüpfung und keine 
zuweisung

von holger (Gast)


Lesenswert?

>  stat=PINB0; //save last read status to compare in next cycle

Der ist auch gut. PINB0 ist eine Konstante;)

von Mike S. (drseltsam)


Lesenswert?

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.


1
//Program to run the USB-Trigger box
2
3
#include <avr/io.h>          
4
5
int main (void) {            
6
7
unsigned char dat = 0;
8
9
DDRD = 0x00; //all input (Byte from FT245R)
10
DDRB = 0b01000010; //only PB1 and PB6 are output
11
DDRC = 0x03; //both BNC outputs enabled
12
13
PORTB |= (1<<PB1); //read strobe to high 
14
PORTB &= ~(1<<PB6);   //LED off
15
16
   while(1) {  
17
                 
18
  if(!(PINB & (1<<PB0))) { //falling edge
19
    
20
    
21
    PORTB &= ~(1<<PB1); //read low
22
    
23
24
    dat=PIND; // read PORTD
25
    
26
    PORTB |= (1<<PB1); //reset
27
28
    if(dat==123) { //trigger condition HIER IST PROBLEM
29
      PORTC |= (1<<PC0); //trigger pulse
30
      PORTB |= (1<<PB6); //light LED      
31
32
    }
33
    else {
34
    
35
    PORTB &= ~(1<<PB6); //darken 
36
    }
37
  
38
  }
39
40
  PORTC &= ~(1<<PC0); //reset trigger channel
41
42
     
43
   } 
44
 
45
   
46
   return 0;
47
}
1
Do
2
3
Pb = Pinb.0
4
5
6
If Pb = 0 Then                                              'falling edge
7
8
9
  Portb.1 = 0                                               'shift data out
10
11
  Dat = 5 * 5                                               'waste some time
12
13
  Dat = Pind
14
15
  Portb.1 = 1
16
17
  If Dat = 123 Then
18
19
  Portb.6 = 1
20
  Else
21
  Portb.6 = 0
22
23
  End If
24
                                                 'reset
25
26
27
End If
28
29
Loop
30
End

von Karl H. (kbuchegg)


Lesenswert?

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.)

von Hc Z. (mizch)


Lesenswert?

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.

von John Doe (Gast)


Lesenswert?

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.

von Hc Z. (mizch)


Lesenswert?

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.

von Mike S. (drseltsam)


Lesenswert?

Jupp, das war's. Die Zahl war noch nicht da, als der MC schon lesen 
wollte. Kleine Pause erledigt das Problem. Danke Euch!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.