Pages

Thursday, January 24, 2013

Hardware Configuration - 19 inch rack mount






Now I have mounted the third MCP23008 and the LCD1602 it drives.  I ran the test LCD function and the display comes out as expected.


# 11. Main test functions *****************************************************
StartProgram("*** Test Demultiplexer v110 TL Fong 2013jan22hkt2401 ***")

#TestBuzzer() # beep buzzer 4 times
#TestLED() # blink LED 8 tmes
#TestButtonEchoBuzzer() # echo buton with buzzer 10 times
#TestButtonEchoLED() # echo button with LED 10 times

# TestToggleMCP23017GP() # toggle MCP23017 output ports

# TestToggleMCP23008GP() # toggle MCP23008 output port

# TestMotor() # move two stepping motors

#TestPollingKeypad() # read 4 keys by polling IO Expander GPIO port of rows

# TestInterruptKeypad() # read 4 keys by polling IO Expander INT pin
# ToggleMCP23008GP(MCP23008BaseAddress1, toggleTime = 0.25, toggleCount = 4)
# ToggleMCP23008GP(MCP23008BaseAddress3, toggleTime = 2.0, toggleCount = 20)

TestLcd(LcdRegisterBaseAddress)

# TestDemux(LcdRegisterBaseAddress, DemuxRegisterBaseAddress, 0, 1)

EndProgram()



.END




# *****************************************************************************
# !/usr/bin/python2.7
#
# Program
#   tdemux112.py - 2013jan24
# Author
#   tlfong01 <http://tlfong01.blogspot.hk/>
# Configuration
#   Raspberry Pi Bv2 512MB, Raspbian Wheezy, Python 2.7.3, GPIO 0.4.1a
# License
#   GNU GPLv3
# Warranty
#   For hobbist only.  Use at your own risk.  There is not  any warranty,
#   not even implied warranty of merchantability or fitness for any
#   particular purpose
# System development methodologies / Programming paradims
#   Software prototyping, Test-driven (TDD), Iterative and incremental (IID),
#   Agile / Functional Programming (FP), Object Oriented Programming (OOP)
# Specifications summary
#   5V0max 50mA, 3V3max 300mA, PerPinMax 17mA source 12mA sink
# References
#   IO Expander
#     1. Mcirochip Application Notes AN1043 (GPIO Expander)
#   Matrix keypad
#     2. Microchip Application Notes AN1081 (Matrix Keypad)
#   LCD1602
#     3. ShenZhen YaJingDa Electronics YJD1602A-1 datasheet (2007-09-08)
#     4. PowerTip PC-1602F datasheet (11/10/2004)
#     5. Sitronix ST7066U Dot Matrix LCD Controller/Driver datasheet (01/03/01)
# Raspberry Pi communities
#   eLinux -  http://elinux.org/RPi_Community
#   element14 - http://www.element14.com/community/groups/raspberry-pi
# *****************************************************************************

# 0. Contents ******************************************************************
#
#  1. Python imports
#  2. RPi GPIO pin assignment
#  3. Global constants
#  4. GPIO Functions
#  5. Debugging and documentation functions (beep, print bit/byte, message)
#  6. IO Expander MCP23008, MCP23017
#  7. Unipolar Stepping Motor 28BYJ48/NPM-PF35/PX245
#  8. Decimal keypad
#  9. LCD1602
# 10. Demultiplexor
# 11. Main test functions


# 1. Python imports ***********************************************************

import smbus
import sys
import RPi.GPIO as GPIO
from time import sleep
import select # interrupt module, not tested yet

# from __future__ import print_function       # import Python 3 print function so it can be used


# 2. RPi GPIO pin assignment **************************************************
#
GPIO.setmode(GPIO.BOARD) # Use RPi GPIO numbering, Not BCM numbering
GPIO.setwarnings(False)  # Disable linux's "pin already in use warning"

# * RPi GPIO pin numbering *

# P1-02 5V, P1-04 5V, P1-06 Gnd
# P1-01 3V3, P1-03 I2C SDA1, P1-05 I2C SCL1
# P1-08 UART TxD (MCP23017 Reset)
# P1-10 UART RxD (MCP23017 INTB)
# P1-12 RPi GPIO_GEN1 (BCM18) LED (P1-12 > LED > 330R > Gnd)
# P1-14 Gnd
# P1-16 GPIO_GEN4 - Buzzer, 3V3 5mA (P1-16 > Buzzer > Gnd)
# P1-18 GPIO_GEN5 Button (3V3 > 10K > Contact 1/2 > 330R > Gnd)
# P1-20 Gnd
# P1-22 GPIO_GEN6 - MCP23008 INT / MCP23017 INTA  

RPiGPIOgen1 = 12 # Brown  (P1-12, BCM GPIO 18) LED
RPiGPIOgen4 = 16 # Yellow (P1-16, BCM GPIO 23) Buzzer
RPiGPIOgen5 = 18 # Green  (P1-18, BCM GPIO 24) Button
RPiGPIOgen6 = 22 # Blue   (P1-22, BCM GPIO 25) IOx/keypad interrupt

RPiTxD = 8 # Orange (P1-08) UART TxD
RPiRxD = 10 # Yellow (P1-10) UART RxD

# * peripherals pins assignment *

LEDpin = RPiGPIOgen1
BuzzerPin = RPiGPIOgen4
ButtonPin = RPiGPIOgen5
TxDpin = RPiTxD
RxDpin = RPiRxD
KeypadInterruptPin = ButtonPin

# * GPIO input/output pins list *

OutputPinList = [LEDpin, BuzzerPin, TxDpin]
InputPinWithNoPullUpList = [ButtonPin, KeypadInterruptPin, RPiGPIOgen6]
InputPinWithPullUpList = []


# 3. Global constants *********************************************************

# * Loop counters *
TwoTimes = 2
FourTimes = 4
EightTimes = 8
TenTimes = 10
TwentyTimes = 20
FiftyTimes = 50
OneHundredTimes = 100
TwoHundredTimess = 200
FourHundredTimes = 400

# * Elapse times *
TwentyMilliSeconds = 0.02
FiftyMilliSeconds = 0.05
TenthSecond = 0.1
QuarterSecond = 0.25
HalfSecond = 0.5
OneSecond = 1
OneAndHalfSeconds = 1.5
TwoSeconds = 2

# * On/Off times *
OnTime = TenthSecond
OffTime = QuarterSecond
ButtonDebouncingTime = QuarterSecond
TestTime = FiftyMilliSeconds

# * Nibble naming *
LowNibble = 0
HighNibble = 1
BothNibble = 2 # full byte of 8 bits

