Forum: Compiler & IDEs ATTiny 2313 Änfängerfrage


von Simon (Gast)


Lesenswert?

Hallo
ich bin dabei mir eine Impulszählerschaltung zu bauen.
Hardware
ATtiny 2313
4 7-Segment Anzeigen
2x 4543
4x BC 328 zum Ansteuern der 7 segment
paar Widerstände und C sowie Festspannungsregler

an pin 4,5 und pin 7,8 hab ich die Transistoren für die 7 Segement 
Anzeige gelötet.

Jetzt möchte ich erstmal ein Grundprogramm schreiben welches auf pin 
4,5,7,8 low Pegel ausgibt.
Allerdings sind bis jetzt alle Versuche gescheitert es liegen immer 5V 
an egal wie ich mein Programm verändere.

Hier mal mein Code.

Thx for help
Grüße
Simon


#define MCU  attiny2313


#include <avr/io.h>     // Namen der IO Register
#include <util/delay.h> // Funktionen zum warten

int main(void){
  DDRA = 0b00000111; //alle A als Ausgang  0-2
  DDRB = 0b11111111; //alle B als Ausgang  0-7
  DDRD = 0b01111111; //alle D als Ausgang  0-6

PORTA = 0b00000011;    //A0,A1 = Pin 4,5 am uC -> Transistor
PORTB = 0b11111111;    //alles high auch für 7 seg
PORTD = 0b00110000;             //D4,D5 = Pin 8,9 am uC -> Transistor

 while(1) {                // (5a)
     /* "leere" Schleife*/  // (5b)


   }                         // (5c)

   /* wird nie erreicht */
   return 0;
}


Selbst wenn ich jetzt die Transitor Pins auf 0 schalte liegen - gemessen 
mim Multimeter - immernoch 5 V an den Pins an.

Danke!

von holger (Gast)


Lesenswert?

>Allerdings sind bis jetzt alle Versuche gescheitert es liegen immer 5V
>an egal wie ich mein Programm verändere.

Ein Schaltplan könnte ganz hilfreich sein;)

von Simon (Gast)


Lesenswert?

ok werd ich morgen - allerdings nur in paint zeichenen und hochladen

von abc (Gast)


Lesenswert?

Aber bitte nicht als bmp! Bildformate

von Simon (Gast)


Angehängte Dateien:

Lesenswert?

Guten Morgen

anbei der gewünschte Schaltplan.

Ich glaube auch den Fehler gefunden zu haben. Ich muss statt des PNP 
Transistors einen NPN einbauen - ?!? oder?

Gestern habe ich noch den uc ausgebaut und dann lagen an den pins für 
TR-1 bis TR-4 5V an. Somit war es immer egal welche pins ich im code auf 
high gezogen habe...

P.S.
Wäre die Schaltung so dann i.o.

an Pin1 des uc hängt ein öffner welchen ich zum resetten des 
impulszählers verwenden möchte (also anzeige auf 0000 bzw ganz aus)

von Edi R. (edi_r)


Lesenswert?

pnp? npn? Ich sehe keinen Transistor.

Der Öffner an Pin 1 ist also normalerweise geschlossen? Dann resettest 
Du den Controller ständig. Außerdem würde ich unbedingt einen Widerstand 
10 kOhm von Pin 1 (Reset) an Vcc (5V) empfehlen. Und muss der Reset 
nicht auch am Programmierstecker liegen?

Nachtrag: Erst jetzt habe ich gesehen, dass die PDF zwei Seiten hat, und 
jetzt habe ich auch die Transistoren gesehen. Die PNP sind schon in 
Ordnung (und besser als NPN an dieser Stelle), aber die Ausgänge TR1 bis 
TR4 müssen normalerweise auf HIGH (also auf 5V) liegen, nur wenn die 
entsprechende Ziffer eingeschaltet werden soll, wird der einzelne 
Ausgang auf LOW (GND) geschaltet.

Zweiter Nachtrag: Beim HEF4543 musst Du PH (Pin 6) auf Vcc legen, wenn 
Du 7-Segment-LEDs mit gemeinsamer Anode hast.

von Simon (Gast)


Lesenswert?

Hi Edi R.

Danke für die Info,

ich habe 7 Segment mit gemeinsamer Kathode.

Zu dem Transistor:
 Ich hab das Problem dass wenn ich Betriebsspannung anlege am Emitter 5V 
anliegen -soll ja auch so sein-
Allerdings kommen über die Basis 4,3V an den uC was mir ja nix bringt - 
desshalb der Gedanke mit einem NPN Transistor nur genau anders herum 
eingebaut.

Folgendes muss ich ncoh ändern : -Richtig?

- an pin 1 häng ich jetzt nen öffner
- zwischen pin 1 und vcc noch 10kOhm Widerstand

- Wo muss ich den Reset am Programmierstecker anbringen?



Danke
Grüße
Simon

von Simon (Gast)


Lesenswert?

