Pages

Friday, January 25, 2013

Hardware Configuration - 19 inch rack mount




http://www.blogger.com/blogger.g?blogID=1840459474737789074#editor/target=post;postID=4426126429310199744

Now I have mounted the last three boards, demux, LCD1, and LCD2 and tested the LCDs demuxed.  Everything went smoothly - both LCD1 on demux channel 0 and LCD2 on channel 1 display OK.

So there are two problems unsolved.

1.  The buzzer sound is feeble.  But this morning it did once in a long while sounds loud.  I guest there might be some wiring, or worse, RPi trace that got damaged and has intermittent failures.  Or that the power supply is not stable.

2. The step motors is not working.  I guess the problem might also be PSU related.  So I think I would try to use an external power for the motors and see if problem solved.

.END

# *****************************************************************************
# !/usr/bin/python2.7
#
# Program
#   tdemux1151.py - 2013jan25
# 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-25 v1141")

# * 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 SetDemuxChannel(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 TestDemux(demuxRegisterBaseAddress, channelNumber): 
    controlDataByte = DemuxGpioSetup(demuxRegisterBaseAddress)
    controlDataByte = SetDemuxChannel(demuxRegisterBaseAddress, controlDataByte, channelNumber)

def TestDemuxLcd(demuxRegisterBaseAddress, lcdRegisterBaseAddress, 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 = SetDemuxChannel(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-25 v1151")

    sleep(2)

    # Select demux channelNumber2
    controlDataByte = SetDemuxChannel(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-25 v1151")

    sleep(2)

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

#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(DemuxRegisterBaseAddress, 4) 

TestDemuxLcd(DemuxRegisterBaseAddress, LcdRegisterBaseAddress, channelNumber1 = 0, channelNumber2 = 1)

EndProgram()

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


.END


No comments:

Post a Comment