# * Nibble constants *
HighNibble1LowNibble0 = 0xf0
HighNibble0LowNibble1 = 0x0f

# * LED and buzzer states *
Off = False
On = True

# * Button states *
ButtonPressed = False
ButonReleased = True

# * Interrupt states *
Low = False
High = True

# 4. GPIO Functions ***********************************************************
#
# * Setup, read/write GPIO pins *
setupOutputPin = lambda oPin: GPIO.setup(oPin, GPIO.OUT) # set GPIO pin as output

setupInputPinWithNoPullUp = lambda iPin: GPIO.setup(iPin, GPIO.IN, pull_up_down=GPIO.PUD_OFF) # set GPIO pin as input, no pull up

setupInputPinWithPullUp = lambda iPin: GPIO.setup(iPin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # set GPIO pin as input, with pull up

writeOutputPin = lambda oPin, oValue: GPIO.output(oPin, oValue) # write value to output pin

setupWriteOutputPin = lambda oPin, oValue: (setupOutputPin(oPin), writeOutputPin(oPin, oValue)) # set and write

readInputPin = lambda iPin: GPIO.input(ButtonPin) # read value from input pin

def SetupGPIOpins(outputPinList, inputPinWithNoPullUpList, inputPinWithPullUpList): # set up GPIO pins in InputPinList and OutputPinList
    for oPin in outputPinList:
       setupWriteOutputPin(oPin, Off)
    for iPin in inputPinWithNoPullUpList:
        setupInputPinWithPullUp(iPin)
    for iPin in inputPinWithPullUpList:
        setupInputPinWithPullUp(iPin)

def SetupGPIO(): # set up GPIO pins
     SetupGPIOpins(OutputPinList, InputPinWithNoPullUpList, InputPinWithPullUpList )

# * pulse/echo/toggle functions *

def pulsePin(oPin, onTime, offTime): # blink LED or beep buzzer
    writeOutputPin(oPin, On)
    sleep(onTime)
    writeOutputPin(oPin, Off)   
    sleep(offTime)

def echoPin(iPin, oPin): # echo input pin to output pin, e.g. button to LED or buzzer
    while True:
        if readInputPin(iPin) == ButonReleased:
            pass
        else:
            pulsePin(oPin, OnTime, OffTime)
            break
        continue

def togglePin(oPin, toggleTime): # toggle pin
    writeOutputPin(oPin, On)
    sleep(toggleTime)
    writeOutputPin(oPin, Off)   
    sleep(toggleTime)

# * Test Buzzer, LED, Button *
def TestBuzzer(): # beep 4 times
    SetupGPIO()
    for i in range (FourTimes):
        pulsePin(BuzzerPin, OnTime, OffTime)

def TestLED(): # blink 8 times
    SetupGPIO()
    for i in range (EightTimes):
        pulsePin(LEDpin, OnTime, OffTime)

def TestButtonEchoBuzzer(): #
    SetupGPIO()
    for i in range (TenTimes):
        echoPin(ButtonPin, BuzzerPin)         

def TestButtonEchoLED(): #
    SetupGPIO()
    for i in range (TenTimes):
        echoPin(ButtonPin, LEDpin)

# GPIO Interrupt function !!! not yet tested !!!
def TestInterruptPinFallingEdgeDetection(): # !!! Not tested !!!
    GPIO.cleanup() # set all input pins no pull up, disable all interutp detection setting
    SetupGPIO()  
    GPIO.set_low_event(InterruptPin) # set up low level detection

    for i in range(30):
        if GPIO.event_detected(InterruptPin):
        break
        else:
            print "No interrupt detected.", i
            sleep(1)
        continue

    GPIO.set_low_event(InterruptPin, enable = False)  # disable detection
    print "End of test, or interrupt detected"


# 5. Debugging and documentation functions ************************************

# * Data bit processing and printing *

def SetDataBit(dataByte, bitIndex):
    setDataByte = 0x01 << bitIndex
    dataByte = dataByte | setDataByte
    return dataByte

def ResetDataBit(dataByte, bitIndex):
    resetDataByte = ~(0x01 << bitIndex)
    dataByte = dataByte & resetDataByte
    return dataByte

def ConvertIntegerToFourBitPattern(integer):
    FourBitPattern = [""]
    for k in range(4):
        FourBitPattern = [i+j for i in ['0','1'] for j in FourBitPattern]
    return FourBitPattern[integer]

def ConvertIntegerToEightPattern(integer):
    EightBitPattern = [""]
    for k in range(8):
        EightBitPattern = [i+j for i in ['0','1'] for j in EightBitPattern]
    return EightBitPattern[integer]

def PrintEightBitPattern(message, dataByte):
    eightBitPattern = ConvertIntegerToEightPattern(dataByte)
    print message, eightBitPattern

OnTime = 0.1
OffTime = 0.25

def Beep(count):
    for i in range(count):
        pulsePin(BuzzerPin, OnTime, OffTime)
   
def StartBeep():
    Beep(4)
    sleep(1)

def EndBeep():
    Beep(4)

def OneBeep():
    Beep(1)

def FourBeeps():
    Beep(4)

def StartProgram(message):
    SetupGPIO()
    StartBeep()
    print "\n", message, "\n"

def EndProgram():
    EndBeep()
    endMessage = "*** End of program.***"
    print "\n", endMessage, "\n"

# 6. IO Expander MCP23008, MCP23017 *******************************************

# * Setup SMBus *
I2C_BUS_NUMBER = 1 # P1-03 = SDA1, P1-05 = SCL1
smBus1 = smbus.SMBus(I2C_BUS_NUMBER) # global variable, cannot be set by a function

# * Register base addresses *
MCP23017BaseAddress1 = 0x22 # LED, button
MCP23008BaseAddress1 = 0x24 # stepping motors
MCP23008BaseAddress2 = 0x25 # keypad
MCP23008BaseAddress3 = 0x26 # LCD1602

# * i2cdetect/i2cset commands *
# To detect I2C device base addresses
#   sudo i2cdetect -y 1
# * To toggle GPIO pin *
#  !/bin/bash
#   i2cset -y 1 0x20 0x00 0x00
#   count=0
#   while [ $count -lt 10 ];
#   do
#     i2cset -y 1 0x20 0x0a 0x00
#     sleep 0.5
#     i2cset -y 1 0x20 0x0a 0xff
#     sleep 0.5
#     let count++
#    done

# * Port type *
PortA = 0
PortB = 1

# * Data constant bytes *
AllOutput = 0x00
AllHigh = 0xff
AllLow =  0x00
AlternateHighLow = 0xaa
AlternateLowHigh = 0x55

# * Direction setting bytes *
HalfHighHalfLow = 0xf0
HalfLowHalfHigh = 0x0f
Nibble1HighNibble2Low = 0xf0
Nibble1LowNibble2High = 0x0f
HighNibbleInputLowNibbleOutput = 0xf0

# * MCP23008/MCP23017 register address offsets *
InputOutputDirection = 0
InputPolarity = 1
InterruptOnChangeEnable = 2
InterruptOnChangeDefaultValue = 3
InterruptOnChangeMode = 4
Configuration = 5
PushPullOpenDrain = 6
InterruptFlag = 7
InterruptCapture = 8
PortStatus = 9
OutputLatch = 10

# * MCP23008/MCP23017 Band0/Band1 register address offset arrays *
RegisterAddressOffsetArray0 = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,       
     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a]
              
