|
Serial I/O with a PIC
I was working on a project to control a stepper motor from a PC serial
port. I needed to receive characters from the serial port, and change
the motor actions based on the character received. The sample code
shown here demonstrates how to receive characters from a serial line.
The source code is shown below. Alternatively, you can click here to save the source onto your
system, or download the hex code to
download directly into the PIC.
It is based on source from Tom Coonan that I simplified by restricting
it to 9600 baud, 8-N-1 settings. If the digit 1 is received
then it turns on an LED connected to pin RB4, if a digit 0 is
received, it turns off the LED. The LED is driven via a 1K
resistor. There is a 10K resistor between pin 3 of the serial plug and
pin RA0 on the PIC to reduce the current into the pin.
Connect a serial line to your computer, and wire the TX line of the
serial cable to pin RA0, via a resistor. Start up a terminal program
on the PC and set the terminal settings to 9600 baud 8-N-1. On Windows
you will have to choose a COM port that corresponds to your computer's
serial device. On Linux, I ran minicom configured to use port
/dev/ttyS0, which corresponds to COM1 in Windows.
;
; led-ctrl.asm
;
; Accept serial data at 9600 8N1 and interpret it
; If a '1' is received, turn on an LED connected to RB4
; If a '0' is received, turn off the LED connected to RB4
;
; Serial TX line is connected via a 10K resistor to RA0
;
; PORT MAP
;
; PORTA
; 0 Input Serial
;
; PORTB
; 4 Output LED
;
; Based on code by Tom Coonan
;
; Copyright 1998-2003 Mark Crosbie 9/29/98
;
include p16c84.inc
radix dec
processor 16c84
SERIAL_BIT equ 0 ; Bit 0 on PORTA
LED_BIT equ 4 ; Bit 4 on PORTB
;**** Application's Memory Variables
INCHAR equ 0xc ; Input character
COUNTHI equ 0x10 ; Counter for Delay routine (MSB)
COUNTLO equ 0x11 ; Counter for Delay routine (LSB)
DELAYHI equ 0x12 ; Argument for DELAY subroutine (MSB)
DELAYLO equ 0x13 ; Argument for DELAY subroutine (LSB)
MASK equ 0x14 ; Mask register for each serial bit input
TEMP equ 0x15 ;
; After the baud rates are established through the jumpers, the right
; delay constants are written into here. These are the constants
; used in all the run-time delays for serial.
;
DELAY_HALF_SERIAL_HI equ 20 ;
DELAY_HALF_SERIAL_LO equ 21 ;
DELAY_FULL_SERIAL_HI equ 22 ;
DELAY_FULL_SERIAL_LO equ 23 ;
;*** End MEMORY Registers **********************************
; DELAY Constants.
;
; Delays were set emperically - using a Logic Analyzer and
; looking at peek signals for bit timing. ASSUMES the
; current design's 4MHz crystal, of course.
DELAY_FULL_9600_HI equ 1
DELAY_FULL_9600_LO equ 25
DELAY_HALF_9600_HI equ 1
DELAY_HALF_9600_LO equ 12
DELAY_50MS_HI equ 0x34
DELAY_50MS_LO equ 0x95
org 0 ; Reset Vector
goto Start ; Main entry point of program
;****************************************
; *
; Start Up Initializtion Stuff *
; *
;****************************************
; Remember, INCHAR started out as all zeros..
; Therefore, we only need to SET bits (when PORTA:0 = 0V)
; Also, remember, serial is inverted:
; 0V on PORTA:0 indicates a logic '1'
; 5V on PORTA:0 indicates a logic '0'
;
; The MASK variable is maintained by caller.
;
;
GetSerialBit
nop
nop
btfsc PORTA, SERIAL_BIT
; Get PORTA with a 'POSITIVE' serial bit on it
retlw 0 ; Do nothing if we got 5V, or logic '0'
GetSerialBitIsClr
movf MASK, W
iorwf INCHAR, f ; SET the bit
retlw 0
;***********************************************************
; *
; Specific Delay Functions. These are specific delays *
; which load specific delay counts. These routines then *
; call the generic DELAY subroutine. *
; *
;***********************************************************
DelayHalfSerial
movf DELAY_HALF_SERIAL_HI, W
movwf DELAYHI
movf DELAY_HALF_SERIAL_LO, W
movwf DELAYLO
retlw 0
DelayFullSerial
; Baud rate is 9600, so set up accorsingly
movf DELAY_FULL_SERIAL_HI, W
movwf DELAYHI
movf DELAY_FULL_SERIAL_LO, W
movwf DELAYLO
retlw 0
Delay50MS
movlw DELAY_50MS_HI
movwf DELAYHI
movlw DELAY_50MS_LO
movwf DELAYLO
retlw 0
InitDelay200MS
call Delay50MS
call Delay
call Delay50MS
call Delay
call Delay50MS
call Delay
call Delay50MS
call Delay
retlw 0
; General DELAY routine
; Inputs:
; DELAYHI - Initial Countdown value MSB
; DELAYLO - Initial Countdown value LSB
; Uses:
; COUNTHI - Counter value MSB
; COUNTLO - Counter value LSB
Delay movf DELAYHI, W
movwf COUNTHI
movf DELAYLO, W
movwf COUNTLO
DelayLoop
decfsz COUNTLO
goto DelayLoop
decfsz COUNTHI
goto DelaySetup2
goto DelayDone
DelaySetup2
movf DELAYLO, W
movwf COUNTLO
goto DelayLoop
DelayDone
retlw 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ***** Main Program Entry !!!
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Start
clrf PORTA
clrf PORTB
; Set up input and output bits
bsf STATUS, RP0
bsf TRISA, SERIAL_BIT ; PORTA.0 is input
bcf TRISB, LED_BIT ; PORTB.4 is output
bcf STATUS, RP0
call Delay50MS ; Wait for tristate to settle...?...
call Delay
;** Set up Baud Constants
movlw DELAY_FULL_9600_HI
movwf DELAY_FULL_SERIAL_HI
movlw DELAY_FULL_9600_LO
movwf DELAY_FULL_SERIAL_LO
movlw DELAY_HALF_9600_HI
movwf DELAY_HALF_SERIAL_HI
movlw DELAY_HALF_9600_LO
movwf DELAY_HALF_SERIAL_LO
call InitDelay200MS
;******* START Main Loop Here **************
; Loop and read characters
WaitChar ; Wait for start bit
clrf INCHAR ; clear the input character
movlw B'00000001' ; start out at bit 0
movwf MASK
btfss PORTA, SERIAL_BIT ; If we get a '1' or a START bit, skip!
goto WaitChar ; Nope.. no start bit. Keep looking
; Got an edge!
nop
nop
call DelayHalfSerial ; Delay half a bit
call Delay
btfss PORTA, SERIAL_BIT ; Serial bit *should* be zero.
goto WaitChar ; False alarm..
BitLoop
; Delay one bit time
call DelayFullSerial
call Delay
call GetSerialBit ; Get Bit into INCHAR
bcf STATUS, C ; Clear the carry bit
rlf MASK, F ; shift mask left one bit, thru carry
btfss STATUS, C ; is the carry set?
goto BitLoop
; Delay one bit time for the STOP bit
call DelayFullSerial
call Delay
; See if the character is 0, if so, turn off the LED
movf INCHAR, w
sublw '0'
btfsc STATUS, Z
bcf PORTB, LED_BIT ; turn off the LED
btfss STATUS, Z
bsf PORTB, LED_BIT ; turn on the LED
; A small pause between each sample
call Delay50MS
call Delay
goto WaitChar
end
|
PIC Microcontroller Project Book
Lot's of great PIC project ideas!
Programming and Customizing the Pic Microcontroller
If you are learning to program microcontrollers then Myke's book is good start.
The Art of Electronics
A classic in the field. Teaches you the art and science of linear and digital electronic design.
If you want to learn why your circuit is not working, read this book and you'll know why.
Mobile Robots: Inspiration to Implementation
A very readable introduction to the art of robotic design and implementation from the best
practioners in the field: the MIT Artificial Intelligence Lab!
Microcontroller Cookbook
A set of cookbook style designs for the 8051 and PIC microcontrollers.
A handy reference to have if you need a quick solution to a problem.
|