Time

11/04/08 | by anthony [mail] | Categories: Informative, General, Code

As your code gets more complex and so does the tasks you wish to perform its often important to take advantage of the build in hardware and gain the ability to multitask. One of the last modules to go over is the timer module. There are several timers build in but we will be focusing on the TMR0 module.

Using the module is fairly straight forward you can turn it “on” with about 3 lines of code. The TMR0 module is a 8 bit timer, thus after 256 clocks it carries over. We can also set a prescaler that sets what the ratio of the timer to the clock is. This prescale value has a max of 256 as well. With max prescaler our timer will reach a max time before rollover of 65536 instructions or .06 seconds. If you need a timer that lasts longer, the other modules hold larger values and thus rollover at a later time.

The Registers:

OPTION_REG: (bank 1) Holds timer configuration information.

The Code:

  #include (p16F690.inc)
     __config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF)
org 0              ; Begginning of code
PORTS:
	bsf       STATUS,RP1
	clrf      ANSEL          ; All pins are digital I/O
 	clrf 	  ANSELH         ; All pins are digital I/O
	bcf       STATUS,RP1	
	bsf       STATUS,RP0
	movlw     b'0111'    	 ; Turn on 256 prescaler
	movwf     OPTION_REG
	bcf          OPTION_REG,3   ; Prescaler set to timer0
	bcf       OPTION_REG,5	 ; set timer for internal osc
	movlw     0x00           ; Move the hex value of 0 to multipurpose register W
              movwf     TRISC          ; make IO PortC all output
	bcf       STATUS,RP0
	clrf      PORTC
MAIN:
	movlw     0x01
	xorwf     PORTC
	btfss     INTCON,2  ; Check if timer overflow flag is set
	goto      $-1
	bcf       INTCON,2
	goto      MAIN
end


This code enables the timer and uses it to flash an LED when it rolls over.

Breaking it down:


movlw b'0111' ; Turn on 256 prescaler
movwf OPTION_REG
bcf OPTION_REG,3 ; Prescaler set to timer0
bcf OPTION_REG,5 ; set timer for internal osc

This is all the code we need for the timer module. It’s fairly straight forward. We mostly change OPTION_REG to set the timer for what we want.

OPTION_REG:

bit 7 RABPU: PORTA/PORTB Pull-up Enable bit

1 = PORTA/PORTB pull-ups are disabled
0 = PORTA/PORTB pull-ups are enabled by individual PORT latch values

bit 6 INTEDG: Interrupt Edge Select bit
1 = Interrupt on rising edge of RA2/INT pin
0 = Interrupt on falling edge of RA2/INT pin

bit 5 T0CS: Timer0 Clock Source Select bit
1 = Transition on RA2/T0CKI pin
0 = Internal instruction cycle clock (FOSC/4)

bit 4 T0SE: Timer0 Source Edge Select bit
1 = Increment on high-to-low transition on RA2/T0CKI pin
0 = Increment on low-to-high transition on RA2/T0CKI pin

bit 3 PSA: Prescaler Assignment bit
1 = Prescaler is assigned to the WDT
0 = Prescaler is assigned to the Timer0 module

bit 2-0 PS<2:0>: Prescaler Rate Select bits
(table in datasheet)

For the TMR0 module the bits we care about are 0,1,2,3 and 5. For basic operation we set bit 5 low, using the internal oscillator for the clock source. We assign the prescaler to the timer module and not the Watch Dog Timer. We also assign 111 to the prescaler which is the max value.

With that set, our basic code does a XOR operation with the current contents of PORTC, waits until the timer overflows by polling the TMR0 overflow flag bit (INTCON,2) and then returning to main and doing it all over again. In the end we get a blinking LED using highly efficient code.

There we have the TMR0 module in a nutshell. Most of the other timers work in a similar fashion. With this hardware under your belt the possibilities are endless.

Assembly Source

HEX

A2D

11/04/08 | by anthony [mail] | Categories: Informative, General, Code

It is often very useful to create a digital representation of an analog signal. The primary way we do this is through a analog to digital conversion. This is done by comparing Vin with a reference voltage (Vref) and converting their ratios to a binary number.

