;-----------------------------------------------------------------------; ; BINCNT.ASM Counts in binary on LEDs ( RB0 - RB4 ) ; ;-----------------------------------------------------------------------; ;-----------------------------------------------------------------------; ; The next 6 lines are directions to the assembler ; ;-----------------------------------------------------------------------; LIST P=16F84 ; tells which processor is used INCLUDE "p16f84.inc" ; defines various registers etc. Look it over. ERRORLEVEL -224 ; supress annoying message because of tris __CONFIG _PWRTE_ON & _LP_OSC & _WDT_OFF ; configuration switches ORG 0 ; start a program memory location zero ;-----------------------------------------------------------------------; ; First we set up all bits of PORT A and B as outputs ; ; and set bits in the OPTION register concerning TMR0 ; ;-----------------------------------------------------------------------; movlw B'00000000' ; all bits low in W tris PORTA ; contents of W copied to PORT A ... tris PORTB ; and PORT B movlw B'00000100' ; pull-ups active ; prescalar assigned to TMR0 and set 1:32 option ; rolls over each second ;-----------------------------------------------------------------------; ; This is the main program ; ;-----------------------------------------------------------------------; clrf PORTB ; start with zero loop: incf PORTB, f ; add 1 to port B btfss INTCON, T0IF ; wait on T0IF to be set goto $ -1 bcf INTCON, T0IF ; clear the interrupt flag goto loop end ; end of program
There are three types of addresses in the '84 depending on which type of memory we are talking about.
These ports are controlled through port 'registers'. Microchip likes to call these 'file' registers and assigns them the letter 'f', (in general). Learn to manipulate the registers and you learn to program the PIC. Each port has 2 registers associated with it. PORTA and PORTB are the names of the registers that show the state of the pins, high or low. TRISA and TRISB are registers that indicate which pins are inputs and which are outputs.
This process is used in the above program to set up the ports. In the TRIS registers a 0 represents an output and a 1 an input. We want to set all pins to outputs. Pins set as inputs should always be pulled high or low. An input should never be left floating. Setting all pins as outputs takes care of those pins not connected to anything, (no inputs).
'movlw' stands for: move a literal, (number), into the 'W' register. We move the binary number B'00000000' into W in the first instruction. The binary representation lets you see all the bits.
Once the TRIS register bits are all set to outputs, the numbers we put in the PORT registers determines what levels are on the pins. 1's will make the pins high and 0's will make them low. We have LEDS on the 4 lowest bits of Port B, (RB0-RB3), so the lowest 4 bits in PORTB will determine if these are on, (1's), or off, (0's).
The 'clrf PORTB' instruction turns all the LED's off. It 'clears' the register named, (sets all bits to zero). In words: 'clear the indicated register'.
Another register TMR0, (timer zero), is involved in setting the delay between counts. TMR0 continually increments at a certain rate. When it gets to B'11111111' the next count 'rolls over' to B'00000000'. At this time a certain bit in the register INTCON, (T0IF), is 'set', (made 1). We can watch for this to happen and know that 256 counts have passed since TMR0 was at zero. The counts happen at a rate of the crystal frequency divided by four. For the watch crystal this means every 0.122 milliseconds.
The register INTCON has eight bits dealing with interrupts. The only one we are concerned with now is bit 2 which is the TMR0 overflow interrupt flag bit. If this bit is one, TMR0 has overflowed, if it is zero, it has not. You are responsible for resetting this flag yourself in your program once it has overflowed.
Testing a bit is done using an instruction that skips over then next instruction if the bit has a certain value. 'BTFSS' stands for: 'test the bit designated and skip the next instruction if the bit is 1, (set). If we make the next instruction a 'goto' then the program either goes to this new location if the bit is clear, (0) or continues on if it is 1. There is also the instruction 'BTFSC' which looks for a clear bit rather than a set bit. The designated bit can be a number, (0-7), or a symbol which is equated with a number such as 'T0IF' in this case. The number is assigned to T0IF in the file "p16F84.inc" which was included at the top of the program.
Normally instructions are carried out in sequence. To break up this sequence and go to another location we use the 'goto' instruction. This instruction usually contains a label which tells where to go next. A variation on this is the use of '$' which stands for current instruction. Adding a -1 means go to the previous instruction, a +2 would be the one after the next and so on. The '$' convention is useful for short jumps. Longer jumps should use labels.
On power up, all bits of OPTION are set to 1. A '1' in bit 3, PSA, (prescalar assignment bit), assigns the prescalar to the watchdog timer rather than TMR0. We definately want that one to be '0'. A '1' in bit 5, T0CS, (timer zero clock source select bit), makes the register TMR0 respond to transitions on pin 3 of the PIC, (RA4). We want that one to be zero also. In the program listing, you can see where W is set to B'00000100' and put into OPTION.
Does the pattern of incrementing binary numbers make sense to you? If you need a refresher on numbering systems you could try: http://www.chesworth.com/pv/technical/computing_numbers.htm Watch the counter until you are familiar with the pattern. Can you guess what the pattern of the high 4 bits of PORTB is like? A single resistor and LED can be made into a probe that you can use to examine these port pins. A low current LED is nice for this because you don't have to worry about drawing too much from the pins.
How would you make the numbers decrement rather than increment? There is an instruction 'decf' which could replace the 'incf'. What happens after you reach zero? Could you add instructions to make the counting start at a particular number, say 10. You can represent a decimal ten as D'10'. The same number in hexidecimal is H'A'. In binary it is B'00001010'. Remember you usually have to go through 'W'.
How would you count only even numbers, (the rightmost LED would never come on). See if you can write and run the program. How about only odd numbers?
You could add four more LED's and count all the way to 255, but four should give you the idea of what is happening. Instead, why not stop when you reach 16, (H'10'), and start decrementing. You have seen the instruction 'btfss (register), (bit)'. See if you can use this to detect when bit 4, ( 5th from the right ), gets set and then start counting down.
But now, what happens at zero? You then want to start incrementing again. We need an 'btfss' that detects not when a certain bit is set but when no bits are set. There is a register that has such a bit. It is the 'Z ' bit of the STATUS register which is set when an instruction gives a result of zero. So use 'btfss STATUS, Z' and write a program that continually counts up and down between 0 and 15, (or 1 and 16 or whatever).
What if you want to 'roll' one lit LED across the display, by doing the number sequence 1,2,4,8,1,2,4,8 etc. Could you write a program to do it? There is an instruction that rolls all bits to the left one place. It is called 'rlf (register), f'. Use it to do the roll program. Then try adding btfss instructions to create the sequence 1,2,4,8,4,2,1,2,4 etc.
Interested:
Questions:
I have a problem with TMR0 instruction. Can you tell me how can I get the value of TMR0 since interrupt was occured. That's mean since I transmit the signal timer will 'on' and start counting until the signal will recieve and the value of TMR0 will move to working register.
clear TMR0 at the start of the interrupt routine and read it when your signal is recieved.
See also: