Forum: Mikrocontroller und Digitale Elektronik 7-Segment Multiplexing mittels ATmega


von Manfred W. (Gast)


Lesenswert?

Ich möchte gerne eine Multiplexing Ansteuerung für vier 7-Segment 
Anzeigen mittels ATmega zusammenbaun.
Was nimmt man da pauschal für Bauteile? Gibt es da Standardrezept?
Also speziel jetzt um die LED's der Segmentanzeige zu treiben.

Ist der ULN2803 eine gute Wahl? Oder ULN2003? Oder ganz was anderes?

ist dieser Aufbau hier grundsätzlich in Ordnung: 
http://codeandlife.com/2012/02/24/7-segment-multiplexing-with-uln2003-pnp-transistors/

danke!

von Georg G. (df2au)


Lesenswert?

Im Forum gibt es etwa 1001 Threads zu diesem Thema. Auch im AVR Tutorial 
und der Codesammlung sind viele Beispiele zu lesen. Bitte benutze die 
Suchfunktion.

von m.n. (Gast)


Lesenswert?

Bevor Du irgendetwas falsch machst, zeige ich Dir lieber meine Schaltung 
:-)
Beitrag "Frequenz, Drehzahl, 4x7-Segment LED, Multiplex-Betrieb"
Oder allegemein für 7-Segmentanzeigen, insbesondere mehrstellige mit 
13mm LED. http://www.mino-elektronik.de/7-Segment-Variationen/LCD.htm

von Manfred W. (Gast)


Lesenswert?

schönen dank, ich habe mir jetzt allerdings mal ein einfaches Beispiel 
aus dem Netz gesucht und für einen ATTiny 2313 angepasst.

Der AVR wird mit 8MHz betrieben.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay_basic.h>
4
5
#define SEVEN_SEGMENT_PORT    PORTD
6
#define SEVEN_SEGMENT_DDR    DDRD
7
8
volatile uint8_t digits[3];
9
10
void SevenSegment(uint8_t n,uint8_t dp)
11
{
12
  if(n<10)
13
  {
14
    switch (n)
15
    {
16
      case 0:           //.gfedcba
17
        SEVEN_SEGMENT_PORT = 0b00111111;
18
      break;
19
20
      case 1:           //.gfedcba
21
        SEVEN_SEGMENT_PORT = 0b00000110;
22
      break;
23
24
      case 2:           //.gfedcba
25
        SEVEN_SEGMENT_PORT = 0b01011011;
26
      break;
27
28
      case 3:           //.gfedcba
29
        SEVEN_SEGMENT_PORT = 0b01001111;
30
      break;
31
32
      case 4:           //.gfedcba
33
        SEVEN_SEGMENT_PORT = 0b01100110;
34
      break;
35
36
      case 5:           //.gfedcba
37
        SEVEN_SEGMENT_PORT = 0b01101101;
38
      break;
39
40
      case 6:           //.gfedcba
41
        SEVEN_SEGMENT_PORT = 0b01111101;
42
      break;
43
44
      case 7:           //.gfedcba
45
        SEVEN_SEGMENT_PORT = 0b00000111;
46
      break;
47
48
      case 8:           //.gfedcba
49
        SEVEN_SEGMENT_PORT = 0b01111111;
50
      break;
51
52
      case 9:           //.gfedcba
53
        SEVEN_SEGMENT_PORT = 0b01101111;
54
      break;
55
    }
56
    if(dp)
57
    {
58
      SEVEN_SEGMENT_PORT |= 0b10000000;
59
    }
60
  }
61
  else
62
  {
63
    SEVEN_SEGMENT_PORT = 0b11111101;
64
  }
65
}
66
67
void Wait()
68
{
69
  uint8_t i;
70
  for (i=0;i<10;i++)
71
  {
72
    _delay_loop_2(0);
73
  }
74
}
75
76
void Print(uint16_t num)
77
{
78
  uint8_t i=0;
79
  uint8_t j;
80
81
  if (num>9999) return;
82
83
  while (num)
84
  {
85
    digits[i]=num%10;
86
    i++;
87
    num=num/10;
88
  }
89
  for (j=i;j<4;j++) digits[j]=0;
90
}
91
92
int main(void)
93
{
94
  uint16_t i;
95
96
  // Prescaler = FCPU/1024
97
  TCCR0B |= (1<<CS02)|(1<<CS00);
98
99
  //Enable Overflow Interrupt Enable
100
  TIMSK |= (1<<TOIE0);
101
102
  //Initialize Counter
103
  TCNT0=0;
104
105
  //Port B[3,2,1,0] as out put
106
  DDRB|=0b00001111;
107
108
  PORTB=0b00000001;
109
110
  //Port D
111
  SEVEN_SEGMENT_DDR=0XFF;
112
113
  //Turn off all segments
114
  SEVEN_SEGMENT_PORT=0X00;
115
116
  //Enable Global Interrupts
117
  sei();
118
119
  while(1)
120
  {
121
    for (i=0;i<10000;i++)
122
    {
123
      Print(i);
124
      Wait();
125
    }
126
  }
127
}
128
129
ISR(TIMER0_OVF_vect)
130
{
131
  static uint8_t i=0;
132
  if (i==3)
133
  {
134
    i=0;
135
  }
136
  else
137
  {
138
    i++;
139
  }
140
  PORTB &= (0b11110000);
141
  PORTB |= (1<<i);
142
  SevenSegment(digits[i],0);
143
}

