Barcode Scanner Emulator

Concept

Build primarily as proof of concept and because I found the challenge interresting, this little unit is able to send an ascii string terminated with a CR/LF via a RS232 connection. It’s emulating the transmission of a barcode and can be used with any kind of equipment that is expecting a barcode.

Schematic

I have been a little lazy on this project, as I have based it on the arduino serial V2 layout. This is also the reason I don’t have a neat schematic to show. But I have the reference schematic from the arduino board. And my handdrawn notes on the wiring and keypad. Please note that I have replaced the transistor version of the TTL to RS232 circuit with a MAX232 chip. This makes a more stable signal for the RS232 communication.

arduino_reference_b13061201c13061202c213061202c1

Oh, and there is also a connection to pin1 on the SUB-D (not shown on the schematic) for supplying the BAR-X with a 5 volt from the RS232 port. (only available on specific equipment)

Photos

Of course a couple of photos of the finished product should not be missing 🙂

P1000649bP1000650bP1000648b

Sourcecode

And finally to make the whole thing work. Here is the sourcecode for the embedded program. Mind you it’s nothing fancy. I tried using some procedures to shorten the code. But it never worked? So I took the sequential approach instead.

/******************************************
 * Barcode Emulator V0.1                  *
 * ====================================== *
 * A pre-defined ASCII code will be send  *
 * using RS232 to a PC or other equipment *
 * connected via the serial connection.   *
 * A Carriage Return(CR) and              *
 * Line feed (LF) char will be appended.  *
 * ====================================== *
 * Programmed by Rene Rasmussen 2011-09   *
 * This software released under the GPL   *
 ******************************************/
#include <avr/io.h>
#include <string.h>
#include <util/delay.h>		// define _delay_ms() ...
// for the delay to work correctly the compiler optimization must be set to -O2

#define UART_BAUD_RATE 9600L
#define UART_BAUD_CALC(UART_BAUD_RATE,F_CPU) ((F_CPU)/((UART_BAUD_RATE)*16L)-1)

// wait ms Milliseconds
void delay_ms(uint16_t ms)
{
  uint16_t t;
  for(t=0; t<=ms; t++)
  _delay_ms(1);
}

void uart_putc(unsigned char c)
{
  while(!(UCSRA & (1 << UDRE))); // Wait for UDR ready
  UDR = c;
}

void uart_puts (unsigned char *s)
{
  while (*s)
  {
    uart_putc(*s);
    s++;
  }
}

void uart_ini()
{
  UCSRB |= (1 << TXEN);		// Enable UART TX (send)
  UCSRB |= (1 << RXEN );		// Enable UART RX (receive)
  UCSRC |= (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);					// Async, 8N1
  UBRRH=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)>>8);	// Choose Baudrate
  UBRRL=(uint8_t)UART_BAUD_CALC(UART_BAUD_RATE,F_CPU);
}

void init_keypad()
{
  // Set all keypad outputs (A-D) to HIGH
  PORTC |= ((1<<0)|(1<<1)|(1<<2)|(1<<3));
}

