Anbei mal meine Version der 8 * 12Bit BAM komplett als Knight Rider. Bei 8MHz CPU-Takt ergibt sich eine PWM von 2kHz. Verschiedene PWM- und Dimmstufen kann man in der "main.h" ausprobieren. Benutzt wird ein 16Bit Timer mit 2 Compare-Interrupts. Für 8 LEDs braucht man ja eh mindestens einen ATtiny24. Eine Änderung auf >12 Bit oder 16 Ausgänge sollte kein Problem sein. Bei 16 Ausgängen ist die Bitzeit natürlich 2 Zyklen. Der Interrupthandler wurde auf den GAS umgeschrieben, was nicht so schwer war. Auch werden alle Register gesichert, so daß es keine Probleme mit den C-Routinen gibt. Damit lassen sich alle nicht zeitkritischen Routinen bequem in C schreiben. Die unterschiedliche Laufzeit der beiden Interrupts bis zur Portausgabe wird im OCR1BL-Wert korrigiert. Die Umwandlung der PWM-Werte in die Ausgabedaten erfordert ein Umsortieren von quer nach längs. Das wird mit Bitbefehlen gemacht (SBRS + OR). Der Compiler hat das auch sofort gemerkt und alle Variablen in Register gehalten. Dadurch ist der Code klein und sauschnell. Die Polarität der LEDs ist per Define einstellbar. Die Umwandlung der Helligkeitsstufen in PWM-Werte erfolgt über eine Tabelle. Anmerkungen: Der Latenzausgleich umfaßt nur 3 Zyklen, es sind also keine anderen Interrupts erlaubt. Man könnte Interrupts in der letzten Bitzeit erlauben, dann sind ~2000 Zyklen bis zum nächsten PWM-Interrupt Zeit. Das Einschreiben der neuen PWM-Daten ist nicht interruptfest. Erfolgt eine Änderung von 2047 auf 2048 oder umgekehrt, kann es flackern. Falls das stört, muß man das Ändern mit der letzten Bitzeit synchronisieren. Z.B. wartet man in der Routine, bis TCNT1 größer als die letzte Bitzeit und noch genügend Zeit zum Laden vor dem nächsten Zyklus ist. Die 2kHz mögen viel klingen, sind es aber nicht unbedingt. Die LEDs des STK500 sind klein und punktförmig, bewegt man die Augen, ist bei nur 100Hz ein deutliches Flackern zu sehen. Mit 2kHz ist man also auf der sicheren Seite, die PWM sieht quasi wie Gleichstrom aus.
:
Bearbeitet durch User
Hallo, ich kann hier auf Arbeit das Zip grad nicht downloaden. Kannst du vielleicht sagen wieviele Cycles die ISR braucht?
Peter Dannegger schrieb: > Anbei mal meine Version der 8 * 12Bit BAM komplett als Knight Rider. > Bei 8MHz CPU-Takt ergibt sich eine PWM von 2kHz. Entschuldige wenn ich da etwas Falsch verstehe, aber... BAM mit 2KHz wurde heissen, dass bit0 weniger als 16Cy hat - mit jump, reti usw... ?
Eine Bitzeit = 1/8MHz = 125ns 8MHz / 4095 = 1,95kHz Die ersten 7 Bits werden im Compare-A Interrupt erzeugt, d.h. 127 Zyklen. Insgesamt dauert der Interrupt 159 Zyklen. Die weiteren Compare-B Interrupts dauern 51 Zyklen. Das ergibt bei 12Bit: (159 + 4 * 51) / 4095 = 9% CPU-Last
Peter Dannegger schrieb: > Die ersten 7 Bits werden im Compare-A Interrupt erzeugt, d.h. 127 > Zyklen. Insgesamt dauert der Interrupt 159 Zyklen. Sorry, war zu faul um mich durchzulesen. Bei mir habe ich nur die bits 0 und 1 ins bit7 verlegt, bin aber nicht besonders glücklich damit.
Nur für die Registratur (und um zu zeigen, dass das Projekt interessiert
und Anklang findet):
in pwm.c
> TCCR1B = 1<<WGM12 | 1<<CS00; // CTC-mode, F_CPU / 1
sollte es wohl eher CS10 heißen.
der alte Hanns schrieb: > Nur für die Registratur (und um zu zeigen, dass das Projekt interessiert > und Anklang findet): > > in pwm.c >> TCCR1B = 1<<WGM12 | 1<<CS00; // CTC-mode, F_CPU / 1 > > sollte es wohl eher CS10 heißen. Da gerade Beitrag "Suche günstigen 5V Mikrocontroller mit 6 PWM Channel für LED Steuerung" drauf verwiesen wird... ist im Define (hier mal die iom8.h genommen) aber (auch nach vier Jahren) mit der gleichen Zahl hinterlegt, (Schwein gehabt - hihi) Aber: der Ordnung halber hast Du Recht.
1 | /* TCCR0 */ |
2 | /* bits 7-3 reserved */ |
3 | #define CS02 2 |
4 | #define CS01 1 |
5 | #define CS00 0 <--- |
6 | ... |
7 | ... |
8 | /* TCCR1B */ |
9 | #define ICNC1 7 |
10 | #define ICES1 6 |
11 | /* bit 5 reserved */ |
12 | #define WGM13 4 |
13 | #define WGM12 3 |
14 | #define CS12 2 |
15 | #define CS11 1 |
16 | #define CS10 0 <--- |
VlG Äxl
Für den "aktuellen" GCC aus https://ww1.microchip.com/downloads/Secure/en/DeviceDoc/avr8-gnu-toolchain-3.6.2.1778-win32.any.x86.zip (Registrierung, aber keine E-Mail-Aktivierung erforderlich) ist eine kleine Anpassung erforderlich:
1 | ap |
2 | 5.4.0 |
3 | In file included from dimm_array.c:3:0: |
4 | dimm_array.h:8:25: error: variable 'DIMM_ARRAY' must be const in order to be put into read-only section by means of '__attribute__((progmem))' |
5 | extern uint16_t PROGMEM DIMM_ARRAY[]; |
6 | ^ |
7 | dimm_array.c:18:18: error: variable 'DIMM_ARRAY' must be const in order to be put into read-only section by means of '__attribute__((progmem))' |
8 | uint16_t PROGMEM DIMM_ARRAY[] = |
9 | ^ |
10 | In file included from main.c:5:0: |
11 | dimm_array.h:8:25: error: variable 'DIMM_ARRAY' must be const in order to be put into read-only section by means of '__attribute__((progmem))' |
12 | extern uint16_t PROGMEM DIMM_ARRAY[]; |
13 | ^ |
14 | Drücken Sie eine beliebige Taste . . . |
15 | |
16 | pwm_8ch>ap |
17 | 5.4.0 |
18 | AVR Memory Usage |
19 | ---------------- |
20 | Device: atmega48 |
21 | |
22 | Program: 1216 bytes (29.7% Full) |
23 | (.text + .data + .bootloader) |
24 | |
25 | Data: 28 bytes (5.5% Full) |
26 | (.data + .bss + .noinit) |
27 | |
28 | |
29 | Drücken Sie eine beliebige Taste . . . |
tiny24 geht auch, aber tiny40 ergibt:
1 | pwm_int.S:38: Error: illegal opcode elpm for mcu avrtiny |
2 | pwm_int.S:52: Error: illegal opcode elpm for mcu avrtiny |
3 | pwm_int.S:84: Error: illegal opcode elpm for mcu avrtiny |
4 | pwm_int.S:31: Warning: operand out of range: 0x23 |
5 | pwm_int.S:77: Warning: operand out of range: 0x23 |
Meine eigentliche Frage: wie kann man einzelne Bits (Pins, 5 & 7) für die Ausgabe im ASM-Interrupthandler maskieren?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.