Hallo Forum,
ich wundere mich gerade über das Verhalten eines Atmega328p, bei dem ich
Pin Change Interrupts verwenden will.
Wenn ich das Datenblatt richtig lese, kann jeder Pin in einer bestimmten
Gruppe den zugehörigen Pin Change Interrupt auslösen. Dazu muss er aber
über das passende PCMSK Register der ISR zugeordnet werden. Danach macht
es keinen Unterschied, ob der Pin Input oder Output ist.
Ich möchte aber nun, dass nur meine Eingänge den entsprechenden
Interrupt auslösen. Bislang scheint aber, trotz der Einstellung des
Maskenregisters, jeder Pin der Gruppe zum Sprung in die ISR Funktion zu
führen. Stellt sich mir also die Frage, ob ich das Masken Register
korrekt anwende?
1
//Includes
2
#include<avr/io.h>
3
#include<avr/interrupt.h>
4
5
//Defines
6
#define ONTIME 10
7
8
//Global variables
9
volatileuint8_tduration=0;
10
volatileuint8_tbrightness=0;
11
volatileuint8_tswitchingthreshold=0;
12
13
//Function declarations
14
voidinit_ports(void);
15
voidinit_timers(void);
16
voidinit_interrupts(void);
17
18
19
// function name: init_ports()
20
// Overall setup of I/O ports
21
//
22
voidinit_ports(void){
23
//Set pull-ups for inputs active = 1, disabled = 0 (default)
24
PORTB|=0b00000000;
25
PORTC|=0b00000000;
26
PORTD|=0b00000000;
27
28
//Set direction output = 1, input = 0 (default)
29
DDRB|=0b11111011;
30
DDRC|=0b11110000;
31
DDRD|=0b11110011;
32
}
33
34
35
36
// function name: init_timers()
37
// configuration of timers for PWM output
38
// and on time duration
39
voidinit_timers(void){
40
//PWM for LEDs left and right side
41
OCR0A=64;
42
OCR0B=128;
43
TCCR0A|=(1<<COM0A1)|(1<<COM0B1)|(1<<WGM01)|(1<<WGM00);//Set Fast PWM non inverting, enable OC0A & OC0B
44
TCCR0B|=(1<<CS02);//256x Prescaler = 240Hz PWM
45
46
//PWM for LEDs front side
47
OCR2A=128;
48
TCCR2A|=(1<<COM2A1)|(1<<WGM21)|(1<<WGM20);//Set Fast PWM non inverting, enable OC2A
Wie sind denn deine Eingänge hardwaremäßig beschaltet? Ohne
Pullup/Pulldown (die internen Pullups sind ja nicht aktiviert)
detektiert der Controller je nach äußerem Einfluss fröhlich
Flankenwechsel, von denen jeder die Interrupt-Routine triggert.
Das hier ist übrigens in der Init nicht sinnvoll:
1
//Set pull-ups for inputs active = 1, disabled = 0 (default)
2
PORTB|=0b00000000;
3
PORTC|=0b00000000;
4
PORTD|=0b00000000;
Durch eine Oder-Verknüpfung kannst du kein Bit auf 0 bringen. Es ist
nicht verwerflich, in der ersten Anweisung eine harte Zuweisung mit "="
zu machen.
Hallo,
ich kann keine Fehler im Code feststellen, kompiliert auch ohne Fehler.
Mit was gehst du an die Eingänge? Taster? Dann wird vermutlich das
prellen so schnell sein, dass du das umschalten gar nicht siehst. Nimm
mal 2 Taster. Einer schaltet ein der andere aus. Oder ausnahmsweise zum
testen ein delay in die Toggle ISR von 50ms. Das toggle musste natürlich
umändern in ein oder aus.
Stimmt die Zuweisung war nicht geschickt. Ändert aber auch nichts, die
Register stehen richtig. An den Port Pins sind PIR Sensoren
angeschlossen, die machen saubere Signale ohne prellen. Per debugger
sehe ich aber, dass die Routine trotz Maskierung aufgerufen wird, wenn
ich einen der anderen Pins den Pegel wechseln lasse.
Hendrik schrieb:> Per debugger> sehe ich aber, dass die Routine trotz Maskierung aufgerufen wird, wenn> ich einen der anderen Pins den Pegel wechseln lasse.
Debugger oder Simulator?
Wenn's ein echter Debugger ist (also auch echte Hardware) dürfte
schlicht ein Schaltungsfehler vorliegen.
Veit D. schrieb:> mal ne ganz doofe Frage.
Allerdings, sehr doofe Frage.
> Taktet dein 328P überhaupt? F_CPU ist irgendwo gesetzt?
Der taktet auch ohne F_CPU. Ohne Takt könnte er nicht einmal sein
Programm in den Flash Speicher übertragen.
Naja, ich glaube das erst wenn er bestätigt das sein PWM taktet wie es
soll. Wenn dieses funktioniert dann funktionieren auch seine PCINTs.
Anders gefragt, konnte er es denn übertragen? Er sagt es funktioniert
nur im Debugger bzw. Simulator? Sonst nicht.
> Er sagt es funktioniert nur im Debugger bzw. Simulator ...
Er schrieb "debugger", und da wüsste ich eben gerne, wie dieser bei
einem ATmega328P aussieht.
Debugger beim Atmega328p geht über so ziehmlich jedes übliche Atmel
Tool. Stichwort Debug Wire.
F_CPU kann man auch als Symbol fürs Projekt festlegen. Die Quarzfrequenz
ändert sich in der Regel ja nicht, außer man wechselt die Hardware. Im
Quellcode mag es übersichtlicher sein. Ich bevorzuge diesen Weg.
Die PWM läuft ohne Probleme. Einzig in den Kommentaren steckt noch ein
Fehler. Auch die zweite PWM läuft mit 244 Hz. Also mit Teiler 256.
Knackpunkt ist das Verhalten der Interrupt Eingänge. Mit dem Debugger
kann ich sehen in welche ISR gesprungen wird. Nehmen wir zum Beispiel
den Pin PC3. Dieser gehört zur PCINT1 Gruppe und sollte entsprechend
maskiert sein. Allerdings springt das Programm auch in die PCINT1_vect
routine wenn ich zum Beispiel PC0 auf Input setze und dann über einen
10k Widerstand auf Vcc lege. Entsprechend wird auch die LED an PB5
getoggelt.
Gleiches verhalten, wenn der Pin auf Ausgang steht. So gibt es das
Datenblatt ja auch vor. Nur sollte der Pin eigenltich durch das Masken
Register nicht beachtet werden. Von der sinnhaftigkeit einen auf Ground
schaltenden Push-Pull Treiber über 10k nach Vcc ziehen zu wollen mal
ganz abgesehen.
Vielleicht noch was zur Hardware. Ausgangsbasis ist ein Arudino Nano den
ich über die SPI Schnittstelle Programmiere oder per Debug Wire eben
debugge. An den Pins PD2, PD3, PB2 und PC3 sind PIR Sensoren
angeschlossen. Die Arbeiten wie der Arduino mit 5V und schalten für 1
Sekunde auf High, wenn Bewegung erkannt wird. An die Eingänge PC0 bis
PC3 sollen Potis angeschlossen werden. An den 3 Pins die als PWM laufen,
werden nacher LEDs angeschlossen, momentan sind sie offen. Genau wie die
restlichen Pins die zu diesem Zwecke auf Ausgang und Low stehen. Das
Problem fing halt an, als ich die zum Testen meiner ADC Funktionen 5V
auf den dann als Eingang konfigurierten PC0 gegeben habe. Aber selbst
als Ausgang wird die ISR ja trotz maskierung gerufen.
Da fällt mir erstmal nichts weiter ein, außer zu wiederholen:
Stefanus F. schrieb:> Gebe mal den aktuellen Wert der beiden Masken-Register auf einer> seriellen Konsole aus oder kontrolliere sie mit einem Debugger.
Hendrik schrieb:> Stellt sich mir also die Frage, ob ich das Masken Register> korrekt anwende?
Mach' doch mal diese elenden Veroderungen weg, wer kommt den auf so eine
Schnapsidee? Ein zuvor startender Bootlader beispielsweise kann Register
vorbesetzen und die bleiben dann auch so. Eine erstmalige Konfiguration
macht man grundsätzlich per direkte Zuweisung.
> Allerdings springt das Programm auch in die PCINT1_vect> routine wenn ich zum Beispiel PC0 auf Input setze und dann über einen> 10k Widerstand auf Vcc lege.
Selbstgestrickte Platine und vergessen eines der GND, VCC oder gar AVCC
am ATMega328 anzuschließen?
Außerdem hilft Dir der Debugger nichts, wenn Du nicht auch mit dem Kopf
debuggen kannst, d.h. Funktionalität des Codes zurückbauen, Code für
einen PCINT und für einen ADC schreiben, Timer und Rest raus. Und dann
die Funktionalität Schritt für Schritt erweitern.