Met onderstaande code probeer ik door bediening op m'n keyboard een ledje te laten dimmen.
Het interrupt gedeelte heb ik uit de manual.
Het principe werkt, alleen heb ik een probleem in de interrupt. deze wordt iedere 32ste cyclus aangeroepen wat resulteert in een maximale gemiddelde uitgangsspanning van 3,6V op porta.1 (red 254 = 3,6V) Als ik de interrupt sneller zet werkt de HRSIN niet meer.
Heeft iemand suggesties om dit op te lossen?
DEVICE 16F648A
CONFIG HS_OSC, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
XTAL 20
ALL_DIGITAL TRUE
RCSTA = $90 ' Enable serial port & continuous receive
TXSTA = $24 ' Enable transmit, BRGH = 1
SPBRG = 10 ' 115200 Baud @ 20MHz, -1,36%
DECLARE LCD_ENPIN PORTB.0
DIM RED AS WORD
DIM GREEN AS BYTE
DIM BLUE AS BYTE
DIM waarde AS BYTE ' zet de grote van waarde als een byte
DIM X AS WORD
DIM Y AS BYTE
DIM FLAG1 AS BIT
DIM FLAGR AS BIT
RED = 10
FLAG1 = 0
CLS
PRINT AT 1,1,"in bedrijf...."
DELAYMS 2000
CLS
ON_HARDWARE_INTERRUPT GOTO Flash
' Assign some Interrupt associated aliases
SYMBOL T0IE = INTCON.5 ' TMR0 Overflow Interrupt Enable
SYMBOL T0IF = INTCON.2 ' TMR0 Overflow Interrupt Flag
SYMBOL GIE = INTCON.7 ' Global Interrupt Enable
SYMBOL PS0 = OPTION_REG.0 ' Prescaler ratio bit-0
SYMBOL PS1 = OPTION_REG.1 ' Prescaler ratio bit-1
SYMBOL PS2 = OPTION_REG.2 ' Prescaler ratio bit-2
SYMBOL PSA = OPTION_REG.3 ' Prescaler Assignment (1=assigned to WDT 0=assigned to oscillator)
SYMBOL T0CS = OPTION_REG.5 ' Timer0 Clock Source Select (0=Internal clock 1=External PORTA.4)
SYMBOL LED = PORTA.1
GOTO Over_interrupt ' Jump over the interrupt subroutine
' Interrupt routine starts here
Flash:
X = 0
T0IF = 0 ' Clear the TMR0 overflow flag
IF RED > 1 THEN HIGH PORTA.1
FOR X = 0 TO 255
IF X > RED THEN LOW PORTA.1
NEXT
CONTEXT RESTORE ' Restore the registers and exit the interrupt
Over_interrupt:
' Initiate the interrupt
GIE = 0 ' Turn off global interrupts
PSA = 0 ' Assign the prescaler to external oscillator
PS0 = 0 ' Set the prescaler
PS1 = 0 ' to increment TMR0
PS2 = 1 ' every 32th instruction cycle
T0CS = 0 ' Assign TMR0 clock to internal source
TMR0 = 0 ' Clear TMR0 initially
T0IE = 1 ' Enable TMR0 overflow interrupt
GIE = 1 ' Enable global interrupts
Inf:
waarde = HRSIN , {20000 , timeout}
IF waarde != 13 THEN PRINT AT 1,1,waarde
HRSOUT waarde 'stuur de waarde die opgehaald is weer serieel uit (rs232)
IF waarde = 114 THEN FLAGR = 1
IF FLAGR = 1 AND FLAG1 = 0 THEN RED = RED + 1
IF RED > 254 THEN RED = 255
IF RED > 254 AND FLAGR = 0 THEN FLAG1 = 1
IF FLAG1 = 1 AND FLAGR = 1 THEN RED = RED - 1
IF RED < 1 THEN RED = 1
IF RED < 2 AND FLAGR = 0 THEN FLAG1 = 0
FLAGR = 0
PRINT AT 2,1, DEC RED
timeout:
GOTO Inf
END
ehh..schopje..
Ik heb nog geen oplossing gevonden. Wanneer ik het zonder interrupt doe heb ik een flikker in de software matige pwm.
Tevens heb ik nog de usart interrupt gebrobeerd, maar dit zorgt er ook voor dat op het moment van de interrupt de pwm stil ligt. Hierdoor is er ook een flikker te zien bij iedere bediening.
Heeft er iemand een idee om de software matige pwm van 0 -5V mogelijk te maken? Dit terwijl de usart niet voor onderbreking van de pwm zorgt?
Alvast bedankt
WilToyo
Maak me niet gek, ik ben al gek.
Heeft dat ding geen hardwarematige PWM. Ben je van alle ellende af. Is ook nog eens makkelijker aan te sturen.
Er zitten een aantal fundamentele fouten in je programma. Ten eerste heeft deze PIC gewoon een hardware PWM, maar buiten dat is het een heel slecht idee om zware dingen te doen in je interrupt handler. Op een PIC is zo'n FOR loop al heel snel een slecht plan.
Om softwarematig PWM te doen zul je moeten spelen met de timer. Een goed plan is bijv om de timer in te stellen op het volgende punt dat je wilt triggeren. Stel dat je een precisie 256 wilt, en elke 32 cycles een interrupt wilt doen. Dan is je totale PWM cycle 256 * 32 = 8192 cycles. Met de interne 4MHz oscillator kom je dan op 4000000/8192 = 488Hz. Dit is meer dan genoeg voor een LEDje, deze frequentie kan je niet zien.
De implementatie van je ISR word dan zoiets als:
#define TMR0 *((volatile uint8_t*) 0x101)
void isr_tmr0{
static uint8_t led_out = 0;
if(led_out)
TMR0 = 0xFF - red;
else
TMR0 = red;
led_out ^= 0x1;
led(led_out);
}
Je vermindert je aantal interrupts en je doet geen processor zware dingen in je interrupt service routine.
Bedankt. Ik maak gebruik van een 16f648a en waardoor ik software pwm gebruik voor de 3 leds RGB. (vb was voor 1 ledje)
Ik was al bang dat het niet de bedoeling is om een for..next lus in een interrupt te plaatsen.... en ben dus ook op zoek naar een andere mogelijkheid om softwarematige pwm in de interrupt routine te doen.
Hoe schrijf je Het vb van Tristan in Basic? of is het beter om de interrupt routine in assembler te schrijven. Dit wel voor 3 uitgangen.... kan je hier gebruik maken van tmr0,1 en 2?
Alvast bedankt.
Zal eventjes een poging wagen, ik vermijd zoveel mogelijk BASIC, dus.
IF LED_OUT = 1 THEN
HIGH PORTA.1
LED_OUT = 0
TMR0 = RED 'Schedule next interrupt
ELSE
LOW PORTA.1
LED_OUT = 1
TMR0 = 255 - RED 'Schedule next interrupt
ENDIF
T0IF = 0 'Interrupt serviced, mark as such
CONTEXT RESTORE
Declareer LED_OUT eventjes als een globale variable (BYTE voldoet).
Je kunt je ISRs uiteraard gewoon in BASIC schrijven. Je zult er echter vrij snel achterkomen dat BASIC op een gegeven moment gewoon niet meer kan (qua timing, en qua kracht). Op dat moment schakel je om naar C en ASM, dit is de meest gebruikte combo (ja, combo) in embedded programmeren. Heel soms C++, maar dat is voor de grotere ARM producten.
[Bericht gewijzigd door Henry S. op (30%)]
Bedankt Tristan. Dit is voor mij een stuk duidelijker. Ik hoop in de toekomst wat meer kennis op te kunnen doen in assembler en/of C.
Nu is deze interrupt gebasseerd op de overflow van 1 timer. Nu heeft de 16f648A tmr0,1, en 2. Kan ik deze timers gebruiker om jouw code 3 x toe te passen?
[Bericht gewijzigd door Henry S. op (60%)]
Ja, dat kan. Het is echter niet erg efficient. Wat nu als je 4 LEDjes wilt aansturen? Ik laat het even als oefening aan de lezer over om de code zo te schrijven dat je drie LEDjes op 1 timer kan draaien. (Gezien dit toch een zelfbouw iets is, kan je d'r mooi iets van leren).
Hint: Gebruik een array. Een array is een lijstje met waarden.
Als je d'r niet uitkomt wil ik 't wel even voor je uitschrijven, maar het is leuker om er zelf achter te komen 
[Bericht gewijzigd door Henry S. op (31%)]