Wednesday, February 11, 2009

Preface





This note will describe a small project of a computerized LCD clock. The clock gets the time from the system (Windows) and relay it through a USB connection to a standard HD44780 Liquid Crystal Display.





















Disclaimer




In no event shall the author or contributors be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement for the substitute of good or services, loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage.





Hardware




The Following scheme describes the hardware section of the clock (Click on the picture enlarge):





















The usb communication




For the USB control, I used the UM245R usb to parallel module. This is a very simple module based on the FT245R IC - Ftdi's popular usb chip which doesn't actually require any knowledge in usb protocol. The UM245R drivers as well as its datasheet are available in Ftdi website and it's easy to communicate with it through C++ or Visual Basic. The general Idea is to send a byte to the module, which controls every one of its output (or input) pins.




The UM245R module also functions as the power supply of the entire cicuit, since the usb hub can supply up to 500 mA current to other consumers.







The UM245R is available for sale in Ftdi's site or Mouser for 20$. I purchased mine in Ebay for 28.5 $ (including shipping fees).
The communication with the UM245R will be described in the software section.

The Lcd Module

I used a simple standard HD44780 compatible 2x16 LCD with backlight.





The HD44780 pinout description:

Pin #1 - Vss (+5 vdc)

Pin #2 - Ground

Pin #3 - Contrast adjustment. I used a 4.7k resistor to set the contrast level.

Pin #4 - RS (Registration Select). If this pin is low, the data on pins 7-14 (the data pins) is refered as a control command. If the pin is high, the lcd will refer to the data on pins 7-14 as a character command.

Pin #5 - R/W (Read/Write). If this pin is low, the data pins (7-14) are related by the lcd as input pins (you can write a command). If the pin is high, the data pins are related as outputs (you can read the status). I connected this pin to the ground.

Pin #6 - E (Enable). In order to write a command to the lcd, you should switch this pin from high to low.

Pin #7 to #14 - Data pins. Pin #7 is DB 0 and Pin #14 is DB 7. The control commands or character commands (depending on RS) are assigned to these pins.

Pin #15 - Backlight voltage supply (+5 vdc).

Pin #16 - Backlight ground.

In order to communicate with the HD44780, you should assign the the character or control word to the data pins, assign '0' to RS for a control command or '1' for a character command, and switch E from high to low. C'est tout!

The instructions to the LCD are available in The HD44780 datasheet here.

A useful JavaScript LCD simulator in this link.


BUFFER AND SHIFT REGISTER


Since the LCD is driven by ten lines: eight data lines and two control lines (RS and E), I used two shift registers controlled by three outputs of the UM245R module, that generate a 16 bit word (8 bits by each shift register). In fact, only the first ten bits of the sixteen are used. In other words, the UM245R functions as a serial device that feeds the shift registers which drive the LCD.
I used two 74LS595 shift registers for the task. The 74LS595 is an eight bit serial in parallel out shift register. It's very easy to make it work:

Pin #16 and Pin #8 are Vcc and Ground.

Pin #14 (SER) is the 'data in' input and Pin #11 (SRCK) is the 'clock' input.

Pins #1-7,15 are the parallel output pins.

Pin #12 (RCK) enables the data in the outputs. This prevents the occurrence of a change in the outputs during the shift.

Pin #13 (G) can be used to bring outputs to high Z. In our project, it's connected to ground.

Pin #10 (MR) clears the data in the shift register. Since it's innecessary it's connected to Vcc.




Thus, whenever SRCK is raised, the data on SER is shifted by one bit. when RCK is raised, the data is available in the outputs. The datasheet of 74LS595 is available here.

In order to protect the UM245R module, I conncected the shift register through 74LS245 Octal Bus Transceiver. It functions as an 8-line asynchronous 2-way data communication between data buses. Direction Input (DR) controls transmission of Data from bus A to busB or bus B to bus A depending upon its logic level. The datasheet of 74LS245 is available
here.


Software

General

The software was designed in VB 6. When the application is activated, the lcd displays the time and date and is accessible form windows tray.

