Bar Code Reader
History
This is a low cost bar code reader made from a product which has a very long history. You can see it at this link. This bar code reader can be purchased for around 6$ at http://mavin.com/computermice.html.
The bar code reader named CueCat is built to be connected in a PS2 keyboard port (standard PC/AT Keyboard). The problem is the information encrypted. I decided to build a small interface which fits in the CueCat to convert, decode the information and send it via RS232. Each time you scan a product, the decoded code is sent serially and is stored in an EEPROM which could store up to 128 bar codes. The idea is to read many bar codes away from the PC. This information could be retrieved later when the bar code reader will be connected to your PC. Later, you could send some commands to communicate with the CueCat. For example, "G" will get all the codes currently stored in the EEPROM; "C" will clear the entire memory.
Features
|
|
Very low cost |
|
|
128 bar codes memory |
|
|
RS232 interface |
Pictures
Click to enlarge
|
CueCat Look |
Open with my modification |
My small PCB |
Sources codes & Schematics
//**************************************************************************
// CueCat RS232
// Version 1.0 Jan 2003
// Sylvain Bissonnette
//**************************************************************************
//
// R E T U R N S T A C K 1 6
//
//**************************************************************************
//**************************************
// I N C L U D E
//**************************************
#include <io2313v.h>
#include <macros.h>
//**************************************
// D E F I N E
//**************************************
#define TRUE 0x01
#define FALSE 0x00
#define SI 0x04
#define SO 0x01
#define CLK 0x08
#define CS 0x02
#define READ 0x03
#define WRITE 0x02
#define WRDI 0x04
#define WREN 0x06
#define RDSR 0x05
#define WRSR 0x01
#define SOUND 0x20
//**************************************
// I N T E R R U P T H A N D L E R
//**************************************
#pragma interrupt_handler RxChar_interrupt:8
#pragma interrupt_handler INT0_interrupt:2
#pragma interrupt_handler Timer0_OVF:7
#pragma interrupt_handler Timer1_OVF:6
//**************************************
// P R O T O T Y P E
//**************************************
void RxChar(void);
void GetData(void);
void SendData(char *);
void TxChar(unsigned char);
void Convert(unsigned char ScanCode);
void Decode(void);
void Add(unsigned char ch);
void INT0_interrupt(void);
void InitLib(void);
void SaveData(unsigned char *ptr);
void UnlockEEprom(void);
void ClearEEprom(void);
void WriteEEprom(unsigned char *ptr,unsigned char page);
void ReadEEprom(unsigned char *ptr,unsigned char page);
unsigned char SPI(unsigned char OutByte);
void SPIDelay(void);
//**************************************
// G L O B A L V A R I A B L E
//**************************************
unsigned char Pulse;
unsigned char NumByte;
unsigned char Byte;
unsigned char Tick;
unsigned char Next;
unsigned char Cat[25];
unsigned char Real[16];
unsigned char CatPtr;
unsigned char RealPtr;
unsigned char Dot;
unsigned char NewScan;
//**************************************
// M A I N
//**************************************
void main()
{
int i;
InitLib();
while(1)
{
_StackCheck();
asm("WDR");
if (NewScan == TRUE)
{
TIMSK |= 0x02; // Sound ON
Decode();
SendData(&Real[0]);
SendData("\n\r\0");
for (i=-32000;i<32000;i++);
TIMSK &= ~0x02; // Sound OFF
SaveData(&Real[0]);
NewScan = FALSE;
}
}
}
/**********************************************************
Name: void _StackOverflowed(char c)
Description: This function is automaticaly called if
the stack trash, PB0 will be set.
Input: none
Output: PB7
Misc:
**********************************************************/
void _StackOverflowed(char c)
{
PORTB |= 0x80;
}
/**********************************************************
Name: void RxChar_interrupt(void)
Description: This function is automaticaly called each
time a char is received on the RS232.
Input: Serial port Data
Output: None
Misc:
**********************************************************/
void RxChar_interrupt(void)
{
unsigned char InChar;
InChar = UDR;
if (InChar == 'C') ClearEEprom();
if (InChar == 'G') GetData();
if (InChar == 'V') SendData("CueCat V1.0\n\r\0");
}
/**********************************************************
Name: void GetData(void)
Description: Send data from External EEprom to Serial port
Input: None
Output: None
Misc:
**********************************************************/
void GetData(void)
{
unsigned char i;
for (i=0;i<128;i++)
{
asm("WDR");
ReadEEprom(&Cat[0],i);
SendData(&Cat[0]);
SendData("\n\r\0");
}
}
/**********************************************************
Name: void SendData(char *)
Description: Send String of data,on the serial port
Input: * char
Output: none
Misc:
**********************************************************/
void SendData(char *buffer)
{
while(*buffer != 0x00) TxChar(*buffer++);
}
/**********************************************************
Name: void TxChar(unsigned char)
Description: Send a char on RS485 bus,
Input: char
Output: none
Misc:
**********************************************************/
void TxChar(unsigned char ch)
{
while ((USR & 0x20) != 0x20); // Wait for empty transmit buffer
UDR = ch; // Write char
while ((USR & 0x40) != 0x40); // Wait for the char to be cue off
USR |= 0x40; // Clear Tx finish flag
}
/**********************************************************
Name: void INT0_interrupt(void)
Description: Called each time a falling eadge from
the keyboard clock arrived. Read the Data
keyboard pin to form the scan code
Input: none
Output: none
Misc:
**********************************************************/
void INT0_interrupt(void)
{
unsigned char i;
Tick = 0;
if (Pulse == 0)
{
Byte = 0x00;
Pulse++;
return;
}
if ((Pulse > 0) && (Pulse < 9))
{
Byte = Byte >> 1;
if ((PIND & 0x08) == 0x08) Byte = Byte | 0x80;
Pulse++;
}
if (Pulse == 9)
{
Pulse++;
return;
}
if (Pulse == 10)
{
Convert(Byte);
NumByte++;
Pulse = 0;
}
}
/**********************************************************
Name: char Convert(unsigned char ScanCode)
Description: Convert the ScanCode to the real key stroke
Input: unsigned char -> ScanCode
Output: in the Cat[..] array
Misc:
**********************************************************/
void Convert(unsigned char ScanCode)
{
unsigned char Val;
Val = 0;
if (Next == TRUE)
{
Next = FALSE;
if (ScanCode == 0x45) Val = '0';
if (ScanCode == 0x16) Val = '1';
if (ScanCode == 0x1e) Val = '2';
if (ScanCode == 0x26) Val = '3';
if (ScanCode == 0x36) Val = '6';
if (ScanCode == 0x3d) Val = '7';
if (ScanCode == 0x32) Val = 'b';
if (ScanCode == 0x2b) Val = 'f';
if (ScanCode == 0x33) Val = 'h';
if (ScanCode == 0x3b) Val = 'j';
if (ScanCode == 0x3a) Val = 'm';
if (ScanCode == 0x31) Val = 'n';
if (ScanCode == 0x2d) Val = 'r';
if (ScanCode == 0x2a) Val = 'v';
if (ScanCode == 0x22) Val = 'x';
if (ScanCode == 0x1a) Val = 'z';
if (ScanCode == 0x21) Val = 'C';
if (ScanCode == 0x23) Val = 'D';
if (ScanCode == 0x24) Val = 'E';
// if (ScanCode == 0x31) Val = 'N'; // HMM
if (ScanCode == 0x4d) Val = 'P';
if (ScanCode == 0x2c) Val = 'T';
if (ScanCode == 0x1d) Val = 'W';
// if (ScanCode == 0x22) Val = 'X'; // HMM
if (ScanCode == 0x35) Val = 'Y';
// if (ScanCode == 0x1a) Val = 'Z'; // HMM
if (ScanCode == 0x49) Dot++;
if ((Dot == 3) && (Val != 0)) Cat[CatPtr++] = Val;
if (ScanCode == 0x5a)
{
NewScan = TRUE;
}
}
if (ScanCode == 0xf0) Next = TRUE;
}
/**********************************************************
Name: void Decode(void)
Description: Decode the encoded 64 of the cue cat
Input: Array Cat[..]
Output: Array Real[..]
Misc:
**********************************************************/
void Decode(void)
{
unsigned char i;
unsigned char a,b,c,d;
RealPtr = 0;
for (i=0;i<CatPtr;i=i+4)
{
a = Cat[i];
b = Cat[i+1];
c = Cat[i+2];
d = Cat[i+3];
if ((a == 'C') && (b == '3')) Add('0');
if ((a == 'C') && (b == 'n')) Add('1');
if ((a == 'C') && (b == 'x')) Add('2');
if ((a == 'C') && (b == 'h')) Add('3');
if ((a == 'D') && (b == '3')) Add('4');
if ((a == 'D') && (b == 'n')) Add('5');
if ((a == 'D') && (b == 'x')) Add('6');
if ((a == 'D') && (b == 'h')) Add('7');
if ((a == 'E') && (b == '3')) Add('8');
if ((a == 'E') && (b == 'n')) Add('9');
if (c == 'n') Add('0');
if (c == 'j') Add('1');
if (c == 'f') Add('2');
if (c == 'b') Add('3');
if (c == 'D') Add('4');
if (c == 'z') Add('5');
if (c == 'v') Add('6');
if (c == 'r') Add('7');
if (c == 'T') Add('8');
if (c == 'P') Add('9');
if (d == 'z') Add('0');
if (d == 'Y') Add('1');
if (d == 'x') Add('2');
if (d == 'W') Add('3');
if (d == '3') Add('4');
if (d == '2') Add('5');
if (d == '1') Add('6');
if (d == '0') Add('7');
if (d == '7') Add('8');
if (d == '6') Add('9');
}
CatPtr = 0;;
Dot = 0;
Add(0x00);
}
/**********************************************************
Name: void Add(unsigned char ch)
Description: Add a char to the Array Real[..]
Input: Char
Output: Real[..]
Misc:
**********************************************************/
void Add(unsigned char ch)
{
Real[RealPtr++] = ch;
}
/**********************************************************
Name: void SaveData(unsigned char *ptr)
Description: Save a array of 16 byte in eeprom
Input: Char pointer
Output: none
Misc:
**********************************************************/
void SaveData(unsigned char *ptr)
{
unsigned char i;
int j;
for (i=0;i<128;i++)
{
ReadEEprom(&Cat[0],i);
if (Cat[0] == 0x00)
{
WriteEEprom(ptr,i);
break;
}
if (i > 126)
{
for (i=0;i<10;i++)
{
TIMSK |= 0x02; // Sound ON
for (j=0;j<3000;j++)
{
SPIDelay();
asm("WDR");
}
TIMSK &= ~0x02; // Sound OFF
for (j=0;j<3000;j++)
{
SPIDelay();
asm("WDR");
}
}
}
}
}
/**********************************************************
Name: void Timer1_OVF(void
Description: 100us Tick interrupt
Input: none
Output: none
Misc: Clear flags
**********************************************************/
void Timer1_OVF(void)
{
TCNT1H = 0xFF; //reload counter high value
TCNT1L = 0x9C; //reload counter low value
Tick++;
if (Tick > 5)
{
Tick = 0;
Pulse = 0;
NumByte = 0;
}
}
/**********************************************************
Name: void UnlockEEprom()
Description: Unlock the external EEprom for write enable
Input: none
Output: none
Misc:
**********************************************************/
void UnlockEEprom(void)
{
PORTB &= ~CS; // CS low
SPI(WREN); // Send WREN Command
PORTB |= CS; // CS High
}
/**********************************************************
Name: void ClearEEprom()
Description: Clear the external EEprom
Input: none
Output: none
Misc:
**********************************************************/
void ClearEEprom()
{
unsigned char i;
unsigned char buff[16];
for (i=0;i<16;i++) buff[i] = 0x00;
for (i=0;i<128;i++)
{
asm("WDR");
WriteEEprom(&buff[0],i);
}
}
/**********************************************************
Name: void WriteEEprom(unsigned char *ptr,unsigned char page)
Description: Write a array of 16 byte in page x of the
external EEprom
Input: char *Array[16]
char page to write (0..127)
Output: none
Misc:
**********************************************************/
void WriteEEprom(unsigned char *ptr,unsigned char page)
{
int i;
UnlockEEprom();
SPIDelay();
PORTB &= ~CS; // CS low
SPIDelay();
SPI(WRITE); // Send Write Command
SPI(page>>4); // Hi 16 bit address
SPI(page<<4); // low 16 bit address
for (i=0;i<16;i++) SPI(*ptr++);
SPIDelay();
PORTB |= CS; // CS High
for (i=0;i<1000;i++) SPIDelay(); // 5ms
}
/**********************************************************
Name: void ReadEEprom(unsigned char *ptr,unsigned char page)
Description: Read a array of 16 byte in page x of the
external EEprom
Input: none
Output: none
Misc:
**********************************************************/
void ReadEEprom(unsigned char *ptr,unsigned char page)
{
unsigned char i;
PORTB &= ~CS; // CS low
SPIDelay();
SPI(READ); // Send Read Command
SPI(page>>4); // Hi 16 bit address
SPI(page<<4); // low 16 bit address
for (i=0;i<16;i++) *ptr++ = SPI(0x00);
SPIDelay();
PORTB |= CS; // CS High
}
/**********************************************************
Name: unsigned char SPI(unsigned char)
Description: Read and write byte on the SPI buss
Input: none
Output: unsigned char -> byte read
Misc:
**********************************************************/
unsigned char SPI(unsigned char OutByte)
{
unsigned char i;
unsigned char InByte;
InByte = 0x00;
for (i=0;i<8;i++)
{
if ((OutByte & 0x80) == 0x80) PORTB |= SI;
else PORTB &= ~SI;
OutByte = OutByte << 1;
SPIDelay();
PORTB |= CLK;
SPIDelay();
if ((PINB & SO) == SO) InByte |= 0x01;
if (i < 7) InByte = InByte << 1;
PORTB &= ~CLK;
SPIDelay();
}
return InByte;
}
/**********************************************************
Name: void SPIDelay(void)
Description: Delay of 5us
Input: none
Output: none
Misc:
**********************************************************/
void SPIDelay(void)
{
unsigned char i;
for (i=0;i<10;i++);
}
/**********************************************************
Name: void Timer0_OVF(void)
Description: Overflow 3.6khz for the piezo
Input: none
Output: none
Misc:
**********************************************************/
void Timer0_OVF(void)
{
TCNT0 = 0xf1;
PORTD ^= SOUND;
}
/**********************************************************
Name: void InitLib(void
Description: Initialize code
Input: none
Output: none
Misc:
**********************************************************/
void InitLib(void)
{
WDTCR = 0x0e; // Enable WatchDog at 0.97 sec
_CLI();
//PORTB
DDRB = 0x8e; // PB0-I PB1-O PB2-O PB3-O PB4-I PB5-I PB6-I PB7-O
//PORTD
PORTD = 0xfd; // Pull up on PD1-3-4-5-6
DDRD = 0x22; // PD0-I PD1-O PD2-I PD3-I PD4-I PD5-O PD6-I PD7-I
//UART
UBRR = 12; // 38400bps at 8Mhz
UCR = 0x98; // Rx & Tx enable, Enable RX interrupt
//INT0
MCUCR = 0x02; // Int0 generate int on falling eadge
GIMSK = 0x40; // Int0 enable
//Timer1
TCCR1B = 0x02; // Timer1 / 8
//Timer0
TCCR0 = 0x03; // Timer0 / 64
// Key Scan
TIMSK = 0x80; // int enable on Timer1 Overflow
NewScan = FALSE;
_SEI();
}