RegisterAddressOffsetArray1 = [0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x11, 0x13, 0x15, 0x17, 0x19,       
     0x01, 0x03, 0x05, 0x07, 0x09, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a]

# * Setup input/output ports *

def SetupMCP23008PortAllOutput(registerBaseAddress):
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, InputOutputDirection, PortA, AllOutput)

def SetupMCP23017BothPortAllOutput(registerBaseAddress):
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, InputOutputDirection, PortA, AllOutput)
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, InputOutputDirection, PortB, AllOutput)

# * Read/write registers *

def WriteDataByte(registerBaseAddress, registerAddressArray, dataRegisterIndex, portType, dataByte):
    if (portType == PortA) | (portType == PortA):
       addressOffset = registerAddressArray[dataRegisterIndex]
    if (portType == PortB):
       addressOffset = registerAddressArray[dataRegisterIndex + 11]
    smBus1.write_byte_data(registerBaseAddress, addressOffset, dataByte)

def ReadDataByte(registerBaseAddress, registerAddressArray, dataRegisterIndex, portType):
    if (portType == PortA):
       addressOffset = registerAddressArray[dataRegisterIndex]
    if (portType == PortB):
       addressOffset = registerAddressArray[dataRegisterIndex + 11]
    dataByte = smBus1.read_byte_data(registerBaseAddress, addressOffset)
    return dataByte

def ReadUpperDataNibble(registerBaseAddress, registerAddressArray, dataRegisterIndex, portType):
    dataByte = ReadDataByte(registerBaseAddress, registerAddressArray, dataRegisterIndex, portType)
    upperDataNibble = dataByte >> 4
    return upperDataNibble

# * Config interrupts *
def EnableInterruptOnChangeHighNibble(registerBaseAddress):
    EnableInterruptHighNibble = 0xf0
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, InterruptOnChangeEnable, PortA, EnableInterruptHighNibble)

def DisableInterruptOnChangeHighNibble(registerBaseAddress):
    DisableInterruptHighNibble = 0x00
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, InterruptOnChangeEnable, PortA, DisableInterruptHighNibble)

def SetInterruptOnChangeDefaultHighNibble(registerBaseAddress):
    DefaultValueByte = 0xf0
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, InterruptOnChangeDefaultValue, PortA, DefaultValueByte)

def SetInterruptOnChangeCompareDefaultHighNibble(registerBaseAddress):
    InterruptOnChangeDefaultValueHighNibble = 0xf0 # GP4~7 change from default value will cause interrupt
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, InterruptOnChangeMode, PortA, InterruptOnChangeDefaultValueHighNibble)

def SetInterruptOutputPushPull(registerBaseAddress): # interrupt pin open drain, no auto add inc, no slew rate
    PushPull  = 0b00111010 # 0x32, seq/slew disabled, interrupt output drive drive (push pull) active High
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, PushPullOpenDrain, PortA, PushPull)

def SetInterruptOutputOpenDrain(registerBaseAddress): # interrupt pin open drain, no auto add inc, no slew rate
    OpenDrain = 0b00111000 # 0x34, seq/slew disabled, interrupt output open drain (don't care active High or Low)
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, PushPullOpenDrain, PortA, OpenDrain)

# * Poll interrupts *
def ReadInterruptFlagHighNibble(registerBaseAddress):
    interruptFlagByte = ReadDataByte(registerBaseAddress,  RegisterAddressOffsetArray0, InterruptFlag, PortA) 
    interruptFlagNibble = interruptFlagByte >> 4
    return interruptFlagNibble  
   
def ReadInterruptCaptureHighNibble(registerBaseAddress):
    interruptCaptureByte = ReadDataByte(registerBaseAddress, RegisterAddressOffsetArray0, InterruptCapture, PortA)   
    interruptCaptureNibble = interruptCaptureByte >> 4
    return interruptCaptureNibble 

def DetectOneInterrupt(registerBaseAddress): # !!! NOT tested !!!  
    interruptFlagNibble = ReadInterruptFlagHighNibble(registerBaseAddress)
    interruptCaptureNibble = ReadInterruptCaptureHighNibble(registerBaseAddress)
    print "Interrupt capture high nibble = ", ConvertIntegerToFourBitPattern(interruptCaptureNibble)
    print "Interrupt capture high nibble = ", ConvertIntegerToFourBitPattern(interruptCaptureNibble)
    ClearInterruptOnChangeHighNibble(registerBaseAddress) # !!! clear interrupt !!!
    sleep(2)

# * Test port toggling, poll interrupts *

def ToggleMCP23008GP(registerBaseAddress, toggleTime, toggleCount):
    SetupMCP23008PortAllOutput(registerBaseAddress)
    for i in range(toggleCount):
        WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, OutputLatch, PortA, AllHigh)
    sleep(toggleTime)
        WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, OutputLatch, PortA, AllLow)
     sleep(toggleTime)

def ToggleMCP23017GP(registerBaseAddress, toggleTime, toggleCount):
    SetupMCP23017BothPortAllOutput(registerBaseAddress)
    for i in range(toggleCount):
        WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, OutputLatch, PortA, AllHigh)
        WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, OutputLatch, PortB, AllHigh)
    sleep(toggleTime)
        WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, OutputLatch, PortA, AllLow)
        WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, OutputLatch, PortB, AllLow)
     sleep(toggleTime)

def TestToggleMCP23008GP():
    ToggleTime = 0.5
    ToggleCount = 4
    ToggleMCP23008GP(MCP23008BaseAddress1, ToggleTime, ToggleCount)

def TestToggleMCP23017GP():
    ToggleTime = 0.5
    ToggleCount = 4
    ToggleMCP23008GP(MCP23017BaseAddress1,  ToggleTime, ToggleCount)

def TestDetectInterrupt(count): # !!! NOT Tested !!!
    RegisterBaseAddress =  MCP23008BaseAddress2
    SetupKeypadInterruptHighNibbleCompareDefaultValueOpenDrainOutput(RegisterBaseAddress)
    for i in range(count):
        DetectOneInterrupt(RegisterBaseAddress)


# 7. Unipolar Stepping Motor 28BYJ48/NPM-PF35/PX245 ***************************

# Unipolar Stepping Motor Switching Sequence
# 1. Wave sequence = 1 - 3 - 2 - 4 (A-, B-, A+, B+)
# 2. Full step sequence = 13 - 14 - 24 - 23 (A-B-, A-B+, A+B+, A+B-)
# 3. Half step sequence  = 13 - 1 - 14 - 4 - 24 - 2 - 23 - 3
# 4. One step swing = 1 - 3 - 1 - 3 (A-, B-, A-, B-)
# Winding        A-(1)    A+(2)    B-(3)   B+(4)    COM
# NPM PF35       Black    Yellow   Brown   Orange   Red
# 28BYJ48        Blue     Pink     Yellow  Orange   Red 
# PX245          Black    Green    Blue    Red      Yelow/White

# * Convert decimal pin number to hex *
def convert1PinToHex(p): # convert 1 of 8 high pin to hex
    hexString = 0x01
    for count in range(p-1):
       hexString = hexString << 1
    return hexString   
def convert2PinToHex(p1, p2):  # convert 2 of 8 high pins to hex
    return (convert1PinToHex(p1) | convert1PinToHex(p2))

def convert2PinToHighNibble(p1, p2):  # convert 2 of 8 high pins to high nibble
    lowNibble = convert1PinToHex(p1) | convert1PinToHex(p2)
    highNibble = lowNibble << 4
    return highNibble

# * Move unipolar stepping motor *

def WriteMotorWindingWaveSequence1324(RegisterBaseAddress, NibbleType, StepCount, StepTime): # move motor using 13-24 sequence 
    # Set port all output
    WriteDataByte(MCP23008BaseAddress1, RegisterAddressOffsetArray0, InputOutputDirection, PortA, AllOutput)

    if NibbleType == LowNibble:
    hexString1 =  convert2PinToHex(1, 3)
      hexString2 =  convert2PinToHex(2, 4)
    else:
    hexString1 = convert2PinToHighNibble(1, 3)
    hexString2 = convert2PinToHighNibble(2, 4)
    for i in range(StepCount):
        WriteDataByte(MCP23008BaseAddress1, RegisterAddressOffsetArray0, OutputLatch, PortA, hexString1)
       sleep(StepTime)
        WriteDataByte(MCP23008BaseAddress1, RegisterAddressOffsetArray0, OutputLatch, PortA, hexString2)
        sleep(StepTime)

def WriteMotorWindingFullStepSequence13232414(RegisterBaseAddress, NibbleType, StepCount, StepTime): #move motor using 13-23-24-14 sequence
    # Set port all output
    WriteDataByte(MCP23008BaseAddress1, RegisterAddressOffsetArray0, InputOutputDirection, PortA, AllOutput)

    if NibbleType == LowNibble:
        motorWindingActivationPatternArray = (0x05, 0x06, 0x0a, 0x09)
    else:
    motorWindingActivationPatternArray = (0x50, 0x60, 0xa0, 0x90)
    for i in range(StepCount):
    for pattern in motorWindingActivationPatternArray:
            WriteDataByte(MCP23008BaseAddress1, RegisterAddressOffsetArray0, OutputLatch, PortA, pattern)
        sleep(StepTime)

def TestConvert1PinToHex(): # test convert 1 high pin to hex
    print "*** Testing 1 pin number decimal 0 ~ 7 converted to hexdecimal 0x01 ~ 0x80"
    for d in range(8):
       print hex(convert1PinToHex(d))

def TestConvert2PinToHex(p1, p2): # test convert 2 high pins to hex
    print "*** Testing 2 pin numbers decimal 0 ~ 7 converted to hexdecimal"
    print "Pin 1 = ", p1, "Pin 2 = ", p2
    print "Hex = ", hex(convert2PinToHex(p1, p2))

def TestConvert2PinToHighNibble(p1, p2): # test convert 2 of 8 high pins to high nibble
    print "*** Testing 2 pin numbers decimal 0 ~ 7 converted to high nibble"
    print "Pin 1 = ", p1, "Pin 2 = ", p2
    print "HighNibble = ", hex(convert2PinToHighNibble(p1, p2))

def MoveTwoMotors(RegisterBaseAddress): 
    OneBeep()
    WriteMotorWindingWaveSequence1324(MCP23008BaseAddress1, LowNibble, TwentyTimes, FiftyMilliSeconds)
    OneBeep()
    WriteMotorWindingWaveSequence1324(MCP23008BaseAddress1, HighNibble, TwentyTimes, FiftyMilliSeconds)
    # OneBeep()
    # WriteMotorWindingFullStepSequence13232414(MCP23008BaseAddress1, LowNibble, TwentyTimes, FiftyMilliSeconds)
    # OneBeep()
    # WriteMotorWindingFullStepSequence13232414(MCP23008BaseAddress1, HighNibble, TwentyTimes, FiftyMilliSeconds)

def TestMotor():
    MotorRegisterBaseAddress = MCP23008BaseAddress1
    MoveTwoMotors(MotorRegisterBaseAddress)


# 8. Decimal keypad ***********************************************************

# * Function descriptions *

# SetupKeypad(registerBaseAddress)
# Assign GP0~3 as output (Col0~2, Col3 n.c), GP4~7 input (Row0~3)

# WriteAllColumnsLow(registerBaseAddress)
# Set all column outputs (GP0~2 actually, GP3 dummy)

# LoopUntilGpioPortHighNibbleChange(registerBaseAddress)
# Loop until GPIO register's GP4~7 not all High (some key pressed)

# LoopUntilInterruptCaptureHighNibbleChange(registerBaseAddress)
# Loop until INTCAP register's ICP4~7 not all High (some key pressed)

# Keypad scanning procedure version 1.0
# 1. Set 3 column ports GP0, GP1, GP2 as output (GP3 don't care)
# 2. Set 4 row ports GP4, GP5, GP6, GP7 as input
# 3. Write Low to all column ports
# 4. Wait until any key pressed (pooling or interrupt)
# 5. Find rowNumber and column number
# 6. Calculate key number

# * keypad base address and smBus setting *

