« Intro to the HD44780 character based LCDGround control to Major Tom. (Serial communication) »

Project: UChat

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

The basis of this project is 5 7 segment displays, One of which the user controls and uses to select a number 0-9, and 4 of which store previously received values. There are 3 buttons; Increment decrement and send, all of do their respectable functions.

This project takes advantage of the following procedures:

Asynchronous Serial Communication – We use the UART module on the PIC16F690 to transmit data from one PIC to another. We use a 9600 baud with the transmitter and receiver set asynchronously. RB5 is RX and RB7 is TX

Multiplexed 7-segment Displays
– One problem with running 5 segment displays is the sheer number of pins we’d need to run each one individually. Each display has 7 segments and a common cathode. For all of the displays that’s 40 pins we’d need to run all those displays. Multiplexing is where we only run one display at an instantaneous moment. We do this but loading the data for one display onto PORTC, then using another port to switch the CC connection using a bipolar transistor. We keep rotating the output on PORTC and the CC we are switching until we’ve gotten to the last display. This happens so fast all the displays seem like they’re on at one given time. One thing to consider when using a multiplexed display is that the outputs must be turned off when you rotate the display, otherwise you will get ghosting of the previous value.

Interrupts – We use the interrupt on change and the receive interrupt to handle user input.

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
;Declare Variables
	cblock 0x20
DISPLAY
FIRSTDISP
SECONDDISP
THIRDDISP
FOURTHDISP
CURRENTDISP
STATUS_TEMP
TEMP
DELAY1
DELAY2
GROUND
W_TEMP
	endc
	goto 	PORTS ;Skip interrupt
;;;;;;;;;;;;;;
;  INTERUPT  ;
;;;;;;;;;;;;;;
	org 0x04
INTERUPT:
	bcf       INTCON,7      ;Turn off interrupts
	movwf     W_TEMP        ; Move W to temp
	bcf       STATUS,RP0    ; Goto bank 0
	bcf       STATUS,RP1    ; Goto bank 0
	btfsc     INTCON,0      ; Check for IOCA/B int
	goto      BUTTONPRESS   ; Yes, goto button press routine
	btfss     PIR1,RCIF     ; No, Check if value received
	goto      OUT           ; No, leave interrupt
	call      RX            ; Yes , receive the value
OUT:
	movf      W_TEMP,w 		; Restore W
	bcf       PIR1,RCIF     ; Clear flag
	bcf       INTCON,0      ; Clear flags
	bsf       INTCON,7      ; Restart interrupts
	retfie                  ; Return from interrupt
BUTTONPRESS:
	btfss     PORTA,3       ;Check first button
	call      INCREASE      ;Goto said function
	btfss     PORTB,4       ;Check Decrement button pressed, 
	call      DECREASE      ;Goto Said function
	btfss     PORTB,6       ;Check if TX button pressed
	call      TX            ; Goto TX routine
	call      DELAY	     	; Button Debounce	
	goto      OUT
INCREASE:
	incf      DISPLAY       ;Increment display
	movlw     0x0A          ; Move 10d to W
	bcf       STATUS,2      ;Clear Z bit
	subwf     DISPLAY,w     ;Subtract w from display
	btfsc     STATUS,2      ;Check if z bit set
	clrf      DISPLAY       ; Yes, clear display
	return                  ; no, return
DECREASE:
	incf      DISPLAY       ;Increment display (incase 0)
	bcf       STATUS,2      ;Z bit
	decf      DISPLAY       ;Decrement display
	btfsc     STATUS,2      ; Check z bit
	goto      INITIALIZE    ;Yes, reinitialize the display
	decf      DISPLAY       ;No, Decrement display
	return                  
INITIALIZE:
	movlw     0x09          ;Move 9d to w
	movwf     DISPLAY       ; Move it to display
	return
TX:
	btfss     PIR1 , TXIF    ; TXIF is set if TXREG has no character
 	goto      $-1            ; Loop until TXIF is cleared
 	movf      DISPLAY,w      ; Data to be transmitted over serial port
 	movwf 	  TXREG          ; Copy data to transmit register
 	bsf       STATUS,RP0     ; RAM PAGE 1
	btfss 	  TXSTA , TRMT   ; Wait until transmission is completed
 	goto      $-1            ; Loop back until transmission completed
	bcf       STATUS,RP0     ; Bank 0
 	return