void main (void)
{
   char CR, LF;

   // Barcode to be send over RS232
   const unsigned char *const barcode[] = { "BARX01" ,
   "BARX02" , "BARX03", "BARX04",
   "BARX05" , "BARX06", "BARX07",
   "BARX08" , "BARX09", "BARX10",
   "BARX11" , "BARX12"};


   DDRC = 0; // reset all bits to zero on port C
   DDRD = 0; // reset all bits to zero on port D

/* Keypad layout
 *
 * col   1  2  3
 * row
 *	1	[1][2][3]
 *	2	[4][5][6]
 *	3	[7][8][9]
 *	4	[*][0][#]
 */
   DDRD &= ~(1 << 5);				// PD5 set as input (DDRD.5 = 0) [column 1]
   DDRD &= ~(1 << 6);				// PD6 set as input (DDRD.6 = 0) [column 2]
   DDRD &= ~(1 << 7);				// PD7 set as input (DDRD.7 = 0) [column 3]
   DDRC |= (1 << 0);				// PC0 set as output (DDRC.0 = 1) [row 1]
   DDRC |= (1 << 1);				// PC1 set as output (DDRC.1 = 1) [row 2]
   DDRC |= (1 << 2);				// PC2 set as output (DDRC.2 = 1) [row 3]
   DDRC |= (1 << 3);				// PC3 set as output (DDRC.3 = 1) [row 3]

   PORTD |= (1 << 5);				// PD5 enable internal pull-up
   PORTD |= (1 << 6);				// PD6 enable internal pull-up
   PORTD |= (1 << 7);				// PD7 enable internal pull-up

   DDRD |= (1 << 4);				// PD4 set as output (DDRD.4 = 0) [LED]
   PORTD &= ~(1 << 4);				// PD4 set to LOW

   CR = 0x0D;						// Carriage Return Code
   LF = 0x0A;						// Linefeed

   uart_ini();
   init_keypad();

   while (1) // Loop forever
   { 

// Row 1
     PORTC &= ~(1<<0); // Set A (DDRC.0) low
     delay_ms(50); // delay to allow port to settle
     if((PIND & (1 << PIND5)) == 0)
     	   {
       uart_puts(barcode[0]);
       uart_putc(CR);
       uart_putc(LF);
       while ((PIND & (1 << PIND5)) == 0)
         {
         PORTD |= (1<<4); // activate LED
         }
       PORTD &= ~(1<<4); // deactivate LED
     	   }
     if((PIND & (1 << PIND6)) == 0)
     	   {
       uart_puts(barcode[1]);
       uart_putc(CR);
       uart_putc(LF);
       while ((PIND & (1 << PIND6)) == 0)
         {
         PORTD |= (1<<4); // activate LED
         }
       PORTD &= ~(1<<4); // deactivate LED
     	   }
     if((PIND & (1 << PIND7)) == 0)
     	   {
       uart_puts(barcode[2]);
       uart_putc(CR);
       uart_putc(LF);
       while ((PIND & (1 << PIND7)) == 0)
         {
         PORTD |= (1<<4); // activate LED
         }
       PORTD &= ~(1<<4); // deactivate LED
     	   }
     PORTC |= (1 << 0); // Set A (DDRC.0) high

// Row 2
     PORTC &= ~(1<<1); // Set B (DDRC.1) low
     delay_ms(50); // delay to allow port to settle
     if ((PIND & (1 << PIND5)) == 0)
     	   {
       uart_puts(barcode[3]);
       uart_putc(CR);
       uart_putc(LF);
       while ((PIND & (1 << PIND5)) == 0)
         {
         PORTD |= (1<<4); // activate LED
         }
       PORTD &= ~(1<<4); // deactivate LED
     	   }
     if((PIND & (1 << PIND6)) == 0)
     	   {
       uart_puts(barcode[4]);
       uart_putc(CR);
       uart_putc(LF);
       while ((PIND & (1 << PIND6)) == 0)
         {
         PORTD |= (1<<4); // activate LED
         }
       PORTD &= ~(1<<4); // deactivate LED
     	   }
     if((PIND & (1 << PIND7)) == 0)
     	   {
       uart_puts(barcode[5]);
       uart_putc(CR);
       uart_putc(LF);
       while ((PIND & (1 << PIND7)) == 0)
         {
         PORTD |= (1<<4); // activate LED
         }
       PORTD &= ~(1<<4); // deactivate LED
     	   }
     PORTC |= (1 << 1); // Set B (DDRC.1) high

// Row 3
     PORTC &= ~(1<<2); // Set C (DDRC.2) low
     delay_ms(50); // delay to allow port to settle
     if ((PIND & (1 << PIND5)) == 0)
     	   {
       uart_puts(barcode[6]);
       uart_putc(CR);
       uart_putc(LF);
       while ((PIND & (1 << PIND5)) == 0)
         {
         PORTD |= (1<<4); // activate LED
         }
       PORTD &= ~(1<<4); // deactivate LED
     	   }
     if((PIND & (1 << PIND6)) == 0)
       {
       uart_puts(barcode[7]);
       uart_putc(CR);
       uart_putc(LF);
       while ((PIND & (1 << PIND6)) == 0)
         {
         PORTD |= (1<<4); // activate LED
         }
       PORTD &= ~(1<<4); // deactivate LED
       }
     if((PIND & (1 << PIND7)) == 0)
       {
       uart_puts(barcode[8]);
       uart_putc(CR);
       uart_putc(LF);
       while ((PIND & (1 << PIND7)) == 0)
         {
         PORTD |= (1<<4); // activate LED
         }
       PORTD &= ~(1<<4); // deactivate LED
       }
     PORTC |= (1 << 2); // Set C (DDRC.2) high

// Row 4
     PORTC &= ~(1<<3); // Set C (DDRC.3) low
     delay_ms(50); // delay to allow port to settle
     if ((PIND & (1 << PIND5)) == 0)
     	   {
       uart_puts(barcode[9]);
       uart_putc(CR);
       uart_putc(LF);
       while ((PIND & (1 << PIND5)) == 0)
         {
         PORTD |= (1<<4); // activate LED
         }
       PORTD &= ~(1<<4); // deactivate LED
       }
     if((PIND & (1 << PIND6)) == 0)
       {
       uart_puts(barcode[10]);
       uart_putc(CR);
       uart_putc(LF);
       while ((PIND & (1 << PIND6)) == 0)
         {
         PORTD |= (1<<4); // activate LED
         }
       PORTD &= ~(1<<4); // deactivate LED
       }
     if((PIND & (1 << PIND7)) == 0)
       {
       uart_puts(barcode[11]);
       uart_putc(CR);
       uart_putc(LF);
       while ((PIND & (1 << PIND7)) == 0)
         {
         PORTD |= (1<<4); // activate LED
         }
       PORTD &= ~(1<<4); // deactivate LED
       }
     PORTC |= (1 << 3); // Set D (DDRC.3) high
   }
}

Final words

This was fun. And I hope it will be of some use out there in the wild.