KeypadRegisterBaseAddress = MCP23008BaseAddress2
KeypadSmBus = smBus1

PollGpioRegister = 0
PollKeypadInterruptPin = 1

# * Set up keypad matrix GPIO and interrupts *

def SetupKeypad(registerBaseAddress):
    SetupKeypadGPIO(registerBaseAddress)
    SetupKeypadInterrupt(registerBaseAddress)
    ClearKeypadInterrupt(registerBaseAddress)

def SetupKeypadGPIO(registerBaseAddress):
    UpperNibbleInputLowerNibbleOutput = 0xf0 # (GP4~7, Row0~3) = input, lower nibble (GP0~3, Column0~2, 3 = no coonect) = output
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, InputOutputDirection, PortA, UpperNibbleInputLowerNibbleOutput)
    WriteAllColumnsLow(registerBaseAddress)

def SetupKeypadInterrupt(registerBaseAddress):
    EnableInterruptOnChangeHighNibble(registerBaseAddress) # Enable interrupt on upper nibble (GP4~7)
    SetInterruptOnChangeDefaultHighNibble(registerBaseAddress) # Interrupt default values = all high (GP4~7 0b1111)
    SetInterruptOnChangeCompareDefaultHighNibble(registerBaseAddress) # select compare default value interrutpt
    SetInterruptOutputOpenDrain(registerBaseAddress) # set interrupt output (INT) open drain

def EnableInterruptOnChangeHighNibble(registerBaseAddress):
    EnableInterruptHighNibble = 0xf0
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, InterruptOnChangeEnable, PortA, EnableInterruptHighNibble)

def SetInterruptOnChangeDefaultHighNibble(registerBaseAddress):
    DefaultValueByte = 0xf0
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, InterruptOnChangeDefaultValue, PortA, DefaultValueByte)

def SetInterruptOnChangeCompareDefaultHighNibble(registerBaseAddress):
    InterruptOnChangeDefaultValueHighNibble = 0xf0 # GP4~7 change from default value will cause interrupt
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, InterruptOnChangeMode, PortA, InterruptOnChangeDefaultValueHighNibble)

def SetInterruptOutputPushPull(registerBaseAddress): # interrupt pin open drain, no auto add inc, no slew rate
    PushPull  = 0b00111010 # 0x32, seq/slew disabled, interrupt output drive drive (push pull) active High
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, PushPullOpenDrain, PortA, PushPull)

def SetInterruptOutputOpenDrain(registerBaseAddress): # interrupt pin open drain, no auto add inc, no slew rate
    OpenDrain = 0b00111000 # 0x34, seq/slew disabled, interrupt output open drain (don't care active High or Low)
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, PushPullOpenDrain, PortA, OpenDrain)

# * Clear and poll interrupts *

def ClearKeypadInterrupt(registerBaseAddress):
    WriteAllColumnsLow(registerBaseAddress)
    sleep(0.5)
    dummyRead = ReadInterruptCaptureHighNibble(registerBaseAddress)

def ReadKeypadInterruptPin(interruptPin):
    interruptStatus = readInputPin(interruptPin)
    return interruptStatus

# * Write columns *

def WriteColumns(registerBaseAddress, columnDataNibble):
    columnDataByte = columnDataNibble | 0x00
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, OutputLatch, PortA, columnDataByte)

def WriteAllColumnsLow(registerBaseAddress):
    AllColumnsLowNibble = 0x0
    WriteColumns(registerBaseAddress, AllColumnsLowNibble)

def WriteColumn0Low(registerBaseAddress):
    Column0LowNibble = 0xe
    WriteColumns(registerBaseAddress, Column0LowNibble)

def WriteColumn1Low(registerBaseAddress):
    Column1LowNibble = 0xd
    WriteColumns(registerBaseAddress, Column1LowNibble)

def WriteColumn2Low(registerBaseAddress):
    Column2LowNibble = 0xb
    WriteColumns(registerBaseAddress, Column2LowNibble)

# * Read rows *

def GetRowDataByte(registerBaseAddress):
    rowDataByte = ReadDataByte(registerBaseAddress, RegisterAddressOffsetArray0, PortStatus, PortA)
    return rowDataByte

def GetRowDataNibble(registerBaseAddress):
    rowDataByte = ReadDataByte(registerBaseAddress, RegisterAddressOffsetArray0, PortStatus, PortA)
    rowDataNibble = rowDataByte >> 4
    return rowDataNibble

# * Get row number, column number, and key number *

def GetRowNumber(registerBaseAddress):
    rowDataByte = ReadDataByte(registerBaseAddress, RegisterAddressOffsetArray0, PortStatus, PortA)
    rowDataNibble = rowDataByte >> 4
    if rowDataNibble == 0b1110:
        rowNumber = 0
        return rowNumber
    elif rowDataNibble == 0b1101:
        rowNumber = 1
        return rowNumber
    elif rowDataNibble == 0b1011:
        rowNumber = 2
        return rowNumber
    elif rowDataNibble == 0b0111:
        rowNumber = 3
        return rowNumber
    else:
        rowNumber = 99 
    return rowNumber

def GetColumnNumber(registerBaseAddress):
    RowsAllHigh = 0xf

    WriteColumn0Low(registerBaseAddress)
    rowDataNibble = ReadUpperDataNibble(registerBaseAddress, RegisterAddressOffsetArray0, PortStatus, PortA)
    if rowDataNibble != RowsAllHigh:
        columnNumber = 0
        return columnNumber

    WriteColumn1Low(registerBaseAddress)
    rowDataNibble = ReadUpperDataNibble(registerBaseAddress, RegisterAddressOffsetArray0, PortStatus, PortA)
    if rowDataNibble != RowsAllHigh:
        columnNumber = 1
        return columnNumber

    WriteColumn2Low(registerBaseAddress)
    rowDataNibble = ReadUpperDataNibble(registerBaseAddress, RegisterAddressOffsetArray0, PortStatus, PortA)
    if rowDataNibble != RowsAllHigh:
        columnNumber = 2
        return columnNumber

def GetKeyNumber(rowNumber, columnNumber):
    # print "Row Number = ", rowNumber
    # print "Column Number = ", columnNumber
    keyNumber = (rowNumber * 3) + (columnNumber + 1)
    return keyNumber

# * Get one key and a sequence of keys *

