;****************************************************************** ;* * ;* Filename: AAC 690+LCD.asm * ;* Author: Mike McLaren, K8LH (k8lh_at_arrl.net) * ;* (C)2010: Micro Application Consultants * ;* Date: 01-Apr-10 * ;* * ;* 16F690 (4-MHz INTOSC) + HD44780 2x16 LCD + DS18B20 Demo' * ;* * ;* * ;* MPLab: 8.50 (tabs=8) * ;* MPAsm: 5.35 * ;* * ;****************************************************************** #include radix dec list st=off ;--< config fuses >------------------------------------------------ __config _FCMEN_OFF& _IESO_OFF& _MCLRE_OFF& _WDT_OFF& _INTOSCIO ; _FCMEN_OFF ; -- fail safe clock monitor enable off ; _IESO_OFF ; -- int/ext switch over enable off ; _BOR_ON ; default, brown out reset on ; _CPD_OFF ; default, data eeprom protection off ; _CP_OFF ; default, program code protection off ; _MCLR_OFF ; -- use MCLR pin as digital input ; _PWRTE_OFF ; default, power up timer off ; _WDT_OFF ; -- watch dog timer off ; _INTOSCIO ; -- internal osc, OSC1 and OSC2 I/O ;--< variables >--------------------------------------------------- temp equ 0x20 ; Put LCD variable delayhi equ 0x21 ; DelayCy() subsystem variable ptrl equ 0x22 ; PutStr subsystem variable ptrh equ 0x23 ; PutStr subsystem variable ; ; DS18B20 variables ; huns equ 0x30 ; huns, 0..1 tens equ 0x31 ; tens, 0..9 ones equ 0x32 ; ones, 0..9 tenths equ 0x33 ; tenths, 0..9 TempLo equ 0x34 ; temperature lo byte TempHi equ 0x35 ; temperature hi byte flags equ 0x36 ; count equ 0x37 ; bit counter OwByte equ 0x38 ; ;--< constants >--------------------------------------------------- line1 equ 128+0 ; LCD "line 1" command line2 equ 128+64 ; LCD "line 2" command DataLo equ b'00000000' ; RB7 = output (lo) DataHi equ b'10000000' ; RB7 = input (hi) #define OwPin PORTB,7 ; RB7 #define negflag flags,0 ; ;****************************************************************** ; K8LH DelayCy() subsystem macro generates four instructions * ;****************************************************************** radix dec clock equ 4 ; 4, 8, 12, 16, 20 (MHz), etc. usecs equ clock/4 ; cycles/microsecond multiplier msecs equ clock/4*1000 ; cycles/millisecond multiplier DelayCy macro delay ; 11..327690 cycle range movlw high((delay-11)/5)+1 movwf delayhi movlw low ((delay-11)/5) call uDelay-((delay-11)%5) endm ;****************************************************************** ; K8LH PutSTR macro * ;****************************************************************** PutSTR macro ptext local string,print movlw low(string) ; movwf ptrl ; movlw high(string) ; movwf ptrh ; goto print ; string dt ptext,0 ; print call PutString ; endm ;****************************************************************** ; reset vector * ;****************************************************************** org 0x000 v_reset clrf STATUS ; force bank 0 and IRP = 0 |B0 goto Init ; |B0 ;****************************************************************** ; interrupt vector * ;****************************************************************** org 0x004 v_interrupt ;****************************************************************** ; LCD "Put" subroutines (hardcoded for LCD D7..D4 on RC3..RC0, * ; LCD RS on RC4, and LCD E on RC7) * ;****************************************************************** PutCMD ; entry point for "cmd" data clrc ; RS = 0 (command) |B0 skpnc ; |B0 PutDAT ; entry point for "dat" data setc ; RS = 1 (data) |B0 movwf temp ; save WREG data byte |B0 swapf temp,W ; hi nybble in b3..b0 |B0 call PutNyb ; send left nybble |B0 movf temp,W ; lo nybble in b3..b0 |B0 call PutNyb ; send right nybble |B0 DelayCy(50*usecs) ; 60 usec delay |B0 return ; |B0 PutNyb andlw 0x0F ; mask off left nybble |B0 skpnc ; C=0 (RS=0)? yes, skip, else |B0 iorlw b'00010000' ; set lcd RS bit (RC4) |B0 movwf PORTC ; assert D7..D4 & RS pins |B0 iorlw b'10000000' ; set lcd E bit (RC7) |B0 movwf PORTC ; E = 1 (strobe) |B0 xorlw b'10000000' ; clr lcd E bit (RC7) |B0 movwf PORTC ; E = 0 |B0 return ; |B0 ;****************************************************************** ; K8LH PutString subroutine * ;****************************************************************** PutString call ReadTable andlw 0xFF ; null terminator? |B0 skpnz ; no, skip, else |B0 return ; exit |B0 call PutDAT ; print character |B0 incf ptrl,F ; bump pointer |B0 skpnz ; |B0 incf ptrh,F ; |B0 goto PutString ; |B0 ReadTable movf ptrh,W ; |B0 movwf PCLATH ; |B0 movf ptrl,W ; |B0 movwf PCL ; effect the jump |B0 ;****************************************************************** ; K8LH DelayCy() subsystem 16-bit uDelay subroutine * ;****************************************************************** nop ; entry for (delay-11)%5 == 4 |B0 nop ; entry for (delay-11)%5 == 3 |B0 nop ; entry for (delay-11)%5 == 2 |B0 nop ; entry for (delay-11)%5 == 1 |B0 uDelay addlw -1 ; subtract 5 cycle loop time |B0 skpc ; borrow? no, skip, else |B0 decfsz delayhi,F ; done? yes, skip, else |B0 goto uDelay ; do another loop |B0 return ; |B0 ;****************************************************************** ; K8LH "One Wire" subroutines * ;****************************************************************** Ow.Reset movlw DataLo ; output a '0' on OwPin |B0 tris PORTB ; update TRIS |B0 movlw 552/4 ; |B0 call Delay ; delay 552 usecs & release bus |B0 movlw 552/4 ; |B0 goto Delay ; delay 552 usecs & return |B0 Ow.WrByte movwf OwByte ; store byte |B0 movlw 8 ; |B0 movwf count ; |B0 wrloop rrf OwByte,F ; move bit to carry |B0 call Ow.WrBit ; send it |B0 decfsz count,F ; done? |B0 goto wrloop ; no, branch, else |B0 return ; |B0 Ow.WrBit bcf INTCON,GIE ; turn interrupts off |B0 movlw DataLo ; |B0 tris PORTB ; initiate write slot |B0 skpnc ; send '0'? yes, skip, else |B0 movlw DataHi ; release bus to send a '1' |B0 tris PORTB ; |B0 movlw 56/4 ; finish 60 usec slot |B0 Delay movwf temp ; |B0 decfsz temp,W ; |B0 goto Delay ; |B0 movlw DataHi ; |B0 tris PORTB ; release data line |B0 bsf INTCON,GIE ; turn interrupts on |B0 return ; |B0 Ow.RdByte movlw 8 ; |B0 movwf count ; |B0 rdloop call Ow.RdBit ; returns C = bit |B0 rrf OwByte,F ; move Carry into byte |B0 decfsz count,F ; built a full byte? |B0 goto rdloop ; no, branch, else |B0 movf OwByte,W ; WREG = OwByte |B0 return ; |B0 Ow.RdBit bcf INTCON,GIE ; turn interrupts off |B0 movlw DataLo ; pull line low |B0 tris PORTB ; falling edge 0 usecs |B0 clrc ; assume bit = 0 1 usecs |B0 movlw DataHi ; 2 usecs |B0 tris PORTB ; release bus at 3 usecs |B0 movlw 3 ; delay 10 usecs |B0 movwf temp ; |B0 decfsz temp,F ; |B0 goto $-1 ; sample between 13-14 usecs |B0 btfsc OwPin ; a '0'? yes, skip (C=0), else |B0 setc ; indicate a '1' (C=1) |B0 bsf INTCON,GIE ; turn interrupts on |B0 goto Delay-1 ; delay 60 usecs & return |B0 ;****************************************************************** ; main init * ;****************************************************************** Init bsf STATUS,RP1 ; bank 2 |B2 clrf ANSEL ; turn off analog pin functions |B2 clrf ANSELH ; |B2 bsf WPUB,7 ; RB7 weak pull-up 'on' |B2 bcf STATUS,RP1 ; bank 0 |B0 bsf STATUS,RP0 ; bank 1 |B1 ; movlw b'01110000' ; setup INTOSC for 8-MHz |B1 ; movwf OSCCON ; |B1 ; btfss OSCCON,HTS ; osc stable? yes, skip, else |B1 ; goto $-1 ; test again |B1 bcf OPTION_REG,NOT_RABPU movlw b'00001000' ; RA3 input |B1 movwf TRISA ; |B1 movlw b'10000000' ; RB7 input |B1 movwf TRISB ; |B1 clrf TRISC ; RC7..RC0 all outputs |B1 bcf STATUS,RP0 ; bank 0 |B0 clrf PORTA ; |B0 clrf PORTB ; |B0 clrf PORTC ; |B0 ; ; HD44780 type LCD 4-bit interface initialization procedure ; DelayCy(30*msecs) ; delay 30-msecs after power up |B0 movlw 0x03 ; step 1, "function set" 8-bit |B0 call PutNyb ; write 4-bits only |B0 DelayCy(5*msecs) ; required 5-msec delay |B0 movlw 0x03 ; step 2, "function set" 8-bit |B0 call PutNyb ; write 4-bits only |B0 DelayCy(160*usecs) ; required 160-usec delay |B0 movlw 0x03 ; step 3, "function set" 8-bit |B0 call PutNyb ; write 4-bits only |B0 DelayCy(160*usecs) ; required 160-usec delay |B0 movlw 0x02 ; step 4, "function set" 4-bit |B0 call PutNyb ; write 4-bits only |B0 DelayCy(160*usecs) ; required 160-usec delay |B0 ; ; now we're in 4-bit mode and can handle 8-bit transactions ; movlw b'00101000' ; 4-bit, 2-lines, 5x7 font |B0 call PutCMD ; send "function set" command |B0 movlw b'00001000' ; display, cursor, blink all off |B0 call PutCMD ; send "display on/off" command |B0 movlw b'00000001' ; clear display (1.53-msecs) |B0 call PutCMD ; send "entry mode set" command |B0 DelayCy(1500*usecs) ; required 1.53-msec delay |B0 movlw b'00000110' ; cursor inc, shift off |B0 call PutCMD ; send "entry mode set" command |B0 movlw b'00001100' ; display on, leave cursor off |B0 call PutCMD ; send "display on/off" command |B0 ;****************************************************************** ; main loop * ;****************************************************************** Loop call Ow.Reset ; |B0 movlw 0xCC ; |B0 call Ow.WrByte ; send 'skip rom' command |B0 movlw 0x44 ; |B0 call Ow.WrByte ; send 'convert' command |B0 movlw 60/4 ; |B0 call Delay ; delay 60-usecs |B0 RdSlot call Ow.RdBit ; conversion complete? |B0 bnc RdSlot ; no, branch (wait), else |B0 RdTemp call Ow.Reset ; |B0 movlw 0xCC ; |B0 call Ow.WrByte ; send 'skip rom' command |B0 movlw 0xBE ; |B0 call Ow.WrByte ; send 'read scratchpad' command |B0 call Ow.RdByte ; |B0 movwf TempLo ; save temperature lo |B0 call Ow.RdByte ; |B0 movwf TempHi ; save temperature hi |B0 AbsFunc bcf negflag ; clear "neg" flag |B0 btfss TempHi,7 ; negative temperature? |B0 goto BinPrep ; no, branch, else |B0 comf TempLo,F ; two's compliment it |B0 comf TempHi,F ; |B0 incf TempLo,F ; |B0 skpnz ; |B0 incf TempHi,F ; |B0 bsf negflag ; indicate "negative" |B0 ; ; put the 7-bit Integer temperature (0..125) in TempHi and ; leave the 4-bit fraction in TempLo ; BinPrep movlw 0xF0 ; W = 11110000 |B0 andwf TempLo,W ; W = LLLL0000, F = LLLLFFFF |B0 iorwf TempHi,F ; F = LLLL0HHH |B0 swapf TempHi,F ; F = 0HHHLLLL, 0..125 |B0 ; ; convert to decimal in "huns", "tens", and "ones" variables ; Bin2BCD clrf huns ; clear 'hunx' |B0 movlw -10 ; wreg = -10 |B0 resetx movwf tens ; reset 'tenx' to -10 |B0 div10x addwf TempHi,F ; subtract 10, borrow? |B0 skpc ; no, skip, else |B0 goto binxit ; branch (we're done) |B0 incfsz tens,F ; increment 'tenx', overflow? |B0 goto div10x ; no, branch, else |B0 incf huns,F ; increment 'hunx' |B0 goto resetx ; reset 'tenx' |B0 binxit subwf tens,F ; fix -10 offset |B0 subwf TempHi,W ; fix -10 offset |B0 movwf ones ; |B0 ; ; "tenths" = fraction * 10 / 16 ; movlw 0x0F ; |B0 andwf TempLo,F ; |B0 movf TempLo,W ; |B0 addwf TempLo,F ; *2, C=0 |B0 rlf TempLo,F ; *4, C=0 |B0 addwf TempLo,F ; *5, C=0 |B0 rlf TempLo,F ; *10 |B0 movlw 8 ; |B0 addwf TempLo,F ; rounding |B0 swapf TempLo,W ; pseudo divide by 16 |B0 andlw 0x0F ; |B0 movwf tenths ; |B0 ; ; minus sign & leading zero suppression ; movf huns,W ; hundreds == "1" or "2"? |B0 bnz Display ; yes, branch, else |B0 movlw ' '^'0' ; the ' ' character |B0 btfsc negflag ; negative? no, skip, else |B0 movlw '-'^'0' ; the '-' character |B0 movwf huns ; |B0 movf tens,W ; tens != "0" |B0 skpnz ; yes, skip, else |B0 movlw ' '^'0' ; the ' ' character |B0 movwf tens ; |B0 ; ; update the LCD display ; Display movlw line1+4 ; |B0 call PutCMD ; |B0 movf huns,W ; |B0 xorlw '0' ; |B0 call PutDAT ; |B0 movf tens,W ; |B0 xorlw '0' ; |B0 call PutDAT ; |B0 movf ones,W ; |B0 xorlw '0' ; |B0 call PutDAT ; |B0 movlw '.' ; |B0 call PutDAT ; |B0 movf tenths,W ; |B0 xorlw '0' ; |B0 call PutDAT ; |B0 movlw 0xDF ; '°' |B0 call PutDAT ; |B0 movlw 'C' ; |B0 call PutDAT ; |B0 goto Loop ; |B0 ;****************************************************************** end