I got my PC boards from OSH Park. The top boards are just some SOT23 breakouts to make breadboarding easier. Soldering wire legs onto SOT23s is a little difficult, and they don't hold up well to plugging and unplugging.
The bottom boards are my PIC10F322 general purpose board. OSH Park shorted me one board, so I only have five. Looks like I need to work on my text label placement and sizing. I don't know if it's my fault or if Eagle 7.3.0 is buggy, but a lot of my labels got cut off partway. Gotta work on that next time...
I quickly soldered one together. That went well - no problems at all. Next time I go surface mount for the diode too. The old toothbrush I used to scrub the flux off was pretty dirty. It left the board looking a bit grubby. I'll have to shine it up later (never).
You can see where I added "a bit more solder" on one end of the diode. You know, "The bigger da blob, da better da job!" Wouldn't hurt to clean that up too.
Here's the back side. Not much to see here except one little decoupling cap.
A closer view. That's a 402 cap on 603 pads. I wondered if that would work. It does, but 402s are really kind of too small for my old eyes to deal with.
Plugged in and running the same program as on the prototype. All works fine so far. Wiring the thing is a whole lot simpler now.
Below is the code that's running in the pics.
I experimented a bit and found that:
- Unlike the prototype, I can program the 10F322 board (with what's connected in the pics above) without using my program/run switch. That almost certainly won't be true with some other connected circuits.
- The code below can be run at up to 16MHz. I thought for sure the LCD would choke if I didn't adjust the delays but it keeps up perfectly fine.
processor 10f322
include "p10f322.inc"
__config _CP_OFF & _FOSC_INTOSC & _WDTE_OFF & _MCLRE_OFF & _LVP_OFF
cblock 0x40
i,nyb,rs,letter,count,count2,flag,temp,saves,savew,binh,binl,ascii_1,ascii_2,ascii_3,ascii_4,d1,d2,d3
endc
CLK equ 0
DAT equ 1
org 0x00
goto start
;-------------------------
;interrupt service routine
org 0x04
movwf savew ;save context (w & status)
swapf STATUS,w
movwf saves
btfsc IOCAF,3 ;is RA3 IOC flag set?
goto buttisr ;yes, go to button code
blink: ;no, must be Timer0
movlw 0x04 ;toggle LED pin RA2
xorwf LATA,f
bcf INTCON,TMR0IF ;clear interrupt flag
goto done
buttisr:
incf flag,f ;yes, flag = 1
bcf IOCAF,3 ;clear the RA3 IOC flag
done:
swapf saves,w ;restore context
movwf STATUS
swapf savew,f
swapf savew,w
retfie
;-------------
; main program
start:
movlw b'01010000' ;4MHz clock
movwf OSCCON
clrf ANSELA ;all pins digital
clrf TRISA ;led pins outputs
movlw b'10000111' ;setup Timer0,1:256
movwf OPTION_REG
bsf INTCON,TMR0IE ;enable Timer0 interrupt
clrf flag ;zero my IOC flag
bsf IOCAN,3 ;enable IOC on RA3
bsf INTCON,IOCIE ;enable interrupt on change
bsf INTCON,GIE ;enable interrupts
bcf LATA,CLK
bcf LATA,DAT
clrf count
clrf count2
call lcd_init
call line1
bleh:
movf count,w ;count = table pointer
call table1 ;get byte from table
xorlw 0x00 ;returned zero?
btfsc STATUS,Z
goto next ;yes, then done
movwf letter ;no, output byte to LCD
call lcd_char
incf count,f ;increment table pointer
goto bleh ;and go again
next:
clrf count
clrf count2
blah:
call delay250ms
btfsc flag,0 ;has button been pushed?
call rset ;yes, go handle it
movf count,w ;set up and go convert
movwf binh ;to ascii for display
movf count2,w
movwf binl
call bin2hex16
call line2 ;display the four hex digits
movf ascii_1,w
movwf letter
call lcd_char
movf ascii_2,w
movwf letter
call lcd_char
movf ascii_3,w
movwf letter
call lcd_char
movf ascii_4,w
movwf letter
call lcd_char
incf count2,f ;increment low byte
btfss STATUS,Z ;is zero set, meaning wrapped around?
goto blah ;no, goto blah
incf count,f ;yes, increment high byte
goto blah ;and go again
;---------------------
; table
table1 addwf PCL,f
retlw 'P'
retlw 'I'
retlw 'C'
retlw '1'
retlw '0'
retlw 'F'
retlw '3'
retlw '2'
retlw '2'
retlw ' '
retlw 'L'
retlw 'C'
retlw 'D'
retlw 0x00
;---------------------
; subroutines
rset:
clrf flag
clrf count
clrf count2
return
;---------------------
;16-bit binary passed in binh/binl
;Ascii hex values returned in ascii_1 thru ascii_4
bin2hex16:
swapf binh,w
andlw 0x0f
movwf ascii_1
movlw 0x0a
subwf ascii_1,w
movlw 0x30
btfsc STATUS,C
movlw 0x37
addwf ascii_1,f
;-----------
movf binh,w
andlw 0x0f
movwf ascii_2
movlw 0x0a
subwf ascii_2,w
movlw 0x30
btfsc STATUS,C
movlw 0x37
addwf ascii_2,f
;-----------
swapf binl,w
andlw 0x0f
movwf ascii_3
movlw 0x0a
subwf ascii_3,w
movlw 0x30
btfsc STATUS,C
movlw 0x37
addwf ascii_3,f
;-----------
movf binl,w
andlw 0x0f
movwf ascii_4
movlw 0x0a
subwf ascii_4,w
movlw 0x30
btfsc STATUS,C
movlw 0x37
addwf ascii_4,f
return
;---------------------
lcd_cmd:
movf letter,w ;do high nybble first
movwf temp
swapf temp,w
movwf nyb
clrf rs ;set rs bit low
call lcd_nybble
movf letter,w ;now do low nybble
movwf nyb
call lcd_nybble
return
;---------------------
lcd_char:
movf letter,w ;do high nybble first
movwf temp
swapf temp,w
movwf nyb
movlw 0x01 ;set rs bit high
movwf rs
call lcd_nybble
movf letter,w ;now do low nybble
movwf nyb
call lcd_nybble
return
;---------------------
lcd_nybble:
bcf LATA,DAT ;clear the 174
movlw 6 ;with 6 zero bits
movwf i
lcdloop1:
call pulse ;clock out a bit
decfsz i,f ;finished 6 bits?
goto lcdloop1 ;no, go again
bsf LATA,DAT ;output the AND value
call pulse
btfss rs,0 ;is RS bit 0 set?
goto yup ;no, go to yup
bsf LATA,DAT ;yes, set data pin high
goto yup1
yup:
bcf LATA,DAT ;no, set data pin low
yup1:
call pulse
movlw 4 ;output the nybble
movwf i ;set loop counter
lcdloop2:
btfsc nyb,3 ;check if high bit is 1
goto one ;yes, goto one
bcf LATA,DAT ;no, set DAT pin low
goto sendbit ;go send it
one:
bsf LATA,DAT ;set DAT pin high
sendbit:
call pulse ;send the bit
rlf nyb,f ;move next bit into line
decfsz i,f ;finished 4 bits?
goto lcdloop2 ;no, go again
call e_togg ;latch data
return
;---------------------
line1:
movlw 0x80
movwf letter
call lcd_cmd
return
;---------------------
line2:
movlw 0xc0
movwf letter
call lcd_cmd
return
;---------------------
pulse:
bsf LATA,CLK ;pulse clock
nop
bcf LATA,CLK
return
;---------------------
lcd_init:
call delay250ms
movlw 0x03
movwf nyb
clrf rs
call lcd_nybble
call delay5ms
call e_togg
call delay160us
call e_togg
call delay160us
movlw 2
movwf nyb
call lcd_nybble
call delay160us
movlw 0x28 ;set 4-bit mode and 2 lines
movwf letter
call lcd_cmd
call delay160us
movlw 0x10 ;cursor move & shift left
movwf letter
call lcd_cmd
call delay160us
movlw 0x06 ;entry mode = increment
movwf letter
call lcd_cmd
call delay160us
movlw 0x0c ;display on - cursor blink off
movwf letter
call lcd_cmd
call delay160us
movlw 0x01 ;clear display
movwf letter
call lcd_cmd
call delay250ms ;30ms is enough
return
;---------------------
e_togg: ;pulse data pin to latch data
bsf LATA,DAT
nop
bcf LATA,DAT
return
;---------------------
delay160us:
movlw 0x33
movwf d1
Delay_10:
decfsz d1,f
goto Delay_10
goto $+1
return
;---------------------
delay5ms:
movlw 0xE6
movwf d1
movlw 0x04
movwf d2
Delay_02:
decfsz d1,f
goto $+2
decfsz d2,f
goto Delay_02
goto $+1
nop
return
;---------------------
delay250ms:
movlw 0x4E
movwf d1
movlw 0xC4
movwf d2
Delay_01:
decfsz d1,f
goto $+2
decfsz d2,f
goto Delay_01
goto $+1
nop
return
;---------------------
delay500ms:
movlw 0x03
movwf d1
movlw 0x18
movwf d2
movlw 0x02
movwf d3
Delay_20:
decfsz d1, f
goto $+2
decfsz d2, f
goto $+2
decfsz d3, f
goto Delay_20
goto $+1
return
;---------------------
delay1s:
movlw 0x07
movwf d1
movlw 0x2F
movwf d2
movlw 0x03
movwf d3
Delay_4:
decfsz d1, f
goto $+2
decfsz d2, f
goto $+2
decfsz d3, f
goto Delay_4
goto $+1
goto $+1
goto $+1
return
;---------------------
end