def GetKey(registerBaseAddress, pollType):
    PollGpioRegister = 0
    PollKeypadInterruptPin = 1

    if (pollType == PollGpioRegister):
        # print "Polling GpioRegister"
        LoopUntilGpioPortHighNibbleChange(registerBaseAddress)

    elif (pollType == PollKeypadInterruptPin):
        # print "Polling Interrupt Pin"
        LoopUntilKeypadInterruptPinLow(registerBaseAddress, KeypadInterruptPin)        

    rowNumber = GetRowNumber(registerBaseAddress)
    columnNumber = GetColumnNumber(registerBaseAddress)
    keyNumber = GetKeyNumber(rowNumber, columnNumber)
    return keyNumber

def GetKeyString(registerBaseAddress, pollType, count):
    for i in range (count):       
        OneBeep()
    keyNumber = GetKey(registerBaseAddress, pollType)   
        print "Key", i + 1, " = ", keyNumber

# * Loop until row data changes *

def LoopUntilGpioPortHighNibbleChange(registerBaseAddress):
    WriteAllColumnsLow(registerBaseAddress)
    NoKeyPressedNibble = 0xf
    rowDataNibble = NoKeyPressedNibble
    while (rowDataNibble == NoKeyPressedNibble):
        rowDataNibble = GetRowDataNibble(registerBaseAddress)
    sleep(0.05) # debouncing time 50mS

# * Loop until interrupt key low *

def LoopUntilKeypadInterruptPinLow(registerBaseAddress, interruptPin):
    ClearKeypadInterrupt(registerBaseAddress)
    interruptPinState = readInputPin(interruptPin)
    #print "interruptPinState = ", interruptPinState
    while (interruptPinState == True):
       interruptPinState = readInputPin(interruptPin)
       #print "interruptPinState = ", interruptPinState
       #sleep(1)
    #print "interruptPinState = ", interruptPinState
    sleep(0.05) # debouncing time 50mS

# * Test keypad *

def TestKeypad(registerBaseAddress, pollType, count):
    SetupKeypad(registerBaseAddress)
    if (pollType == PollKeypadInterruptPin):
        SetupKeypadInterrupt(registerBaseAddress)
        ClearKeypadInterrupt(registerBaseAddress)
    print "*** Start testing keypad. ***" 
    print "Press keypad ", count, "times."
    GetKeyString(registerBaseAddress, pollType, count)
    ClearKeypadInterrupt(registerBaseAddress)
    print "*** Stop testing keypad. ***\n"

def TestPollingKeypad():
    TestKeypad(KeypadRegisterBaseAddress, PollGpioRegister, count = 4)

def TestInterruptKeypad():
    TestKeypad(KeypadRegisterBaseAddress, PollKeypadInterruptPin, count = 4)


# * LCD1602 *******************************************************************

LcdRegisterBaseAddress = MCP23008BaseAddress3 # 0x26

# * LCD1602A-1 16-pin connector (MCP23008 GPIO 6-pin connector) Pin numbering *

# Pin 04 (Pin 1) RegisterSelect
# Pin 06 (Pin 2) WriteEnable 
# Pin 11 (Pin 3) DataBit4 = 2
# Pin 12 (Pin 4) DataBit5 = 3
# Pin 13 (Pin 5) DataBit6 = 4
# Pin 14 (Pin 6) DataBit7 = 5

# LCD1602 software initialization procedure

# Part 1 - Pseudo 8 bit instructions to config 4 bit instruction mode (0x30, 0x30, 0x30, 0x20)

# 1. Power on, wait 20mS (> 15mS)
# 2. Write 0x3, wait 5mS (> 4.1mS) # set 8 bit interface
# 3. Write 0x3, wait 1mS (> 100uS) # set 8 bit interface
# 4. Write 0x3, wait 1mS (> 37uS)  # set 8 bit interface
# 5. Write 0x2, wait 1mS (> 37uS)  # set 4 bit interface

# Part 2- 4 bit instructions to config display characteristics (0x28, 0x08, 0x01, 0x06, 0x02)

# 6. Write 0x2, wait 1mS (> 37uS) 0x8 wait 1mS (> 37uS) (2 lines, 5x8 dot)
# 7. Write 0x0, wait 1mS (> 37uS) 0x8 wait 1mS (> 37uS) (cursor on, no blinking, blank screen)
# 8. Write 0x0, wait 1mS (> 37uS) 0x1 wait 2mS (> 1.52mS)(clear display)
# 9. Write 0x0, wait 1mS (> 37uS) 0xe (DisplayOnCursorOnCursorBlinkOff)
# a. Write 0x0, wait 1mS (> 37uS) 0x2 wait 2mS (cursor home)

# * LCD1602A-1 16-pin connector pin numbering *

RegisterSelect = 0 # 0 = instruction register, 1 = data register
WriteEnable = 1 # 1 = enable, 0 = disable
DataBit4 = 2
DataBit5 = 3
DataBit6 = 4
DataBit7 = 5

# * Constant data bytes *

AllZeroDataByte = 0x00
AllOneDataByte = 0xff

# * Write Enable/Disable, Select Data/Instruction masks *

EnableWriteMask  = 0x02 # 0b 0000 0010
DisableWriteMask = 0xfd # 0b 1111 1101

SelectDataRegisterMask        = 0x01 # 0b 0000 0001
SelectInstructionRegisterMask = 0xfe # 0b 1111 1110

# Register selection constant *

InstructionRegister = 0
DataRegister = 1

# * LCD1602A-1 control instructions *

# * Instruction codes *

EightBitInstructionMode = 0x3
FourBitInstructionMode  = 0x2

TwoLineFiveTimesEightDot1 = 0x2
TwoLineFiveTimesEightDot2 = 0x8

DisplayOnCursorOnCursorBlinkOff1 = 0x0
DisplayOnCursorOnCursorBlinkOff2 = 0xe

ClearDisplay1 = 0x0
ClearDisplay2 = 0x1

CursorIncrementDisplayNoShift1 = 0x0
CursorIncrementDisplayNoShift2 = 0x6

CursorHome1 = 0x0
CursorHome2 = 0x2

# * Instruction timing *

PowerOnResetDelay      = 0.05    # 50mS
VeryLongOperationDelay = 0.005   # 5mS
LongOperationDelay     = 0.002   # 2mS
ShortOperationDelay    = 0.00005 # 50uS
WritePulseLength       = 0.00005 # 50uS

# * RPi/MCP23008 Python functions *

def LcdGpioSetup(registerBaseAddress):
    SetupMCP23008PortAllOutput(registerBaseAddress)

