;Program T1621_2.bas

;This program illustrates how to use the Versatech Tickit62 to make 
;continuous temperature measurements with 0.03 degrees of resolution, 
;from a Dallas Semiconductor DS1621 Digital Thermometer and Thermostat, 
;and then write the value to the console.
;
;This is for positive values of temperature only.
;
;  Data_2 (term 33) ---------------> SCL (term 2)
;  Data_3 (term 34) <--------------> SDA (term 1)

;copyright, Locksley Haynes, Morgan State University, Sept. 29, 1997.

DEF tic62_b
LIB fbasic.lib      ;Library for standard functions
LIB constrin.lib    ;Library for string functions

DEF SCL   pin_D2
DEF SDA   pin_D3

DEF MEASUREMENTS 0d10b  ;amount of temp. measurements

GLOBAL byte RAW 0b      ;raw data read from device
GLOBAL byte slope 0b
GLOBAL byte counter 0b

;**Function start_comm initiates communication with the DS1621, by
bringing 
;**the SDA pin from a high to a low while the SCL is high. 
FUNC none start_comm
BEGIN
   pin_low( SCL )
   pin_high( SDA )    ;bring SDA(data) from a high
   pin_high( SCL )    ;while the SCL(clock) is high
   pin_low( SDA )     ;to a low
ENDFUN

;**Function stop_comm terminates communication with the DS1621, by
bringing 
;**the SDA pin from a low to a high while the SCL is high. 
FUNC none stop_comm
BEGIN
   pin_low( SCL )
   pin_low( SDA )    ;bring the SDA(data) from a low
   pin_high( SCL )   ;while the SCL(clock) is high
   pin_high( SDA )   ;to a high
ENDFUN

;**Function out_bit sets the state of DATA lead to bit_value, followed
;**by a clock pulse.
FUNC none out_bit
   PARAM byte value
   LOCAL byte val
BEGIN
   
   pin_low( SCL )
   IF ==( value, 0b )    ;if value equal zero
     pin_low( SDA )    ;then write zero to DATA lead
   ELSE
     =(val, pin_in( SDA ))     ;else write one.
   ENDIF
   pin_high( SCL )       ;provide clock pulse
   pin_low( SCL )
          
ENDFUN

;**Function write_command writes any eight bit command via DATA output, 
;**most significant bit first.
FUNC none write_command
   PARAM byte command       ;command sent to be written
   LOCAL byte comm          ;bit value of command to be sent
   LOCAL byte n             ;looping index for bits
   LOCAL byte i             ;looping index for shifting
BEGIN
   pin_low( SCL )
   pin_low( SDA )
   =( n, 8b)
   WHILE >( n, 0b )
      =( comm, command )
      =( i, -( n, 1b) )

      WHILE  >(i, 0b)          ;shift the bit over
         =(comm, >>( comm ))
         --( i )
      LOOP   
         
      =(comm, and(comm, 1b) )  ;assign bit to val
      out_bit( comm )    ;send that bit to DATA lead
      --( n )
      
   LOOP
   
   delay(200)

   pin_low( SCL )
   pin_high( SCL )  ;clock pulse to acknowledge data transfer
   pin_low( SCL )

ENDFUN

;**Function send_control_byte sends the control byte, which contains
;**the address of the particular device to be communicated with.
FUNC none send_control_byte
  PARAM byte addr        ;address of DS1621 device
  LOCAL byte control_byte 
BEGIN
   =( control_byte, 0x90b )
   =( control_byte, or(control_byte, addr) ) ; 1 0 0 1 a2 a1 a0 R/W
   write_command(control_byte)
ENDFUN

;**Function configure configures the register of the device whose
;**address is sent to the function.
FUNC none configure
   PARAM byte addr
   LOCAL byte conf 
   LOCAL byte WRITE_CONF
BEGIN
   =(conf, 2b)               ;set status register to CPU mode 
                             ;and continuous temperature measurements 
   =(WRITE_CONF, 0xacb)

   start_comm()
   send_control_byte(addr)
   write_command(WRITE_CONF)
   write_command(conf)
   stop_comm()
   pin_high( SCL )
   delay(200)  ;wait for prgramming of configuration register
ENDFUN

;**Function start_convert_temp starts temperature conversions on a device
;**via their address.
FUNC none start_convert_temp
  PARAM byte addr
  LOCAL byte START_CONVERT
BEGIN
   =(START_CONVERT, 0xeeb)

   start_comm()
   send_control_byte(addr)
   write_command(START_CONVERT)   ;start converting temperature
   stop_comm()
   pin_high( SCL )
   delay(1000)  ;wait a minute for conversions
