Forum: Mikrocontroller und Digitale Elektronik ATMega32 Timer, ADC problem und Fuses frage


von Tobias N. (silberkristall)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

> 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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Tobias N. (silberkristall)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Tobias N. (silberkristall)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Tobias N. (silberkristall)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

> 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.

von Tobias N. (silberkristall)


Lesenswert?

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
}

von Karl H. (kbuchegg)


Lesenswert?

> 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.

von Karl H. (kbuchegg)


Lesenswert?

Wirf mal alles raus, was du nicht notwendigerweise für deine Uhr 
brauchst.

Diese Temperatur, was steckt da dahinter?

von Tobias N. (silberkristall)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.