Nachtrag:
Was bringt mir der zusätzliche 10k Widerstand?

von Edi R. (edi_r)


Lesenswert?

Simon schrieb:
> ich habe 7 Segment mit gemeinsamer Kathode.

Bist Du sicher? Im Schaltplan steht auch: "CA", was ich als "Common 
Anode" verstehe. Aber wenn die Displays gemeinsame Kathoden haben, dann 
passt der Schaltplan nicht.

> Zu dem Transistor:
>  Ich hab das Problem dass wenn ich Betriebsspannung anlege am Emitter 5V
> anliegen -soll ja auch so sein-
> Allerdings kommen über die Basis 4,3V an den uC was mir ja nix bringt -
> desshalb der Gedanke mit einem NPN Transistor nur genau anders herum
> eingebaut.

Zuerst sollten wir klären, ob die Displays wirklich gemeinsame Kathoden 
haben, und wenn ja, den ganzen Schaltplan umstellen.

> - an pin 1 häng ich jetzt nen öffner

Ich dachte, da ist jetzt schon ein Öffner? Es sollte ein Schließer 
zwischen Pin 1 und GND hinkommen. Der ATtiny macht einen Reset, wenn der 
Pin 1 auf LOW gezogen wird.

> - zwischen pin 1 und vcc noch 10kOhm Widerstand

Richtig. Mit diesem Widerstand wird der Pin 1 sicher auf HIGH gezogen. 
Es ist zwar ein Pull-Up-Widerstand eingebaut, aber nach meinen 
Erfahrungen ist der zu hochohmig. Atmel empfiehlt diesen externen 
Widerstand übrigens auch.

> - Wo muss ich den Reset am Programmierstecker anbringen?

Wenn Du den 10-poligen ISP-Stecker verwendest: An Pin 5. Und ich sehe 
gerade, dass dort auch schon der 10-kOhm-Widerstand ist. Es fehlt also 
nur noch die Verbindung zu Pin 1, dann hat sich die Sache mit dem 
zusätzlichen Pull-Up-Widerstand auch erledigt.

von Simon S. (simon-1)


Angehängte Dateien:

Lesenswert?

Hallo again, jetzt auch mit Anmeldung.

also ich hab nachgeschaut.
- Das sind die 7 Segment - und doch mit gemeinsamer Anode.
http://www.reichelt.de/?;ACTION=3;LA=444;GROUP=A51;GROUPID=3002;ARTICLE=6916;START=0;SORT=artnr;OFFSET=16;SID=31TQHyr38AAAIAADAKATY732e878fb025c20a23a09b38664a00bd


- Pin 1 bekommt natürlich einen schließer - sorry for that.

- anbei mal der neue schaltplan.

zusätzlich habe ich auch den pin 6 vom 4543 geändert.


Was mich eben stört ist die Tatsache, dass der Transistor eben die 4,3V 
an den uC Transistor Pin schaltet. Um auf 0V zu kommen bräuche ich ja ne 
negative Spannung am uC - oder?

Thx for help

Edit:
Sorry fals es jetzt nichts mehr mit Programmierung zu tun hat und somit 
im falschen Forum ist

von Edi R. (edi_r)


Lesenswert?

Simon S. schrieb:
> - Das sind die 7 Segment - und doch mit gemeinsamer Anode.

Dann passt der Schaltplan, dann passen auch die PNP-Transistoren. Ob die 
Basisvorwiderstände mit 1 kOhm nicht zu hochohmig sind, muss sich noch 
herausstellen. Möglicherweise reicht das aber auch.

> zusätzlich habe ich auch den pin 6 vom 4543 geändert.

Was die Hardware betrifft, müsste es so klappen. Obwohl ich ein paar 
Sachen ändern würde, aber das geht momentan schon zu weit.

> Was mich eben stört ist die Tatsache, dass der Transistor eben die 4,3V
> an den uC Transistor Pin schaltet. Um auf 0V zu kommen bräuche ich ja ne
> negative Spannung am uC - oder?

Der Transistor schaltet über die Basis überhaupt nichts, und Du brauchst 
auch keine negative Spannung am µC. Die 4,3 V misst Du wahrscheinlich 
direkt am Transistor, nicht am Portpin, oder? Dazwischen ist ja noch der 
Widerstand. Wenn Du direkt am Portpin 4,3 V misst, dann ist er nicht als 
Ausgang geschaltet. Oder die Basisvorwiderstände fehlen (bzw. sind 
kurzgeschlossen).

