Point of Sale systems typically can cost up to thousands of dollars we do it very simply for seventy.
For small stores, point of sale systems can be very expensive. One thousand dollars for a piece of machinery whose functionality is quintessentially simple can be exuberant. Our goal was to design a point of sale system for under seventy dollars with all of the functionality of a standard cash register. While constructing and implementing the entire set of functions that a modern cash register can perform, we were able to implement most of the functionality that one would desire. Particularly, our point of sale system supports barcode scanning, inventory management, cost calculations, and purchases and returns were all implemented, along with receipt/barcode printer support. Card readers (such as debit and credit cards) and networking, while desirable in a cash register, were not ultimately implemented due to time constraints (but not cost constraints).
High level Design
A lot of the interesting problems that we originally wished to tackle had already been explored. So we thought from a different angle. What if we could do something that was simple, but normally expensive? This was our motivation in choosing a point of sale system as our design project.
Here we discuss each component in our point of sale system and its purpose.
Keyboard The keyboard is used for providing input to the point of sale interface. This involves navigating all of the menus. It can optionally be used to manually enter a barcode. The keyboard interfaces with the microcontroller using the PS/2 protocol.
Barcode Scanner The barcode reader is used to scan items and return their ID number. The scanned value is instantly transmitted to the interface as input.
LCD Screen (Large) The LCD screen is used for interacting with the point of sale system. It displays the menus, keyboard and barcode scanner input, and feedback.
Receipt Printer After sales, returns, or inventory changes, receipts are printed of the transaction. Its memory is also used for non-volatile storage of register balance and inventory.
Microcontroller The Microcontroller is the main processor of all the smaller components. It is used for managing the state machine of the menu system, interpreting PS/2 keyboard and barcode scanner input, sending receipt print commands, handling nonvolatile storage, and updating the LCD screen.
We followed RS-232 (recommended standard 232) for communication with the serial port (receipt printer), and PS/2 for communication from the keyboard/barcode scanner. The implementation code of the RS-232 standard was a modification of Bruce Lands modification of Joerg Wunschs uart code; in particular, we removed the echo function, and interpretation of control characters. We also use Ascii (American Standard Code for Information Interchange) for our character interpretation.
Copyrights, Patents, Trademarks
There are no relevant copyrights, patents, or trademarks of which we are aware.
For our POS system we chose the Hyundai HG25504 because it had a large display 256 x 128 pixels and was used by ECE 476 groups in the past. The LCD uses the same standard 5V power supply for logic as the MCU uses but also requires a -10V reference for contrast. We had planned to use a inverter/regulator chip from Maxim but it was easier to just use a wall wart with a -12V reference and a potentiometer to adjust the voltage on the contrast pin. The LCD uses 5 control signals, Reset, RD, WR, CS, and A0 and one 8 bit data bus which we connected to PORTC. [Reset, A0, WR, RD] are connected to pins A3 to A0 respectively with CS set to ground because the SED1330F will ignore any commands or data if CS is not set to ground. CS is meant to select a specific LCD if multiple LCDs are in use. RD is always set to 1 since we never needed to read from the LCD. The init function initializes the LCD by first waiting 3ms with all 4 control signals set high as they are all active low in order to allow the LCD to start up. Then Reset is pulled low for 2ms and then set high again for the remainder of the program. Once the LCD is reset we are able to send the configuration parameters using the write_cmd and write_data functions. A0 selects the data type by A0=0 signaling that the data on PORTC is data and A0=1 signaling that the data is a command. The two write functions first set the data or command value to PORTC since the data must be stable 30ns before the falling edge of WR. WR is then set to 1 and A0 is set for two cycles since the value will be set by the end of the first cycle leaving the second cycle, 62.5ns = 1/16MHz, to meet the 30ns setup time. WR is then held low for two cycles to allow the LCD to read the data or command and then WR returns to 1 to complete the write.
The function write_cmd runs first to signal the LCD which parameters will be set followed by write_data to send the actual parameter values. First, the system set command runs to set all of the necessary parameters for operating the LCD including character size and LCD screen size. The first data block chooses the internal characters and no correction for characters near the edges which can make them easier to read but was not necessary. The next data block sets the character width to 8 pixels and the following data block sets the character height to 8 pixels. The next two data blocks set 32 characters per line since each character is 8 pixels wide and the screen is 256 pixels wide. Then the next data block tells the SED1330F controller that the LCD screen is 128 pixels tall. The final two data blocks signal the SED1330F that only 32 bytes should be allocated per line, the minimum amount 256 bytes/8 pixels, because more bytes could be allocated to allow horizontal shifting of characters to the left and right out of view.
Then we set the overlay command to OR the three layers since we are only using one layer, the other two layers are turned off. The LCD has three layers which means that the screen can look at three different areas of memory at once but this is primarily used for graphics so we only use layer 1. This command also sets the layer into text mode which draws characters instead of graphics mode which draws pixels. The csrform command sets the cursor size to 5 x 7 pixels which fills most of the 8 x 8 pixel window that each character fills. The csrright command causes the cursor to move one character to the right after writing a character. The hscroll command turns off horizontal scrolling of characters. The dispon command then turns on layer 1 and prevents the layer from flashing. The last part of initialization involves clearing the LCD by writing blank spaces to all of the memory seen by the LCD. The csrw command sets the cursor location and the mwrite command writes the blank spaces to the LCD memory.
Writing Strings to the LCD
The function write_string takes a string as an input to write to the LCD starting at the current cursor position. The write_string function will only write 31 characters per line instead of 32 because the cursor hides the last character at the end of the line. Write_string handles two major cases: writing regular characters and moving the cursor to the next line when reading a newline, \n. In order to provide the appearance of a never ending scrolling command prompt, the LCD uses twice as much memory as is needed for a standard 32 by 16 character display, 1KB instead of 512 bytes. Initially the LCD writes strings to rows 0-15 or the first 512KB block of memory but then when writing to row 16, the LCD changes its view to the second 512KB block of memory, rows 16-31. When changing its view to the second 512KB block of memory the LCD writes to the same relative row in both blocks of memory so that when reading a newline on row 31 the LCD can switch the view back to the first 512KB starting at row 1 without the user noticing. When switching back to the 1st 512KB block of memory, the LCD starts to write on row 16 and scrolls the view of memory by one row for every newline. For every newline the LCD also blanks the entire next line since this line could be filled with previous data. The LCD then continues to blank the next row and advance the scroll view by one until reaching row 31.
The PS/2 protocol
PS2 protocol is the dated standard for communication between keyboards and computers. Since it is easier to implement than USB connections, however, we decided to use it for our Point of Sale system for entering commands. We begin by detailing the hardware. The female PS/2 connector has six pins. Pins 6 and 2 are not used, pin 3 is ground, and pin 4 is +Vcc, whose standard value is 5V DC at 275 mA (max values). Pin 5 supplies a clock, which we have set to 10 KHz, while pin 1 supplies the data bits from keyboard input.
We use the external ISR to poll the value of the data pin at each falling edge of the clock; in PS/2 protocol, one bit from keyboard input is sent at every tick of the clock (nothing is sent when there is no keyboard input). The data pin is active low. The data stream per key input is split into eleven bits. The first bit, a 0, is a start bit. Upon receiving this bit, we expect to receive an eleven bit stream (including the start bit) beginning in 0 and ending in 1. The tenth bit is a parity bit, which we dont need for the purposes of our application. Bits 1 through 8 are a unique 8 bit data code, sent least significant bit first. We implement PS/2 by using the external interrupt 0 to detect the falling edge of the clock signal and after a 10us delay the ISR reads the value of the data pin. The ISR shifts the new data value to the right for the first 9 bits so that scan_code equals bits 8 to 1. On the last bit, the ISR copies scan_code into the circular buffer, scan_code_buffer. The function get_input then reads from this circular buffer to turn the scan codes into ASCII values. Two pointers index this buffer, scan_in is the index for writing into the buffer and ascii_out is the index for reading the buffer. The function get_input (explained in the next section) uses ascii_out to index scan_code_buffer to convert the scan codes into printable ASCII keys or left/right arrow, backspace, or delete.
The 8 bit data code can be F0, E0 or another random hexadecimal number representing a unique key. If the key is preceded by a data stream containing the sequence F0, it is a break command; the absence of an F0 sequence implies a make command. A make command means that the key was just pressed, while a break command means that the key was just released. E0 precedes the unique code for the extended keys for both the make and break codes which includes most of the non printable keys such as insert, delete, home, end, etc.
We implemented PS/2 fully for all printable characters except for excluding any keys we did not need such as the function keys. We also did not allow the microcontroller to send commands back to the keyboard because this would have only been useful to turn on the num, caps or scroll lock lights, not a critical feature.
The function get_input takes the scan codes stored by the ISR and converts them into meaningful printable ASCII characters or processes their function for home, end, backspace, delete, and left/right arrow. Get_input takes an input of how many characters to allow the user to input and sets the global input string which the interface reads to process users input. Get_input first nulls all characters of input and then enters a while that processes the scan codes until receiving a newline. There is a new available scan code for get_input to process if there is a mismatch in the two indexing pointers, scan_in and ascii_out. Get_input sets the shift flag if the shift key is currently pressed by checking if the shift make code is the current scan code and the previous code is not F0, a break code. The caps_flag is toggled when the caps lock key is pressed and is not toggled again until caps lock is released and pressed again. The shift flag causes ascii_val to be set from the shift_code_tbl instead of code_tbl if caps_lock is not set while if both shift and caps lock are set, ascii_val selects from code_tbl as usual. The one exception is for all non letter keys which caps lock has no effect on. The two tables code_tbl and shift_code_tbl, contain the ASCII values at the index equal to the scan code. All non implemented keys such as the function keys are set to null in the table. Get_input then checks for any special keys including for home, end, backspace, delete, or left/right arrow and if none are detected, get_input writes ascii_val to the LCD with write_string and added to input.
Backspace moves the cursor to the left by one position and blanks that location. Backspace checks that the index for input is greater than 0 since backspace should not blank out text written to prompt the user. Delete completes mostly the opposite action by blanking the current location and moving the cursor to the right one position. Home advances the cursor to the leftmost position where the user can enter text. End completes the opposite action by advancing the cursor to the rightmost location where the user can enter text. Left/right arrow simply move the cursor to the left or right by one position.
Stk 500 $15
White board $6
Hyundai HG25504 18.50
Ps/2 extension cable $1.13
Axiohm A758 Receipt printer donated from Cornell store
Welch Allyn IT 3800 $9.99
PS/2 keyboard owned
-12V wall wart scrapped from ECE 476 lab
3 1 wire flat cable $3
1 2 wire flat cable $1
Serial cable $1.63
For more detail: Point of Sale Terminal Using Atmega644