Fortunately for us the PIC microcontroller has analog to digital converters built into the hardware. Doing an analog to digital conversion does take time however, but it is an extremely valuable resource. We often use analog to digital conversions for sensor applications, or anything where voltage varies with conditions.
Doing an A2D conversion

As with everything in the PIC, the first thing we have to do is enable the hardware and then set up the port to do an A2D conversion.

The registers:

ADCON0: (bank 0) Stores the config information for the A2D module
ADCON1: (bank 1) Sets the clock for the A2D conversion
ANSEL: (bank 2) Determines whether a port is digital or analog, for A2D we obviously want whatever port were using to be analog
ADRESH: (bank 0 ) Results of conversion are here.

The Code:

    #include 
     __config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF)
org 0                                               ; Beginning of code
DISPLAY equ 0x22                        ; DISPLAY var stored at General purpose register 0x22
PORTS:
	bsf       STATUS,RP0        ; select BANK 1
	movlw     0x00               ; Move the hex value of 0 to multipurpose register W
        movwf     TRISC              ; make IO PortC all output
	movlw     0xff                 ; Move the hex value of FF(255) to multipurpose register W
	movwf     TRISA              ; Make  PortA all inputs
	movlw     0x10               
        movwf     ADCON1         ;set A2d Clock to FOSC/32
	bcf       STATUS,RP0       ;Exit bank 1
	bsf       STATUS,RP1       ; BANK 2
	movlw     0xff     
	movwf     ANSEL            ; Set PortA for all analog 
	bcf       STATUS,RP1      ; Exit bank 2, Enter bank 0
	movlw     0x01            
	movwf     ADCON0      ; Configure ADCON and turn it on {Left just, VDD=VREF, RA0,A2D ON}
	clrf      DISPLAY             ; Clear Display Var
MAIN:
	call      A2D                    ; Call subroutine
	movf      DISPLAY,w     ; Move Display to w	
	movwf     PORTC         ; Move W to portC
	goto 	  MAIN            ; Return to main
A2D:
	nop              
	nop
	nop
	nop
	nop                               ; wait 5 uS
	bsf       ADCON0,GO  ; Start the conversion 
	btfss     ADCON0,GO ; Bit will stay high until conversion is complete
	goto      $-1                 ; Until then keep going back
        movf      ADRESH,w  ; Move result to w
	movwf     DISPLAY    ;Then w to Display
	return
 end

The Breakdown:

Most of the code is fairly straight forward, we set up the A2D module in the ports routine and then we do a conversion on RA0 and display the results on PORTC.

movlw     0x10               
movwf     ADCON1         ;set A2d Clock to FOSC/32

These lines move a literal into ADCON1, ADCON1 is the register for the clock of the conversion module, this one sets the time to the oscillator by 32, which is fairly slow. The higher the impedance of your input, the longer you should let the conversion take. The longer the clock, the more data you acquire and the more accurate your results are. However set this to what best fits your application


movlw     0xff     
movwf     ANSEL            ; Set PortA for all analog 

This merely tells the PIC to set porta up for analog signals, if you’re doing a purely digital circuit it’s wise to set these low

movlw     0x01            
movwf     ADCON0      ; Configure ADCON and turn it on {Left just, VDD=VREF, RA0,A2D ON}

ADCON0 is the configuration register of the A2D module, here you set the VREF source, how the data is outputted, and what port to run the conversion on and weather to start or stop the conversion. The datasheet explains what each bit does. This setup, we have our data left justified (A2D is a 10 bit operation, bit we only want 8, so we have the data start with the first 8 bits rather than the first 2), Our VREF is VDD, channel 000 is set (ra0) and we turned the module on.

A2D:
	nop              
	nop
	nop
	nop
	nop                               ; wait 5 uS
	bsf       ADCON0,GO  ; Start the conversion 
	btfss     ADCON0,GO ; Bit will stay high until conversion is complete
	goto      $-1                 ; Until then keep going back
        movf      ADRESH,w  ; Move result to w
	movwf     DISPLAY    ;Then w to Display

