'm168-test-capacitor-rc-timing-direct.bas
'  v0.02 - Removed redundant variables and converte average
'          to a loop.  This version seems to provide very
'          stable readings for a single sensor and is
'          smaller than v0.01
'
'  v0.03 - Added eram storage of config paramters
'        - Added support for 7 sensors
'         - Added support for internal configuration

'  Direct read capacitive humidity sensor from Micro controller.
'  which reduces the parts costs.  The basic capacitive sensors start
'  at about $3.50 while the voltage or freq out tend to start at $15
'  and run to over $30.  My favorite is the SHT11 and SHT75 but they
'  start at $30.    The same approach can be used
'  to sense change in capacitance for other circuits
'  such as strain gauges.
'
'  This design provides easy field program calibration capability through
'  serial line which the other sensors do not.   Simply send command to
'  calibrate and current reading near the sensor.  It will compare that to
'  current values and save reading in eprom.  Allows for easy field
'  calibaration.
'
'  Tested on Mega168

'  Probably better implemented with
'  a AVRTiny which could be mounted right on the sensor and then hold
'  1 wire conversation back to master controller.
'
'
' HCH sensor typical response curve 298Pf at 0%RH upto 358pf @ 100%. Interestingly
' got numbers very close to this range from loop counter with 10M resistor.
' http://www.honeywell-sensor.com.cn/prodinfo/sensor_humidity_moisture/datasheet/HCH-1000.pdf
' http://mouser.com/ProductDetail/Honeywell/HCH-1000-002/?qs=yJVtgANCw01Gp3IHDXhPcA%3d%3d
'
'

' ******
' **** Enhancments ***
' ******

' TODO: Convert simple low, High readings to an array so we find the first
'   last low reading which is lower than the current reading.  Allow upto 5
'   calibration settings per sensor.  May be able to hard code these for
'   Magnesium Chloride = 32.78,  sodium Chloride 75.3, potassium nitrate 93.5,
'   and water 100% but in the field I may be forced to use a recently
'   calibrated sensor and use of ambient so should store the percentage with
'   the reading number and treat as simple array.  How to store an array in
'   the software?      Would be nice to offer immediate calibrate read
'   or  delayed.  If The read % is the same then override Should wait until I
'   get 5 identical reads for calibration.   also need to be able to clear
'   the read.   Should set the calibration for slot # eg:  s0 is for lowest
'   calibration while sl5 is for the highest.   Not getting 5 reads in a row
'   seems to be low but we normally only see a 1 digit variration +- once
'   stabilized so we have the choice of averaging 20 reads or taking the
'   first one where we get 5 out of ten of the same reading.
'
' TODO: Add inbound commands to run average of 33% salt solution and store
'  in non volatile memory.  second button for 76% or 100% solution.
'  change calculator to use NV memory to retain.
' TODO: Add pin 1..7 to allow any additional pins on port D to
'  to act as readers.  Allow these to be multi-plexed  by passing
'  in parm to function.  Need to figure out how to pad pind.x as parm.
' TODO: Convert all to word calculations and scale up by 100 to retain decimals
' that way eliminate need for floating point at all.
' TODO: Add 1 leg of temp sensor back into the solution to allow temperature
'  compensation.



'$regfile = "m64def.dat"
$regfile = "m16def.dat"
$crystal = 8000000
$hwstack = 64                                               ' default use 32 for the hardware stack
$swstack = 60                                               ' default use 10 for the SW stack
$framesize = 80                                             ' default use 40 for the frame space

'eprom storage
Dim Empty_byte As Eram byte at 0                       '1b
Dim sensor_id as Eram  Byte                            '1b
Dim sens_read_per_hour as eram  word                   '2b
   'attempt this many reads per
   'hour on all active sensors. maximum
   ' is alloated at about 1 read per 2
   ' seconds.
Dim sen_calib(70) as Eram word                         '140b
   ' 5 slots * (1-percent, 1-cnt) * 7 sensors
   'pndx = slotid * 2
   'rndx = slotid * 2 + 1
   ' where slot id is numbered 0..6
   ' convention is that each slot contains the reading for the next
   ' higher percentage reading and that the empty slots are skipped.
   ' lowest slot will contain highest lowest calibration reading
   ' highest slot will contain highes calibration reading
dim sens_active(7) as eram byte                       '7b
   ' sensor acive or inacive array determines if the sensor
   ' is read.
dim sens_alarm_low(7) as eram byte                    '7b
   ' Array of low and high alarms.
dim sens_alarm_high(7) as eram byte                   '7b
   ' if the sensor goes above or below the alarm specified
   ' the raise IO pin for that sensor and send out the
   ' alarm command information.  Also send out the
   ' recover when it comes back in range.
   ' s(n).low = sens_larm(



dim tfloat as single
dim tsingle as single
dim tlong as long
dim tword as word

dim r_dif as single
dim p_dif as single
dim rdif_per_perc as single


Declare Function conv_count_to_humidity(cnt as Word, byval low_r as word, byval low_p as word, cnt_per_perc as Single) As Single
Declare Function read_humdity_avg(byval sens_num as byte) as Word
Declare Function read_humid(byval sens_num as byte) as Word
declare Function read_humid_s0() As Word
declare Function read_humid_s1() As Word
declare Function read_humid_s2() As Word
declare Function read_humid_s3() As Word
declare Function read_humid_s4() As Word
declare Function read_humid_s5() As Word
declare Function read_humid_s6() As Word


'declare Function test_pass_pin(byval aPin as byte) as word


Open "comd.1:9600,8,N,1,inverted" For Output As #1
Open "comd.0:9600,8,N,1,inverted" For Input As #2


Const bon = 1
Const boff = 0

Config Portd.5 = Output
Config Portd.4 = input
config portd.6 = output

humid_rc_charge alias portd.5
humid_rc_read_s0 alias pind.0
humid_rc_read_s1 alias pind.1
humid_rc_read_s2 alias pind.2
humid_rc_read_s3 alias pind.3
humid_rc_read_s4 alias pind.4
humid_rc_read_s5 alias pind.5
humid_rc_read_s6 alias pind.6
' Pin 7 reserved for dricing the power
humid_led alias portd.6
humid_rc_charge = boff


const chi_r = 1121   ' count reading at high humidity
const chi_p = 100     ' percentage reading taken at
'const chi_r = 1099  ' count reading at high humidity
'const chi_p = 75.3  ' percentage reading taken at


'const lo_r = 1045 ' count reading at low humidity
'const lo_p = 33   ' RH percentage at low humidity reading
const clo_r = 1021 ' count reading at low humidity
const clo_p = 42 ' RH percentage at low humidity reading


const clo_no_sens = 400 ' if reading is lower than this assume no sensor present
                        ' no sensor is typically about 19

r_dif =   chi_r - clo_r
p_dif =   chi_p - clo_p
rdif_per_perc =  r_dif / p_dif

print #1, "m168-test-capacitor-rc-timing-direct.v.02.bas"

print #1, "cnt per percent = ";   rdif_per_perc

Dim calc_p as single

'tword = test_pass_pin(pind.5)



Do
  tword = read_humdity_avg(0)
  print #1, " 2avg="; tword;
  calc_p = conv_count_to_humidity(tword, clo_r, clo_p, rdif_per_perc)
  print #1, " avg%=";Fusing(calc_p , "-###.#")
  Waitms 500
Loop


Function read_humdity_avg(sens_num) as Word  ' add another layer of averages
  const num_avg = 9
  dim ci as byte
  dim tread as long
  tread = 0
  for ci = 1 to num_avg
    tword = read_humid(sens_num)
    tread = tread + tword
  next ci
  tread = tread / num_avg
  read_humdity_avg = tread
  'waitms 300
end function


'Function test_pass_pin(byval aPin as byte) as word
'  dim tt as byte
'end function

Function conv_count_to_humidity(cnt as Word, byval low_r as word, byval low_p as word, cnt_per_perc as Single) As Single
 'Convert Avg reading to Percentage
  dim ddelta as single
  dim dmult as single
  dim tperc as single
  ddelta = cnt - low_r
  '  how far are we above low calibration reading
  dmult = ddelta / cnt_per_perc
  '  how many units of percentage dose delta reading work out to.
  tperc = low_p + dmult
  conv_count_to_humidity = tperc
end function



const humid_num_to_read = 12
const humid_wait_between_read = 4
Dim humid_ri as  Byte ' index 2
Dim humid_tot_read as Word ' accumulator 2
Dim humid_tcnt as  Word


' Would have preferred to use the bit number as a parm
' so we could pass in the alias for portd.pin4 but
' can not figure out how to get the compiler to do this.
function read_humid(sens_num as byte) as word
  ' Take 1 waste reading to setup the capacitor
  ' state the exact same as it would be in the
  ' averaging loop.  Otherwise the cap may be
  ' more fully discharged and could result in
  ' a lower first read value.

  humid_tcnt = read_humid_s0()
  select case sens_num
      case 0: humid_tcnt = read_humid_s0()
      case 1: humid_tcnt = read_humid_s1()
      case 2: humid_tcnt = read_humid_s2()
      case 3: humid_tcnt = read_humid_s3()
      case 4: humid_tcnt = read_humid_s4()
  end select

  ' Take multiple readings in a row and average them.
  ' for any single reading.
  humid_tot_read = 0
  for humid_ri = 1 to humid_num_to_read
    select case sens_num
      case 0: humid_tcnt = read_humid_s0()
      case 1: humid_tcnt = read_humid_s1()
      case 2: humid_tcnt = read_humid_s2()
      case 3: humid_tcnt = read_humid_s3()
      case 4: humid_tcnt = read_humid_s4()
    end select
    humid_tot_read = humid_tot_read + humid_tcnt
  next humid_ri
  humid_tot_read = humid_tot_read / humid_num_to_read
  read_humid = humid_tot_read
end function


sub humid_set_sensor_active(sensor_num as byte)

end sub

sub humid_set_sensor_deactive(sensor_num as byte)

end sub

sub humid_set_sensor_alarm_hi(sensor_num as byte, alarm_perc as word)
end sub

sub humid_set_sensor_alarm_lo(sensor_num as byte, alarm_perc as word)
end sub

' return alarm threashol value for hi sensor
' or 0 if not set
function humid_sensor_alarm_hi(sensor_num as byte)
end function

' return alarm threashold for low alarm or 0 if not set
function humid_sensor_alarm_lo(sensor_num as byte)
end function



' Calibrate multiple sensors to the specified
' percentage.   This is used in the case when
' all the sensors are placed in the same chamber
' and need to all be calibrated for that percentage solution.
sub humid_calibrate_sensors(slot_num as byte,  perc_in as byte)


end sub



' Read the sensor and until we get 10 readings where the
' net delta in readings is less than 1 count unit +-
' then average the next 20 readings ans save the result
' in configuration slot for that sensor.
sub humid_calibrate_sensor(sensor_num as byte, slot_num as byte, perc_in as word)

end sub


' Loop through the slots and find the first highest
' low reading  which is less than the reading in
' and the lowest high reading which is higher than
' the
Function humid_find_slots(sensor_num as byte, reading as word)

end function




' *********************
' *** Primitive sensor reading
' *********************


'*****
'**** Would prefer to pass the bit number into the read_humdiity_sensor
'*** but can not figure out how to get Bascom to accept this.
'*****
Function read_humid_s0() As Word
    reset humid_rc_charge
    Bitwait humid_rc_read_s0, reset  ' wait until read low
    waitms humid_wait_between_read ' Give time to discharge thorugh diode.

    humid_tcnt = 0
    set humid_led
    set humid_rc_charge
    while humid_rc_read_s0 < bon ' Manual loop to see how long it takes to
      humid_tcnt = humid_tcnt + 1   ' Charge the capacitor
    wend
    reset humid_rc_charge
    reset humid_led
    read_humid_s0 = humid_tcnt
end function