ENDFUN

;**Function stop_convert_temp stops temperature conversions on a device
;**via their address.
FUNC none stop_convert_temp
  PARAM byte addr
  LOCAL byte STOP_CONVERT
BEGIN   
   =(STOP_CONVERT, 0x22b)

   start_comm()
   send_control_byte(addr)
   write_command(STOP_CONVERT)  ;halt temp. conversion to save power.
   stop_comm()
   pin_high( SCL )
   delay(1000)  ;wait a second for conversions
ENDFUN


;**Function read_data reads a eight bit digital word via the DATA lead.
FUNC none read_data
   LOCAL byte n 
   LOCAL byte val
BEGIN   
   =( RAW, 0b )
   =( n, 0b )

   WHILE <=( n, 7b )        ;read SDA pin eight times
      pin_low( SCL )
      pin_high( SCL )
      =( val, and( pin_in( SDA), 1b))  ;read SDA pin
      pin_low( SCL )
      =( RAW, or( <<( RAW ), val ))   ;build digital word
      ++( n )
   LOOP

   ;clock pulse acknowledges device for recieving data  
   pin_low( SCL )
   pin_high( SCL )
   pin_low( SCL )

   =(n,0b)
   WHILE <=( n, 7b )   ;provide clock pulses for unwanted bits     
      pin_low( SCL )
      pin_high( SCL )
      pin_low( SCL )
      ++( n )
   LOOP
ENDFUN

;**Function read_counter reads the value in the counter of the DS1621
FUNC none counter_value
  PARAM byte addr
  LOCAL byte read_addr
  LOCAL byte READ_COUNT
BEGIN
   =(READ_COUNT, 0xa8b )   

   start_comm()
   send_control_byte(addr)
   write_command(READ_COUNT)
   =(read_addr, or(addr, 1b))
   start_comm()
   send_control_byte(read_addr)
   read_data()
   pin_high( SCL )
   stop_comm()

   =(counter, RAW)

ENDFUN

;**Function read_slope reads the slope value in  the DS1621
FUNC none slope_value
  PARAM byte addr
  LOCAL byte read_addr
  LOCAL byte READ_SLOPE
BEGIN
   =(READ_SLOPE, 0xa9b ) 

   start_comm()
   send_control_byte(addr)
   write_command(READ_SLOPE)
   =(read_addr, or(addr, 1b))
   start_comm()
   send_control_byte(read_addr)
   read_data()
   pin_high( SCL )
   stop_comm()

   =(slope, RAW)
ENDFUN


;**Function read_temperature reads the temp. from a particular device
;**via the address sent to it.
FUNC none read_temperature
  PARAM byte addr
  LOCAL byte read_addr
  LOCAL byte READ_TEMP 
  ;LOCAL byte count
  ;LOCAL byte slope
  LOCAL byte temp
  LOCAL byte fract
BEGIN
  
  =(READ_TEMP, 0xaab)
  
  start_comm()
  send_control_byte(addr)
  write_command(READ_TEMP)
  =(read_addr, or(addr, 1b))
  start_comm()
  send_control_byte(read_addr)
  read_data()
  pin_high( SCL )
  stop_comm()
  
  =(temp, -(RAW, 1b)) 
  
  counter_value(addr)
  
  slope_value(addr)

  =(fract, +(50b, -(100b /( *(100b, counter), slope))))
  
  IF >=(fract, 0d100b)
      ++( temp )
      =(fract, -(fract, 100b))
  ENDIF

  ;=( temp, +( 32b, /( *(temp, 9b), 5b))) ;convert to temp. fahrenheit

  con_string( "The temperature is ")
  con_out( temp )
  con_string( ".")
  con_out( fract )
  con_string( " degrees celcius. \r\l")

ENDFUN


;****************************Main function***************** 
FUNC none main
   LOCAL byte count 
   LOCAL byte DEVICE1 0x01b ;DS1621 device with address A2=0 A1=0 A0=1
BEGIN
   =(DEVICE1 <<( DEVICE1 )) ;shift to make space for R/W bit

   con_string( "\r\l\lPreparing device...\r\l\l" )
   configure(DEVICE1)
   
   start_convert_temp(DEVICE1)
   
   con_string( "Measuring temperature...\r\l\l")
   =(count, 1b)
   WHILE <=( count, MEASUREMENTS)
      
      read_temperature(DEVICE1)
      ++( count )
      delay( 10000 )        ;wait ten seconds
      con_string( "\r\l" )
   LOOP
   
   stop_convert_temp(DEVICE1)

   con_string( "End temperature measurements.\r\l" )
   
   debug_on() ;return control to debugger.
ENDFUN