Es zählt zwar, soweit ich das beurteilen kann, aber es flackert verdammt 
häftig.
Sind 8MHz dafür einfach zu langsam oder woran könnte das liegen?

von Uwe S. (de0508)


Lesenswert?

Hallo Manfred ,

dann solltest Du dir mal die LED Refreshfrequenz ausrechnen.
Ich finde 7,6Hz doch etwas langsam.

von Karl H. (kbuchegg)


Lesenswert?

Naja,

Was erwartetst du bei
1
// Prescaler = FCPU/1024


8000000 / 1024 = 7812
7812 / 256 = 30

30/4 = 7.5

7.5Hz flackert eben.

Lös doch mal die 'Handbremse'!

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Und PS:

Deine Funktion 'SevenSegment' kann man auch durch ein Array ersetzen.
1
uint8_t digitPattern[] = { 0b00111111,
2
                           0b00000110,
3
                           0b01011011,
4
                           0b01001111,
5
                           0b01100110,
6
                           0b01101101,
7
                           0b01111101,
8
                           0b00000111,
9
                           0b01111111,
10
                           0b01101111,
11
                         };
12
13
volatile uint8_t digits[3];
14
....

was dann gleich auch noch den Funktionsaufruf aus der ISR entfernt und 
den GCC nicht dazu zwingt, dem Tiny unötige Mehraufgabe aufzubrummen.

macht man dann auch noch die Ausgaben in der richtigen Reihenfolge ...
1
ISR(TIMER0_OVF_vect)
2
{
3
  static uint8_t i=0;
4
5
  PORTB &= (0b11110000);        // erst mal alles aus!
6
                                // das schieb ich mal an den Anfang der ISR
7
                                // nur für den Fall, dass irgenwo kleinere
8
                                // Kapazitäten ein winziges Nachleuchten
9
                                // der LED nach dem Abschalten zur Folge haben
10
11
  if (i==3)                     // denn während sich das abbaut, kann der Tiny
12
  {                             // in der Zwischenzeit bestimmen, welches die
13
    i=0;                        // nächste Stelle ist. Quasi ein
14
  }                             // Multitasking des Tiny mit den LED :-)
15
  else
16
  {
17
    i++;
18
  }
19
                                // dann können die LEDs auf das neue Muster
20
                                // umgeschaltet werden.
21
  SEVEN_SEGMENT_PORT = digitPattern[ digits[i] ]; 
22
                                // das neue Muster liegt zwar jetzt an,
23
                                // leuchtet aber noch nicht
24
                                // Daher jetzt die LED endgültig mit dem
25
                                // neuen Muster einschalten
26
  PORTB |= (1<<i);
27
}
... dann ist auch gleich noch das sog. Ghosting eliminiert.

: Bearbeitet durch User
von Manfred W. (Gast)


