1

I want to have two more-or-less independent programs running on my Raspberry Pi, one that monitors temperature and another that does protocol translation between two asynchronous serial devices.

I have a program running on my Raspberry Pi that prints out temperatures from a couple of MAX31820 thermometers on a 1-wire bus attached to P1 pin 7. It seems to work fine by itself.

I also have another program my Raspberry Pi that reads and writes data to two different RS-232-like asynchronous serial communication serial devices. (The Pi reads data in one format from a RS-485 bus through one level converter, reformats it to another protocol and sends it to a camera's 3.3 V UART). From what I read on the web, the pigpio library is the easiest way to get a second UART. (Thank you, joan2937 !) (That program uses P1 pins 8, 10, 11, and 13). The program I write that uses pigpio to talk to those two devices also seems to work by itself.

Alas, after I start pigpio, my thermometer program can't see the thermometers any more. When I do "sudo killall pigpiod", my thermometer program starts working again.

Is there some way to tell pigpio to let my thermometer program access the 1-wire bus in the normal way? How do I get these two programs to work together running at the same time?

#!/usr/bin/env python
# thermometer.py
# based on https://learn.adafruit.com/adafruits-raspberry-pi-lesson-11-ds18b20-temperature-sensing/software

import os 
import glob 
import time

os.system('modprobe w1-gpio') 
os.system('modprobe w1-therm')

base_dir = '/sys/bus/w1/devices/' 
device_folder = glob.glob(base_dir + '28*') 
device_file = [
    device_folder[0] + '/w1_slave',
    device_folder[1] + '/w1_slave'
    ]

def read_temp_raw(which):
  f = open(device_file[which], 'r') 
  lines = f.readlines()  
  f.close()
  return lines

def read_temp(which):
  lines = read_temp_raw(which)
  while lines[0].strip()[-3:] != 'YES':
    time.sleep(0.2)
    lines = read_temp_raw()  
  equals_pos = lines[1].find('t=') 
  if equals_pos != -1:
    temp_string = lines[1][equals_pos+2:] 
    temp_c = float(temp_string) / 1000.0 
    temp_f = temp_c * 9.0 / 5.0 + 32.0 
    return which, temp_c, temp_f

while True:
  temp0 = read_temp(0)
  temp1 = read_temp(1)
  print(temp0),
  print(temp1)
  difference = temp0[2] - temp1[2]
  print("difference: " + str(difference) )
  time.sleep(1)

EDIT: Thank you, joan. I think your hint puts me very close to solving this problem.

In order to make a SSCCE I trimmed down a (copy of) the other program, serial.py, that used pigpio, and I was surprised to find it still interfered with the temperature readings even when it was reduced so far that it no longer actually does any serial communication or even references pigpio:

#!/usr/bin/python
# serial.py

import time

#returns ms since the epoch
def millis():
    return time.time() * 1000

def delay(milliseconds):
    delay_float = milliseconds / 1000.0
    time.sleep(delay_float)

def rs485_loop():
      print "starting 'while 1:' loop: "
      delay(50)
      while 1:
        now = millis()

if __name__ == '__main__':
        rs485_loop()

The symptom I'm seeing is:

  • I run the thermometer program, it prints the temperature periodically.
  • I run the serial program, then the thermometer program doesn't print anything for a long time -- locked up?
  • I pause the serial program with CTRL+Z, then the thermometer program resumes printing out temperatures again
  • I resume the serial program with "fg", then the thermometer program doesn't print anything for a long time -- locked up?
  • I stop the serial program with "CTRL+C", then the thermometer program resumes printing out temperatures again.

What I want to happen is:

  • I run the thermometer program, it prints the temperature periodically.
  • I run the serial program (as a separate process), and it runs fine and the thermometer program continues to print the temperature periodically.
  • pigpio should not interfere with the 1-wire bus, or any gpios it is not told to use. To clarify are you saying that the above (DS18B20 reading) code stops working if you run sudo pigpiod? – joan Aug 19 '15 at 17:30
  • 1
    I have only just noticed your edit. The rs485_loop() is doing a busy spin and will be trying to use 100% CPU. Add a delay(0.01) or similar at the same level as the now = millis(). – joan Aug 20 '15 at 8:34
  • @joan: Thank you very much. I've added the delay to not only my test code but the corresponding location in the full application, and now while the full application (which uses pigpiod) is running in the background I can run the thermometer application and both work fine. Yay! Post an answer mentioning "sleep" or "delay" so I can mark it as accepted. – David Cary Aug 20 '15 at 20:11
2

Whenever you have multiple threads of activity it is important each thread is not starved of time.

This is usually taken care of automatically if your thread contains system calls which yield to another thread, e.g. I/O calls.

If a thread does a busy loop without such a system call it is important to add a time delay to allow other threads time to run.

In the question

def rs485_loop():
      print "starting 'while 1:' loop: "
      delay(50)
      while 1:
        now = millis()

the

      while 1:
        now = millis()

is a busy spin.

To give other threads time to run change the code to something like

def rs485_loop():
      print "starting 'while 1:' loop: "
      delay(50)
      while 1:
        now = millis()
        time.sleep(0.01)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.