Ich weiß ja nicht, mit welcher Entwicklungsumgebung Du arbeitest, aber 
probier mal, ob dieses Programm übersetzt wird und läuft:
1
#include <avr/io.h>     // Namen der IO Register
2
#include <util/delay.h> // Funktionen zum warten
3
4
int main(void){
5
  DDRA = 0b00000111; //alle A als Ausgang  0-2
6
  DDRB = 0b11111111; //alle B als Ausgang  0-7
7
  DDRD = 0b01111111; //alle D als Ausgang  0-6
8
9
  PORTA = 0b00000011;
10
  PORTB = 0b00000000;
11
  PORTD = 0b00110000;
12
13
  while(1) {
14
    PORTA &= (1<<0);
15
    _delay_ms(250);
16
    PORTA |= (1<<0);
17
18
    PORTA &= (1<<1);
19
    _delay_ms(250);
20
    PORTA |= (1<<1);
21
22
    PORTD &= (1<<4);
23
    _delay_ms(250);
24
    PORTD |= (1<<4);
25
26
    PORTD &= (1<<5);
27
    _delay_ms(250);
28
    PORTD |= (1<<5);
29
  }
30
}

Damit müssten der Reihe nach auf den vier Digits "0" erscheinen.

von Simon S. (simon-1)


Lesenswert?

Edi R. schrieb:
> Der Transistor schaltet über die Basis überhaupt nichts, und Du brauchst
> auch keine negative Spannung am µC. Die 4,3 V misst Du wahrscheinlich
> direkt am Transistor, nicht am Portpin, oder? Dazwischen ist ja noch der
> Widerstand. Wenn Du direkt am Portpin 4,3 V misst, dann ist er nicht als
> Ausgang geschaltet. Oder die Basisvorwiderstände fehlen (bzw. sind
> kurzgeschlossen).

Also ich hab den uC ausgebaut und messe am uC Sockel die 4,3V und das 
Wundert mich eben. Vorwiderstände lt. Schaltplan 1k und nicht 
kurzgeschlossen.

>
> Ich weiß ja nicht, mit welcher Entwicklungsumgebung Du arbeitest, aber
> probier mal, ob dieses Programm übersetzt wird und läuft:
>
Ich arbeite mit AVR STudio und WinAVR müsste also klappen.
Leider kann ich erst am Sonntag abend bescheid geben ob es funktionert 
hat da ich übers we weg bin.

thx bis sonntag bzw montag

von Simon S. (simon-1)


Lesenswert?

Nabend.

also es funktioniert so weit.
Jetzt hab ich ne frage zum code :-)

Ich habe dein Beispiel etwas angepasst.
Es sollen die Zeichen 1-4 auf der Anzeige ausgegeben werden.
Segment 1 = 1
Segment 2 = 2
Segment 3 = 3
Segment 4 = 4

Problem ist, das 1-3 geht bei 4 kommt ne 6 raus und beim nächsten 
durchlauf geht es
1636 1636 usw

hier mal der code.
thx for help
1
#define MCU  attiny2313
2
3
4
#include <avr/io.h>     // Namen der IO Register
5
#include <util/delay.h> // Funktionen zum warten
6
7
int main(void){
8
  
9
  DDRA = 0b00000111; //alle A als Ausgang  0-2
10
  DDRB = 0b11111111; //alle B als Ausgang  0-7
11
  DDRD = 0b01111111; //alle D als Ausgang  0-6
12
13
  PORTA = 0b00000011;
14
  PORTB = 0b00000000;
15
  PORTD = 0b00110000;
16
17
  while(1) {
18
  
19
   PORTB |= (1<<PB1) ;   //Einschalten Ziffer 1
20
   PORTB &= ~(1<<PB2) | (1<<PB3) | (1<<PB5); // Einschalten Ziffer 1
21
   PORTD &= ~(1<<PD5); //AUsschalten pos 1
22
   _delay_ms(250);
23
   PORTD |= (1<<PD5);   //Einschalten
24
25
   PORTD |= (1<<PD1)  ;   //Einschalten Ziffer 2
26
   PORTD &= ~(1<<PD0) | (1<<PD2)| (1<<PD3); // Einschalten Ziffer 2
27
   PORTD &= ~(1<<PD4); //Ausschalten pos 2 
28
   _delay_ms(250);
29
   PORTD |= (1<<PD4);   //Einschalten
30
31
   PORTB |= (1<<PB1) | (1<<PB2) ;   //Einschalten Ziffer 3
32
   PORTB &= ~(1<<PB3) | (1<<PB5); // Einschalten Ziffer 3
33
   PORTA &= ~(1<<PA0); //AUsschalten pos 3
34
   _delay_ms(250);   
35
   PORTA |= (1<<PA0);   //Einschalten
36
37
38
   PORTD |= (1<<PD2)  ;   //Einschalten Ziffer 4
39
   PORTD &= ~(1<<PD0) | (1<<PD1)| (1<<PD3); // Einschalten Ziffer 4
40
   PORTA &= ~(1<<PA1); //AUsschalten pos 4
41
   _delay_ms(250);   
42
   PORTA |= (1<<PA1);   //Einschalten
43
44
45
46
  }
47
}

von Simon S. (simon-1)


Angehängte Dateien:

Lesenswert?

Hallo nochmal

ich hab es geschafft der Impulszähler funktioniert.

