Also:
;-------------------------------------------------------------------------; ; SHOTMR0.ASM Show TMR0 in decimal on LCD after counting 1 second ; ;-------------------------------------------------------------------------; LIST P=16F84 ; 16F84 Runs at 4 MHz INCLUDE "p16f84.inc" __CONFIG _PWRTE_ON & _LP_OSC & _WDT_OFF ; uses 32.768 kHz crystal ERRORLEVEL -224 ; supress annoying message because of tris ERRORLEVEL -302 ; supress message because of page change ; Define Information #DEFINE RS PORTA, 0 ; RA0 is RS line of LCD #DEFINE E PORTA, 1 ; RA1 is E line of LCD ; RB0-RB3 are D4-D7 of LCD ; Macro EStrobe MACRO ; Strobe the "E" Bit bsf E bcf E ENDM CBLOCK 0CH Temp ; a temporary variable count ; counter precount ; holds value for prescalar bin ; binary number to be converted to BCD hundreds ; BCD hundreds result tens_and_ones ; BCD tens and ones result ENDC ORG 0 ; start at location 0 goto main ; jump over to main routine ;-------------------------------------------------------------------------; ; Data for message to be output ; ;-------------------------------------------------------------------------; shomsg: ; Message to Output addwf PCL, f ; Output the Characters m0 dt "TMR0 Value:", 0 m1 dt "Multiply by:", 0 ;-------------------------------------------------------------------------; ; Ratios of Prescaler ; ;-------------------------------------------------------------------------; preratio: addwf PCL, f ; select offset using W dt D'2',D'4',D'8',D'16',D'32',D'64',D'128' ;-------------------------------------------------------------------------; ; Initialize the ports ; ;-------------------------------------------------------------------------; Init: clrf PORTA clrf PORTB movlw B'00010000' ; RA4 input, others outputs tris PORTA movlw B'00110000' ; RB4, RB5 input, others outputs tris PORTB movlw B'00100001' ; pull-ups enabled ; prescaler assigned to RA4 ; prescaler set to 1:4 option clrf precount return ;-------------------------------------------------------------------------; ; Initialize the LCD ; ;-------------------------------------------------------------------------; initlcd: movlw D'40' call nmsec ; Wait 40 msecs before Reset bcf RS ; send an 8 bit instruction movlw 0x03 ; Reset Command call NybbleOut ; Send the Nybble call Dlay5 ; Wait 5 msecs before Sending Again EStrobe nop nop ; Wait 244 usecs before Sending the Second Time EStrobe nop nop ; Wait 244 usecs before Sending the Third Time bcf RS ; send an 8 bit instruction movlw 0x02 ; Set 4 Bit Mode call NybbleOut nop nop movlw 0x028 ; 4 bit, 2 Line, 5x7 font call SendINS movlw 0x010 ; display shift off call SendINS movlw 0x001 ; Clear the Display RAM call SendINS call Dlay5 ; Note, Can take up to 4.1 msecs movlw 0x006 ; increment cursor call SendINS movlw 0x00C ; display on cursor off call SendINS return ;-------------------------------------------------------------------------; ; Send the character in W out to the LCD ; ;-------------------------------------------------------------------------; SendASCII addlw '0' ; Send nbr as ASCII character SendCHAR ; Send the Character to the LCD movwf Temp ; Save the Temporary Value swapf Temp, w ; Send the High Nybble bsf RS ; RS = 1 call NybbleOut movf Temp, w ; Send the Low Nybble bsf RS call NybbleOut return ;-------------------------------------------------------------------------; ; Send an instruction in W out to the LCD ; ;-------------------------------------------------------------------------; SendINS ; Send the Instruction to the LCD movwf Temp ; Save the Temporary Value swapf Temp, w ; Send the High Nybble bcf RS ; RS = 0 call NybbleOut movf Temp, w ; Send the Low Nybble bcf RS call NybbleOut return ;-------------------------------------------------------------------------; ; Send the nibble in W out to the LCD ; ;-------------------------------------------------------------------------; NybbleOut ; Send a Nybble to the LCD movwf PORTB EStrobe ; Strobe out the LCD Data nop nop return ;-------------------------------------------------------------------------; ; Output the message on the LCD ; ;-------------------------------------------------------------------------; OutMessage: movwf FSR ; Point at first letter OutLoop: movf FSR, w ; Get pointer into W incf FSR, f ; Set up for next letter call shomsg ; Get character to output iorlw 0 ; At the End of the Message? btfsc STATUS, Z ; Skip if not at end return ; Yes - Equal to Zero call SendCHAR ; Output the ASCII Character goto OutLoop ; Get the next character ;-------------------------------------------------------------------------; ; Change binary nbr in bin to BCD ; ;-------------------------------------------------------------------------; binary_to_bcd ; by Scott Dattalo clrf hundreds swapf bin, W addwf bin, W andlw B'00001111' skpndc addlw 0x16 skpndc addlw 0x06 addlw 0x06 skpdc addlw -0x06 btfsc bin,4 addlw 0x16 - 1 + 0x6 skpdc addlw -0x06 btfsc bin,5 addlw 0x30 btfsc bin, 6 addlw 0x60 btfsc bin,7 addlw 0x20 addlw 0x60 rlf hundreds, f btfss hundreds, 0 addlw -0x60 movwf tens_and_ones btfsc bin,7 incf hundreds, f return ;-----------------------------------------------------------------------; ; Delay routine ; ;-----------------------------------------------------------------------; msec250 movlw 0 ; 250 msec delay (adjusted to try and ; allow for 2.5% low loop time) goto $+2 Dlay5 movlw 5 ; delay for 5 milliseconds nmsec: ; delay for # msec in W on entry nop ; each nop is 0.122 milliseconds nop nop ; each total loop is 8 X 0.122 = 0.976 msec nop addlw H'FF' ; same as subtracting 1 from W btfss STATUS, Z ; skip if result is zero goto nmsec ; this is 2 X 0.122 msec return ; back to calling point ;-------------------------------------------------------------------------; ; Display binary value in W in decimal ; ; ;-------------------------------------------------------------------------; DispDec movwf bin call binary_to_bcd movf hundreds, W call SendASCII swapf tens_and_ones, W andlw H'F' call SendASCII movf tens_and_ones, W andlw H'F' call SendASCII return ;-------------------------------------------------------------------------; ; Return the prescalar ratio setting in W ; ;-------------------------------------------------------------------------; getpre: bsf STATUS, RP0 ; change to page 1 movf OPTION_REG, W ; get OPTION register bcf STATUS, RP0 ; back to page 0 andlw 7 ; get 1st 3 bits in W return ;-------------------------------------------------------------------------; ; Check pushbuttons and increment or decrement prescalar ; ;-------------------------------------------------------------------------; ckbuttons: call getpre ; get prescalar ratio # in Temp movwf Temp btfss PORTB, 4 ; Skip if button on RB4 up goto preup ; increment prescalar btfss PORTB, 5 ; Skip if button on RB5 up goto predown ; decrement prescalar return ; no buttons pressed, return preup: incf Temp, f ; up one btfsc Temp, 3 ; if reach 8, go back to zero clrf Temp goto newpre ; and fix new ratio predown: decf Temp, f ; down one movlw H'FF' ; check for underflow subwf Temp, W btfss STATUS, Z ; skip if underflow goto newpre ; and fix new ratio movlw 7 ; reset to 7 movwf Temp newpre bsf STATUS, RP0 ; change to page 1 movlw B'11111000' ; mask out low three bits andwf OPTION_REG, W ; result in W bcf STATUS, RP0 ; back to page 0 iorwf Temp, W ; add in new prescalar ratio # option ; update OPTION return ;-------------------------------------------------------------------------; ; The Main routine ; ;-------------------------------------------------------------------------; main: call Init ; initialize ports, set up timer call initlcd ; initialize the LCD movlw H'80' ; position at 1st line column 0 call SendINS movlw m0 -2 ; send 'TMR0 Value:' message call OutMessage movlw H'C0' call SendINS ; position at 2nd line column 0 movlw m1 -2 ; send 'Multiply by:' message call OutMessage sholoop: call ckbuttons ; update prescalar if buttons pushed movlw H'CD' ; position at 2nd line column 13 call SendINS call getpre ; get prescalar ratio # in binary call preratio ; change to prescalar ratio call DispDec ; put it on LCD movlw H'8C' ; position at 1st line column 12 call SendINS bcf INTCON, T0IF ; clear timer zero interrupt flag clrf TMR0 ; zero TMR0 call msec250 ; wait a total of one second call msec250 call msec250 call msec250 movf TMR0, W ; retrieve timer zero btfsc INTCON, T0IF ; check if timer overflowed goto overload ; yes, display 'OVR' call DispDec ; display TMR0 value goto sholoop ; repeat forever overload movlw 'O' ; output 'OVR' call SendCHAR movlw 'V' call SendCHAR movlw 'R' call SendCHAR goto sholoop ; and continue end
Timer 0 can be set up to count pulses entering the pic on RA4. You can make
a simple 555 circuit as shown below to generate the pulses.
TMR0 can hold values only up to 255. What if the frequency is higher than this? The answer lies in the prescalar which is inserted between RA4 and TMR0 and provides division of the count by 2,4,8...256 depending on the lowest three bits in the OPTION register, (PS0-PS2). Changing this to 1:256 allows us to count frequency up through 64K. Pushbuttons are used to change the prescalar and the multiplying factor is shown on the display along with TMR0.
Since TMR0 is used to do the counting, it can't be used to provide a one second interval at the same time. We must rely on instruction time counting to get one second. The routine nmsec is not accurate. 1 millisecond turns out to be closer to 975 microseconds, 2.5 % low. We try to allow for this when calling msec250 by counting more than 250 loops. The maximum we can count using one byte is 256 by setting the intial value to 0. Actually this turns out to be pretty close to the value we need, (maybe a little long because of the calls, returns and other overhead). You might also try D'255'.
If the message 'OVR' is displayed instead of a value for TMR0, it means that timer 0 has overflowed and the prescalar must be set to a higher ratio. The button on RB4 moves the ratio up and the one on RB5 moves it down. No debouncing is necessary for these buttons because they are checked only once each second. It also means you have to hold the button down for a while to make it work. Multiply the value of TMR0 by the multiplier indicated to get the actual frequency.
There is a method to get higher precision, but it is a little involved. The residual count actually appears in the prescalar when counting is complete. The problem is that the prescalar can't be read directly as a register. What is usually done is to use another pin to pulse RA4, keeping track of the number of pulses until TMR0 overflows. Subtract this number from 256 and the result is the contents of the prescalar when counting was first terminated. The total count is then the ratio times TMR0 plus this residual. For an example of this, go to http://www.piclist.com/faq and click on 'PICList projects' and the 'Weeder Frequency Counter PIC16F84 port'.
The frequency of the 555 oscillator is determined by the resistors and capacitor used. This suggests that since we can measure frequency, we can measure an unknown capacitance if the reistance is known or vice-versa. Also, any property which varies one of these can be measured if we know how this property makes the frequency change. Think of some properties you might like to measure with this setup.
Interested:
Comments: