smartyPies.com

ADS1115Runner.py

Mark&copy&paste the code into a file named "ADS1115Runner.py".
Thanks to the guys from GeSHi and Curt, who made me revise the code.

Created with GeSHi http://qbnz.com/highlighter/
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. '''
  4. @author: guido lutterbach
  5. @contact: guido@smartypies.com
  6. @version: 1.1
  7. @licence: Public Domain
  8.  
  9. This program implements 4 cases for ADS1115 on raspberry pi with default libraries.
  10. 1) single-shot - open drain - timed
  11. 2) single-shot - open drain - GPIO alert
  12. 3) continuous mode - differential - GPIO alert
  13. 4) continuous mode - differential - GPIO alert when value leaves high/low threshold range
  14. Please check the electric circuit that goes with it at www.smartypies.com (ADS1115 project)
  15. For testing 1) + 2) use potentiometer 1
  16. For testing 3) + 4) use potentiometer 2
  17. Enjoy!
  18. '''
  19.  
  20. import cmd, time, logging, smbus, RPi.GPIO as GPIO
  21.  
  22. # ADS1115 + hardware constants
  23. I2C_BUS = 1
  24. DEVICE_ADDRESS = 0x4B
  25. POINTER_CONVERSION = 0x0
  26. POINTER_CONFIGURATION = 0x1
  27. POINTER_LOW_THRESHOLD = 0x2
  28. POINTER_HIGH_THRESHOLD = 0x3
  29.  
  30. RESET_ADDRESS = 0b0000000
  31. RESET_COMMAND = 0b00000110
  32.  
  33. # Open I2C device
  34. BUS = smbus.SMBus(I2C_BUS)
  35. BUS.open(I2C_BUS)
  36.  
  37. ALERTPIN =  27
  38.        
  39. def swap2Bytes(c):
  40.     '''Revert Byte order for Words (2 Bytes, 16 Bit).'''
  41.     return (c>>8 |c<<8)&0xFFFF
  42.  
  43. def prepareLEconf(BEconf):
  44.     '''Prepare LittleEndian Byte pattern from BigEndian configuration string, with separators.'''
  45.     c = int(BEconf.replace('-',''), base=2)
  46.     return swap2Bytes(c)
  47.  
  48. def LEtoBE(c):
  49.     '''Little Endian to BigEndian conversion for signed 2Byte integers (2 complement).'''
  50.     c = swap2Bytes(c)
  51.     if(c >= 2**15):
  52.         c= c-2**16
  53.     return c
  54.  
  55. def BEtoLE(c):
  56.     '''BigEndian to LittleEndian conversion for signed 2 Byte integers (2 complement).'''
  57.     if(c < 0):
  58.         c= 2**16 + c
  59.     return swap2Bytes(c)
  60.  
  61. def resetChip():
  62.     BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)
  63.     return
  64. # Use BCM GPIO references
  65. GPIO.setmode(GPIO.BCM)
  66. GPIO.setup(ALERTPIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) ## read mode, pull up resistor
  67.  
  68.  
  69. class ADS1115Runner(cmd.Cmd):
  70.     intro = '''usage: type following commands
  71.           1    - one-shot measurement mode, timed
  72.           2    - one-shot measurement mode, alerted through GPIO
  73.           3    - continuous measurment mode, alerted through GPIO
  74.           4  low high  - continuous mode, alerted when value out of range [low, high]
  75.           q (quit)
  76.           just hitting enter quits any mode 1-4. Enter 'y' to continue in modes 1 and 2.'''
  77.     prompt = 'Enter 1,2,3,4 or q >>'
  78.     file = None
  79.  
  80. #    __logfile = None
  81.  
  82.     def alerted(self, arg):        
  83.         data_raw =  BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
  84.         print('alerted:' + str(LEtoBE(data_raw)))
  85.         return
  86.    
  87.     def do_1(self, arg):
  88.         '''One-shot, Read value from channel 0 with wait time'''
  89.         resetChip()
  90.        
  91.         # compare with configuration settings from ADS115 datasheet
  92.         # start single conversion - AIN2/GND - 4.096V - single shot - 8SPS - X
  93.         # - X - X - disable comparator
  94.         conf = prepareLEconf('1-110-001-1-000-0-0-0-11')
  95.  
  96.         go = 'y'
  97.         while True and go in ['y','Y']:
  98.             BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
  99.             # long enough to be safe that data acquisition (conversion) has completed
  100.             # may be calculated from data rate + some extra time for safety.
  101.             # check accuracy in any case.
  102.             time.sleep(0.2)
  103.             value_raw = BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
  104.             value = LEtoBE(value_raw)
  105.             print(value)
  106.             #enter to break, repeat with 'y'
  107.             go= input('continue: n/y')
  108.             if (len(go)==0):
  109.                 go='n'
  110.         return
  111.    
  112.     def do_2(self, arg):
  113.         '''One-shot with GPIO alert'''
  114.         # register callback for alerts
  115.         GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
  116.         # reset call
  117.         resetChip()
  118.         # compare with configuration settings from ADS115 datasheet:
  119.         # start single conversion - AIN2/GND - 4.096V - single shot - 8SPS -
  120.         # trad. comparator - active high - latching - assert after one conversion
  121.         conf = prepareLEconf('1-110-001-1-000-0-1-1-00')
  122.         BUS.write_byte(0b0000000,0b00000110) # reset call
  123.         # set High and Low threshold for ALERT pin mode
  124.         BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, 0xFF7F) # 0x7FFF in BigEndian
  125.         BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, 0x0080) # 0x8000 in BigEndian  
  126.         go = 'y'
  127.         while True and go in ['y','Y']:
  128.             BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
  129.             #enter to break, repeat with 'y'
  130.             go= input('continue: n/y\n')
  131.  
  132.         # remove event listener
  133.         GPIO.remove_event_detect(ALERTPIN)
  134.         return
  135.    
  136.     def do_3(self, arg):
  137.         '''Continuous mode with GPIO alert'''
  138.         # register callback for alerts
  139.         GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
  140.         # reset call
  141.         resetChip()
  142.         # compare with configuration settings from ADS115 datasheet
  143.         # X - AIN0/AIN1 - 2.048V - continuous mode - 64SPS -
  144.         # window comparator - active high - nonlatching - assert after one conversion      
  145.         conf = prepareLEconf('0-000-010-0-011-1-1-0-00')
  146.         # set High and Low threshold for ALERT pin mode
  147.         BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, 0xFF7F) # 0x7FFF in BigEndian
  148.         BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, 0x0080) # 0x8000 in BigEndian
  149.         # write configuration ONCE
  150.         BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
  151.        
  152.         # wait for input(), enter to break
  153.         input('enter to stop\n' )
  154.         # remove event listener to stop execution
  155.         GPIO.remove_event_detect(ALERTPIN)
  156.         return
  157.    
  158.     def do_4(self, arg):
  159.         ''' Continuous measurements with latch and allowable data range'''
  160.         largs = tuple(map(int, arg.split()))
  161.         if len(largs) != 2:
  162.             print('please call with exactly 2 integer arguments')
  163.             return
  164.         # reset call
  165.         resetChip()
  166.         # compare with configuration settings from ADS115 datasheet
  167.         # X - AIN0/AIN1 - 2.048V - continuous mode - 8SPS -
  168.         # window comparator - active high - latching - assert after one conversion      
  169.         conf = prepareLEconf('0-000-010-0-000-1-1-1-00')
  170.         # register callback for alerts
  171.         GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
  172.         # prepare for ALERT pin mode - define window
  173.  
  174.         low = min(largs) # Python BigEndian - RaspberryPi LittleEndian
  175.         high = max(largs)
  176.         low_val = BEtoLE(low)
  177.         high_val = BEtoLE(high)
  178.         logger.debug( "{:04X} {:04x} {:04x} {:04x} ".format(low, low_val, high, high_val))
  179.         BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, low_val)
  180.         BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, high_val)
  181.        
  182.         # write configuration ONCE
  183.         BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
  184.        
  185.         # wait for input(), enter to break
  186.         input('enter to stop\n' )
  187.         # remove event listener to stop execution
  188.         GPIO.remove_event_detect(ALERTPIN)
  189.         return
  190.    
  191.     def do_q(self, arg):
  192.         '''Quit.'''
  193.         return True
  194.    
  195.     def default(self, line):
  196.         print('undefined key')
  197.    
  198.     def shutdown(self):
  199.         GPIO.cleanup()
  200.         BUS.close()
  201.         pass    
  202.  
  203. if __name__ == "__main__":
  204.     try:
  205.         logging.basicConfig(
  206.             level=logging.DEBUG,
  207.             #format='%(name)-12s: %(levelname)-8s %(message)s')
  208.             format='%(message)s')
  209.         logger = logging.getLogger('ADS1115Runner')
  210.         Runner = ADS1115Runner()
  211.         Runner.cmdloop()
  212.     finally:
  213.         Runner.shutdown()