Lesenswert?

Danke dir Karl-Heinz!

Gibt's da sowas wie einen Rechner dafür?
Ich habe jetzt mal mit den Werten

TCCR0B |= (1<<CS01) | (1<<CS00);
TCNT0=131;

ins blaue geraten.

Damit läufts perfekt.
Die Frage ist nur ob das nicht zu viel ist.

von Uwe S. (de0508)


Lesenswert?

Hallo Manfred ,

da das nennt sich Datenblatt lesen.

Dort stehen die Formeln !

und Was soll das bewirken ?

TCCR0B |= (1<<CS01) | (1<<CS00);
TCNT0=131;

Programmieren hat etwas mit wissen zu tun und nicht mit raten !

von Manfred W. (Gast)


Lesenswert?

Ich hab mir dafür diesen Rechner hier zu gute gezogen: 
http://evolutec.publicmsg.de/index.php?menu=software&content=prescalertools

Ist dann wohl auch nicht das wahre :)

von Manfred W. (Gast)


Lesenswert?

Aja, was ist denn fürs Menschliche Aue noch flimmerfrei? 60Hz?

von Karl H. (kbuchegg)


Lesenswert?

Manfred W. schrieb:
> Danke dir Karl-Heinz!
>
> Gibt's da sowas wie einen Rechner dafür?

Wozu brauchst du da einen Rechner?
Einfach ein wenig nachdenken.

Der Timer wird vom Systemtakt angesteuert.
Wenn du einen Vorteiler von 1 hättest, dann würde der in 1 Sekunde bis 
8000000 zählen (ich ignorier mal, dass der nur bis 255 zählen kann)
Da du aber einen Vorteiler von 1024 hast, zählt er daher in 1 Sekunde 
wie weit?

Genau. Bis 8000000 / 1024 gleich 7812

Jetzt kann der Timer aber nicht bis 7812 zählen. Der ist ja nur 8 Bit 
gross kann nur bis 255 zählen (256 Zählschritte). Danach gibt es einen 
Overflow und er fängt wieder bei 0 an. Genau auf diese Overflows bist du 
aber aus. Denn genau bei jedem Overflow wird der Interrupt ausgelöst.
Wenn der Timer also theoretisch in 1 Sekunde bis 7812 zählen möchte, es 
aber wegen der Overflow nach jeweils 256 Zählschritten nicht kann, 
wieviele Oberflows sind das dann daher in 1 Sekunde?

genau. Das sind 7812 / 256 gleich 30 Overflows (und ein paar 
Zerquetschte, die ich mal grosszügig ignoriere)

D.h. pro Sekunde hast du 30 Overflows. Bei jedem Overflow wird eine 
andere Anzeige eingeschaltet. Du hast 4 Anzeigen. Wie oft kommt daher 
jede Anzeige pro Sekunde drann?

Genau. 30 / 4 gleich 7.5 mal


Wenn dir klar ist, was da vor sich geht, dann hast du dir die Zahlen so 
schneller hergeleitet, als du einen "Rechner" rausgekramt hast oder dir 
die Formeln im Datenblatt gesucht hast.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Manfred W. schrieb:

> ins blaue geraten.

rechne es dir einfach aus. Oder warum denkst du hab ich dir den 
Rechengang aufgeschrieben?

Welcher vorteiler ist das
1
  TCCR0B |= (1<<CS01) | (1<<CS00);
und mit dem wird gerechnet.

Sei nicht so faul! Das kann man alles verstehen und rechnen.

: Bearbeitet durch User
von Uwe S. (de0508)


Angehängte Dateien:

Lesenswert?

Hallo Manfred,

ich sehe 100Hz noch.

In meinem aktuellen 4-fach LED Multiplex verwende ich deshalb 250Hz LED 
Anzeigefrequenz.

Hier ist noch ein Bild vom Testbetrieb.

Karl-Heinz kennt die Schaltung schon, LED Kathode Vorwiderstände 270R.

: Bearbeitet durch User
von Manfred W. (Gast)


Lesenswert?

Ok, danke Karl Heinz für die ausführliche Erklärung. Das hab ich 
verstanden.
Ich verwende jetzt mal einen Teiler von 64. Das ergibt dann einen Takt 
von 122 Hz.
Ich belasse das mal dabei. Flackern kann ich da mit meinem Auge nicht 
mehr erkennen.

jetzt hab ich noch eine Frage, ich möchte gerne das der Zähler bei den 
Segmenten mit führender Null zählt also wie bei einem Bandzählwerk.

0001
0002
  |
  |
0010
0011

Wie stelle ich es an das die Stellen von rechts nach links rücken?

von Karl H. (kbuchegg)


Lesenswert?

Manfred W. schrieb:

> Wie stelle ich es an das die Stellen von rechts nach links rücken?

Da brauchst du überhaupt nichts rücken.
Die Print Funktion generiert doch ohnehin führende 0-en.

Also einfach einen Zähler als uint16_t Variable definieren und die 
erhöhen oder erniedrigen (je nachdem was der Zähler tun soll)

von Karl H. (kbuchegg)


Lesenswert?

Übrigens (und da hab ich auch geschlafen)

Das hier
1
volatile uint8_t digits[3];

muss natürlich ein Array der Länge 4 sein
1
volatile uint8_t digits[4];

sind ja schliesslich 4 Anzeigen und dementsprechend auch 4 digits.

von Manfred W. (Gast)


Lesenswert?

hm, dann stimmt die Verkabelung nicht?

Denn der zählt von links nach rechts.

Erstes Segment zählt bis 9 dann erhöht sich das zweite Segment. Wenn das 
zweite Segment über 9 kommt erhöht sich das dritte Segment. Also von 
links nach rechts.

Die Kathode des ersten Segmentes hängt an PB0
Das zweite an PB1 usw.

von Manfred W. (Gast)


Lesenswert?

So sieht das aus: http://youtu.be/VPM_iuTrWUc

von holger (Gast)


Lesenswert?

>Die Kathode des ersten Segmentes hängt an PB0
>Das zweite an PB1 usw.

Dann vertauscht die halt bis es passt.
Da musst du nicht mal die Software für ändern.
Ist das denn so schwer?

von Manfred W. (Gast)


Lesenswert?

ja, hab ich jetzt eh. Passt schon.

von Manfred W. (Gast)


Lesenswert?

Ich habe jetzt noch ein Problem.
Ich möchte in dem Programm jetzt noch zusätzlich eine Auswertung eines 
Drehgebers implementieren. Weil ich denke das die Funktionsweise eines 
mechanischen Zählwerkes entspricht. Anstelle des Drehgebers selbst 
möchte ich am Motor eine Scheibe montieren die dann 2 Lichtschranken 
bedient.

Die Auswertung des Drehgebersbeispiel: 
http://www.mikrocontroller.net/articles/Drehgeber
verwendet aber wieder ein anderes Timing wie mir scheint.
Wie implementiere ich das nun.

Ich hätte das mal so versucht:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
5
#define SEVEN_SEGMENT_PORT    PORTD
6
#define SEVEN_SEGMENT_DDR    DDRD
7
#define ENCODER_A        (PINB & (1 << PB4))
8
#define ENCODER_B        (PINB & (1 << PB5))
9
#define TASTER          (1 << PB6)
10
11
                 // .gfedcba
12
uint8_t digitPattern[] =  {
13
                0b00111111,
14
                0b00000110,
15
                0b01011011,
16
                0b01001111,
17
                0b01100110,
18
                0b01101101,
19
                0b01111101,
20
                0b00000111,
21
                0b01111111,
22
                0b01101111,
23
              };
24
25
volatile uint8_t digits[4];
26
27
volatile int8_t enc_delta;
28
static int8_t last;
29
30
void encode_init( void )
31
{
32
  int8_t neu;
33
34
  neu = 0;
35
  if(ENCODER_A)
36
    neu = 3;
37
  if(ENCODER_B)
38
    neu ^= 1;
39
  last = neu;
40
  enc_delta = 0;
41
42
  TCCR0A = (1<<WGM01);
43
  OCR0A = (uint8_t)(F_CPU / 64.0 * 1e-3 - 0.5);
44
  TCCR0B = (1<<CS01 | 1<<CS00);
45
  TIMSK = (1<<OCIE0A);
46
}
47
48
void Wait()
49
{
50
  uint8_t i;
51
  for (i=0;i<10;i++)
52
  {
53
    _delay_ms(2);
54
  }
55
}
56
57
void Print(uint16_t num)
58
{
59
  uint8_t i=0;
60
  uint8_t j;
61
62
  if (num>9999) return;
63
64
  while (num)
65
  {
66
    digits[i]=num%10;
67
    i++;
68
    num=num/10;
69
  }
70
  for (j=i;j<4;j++) digits[j]=0;
71
}
72
73
ISR(TIMER0_OVF_vect)
74
{
75
  static uint8_t i=0;
76
77
  PORTB &= (0b11110000);
78
  if (i==3)
79
  {
80
    i=0;
81
  }
82
  else
83
  {
84
    i++;
85
  }
86
  SEVEN_SEGMENT_PORT = digitPattern[ digits[i] ]; 
87
  PORTB |= (1<<i);
88
}
89
90
ISR(TIMER0_COMPA_vect)
91
{
92
  int8_t neu, diff;
93
 
94
  neu = 0;
95
  if(ENCODER_A)
96
    neu = 3;
97
  if(ENCODER_B)
98
    neu ^= 1;
99
  diff = last - neu;
100
  if(diff & 1){
101
    last = neu;
102
    enc_delta += (diff & 2) - 1;
103
  }
104
}
105
106
int8_t encode_read1(void)
107
{
108
  int8_t val;
109
 
110
  cli();
111
  val = enc_delta;
112
  enc_delta = 0;
113
  sei();
114
  return val;
115
}
116
117
int main(void)
118
{
119
  int32_t val = 0;
120
121
  TCCR0B |= (1<<CS01) | (1<<CS00);
122
  TIMSK |= (1<<TOIE0);
123
  TCNT0=0;
124
125
  DDRB |= 0b00001111;
126
  PORTB = 0b01110001;
127
128
  SEVEN_SEGMENT_DDR = 0xFF;
129
  SEVEN_SEGMENT_PORT = 0x00;
130
131
  encode_init();
132
  sei();
133
134
  while(1)
135
  {
136
      val += encode_read1();
137
      Print(val);
138
  }
139
}

Aber das spiest sich ja.

von Uwe S. (de0508)


Lesenswert?

Hi,

ich schreibe nur Timer 0 zwei mal initialisiert, weist Du welcher ISR 
noch angesprungen wird ?

von Manfred W. (Gast)


Lesenswert?

Hallo Uwe,

TIMER0, ok. Aber welchen der beiden lasse ich dann weg?
Beim Drehgeber wird der bei jeder Drehbewegung initialisiert.

Welcher ISR außer den beiden?

von Uwe S. (de0508)


Lesenswert?

Hallo Manfred,

welchen Atmel µC verwendest Du?

Dann schau mal ins Datenbatt unter TimerN/CounterN nach, und was steht 
da?

von Uwe S. (de0508)


Lesenswert?

Manfred W. schrieb:
> Beim Drehgeber wird der bei jeder Drehbewegung initialisiert.

Wie soll ich das verstehen?

Ich kenne PaDas Drehencoder Code und kann ihn auch einsetzen, mir 
scheint , dass Dir noch C Grundlagen fehlen.

Also erst den gesamten Code verstehen und dann einbinden.

Ok?

von Manfred W. (Gast)


Lesenswert?

Ähm, Blödsinn. Natürlich nicht bei jeder Drehbewegung.
encode_init() wird ja nur ein mal aufgerufen.

Es ist ein ATtiny2313

Ich hab das ganze jetzt mal zusammengefasst so wie es bei meinem 
Programm aufgerufen wird:
1
  TCCR0A = (1<<WGM01);
2
  OCR0A = (uint8_t)(F_CPU / 64.0 * 1e-3 - 0.5);
3
  TCCR0B = (1<<CS01 | 1<<CS00);
4
  TIMSK = (1<<OCIE0A);
5
6
  TCCR0B |= (1<<CS01) | (1<<CS00);
