Hi,
ich wollte mir einen RC-Switch bauen.
ganz simpel - dacht ich mir
TINY13:
Int0 an Impulsleitung
PB4 an Schalt-Mosfet
Fuses sind gesetzt auf 4,8Mhz ohne Prescaler
Mein Problem ist jetzt das der Mosfet (bzw die LED) ständig an ist, bzw.
bei einer Sendeweg von ca 30% flackert.
Verstehen kann ich das nicht.
Bei nem Tackt von 4,8MHz und nem 64er Timer-Teiler sollte ca alle
0,013ms der Timer inkremmentiert werden -> bei 1,5ms (mittelstellung)
wären wir bei TCNT0 = 112,5
Und das liegt im bereich von 111 bis 114 wo er eigentlich dicht machen
sollte (PIN 4).
Code:
Wolly2.0 schrieb:> Fuses sind gesetzt auf 4,8Mhz ohne Prescaler
Wo kommen die 4.8Mhz her?
interner RC-Generator?
Dann würde ich nicht davon ausgehen, dass das exakt 4800000 Hz sind.
Ich kenn jetzt den Tiny 13 nicht konkret, aber andere Tinys haben ein
Register OSCAL (Oszillator Calibration), mit dem man den Oszillator
kallibrieren kann.
> bei einer Sendeweg von ca 30% flackert.
Wenn man die Flankenrichtung eines Eingangs umstellt, ist es meistens
eine gute Idee, wenn man gleich danach sicherheitshalber das Interrupt
Flag noch zusätzlich löscht. Nicht dass sich durch das Umstellen selbst
wieder ein Interrupt ergibt.
Aber an deiner Stelle würde ich ehrlich gesagt, die Flankenrichtung gar
nicht umstellen, wenn es sich vermeiden lässt. Wenn dein Tiny das kann,
dann lass ihn bei jeder Flanke (egal ob steigend oder fallend) einen
Interrupt auslösen. Welche Flanke es war kannst du ganz leicht
feststellen, wenn du den Pin einliest und nachsiehst ob er 1 war (dann
muss es ein Übergang 0->1 gewesen sein).
Da valu eine int Variable ist, müsstest du ausserdem atomaren Zugriff
sicherstellen. Es erhebt sich allerdings die Frage, warum value
überhaupt ein int sein muss. Bei einem Wertebereich bis maximal 256
reicht ein uint8_t dicke aus.
Weiters solltest du dir das AVR-GCC-Tutorial reinziehen. In deinem Code
ist so ziemlich alles enthalten, was man heutzutage nicht mehr macht,
wenn man Programme für den WinAVR schreibt. Hol dir im Tutorial
Anregungen, wie du die Dinge besser schreiben kannst.
Wolly2.0 schrieb:> if ((valu > 111) && (valu < 114)) { //grober Bereich Mittelstellung
So grob finde ich das eigentlich nicht. Deine LED geht nur bei den
Werten 112 und 113 aus. Das sind ca. 2,7% vom gesamten Weg.
Karl Heinz Buchegger schrieb:> Dann würde ich nicht davon ausgehen, dass das exakt 4800000 Hz sind.> Ich kenn jetzt den Tiny 13 nicht konkret, aber andere Tinys haben ein> Register OSCAL (Oszillator Calibration), mit dem man den Oszillator> kallibrieren kann.
Und bei 4,8 MHz auch muß:
(aus dem Datenblatt des Tiny13)
There is a separate calibration byte for the internal oscillator in 4.8
MHz
mode of operation but this data is not loaded automatically. The
hardware
always loads the 9.6 MHz calibraiton data during reset. To use separate
calibration data for the oscillator in 4.8 MHz mode the OSCCAL register
must be updated by firmware. The calibration data for 4.8 MHz operation
is
located in the high byte at address 0x01 of the signature area.
> Aber an deiner Stelle würde ich ehrlich gesagt, die Flankenrichtung gar> nicht umstellen, wenn es sich vermeiden lässt.
Ich würde auch den Timer nicht jedesmal stoppen und starten, sondern
einfach bei steigender Flanke auf 0 setzen, oder besser noch sich vorher
und nachher den Wert merken und die Differenz bilden. So läßt sich der
Timer auch für andere Sachen noch nutzen.
Also das mit dem OSCCAL Register wusste ich nicht, dafür schonmal ein
dickes THX.
Und das mit dem Timer nicht mehr starten und stoppen hab ich auch mal
übernommen.
Ändert aber leider nichts an dem Punkt das es nicht geht.
Interessant ist das das Flackern bei 30% jetzt weg ist, jetzt passiert
einfach garnichts mehr.
An der Hardware liegts aber nicht, ich hab hier ein Bascom Programm das
eine Ähnlich aufgabe erledigt und das geht.
Verbesserter Code
sbi(MCUCR,ISC01);sbi(MCUCR,ISC00);//Interrupt an INT0 bei steigender Flanke
26
27
sbi(TCCR0B,CS01);sbi(TCCR0B,CS00);//Timer mit 64er Teiler starten
28
29
sei();//Interrupts an
30
31
while(1){
32
if((valu>110)&&(valu<115)){//grober Bereich Mittelstellung
33
cbi(PORTB,PB4);//PIN 4 aus
34
sbi(PORTB,PB3);//PIN 3 an
35
}else{
36
sbi(PORTB,PB4);//PIN 4 an
37
cbi(PORTB,PB3);//PIN 3 aus
38
}
39
}
40
41
42
return0;
43
}
44
45
46
47
ISR(_VECTOR(1)){//ISR Routine für INT0
48
if(MCUCR&(1<<ISC00)){//Wenn auf steigende Flanke gesetz
49
TCNT0=0;//Timer reseten
50
cbi(MCUCR,ISC00);//Interrupt auf fallende Flanke setzen
51
}else{//Wenn auf fallende Flanke gesetzt
52
valu=TCNT0;//Timerwert übergeben
53
sbi(MCUCR,ISC00);//auf steigende Flanke setzen
54
}
55
}
Und bitte nicht böse sein wegen dem sbi und cbi, ich kann damit einfach
besser als mit den ganzen &= ~ / |= usw. - mach ich warsch dann mehr
Fehler als so, und das sollte ja das Prog auch nich ausbremsen.
Ich kann nicht so recht glauben, dass das Calibration-Byte in der
Signatur tatsächlich 1 ist (wäre ziemlich extrem). Ich denke, du hast
wohl das Datenblatt-Zitat falsch verstanden.
Oja stimmt das volatile hab ich da glatt unterschlagen.
"The calibration data for 4.8 MHz operation
is located in the high byte at address 0x01 of the signature area."
So ganz freie Übersetzung:
Die Kalibrierungseinstellung für 4,8MHz liegt im hohen Byte in mit der
Adresse 0x01
(ich weiß mein Englisch ist Mist)
Ich dachte das das mit
Ok ich hab grad gesehen bei PonyProg gibts ja die Option 'Osc.
Calibration Options'
Da kann man das warsch. setzen
wenn ich dort den wert auslesen lasse kommt da 0x6B (107) raus
Sollte ich da jetzt dann 01 setzen?
bzw im setzen Feld sind sogar 4Bits verfügbar (Maske 0x0000)
Soll ich da jetzt einfach mal 0x0010 reintexten oder mach ich da dann
iwas falsch/kapput?
Wolly2.0 schrieb:> "The calibration data for 4.8 MHz operation> is located in the high byte at address 0x01 of the signature area.">> So ganz freie Übersetzung:> Die Kalibrierungseinstellung für 4,8MHz liegt im hohen Byte in mit der> Adresse 0x01> (ich weiß mein Englisch ist Mist)>> Ich dachte das das mit>
1
>OSCCAL=0x01;
2
>
> zu verstehen ist
Nö.
In der Beschreibung steht "Address" also Adresse. Unter dieser Adresse
(die daher das Byte 0x01 im Bereich der Signatur-Daten kennzeichnet), da
ist der Wert zu finden, der ins OSCCAL Register muss.
Address ist immer die Angabe, wo man einen Wert findet, aber sie ist
nicht selber dieser Wert.
Wolly2.0 schrieb:> Ok ich hab grad gesehen bei PonyProg gibts ja die Option 'Osc.> Calibration Options'>> Da kann man das warsch. setzen> wenn ich dort den wert auslesen lasse kommt da 0x6B (107) raus
107 schaut vernünftig aus. Könnte stimmen. Zumindest ist die Zahl im
erwarteten Wertebereich.
Kann man aber auch einfach ausprobieren.
> Sollte ich da jetzt dann 01 setzen?
No.
Der kommt ins OSCCAL Register.
> iwas falsch/kapput?
kaputt machst du erst mal gar nichts. Das ist nur eine Kalibrierung, mit
der der RC-Schwingkreis "gestimmt" wird.
Schreib dir doch ein Testprogramm:
1
#define F_CPU 4800000UL
2
3
#include"avr/io.h"
4
#include"utils/delay.h"
5
6
intmain()
7
{
8
OSCCAL=107;
9
10
DDRB=(1<<PB4);
11
12
while(1){
13
PORTB|=(1<<PB4);
14
_delay_ms(1000);
15
PORTB&=~(1<<PB4);
16
_delay_ms(1000);
17
}
18
}
an PB4 hängst du eine LED
(Optimizer auf -Os stellen nicht vergessen)
Wenn der µC tatsächlich mit 4.8Mhz läuft, dann stimmen die Wartezeiten,
die der Compiler anhand der F_CPU Vorgabe errechnet hat. Die LED wird
ruhig und konstant 1 Sekunde ein / 1 Sekunde aus sein. Größere
Abweichungen sieht man normalerweise mit freiem Auge sofort, zur Not
einfach eine Uhr mit Sekundenzeiger daneben legen. Kleinere Abweichungen
kannst du leicht feststellen, in dem du zb 60 derartige Zyklen abwartest
und mit einer Uhr stoppst. Wenn die Taktfrequenz stimmt, dann dauern 60
Blinker ziemlich genau 2 Minuten. Noch genauer wirst du es für deine
Zwecke nicht brauchen.
Du kannst auch mal den Gegentest machen und ins OSCCAL Register einen
kleinen Wert (10) oder einen großen Wert (250) laden und dir ansehen,
wie sich das auf das Geblinke auswirkt.
Und wenn die 107 nicht stimmen, dann weißt du dann auch ob du den Wert
vergrößern oder verkleinern musst, um die 60 Blinker auf 2 Minuten zu
bringen.
Wolly2.0 schrieb:> der OSCCAL wert 107 ist aber der standard wert - also für 9,6Mhz> sollte dann also für 4,8MHz 53,5 respektive 53/54 sein oder irre ich> schon wieder
Du irrst.
Beim Umstellen von 9.6Mhz auf 4.8Mhz werden ganze Baugruppen
umgeschaltet. OSCCAL ist nur die Feineinstellung auf die Zielfrequenz.
Die kann (und wird) bei 9.6Mhz ein wenig anders als bei 4.8Mhz sein.
Stell dir das ganze wie bei einem (analogen) Oszilloskop vor.
Mit dem großen Knopf stellst du die Ablenkfrequenz grob ein. Und daneben
ist noch ein kleiner Einstellknopf mit dem man noch ein wenig Feintuning
machen kann. Das ist der OSCCAL.
Wolly2.0 schrieb:> hmm ok dann tast ich mich mal n bischen an den wert ran mit der> blink-uhr methode> müsste man ja sogar mit ++ un -- otf einstellen können
Machs um Gottes Willen nicht zu kompliziert.
Mit Halbieren des Suchbereichs hast du das ratz fatz ausgemittelt.