The Vb project contains one form - Main.frm (that is actually invisible) and three modules: FTDI.bas that contains the definitions of FT245 access functions from FT2xx.dll, Tray.bas - contains the tray definitions, Usb_Functions.bas - contains functions that control the activity of the usb actions and General.bas - the procedures that process the info (time & date) into serial data fits for the shift registers.

FTDI.bas

Contains the FT2xx functions declarations:

Option Explicit

'===========================
'CLASSIC INTERFACE
'===========================

Public Declare Function FT_GetNumDevices Lib "FTD2XX.DLL" Alias "FT_ListDevices" (ByRef arg1 As Long, ByVal arg2 As String, ByVal dwFlags As Long) As Long
Public Declare Function FT_Open Lib "FTD2XX.DLL" (ByVal intDeviceNumber As Integer, ByRef lngHandle As Long) As Long
Public Declare Function FT_GetStatus Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByRef lngRxBytes As Long, ByRef lngTxBytes As Long, ByRef lngEventsDWord As Long) As Long
Public Declare Function FT_Close Lib "FTD2XX.DLL" (ByVal lngHandle As Long) As Long
Public Declare Function FT_Write Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByRef lpszBuffer As String, ByRef lngBufferSize As Long, ByRef lngBytesWritten As Long) As Long
Public Declare Function FT_WriteByte Lib "FTD2XX.DLL" Alias "FT_Write" (ByVal lngHandle As Long, ByRef lpszBuffer As Any, ByVal lngBufferSize As Long, ByRef lngBytesWritten As Long) As Long
Public Declare Function FT_ResetDevice Lib "FTD2XX.DLL" (ByVal lngHandle As Long) As Long
Public Declare Function FT_GetDeviceInfo Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal devtyp As Long, ByVal lpdwID As Long, ByVal pcSerialNumber As Long, ByVal pcDescription As Long, ByVal pvDummy As Long) As Long
Public Declare Function FT_OpenEx Lib "FTD2XX.DLL" (ByVal arg1 As String, ByVal arg2 As Long, ByRef lngHandle As Long) As Long
Public Declare Function FT_Read Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal lpszBuffer As String, ByRef lngBufferSize As Long, ByRef lngBytesReturned As Long) As Long
Public Declare Function FT_SetBaudRate Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal lngBaudRate As Long) As Long
Public Declare Function FT_SetDataCharacteristics Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal byWordLength As Byte, ByVal byStopBits As Byte, ByVal byParity As Byte) As Long
Public Declare Function FT_SetFlowControl Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal intFlowControl As Integer, ByVal byXonChar As Byte, ByVal byXoffChar As Byte) As Long
Public Declare Function FT_SetDtr Lib "FTD2XX.DLL" (ByVal lngHandle As Long) As Long
Public Declare Function FT_ClrDtr Lib "FTD2XX.DLL" (ByVal lngHandle As Long) As Long
Public Declare Function FT_SetRts Lib "FTD2XX.DLL" (ByVal lngHandle As Long) As Long
Public Declare Function FT_ClrRts Lib "FTD2XX.DLL" (ByVal lngHandle As Long) As Long
Public Declare Function FT_GetModemStatus Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByRef lngModemStatus As Long) As Long
Public Declare Function FT_SetChars Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal byEventChar As Byte, ByVal byEventCharEnabled As Byte, ByVal byErrorChar As Byte, ByVal byErrorCharEnabled As Byte) As Long
Public Declare Function FT_Purge Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal lngMask As Long) As Long
Public Declare Function FT_SetTimeouts Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal lngReadTimeout As Long, ByVal lngWriteTimeout As Long) As Long
Public Declare Function FT_GetQueueStatus Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByRef lngRxBytes As Long) As Long
Public Declare Function FT_SetBreakOn Lib "FTD2XX.DLL" (ByVal lngHandle As Long) As Long
Public Declare Function FT_SetBreakOff Lib "FTD2XX.DLL" (ByVal lngHandle As Long) As Long
Public Declare Function FT_SetEventNotification Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal dwEventMask As Long, ByVal pVoid As Long) As Long