def LcdConfiguration(registerBaseAddress):
    dataControlByte = AllZeroDataByte
    # PrintEightBitPattern("dataControlByte01 = ", dataControlByte)
    LcdDisableWrite(registerBaseAddress, dataControlByte)
    sleep(PowerOnResetDelay)

    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, EightBitInstructionMode, InstructionRegister, VeryLongOperationDelay)
    # PrintEightBitPattern("dataControlByte02 = ", dataControlByte)
    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, EightBitInstructionMode, InstructionRegister, LongOperationDelay)
    # PrintEightBitPattern("dataControlByte03 = ", dataControlByte)
    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, EightBitInstructionMode, InstructionRegister, LongOperationDelay)
    # PrintEightBitPattern("dataControlByte04 = ", dataControlByte)
    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, FourBitInstructionMode, InstructionRegister, LongOperationDelay)
    # PrintEightBitPattern("dataControlByte05 = ", dataControlByte)

    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, TwoLineFiveTimesEightDot1, InstructionRegister, LongOperationDelay)
    # PrintEightBitPattern("dataControlByte06 = ", dataControlByte)
    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, TwoLineFiveTimesEightDot2, InstructionRegister, LongOperationDelay)
    # PrintEightBitPattern("dataControlByte07 = ", dataControlByte)

    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, DisplayOnCursorOnCursorBlinkOff1, InstructionRegister, LongOperationDelay)
    # PrintEightBitPattern("dataControlByte08 = ", dataControlByte)
    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, DisplayOnCursorOnCursorBlinkOff2, InstructionRegister, LongOperationDelay)
    # PrintEightBitPattern("dataControlByte09 = ", dataControlByte)

    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, ClearDisplay1, InstructionRegister, LongOperationDelay)
    # PrintEightBitPattern("dataControlByte10 = ", dataControlByte)
    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, ClearDisplay2, InstructionRegister, LongOperationDelay)
    # PrintEightBitPattern("dataControlByte11 = ", dataControlByte)

    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, CursorIncrementDisplayNoShift1, InstructionRegister, LongOperationDelay)
    # PrintEightBitPattern("dataControlByte12 = ", dataControlByte)
    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, CursorIncrementDisplayNoShift2, InstructionRegister, LongOperationDelay)
    # PrintEightBitPattern("dataControlByte13 = ", dataControlByte)

    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, CursorHome1, InstructionRegister, LongOperationDelay)
    # PrintEightBitPattern("dataControlByte14 = ", dataControlByte)
    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, CursorHome2, InstructionRegister, LongOperationDelay)
    # PrintEightBitPattern("dataControlByte15 = ", dataControlByte)

    return dataControlByte

def LcdSelectDataRegister(registerBaseAddress, dataByte):
    dataByte = dataByte | SelectDataRegisterMask
    LcdWriteDataByte(registerBaseAddress, dataByte) 
    return dataByte

def LcdSelectInstructionRegister(registerBaseAddress, dataByte):
    dataByte = dataByte & SelectInstructionRegisterMask
    LcdWriteDataByte(registerBaseAddress, dataByte)
    return dataByte

def LcdEnableWrite(registerBaseAddress, dataByte):
    dataByte = dataByte | EnableWriteMask
    LcdWriteDataByte(registerBaseAddress, dataByte)
    return dataByte

def LcdDisableWrite(registerBaseAddress, dataByte):
    dataByte = dataByte & DisableWriteMask
    LcdWriteDataByte(registerBaseAddress, dataByte)
    return dataByte

def LcdWritePulse(registerBaseAddress, dataByte):
    LcdEnableWrite(registerBaseAddress, dataByte)
    sleep(WritePulseLength)
    LcdDisableWrite(registerBaseAddress, dataByte)
    return dataByte

def LcdWriteDataByte(registerBaseAddress, dataByte):
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, OutputLatch, PortA, dataByte)
    return dataByte

def LcdWriteDataNibble(registerBaseAddress, dataByte, dataNibble, registerType, operationDelay):
    dataNibble = dataNibble << 2
    dataByte = dataByte & 0b11000011
    dataByte = dataByte | dataNibble
    if (registerType == InstructionRegister):
       dataByte = LcdSelectInstructionRegister(registerBaseAddress, dataByte)
    elif (registerType == DataRegister):
       dataByte = LcdSelectDataRegister(registerBaseAddress, dataByte)
    LcdDisableWrite(registerBaseAddress, dataByte)
    dataByte = LcdWriteDataByte(registerBaseAddress, dataByte)
    LcdWritePulse(registerBaseAddress, dataByte)
    sleep(operationDelay)
    return dataByte

def LcdWriteCharFourBitMode(registerBaseAddress, dataControlByte, asciiChar, registerType):
    charUpperNibble = ord(asciiChar) >> 4
    charLowerNibble = ord(asciiChar) & 0x0f
    LcdWriteCharTwoNibbles(registerBaseAddress, dataControlByte, charUpperNibble, charLowerNibble, registerType)
    return dataControlByte

def LcdWriteDataByteFourBitMode(registerBaseAddress, dataControlByte, dataByte, registerType):
    upperNibble = dataByte >> 4
    lowerNibble = dataByte & 0x0f
    LcdWriteCharTwoNibbles(registerBaseAddress, dataControlByte, upperNibble, lowerNibble, registerType)
    return dataControlByte

def LcdWriteCharTwoNibbles(registerBaseAddress, dataControlByte, upperNibble, lowerNibble, registerType):
    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, upperNibble, registerType, ShortOperationDelay)
    # PrintEightBitPattern("dataControlByte01 = ", dataControlByte)
    dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, lowerNibble, registerType, ShortOperationDelay)
    # PrintEightBitPattern("dataControlByte02 = ", dataControlByte)
    return dataControlByte

def LcdWriteCharString(registerBaseAddress, dataControlByte, string):
    for asciiChar in (string):
        LcdWriteCharFourBitMode(registerBaseAddress, dataControlByte, asciiChar, DataRegister)
    return dataControlByte

def LcdMoveCursor(registerBaseAddress, dataControlByte, rowNumber, columnNumber):
    if (rowNumber == 1):
       cursorByte = 0x80 | (0x00 + (columnNumber - 1)) # command = 0x80, row 1 DDRAM start address = 0x10
    elif (rowNumber == 2):
       cursorByte = 0x80 | (0x40 + (columnNumber - 1)) # row 2 DDRAM start address = 0x40
    LcdWriteDataByteFourBitMode(registerBaseAddress, dataControlByte, cursorByte, InstructionRegister)

    # charUpperNibble = cursorByte >> 4
    # charLowerNibble = cursorByte & 0x0f
    # dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, charUpperNibble, InstructionRegister, ShortOperationDelay)
    # dataControlByte = LcdWriteDataNibble(registerBaseAddress, dataControlByte, charLowerNibble, InstructionRegister, ShortOperationDelay)
    return dataControlByte