Allerdings hab ich noch etwas Probleme mit meinem Code.

Die Profis unter euch werden sich bestimmt die Hände über dem Kopf 
zusammschlagen.

Anbei ist ein Bild von der 7 Segment.
Es ist deutlich zu erkennen, dass z.b. bei der 7 immer noch die 0 
schwach durchleuchtet.
Wie kann ich das umgehen.
Ich hab auch schon im AVR Tutorial nachgelesen zwecks Geisterleuchten, 
komm aber gerade nicht weiter.

Hier zusätzlich mein Code.
vielen Dank
1
#include <avr/io.h>     // Namen der IO Register
2
#include <util/delay.h> // Funktionen zum warten
3
4
5
void Display(int num)
6
{  
7
switch (num) 
8
  {
9
    case 0: 
10
    PORTB &= ~(1<<PB1)| (1<<PB2)| (1<<PB3)| (1<<PB4);
11
    PORTD &= ~(1<<PD0)| (1<<PD1)| (1<<PD2)| (1<<PD3);break;
12
    case 1:
13
  PORTB |= (1<<PB1);
14
    PORTB &= ~(1<<PB2)| (1<<PB3)| (1<<PB4);
15
  PORTD |= (1<<PD0);
16
    PORTD &= ~(1<<PD1)| (1<<PD2)| (1<<PD3);break;
17
    case 2:
18
  PORTB |= (1<<PB2);
19
    PORTB &= ~(1<<PB1)| (1<<PB3)| (1<<PB4);
20
  PORTD |= (1<<PD1);
21
    PORTD &= ~(1<<PD0)| (1<<PD2)| (1<<PD3);break;
22
    case 3:
23
  PORTB |= (1<<PB1) | (1<<PB2);
24
    PORTB &= ~(1<<PB3)| (1<<PB4);
25
  PORTD |= (1<<PD0) | (1<<PD1);
26
    PORTD &= ~(1<<PD2)| (1<<PD3);break;
27
    case 4:
28
  PORTB |= (1<<PB3);
29
    PORTB &= ~(1<<PB1)| (1<<PB2)| (1<<PB4);
30
  PORTD |= (1<<PD2);
31
    PORTD &= ~(1<<PD0)| (1<<PD1)| (1<<PD3);break;
32
    case 5:
33
  PORTB |= (1<<PB1) | (1<<PB3);
34
    PORTB &= ~(1<<PB2)| (1<<PB4);
35
  PORTD |= (1<<PD0) | (1<<PD2);
36
    PORTD &= ~(1<<PD1)| (1<<PD3);break;
37
    case 6:
38
  PORTB |= (1<<PB2) | (1<<PB3);
39
    PORTB &= ~(1<<PB1)| (1<<PB4);
40
  PORTD |= (1<<PD1) | (1<<PD2);
41
    PORTD &= ~(1<<PD0)| (1<<PD3);break;
42
    case 7:
43
  PORTB |= (1<<PB1) | (1<<PB2) | (1<<PB3);
44
    PORTB &= ~(1<<PB4);
45
  PORTD |= (1<<PD0) | (1<<PD1) | (1<<PD2);
46
    PORTD &= ~(1<<PD3);break;
47
    case 8:
48
  PORTB |= (1<<PB4);
49
    PORTB &= ~(1<<PB1)| (1<<PB2)| (1<<PB3);
50
  PORTD |= (1<<PD3);
51
    PORTD &= ~(1<<PD0)| (1<<PD1)| (1<<PD2);break;
52
    case 9:
53
  PORTB |= (1<<PB1) | (1<<PB4);
54
    PORTB &= ~(1<<PB2)| (1<<PB3);
55
  PORTD |= (1<<PD0) | (1<<PD3);
56
    PORTD &= ~(1<<PD1)| (1<<PD2);break;
57
    default:
58
    PORTB &= ~(1<<PB1)| (1<<PB2)| (1<<PB3)| (1<<PB4);
59
    PORTD &= ~(1<<PD0)| (1<<PD1)| (1<<PD2)| (1<<PD3);break;  
60
  }
61
}
62
63
void SegmentNummer(int tausender, int hunderter, int zehner, int einer)
64
{
65
66
    // gebe einer aus 
67
Display(einer);
68
  PORTD &= ~(1<<PD5);   //Transistor Seg 1 aus -> Seg = ein 
69
  PORTD |= (1<<PD4);  //Transistor Seg 2 an -> Seg = aus
70
  PORTA |= (1<<PA0);  //Transistor Seg 3 an -> Seg = aus
71
  PORTA |= (1<<PA1);  //Transistor Seg 4 an -> Seg = aus
72
_delay_ms(2);
73
  PORTA = 0b00000000;
74
  PORTB = 0b00000000;
75
  PORTD = 0b00000000; 
76
77
  // gebe zehner aus 
78
Display(zehner);
79
  PORTD |= (1<<PD5);    //Transistor Seg 1 an -> Seg = aus 
80
  PORTD &= ~(1<<PD4);  //Transistor Seg 2 aus -> Seg = ein
81
  PORTA |= (1<<PA0);  //Transistor Seg 3 an -> Seg = aus
82
  PORTA |= (1<<PA1);  //Transistor Seg 4 an -> Seg = aus
83
_delay_ms(2);    
84
  PORTA = 0b00000000;
85
  PORTB = 0b00000000;
86
  PORTD = 0b00000000;
87
88
// gebe hunderter aus 
89
Display(hunderter);
90
  PORTD |= (1<<PD5);    //Transistor Seg 1 an -> Seg = aus 
91
  PORTD |= (1<<PD4);  //Transistor Seg 2 an -> Seg = aus
92
  PORTA &= ~(1<<PA0);  //Transistor Seg 3 aus -> Seg = ein
93
  PORTA |= (1<<PA1);  //Transistor Seg 4 an -> Seg = aus
94
_delay_ms(2);    
95
  PORTA = 0b00000000;
96
  PORTB = 0b00000000;
97
  PORTD = 0b00000000; 
98
99
// gebe tausender aus 
100
Display(tausender);
101
  PORTD |= (1<<PD5);    //Transistor Seg 1 an -> Seg = aus 
102
  PORTD |= (1<<PD4);  //Transistor Seg 2 an -> Seg = aus
103
  PORTA |= (1<<PA0);  //Transistor Seg 3 an -> Seg = aus
104
  PORTA &= ~(1<<PA1);  //Transistor Seg 4 aus -> Seg = ein
105
_delay_ms(2);
106
  PORTA = 0b00000000;
107
  PORTB = 0b00000000;
108
  PORTD = 0b00000000; 
109
110
111
}
112
113
114
// Modification for active high push button
115
 