RX:
	btfss     PIR1,RCIF     ; Wait for value to be recieved
	goto      $-1           ; loop
	bcf       PIR1,RCIF     ; Clear flag
	movf      RCREG,w       ; Move recieved word to w
	movwf     TEMP          ; then to var temp
	clrf      FOURTHDISP    ;Clear 4th display <- 3rd Disp <- Second Display <- First Display <- Temp
	movfw     THIRDDISP
	movwf     FOURTHDISP
	movfw     SECONDDISP
	movwf     THIRDDISP
	movfw     FIRSTDISP
	movwf     SECONDDISP
	movfw     TEMP
	movwf     FIRSTDISP
	return
DELAY:                     ; Generic Delay routine
	decfsz   DELAY1
	goto     DELAY
	decfsz   DELAY2
	goto     DELAY
	return
PORTS:
	; Analog
	bsf       STATUS,RP1    ; Bank 2
	clrf      ANSEL         ; All pins are digital I/O
 	clrf 	  ANSELH        ; All pins are digital I/O
	bcf       STATUS,RP1    ; Bank 0 
	; Tris
	bsf       STATUS,RP0     ; goto bank 1
	movlw     0x00           ; Move the hex value of 0 to multi purpose register W
              movwf     TRISC          ; make IO PortC all output
	movlw     b'01010000'    ; Move move b'01010000' to w
               movwf     TRISB          ; move to tris
	movlw     b'00001000'    ;Make porta.3 input rest output
	movwf     TRISA
	bcf       STATUS,RP0    ; goto bank 0
	; Interrupt
	bsf       INTCON,7      ;Set up global interrupts
	bsf       INTCON,6      ;Peripferal Interupts
	bsf       INTCON,3      ; IOCA/B interupt
	bsf       STATUS,RP0    ; Bank 1
	bsf       PIE1,5        ; Enable Interupt on Recieve
	bcf       STATUS,RP0    ; Bank 0
	bcf       PIR1,RCIF     ; Clear Flag
	bcf       INTCON,0      ; IOCA/B change flag
	; IOCB
	bsf       STATUS,RP1    ;Bank2
	movlw     b'01010000'   ; Make ports 4 and 6 IOC
	movwf     IOCB
	bcf       STATUS,RP1    
	bsf       STATUS,RP0    ;Bank1
	; IOCA
	movlw     b'00001000'   ;Make porta.3 IOC
	movwf     IOCA
	;serial comm transmit
	movlw     d'25'          ; Move the value of 25 or 0x19, to the baud rate genrator
	movwf     SPBRG          ; this will make the baud rate = to 9600 at a 4mhz internal clock in high speed mode
	bsf       TXSTA,BRGH     ;baud rate high
	bsf       TXSTA,TXEN     ;Enable Transmission
	bcf       TXSTA,SYNC     ;asynchronous
	bcf       STATUS,RP0     ;Exit bank 1
	;Serial comm Receive
	bsf       RCSTA,SPEN     ;Set serial port enable high
	bsf       RCSTA,CREN     ; Enable receiver
	; Initialize
	clrf      DISPLAY
	clrf      FIRSTDISP
	clrf      SECONDDISP
	clrf      THIRDDISP
	clrf	  FOURTHDISP
	movlw     0x01            ;Move 0x01 to ground
	movwf     GROUND
	movlw     0x20            ;Start pointer at DISLAY location: 0x20
	movwf     FSR
;;;;;;;;;;;;;;;;;;
;  MAIN ROUTINE  ;
;;;;;;;;;;;;;;;;;;
MAIN:
	bsf       STATUS,RP0 ;goto bank 1 and turn off display
	movlw     0xff
	movwf     TRISA
	movlw     0xff
	movwf     TRISC
	bcf       STATUS,RP0 ;bank 0
;Begin rotate
	movfw     INDF
	call      TABLE
	movwf     PORTC
	movfw     GROUND
	movwf     PORTA
;Turn on Displays
	bsf       STATUS,RP0
	movlw     0x00           
  	 movwf     TRISC          
	movlw     b'00001000'           
	movwf     TRISA
	bcf       STATUS,RP0