7
  TIMSK |= (1<<TOIE0);
8
  TCNT0=0;

TCCR0B ... kann ich einen schon mal kübeln.

Bei TIMSK addiert man da einfach den zweiten dazu?

von Manfred W. (Gast)


Lesenswert?

Haa, es läuft wenn ich den
TCCR0A = (1<<WGM01); weglasse.

Also nur:
1
  OCR0A = (uint8_t)(F_CPU / 64.0 * 1e-3 - 0.5);
2
  TCCR0B = (1<<CS01 | 1<<CS00);
3
  TIMSK = (1<<OCIE0A | 1<<TOIE0);

Allerdings in zweier Schritten.

von Uwe S. (de0508)


Lesenswert?

Hallo,

ich wollte Dich auf den zweiten Timer hinweisen.

Was kommt hierbei raus?

TCCR0B = (1<<CS01 | 1<<CS00);

Ich bin für heute raus.

: Bearbeitet durch User
von Manfred W. (Gast)


Lesenswert?

64

Karl Heinz, kannst du mir noch einen Tipp geben wie ich den Punkt der 
Anzeige, also den dp da auch wieder in mein Programm bekomme?
Diese Auswertung ist ja beim Array flöten gegangen.

von Karl H. (kbuchegg)


Lesenswert?

Manfred W. schrieb:
> 64
>
> Karl Heinz, kannst du mir noch einen Tipp geben wie ich den Punkt der
> Anzeige, also den dp da auch wieder in mein Programm bekomme?
> Diese Auswertung ist ja beim Array flöten gegangen.

Na ja.
Indem du ihn setzt bzw. bei der entsprechenden Stelle das Digit 
einschaltest, wenn du ihn brauchst.

Was soll ich dir da jetzt gross für einen Tip geben? Du wirst ja doch 
wohl ein einzelnes Bit an einem Port auf 1 setzen können, wenn es 1 
werden soll.

Wenn beim Multiplexen die 7Segment Anzeige mit der Nummer 0 drann ist, 
dann eben den Punkt noch mit dazu einschalten
1
....
2
  SEVEN_SEGMENT_PORT = digitPattern[ digits[i] ]; 
3
  if( i == 0 )
4
    SEVEN_SEGMENT_PORT |= 0x80;
5
....

oder
1
#define SEVEN_SEGMENT_PORT    PORTD
2
#define SEVEN_SEGMENT_DDR    DDRD
3
4
                 // .gfedcba
5
uint8_t digitPattern[] =  {
6
                0b00111111,
7
                0b00000110,
8
                0b01011011,
9
                0b01001111,
10
                0b01100110,
11
                0b01101101,
12
                0b01111101,
13
                0b00000111,
14
                0b01111111,
15
                0b01101111,
16
              };
17
18
#define DP_DIGIT  7    // der Dezimalpunkt ist am Bit 7 verkabelt
19
20
volatile uint8_t digits[4];
21
22
23
....
24
  SEVEN_SEGMENT_PORT = digitPattern[ digits[i] ]; 
25
  if( i == 0 )
26
    SEVEN_SEGMENT_PORT |= ( 1 << DP_DIGIT );
27
....
dann ist es ein wenig besser organisiert und das Bit, das den 
Dezimalpunkt steuert, findet sich im Code an der Stelle, in der auch der 
Aufbau der anderen Ziffern aus den Segmenten der Anzeige beschrieben 
ist.


(oder eben bei der Anzeige 3, je nachdem ob die Nummerierung der 
Anzeigen von links nach rechts oder von rechts nach links durchläuft).

: Bearbeitet durch User
von Manfred W. (Gast)


Lesenswert?

Bit auf 1 setzen ist kein Problem.
Nur wie teil ich ihm mit das er dieses Bit nur auf dem 1 Segment setzen 
soll wenn ich zb. eine Taste drücke.

von Manfred W. (Gast)


Lesenswert?

auf dem ersten Ziffernsegment meine ich.

von Karl H. (kbuchegg)


Lesenswert?

Na komm.
Denk dir was aus!

Variablen sind schon erfunden. Ein 'if' ist schon erfunden. Vergleiche 
sind schon erfunden.

