'Telemetry to rtty by M0DTS
'rob@m0dts.co.uk
'Reads data from sensors and outputs the data in a string in fsk ASCII8 format
'External temp sensor is a DS18B20 from sparkfun
'Pressure and Internal Temp sensor is a BMP085 from sparkfun
'Battery voltage is sent from an ADC port and uses vref pin
DEFINE OSC 4 '4MHz oscillator
'Main Variables
string VAR BYTE[66] 'Main array containing string to be transmitted
abyte VAR BYTE 'byte to send on fsk port
abyte2 VAR BYTE[3] 'byte array for checksum decimal to hex conversion
polarity VAR BIT 'Used for setting fsk polarity
a VAR BYTE 'Universal count variable
counter VAR WORD 'loop counter
sum VAR BYTE 'Checksum return value
strlen VAR BYTE 'string position
volts VAR WORD 'ADC reading for voltage
sign VAR BYTE 'Temperature positive/negative sign
tempC VAR BYTE 'Temp calc
temp2 VAR WORD 'Temp calc
temp VAR WORD 'Temp calc
utemp VAR WORD 'Un compensated BMP085 temp reading
upres VAR WORD 'Un compensated BMP085 pressure reading
Cal_table VAR WORD[11] 'BMP085 Sensor calibration data
AC1 VAR Cal_table[0] '
AC2 VAR Cal_table[1] 'BMP085 has 11 16bit values stored in EEPROM
AC3 VAR Cal_table[2] 'First byte is at $AA last at $BF, two bytes per cal value
AC4 VAR Cal_table[3] 'Lowbyte is MSB (e.g $AA), Highbyte is LSB (e.g. $AB)
AC5 VAR Cal_table[4] '
AC6 VAR Cal_table[5]
B1 VAR Cal_table[6] 'AC4, AC5, AC6 are UNSIGNED values, the rest are SIGNED
B2 VAR Cal_table[7]
MB VAR Cal_table[8]
MC VAR Cal_table[9]
MD VAR Cal_table[10]
'Port aliases
DQ VAR PORTC.1 'One-Wire data pin (DS18B20)
CS VAR PORTC.5 'Chip select for BMP085
SDA VAR PORTC.4 'Data line to BMP085
SCL VAR PORTC.3 'Clock line to BMP085
'Port settings '16F688 specific settings
TRISA = %000010 'PortA.1 is only input on PortA for Vref
'TRISC = %011100 'not configured, upsets I2C???
Ansel=%01000010 'AN6 selected, all other digital *
Cmcon0=%00000111 'sets comparator pins to digital ports
Adcon0=%11011001 'Right justified,Enabled *
Adcon1=%00100000 'fosc/32
DEFINE ADC_BITS 10 ' 10-bits for adc value
'Setup initialise port levels
porta.2 = 1
PAUSE 4000
counter = 1
cs = 1
'RTTY Polarity
polarity = 0 '0=normal, 1=inverted
'Main Program
main:
GOSUB readtemp 'Get temp
GOSUB readtp 'Read temp/pressure from BMP085
PAUSE 2000 'delay 2sec
GOSUB readvolts 'read battery ADC value
GOSUB sendrtty 'Send RTTY data
counter= counter + 1 'Incrememnt line counter
GOSUB main 'Loop
readtp: 'Read BMP085 sensor data
CS =0 'Enable BMP085
'gosub readcal 'Only required once for data, calculation done on server
'$F4 is the control register address
I2CWRITE SDA,SCL,$EE,$F4,[$2E]
PAUSE 30 'Delay 30ms after each write
'$F6 is the result register MSB
I2CREAD SDA,SCL,$EF,$F6,[utemp],I2C_error
'serout2 portc.0,16780,["Utemp:",dec utemp,10,13] 'debug
I2CWRITE SDA,SCL,$EE,$F4,[$34] 'Write $34 to set pressure conversion (OSS=0)
PAUSE 30 'Delay 30ms after each write
I2CREAD SDA,SCL,$EF,$F6,[upres],I2C_error 'Read pressure MSB, LSB
'serout2 portc.0,16780,["Upressure:",dec upres,10,13] 'debug
cs = 1 'Disable BMP085
RETURN
readtemp: 'Read DS18B20 sensor data, works with only one sensor, no id used.
OWOUT DQ, 1,[$CC, $44] 'Initialise Temp conversion
PAUSE 1000 'Wait for conversion - 1 second!
OWOUT DQ, 1, [$CC, $BE] 'Get sensor to send data from scratchpad
OWIN DQ,2,[temp.LowByte,temp.HighByte] 'Read first 2 bytes of data (temperature) and store in temp variable
IF temp.Bit11 = 1 THEN
sign="-"
temp2 = 625 * ~temp+1 'Multiply to load internal registers with 32-bit value
tempC = DIV32 1000 'Use Div32 value to calculate precise deg C
ELSE
sign="+"
temp2 = 625 * temp 'Multiply to load internal registers with 32-bit value
tempC = DIV32 1000 'Use Div32 value to calculate precise deg C, eg 201 for 20.1C
ENDIF
RETURN
readcal:
I2CREAD SDA,SCL,$EF,$AA,[STR Cal_table\11],cal_error 'Read 11 reversed words out of BMP085 sensor
SEROUT2 portc.0,16780,["Cal data in order:",10,13] 'debug
AC1 = (AC1.LowByte<<8) + AC1.HighByte 'swap MSB and LSB of each to use in PBP (un-reverse then)
AC2 = (AC2.LowByte<<8) + AC2.HighByte 'device stores the MSB in the Low byte, LSB in the High byte
AC3 = (AC3.LowByte<<8) + AC3.HighByte
AC4 = (AC4.LowByte<<8) + AC4.HighByte
AC5 = (AC5.LowByte<<8) + AC5.HighByte
AC6 = (AC6.LowByte<<8) + AC6.HighByte
B1 = (B1.LowByte<<8) + B1.HighByte
B2 = (B2.LowByte<<8) + B2.HighByte
MB = (MB.LowByte<<8) + MB.HighByte
MC = (MC.LowByte<<8) + MC.HighByte
MD = (MD.LowByte<<8) + MD.HighByte
'serout2 portc.0,16780,[10,13,Sdec ac1,10,13,Sdec ac2,10,13,Sdec ac3,10,13,dec ac4,10,13,dec ac5,10,13,dec ac6,10,13,Sdec B1,10,13,Sdec B2,10,13,Sdec MB,10,13,Sdec MC,10,13,Sdec MD,10,13]
RETURN
I2C_error:
SEROUT2 portc.0,16780,["I2C problem....",10,13]
GOTO main
cal_error:
SEROUT2 portc.0,16780,["I2C cannot read cal....",10,13]
GOTO main
readvolts:
ADCIN 6,volts 'Read ADC value from Port 6 into 'volts' variable
'serout2 portc.0,16780,["Voltage:",dec volts,".",10,13] 'debug
RETURN
sendrtty: 'Load chars into array(string) then send out on FSK port.
strlen = 0 'initialise string position counter
FOR a=0 TO 11
LOOKUP a,[" $$PAYLOAD,"],abyte 'Lookup stores char number into 'abyte' variable, incrementing a in for/loop
string[a] = abyte
NEXT
strlen = strlen + a
'Send line counter - 5 digits
FOR a = 0 TO 4
string[strlen + a] = counter DIG (4-a) +48 'Send decimal digits one at a time with DIG command, ascii = +48
NEXT 'by default digit 0 is the MSB digit so need to reverse with (4-a)
strlen = strlen + a
string[strlen] = "," 'comma seperated values in string
strlen = strlen +1
FOR a = 0 TO 4 'Include pressure
string[strlen +a] = upres DIG (4-a) +48
NEXT
strlen = strlen + a
string[strlen] = "," 'comma seperated values in string
strlen = strlen +1
FOR a = 0 TO 4 'Include Internal temp
string[strlen +a] = utemp DIG (4-a) +48
NEXT
strlen = strlen + a
string[strlen] = "," 'comma seperated values in string
strlen = strlen +1
string[strlen] = sign 'Temperature positive/negative sign
strlen = strlen +1
'Include External Temp
string[strlen] = tempC DIG (2) +48
strlen = strlen +1
string[strlen] = tempC DIG (1) +48
strlen = strlen +1
string[strlen] = "."
strlen = strlen +1
string[strlen] = tempC DIG (0) +48
strlen = strlen +1
string[strlen] = "," 'comma seperated values in string
strlen = strlen +1
FOR a = 0 TO 2 'Send Voltage, raw ADC value
string[strlen +a] = volts DIG (2-a) +48
NEXT
strlen = strlen + a
string[strlen] = "," 'comma seperated values in string
strlen = strlen +1
GOSUB checksum 'calcuate XOR checksum for 'string'
FOR a = 0 TO strlen -1 'Send main string rtty...
abyte = string[a]
GOSUB sendbyte 'Sendbyte routine sends each bit of 'abyte' in sequence on FSK pin
NEXT
abyte = "*" 'Send * before checksum
GOSUB sendbyte
a=0
'convert checksum decimal to hex
WHILE sum > 0
abyte2[a] = (sum // 16) +48 '// division returns remainder, 48 = ASCII char "0"
IF abyte2[a] > 57 THEN 'if char is greater than 9 then jump to A etc..
abyte2[a] = (abyte2[a] + 7 )
ENDIF
sum = sum / 16 'continue until sum cannot be divided as whole by 16 (end of string)
a=a+1
WEND
'serout2 portb.1,16780,[DEC abyte2[1],10,13] 'Debug
FOR a = 0 TO 1 'Send checksum hex chars
abyte = abyte2[1-a]
GOSUB sendbyte
NEXT
abyte = 10 'send newline char
GOSUB sendbyte
PAUSE 500
RETURN 'return to main routine
CheckSum: 'Calculate XOR checksum value
sum = 0 'Clear SUM on entry 'chopping off "$" & "*"
FOR a = 2 TO strlen -1 'ignore $$ at beginning
sum = (sum ^ string[a]) 'XOR 'sum' with next byte in 'string' until end of string
NEXT
RETURN
sendbyte: 'sends each bit of 'abyte' in sequence on FSK pin
a=0
porta.2=0 - polarity 'Start Bit - normal = low
PAUSEUS 20000 '20mS bit time, 1second/50baud
FOR a=0 TO 7
porta.2=abyte.0[a] - polarity
PAUSEUS 20000
NEXT
porta.2=1 - polarity 'Stop bit - normal = high
PAUSEUS 20000 '31000 for 6MHz
RETURN