[AVR] Controller reagiert auf falsche Zahl.

OP #1840645
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
}
OP #1842027
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
#1842045
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.)
#1842100
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.
Gast #1842103
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.
#1842121
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren