Hallo!
Ich hab grad damit begonnen, mich in die Materie der MC Programmierung
einzuarbeiten.
Verwende einen Attiny 2313A und Atmel Studio 6.
Folgendes möcht ich machen:
Durch Verwendung des Analog Comparators soll mit Hilfe eines
Phototransistors ein Interrupt ausgelöst werden, wenn das Umgebungslicht
eine gewisse Schwelle unterschreitet. Das funktioniert auch schon.
Dann soll in der Interrupt Routine des AC´s eine LED aktiviert und ein
Flag gesetzt werden.
In der While Schleife im Main wird bei gesetztem Flag ein Timer im CTC
Modus aktiviert. Außerdem wird das AC Interrupt Bit 0 gesetzt.
Erreicht der Timer/Counter den definierten Wert, wird wieder ein
Interrupt ausgelöst und die LED wieder deaktiviert und der Timer
gestoppt.
Das funktioniert auch schon.
Nun hab ich allerdings das Problem, dass der AC wieder ein Interrupt
auslöst, wenn das Umgebungslicht einen gewissen Wert unterschreitet,
obwohl ich das Interruptbit auf 0 gesetzt habe.
1
//Analog Comparator
2
ACSR=0<<ACIE;//clear the interrupt bit
3
ACSR=0<<ACD;//power ON analog comparator
4
ACSR=0<<ACBG;//use AIN0 as positive Input
5
ACSR=0<<ACIC;//Input Capture disabled
6
ACSR=0<<ACIS0;//Interrupt Mode (Output Toggle)
7
ACSR=0<<ACIS1;//Interrupt Mode (Output Toggle)
8
ACSR=1<<ACIE;//Enable Interrupts again
9
10
//16 bit Timer1 Register A
11
TCCR1B&=((0<<CS12)|(0<<CS11)|(0<<CS10));//Stop Timer/Counter (Timer 1 Register A and B uses the same Clock)
12
TCCR1A=0<<COM1A1;//Normal port operation - OC1A disconnected
13
TCCR1A=0<<COM1A0;//Normal port operation - OC1A disconnected
14
TCCR1A=0<<WGM13;
15
TCCR1A=1<<WGM12;//CTC1 - CTC mode with Top OCR1A
16
TCCR1A=0<<WGM11;//disable PWM11
17
TCCR1A=0<<WGM10;//disable PWM10
18
19
OCR1AH=0x00;//compare register high
20
OCR1AL=0x98;//compare register low
21
22
sei();//Global Interrupts enabled
23
24
25
while(1)
26
{
27
if(flag==1)
28
{
29
cli();
30
flag=0;
31
TIMSK=1<<OCIE1A;//Timer, Output Compare A Match Interrupt enable
32
ACSR=0<<ACIE;//Disable Analog Comparator Interrupts
PORTD = 0<<PORTD2; //disable LED
das macht auch nicht wirklich das was du willt. Da kannst du auch gleich
PORTD = 0 schreiben.
TCCR1B |= ( (0<<CS12) | (1<<CS11) | (1<<CS10)); //start timer/counter
ist genauso unsinn. Denke doch mal drüber nach was du schreibst.
Peter II schrieb:> TCCR1B |= ( (0<<CS12) | (1<<CS11) | (1<<CS10)); //start timer/counter>> ist genauso unsinn. Denke doch mal drüber nach was du schreibst.
sorry, meinste es nicht so schlimmt. Das Problem ist das du CS12 mit
dieser anweisung nicht löschen kannst. Wenn es vorher 1 ist, bleibt es
auch 1.
Auch ganz oben beim Anfang sind viele 0<<ACIE usw. Dort trifft das auch
zu.
Mach eine Veroderung der einzelnen Bits und weise das ganze Byte auf
einmal dem Register zu (z.B. ACSR).
Athlon N/a schrieb:> ACSR = 0<<ACIE; //clear the interrupt bit> ACSR = 0<<ACD; //power ON analog comparator> ACSR = 0<<ACBG; //use AIN0 as positive Input> ACSR = 0<<ACIC; //Input Capture disabled> ACSR = 0<<ACIS0; //Interrupt Mode (Output Toggle)> ACSR = 0<<ACIS1; //Interrupt Mode (Output Toggle)> ACSR = 1<<ACIE; //Enable Interrupts again>> //16 bit Timer1 Register A> TCCR1B &= ( (0<<CS12) | (0<<CS11) | (0<<CS10)); //Stop Timer/Counter (Timer 1
Register A and B uses the same Clock)
> TCCR1A = 0<<COM1A1; //Normal port operation - OC1A disconnected> TCCR1A = 0<<COM1A0; //Normal port operation - OC1A disconnected> TCCR1A = 0<<WGM13;> TCCR1A = 1<<WGM12; //CTC1 - CTC mode with Top OCR1A> TCCR1A = 0<<WGM11; //disable PWM11> TCCR1A = 0<<WGM10; //disable PWM10
Das ist kompletter Humbug. Die Register werden ja jedesmal komplett
überschrieben. ACSR wird am Ende also nur ACIE gesetzt haben, und
TCCR1A steht auf 0. Schreib das so:
1
ACSR=(1<<ACIE);
2
TCCR1A=(1<<WGM12);
Wenn du unbedingt noch kommentieren willst, was alles nicht gesetzt
ist, dann so:
Die Bibliothek bietet noch den Makro _BV() als Abkürzung für das
Bitgeschiebe. Meiner Meinung nach lässt er sich geringfügig besser
lesen als eine Anhäufung von (1 << BIT).
WGM12 ist nicht im Register TCCR1A angesiedelt, sondern in TCCR1B.
Zu guter Letzt liegt der Verdacht noch nahe, dass dein "flag" nicht
volatile deklariert ist. Die Deklaration hast du uns aber
vorenthalten.
Athlon N/a schrieb:> Das Problem besteht leider immer noch. Flag wurde als volatile> definiert.
ich glaube du hast immer noch nicht verstanden was du überhaupt machst
PORTA &= 0b11111110; //A0 MOS2 supply Bit
PORTA &= 0b11111101; //A1 deactivate pull Up Resistor - DIP #1
was soll das?
Das PORTA Register besteht doch aus 8 bit. Nun sag ich PORTA = PORTA &
0b11111110
Das heißt, das letzte bit wird 0 gesetzt und alle anderen Bits bleiben
so wie sie waren.
Sollte so doch gehn oda?
Athlon N/a schrieb:> Das heißt, das letzte bit wird 0 gesetzt und alle anderen Bits bleiben> so wie sie waren.> Sollte so doch gehn oda?
aber welchen welchen Startwert geht du denn aus? Wenn PORTA nach dem
init 0 ist, dann bringen deine Befehle nichts.
Das MOS2 Supplybit soll hier 0 gesetzt werden, das brauch ich erst wenn
der Rest funktioniert. Egal welchen Startwert PORTA beim init hat, PORT
A0 wird 0 gesetzt.
Diese Befehle sind hier unnötig das stimmt, ich kann mir so aber quasi
notieren, welche Ports wie eingestellt sind.
@ Athlon N/a (athlon)
>volatile int8_t flag = 0;
Warum int? uint reicht, ist hier aber egal.
>int main(void)>{> cli(); //Global Interrupts disabled
Ist überflüssig, denn hier sind die Interrupts SICHER gesperrt, nach dem
Reset.
> //Port Directions> DDRA |= 0b00000001; //A0 as Output - MOS2 Supply> DDRA &= 0b11111101; //A1 as Input - DIP switch #1> DDRB &= 0b11111110; //B0 as Input - positive Analoginput - AIN0> DDRB &= 0b11111101; //B1 as Input - negative Analoginput - AIN1> DDRD &= 0b11111110; //D0 as Input - DIP switch #3> DDRD &= 0b11111101; //D1 as Input - DIP switch #2> DDRD |= 0b00000100; //D2 as Output - LED Supply
Schreibt man anders, damit man es besser lesen kann, siehe
Bitmanipulation.
> //Analog Comparator
Dito. Da sieht man nur schwer durch. Probiers mal so
ACSR = (1<<ACIE); // enable AC interrupts
ACSR |= (1<<ACIF); //clear the interrupt bit
>ISR(ANA_COMP_vect)>{> PORTD |= 0b00000100; //enable LED> flag = 1;>}
OK.
Lass mal die Timer ISR erstmal weg. Dann muss wenigstens erstmal dr
Analogcomparator reagieren.
Du ersetzt eine bescheuerte Schreibweise durch eine andere.
Das ist doch alles Schwachsinn.
Wenn es dir so schwer fällt, da endlich mal eine ordentliche
Schreibweise zu finden, dann mach dir von mir aus ein paar Makros
und für den Rest genauso. Aber eigentlich ist das Unsinn immer alle Bits
eines Register unbedingt in Einzelanweisungen behandeln zu wollen.
Aber so wie du das machst, tappst du von einem unverständlichen Code in
den nächsten.
Das kann doch kein Mensch mehr analysieren, was da wirklich abgeht!
> Diese Befehle sind hier unnötig das stimmt, ich kann mir so aber> quasi notieren, welche Ports wie eingestellt sind.
Das einzige was du tust ist, du erhöhst die Komplexität soweit, dass du
sie nicht mehr überblicken kannst.
DDRB&=0b11111110;//B0 as Input - positive Analoginput - AIN0
4
DDRB&=0b11111101;//B1 as Input - negative Analoginput - AIN1
5
DDRD&=0b11111110;//D0 as Input - DIP switch #3
6
DDRD&=0b11111101;//D1 as Input - DIP switch #2
7
DDRD|=0b00000100;//D2 as Output - LED Supply
Du brauchst Kommentare und ein gutes Auge um zu erkennen, welches Bit in
jeder Zeile eigentlich das relevante ist und wo es daher am eigentlichen
µC hardwaremässig zu finden ist.
Mit ein paar #define, mit denen man den Pins Namen gibt, spart man nicht
nur Kommentare sondern macht auch gleichzeitig den Code lesbarer. Denn
dann steht da eben
PORTD |= ( 1 << LED_PIN );
was man als C-Programmierer sofort als: Hier wird ein Pin auf 1 gesetzt
liest. Welcher Pin? Der Pin an dem die LED hängt.
(Und in dem Fall sollte man für die Port-Namen dann nochmal dasselbe
machen.
Aber so kriegt man Übersicht in seinen Code. Und dann kann man auch mit
dem Code arbeiten.
TIMSK|=0b00100000;//Timer, Output Compare B Match Interrupt enable
6
ACSR&=0b11110111;//Disable Analog Comparator Interrupts
7
TCCR1B|=0b00000101;//start timer/counter with Clock/1024 Prescaler CS12=0, CS11=1, CS10=1
8
sei();
9
}
sicherheitshalber vor dem Wiederzulassen der Interrupts auch as ACI Bit
noch löschen. Nicht das währenddessen ein weiterer Intrerrupt vom
Komperator aufgelaufen ist, der ein erneutes Triggern des Komperator
Interrupts auslöst
1
if(flag==1)
2
{
3
cli();
4
flag=0;
5
6
ACSR&=~(1<<ACIE);// Interrupts disablen
7
ACSR|=(1<<ACI);// und eventuell noch aufgelaufene Interrupt
8
// Anforderungen löschen
9
10
TIMSK|=(1<<OCIE1A);
11
TCNT1=0;
12
OCR1A=1432;
13
TCCR1B|=(1<<CS12)|(1<<CS10);// 1024
14
15
sei();
16
}
Anstatt
OCR1A = 1432;
wärs noch besser, wenn du die gewünschte Zeit mittels des
Timer-Prescalers (den 1024) in Beziehung zur F_CPU setzt. Der Compiler
rechnet dir den Zahlenwert schon aus, wenn du eine Formel hast (und die
musst du haben, schliesslich hast du das ja auch mit dem Taschenrechner
rechnen können) und Zeit, F_CPU und die 1024 in der Formel vorgibst
Das Problem besteht aber leider immer noch.
Der Interrupt vom AC wird einfach nicht deaktiviert bzw. lässt sich
nicht nur einmal ausführen.
Woran kann das liegen? :/
Lg
> ACSR &= ~(1<<ACI); //Clear the Interrupt flag
No.
Das hat schon seinen Grund warum ich
ACSR |= ( 1 << ACI ); // und eventuell noch aufgelaufene
Interrupt
// Anforderungen löschen
geschrieben habe.
Derartige Interrupt Flags werden gelöscht, indem man ein 1 Bit an die
entsprechende Position im Register schreibt. Das war kein Tippfehler.
Aus dem Datenblatt
1
• Bit 4 – ACI: Analog Comparator Interrupt Flag
2
3
This bit is set by hardware when a comparator output event triggers
4
the interrupt mode defined by ACIS1 and ACIS0. The Analog Comparator
5
interrupt routine is executed if the ACIE bit is set and the I-bit in
6
SREG is set. ACI is cleared by hardware when executing the corresponding
7
interrupt handling vector. Alternatively, ACI is cleared by writing a
Athlon N/a schrieb:> ACSR &= ~(1<<ACI); //Clear the Interrupt flag
1. wird das Flag so nicht gelöscht. Sonden indem man da eine 1
reinschreibt. Aber das nur am Rande.
Athlon N/a schrieb:> ISR(TIMER1_COMP1_vect)
2. Stürzt dein Programm hier ab. D.h. nicht hier sondern beim Sprung in
die nicht vorhandene Timer-ISR.
Der Interrupt-Vektor heisst TIMER1_COMPA_vect.
Das hat aber auch Mecker vom Compiler gegeben. Warnings sind nicht zum
ignorieren da!
mfg.
Ah tatsächlich, danke!
Das Problem besteht leider immer noch.
Komisch.. In die if Anweisung wird ja gesprungen, sonst würde der Timer
nicht gestartet werden.
Gibt es noch eine andere Interrupteinstellung für den AC die ich
übersehn hab?
Ich hab auch schon versucht den AC mittels
Thomas Eckmann schrieb:>> ISR(TIMER1_COMP1_vect)>> 2. Stürzt dein Programm hier ab. D.h. nicht hier sondern beim Sprung in> die nicht vorhandene Timer-ISR.>> Der Interrupt-Vektor heisst TIMER1_COMPA_vect.
richtig, der ist mir im Zuge des Durcharbeitens des Codes auch schon
aufgefallen, hab aber dann vergessen zu kontrollieren, ob beim Tiny2313
der Vektor vielleicht wirklich anders heißt, denn ...
> Das hat aber auch Mecker vom Compiler gegeben. Warnings sind nicht zum> ignorieren da!
Thomas Eckmann schrieb:> Athlon N/a schrieb:>> ISR(TIMER1_COMP1_vect)>> 2. Stürzt dein Programm hier ab. D.h. nicht hier sondern beim Sprung in> die nicht vorhandene Timer-ISR.>> Der Interrupt-Vektor heisst TIMER1_COMPA_vect.>> Das hat aber auch Mecker vom Compiler gegeben. Warnings sind nicht zum> ignorieren da!
Danke!!! Das wars. Hab in der falschen Bibliothek nachgesehen -.-
Warnings hat er leider nicht ausgegeben :/. Hier der Output:
Target "PreBuildEvent" skipped, due to false condition; ('$(PreBuildEvent)'!='') was evaluated as (''!='').
5
Target "CoreBuild" in file "D:\Programme\Atmel\Atmel Studio 6.0\Vs\Compiler.targets" from project "D:\Projects and Stuff\Projects\AtmelProjects\Licht\Licht\Licht.cproj" (target "Build" depends on it):
6
Task "RunCompilerTask"
7
D:\Programme\Atmel\Atmel Studio 6.0\make\make.exe all
8
make: Nothing to be done for `all'.
9
Done executing task "RunCompilerTask".
10
Task "RunOutputFileVerifyTask"
11
Program Memory Usage : 262 bytes 12,8 % Full
12
Data Memory Usage : 1 bytes 0,8 % Full
13
Done executing task "RunOutputFileVerifyTask".
14
Done building target "CoreBuild" in project "Licht.cproj".
15
Target "PostBuildEvent" skipped, due to false condition; ('$(PostBuildEvent)' != '') was evaluated as ('' != '').
16
Target "Build" in file "D:\Programme\Atmel\Atmel Studio 6.0\Vs\Avr.common.targets" from project "D:\Projects and Stuff\Projects\AtmelProjects\Licht\Licht\Licht.cproj" (entry point):
17
Done building target "Build" in project "Licht.cproj".
Athlon N/a schrieb:> Warnings hat er leider nicht ausgegeben :/. Hier der Output:
LOL
1
Task "RunCompilerTask"
2
D:\Programme\Atmel\Atmel Studio 6.0\make\make.exe all
3
make: Nothing to be done for `all'.
Nothin to be done - es gibt nichts zu tun.
Verändere mal deinen Code ein wenig, damit es was zu tun gibt.
Leerzeichen rein/raus reicht schon.
> Sind die Warnings defaultmäßig deaktiviert??
EIn -Wall in den Compiler-flags hat noch nie geschadet.
Hab grad gesehn dass er die Warnung eh ausgibt -.-
Hätt mir gedacht, dass die im Output Log etwas mehr hervorgehoben werden
würde. Nun gut wieder etwas gscheider gworden.
Das ist vorerst mal alles, danke euch!!
Jörg Wunsch schrieb:> Karl Heinz Buchegger schrieb:>> EIn -Wall in den Compiler-flags hat noch nie geschadet.>> -Wall -Wextra
Danke euch, was macht -Wextra? Konnte es in der Doku nicht finden.
Jörg Wunsch schrieb:> Athlon N/a schrieb:>>> Danke euch, was macht -Wextra? Konnte es in der Doku nicht finden.>> Du solltest natürlich die GCC-Doku lesen, nicht die für deine> Brotschneidemaschine. ;-)>> http://gcc.gnu.org/onlinedocs/gcc/Warning-Options....
Aja tatsächlich :D.
Habs jetz in Atmel Studio unter -W gefunden. -Wextra habn sie dort wohl
abgeschafft.
Athlon N/a schrieb:> -Wextra habn sie dort wohl> abgeschafft.
Nein, das ist bei denen nur noch nicht angekommen. Gibt's ja auch erst
seit ca. 10 Jahren (in ChangeLog-2003 finde ich es auf die Schnelle das
erste Mal erwähnt).