Thanks Henrik.
It looks good but I can't see how LED2 will ever toggle. I think there should be a line
IntCount = IntCount + 1
somewhere within the interrupt routine.
Anyway, I will have a play with it and let you know how I go.
Cheers
Barry
VK2XBP
Thanks Henrik.
It looks good but I can't see how LED2 will ever toggle. I think there should be a line
IntCount = IntCount + 1
somewhere within the interrupt routine.
Anyway, I will have a play with it and let you know how I go.
Cheers
Barry
VK2XBP
Definitely so. Somehow that fell out of there.....
Why do you need me for this ? ;-)
Nice job Henrik.
LED1 will toggle LED1 every 1 second not 0.5 (based on correct 8MHz clock).
Ioannis
Hi Henrik,
All good so far - Step 2 complete.
I have the leds blinking and have modified the code to display Frequency (averaged over a ten cycle loop) on the LCD as follows:
OK, I appreciate that the Frequency readout isn't really the true frequency but I just wanted to prove the averaging routine.Code:' Define LCD registers and bits Define LCD_DREG PORTC Define LCD_DBIT 0 Define LCD_RSREG PORTA Define LCD_RSBIT 5 Define LCD_EREG PORTC Define LCD_EBIT 4 Define LCD_BITS 4 Define LCD_LINES 2 CMCON0 = %00000111 ' Disable comparators ANSEL = %00000000 ' Set PORTA as digital I/O TRISC = 0 ' Set PORTC as output TRISA.1 = 0 ' Make TOCKI input OPTION_REG.0 = 0 ' Prescaler 1:1 OPTION_REG.1 = 0 ' OPTION_REG.2 = 0 ' OPTION_REG.3 = 1 ' Prescaler assigned to WDT OPTION_REG.4 = 0 ' Increment on low-to-high transition OPTION_REG.5 = 1 ' Clock on T0CKI-pin OPTION_REG.6 = 0 ' OPTION_REG.7 = 1 ' OSCCON = %01110101 ' Set clock frequency to 8MHz define OSC 8 ' Included the interrupt system INCLUDE "DT_INTS-14.bas" INCLUDE "ReEnterPBP.bas" ' When compiling for the 16F684 DT-Ints tells us to add these variables so we do that wsave VAR BYTE $20 SYSTEM wsave1 VAR BYTE $A0 SYSTEM TMR1_Reload CON 45536 ' Reload value for ~100Hz interrupt frequency at 8MHz, prescaler 1:1 TMR1_Temp VAR WORD ' Temporary variable use for reloading the timer IntCount VAR BYTE ' Keep track of number of interrupts oldCount VAR BYTE newCount VAR BYTE Frequency VAR WORD UpdateDisplay VAR BIT LED1 VAR PortA.0 LED2 VAR PortA.1 ASM INT_LIST macro ; IntSource, Label, Type, ResetFlag? INT_Handler TMR1_INT, _ISR, PBP, yes endm INT_CREATE ; Creates the interrupt processor ENDASM T1CON.0 = 1 ' Start TMR1 @ INT_ENABLE TMR1_INT ; Enable Timer 1 Interrupts Main: ' Toggle LED1 ' Pause 1000 ' Goto Main if intCount = 0 then LCDOUT $FE, $02, "NewCount: ", #newCount, " " LCDOUT $FE, $C0 LCDOUT "Frequency: ", #Frequency, " " Frequency = 0 endif Goto Main ' This is the interrupt routine for the TMR1 interrupt. ISR: T1CON.0 = 0 ' Stop timer TMR1_Temp.HighByte = TMR1H ' Get current "time" TMR1_Temp.LOWBYTE = TMR1L TMR1_Temp = TMR1_Temp + TMR1_Reload ' Add reload value to get correct interval TMR1H = TMR1_Temp.HIGHBYTE ' Move result back to timer TMR1L = TMR1_Temp.LOWBYTE newCount = TMR0 - oldCount oldCount = TMR0 T1CON.0 = 1 ' Start timer IntCount = INtCount + 1 ' Increment interrupt counter Frequency = Frequency + newCount If IntCount = 9 THEN Frequency = Frequency/10 IntCount = 0 ENDIF @ INT_RETURN
Onwards and upwards... What's next?
Cheers
Barry
VK2XBP
Ioannis,
Not sure I understand.... it will toggle LED1 once every second which means it will blink at 0.5Hz - isn't that what I wrote?
Barry,
Excellent! I wouldn't check IntCount in the main routine like that. Instead I'd check IntCount in the ISR and set a flag (UpdateDisplay or whatever). The main routine then checks this flag, executes the code and resets the flag. The reason for this is that when the code grows the Main routine may "miss" the when IntCount=0 (depending on what else it has to do and how long it takes). If you instead use the flag/semaphore method the Main routine WILL see that it's time to update display - when it gets around to it.
OK, now that you have a stable time base and the pulses counted in hardware it's time to add in the PID again. The ISR would look something like:Your setpoint in this case is pulses per interrupt period, not actual frequency in Hz.Code:ISR: T1CON.0 = 0 ' Stop timer TMR1_Temp.HighByte = TMR1H ' Get current "time" TMR1_Temp.LOWBYTE = TMR1L TMR1_Temp = TMR1_Temp + TMR1_Reload ' Add reload value to get correct interval TMR1H = TMR1_Temp.HIGHBYTE ' Move result back to timer TMR1L = TMR1_Temp.LOWBYTE T1CON.0 = 1 ' Start timer ' Get the current motor velocity newCount = TMR0 - oldCount oldCount = TMR0 ' Calculate error and run PID pid_Error = SetPoint - newCount GOSUB PID IntCount = IntCount + 1 ' Increment interrupt counter If IntCount = 9 THEN UpdateDisplay = 1 IntCount = 0 ENDIF @ INT_RETURN
And the Main routine perhaps something like:This is untested but I'm sure you'll get the idea.Code:UpdateDisplay VAR BIT Main: If UpdateDisplay THEN 'LCDOUT..... 'LCDOUT..... UpdateDisplay = 0 Goto Main
/Henrik.
Ooops, yes Henrik. Sorry about that. Thought it was 0.5 second and not Hz as you stated.
Ioannis
OK, now I am a little confused....
You said that Setpoint now becomes pulses per interrupt period but how is this referenced to the ADCin result of my speed set trimpot?
Shouldn't the setpoint always be derived from the setting of the speed set trimpot and the error be calculated from the pulses per interrupt period?
Cheers
Barry
VK2XBP
Yes, what I mean is that if you previously had your setpoint scaled directly in Hz it now needs to be scaled in pulses/interrupt period.
/H.
Bookmarks