116
#define debounce( port, pin )                                        \
117
({                                                                   \
118
  static uint8_t flag = 0; /* new variable on every macro usage */   \
119
  uint8_t i = 0;                                                     \
120
                                                                     \
121
  if( flag ){                  /* check for key release: */          \
122
    for(;;){                   /* loop... */                         \
123
      if( (port & 1<<pin) ){   /* ... until key pressed or ... */    \
124
        i = 0;                 /* 0 = bounce */                      \
125
        break;                                                       \
126
      }                                                              \
127
      _delay_us( 98 );         /* * 256 = 25ms */                    \
128
      if( --i == 0 ){          /* ... until key >25ms released */    \
129
        flag = 0;              /* clear press flag */                \
130
        i = 0;                 /* 0 = key release debounced */       \
131
        break;                                                       \
132
      }                                                              \
133
    }                                                                \
134
  }else{                       /* else check for key press: */       \
135
    for(;;){                   /* loop ... */                        \
136
      if( !(port & 1<<pin) ){  /* ... until key released or ... */   \
137
        i = 0;                 /* 0 = bounce */                      \
138
        break;                                                       \
139
      }                                                              \
140
      _delay_us( 98 );         /* * 256 = 25ms */                    \
141
      if( --i == 0 ){          /* ... until key >25ms pressed */     \
142
        flag = 1;              /* set press flag */                  \
143
        i = 1;                 /* 1 = key press debounced */         \
144
        break;                                                       \
145
      }                                                              \ 
146
    }                                                                \
147
  }                                                                  \
148
  i;                           /* return value of Macro */           \
149
})
150
151
152
153
154
int main(void){
155
  
156
  DDRA = 0b00000111; //alle A als Ausgang  0-2
157
  DDRB = 0b11111110; //alle B als Ausgang  0-7
158
  DDRD = 0b01111111; //alle D als Ausgang  0-6
159
160
  PORTA = 0b00000011;
161
  PORTB = 0b00000000;
162
  PORTD = 0b00011000;  
163
164
int zahl = 0;
165
166
 while(1) {
167
168
  if (zahl >9999)
169
    {
170
    zahl=0;
171
    }
172
  
173
  int tausender = zahl/1000;
174
  int hunderter = (zahl-(tausender*1000))/100;      
175
  int zehner    = (zahl-(tausender*1000) - (hunderter*100))/10;
176
  int einer     = (zahl-(tausender*1000) - (hunderter*100) - (zehner*10));
177
178
  
179
  SegmentNummer(tausender, hunderter, zehner, einer);
180
181
 
182
    if( debounce( PINB, PB0 ) )
183
       zahl++;
184
185
186
187
188
  }
189
}

von Edi R. (edi_r)


Lesenswert?

Simon S. schrieb:
> Es sollen die Zeichen 1-4 auf der Anzeige ausgegeben werden.
> Segment 1 = 1
> Segment 2 = 2
> Segment 3 = 3
> Segment 4 = 4

Das hat mich erst ein wenig verwirrt, denn als Segment bezeichnet man 
die einzelnen Striche des Displays ("7-Segment-Anzeige"). Was Du meinst, 
sind Stellen oder Digits.