'*****
'**** Would prefer to pass the bit number into the read_humdiity_sensor
'*** but can not figure out how to get Bascom to accept this.
'*****
Function read_humid_s1() As Word
    reset humid_rc_charge
    Bitwait humid_rc_read_s1, reset  ' wait until read low
    waitms humid_wait_between_read ' Give time to discharge thorugh diode.

    humid_tcnt = 0
    set humid_led
    set humid_rc_charge
    while humid_rc_read_s1 < bon ' Manual loop to see how long it takes to
      humid_tcnt = humid_tcnt + 1   ' Charge the capacitor
    wend
    reset humid_rc_charge
    reset humid_led
    read_humid_s1 = humid_tcnt
end function

'*****
'**** Would prefer to pass the bit number into the read_humdiity_sensor
'*** but can not figure out how to get Bascom to accept this.
'*****
Function read_humid_s2() As Word
    reset humid_rc_charge
    Bitwait humid_rc_read_s2, reset  ' wait until read low
    waitms humid_wait_between_read ' Give time to discharge thorugh diode.

    humid_tcnt = 0
    set humid_led
    set humid_rc_charge
    while humid_rc_read_s2 < bon ' Manual loop to see how long it takes to
      humid_tcnt = humid_tcnt + 1   ' Charge the capacitor
    wend
    reset humid_rc_charge
    reset humid_led
    read_humid_s2 = humid_tcnt
end function

'*****
'**** Would prefer to pass the bit number into the read_humdiity_sensor
'*** but can not figure out how to get Bascom to accept this.
'*****
Function read_humid_s3() As Word
    reset humid_rc_charge
    Bitwait humid_rc_read_s3, reset  ' wait until read low
    waitms humid_wait_between_read ' Give time to discharge thorugh diode.

    humid_tcnt = 0
    set humid_led
    set humid_rc_charge
    while humid_rc_read_s3 < bon ' Manual loop to see how long it takes to
      humid_tcnt = humid_tcnt + 1   ' Charge the capacitor
    wend
    reset humid_rc_charge
    reset humid_led
    read_humid_s3 = humid_tcnt
end function

'*****
'**** Would prefer to pass the bit number into the read_humdiity_sensor
'*** but can not figure out how to get Bascom to accept this.
'*****
Function read_humid_s4() As Word
    reset humid_rc_charge
    Bitwait humid_rc_read_s4, reset  ' wait until read low
    waitms humid_wait_between_read ' Give time to discharge thorugh diode.

    humid_tcnt = 0
    set humid_led
    set humid_rc_charge
    while humid_rc_read_s4 < bon ' Manual loop to see how long it takes to
      humid_tcnt = humid_tcnt + 1   ' Charge the capacitor
    wend
    reset humid_rc_charge
    reset humid_led
    read_humid_s4 = humid_tcnt
end function

'*****
'**** Would prefer to pass the bit number into the read_humdiity_sensor
'*** but can not figure out how to get Bascom to accept this.
'*****
Function read_humid_s5() As Word
    reset humid_rc_charge
    Bitwait humid_rc_read_s5, reset  ' wait until read low
    waitms humid_wait_between_read ' Give time to discharge thorugh diode.

    humid_tcnt = 0
    set humid_led
    set humid_rc_charge
    while humid_rc_read_s5 < bon ' Manual loop to see how long it takes to
      humid_tcnt = humid_tcnt + 1   ' Charge the capacitor
    wend
    reset humid_rc_charge
    reset humid_led
    read_humid_s5 = humid_tcnt
end function

'*****
'**** Would prefer to pass the bit number into the read_humdiity_sensor
'*** but can not figure out how to get Bascom to accept this.
'*****
Function read_humid_s6() As Word
    reset humid_rc_charge
    Bitwait humid_rc_read_s6, reset  ' wait until read low
    waitms humid_wait_between_read ' Give time to discharge thorugh diode.

    humid_tcnt = 0
    set humid_led
    set humid_rc_charge
    while humid_rc_read_s6 < bon ' Manual loop to see how long it takes to
      humid_tcnt = humid_tcnt + 1   ' Charge the capacitor
    wend
    reset humid_rc_charge
    reset humid_led
    read_humid_s6 = humid_tcnt
end function