Public Declare Function FT_GetBitMode Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByRef intData As Any) As Long

Public Declare Function FT_SetLatencyTimer Lib "FTD2XX.DLL" (ByVal Handle As Long, ByVal pucTimer As Byte) As Long
Public Declare Function FT_GetLatencyTimer Lib "FTD2XX.DLL" (ByVal Handle As Long, ByRef ucTimer As Long) As Long


Public Declare Function FT_ListDevices Lib "FTD2XX.DLL" (ByRef arg1 As Long, ByVal arg2 As String, ByVal dwFlags As Long) As Long
'Public Declare Function FT_SetDivisor Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal shDivisor) As Short
Public Declare Function FT_SetDivisor Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal Divisor As Single) As Long
Public Declare Function FT_SetBitMode Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal intMask As Byte, ByVal intMode As Byte) As Long
Public Declare Function FT_GetEventStatus Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByRef lngEventsDWord As Long) As Long

'=============================
'FT_W32 API
'=============================

Public Declare Function FT_W32_CreateFile Lib "FTD2XX.DLL" (ByVal lpszName As String, ByVal dwAccess As Long, ByVal dwShareMode As Long, ByRef lpSecurityAttributes As LPSECURITY_ATTRIBUTES, ByVal dwCreate As Long, ByVal dwAttrsAndFlags As Long, ByVal hTemplate As Long) As Long
Public Declare Function FT_W32_CloseHandle Lib "FTD2XX.DLL" (ByVal ftHandle As Long) As Long
Public Declare Function FT_W32_ReadFile Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal lpszBuffer As String, ByVal lngBufferSize As Long, ByRef lngBytesReturned As Long, ByRef lpftOverlapped As lpOverlapped) As Long
Public Declare Function FT_W32_WriteFile Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal lpszBuffer As String, ByVal lngBufferSize As Long, ByRef lngBytesWritten As Long, ByRef lpftOverlapped As lpOverlapped) As Long
Public Declare Function FT_W32_GetOverlappedResult Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByRef lpftOverlapped As lpOverlapped, ByRef lpdwBytesTransferred As Long, ByVal bWait As Boolean) As Long
Public Declare Function FT_W32_GetCommState Lib "FTD2XX.DLL" (ByVal lngHandle, ByRef lpftDCB As FTDCB) As Long
Public Declare Function FT_W32_SetCommState Lib "FTD2XX.DLL" (ByVal lngHandle, ByRef lpftDCB As FTDCB) As Long
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Public Declare Function CreateEvent Lib "kernel32" Alias "CreateEventA" (ByVal lpEventAttributes As Long, ByVal bManualReset As Long, ByVal bInitialState As Long, ByVal lpName As String) As Long
Public Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Public Declare Function SetEvent Lib "kernel32" (ByVal hHandle As Long) As Long
Public Declare Function CreateThread Lib "kernel32" (lpThreadAttributes As Any, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, lpParameter As Any, ByVal dwCreationFlags As Long, lpThreadID As Long) As Long
Public Declare Function TerminateThread Lib "kernel32" (ByVal hThread As Long, ByVal dwExitCode As Long) As Long
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

'====================================================================
'APIGID32.DLL by DESAWARE Inc. (www.desaware.com), see Dan Appleman's
'"Visual Basic Programmer's Guide to the WIN32-API"; here used to get
'the addresses of the VB-bytearrays:
'====================================================================
Public Declare Function agGetAddressForObject& Lib "apigid32.dll" (object As Any)

'==============================================================
'Declarations for the EEPROM-accessing functions in FTD2XX.dll:
'==============================================================
Public Declare Function FT_EE_Program Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByRef lpData As FT_PROGRAM_DATA) As Long
Public Declare Function FT_EE_Read Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByRef lpData As FT_PROGRAM_DATA) As Long
Public Declare Function FT_EE_UASize Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByRef lpdwSize As Long) As Long
Public Declare Function FT_EE_UAWrite Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal pucData As String, ByVal dwDataLen As Long) As Long
Public Declare Function FT_EE_UARead Lib "FTD2XX.DLL" (ByVal lngHandle As Long, ByVal pucData As String, ByVal dwDataLen As Long, ByRef lpdwBytesRead As Long) As Long