;Finish rotating
	rlf       GROUND
	call      RA3
	incf      FSR
	movlw     0x25
	bcf       STATUS,2
	subwf     FSR,w
	btfsc     STATUS,2
	call      CLEAR
	goto      MAIN
RA3:
	btfss     GROUND,3
	return
	rlf       GROUND
	return
CLEAR:
	movlw     0x20	
	movwf     FSR
	movlw     0x01
	movwf     GROUND
	return
TABLE:                          ;Generic lookup table
	addwf     PCL      ;            1;
	retlw     b'00111111';0      ;;;;;;;
	retlw     b'00000110';1    6 ;     ; 2
	retlw     b'01011011';2      ;  7  ;
	retlw     b'01001111';3      ;;;;;;;
	retlw     b'01100110';4    5 ;     ; 3
	retlw     b'01101101';5      ;     ;
	retlw     b'01111100';6      ;;;;;;;
	retlw     b'00000111';7         4
	retlw     b'01111111';8
	retlw     b'01100111';9
	return
end
;end

The Breakdown:

Initialization:
We initialize our variables to hold temporary values as well as the current values in each display.
Ports:
We set all digital I/O, Port C all output, Port A 0,1,2,4,5 as output 3 as input, Port B 4,6 as input, 7 and 5 as TX and RX respectively. The I/O Structure for this code is:
PORTC – Primary 7-Segment driver
PORTA - Drives the line for the ground for the common cathode as well as the send input
PORTB – Handles serial comm., as well as increment and decrement inputs.
We use the interrupt on change for Port A and B; we set up that interrupt for its respectful inputs
We set up the UART module for asynchronous communication, high speed baud and we turn on TX and RX.
We finally clear the display variables, set the ground to the first position and set the pointer to look at the first digit’s memory location (0x20)

Main:
We turn off the outputs to prevent ghosting. Since we can only change one port at one time and the display uses to ports to display data we shut off the ports, change the value and then update the ports. Thus we prevent the previous value from being displayed on top of the current one. We display the current value by using the value in that digit’s block of memory into a lookup table and then outputting to PORTC, along with the respectable ground for that digit’s display being HIGH.
After that we update the pointer reference to the next digit and rotate the ground position. We must note however, when the ground is at RA3 (input only) we rotate it once more since were using it as input.
Once we reach the end of the rotation, we reinitialize the displays.

Interrupts:
The interrupt routine is fairly simple it handles 4 conditions.
-Increment pressed
-Decrement pressed
-Send pressed
-Value Receive
The first two conditions are fairly simple, the interrupt happens we pool for a button press and then we update the first digit’s value.
The send routine, pools for a button press, if it was the first digit is loaded into the TX reg and is sent out.
When a value is received, we enter the RX routine, we store the value into a temp register and we begin updating the displays.
Temp>>First>>Second>>Third>>Fourth>>Clear
We do this by rotating the display into the next one. I.e. the third display into the fourth, etc.
If no conditions are met, we just exit the interrupt.

Conclusion:

This is a fairly simple project but it takes advantage of the PIC’s resources and on board hardware, we end up using 19 of the 20 pins of the PIC MCU. This is a great demo for serial communication between two PIC MCUs. I’ve expanded this project to include two Zigbee RF modules in which the two modules talk to each other wirelessly.

Where to go from here:
There is one major downside to this project, and that is the displays. The 7-segments are horribly inefficient and lack much flexibility. One way I’d like to expand this project is to add a LCD screen and a keypad matrix to expand the user input and possible output.

General Note:

I went through the explanation of the code very quickly in this article. As the code gets more complicated I won’t be able to keep revisiting basic techniques and explaining everything. That is what the previous posts are for, to lay the basic ground work down. If you need further explanation feel free to email me, I’m glad to break it down if you need it.

Thanks once again for taking the time to read this, Source and hex as always, is below.

Source
Hex

Permalink

Trackback address for this post

This is a captcha-picture. It is used to prevent mass-access by robots.

Please enter the characters from the image above. (case insensitive)

Array

No feedback yet

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
PoorExcellent
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)
This is a captcha-picture. It is used to prevent mass-access by robots.

Please enter the characters from the image above. (case insensitive)

Array
February 2012
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      

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

powered by free blog software