Close

Arduino-like SoftwareSerial

A project log for ViperPhoton weather station

Host webpage with weather readings from distributed sensors on a viperized Photon

andreas.betzandreas.betz 10/28/2015 at 17:020 Comments

In the Arduino IDE there's a very nice little library called NewSoftSerial, which allows to establish a serial link on any digital pin of your Arduino board. Very neat stuff indeed and often used for 433MHz RF links.

Since this didn't exist on VIPER (yet), I've ported the "receive serial" part, using interrupt routines, to it (see below).

Now, I'm sure that there's better ways of coding this, but for the moment I'm quite happy with it.

################################################################################
# SoftRx
#
# Created: 2015-10-27 08:46:15.793526
#
################################################################################

#DO THESE THINGS IN THE MAIN PROGRAM

# import the streams module for USB serial port.
import streams

# open the default serial port
streams.serial()

#import necessary libraries
import timers
import pwm #needed to enable hwtimers to run (?)
import hwtimers

global RxBuffer
global RxByteDec

## end of things to do in main program

#########
#set up the SoftRx routine
#########
def SoftRx_setup(_rxpin, _baudrate, _timeUnit): # set _timeUnit=1 for microseconds, default is milliseconds
    global last_Rx_time
    global Rx_time
    global Rxpin
    global duration1bitMICROS
    global duration1bitMILLIS
    global RxBuffer
    global TimeUnit
    
    TimeUnit = _timeUnit
    Rxpin = _rxpin
    duration1bit = 1/_baudrate #duration of HIGH/LOW for 1 transmitted bit in seconds
    #
    duration1bitMILLIS = int(duration1bit*(10**3))
    duration1bitMICROS = int(duration1bit*(10**6)) # 1s = 10^6 microseconds, rounded to next integer
    RxBuffer = []
    last_Rx_time = 0 #used for interrupt settling
    Rx_time = timers.now() #used for interrupt settling, time in milliseconds
    
    ## debugging
#    print("debugging")
#    print(duration1bitMILLIS)
#    print(3/2*duration1bitMILLIS)
#    print(int(3/2*duration1bitMILLIS))

#########
# receive data on the software serial port
#########
def receive8bits():
    global last_Rx_time
    global Rx_time
    global Rxpin
    global duration1bitMICROS
    global duration1bitMILLIS
    global RxBuffer

    Rx_time = timers.now()
    time_test = Rx_time - last_Rx_time #time difference between last 2 interrupts, in milliseconds
    if time_test > int(10*duration1bitMILLIS): #interrupt fires at each HIGH->LOW, hence need to ignore any interrupt during reception of 1 byte = 1 start bit + 8 bits+1 stopbit
        if TimeUnit==1:
            hwtimers.sleep_micros(int(duration1bitMICROS/2)) # read at bit centres
        else:
            sleep(int(duration1bitMILLIS/2)) #only works for baudrates <1000
            #sleep(1)
        for i in range(9): #now read 9 bits (start+8) at their respective centres
            tmp = digitalRead(Rxpin)
            if len(RxBuffer)>255: #don't store more than 32 bytes (=256 bits) in buffer
                RxBuffer[0] = [] #remove oldest bit
            RxBuffer.append(tmp)
            #print(tmp) #use for debugging
            if TimeUnit==1:
                hwtimers.sleep_micros(duration1bitMICROS) # start bit: LOW for duration=1/baudrate, then read at bit centres
            else:
                sleep(duration1bitMILLIS) #only works for baudrates <1000
                #sleep(2)
        last_Rx_time = Rx_time
        RxBuffer[0:1] = [] #remove start bit
        return RxBuffer
    else:
        return

#########
# start up the serial port
#########
def SoftRx_start():
    onPinFall(Rxpin,receive8bits) #start listening on the SoftSerial port

#########
# convert RxBuffer to decimal
#########
def SoftRx_Bin2Dec(_BinList):
    tmpDec = 0
    for i in range(8):
        tmpDec += _BinList[i]*(2**i)
    return tmpDec


##the following is just to test the above...
SoftRx_setup(D0,500,1) # set up all the necessary bits
SoftRx_start() #start listening on the SoftSerial port


while True:
    sleep(1000)
    if len(RxBuffer)>0:
        RxData = RxBuffer[0:8]
        RxBuffer[0:8] = []
        RxByteDec = SoftRx_Bin2Dec(RxData)
        print(RxData)
        print(RxByteDec)
        print("---")

Discussions