Public Type LPSECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type

Public Type lpOverlapped
Internal As Long
InternalHigh As Long
Offset As Long
OffsetHigh As Long
hEvent As Long
End Type

Public Type FTDCB
DCBlength As Long 'sizeof (FTDCB)
BaudRate As Long '9600
' fBinary As Long '= 1 Binary mode (skip EOF check)
' fParity As Long '= 1 Enable parity checking
' fOutxCtsFlow As Long '= 1 CTS handshaking on output
' fOutxDsrFlow As Long '= 1 DSR handshaking on output
' fDtrControl As Long '= 2 DTR flow control
' fDsrSensitivity As Long '= 1 DSR Sensitivity
' fTXContinueOnXoff As Long '= 1 Continue TX when Xoff sent
' fOutX As Long '= 1 Enable output X-on/X-off
' fInX As Long '= 1 Enable input X-on/X-off
' fErrorChar As Long '= 1 Enable error replacement
' fNull As Long '= 1 Enable null stripping
' fRtsControl As Long '= 2 RTS flow control
' fAbortOnError As Long '= 1 Abort all reads and writes on error
' fDummy2 As Long '= 17 Reserved
' wReserved As Integer 'Not currently used
' XonLim As Integer 'Transmit X-on threshold
' XoffLim As Integer 'Transmit X-off threshold
' ByteSize As Byte 'Number of bits/ byte, 7-8
' Parity As Byte '0-4= None, Odd, Even, Mark, Space
' StopBits As Byte '0, 2 = 1, 2
' XonChar As Byte 'TX and RX X-ON character
' XoffChar As Byte 'TX and RX X-OFF character
' ErrorChar As Byte 'Eror replacement char
' EofChar As Byte 'End of input Character
' EvtChar As Byte 'Received event character
' wReserved1 As Integer 'BCD (0x0200 => USB2)
End Type




'====================================================================
'Type definition as equivalent for C-structure "ft_program_data" used
'in FT_EE_READ and FT_EE_WRITE;
'ATTENTION! The variables "Manufacturer", "ManufacturerID",
'"Description" and "SerialNumber" are passed as POINTERS to
'locations of Bytearrays. Each Byte in these arrays will be
'filled with one character of the whole string.
'(See below, calls to "agGetAddressForObject")
'=====================================================================


Public Type FT_PROGRAM_DATA

Signature1 As Long ' // Header - must be 0x00000000
Signature2 As Long ' // Header - must be 0xFFFFFFFF
Version As Long ' // 0 = original, 1 = FT2232C extensions
VendorID As Integer ' // 0x0403
ProductID As Integer ' // 0x6001
Manufacturer As Long ' // "FTDI" (32 bytes allocated)
ManufacturerID As Long ' // "FT" (16 bytes allocated)
Description As Long ' // "USB HS Serial Converter" (64 bytes allocated)
SerialNumber As Long ' // "FT000001" if fixed, or NULL (16 bytes allocated)
MaxPower As Integer ' // 0 < 0 =" disabled," 1 =" enabled" 0 =" bus" 1 =" self" 0 =" not" 1 =" capable" 0x0200 =""> USB2)

' FT2232C extensions:
Rev5 As Byte ' // non-zero if Rev5 chip, zero otherwise
IsoInA As Byte ' // non-zero if in endpoint is isochronous
IsoInB As Byte ' // non-zero if in endpoint is isochronous
IsoOutA As Byte ' // non-zero if out endpoint is isochronous
IsoOutB As Byte ' // non-zero if out endpoint is isochronous
PullDownEnable5 As Byte ' // non-zero if pull down enabled
SerNumEnable5 As Byte ' // non-zero if serial number to be used
USBVersionEnable5 As Byte ' // non-zero if chip uses USBVersion
USBVersion5 As Integer ' // BCD (0x0200 => USB2)
AIsHighCurrent As Byte ' // non-zero if interface is high current
BIsHighCurrent As Byte ' // non-zero if interface is high current
IFAIsFifo As Byte ' // non-zero if interface is 245 FIFO
IFAIsFifoTar As Byte ' // non-zero if interface is 245 FIFO CPU target
IFAIsFastSer As Byte ' // non-zero if interface is Fast serial
AIsVCP As Byte ' // non-zero if interface is to use VCP drivers
IFBIsFifo As Byte ' // non-zero if interface is 245 FIFO
IFBIsFifoTar As Byte ' // non-zero if interface is 245 FIFO CPU target
IFBIsFastSer As Byte ' // non-zero if interface is Fast serial
BIsVCP As Byte ' // non-zero if interface is to use VCP drivers

End Type



' Return codes
Public Const FT_OK = 0
Public Const FT_INVALID_HANDLE = 1
Public Const FT_DEVICE_NOT_FOUND = 2
Public Const FT_DEVICE_NOT_OPENED = 3
Public Const FT_IO_ERROR = 4
Public Const FT_INSUFFICIENT_RESOURCES = 5
Public Const FT_INVALID_PARAMETER = 6
Public Const FT_INVALID_BAUD_RATE = 7
Public Const FT_DEVICE_NOT_OPENED_FOR_ERASE = 8
Public Const FT_DEVICE_NOT_OPENED_FOR_WRITE = 9
Public Const FT_FAILED_TO_WRITE_DEVICE = 10
Public Const FT_EEPROM_READ_FAILED = 11
Public Const FT_EEPROM_WRITE_FAILED = 12
Public Const FT_EEPROM_ERASE_FAILED = 13
Public Const FT_EEPROM_NOT_PRESENT = 14
Public Const FT_EEPROM_NOT_PROGRAMMED = 15
Public Const FT_INVALID_ARGS = 16
Public Const FT_NOT_SUPPORTED = 17
Public Const FT_OTHER_ERROR = 18

' Word Lengths
Public Const FT_BITS_8 = 8
Public Const FT_BITS_7 = 7

' Stop Bits
Public Const FT_STOP_BITS_1 = 0
Public Const FT_STOP_BITS_1_5 = 1
Public Const FT_STOP_BITS_2 = 2

' Parity
Public Const FT_PARITY_NONE = 0
Public Const FT_PARITY_ODD = 1
Public Const FT_PARITY_EVEN = 2
Public Const FT_PARITY_MARK = 3
Public Const FT_PARITY_SPACE = 4

' Flow Control
Public Const FT_FLOW_NONE = &H0
Public Const FT_FLOW_RTS_CTS = &H100
Public Const FT_FLOW_DTR_DSR = &H200
Public Const FT_FLOW_XON_XOFF = &H400

' Purge rx and tx buffers
Public Const FT_PURGE_RX = 1
Public Const FT_PURGE_TX = 2

' Modem Status
Public Const FT_MODEM_STATUS_CTS = &H10
Public Const FT_MODEM_STATUS_DSR = &H20
Public Const FT_MODEM_STATUS_RI = &H40
Public Const FT_MODEM_STATUS_DCD = &H80

Public Const FT_EVENT_RXCHAR As Long = 1
Public Const FT_EVENT_MODEM_STATUS = 2

Const WAIT_ABANDONED As Long = &H80
Const WAIT_FAILD As Long = &HFFFFFFFF
Const WAIT_OBJECT_0 As Long = &H0
Const WAIT_TIMEOUT As Long = &H102

' Flags for FT_ListDevices
Public Const FT_LIST_BY_NUMBER_ONLY = &H80000000
Public Const FT_LIST_BY_INDEX = &H40000000
Public Const FT_LIST_ALL = &H20000000

' Flags for FT_OpenEx
Public Const FT_OPEN_BY_SERIAL_NUMBER = 1
Public Const FT_OPEN_BY_DESCRIPTION = 2


Private Const INFINITE As Long = 1000 '&HFFFFFFFF

Global hThread As Long
Global hThreadID As Long
Global hEvent As Long
Global EventMask As Long

Global lngHandle As Long