Hi @ all,
Ich muss für die schule derzeit ein Anemometer bauen.
Die Hardware hab ich auch schon komplett fertig. (Elektronix, und
windmessmechanik)
Vom prinzip her sieht das so aus:
ein reed kontakt löst bei jeder Umdrehung am INT0 Pin einen Interrupt
aus. (das klappt soweit) In der interrupt routine wird eine variable
hochgezählt. (bei jedem durchlauf var++) paralell dazu läuft ein 16-bit
Timer, der alle 10 sek den ComparMatch1A Interrupt auslöst. in dieser
interrupt routine wird die zählvariable kopiert, die hauptfunktion dazu
veranlasst die windgeschwindigkeit zu berechnen, und dann die
zählvariable wieder auf 0 setzt. Die Hauptfunktion berechnet die
geschwindigkeit, und sendet den wert dann via USART an den PC (der USART
teil funktionier auch)
Jetzt zu meinen Problemen:
1. Ich bekomme auf einem in Delphi selbst geschriebenen Terminal (das
terminal funktioniert nachweislich) immer 0,000km/h. Das ist irgendwie
mysteriös...
2. Der Timer sendet bei aktueller einstellung immer alle 8,8 sek den
Compare match interrupt, was ich ja noch einstellen könnte, aaaber:
er sendet den interrupt immer alle 8,8 sekunden, egal was ich in OCR1A
schreib. Auch mysteriös...
für weitere codeverbesserungen bin ich auch gerne offen!
Achja, ich verwende einen Atmega8 @ 8Mhz
und hier noch mein Code:
1
#include<stdlib.h>
2
#include<avr/io.h>
3
#include<avr/interrupt.h>
4
#include<avr/iom8.h>
5
6
#define UMFANG 68.173 // Umfang des Schaufelrades in cm
7
8
#define BAUD 2400L // Baudrate
9
10
// Berechnung
11
#define UBRR_VAL F_CPU/16/BAUD-1
12
13
voidUSART_Init(unsignedintubrr)
14
{
15
// Set baud rate
16
UBRRH=(unsignedchar)(ubrr>>8);
17
UBRRL=(unsignedchar)ubrr;
18
// Enable transmitter
19
UCSRB=(1<<TXEN);
20
// Set frame format: 8data, 1stop bit
21
UCSRC=(1<<URSEL)|(3<<UCSZ0);
22
}
23
24
voidUSART_Transmit(unsignedchardata)
25
{
26
// Wait for empty transmit buffer
27
while(!(UCSRA&(1<<UDRE)));
28
// Put data into buffer, sends the data
29
UDR=data;
30
}
31
32
voidUSART_Putstring(char*s)
33
{
34
while(*s)
35
{// so lange *s != '\0' also ungleich dem "String-Endezeichen"
36
USART_Transmit(*s);
37
s++;
38
}
39
}
40
41
chartempbuff[8];// buffer
42
43
voidUSART_Putfloat(floatspeed)
44
{
45
dtostrf(speed,6,3,tempbuff);
46
USART_Putstring(tempbuff);
47
}
48
49
// interrupts initialisieren
50
voidINT_Init(void)
51
{
52
GIMSK|=(1<<6);// int0 aktivieren
53
MCUCR|=(1<<1);// bei fallender flanke interrupt auslösen
54
MCUCR&=~(1<<0);// /
55
sei();// interrupts ein
56
}
57
58
// 16-bit timer initialisieren
59
voidTIMER_Init(void)
60
{
61
TCCR1A=(1<<WGM12);// CTC Mode
62
TCCR1B=(1<<CS12)|(1<<CS10);// F_CPU/1024 from prescaler
63
OCR1A=0xFFFF;// compare value
64
TIMSK=(1<<OCIE1A);// enable compare match interrupt
65
}
66
67
// globale variablen
68
uint8_tdist=0,zwi=0;
69
volatileuint8_tupm=0,calc=0,usek=0;
70
floatspeed;
71
72
// interrupt routinen
73
74
// INT0 Pin
75
ISR(INT0_vect)
76
{
77
upm++;
78
}
79
80
// Timer
81
ISR(TIMER1_COMPA_vect)
82
{
83
calc=1;
84
usek=upm;
85
upm=0;
86
}
87
88
89
intmain(void)
90
{
91
USART_Init(UBRR_VAL);// uart initialisieren
92
93
TIMER_Init();// timer initialisieren
94
95
INT_Init();// interrupts initialisieren
96
97
98
while(1)
99
{
100
if(calc)
101
{
102
dist=usek*UMFANG;// streckenberechnung in cm
103
zwi=dist/10000;// umrechnung in km
104
speed=zwi*6*60;// umrechnung in km/h
105
USART_Putfloat(speed);// ausgabe auf USART
106
calc=0;
107
}
108
}
109
110
return0;
111
}
ah nochwas: im anhang schick ich mal noch mein Delphi Terminal mit.
Achtung: Die durchschnittsgeschwindigkeitberechnung ist nochnicht ganz
korrekt.
UND: die datums-zeitangabe und das "km/h" am schluss werden vom Programm
eiingefügt. Vom µC kommt nur der eigentlich wert!
@2919:
wie genau meinst du das? kannst du das mal konkretisieren (oder steh ih
auf der leitung?)
@crazy horse: wie oben beschrieben ist die .exe nur mein
selbergeschriebenes messterminal. Nicht direkt relevant!
also wie gesagt, ich bin auch für alternative lösungsvorschläge
bezüglich des timers und so offen!
ich bin halt noch relativ am anfang der microcontroller...
Ja machn Int0 so dass er eine Variable hochzaehlt. Und dann machst einen
Timer0, zB alle 10ms der zaehlt auf einen Sekunde, oder auf eine Minute
oder irgendwas. Wenn diese Zeit vorueber ist, wird die
Int0-Zaehl-Variable gelese und zurueckgesetzt.
Bei einer Division mit Integer-Zahlen werden die Kommastellen
abgeschnitten.
Im Code wird folgendes gerechnet:
uint8_t dist = 0, zwi = 0;
dist = usek*UMFANG; // streckenberechnung in cm
zwi = dist/10000; // umrechnung in km
speed = zwi*6*60; // umrechnung in km/h
Die Variable zwi ist nur dann ungleich Null, wenn die Variable dist
einen grösseren Wert als 10000 besitzt. Aber da es nur einen "uint8_t"
ist, kommt diese nur auf max. 255. Somit ergibt sich für die Variable
zwi immer eine Null.
@ Ephi (Gast)
>ah, ja klar...>trotz der anpassung der variablen für die berechnung, hab ich noch was>merkwürdiges: bei der messung kommt jetzt am Terminal entweder 0,000>oder 360,000 an. kann ja irgendwie nicht sein!?Festkommaarithmetik
Floating Point ist hier überflüssig. Erst alle Multiplikationen, dann
alle Divisionen!
>am timer arbeite ich noch...
soooo lange?
>hier der aktuelle code:
Solche langen Sachen sind besser als Anhang.
Es fehlt das #define für F_CPU! Das Flag calc sollte man als erstes
zurücksetzen. Ist hier zwar unkritisch, kann aber in anderen Programmen
komische Wirkung haben, wenn die Rechnung sehr lang wird.
Wenn schon, dann so.
1
calc=0;
2
speed=temp*6*60*UMFANG*usek/10000;// umrechnung in km/h
> trotz der anpassung der variablen für die berechnung, hab ich noch was> merkwürdiges: bei der messung kommt jetzt am Terminal entweder 0,000> oder 360,000 an. kann ja irgendwie nicht sein!?
Was ist daran merkwürdig.
> temp = dist/10000; // umrechnung in km> speed = temp*6*60; // umrechnung in km/h
da sowohl dist als auch 10000 integer Datentypen sind, wird
die Division auch als Integer Division ausgeführt.
Und da ich nicht davon ausgehe, dass die Spitzen deines
Anemometers mehr als 1 km in 10 Sekunden zurücklegen
werden, wird das Ergebnis deiner Division entweder 0 oder 1
sein. Und zwar auch dann, wenn du eigentlich ein Ergebnis von
0.0001 erwartet hättest
Aber wie Falk schon sagte: Auch float ist an dieser Stelle
überflüssig. Wenn man die Berechnung etwas umstellt, dann kriegt
man da auch schöne Ergebnisse komplett ohne float.
Hi,
ertma vielen dank! ich habs jetzt erstmal mit fließkomma eiinigermaßen
hin gebracht, ich werds heut abend mal mit festkomma probieren!
ich hatte den code extra nicht als anhang gemacht, da ich dachte man
kann ihn so schneller einsehn.
F_CPU hab ich in den compileroptionen definiert gehabt...
>>am timer arbeite ich noch...>soooo lange?
ja. ich hätte eher schreiben sollen, am timer rätsele ich noch ;)
ich weis nämlich wirklich noch nicht, wie ich dem beibringe so und so
viel ms, oder auch s zu warten. das hängt doch alles von der
taktfrequenz ab.
mit dem compare match hätte ich halt so lange rumprobiert bis ich nen
compare wert gefunden hätte, dann ziemlich genau 10sek. entspricht (5sek
wär jetzt auch kein beinbruch..) allerdings ist der compare match
interrupt intervall trotz meiner korrektur in der INIT routine
unabhängig vom inhalt von OCR1A immer gleich :confused:
P.S.: sorry wen hin und wieder mal ein c fehlt, meine tastatur hängt ;)
Der Timer besteht ja nur aus einer handvoll Register. Davon braucht man
nur etwa 2 stueck. Da ist man selbst mit wahllosem Permutieren
schneller. Sonst kann man auch mit Google nach "AVR timer ASM" suchen.
Gibt beliebig viele Eintraege.
@ Ephi (Gast)
>ja. ich hätte eher schreiben sollen, am timer rätsele ich noch ;)>ich weis nämlich wirklich noch nicht, wie ich dem beibringe so und so>viel ms, oder auch s zu warten. das hängt doch alles von der>taktfrequenz ab.
Ach neee!
>mit dem compare match hätte ich halt so lange rumprobiert bis ich nen>compare wert gefunden hätte, dann ziemlich genau 10sek. entspricht
AUA!!!!!!
Schon mal was von Rechnen gehört?
Wenn der Timer mit 1 MHz läuft, sind das 1 Millionen Takte pro Sekunde.
Na, dämmerts?
Mfg
Falk
ok, sry, seid etwas nachsichtig mit mir, ih bin wohl atm nicht so ganz
hell auf der platte ;) soll vorkommen...
aalso ich hab mal etwas gerechnet:
wenn ich den 16bit timer mit F_CPU/256 vom prescaler versorge,
läuft der timer bei 8Mhz systemtakt mit 31250Hz
wenn ih jetzt erstmal bei meiner lösung mit dem compare match bleibe,
müsste ich im OCR1A als compare value 0x7A12 festlegen.
dann wird der compare match interrupt jede sekunde ausgelöst. jetzt noch
ne kleine verzweigung in der int routine, die auf 10 zählt, und dann zur
berechnung veranlasst.
ich werd das mal ausprobieren, aber selbstverständlich mal noch nach
anderen timermethoden googlen
gruß
Ephi
hier noch meine jetzige init und interrupt funktion:
Timer INIT:
1
// 16-bit timer initialisieren
2
voidTIMER_Init(void)
3
{
4
TCCR1B=(1<<WGM12);// CTC Mode
5
TCCR1B=(1<<CS12);// F_CPU/256 from prescaler
6
OCR1A=0x7A12;// compare value
7
TIMSK=(1<<OCIE1A);// enable compare match interrupt
8
}
INT handler:
1
// Timer
2
ISR(TIMER1_COMPA_vect)
3
{
4
if(intcount==10)
5
{
6
intcount=0;
7
calc=1;
8
usek=upm;
9
upm=0;
10
}
11
else
12
intcount++;
13
}
ich hab das gefühl, der löst den COMPA_vect, immer blos beim overflow,
und nicht bei meinem value aus :(
hab die init auch nochmal anhand vom datenblatt geprüft
sollte soweit korrekt sein!
ok, auch die fließkomma arithmetik klappt soweit.
allerdings hab ich jetzt noch ein problem:
und zwar war mir nicht bewusst, das reed kontakte ja auch prellen :(
und jetzt weis ich wirklich nihtmehr weiter, wie ich einen reed kontakt
entprelle. das ist zwar kein problem, aber wie soll ih das am interrupt
machen?
evtl ne hardware entprellung? wie würde sowas aussehen?
Ehi, die Fliessskommarechnung wuerd ich mal rausnehmen, bis ueberhaut
etwas Sinnvolles kommt. Lass dir doch mal rausgeben, wieviele Impulse
denn im Messzyklus ankommen. Und falls die unrealistisch sind, aendere
die Software bis das zuerst mal stimmt.
Ephi wrote:
> na dann ;)>> habs ausprobiert, und klappt ;)>> wozu eig überhaupt die ganze softwareentprellerei, wenns so einfach in> hw geht?
Weil bei 10 Tasten dann doch schon einiges an externer Hardware
dazukommt, der
* bezahlt werden muss
* Platz auf der Platine braucht
Und dann natürlich noch: Entprellen ist eine Seite der Medaille.
Aber die 'klassische' PeDa-Entprellung liefert dir gleich noch
einiges mehr mit: Kein Tastendruck geht verloren, sie kostet praktisch
keine CPU Last, Unterscheidung zwischen langem und kurzem Tasten-
druck, Autorepeat.
@2920
flieskomma ist schon lang raus!
das mit dem impulse ausgeben hab ich auh schon gemacht, nach der
entprellung passt das nun!
@karl heinz buchegger
ja ok, stimmt schon, aber in meinem fall brauch ich das ja alles nicht.