This is the main A2D subroutine. The module works by charging an internal capacitor; this takes time to charge so it’s always good practice to kill some time before the conversion starts. Once you set the ADCON0 GO bit high the conversion starts. After the conversion finishes the bit will go low, so we continue to poll that bit until it does so, and then we move the contents of ADRESH to wherever we want. In this case we move it to DISPLAY.
There we have it, a basic Analog to digital conversion. It is worth your time to check out the chapter on A2D conversion in the PIC hand guide. Good luck on your future code, the source and compiled hex are located below

Assembly Source A2D.asm

HEX

S vs C

10/21/08 | by anthony [mail] | Categories: Informative, Tips

This post is going to start off a new category: Tips.

Posts in the tips category are going to be generally short and they wont be chronologically significant. They are just meant to demonstrate common techniques and/or common errors.

There are two letters that will absolutely devastate your code if your not careful, they are s and c. s and c are used in most bit orientated instructions (bcf, bsf, btfss, btfsc). They stand for Set and Clear or 1 and 0 respectively. When making your code and going over your logic, make sure you note what you are setting high and what needs to be set low. Reversing these two letter will utterly change your code, often for the worst. I've had code that went from useless to perfectly working by changing only one letter. A tip for debugging code, ALWAYS simplify your code first and then always check your bit orientated operations and make sure you're using the right instruction. With that in mind you will spend more time programming and testing and less time debugging.

Expanding the PIC

10/08/08 | by anthony [mail] | Categories: Informative

Most of the code on the side barely scratches the surface of the PIC microcontrollers capabilities. There are tons of functions and features in an average PIC that makes they incredibly powerful and useful devices

Even though the PIC is a 2$ microcontroller at its maximum clock speed it is capable of doing 1 million instructions per second. An average program of sophisticated design only is about 100 or so lines in assembly will be executed 10000 times in a second. This is something you must consider when writing a program.

A good example of this is when asking for user input, you'd want to add a delay routine to account for the physical bouncing of the switch as a switch isn't a perfect on/off device a switches contacts will bounce several times before actually settling to a specific state.

Applications using timers want to have a routine that handles overflows so you have data integrity.

With a microcontroller speed and efficiency is a double edged sword, you want as much speed as possible and you want as much speed as possible both however lead to less data resolution. Slower clunkier routines tend to be more reliable and accurate (not always true) As a programmer you want to be on a middle ground between having reliable data and a quick update time


Interrupts

Interrupts are very crucial parts of taking advantage of a PIC microcontroller. An interrupt in a nutshell is a special case where the PIC will stop what its doing and go to the interrupt routine, after its done with that it goes back to where it came from and waits for the next one to trigger.

This makes software incredibly efficient as you don't have to keep checking the state of something hoping that you happen to catch it while its changing, instead you just enable it as an interrupt and have it execute code relative to its function.

There are several standard interrupts available on the PIC MCU as well as several special to each device.

All interrupt related bits are held in the INTCON register which is accessible through all banks

(For PIC16F690)

Bit 7 is the global interrupt enable bit, this is the bit that controls weather interrupts are enabled are not, you set this high when you want to use interrupts.

Bit 6 enables or disables the extra peripheral interrupts, this doesn't need to be enabled unless using the extra interrupts

Bit 5 enables the Timer 0 module overflow interrupt. Most all PICs have atleast one timer module, Timer 0 is an 8 bit module thus it overflows at a max value of 255. When it does this interupt triggers

Bit 4 is the RA2 interrupt pin, this triggers when RA2 is set high (as in a button press)

Bit 3 is the RA/RB change interrupt bit, this is for setting up the Interrupt on Change feature of PORTA and PORTB, after this is set you need to go to the register IOCA and IOCB for PORTA and PORTB to choose what pins trigger the interrupt

Bit 2 is the flag for the Timer 0 overflow interrupt, this flag is high when the interrupt occurs.

Bit 1 is the RA2 interrupt flag, this is set when the RA2 interrupt occurs

Bit 0 is the RA/B change interrupt flag, set when the RA/B change interrupt occurs.