Simon S. schrieb:
> Es ist deutlich zu erkennen, dass z.b. bei der 7 immer noch die 0
> schwach durchleuchtet.
> Wie kann ich das umgehen.

Du musst alle Digits erst mal abschalten, bevor Du die Segmente 
umstellst. Außerdem kann es sein, dass Du nach dem Abschalten noch kurz 
warten musst, weil die Transistoren nicht sofort abschalten können 
("Sperrverzugszeit"). Da reichen aber wenige Mikrosekunden. Zum Beispiel 
so:
1
> Display(einer);
2
>   PORTD &= ~(1<<PD5);   //Transistor Seg 1 aus -> Seg = ein
3
>   PORTD |= (1<<PD4);  //Transistor Seg 2 an -> Seg = aus
4
>   PORTA |= (1<<PA0);  //Transistor Seg 3 an -> Seg = aus
5
>   PORTA |= (1<<PA1);  //Transistor Seg 4 an -> Seg = aus
6
> _delay_ms(2);
7
8
   PORTD |= (1<<PD5);  // alles aus
9
   PORTD |= (1<<PD4);
10
   PORTA |= (1<<PA0);
11
   PORTA |= (1<<PA1);
12
   _delay_us(2);
13
14
>   PORTA = 0b00000000;
15
>   PORTB = 0b00000000;
16
>   PORTD = 0b00000000;

Damit sollte es funktionieren. Noch ein Tipp:

Simon S. schrieb:
> void Display(int num)
> {
> switch (num)
>   {
>     case 0:
>     PORTB &= ~(1<<PB1)| (1<<PB2)| (1<<PB3)| (1<<PB4);
>     PORTD &= ~(1<<PD0)| (1<<PD1)| (1<<PD2)| (1<<PD3);break;
>     case 1:
>   PORTB |= (1<<PB1);
>     PORTB &= ~(1<<PB2)| (1<<PB3)| (1<<PB4);
>   PORTD |= (1<<PD0);
>     PORTD &= ~(1<<PD1)| (1<<PD2)| (1<<PD3);break;
>     case 2:

Diese Funktion könnte man deutlich einfacher machen. Statt jedes Segment 
einzeln zu setzen, kann man das "num" direkt ausgeben, weil Du 
praktischerweise die Portpins schon passend gewählt hast:
1
void Display(unsigned char num)
2
{
3
  PORTB = (PORTB & 0b00001111) | (num & 0b11110000);
4
  PORTD = (PORTD & 0b00001111) | (num & 0b11110000);
5
}

Außerdem reicht auch ein "unsigned char" für die Ziffern 0 bis 9.

Noch was: Es wird Dir vielleicht auffallen, dass die Tausender-Stelle 
ein wenig heller ist als die anderen Stellen, oder dass die Stellen kurz 
flackern, wenn Du die Taste drückst. Das kommt vom Makro "debounce", das 
immer wieder mal eine Millisekunde wartet. In dieser Zeit wird die 
Anzeige nicht angesteuert. Deshalb macht man das Multiplexen lieber über 
Timer-Interrupts. Aber lass es vorerst ruhig mal so, wie es ist, das ist 
schon ok.

Und noch was: Nachdem Du zwei 4543 eingebaut hast, könntest Du zwei 
Stellen gleichzeitig anzeigen, nämlich die Tausender und die Zehner 
gleichzeitig, oder die Hunderter und die Einer. Das würde die Helligkeit 
der Anzeige noch ein wenig erhöhen, weil jede Stelle doppelt so lange 
eingeschaltet wäre.

Ich denke, Dein Ziel hast Du bereits erreicht :-)

von Simon S. (simon-1)


Lesenswert?

hi danke
es funktioniert :D

jetzt geht es ans fein tuning :D
kann man es so einstellen, dass beim impuls die anzeige solange 8888 
anzeigt bis der taster wieder losgelassen wird?

thx grüße
simon

von Karl H. (kbuchegg)


Lesenswert?

natürlich kann man.

Allerdings: so wie du es jetzt hast, wirst du bald anstehen.
Du musst jetzt den Schritt in Richtung Timer und Timerintererrupt gehen 
und das Multiplexing dorthinein verlagern. Die Anzeige muss eigenständig 
und ohne weiteres Zutun der Hauptschleife ständig upgedated werden. Auch 
die ganzen delays, die du im Multiplexing hast, fallen dann raus.
Bei jedem Aufruf der ISR wird immer nur das nächste Digit eingeschaltet 
(Tausender, Hunderter, Zehner, Einer, Tausender, Hunderter, ...) und das 
reihum. Jedes Digit leuchtet solange, bis die ISR das nächste mal vom 
Timer aufgerufen wird.
Was anzuzeigen ist, holt sich die ISR von globalen Variablen.

Und egal welche Ziffern du dann in diese globalen Variablen 
reinschreibst, die ISR zeigt sie an.

Deine Zwischenanzeige ist dann nichts anderes als der Aufruf der 
Ausgabefunktion, die die einzelnen Variablen für die ISR befüllt. Mehr 
steckt dann nicht mehr dahinter und du kannst zu jedem beliebigen 
Zeitpunkt jewde Zahl zur Anzeige bringen.

> jetzt geht es ans fein tuning :D
Noch nicht. Was du hast, ist eine Machbarkeitsstudie, die zeigt dass man 
auf deiner Hardware etwas anzeigen kann. Der nächste SChritt ist es 
jetzt, aus diesem Hardwaretest etwas Brauchbares und Vernünftiges zu 
entwickeln.

von Simon S. (simon-1)


Lesenswert?

Simon S. schrieb:
> // Modification for active high push button
>
> #define debounce( port, pin )                                        \
> ({                                                                   \
>   static uint8_t flag = 0; /* new variable on every macro usage */   \
>   uint8_t i = 0;                                                     \
>                                                                      \
>   if( flag ){                  /* check for key release: */          \
>     for(;;){                   /* loop... */                         \
>       if( (port & 1<<pin) ){   /* ... until key pressed or ... */    \
>         i = 0;                 /* 0 = bounce */                      \
>         break;                                                       \
>       }                                                              \
>       _delay_us( 98 );         /* * 256 = 25ms */                    \
>       if( --i == 0 ){          /* ... until key >25ms released */    \
>         flag = 0;              /* clear press flag */                \
>         i = 0;                 /* 0 = key release debounced */       \
>         break;                                                       \
>       }                                                              \
>     }                                                                \
>   }else{                       /* else check for key press: */       \
>     for(;;){                   /* loop ... */                        \
>       if( !(port & 1<<pin) ){  /* ... until key released or ... */   \
>         i = 0;                 /* 0 = bounce */                      \
>         break;                                                       \
>       }                                                              \
>       _delay_us( 98 );         /* * 256 = 25ms */                    \
>       if( --i == 0 ){          /* ... until key >25ms pressed */     \
>         flag = 1;              /* set press flag */                  \
>         i = 1;                 /* 1 = key press debounced */         \
>         break;                                                       \
>       }                                                              \
>     }                                                                \
>   }                                                                  \
>   i;                           /* return value of Macro */           \
> })

Das mit dem flackern hab ich wegbekommen indem ich die
_delay_us( 98 ) auf
_delay_us (1) geändert hab.
Es funktioniert -allerdings hab ich die Befürchtung dass es wieder grob 
fahrlässig war und jetzt irgendwas schieflaufen könnte.


>> jetzt geht es ans fein tuning :D
>Noch nicht. Was du hast, ist eine Machbarkeitsstudie, die zeigt dass man
>auf deiner Hardware etwas anzeigen kann. Der nächste SChritt ist es
>jetzt, aus diesem Hardwaretest etwas Brauchbares und Vernünftiges zu
>entwickeln.

Was verstehst du unter brauchbar bzw vernünftig?
Das was es können sollte geht ja schonmal - brauchbar also ja oder?

von Nico22 (Gast)


Lesenswert?

Simon S. schrieb:
> Das mit dem flackern hab ich wegbekommen indem ich die
> _delay_us( 98 ) auf
> _delay_us (1) geändert hab.
> Es funktioniert -allerdings hab ich die Befürchtung dass es wieder grob
> fahrlässig war und jetzt irgendwas schieflaufen könnte.

Damit hast du leider die gesamte Debounce-Funktion nichtig gemacht.


> Was verstehst du unter brauchbar bzw vernünftig?
> Das was es können sollte geht ja schonmal - brauchbar also ja oder?

Dass es funktioniert, heißt nicht, dass es brauchbar ist. Da du noch in 
der Hauptfunktion multiplext, kannst du mit dem Controller praktisch 
nichts Anderes anfangen. Verlagerst du das Multiplexing wie 
vorgeschlagen in eine ISR, hat dein Controller plötzlich massig 
Kapazität für weitere Spielereien, u. A. auch, dass während des 
Tastendrucks 8888 angezeigt wird.

Nico

von Simon S. (simon-1)


Lesenswert?

Nico22 schrieb:
> Simon S. schrieb:
>> Das mit dem flackern hab ich wegbekommen indem ich die
>> _delay_us( 98 ) auf
>> _delay_us (1) geändert hab.
>> Es funktioniert -allerdings hab ich die Befürchtung dass es wieder grob
>> fahrlässig war und jetzt irgendwas schieflaufen könnte.
>
> Damit hast du leider die gesamte Debounce-Funktion nichtig gemacht.
>
>
>> Was verstehst du unter brauchbar bzw vernünftig?
>> Das was es können sollte geht ja schonmal - brauchbar also ja oder?
>
> Dass es funktioniert, heißt nicht, dass es brauchbar ist. Da du noch in
> der Hauptfunktion multiplext, kannst du mit dem Controller praktisch
> nichts Anderes anfangen. Verlagerst du das Multiplexing wie
> vorgeschlagen in eine ISR, hat dein Controller plötzlich massig
> Kapazität für weitere Spielereien, u. A. auch, dass während des
> Tastendrucks 8888 angezeigt wird.
>
> Nico

Ok das 1. war mir schon fast klar -wäre ja zu schön gewesen.
- kannst du mir erklären warum ich es zunichte gemacht hab?
- immerhin flackert jetzt ja nichts mehr und bei jedem tastendruck ob 
kurz oder lang zählt er eins nach oben

Dann werd ich mich wohl nochmal in die Sache mit dem ISR einlesen 
müssen.
Ist wie gesagt mein 1. Projekt mit uC und C Programmierung.

Vielen Dank schonmal bis hier hat mich schon sehr viel weiter gebracht 
als ich zu beginn des Freds war.

von Karl H. (kbuchegg)


Lesenswert?

Simon S. schrieb:

> Ok das 1. war mir schon fast klar -wäre ja zu schön gewesen.
> - kannst du mir erklären warum ich es zunichte gemacht hab?

Weil du damit das debouncing ausgehebelt hast.
Das Prinzip des Debouncen ist:
Da Taster prellen, muss man sich einen Weg überlegen, wie man einen 
prellenden Taster von mehreren Tastendrücken unterscheiden kann. Die 
einfachste und einzigste Möglichkeit ist es, das über die Zeit zu 
machen.
Verändert ein Taster in 1 Millisekunde seinen Wert mehrfach, dann wird 
das wohl kein Tastendruck vom Benutzer gewesen sein, sondern 
unerwünschtes Tastenprellen. So schnell kann kein Mensch drücken und 
loslassen. Verändert ein Taster aber nach einer halben Sekunde seinen 
Zustand, dann ist das kein Tastenprellen mehr sondern da wird wohl der 
Benutzer die Taste sehr schnell losgelassen haben.
Die Unterscheidung zwischen Prellen und Benutzeraktion erfolgt also 
durch den Beobachtungszeitraum. Alle Wechsel des Zustands innerhalb 
dieses Beobachtungszeitraums werden als Prellen gewertet, alle die 
länger sind, als Benutzeraktion. Machst du den Beobachtunszeitraum aber 
zu kurz, dann wird plötzlich Prellen als Benutzeraktion gewertet. Und 
das war ja eigentlich Sinn der Übung, das genau das nicht passiert.

> - immerhin flackert jetzt ja nichts mehr und bei jedem tastendruck ob
> kurz oder lang zählt er eins nach oben

Aber du kannst dein Programm nicht mehr erweitern ohne ständig auf die 
Anzeige Rücksicht nehmen zu müssen!

Eine Holzplatte mit 4 Holzrädern auf Schrauben an den 4 Ecken ist auch 
eine Plattform die rollen kann und auf der man etwas transportieren kann 
(solange es nicht zu schwer ist). Aber von dort weg, bis zu einem 
vernünftigen Transportmittel ist es noch ein weiter Weg. Du hast 
momentan die Grundplatte mit den 4 Rädern drann. Jetzt geht es darum, 
daraus eine richtige Transportplattform zu bauen. Und dazu gehört, dass 
der Benutzer nicht mehr ständig einen Schraubenzieher mit haben muss um 
die Schrauben neu festzuziehen, sondern dass die Räder auf vernünftige 
Achsen gesetzt und gelagert werden.

Solange dein Programm nicht regelmässig die Werte ausgibt, wird auch die 
Anzeige nicht aufgebaut.
Du hast jetzt 2 Möglichkeiten: Entweder du spickst dein Programm an 
allen Ecken und Enden mit Aufrufen deiner Ausgabefunktion, oder du baust 
einen Automatismus, der in regelmässigen Abständen ganz von alleine dein 
Programm unterbricht und für die Anzeige sorgt.

Was wohl wird dir lieber sein?
(Hinweis: In der Programmierung ist man gerne 'faul'. Faul in dem Sinne, 
dass man sich beim Arbeiten an möglichst wenige Dinge erinnern und 
berücksichtigen muss. Ein geforderter regelmässig Aufruf, den ich selber 
Programmieren muss, ist etwas an das ich mich erinnern muss)

Was du hast, um ein anderes Beispiel zu gebrauchen, ist ein Wecker der 
zwar morgens um halb 7 klingeln kann und dessen Zeiger sich auch richtig 
bewegen. Aber du musst händisch das Uhrwerk jede Sekunde betätigen, 
damit die Uhr auch tickt. Was du brauchst ist ein Uhrwerk, welches das 
Ticken von alleine macht.


> Dann werd ich mich wohl nochmal in die Sache mit dem ISR einlesen
> müssen.

Darauf läuft es hinaus.
Und so schwer ist das nicht.

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.