# * Test LCD1602 functions *

def TestLcd(registerBaseAddress):
    LcdGpioSetup(registerBaseAddress)
    dataControlByte = LcdConfiguration(registerBaseAddress)
    dataControlByte = LcdMoveCursor(registerBaseAddress, dataControlByte, 1, 2)
    dataControlByte = LcdWriteCharString(registerBaseAddress, dataControlByte, "Raspberry Pi")
    dataControlByte = LcdMoveCursor(registerBaseAddress, dataControlByte, 2, 1)
    dataControlByte = LcdWriteCharString(registerBaseAddress, dataControlByte, "2013-01-24 v11.2")

# * Demultiplexer *************************************************************

DemuxRegisterBaseAddress = KeypadRegisterBaseAddress

def DemuxGpioSetup(registerBaseAddress):
    UpperNibbleInputLowerNibbleOutput = 0xf0 # Input (GP4~7, Row0~3), Output (GP0~3, Column0~2, 3 reserved)
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, InputOutputDirection, PortA, UpperNibbleInputLowerNibbleOutput)
    InitialControlDateByte = 0x00
    return InitialControlDateByte

def DemuxAddressLatch(controlDataByte, latchAction):
    DemuxAddressLatchMask = 0b00001000
    Enable = 1
    Disable = 0
    if (latchAction == Enable):
        controlDataByte = controlDataByte | DemuxAddressLatchMask
    elif (latchAction == Disable):
       controlDataByte = controlDataByte & ~(DemuxAddressLatchMask)
    return controlDataByte

def SetAndLatchDemuxAddress(registerBaseAddress, controlDataByte, addressNibble):
    Enable = 1
    Disable = 0
    controlDataByte = controlDataByte & 0b11110000
    addressNibble = addressNibble & 0b00000111
    controlDataByte = controlDataByte | addressNibble
    controlDataByte = DemuxAddressLatch(controlDataByte, Disable)
    PrintEightBitPattern("demuxDataByte = ", controlDataByte)
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, OutputLatch, PortA, controlDataByte)
    controlDataByte = DemuxAddressLatch(controlDataByte, Enable)
    PrintEightBitPattern("demuxDataByte = ", controlDataByte)
    WriteDataByte(registerBaseAddress, RegisterAddressOffsetArray0, OutputLatch, PortA, controlDataByte)
    return controlDataByte

def TestDemultiplexer(lcdRegisterBaseAddress, demuxRegisterBaseAddress): 
    # TestLcd(LcdRegisterBaseAddress)
    # controlDataByte = DemuxGpioSetup(demuxRegisterBaseAddress)   
    # for addressNibble in range(8):
    #     controlDataByte = SetAndLatchDemuxAddress(demuxRegisterBaseAddress, controlDataByte, addressNibble)
    #     sleep(1)

    controlDataByte = DemuxGpioSetup(lcdRegisterBaseAddress)
    # addressNibble = 0
    addressNibble = 1
    controlDataByte = SetAndLatchDemuxAddress(demuxRegisterBaseAddress, controlDataByte, addressNibble)

    controlDataByte = SetAndLatchDemuxAddress(demuxRegisterBaseAddress, controlDataByte, channelNumber)

def TestDemux(lcdRegisterBaseAddress, demuxRegisterBaseAddress, channelNumber1, channelNumber2):
    Row1 = 1
    Row2 = 2
    Row3 = 3
    Row4 = 4
    Column1 = 1

    # Setup one MCP23008 for Demultiplexor, another MCP23008 for LCD1602/LCD2004
    controlDataByte = DemuxGpioSetup(demuxRegisterBaseAddress)
    LcdGpioSetup(lcdRegisterBaseAddress)

    # Select demux channelNumber1
    controlDataByte = SetAndLatchDemuxAddress(demuxRegisterBaseAddress, controlDataByte, channelNumber1)

    # Display two lines in the LCD at this channel
    dataControlByte = LcdConfiguration(lcdRegisterBaseAddress)
    dataControlByte = LcdMoveCursor(lcdRegisterBaseAddress, dataControlByte, Row1, Column1)
    dataControlByte = LcdWriteCharString(lcdRegisterBaseAddress, dataControlByte, "Channel 11111111")
    dataControlByte = LcdMoveCursor(lcdRegisterBaseAddress, dataControlByte, Row2, Column1)
    dataControlByte = LcdWriteCharString(lcdRegisterBaseAddress, dataControlByte, "2013-01-22 v1091")

    # Select demux channelNumber2
    controlDataByte = SetAndLatchDemuxAddress(demuxRegisterBaseAddress, controlDataByte, channelNumber2)

    # Display two lines in the LCD at this channel
    dataControlByte = LcdConfiguration(lcdRegisterBaseAddress)
    dataControlByte = LcdMoveCursor(lcdRegisterBaseAddress, dataControlByte, Row1, Column1)
    dataControlByte = LcdWriteCharString(lcdRegisterBaseAddress, dataControlByte, "Channel 22222222")
    dataControlByte = LcdMoveCursor(lcdRegisterBaseAddress, dataControlByte, Row2, Column1)
    dataControlByte = LcdWriteCharString(lcdRegisterBaseAddress, dataControlByte, "2013-01-24 v11.2")

# 11. Main test functions *****************************************************
StartProgram("*** Test Demultiplexer v110 TL Fong 2013jan22hkt2401 ***")

#TestBuzzer() # beep buzzer 4 times
#TestLED() # blink LED 8 tmes
#TestButtonEchoBuzzer() # echo buton with buzzer 10 times
#TestButtonEchoLED() # echo button with LED 10 times

# TestToggleMCP23017GP() # toggle MCP23017 output ports

# TestToggleMCP23008GP() # toggle MCP23008 output port

# TestMotor() # move two stepping motors

#TestPollingKeypad() # read 4 keys by polling IO Expander GPIO port of rows

# TestInterruptKeypad() # read 4 keys by polling IO Expander INT pin
# ToggleMCP23008GP(MCP23008BaseAddress1, toggleTime = 0.25, toggleCount = 4)
# ToggleMCP23008GP(MCP23008BaseAddress3, toggleTime = 2.0, toggleCount = 20)

TestLcd(LcdRegisterBaseAddress)

# TestDemux(LcdRegisterBaseAddress, DemuxRegisterBaseAddress, 0, 1)

EndProgram()

# *****************************************************************************
# End of Program
# *****************************************************************************


.END

No comments:

Post a Comment