Where does an interrupt go when it is triggered?

The org function tells the compiler where to place the code in memory, 0x00 is the beginning of the programming registers and 0x04 is where interrupts are stored.

An example:

org 0x00
goto PORTS
org 0x04
"Place interrupt here"
retfie
PORTS:
do work
MAIN:
do work

If you have your main function set up to loop, the program will go to the main function and loop until an interrupt is triggered. To exit an interrupt we use the retfie function which means return from interrupt

Things to consider:

-When you are working in an interrupt you WANT to save the w reg that was in the main loop before the interrupt was triggered. You do this by loading w into a temporary register you declared earlier.
- Save the STATUS register, the interrupt will change STATUS thus it is best to save it to a temporary value. However when restoring status you want to swap nibbles twice using swapf as to not set any flags by mistake.
- TURN OFF GLOBAL INTERRUPTS, you don't want another interrupt triggering so its best to turn off the global interrupt while in the actual interrupt until your done with the routine
- Clear all interrupt flags, clear the flags and if your using more than one type of interrupt use the flags to see which interrupt occurred *btfss/c*
- Restore w

Interrupts can be extremely powerful tools when used correctly. They are essential if you ever want to seriously start making effective and efficient programs. More to come on how to get the most out of your PIC coming up in the next few days so stay tuned!

The Matrix.

09/08/08 | by anthony [mail] | Categories: Code, Projects

Matrices are somewhat interesting. They present a way to organize large and similar data sets. And because of the similarities you can do some interesting things with the numbers. In an electronic sense matrices are grids of components that can simplify i/o over a large amount of components of a similar function. The two most widely known are keypads and displays. Keypad uses a matrix of switches while a display uses a matrix of LEDs or liquid crystals. I'll be demonstrating the schematics and code to operate a simple static 8X4 LED matrix.

The Circuit

This project relies heavily on a correct circuit layout. Matrices are special because of how they're hooked up. Essentially, you provide power to one column and ground one row where they intersect, that LED lights.

The program used for drawing the schematics and making the board is called EAGLE. It is free to download and evaluate at their site

The basic schematic is as follows:

PORTC controls power and PORTB controls ground. Where PORTC = 1 and PORTB = 0 we get an illuminated LED

The CODE

The objective: To implement a 8X4 LED matrix in a way that is useful for displaying useful information.

The procedure:

1 - Set up the variables
2 - Set up the port
3 - call a table to display the pattern for the first column
4 - Rotate to the next column
5 - Increment count bit to keep track of bit location
6 - check if overflowed
a - if overflowed, clear count
7 - goto beginning

Essentially, Portc cycles so rapidly it seams that all the columns are on at one even though only one is on at a time.

The the "0"s in the look up table also essentially represent which LEDs are going to be lit.

What can be improved: The code can be improved by removing the COUNT variable and just observing and rotating PORTC, the current configuration however is more flexibly and allows expandability.

This version is also STATIC, there is no user implementation if the user wants a different design he has to go into the code and modify the look up table. Future versions will be dynamic.

As always, this is just a short description of the code and its functions. Full code is available below and discussion is welcome!

The Board

The board layout was designed is EAGLE as well and is meant to be as compact as possible. No voltage regulation features or external oscillators have been implemented yet. For troubleshooting purposes, this is fine.

http://mcuplace.com/mcu/media/blogs/blog/LED.asm (ASSEMBLY FILE)
http://mcuplace.com/mcu/media/blogs/blog/LED.HEX (HEX)

Pages: << 1 2 3 4 5 >>

September 2010
Sun Mon Tue Wed Thu Fri Sat
 << <   > >>
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    

Ads by Google

This blog is dedicated to working with digital circuitry and the use of microcontrollers, small compact computers on a chip. I will be encompassing many techniques to develop projects, tools to use to write and assemble code and i will be sharing any projects i am currently working on. User feedback is a must! I do not know it all, hell im not even that experienced, but without a general place to get all the info needed i find it very hard to get into the world of microcontrollers without pursing a CE degree. So come one come all and enter the world of mystery and creativity!

Search

XML Feeds

multiblog engine