Hallo,
ich möchte einen CTC Timer auf meinem Mega32 laufen lassen. So weit so
gut, auf einem Mega8 habe ich das schon mehrfach ohne Probleme
hinbekommen. Ich möchte diese Art Timer mit dem TCNT und wo ich OCR
angeben kann.
1 | //Variable für die Zeit des Timers
| 2 | int millisekunden;
| 3 | int sekunde;
| 4 | int minute;
| 5 | int stunde;
| 6 |
| 7 | // Timer ISR
| 8 | SIGNAL (TIMER1_COMPA_vect)
| 9 | {
| 10 | TCNT2 = 0;
| 11 | millisekunden++;
| 12 | if(millisekunden == 1000)
| 13 | {
| 14 | sekunde++;
| 15 | millisekunden = 0;
| 16 | if(sekunde == 60)
| 17 | {
| 18 | minute++;
| 19 | sekunde = 0;
| 20 | }
| 21 | if(minute == 60)
| 22 | {
| 23 | stunde++;
| 24 | minute = 0;
| 25 | }
| 26 | if(stunde == 24)
| 27 | {
| 28 | stunde = 0;
| 29 | }
| 30 | }
| 31 | }
| 32 | // Timer ISR ende
| 33 |
| 34 | // Timer
| 35 | TCCR1A = 1<<WGM12;
| 36 | TCCR1B = (1<<WGM12) | (1<<CS12);
| 37 | OCR1A = 27;
| 38 | TIMSK |= 1<<OCIE1A;
| 39 | sei();
| 40 | // Timer ende
|
Mit dieser einstellung läuft der Timer so "fast" im Sekundenbereich,
also die variable sekunde passt "fast", bei 10 Sekunden ist der Timer
bei 13 Sekunden gerne würde ich das ganze auch "voll" berechnen
allerdings finde ich die Formel dazu nicht mehr. Und durch diese
"bruchansicht" blicke ich nicht durch.
Zum ADC 1 | // ADC
| 2 | void ADC_Init(void) {
| 3 |
| 4 | uint16_t result;
| 5 | ADCSRA = (1<<ADPS1) | (1<<ADPS0);
| 6 | ADCSRA |= (1<<ADEN);
| 7 |
| 8 | ADCSRA |= (1<<ADSC);
| 9 | while (ADCSRA & (1<<ADSC) ) {}
| 10 | result = ADCW;
| 11 | }
| 12 |
| 13 | uint16_t ADC_Read( uint8_t channel )
| 14 | {
| 15 | ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
| 16 | ADCSRA |= (1<<ADSC);
| 17 | while (ADCSRA & (1<<ADSC) ) {}
| 18 | return ADCW;
| 19 | }
| 20 |
| 21 | // ADC Ende
|
Was muss ich hier ändern das ich es "andersherum" habe? Also ich werte
einen Fotowiderstand (GND) aus. Wie kriege ich es hin das bei Dunkel 0
und bei Hell 1024 als Wert da ist? Derzeit habe ich bei Dunkel 1024 und
bei Hell 0.
Dann noch zu den Fuses. Ich nutze dafür den Fusecalc. Aber was hat es
mit der "startzeit" auf sich? Also dieses 1K CK + 0ms oder 1K CK + 4ms
usw?
Auchso, der Mega32 hat einen externen 8 MHz Quarz.
Ich danke für hilfen.
Ohne im Datenblatt nachgesehen zu haben, kann ich dir auch so sagen,
dass hier
> TCCR1A = 1<<WGM12;
> TCCR1B = (1<<WGM12) | (1<<CS12);
was nicht stimmen kann. Denn WGM12 kann nicht gleichzeitig im TCCR1A und
im TCCR1B sein. Eines der beiden MUSS falsch sein.
> das ganze auch "voll" berechnen
> allerdings finde ich die Formel dazu nicht mehr.
Lies dir das hier durch
FAQ: Timer
dann brauchst du keine Formel wiederfinden, weil du mit 3 mal scharf
nachdenken mit dem Dreisatz und abzählen an den 10 Fingern von alleine
und völlig zwanglos auf die entsprechenden Zahlen kommst.
Tobias N. schrieb:
> Was muss ich hier ändern das ich es "andersherum" habe? Also ich werte
> einen Fotowiderstand (GND) aus. Wie kriege ich es hin das bei Dunkel 0
> und bei Hell 1024 als Wert da ist? Derzeit habe ich bei Dunkel 1024 und
> bei Hell 0.
Das Ergebnis vom ADC von 1024 abziehen?
> Dann noch zu den Fuses. Ich nutze dafür den Fusecalc. Aber was hat es
> mit der "startzeit" auf sich? Also dieses 1K CK + 0ms oder 1K CK + 4ms
> usw?
Das ist einfach nur die Zeit, die die Elektronik im µC dem Rest Zeit
gibt um sich zu stabilisieren. Zb steigt ja die Versorgungsspannung
nicht in 0-Zeit von 0 auf +5V. Oder der Quarz schwingt auch nicht von
der ersten Nanosekunde an mit der vorgegebenen Frequenz.
Karl Heinz Buchegger schrieb:
> Tobias N. schrieb:
>
>> Was muss ich hier ändern das ich es "andersherum" habe? Also ich werte
>> einen Fotowiderstand (GND) aus. Wie kriege ich es hin das bei Dunkel 0
>> und bei Hell 1024 als Wert da ist? Derzeit habe ich bei Dunkel 1024 und
>> bei Hell 0.
>
> Das Ergebnis vom ADC von 1024 abziehen?
naja, dann habe ich bei einem wert von 0 aber dann ein minus 1024 wert.
ich dachte halt eher daran das man irgendwelche register "tauscht" so
das der adc dann halt andersherum also z.b. nicht von 0 - 1024 geht
sondern von 1024 zu 0. in meinem fall also wäre dann bei gnd der wert
1024 und bei VCC dann der wert 0.
>> Dann noch zu den Fuses. Ich nutze dafür den Fusecalc. Aber was hat es
>> mit der "startzeit" auf sich? Also dieses 1K CK + 0ms oder 1K CK + 4ms
>> usw?
>
> Das ist einfach nur die Zeit, die die Elektronik im µC dem Rest Zeit
> gibt um sich zu stabilisieren. Zb steigt ja die Versorgungsspannung
> nicht in 0-Zeit von 0 auf +5V. Oder der Quarz schwingt auch nicht von
> der ersten Nanosekunde an mit der vorgegebenen Frequenz.
ok, danke für die erklärung
Tobias N. schrieb:
> Karl Heinz Buchegger schrieb:
>> Tobias N. schrieb:
>>
>>> Was muss ich hier ändern das ich es "andersherum" habe? Also ich werte
>>> einen Fotowiderstand (GND) aus. Wie kriege ich es hin das bei Dunkel 0
>>> und bei Hell 1024 als Wert da ist? Derzeit habe ich bei Dunkel 1024 und
>>> bei Hell 0.
>>
>> Das Ergebnis vom ADC von 1024 abziehen?
>
> naja, dann habe ich bei einem wert von 0 aber dann ein minus 1024 wert.
du sollst nicht 1024 vom Ergebnis abziehen, sondern das Ergebnis von
1024!
Anstatt
result = ADC;
dann eben
result = 1024 - ADC;
> ich dachte halt eher daran das man irgendwelche register "tauscht" so
> das der adc dann halt andersherum also z.b. nicht von 0 - 1024 geht
> sondern von 1024 zu 0. in meinem fall also wäre dann bei gnd der wert
> 1024 und bei VCC dann der wert 0.
manchmal kann die Welt ganz einfach sein und man rechnet einfach ein
wenig.
Wenn dein Maximalwert 100 ist, und du einen Wert von 80 hast, welches
ist dann der 'Gegenwert'. Wieviele fehlen dann noch auf 100?
Genau 100 - 80 -> 20
Anstelle von 80 lautet dein Ergebnis dann eben 20 und alles dreht sich
um. Je höher dein Originalwert ist, desto kleiner fällt dein
korrigierter Wert aus. Je kleiner dein Originalwert, desto jöher fällt
dein korrigierter Wert aus.
Du kannst natürlich auch LDR und Widerstand tauschen, aber einfach im
Programm zu korrigieren dürfte die deutlich einfachere Variante sein.
so, ich habe das jetzt mal abgeändert
1 | // Timer
| 2 | TCCR1B = (1<<WGM12) | (1<<CS12);
| 3 | OCR1A = 27; //64 Überläufe/sek.
| 4 | TIMSK |= 1<<OCIE1A; //Int Enable //start position
| 5 | sei();
| 6 | // Timer ende
|
aber immernoch stimmt die zeit nicht korrekt. wo wie was brechne ich
nun um auf 1 sek zu kommen oder 100ms oder sowas aber halt einen guten
wert aus dem man dann halt sekunden machen kann?
Hier zb ist dazu etwas geschrieben
FAQ: Timer
Ausgangspunkt ist die Taktfrequenz.
Du hast einen Vorteiler von 256 gewählt.
Dann rechnen wir mal ein bischen.
8000000 / 256 = 31250
Wenn du also sonst nichts tust, dann würde dein Timer in 1 Sekunde von 0
bis 31249 zählen.
Na das wäre ja schon mal ein Wert, mit dem du arbeiten kannst.
Benutzt du den CTC Modus und schreibst die 31249 ins OCR1A, dann wird
die zugehörige Compare Match ISR im Abstand von 1 Sekunde aufgerufen.
31250, da bietet sich schon fast von alleine eine Division durch 10 an.
lässt du den Timer nur 3125 Takte abzählen, dann kriegst du ISR Aufrufe
im Abstand von 0.1 Sekunden. In dem gewünschten Fall müsstest du also
3124 ins OCR1A schreiben. Oder du suchst dir eben einen anderen Teiler,
der die 31250 möglichst ganzzahlig teilt. Oder du benutzt einen anderen
Vorteiler um erst mal auf eine andere Zählbasis zu kommen. Da steht dir
jetzt Tüt und Tor offen.
Ganz exakt werden die 1 Sekunde allerdings auch nicht sein. Denn auf
deinem Quarz steht zwar 8Mhz drauf, aber der schwingt nicht mit exakt
8000000Hz sondern etwas mehr oder weniger. Nicht viel, aber doch. Auf
lange Sicht gesehen, wirst du also eine Abweichung feststellen. Die
bewegt sich aber im einstelligen Sekundenbereich pro Tag. Und: man kann
sie korrigieren.
Ah, ok, soweit verstanden. Würde ich das ganze dann durch 1000 teilen
wäre ich im ms bereich. Soweit alles klar.
Für die "genaue" Sekunde braucht man dann so einen Uhrenquarz, korrekt?
Jetzt läuft das zwar so wie ich das will aber alle 5 sekunden steht die
zeit für 1 sek. also
tick - tick - tick - tick - tick - kein tick - tick - tick - tick
was kann das sein? ok also müsste man mal "zählen" wieviel sekunden in
24h "versatz" und dann das ganze subtrahieren um die "genaue" zeit zu
kriegen, oder?
Tobias N. schrieb:
> Jetzt läuft das zwar so wie ich das will aber alle 5 sekunden steht die
> zeit für 1 sek. also
>
> tick - tick - tick - tick - tick - kein tick - tick - tick - tick
>
> was kann das sein?
Tja. Ich kann dein Programm nicht sehen. Das kannst momentan nur du.
> ok also müsste man mal "zählen" wieviel sekunden in 24h
> "versatz" und dann das ganze subtrahieren um die "genaue"
> zeit zu kriegen, oder?
Du meinst wegen der 8Mhz?
Im Prinzip ja. Allerdings gehen sich dann die Zahlen meistens nicht mehr
so schön aus, wie jetzt :-)
Such mal im Wiki nach "die genaue Sekunde" oder so ähnlich. Da gibts
einen Artikel drüber. Die Wiki-Suche müsste ihn mit dem Suchbegriff
eigentlich finden.
1 | #include <avr/io.h>
| 2 | #include <avr/interrupt.h>
| 3 | #include <util/delay.h>
| 4 | #include <stdio.h>
| 5 | #include <stdint.h>
| 6 | #include <avr/eeprom.h>
| 7 |
| 8 | // LCD
| 9 | #include "mylcd.h"
| 10 | #include "small_font.h"
| 11 | #include "mega.h"
| 12 | #include "image_load.h"
| 13 | // Thermometer
| 14 | #include "ow.h"
| 15 |
| 16 | //Variable für die Zeit des Timers
| 17 | int millisekunden;
| 18 | int sekunde;
| 19 | int minute;
| 20 | int stunde;
| 21 |
| 22 | // ADC
| 23 | void ADC_Init(void) {
| 24 |
| 25 | uint16_t result;
| 26 | ADCSRA = (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
| 27 | ADCSRA |= (1<<ADEN); // ADC aktivieren
| 28 |
| 29 | ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
| 30 | while (ADCSRA & (1<<ADSC) ) { // auf Abschluss der Konvertierung warten
| 31 | }
| 32 | result = ADCW;
| 33 | }
| 34 |
| 35 | uint16_t ADC_Read( uint8_t channel )
| 36 | {
| 37 | ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
| 38 | ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
| 39 | while (ADCSRA & (1<<ADSC) ) { // auf Abschluss der Konvertierung warten
| 40 | }
| 41 | return ADCW; // ADC auslesen und zurückgeben
| 42 | }
| 43 |
| 44 | // ADC Ende
| 45 |
| 46 | // Timer ISR
| 47 | SIGNAL (TIMER1_COMPA_vect)
| 48 | {
| 49 | millisekunden++;
| 50 | if(millisekunden == 1000)
| 51 | {
| 52 | sekunde++;
| 53 | millisekunden = 0;
| 54 | if(sekunde == 60)
| 55 | {
| 56 | minute++;
| 57 | sekunde = 00;
| 58 | }
| 59 | if(minute == 60)
| 60 | {
| 61 | stunde++;
| 62 | minute = 00;
| 63 | }
| 64 | if(stunde == 24)
| 65 | {
| 66 | stunde = 00;
| 67 | }
| 68 | }
| 69 | }
| 70 | // Timer ISR ende
| 71 |
| 72 | // EEPROM Start
| 73 | uint8_t eeminute EEMEM = 0;
| 74 | // EEPROM Stop
| 75 |
| 76 | int main(void)
| 77 | {
| 78 |
| 79 | DDRD |= (1<<PD4);
| 80 |
| 81 | PORTD |= (1<<PD4);
| 82 |
| 83 | // Timer
| 84 | TCCR1B = (1<<WGM12) | (1<<CS12);
| 85 | OCR1A = 31; //64 Überläufe/sek.
| 86 | TIMSK |= 1<<OCIE1A; //Int Enable //start position
| 87 | sei();
| 88 | // Timer ende
| 89 |
| 90 | //init lcd
| 91 | lcd_init();
| 92 | lcd_clear();
| 93 |
| 94 | // Temp variablen
| 95 | char Buffer[20];
| 96 | char temp = 0;
| 97 | char temp2;
| 98 |
| 99 | // ADC
| 100 | uint16_t adcval;
| 101 | ADC_Init();
| 102 |
| 103 | lcd_draw_fullscreen_bmp(img);
| 104 | _delay_ms(4000);
| 105 | lcd_clear();
| 106 | while(1)
| 107 | {
| 108 | // tests
| 109 |
| 110 | temp = Read_Skip_Temp();
| 111 | temp2 = temp;
| 112 |
| 113 | lcd_set_cursor(10,LINE3);
| 114 | lcd_puts(small_font, "Temperatur: ");
| 115 |
| 116 | sprintf( Buffer, "%+03d.%1d", temp/2, ( temp%2) * 5 );
| 117 | lcd_puts(small_font, Buffer);
| 118 |
| 119 | adcval = ADC_Read(1);
| 120 |
| 121 | itoa( adcval, Buffer, 10 );
| 122 | lcd_set_cursor(10,LINE5);
| 123 | lcd_puts(small_font, Buffer);
| 124 |
| 125 | itoa( sekunde, Buffer, 10 );
| 126 | lcd_set_cursor(10,LINE7);
| 127 | lcd_puts(small_font, Buffer);
| 128 |
| 129 | lcd_set_cursor(20,LINE7);
| 130 | lcd_puts(small_font, ":");
| 131 |
| 132 | itoa( minute, Buffer, 10 );
| 133 | lcd_set_cursor(30,LINE7);
| 134 | lcd_puts(small_font, Buffer);
| 135 | }
| 136 | }
|
> int sekunde;
> int minute;
> int stunde;
zumindest die 3 müssen volatile sein und wenn du zu deinem µC nett bist,
dann jagst du ihn nicht sinnloser weise in 16 Bit Arithmetik rein, wo es
8 Bit auch tun
volatile uint8_t sekunde;
.....
Den Rest seh ich noch durch. Das ist mir nur als erstes aufgefallen.
Wirf mal alles raus, was du nicht notwendigerweise für deine Uhr
brauchst.
Diese Temperatur, was steckt da dahinter?
Da messe ich einen DS18S20 aus. Das Display soll in den Aquarienschrank
eingebaut werden.
Mit einem Fotowiderstand wird die Helligkeit am Aquarium gemessen. Ist
es Dunkel (meistens Abends) dann soll das Display selbst ausgeschaltet
werden.
Mit dem DS18S20 messe ich die Wassertemperatur.
Die Uhr benötige ich für eine Zeitschaltuhr. Hiermit will ich unter
anderem die Beleuchtung und die Sauerstoffpumpe schalten.
Ich suche auch noch nach Sensoren die den pH und CO2 gehalt messen
können.
Über 3 Tasten soll dann noch alles eingestellt werden können.
und während der DS ausgelesen wird, werden die Interrupts gesperrt?
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|