Thanks Henrik.
I will need to wade through this tomorrow...oops, it is already tomorrow!
I will get back to you after I have had some time to digest it and put it into action
Cheers
Barry
VK2XBP
Thanks Henrik.
I will need to wade through this tomorrow...oops, it is already tomorrow!
I will get back to you after I have had some time to digest it and put it into action
Cheers
Barry
VK2XBP
Hi Henrik,
I loaded the following code into my'684 and wired it up on my breadboard with a 2 x 16 LCD.
I adjusted the speed of the motor such that the pulse train frequency from the photo interruptor was under 200Hz.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 newCount var byte newCount = 0 Main: newCount = TMR0 - newCount lcdout $FE, 1 LCDOUT "TMR0 Count: ", #TMR0 LCDOUT $FE, $C0 LCDOUT "Count since: ", #newCount Pause 1000 Goto Main
Each loop of the main program gives me a valid reading for #TMR0 and #newCount but there is no correlation between the numbers.
To be honest, I don't really see how there could be. TMR0 doesn't appear to be reset anywhere so it should just roll over from 255 to 0 each time the maximum count is reached.
When/how does TMR0 start and stop counting?
You did say in your last post that we would take this "one step at a time."
First step completed - we are now counting pulses. What next?
If I understand the process correctly, we need to set up one timer (say TMR0) as an accurate interval timer (say 10ms) and the other timer (TMR1) as a counter for the pulses. As the interval timer ends its cycle, the value of the counter is returned as ADValue for the PID routine. Am I on the right path here?
I look forward to your "next step" suggestions.
Cheers
Barry
VK2XBP
Hi Barry,
TMR0 starts counting as soon as you set to BE a counter (OPTION_REG.5=1) and it will keep counting the incoming pulses. It will overflow att 255->0. The idea was that, because both newCount and TMR0 is a BYTE, that it will/should automatically give you the correct result but I think I may have made a little mistake there.
Lets try this instead:When we have TMR0 counting pulses reliably we'll move to the next step which will be set TMR1 up to generate an interrupt periodically (using DT Ints). This interrupt will then "capture" the current count, calculate the "speed" using the above code and run the PID-loop. But lets make sure we have TMR0 and the code above working properly first. Basically it should now display the frequency of the incoming signal but the timebase will be a bit off due to LCDOUT statements taking a bit of time on top of the PAUSE 1000.Code:newCount VAR BYTE oldCount VAR BYTE newCount = 0 oldCount = 0 Main: newCount = TMR0 - oldCount oldCount = TMR0 LCDOUT "TMR0 Count: ", #TMR0 LCDOUT $FE, $C0 LCDOUT "Count since: ", #newCount Pause 1000 Goto Main
/Henrik.
All good Henrik.
It is nice and stable and giving me a good frequency output.
I verified the result by inputing a 10Hz and then 100Hz square wave from my signal generator and the result was within 1Hz.
Let's go to Step 2
Cheers
Barry
VK2XBP
Great! Now lets put that on hold for a bit and see if we can get a timer interrupt going - then we'll glue it together.
I am a bit worried about the somewhat limited amount of RAM on '684 but we'll just have to see. I won't try to go into too much detail about DT-Ints, there's been several threads and several examples on the forum and obviosuly on Darrels site. If you don't already have the needed files you get them here. Place them either in the project directory or in the root folder of your PBP installation.
TMR1 is a 16bit timer and it causes an interrupt (if enabled) at rollover from $FFFF to 0. If we would let the timer free-run we'd get an interrupt every 65536th instruction cycle. At 8Mhz, that would be every 32.768ms or a frequency of ~30.5 Hz. If we want any other frequency we need to make sure that the timer doesn't start at 0 but at some other value. This is done by preloading the timer inside the interrupt service routine.
At 8Mhz one instruction cycle is 500ns. If we want an interrupt frequency of 100Hz we need the timer to roll over every 10ms, or once every 20000 instruction (20000*500ns=10ms). Because the timer interrupt when it rolls over we use 65536-20000=45536.
OK, now the code:The main routine in the above code will blink LED1 at 0.5Hz. The timer interrupt should cause LED2 to blink at ~5Hz. The code compiles here but I haven't tested it. Obviosuly you need to add your CONFIG, TRIS, ANSEL, CMCON, whatever at the top too.Code:' 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 PortC.4 LED2 VAR PortC.5 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 ' 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 T1CON.0 = 1 ' Start timer If IntCount = 19 THEN Toggle LED2 IntCount = 0 ENDIF @ INT_RETURN
Give it a go, see if you can calculate and set the desired frequency.
/Henrik.
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 ? ;-)
Bookmarks