Oh...that is just tooooo coool!!! :-D
Love these toys!!!
Thanks Henrik!!
Oh...that is just tooooo coool!!! :-D
Love these toys!!!
Thanks Henrik!!
Hi Darrel and Hendrick,
I'm still moving along dabbling with this project.
Since I have the 16F887A in a LABX-1 project board, and I had a 12F683 mounted in a bread-board, I decided for convenience to see if I can make another step in this project using the 12F683. I got the 32khz crystal up and running on Timer1. By loading a preset value into Timer1's hi-byte, I can initiate the the frequency counting gate and Timer1 will interrupt right at 1Sec. (close enough on my Oscope).
So then I moved to add using Timer0 as the counter for the external frequency.
I'm only playing with a max input frequency of 300Khz right now, so I can utilize the PICs internal oscillator.
The following code is my progress.
It doesn't yet have the step of capturing the remainder value within Timer0.
Just got the point of attempting to counting Timer0 overflows.
But since I added the Timer0 register settings, it appears that I can't shut off the Timer1 overflow no matter what I do. Its supposed to display the timer0 overflow count and then go into a forever loop. But it keeps popping back up to "Display_Results". So I suspect timer1 is still initiating the interrupt routine.
Code:' Name : Frequency Counter Clock in Timer0 - Gate with Timer1 ' Compiler : PICBASIC PRO Compiler 2.6 ' Assembler : PM or MPASM ' Target PIC : PIC12F683 ' Hardware : 32.768khz crystal on OSC1-ISC2 for 1sec gate ' Oscillator : 4MHz internal osc for PIC ' Keywords : ' Language : PICBASIC PRO ' ' VDD --- 1|----|8--- vSS ' GP5/TICKI/OSC1/CLKIN --- 2|----|7--- GP0/AN0/CIN+/ICSPDAT/ULPWU ' GP4/AN3/T1G/OSC2/CLKOUT --- 3|----|6--- GP1/AN1/CIN-/VREF/ICSPCLK ' GP3/MCLR/VPP --- 4|----|5--- GP2/AN2/T0CKI/INT/COUT/CCP1 '------------------------------------------------------------------------ Include "modedefs.bas" ' Include serial modes for LCD display define osc 4 OSCCON = %01100100 ' internal oscillator at 4 MHZ runs the pic CMCON0 = 7 ' Comparators off ANSEL = 0 ' Set all digital WPU = 0 ' Internal pull-ups = off GPIO = %00000000 ' clear GPIO port TRISIO = %00000100 ' All outputs except gpio.2 (input to frequency) CCP1CON=0 ' ccpm module off LCD var GPIO.1 'use GPIO1 pin 6 to LCD display GATE var byte 'variable for 1 second gate flag TMR_CNT var word 'variable for counting timer0 overflows on interrupt goto TMR1_INT 'setup Timer0 option_register OPTION_REG = %10100111 'bit 7 pullups disabled 'bit 6 don't care 'bit 5 Transition on TOCKI pin 'bit 4 Increment on low to high TOCKI pin 'bit 3 Prescaller assigned to TIMER0 'bit 2-0 Prescaller setting 1:256 INTCON.2 = 0 'set Timer0 ovrflow flag zero TMR0 = 0 'clear the Timer0 counter register 'clear Timer1 interrupt registers T1CON.0 = 0 'TMR1ON disable interrupts for now TMR1L = 0 'clear lower 8 bits of Timer1 counter INTCON = 0 'clear the system interrupt control register PIR1 = 0 'clear the system interrup flag bits register PIE1 = 0 'clear perephrial interrupt enable register pause 1000 'configure Timer1 interrupt settings T1CON.3 = 1 'T1OSC of the T1CON register enabled PIE1.0 = 1 'Timer1 overflow enable bit enabled INTCON.6 = 1 'Perephrial enable bit set to enable INTCON.7 = 1 'GIE Global interrupt enable bit enabled T1CON = 14 'T1OSCEN enable 'T1Sync disabled 'TMR1CS external source for Timer1 TMR1H = 207 'preload hi-byte of Timer1 counter so 'when interrupt occurs with 32khz crystal 'on OSC1 + OSC2, it will be 1 second T1CON.0 = 1 'T1CON.TMR1ON Timer1 enabled *NOW* GATE = 1 main: while GATE > 0 'After 1 Second Gate interrupt this ends @ BTFSC INTCON,2 ;Test Timer0 overflow flag bit @ incf _TMR_CNT,f ;If flag set then increment TMR_CNT by 1 @ BTFSC INTCON,2 ;Test Timer0 overflow flag bit again @ BCF INTCON,2 ;If flag set then clear it wend Display_Results: serout LCD,T9600, [#TMR_CNT] pause 2000 loop_here: goto loop_here ' ************ TIMER1 GATE INTERRUPT ROUTINE AFTER 1 SEC ************** disable TMR1_INT: GATE = 0 T1CON.0 = 0 'TMR1ON disable interrupts for now INTCON = 0 'clear the system interrupt control register PIR1 = 0 'clear the system interrup flag bits register PIE1 = 0 'clear perephrial interrupt enable register INTCON.2 = 0 'set Timer0 ovrflow flag zero INTCON.7 = 0 'GIE OFF - Turn off all Interrupts resume 'goto main End
Last edited by Darrel Taylor; - 17th February 2014 at 18:44. Reason: Fixed Archangel's code tags
For this project ... you should not be using interrupts.
Especially not ON INTERRUPT. There's no guaranteed timing with ON INTERRUPT.
207 isn't a good value to load in the Timer.
Since the Timer will normally overflow in 65536 counts, you just need to set bit-7 of the high byte to make it overflow in 32768 counts.
With a 32768 Hz crystal, it will overflow in exactly 1 second.
Timer1 doesn't free-run. You need to stop and start it so that you can synchronize the Timer0 Gate output with Timer1's 1 second window.
Since the PIC's changed now, the oscillator's changed and interrupts are introduced ...
I think I'll just post my code for the 877A simulation in post #5.
Hopefully you can convert it for your needs with a different PIC.
Code:; DT_FREQy.pbp ; ; Created : Mon Feb 3 2014 ; Processor : PIC16F877A ; Compiler : PicBasic Pro 3.0 ;----[Device Configuration]--(See manual section 4.9)--------------------------- #CONFIG __config _HS_OSC & _WDT_OFF & _PWRTE_OFF & _BODEN_OFF & _LVP_OFF & _CPD_OFF & _WRT_OFF & _DEBUG_OFF & _CP_OFF #ENDCONFIG ;----[DEFINEs]------------------------------------------------------------------ DEFINE OSC 20 DEFINE LCD_DREG PORTD ; LCD data port DEFINE LCD_DBIT 4 ; LCD data starting bit 0 or 4 DEFINE LCD_RSREG PORTD ; LCD register select port DEFINE LCD_RSBIT 2 ; LCD register select bit DEFINE LCD_EREG PORTD ; LCD enable port DEFINE LCD_EBIT 3 ; LCD enable bit DEFINE LCD_BITS 4 ; LCD bus size 4 or 8 DEFINE LCD_LINES 2 ; LCD Number lines on LCD DEFINE LCD_COMMANDUS 2000 ; LCD Command delay time in us DEFINE LCD_DATAUS 50 ; LCD Data delay time in us ;----[Aliases]------------------------------------------------------------------ Timer1 VAR WORD EXT : @Timer1 = TMR1L TMR0IF VAR INTCON.2 TMR0CS VAR OPTION_REG.5 TMR1IF VAR PIR1.0 TMR1CS VAR T1CON.1 ; Timer1 Clock Source Select bit T1OSCEN VAR T1CON.3 ; Timer1 Oscillator Enable Control bit TMR1ON VAR T1CON.0 ; Timer1 On bit T1OSI VAR PORTC.1 ; 32768 Hz input pin PSCLKOUT VAR PORTA.3 ; pin to clock out the remaining prescaler PSA VAR OPTION_REG.3 ; Prescaler Assignment bit ;----[Variables]---------------------------------------------------------------- Result VAR WORD[2] ; Final 32-bit Frequency measurement T0overflow VAR Result[1] ; Counts Timer0 overflows (HighWord of the result) T0value VAR Result.BYTE1 ; Final Timer0 value PScount VAR Result.BYTE0 ; Final Timer0 Prescaler value FreqHigh VAR WORD ; Top five digits of the decimal result FreqLow VAR WORD ; Bottom 3 digits of the decimal result MeasCount VAR WORD ; Counts number of measurements ;----[Initialize]--------------------------------------------------------------- ADCON1 = 7 ; All Digital CMCON = 7 T1OSCEN = 1 ; Start Timer1 oscillator PAUSE 250 ; LCD Power-Up delay LCDOUT $FE,1,"DT's FREQy" MeasCount = 0 ; clear the measurement count ;----[Main Program Loop]-------------------------------------------------------- Main: GOSUB MeasureFreq ; Get a Frequency Measurement GOSUB DisplayFreq ; Display the Frequency MeasCount = MeasCount + 1 ; increment and display measurement count LCDOUT $FE,$94,"Meas = ", DEC MeasCount GOTO Main ;----[Measure frequency on T0CKI]----------------------------------------------- MeasureFreq: LOW PSCLKOUT ; prevent signal from getting to Timer0 PSA = 0 ; Prescaler is assigned to the Timer0 module TMR0CS = 1 ; Transition on T0CKI pin TMR1CS = 1 ; Timer1 Clock source = T1CKI (T1OSC) TMR1ON = 0 ; Stop Timer1 TMR0IF = 0 ; Clear Timer0 overflow flag T0overflow = 0 ; Clear Timer0 overflow count TMR0 = 0 ; Clear Timer0 value Timer1 = $FFFF ; Timer1 overflows on next cycle of 32768 Hz clock TMR1IF = 0 ; Clear Timer1 overflow flag TMR1ON = 1 ; Start Timer1 1 sec. period WHILE !TMR1IF : WEND ; Synchronize to 32768 clock INPUT PSCLKOUT ; Start counting freq input Timer1.15 = 1 ; Set Timer1 to 32768 for 1 Sec. period TMR1IF = 0 ; Clear Timer1 overflow flag WHILE !TMR1IF ; while 1 sec. window is open ---| IF TMR0IF THEN ; count TMR0 overflows | This section T0overflow = T0overflow + 1 ; | does the actual TMR0IF = 0 ; | 1-Sec measurement ENDIF ; | Window WEND ; ---| LOW PSCLKOUT ; Stop further counting T0value = TMR0 ; get Timer0 value PScount = 0 ; Clock out remaining prescaler WHILE TMR0 = T0value ; until TMR0 value changes HIGH PSCLKOUT PAUSEUS 3 LOW PSCLKOUT PAUSEUS 3 PScount = PScount + 1 WEND PScount = -PScount ; negate to get prescaler count RETURN ;----[Display frequency on LCD]------------------------------------------------- DisplayFreq R2 = Result ; Load Result into PBP's system vars for DIV32 R0 = Result[1] FreqHigh = DIV32 1000 ; get left most 5 digits FreqLow = R2 ; remainder (R2) is right 3 digits LCDOUT $FE,$C0,"Freq = " IF FreqHigh > 0 THEN ; if any left digits LCDOUT DEC FreqHigh, DEC3 FreqLow," " ; display both left and right ELSE ; otherwise LCDOUT DEC FreqLow," " ; display only right digits ENDIF RETURN END
Last edited by Darrel Taylor; - 17th February 2014 at 20:34.
DT
Thanks Darrel!!
I think I'll try to figure out how to mount the 32khz crystal onto the Labx-1 board.
I may be able to create a small pcb with headers that I can plug into the female header pins on the side of the 887a.
I should be able to see the 32khz oscillator with an Oscope to verify its running.
Interesting, I did play with loading different values into the high byte of Timer1s counting register and had it pull a pin high for the duration until timer1 rolled over and into the interrupt routine. 207 was what gave me a 1 sec pulse.
So I assumed it was the right number to load.
Thanks again for providing the code.
It will be super fun to try it out :-]
Duane
I had a question...but connected the dots when I posted it.
Last edited by dw_picbasic; - 19th February 2014 at 22:12. Reason: tried to remove the question....got it :-]
Hi Darrel,
I'm curious about something in the code
I see that you capture the Timer1 overflow count and load it into RESULTS.[bit16-31]
Then load the remaining count in TMR0 into RESULTS.[bit8-15]
But I thought that TMR0 is a 16 bit register....how is it we're loading its value into an 8 bit location in RESULTS?
Thanks!!
Duane :-]
Hi Duane,
No, the TMR0 register is only 8 bits wide, that's why you need to use the trick with getting the remaining count out of the prescaler.
So, RESULT is a total of 4 bytes where the two most significant bytes are the number of TMR0 overflows, the next byte is the TMR0 count (where each count equals 256 transitions of the inputsignal due the 1:256 presacaler ratio) and the least significant byte is the number of transitions "stored" in the prescaler.
/Henrik.
Bookmarks