; AVR test program by Charles R. (Randy) Ott - 5/13/98 ; Exercise Dallas Semiconductor DS1820 digital thermometer ; Only works for temperatures above 0 C ; Power, ground, and data I/O are on port D pins for simplicity ; Plug device into unused 40 pin socket pins PD4,5,6 ; Pin PD5 requires a pullup resistor ; Clock uses 9.8304 MHz. crystal, change delays and baud rate ; for other crystal frequencies ; Binary to BCD conversion borrowed from Atmel app.note AVR204 ; Use Atmel app note for multiply to convert to degrees F .nolist .include "2313def.inc" ;Define chip particulars .list ;***** Global register variables .def wreg =R16 ;General use working register .def timeout =R17 ;Timeout value passed to subroutine .def inreg =R18 ;Data register for reading DS1820 .def outreg =R19 ;Data register for writing DS1820 .def temphi =R20 ;High byte of temperature reading .def templo =R21 ;Low byte of temperature reading .def loopcnt =R22 ;Loop counter for serial read/write ;***** Registers used for 8 x 8 = 16 bit multiply .def mcnt8u =R22 ;Loop counter .def mc8u =r23 ;multiplicand .def mp8u =r24 ;multiplier .def m8uL =r24 ;result Low byte .def m8uH =r25 ;result High byte ;***** Registers used for BCD conversion .equ AtBCD0 =23 ;Direct address of tBCD0 .equ AtBCD2 =25 ;Direct address of tBCD1 .def tBCD0 =r23 ;BCD value digits 1 and 0 .def tBCD1 =r24 ;BCD value digits 3 and 2 .def tBCD2 =r25 ;BCD value digit 4 .def fbinL =r17 ;binary value Low byte .def fbinH =r18 ;binary value High byte .def tmp16a =r19 ;temporary value .def cnt16a =r22 ;loop counter ;***** Port pin definitions .equ dsvcc =4 ;DS1820 Vcc connected to PD4 .equ dsio =5 ;DS 1820 I/O pin connected to PD5 .equ dsgnd =6 ;DS 1820 Gnd connected to PD6 ;***** Other equates ; Change for other crystal frequencies .equ T0PRE =0b00000010 ;Timer 0 prescaler 4MHz / 8 = 2uS .equ BAUD =64 ;9600 bps at 9.8304 MHz. .cseg ;***** Interrupt vectors ; Perhaps overdone, all vectors shown for completeness .org 0 rjmp reset ;Reset Vector .org INT0addr ;External Interrupt0 Vector reti .org INT1addr ;External Interrupt1 Vector reti .org ICP1addr ;Input Capture1 Interrupt Vector reti .org OC1addr ;Output Compare1 Interrupt Vector reti .org OVF1addr ;Overflow1 Interrupt Vector reti .org OVF0addr ;Overflow0 Interrupt Vector rjmp t0int .org URXCaddr ;UART Receive Complete Interrupt Vector reti .org UDREaddr ;UART Data Register Empty Interrupt Vector reti .org UTXCaddr ;UART Transmit Complete Interrupt Vector reti .org ACIaddr ;Analog Comparator Interrupt Vector reti ; Program entry point on reset reset: ldi wreg,RAMEND out SPL,wreg ;Init Stack Pointer sbi DDRD,dsvcc ;Make Vcc pin an output sbi DDRD,dsio ;Make I/O pin an output sbi DDRD,dsgnd ;Make ground pin an output cbi PORTD,dsgnd ;Pull ground pin low sbi PORTD,dsvcc ;Turn on Vcc to device ldi wreg,0b00000010 ;Enable Timer 0 interrupt out TIMSK,wreg ldi wreg,BAUD out UBRR,wreg ;Set baud rate generator ldi wreg,0b00001000 out UCR,wreg ;Enable UART tx w/o interrupt sei ;Enable interrupts main: rcall resetds ;Reset DS1820 device brts present ;Device found rjmp main present: ldi outreg,0xCC ;DS1820 Skip ROM command rcall writeds ldi outreg,0x44 ;DS1820 Convert T command rcall writeds twait: rcall readds ;Check for DS1820 conversion complete cpi inreg,0xFF ;DS1820 Returns all ones when done brne twait rcall resetds ;Reset DS1820 again ldi outreg,0xCC ;DS1820 Skip ROM command rcall writeds ldi outreg,0xBE ;DS1820 Read scratchpad command rcall writeds rcall readds ;Read DS1820 temperature LSB mov templo,inreg ;Store reading rcall readds ;Read DS1820 temperature MSB mov temphi,inreg ;Store reading rcall resetds ;Reset DS1820, Don't read the rest mov mc8u,templo ;Get unsigned temperature ldi mp8u,9 ;Multiply times 9 rcall mpy8u ldi wreg,0x40 ;Add 320 to result add wreg,m8uL mov fbinL,wreg ldi wreg,0x01 adc wreg,m8uH mov fbinH,wreg ;fbinH:fbinL = degs F * 10 rcall bin2BCD16 ;Convert to BCD mov wreg,tBCD1 ;Get second two digits swap wreg ;Get upper nibble andi wreg,0x0F ;Strip off upper nibble subi wreg,-'0' ;Convert to ASCII digit cpi wreg,'0' ;Check for leading zero brne nolead ldi wreg,' ' ;Print a space instead nolead: rcall putchar ;Send to terminal mov wreg,tBCD1 ;Get second two digits andi wreg,0x0F ;Strip off upper nibble subi wreg,-'0' ;Convert to ASCII digit rcall putchar ;Send to terminal mov wreg,tBCD0 ;Get last two digits swap wreg ;Get upper nibble andi wreg,0x0F ;Strip off upper nibble subi wreg,-'0' ;Convert to ASCII digit rcall putchar ;Send to terminal ldi wreg,'.' ;Print decimal point rcall putchar mov wreg,tBCD0 ;Get last two digits andi wreg,0x0F ;Strip off upper nibble subi wreg,-'0' ;Convert to ASCII digit rcall putchar ;Send to terminal ldi wreg,0x0d rcall putchar rjmp main ;Do it again..... ;***** Write a byte from wreg to UART putchar: sbis USR,UDRE ;Is UART transmitter ready? rjmp putchar ;If not, wait out UDR,wreg ;Put character to UART ret ;***** Read/write a byte to the DS1820. Write 0xFF to read device readds: ldi outreg,0xFF ;Set output to all ones for reading writeds: ldi loopcnt,8 ;Send 8 bits to device rwloop: sbi DDRD,dsio ;Make I/O pin an output cbi PORTD,dsio ;Pull I/O pin low ldi timeout,-1 ;Make timer 0 count 2uS rcall delay ror outreg ;Get bit from output register into carry brcc wrzero ;If clear, leave line low cbi DDRD,dsio ;Otherwise let pull up go high wrzero: ldi timeout,-12 ;Make timer 0 count 12 * 0.8uS rcall delay ;Give pin time to go high if needed clc ;clear carry, assume bit is a zero sbic PIND,dsio ;Sample input pin sec ;Set carry if pin was high ror inreg ;Get bit into input register ldi timeout,-61 ;Make timer 0 count 61 * 0.8uS rcall delay ;Fill out time slot cbi DDRD,dsio ;Let line go back high ldi timeout,-1 ;Make timer 0 count 2uS rcall delay ;Leave I/O pin high for recovery dec loopcnt ;Decrement bit counter brne rwloop ;Loop for all 8 bits ret ;***** Reset DS1820 and read presence pulse, return result in T ; Modified for new timer to obtain long delays needed resetds: sbi DDRD,dsio ;Make I/O pin an output cbi PORTD,dsio ;Pull I/O pin low ldi timeout,0 ;Make timer 0 count 256 * 0.8uS rcall delay ldi timeout,0 ;Make timer 0 count 256 * 0.8uS rcall delay ldi timeout,-100 ;Make timer 0 count 100 * 0.8uS rcall delay sbi PORTD,dsio ;Pull I/O pin high cbi DDRD,dsio ;Make I/O pin an input ldi timeout,-111 ;Make timer 0 count 111 * 0.8uS rcall delay clt ;Assume device not present sbis PIND,dsio ;Check for presence pulse set ;Indicate result in T ldi timeout,0 ;Make timer 0 count 256 * 0.8uS rcall delay ldi timeout,0 ;Make timer 0 count 256 * 0.8uS rcall delay ldi timeout,-100 ;Make timer 0 count 100 * 0.8uS rcall delay ret ;***** Timer 0 overflow interrupt handler t0int: set ;Set T flag ldi wreg,0 ;Timer 0 off out TCCR0,wreg ;Stop timer reti ;Done, return ;***** Delay n*2 microseconds using timer 0, delay time passed in timeout delay: in wreg,SREG ;Save status register push wreg cpi timeout,-1 ;Special case breq skipit out TCNT0,timeout clt ;Clear T ldi wreg,T0PRE ;Timer 0 prescaler out TCCR0,wreg ;Run timer dwait: brtc dwait ;Wait for timer 0 interrupt to set T skipit: pop wreg ;Restore status register out SREG,wreg ret ;*************************************************************************** ;* ;* "mpy8u" - 8x8 Bit Unsigned Multiplication ;* ;* This subroutine multiplies the two register variables mp8u and mc8u. ;* The result is placed in registers m8uH, m8uL ;* ;* Number of words :9 + return ;* Number of cycles :58 + return ;* Low registers used :None ;* High registers used :4 (mp8u,mc8u/m8uL,m8uH,mcnt8u) ;* ;* Note: Result Low byte and the multiplier share the same register. ;* This causes the multiplier to be overwritten by the result. ;* ;*************************************************************************** mpy8u: clr m8uH ;clear result High byte ldi mcnt8u,8 ;init loop counter lsr mp8u ;rotate multiplier m8u_1: brcc m8u_2 ;carry set add m8uH,mc8u ; add multiplicand to result High byte m8u_2: ror m8uH ;rotate right result High byte ror m8uL ;rotate right result L byte and multiplier dec mcnt8u ;decrement loop counter brne m8u_1 ;if not done, loop more ret ;*************************************************************************** ;* ;* "bin2BCD16" - 16-bit Binary to BCD conversion ;* ;* This subroutine converts a 16-bit number (fbinH:fbinL) to a 5-digit ;* packed BCD number represented by 3 bytes (tBCD2:tBCD1:tBCD0). ;* MSD of the 5-digit number is placed in the lowermost nibble of tBCD2. ;* ;* Number of words :25 ;* Number of cycles :751/768 (Min/Max) ;* Low registers used :3 (tBCD0,tBCD1,tBCD2) ;* High registers used :4(fbinL,fbinH,cnt16a,tmp16a) ;* Pointers used :Z ;* ;*************************************************************************** ; Courtesy Atmel app note AVR204.ASM bin2BCD16: ldi cnt16a,16 ;Init loop counter clr tBCD2 ;clear result (3 bytes) clr tBCD1 clr tBCD0 clr ZH ;clear ZH (not needed for AT90Sxx0x) bBCDx_1:lsl fbinL ;shift input value rol fbinH ;through all bytes rol tBCD0 ; rol tBCD1 rol tBCD2 dec cnt16a ;decrement loop counter brne bBCDx_2 ;if counter not zero ret ; return bBCDx_2:ldi r30,AtBCD2+1 ;Z points to result MSB + 1 bBCDx_3: ld tmp16a,-Z ;get (Z) with pre-decrement subi tmp16a,-$03 ;add 0x03 sbrc tmp16a,3 ;if bit 3 not clear st Z,tmp16a ; store back ld tmp16a,Z ;get (Z) subi tmp16a,-$30 ;add 0x30 sbrc tmp16a,7 ;if bit 7 not clear st Z,tmp16a ; store back cpi ZL,AtBCD0 ;done all three? brne bBCDx_3 ;loop again if not rjmp bBCDx_1