Hallo, um den AVR etwas kennen zu lernen, probiere ich gerade am STK500 die PWM aus. Wenn der Timer1 (AT90S8515) benutzt wird, wird es wohl auch Fast PWM genannt. Jedenfalls wollte ich es mit den SW0/1 breiter oder schmaler werden lassen, allerdings kommt es irgendwo zu einem Überlauf, denn wenn ich incrementiere begrenzt der Code nicht - auf dem Scope sieht man dann ein Invertieren des PWM Signals, eigentlich sollte es nicht weiter verändern. Wo ist mein Fehler? Im Simulator klappt natürlich alles. Viele Grüße Olaf ---8<--- .nolist .include <8515def.inc> .list .equ PWM10_TOPVAL = 0x03FF .equ PWM10_50VAL = 0x01FF .equ PWM_RLDVAL = 184 ; 20ms with CK/1024 .equ INCR_VAL = 2 .def TEMP = r16 .def PWM10H = r17 .def PWM10L = r18 .def ZERO = r2 .def INCR = r3 .def PWM_RLD = r4 .def KEY_SCAN = r5 .cseg .org 0x0000 rjmp init .org INT0addr ; External Interrupt Request 0 reti .org INT1addr ; External Interrupt Request 1 reti .org ICP1addr ; Timer/Counter Capture Event reti .org OC1Aaddr ; Timer/Counter1 Compare Match A reti .org OC1Baddr ; Timer/Counter1 Compare MatchB reti .org OVF1addr ; Timer/Counter1 Overflow reti .org OVF0addr ; Timer/Counter0 Overflow rjmp T0_OVF .org SPIaddr ; Serial Transfer Complete reti .org URXCaddr ; UART, Rx Complete reti .org UDREaddr ; UART Data Register Empty reti .org UTXCaddr ; UART, Tx Complete reti .org ACIaddr ; Analog Comparator reti init: ; init SP ldi TEMP, LOW(RAMEND) out SPL, TEMP ldi TEMP, HIGH(RAMEND) out SPH, TEMP ; set vars ldi PWM10L, LOW(PWM10_50VAL) ; PWM10 start val 50% ldi PWM10H, HIGH(PWM10_50VAL) ldi TEMP, PWM_RLDVAL ; Timer reload value var mov PWM_RLD, TEMP ldi TEMP, INCR_VAL mov INCR, TEMP clr ZERO ; enable sleep mode ldi TEMP, (1<<SE) out MCUCR, TEMP ; PD5 as output OC1A ldi TEMP, (1<<DDD5) out DDRD, TEMP ; PD0/PD1 as input with pull-up for switches (PWM up/down 0..100%) ldi TEMP, (1<<PORTD0)|(1<<PORTD1) out PORTD, TEMP ; intall 10-bit pwm mode on T/C1 ; OC1A non-inverted and OC1B inverted PWM, prescale CK/8 ldi TEMP, (1<<COM1A1)|(1<<COM1B1)|(1<<COM1B0)|(1<<PWM11)|(1<<PWM10) out TCCR1A, TEMP ldi TEMP, (1<<CS11) out TCCR1B, TEMP ; install interrupt for switch PWMing on T/C0 ldi TEMP, (1<<TOIE0) out TIMSK, TEMP ldi TEMP, (1<<CS02)|(1<<CS00) ; CK/1024 => 3.686MHz/1024 = 278us ;ldi TEMP, (1<<CS01) ; CK/8 for SIMULATOR TEST ONLY out TCCR0, TEMP out TCNT0, PWM_RLD ; reload für 20ms ; pwm 50%, load top values ldi TEMP, HIGH(PWM10_50VAL) out OCR1AH, TEMP ldi TEMP, LOW(PWM10_50VAL) out OCR1AL, TEMP ldi TEMP, HIGH(PWM10_50VAL) out OCR1BH, TEMP ldi TEMP, LOW(PWM10_50VAL) out OCR1BL, TEMP sei main: sleep rcall pwm_keys rjmp main ; **** sub routines **** ; -- eval switch scan codes -- ; Note, the STK500 keys are low active ; SW0 -> down ; SW1 -> up pwm_keys: ; for SIMULATOR TEST ONLY ; ldi TEMP, 0x02 ; mov KEY_SCAN, TEMP ; check on sw0/PD0 sbrs KEY_SCAN, PORTD0 rcall pwm_dec ; check on sw1/PD1 sbrs KEY_SCAN, PORTD1 rcall pwm_inc pwm_keys_exit: ldi TEMP, 0x03 or KEY_SCAN, TEMP ; clear pwm key scan ; set the PWM values out OCR1AH, PWM10H out OCR1AL, PWM10L out OCR1BH, PWM10H out OCR1BL, PWM10L ret ; -- decrement PWM -- pwm_dec: sub PWM10L, INCR sbc PWM10H, ZERO brmi pwm_dec_limit ; if PWM10 value less than zero, limit it ret pwm_dec_limit: clr PWM10L clr PWM10H ret ; -- increment PWM -- pwm_inc: add PWM10L, INCR adc PWM10H, ZERO ; test on PWM TOPVAL mov TEMP, PWM10L subi TEMP, LOW(PWM10_TOPVAL + 1) mov TEMP, PWM10H sbci TEMP, HIGH(PWM10_TOPVAL + 1) breq pwm_inc_limit ; if PWM10 value greater than TOPVAL, limit ret pwm_inc_limit: ldi PWM10L, LOW(PWM10_TOPVAL) ldi PWM10H, HIGH(PWM10_TOPVAL) ret ; ********* ISR ********* T0_OVF: cli push TEMP ; save register in TEMP, SREG push TEMP in KEY_SCAN, PIND ; scan switches on PD out TCNT0, PWM_RLD ; reload timer pop TEMP ; restore register out SREG, TEMP pop TEMP sei reti --->8---
Hi, dies ist natürlich jetzt auf die schnelle ziemlich schwierig einen überblick von dem assembler code zu machen. Falls du die möglichkeit hast dies in c zu programmieren, mache dies. Tipp: für kleinere Prögrämmchen: CodevisionAvr --> http://www.hpinfotech.ro/html/download.htm Sorry ansonsten kann ich dir nicht weiterhelfen. Ich assembliere nie wieder, seit ich mit c arbeite.
Also, zwei Tasten am STK500 sollen die Pulswidth der 10-bit PWM inc/decrementieren. Dabei sollen die "Anschläge" bei TOPVAL=0x3FF (10bit full) bzw. 0x00 sein. So würde ich es in C machen: ---8<--- uint8_t keyscan; // keys are low active, Port read into var uint16_t pwmval; // pwm compare value void pwm_keys() { if(~keyscan & 0x01) // bit 0 active -> decrement if(--pwmval < 0) pwmval = 0; if(~keyscan & 0x02) // bit 1 active ->increment if(++pwmval > 0x3FF) pwmval = 0x3FF; OCR1A = pwmval; } --->8--- Ist in diesem Algo schon der Fehler? Viele Grüße Olaf
Hallo ope, ich denke, daß der Fehler hier liegt. if(++pwmval > 0x3FF) pwmval = 0x3FF; ^^ Denn angenommen pwmva1 steht auf 0x3FF und soll nochmal um eins erhöht werden, dann wird zuerst 0x01 zu 0x3FF dazugezählt und man erhält einen Überlauf, so daß pwmva1 dann 0x00 ist. Der anschließende Vergleich ob pwmva1 größer wie 0x3FF rennt dann ins Leere. Probiere mal das hier aus: if(pwmval < 0x3FF) pwmval++; Dann sollte pwmva1 bei 0x3FF stehen bleiben. Beim dekrementieren ist übrigens der selbe Fehler. Gruß Schmidle
vielen Dank für den Hinweis; aber ++pwmval ist ein pre-increment und pwmval eine 2-byte/16-Bit Variable, d.h. 0x03FF + 0x0001 = 0x4000 passen ohne Überlauf rein. Mit dem Nachfolgenden Vergleich wird festgestellt, dass mehr als die 10Bit gesetzt sind (bzw. 0x4000 > 0x03FF) und pwmval wieder auf 0x03FF fest getackert - oder liege ich hier total falsch? Viele Grüße Olaf
sorry, du hast natürlich recht. Ein Überlauf bei 0x3FF íst bei einer 16-Bit Variablen natürlich Unsinn. Gruß Schmidle
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.