Ein wenig musst du auch selber was 'erfinden'. Ist ja schliesslich dein 
Projekt. Ganz im Gegenteil: Das 'sich etwas ausdenken' und nachsehen ob 
das funktioniert ist doch der ganze Spass an der Sache.

von Uwe S. (de0508)


Lesenswert?

Guten Morgen Manfred,

Uwe S. schrieb:
> Hallo,
>
> ich wollte Dich auf den zweiten Timer hinweisen.
>
> Was kommt hierbei raus?
>
> TCCR0B = (1<<CS01 | 1<<CS00);

Die Clock Select Bit werden nicht für einen Vorteiler von 64 gesetzt - 
also FALSCH!

Der Ausdruck liefert die Zahl 2 also 0b10 und damit einen Vorteile von 8 
!

Wissen ist hier gefragt nicht raten !

Siehe:

http://de.wikibooks.org/wiki/C-Programmierung:_Liste_der_Operatoren_nach_Priorit%C3%A4t

von Karl H. (kbuchegg)


Lesenswert?

Uwe S. schrieb:

>> Was kommt hierbei raus?
>>
>> TCCR0B = (1<<CS01 | 1<<CS00);
>
> Die Clock Select Bit werden nicht für einen Vorteiler von 64 gesetzt -
> also FALSCH!
>
> Der Ausdruck liefert die Zahl 2 also 0b10

fast. Es ergibt 3

Aber warum so kompliziert. Einfach im Datenblatt nachsehen. Es werden 
offensichtlich im Code die Bits CS01 und CS00 gesetzt. Im Datenblatt 
gibt es beim Timer 0 eine Tabelle, in der man mit den beiden Bits CS01 
bzw. CS00 nachsehen kann, welchem Vorteiler das entspricht. Den 
Zahlenwert, der sich aus den Bits ergibt, braucht man dazu nicht 
wirklich wissen.

von Uwe S. (de0508)


Lesenswert?

Hallo Karl Heinz,

da fehlen noch Klammern - die sehen wir gerne nicht mehr - deshalb nur 
2.

Also eher so wird der Kompiler den Ausdruck verarbeiten:
1
TCCR0B = (1<< (CS01 | 1) <<CS00);

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Uwe S. schrieb:
> Hallo Karl Heinz,
>
> da fehlen noch Klammern - die sehen wir gerne nicht mehr - deshalb nur
> 2.

?
<< hat eine wesentlich höhere Precedence als |
Die Klammern die dir fehlen sind ein optisches Gimmick aber rein 
technisch sind sie in diesem Ausdruck nicht notwendig. Der Ausdruck 
parst auch ohne Klammern genau so, wie er soll.
Ob das schlau ist, die Klammern wegzulassen, steht auf einem anderen 
Blatt. Notwendig sind sie hier aber konkret nicht.

>
> Also eher so wird der Kompiler den Ausdruck verarbeiten:
>
1
TCCR0B = (1<< (CS01 | 1) <<CS00);

Nope.
Das ist kompletter Quatsch.
Schau bitte mal in eine Operator Precedence Table hinein. Da gehts auch 
nicht um 'eher', sondern dafür gibt es exakte Regelungen.


Edit:
Hier ist eine
http://en.cppreference.com/w/c/language/operator_precedence
Operatoren, die weiter oben stehen, binden stärker.

: Bearbeitet durch User
von Manfred W. (Gast)


Lesenswert?

Dann stimmt diese Tabelle hier nicht?

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR

CS00 -> 1
CS01 -> 1
= CPU-Takt / 64

von Karl H. (kbuchegg)


Lesenswert?

Manfred W. schrieb:
> Dann stimmt diese Tabelle hier nicht?
>
> 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR
>
> CS00 -> 1
> CS01 -> 1
> = CPU-Takt / 64

Abgesehen davon, dass sie für den falschen µC-Typ ist, Zitat
1
Der 8-Bit Timer wird z.B bei AT90S2313
stimmt das schon.
Nur gewöhn dir an, dass deine Bibel das Datenblatt zu deinem Prozessor 
ist und nichts anderes! Egal, was du in einem Tutorial liest, du checkst 
es mit dem Datenblatt zu deinem Prozessortyp!

: Bearbeitet durch User
von Ingo S. (schicki)


Lesenswert?

Hallo Manfred,

ich habe das mit einem ganz einfachen BCD-Treiber realisert.

http://www.schwabenplan.com/downloads/d01500.pdf

Die Treiber für 8051 und PIC hätte ich auch.

http://www.schwabenplan.com/downloads/MC-Lehrsystem_Katalog.pdf

Grüße
Ingo

von Manfred W. (Gast)


Lesenswert?

Ist bei ATtiny2313 laut Datenblatt genau ident.
CS00 und CS01 auf 1 = clk/64

Also wieso 3?

von Karl H. (kbuchegg)


Lesenswert?

Uh. bei dir muss man aber wirklich ganz unten anfangen.

8 Bit

Hier sind sie
1
 Bitnummer      7   6   5   4   3   2   1   0
2
              +---+---+---+---+---+---+---+---+
3
 0 oder 1     |   |   |   |   |   |   |   |   |
4
              +---+---+---+---+---+---+---+---+

welche Kombinationen der Bits mit 0-en oder 1-en gibt es und wie werden 
sie sinnvoll durchnummeriert
1
   00000000           0
2
   00000001           1
3
   00000010           2
4
   00000011           3
5
   00000100           4
6
   00000101           5
7
   00000110           6
8
   00000111           7
9
   00001000           8
10
   00001001           9
11
   00001010          10
12
   00001011          11
13
   00001100          12
14
   ....
15
   11111101         253
16
   11111110         254
17
   11111111         255

CS00 ist laut Datenblatt im Byte des Registers das Bit 0
CS01 ist laut Datenblatt im Byte des Registers das Bit 1

Betrachtet man also nur die beiden Bits, dann hat man 1 Byte (das mit 
dem Rest des Registers verodert wird), in dem das Bit 0 und das Bit 1 
gesetzt sind. Und das ist dezimal ausgedrückt welche Zahl (siehe 
Tabelle)?

: Bearbeitet durch User
von Manfred W. (Gast)


Lesenswert?

Binär gerechnet schon klar Karl Heinz, aber Uwe meinte ja:

> TCCR0B = (1<<CS01 | 1<<CS00);

Die Clock Select Bit werden nicht für einen Vorteiler von 64 gesetzt -
also FALSCH!
Der Ausdruck liefert die Zahl 2 also 0b10 und damit einen Vorteile von 8

Das versteh ich jetzt nicht.
Wieso entspricht 2 (oder 3) in diesem Falle dann einen Vorteiler von 8?

von Karl H. (kbuchegg)


Lesenswert?

Manfred W. schrieb:
> Binär gerechnet schon klar Karl Heinz, aber Uwe meinte ja:

Uwe hat sich geirrt.
Wie dir als C Kenner natürlich sofort aufgefallen ist :-)

von Karl H. (kbuchegg)


Lesenswert?

Manfred W. schrieb:

> Wieso entspricht 2 (oder 3) in diesem Falle dann einen Vorteiler von 8?


Weil im Rechner alles einfach nur BIts sind.

Ob du   0000 0011
als 8 Bits auffasst, in denen das Bit 0 und das Bit 1 auf 1 gesetzt ist, 
oder ob du das als die Dezimalzahl 3 auffast eine reine Frage dessen 
ist, welche Sichtweise du haben willst. Dem COmputer ist das egal. Der 
sieht einfach nur 1 Byte in dem die beiden Bits gesetzt sind.

Und wenn du im Datenblatt nachsiehst, dann entspricht das (reduziert auf 
nur die Vorteiler Bits) einem Vorteiler von 64.

: Bearbeitet durch User
von Manfred W. (Gast)


Lesenswert?

Ist denn die Schreibweise nun korrekt?

Mit Klammer, ohne, oder ganz anders?

TCCR0B = (1<<CS01 | 1<<CS00);
TCCR0B = (1<<CS01) | (1<<CS00);
TCCR0B = 1<<CS01^1<<CS00;

???

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.