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!
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.
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
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?
Hallo Manfred , dann solltest Du dir mal die LED Refreshfrequenz ausrechnen. Ich finde 7,6Hz doch etwas langsam.
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
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
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.
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 !
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 :)
Aja, was ist denn fürs Menschliche Aue noch flimmerfrei? 60Hz?
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
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
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
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?
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)
Ü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.
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.
>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?
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.
Hi, ich schreibe nur Timer 0 zwei mal initialisiert, weist Du welcher ISR noch angesprungen wird ?
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?
Hallo Manfred, welchen Atmel µC verwendest Du? Dann schau mal ins Datenbatt unter TimerN/CounterN nach, und was steht da?
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?
Ä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?
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.
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
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.
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
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.
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.
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
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.
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
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
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
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
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
Ist bei ATtiny2313 laut Datenblatt genau ident. CS00 und CS01 auf 1 = clk/64 Also wieso 3?
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
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?
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 :-)
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.