Overview
A barcode is a square or rectangular image consisting of a series of parallel black lines and white spaces of varying widths that can be read by a scanner. Barcodes are applied to products as a means of quick identification. They are used in retail stores as part of the purchase process, in warehouses to track inventory, and on invoices to assist in accounting, among many other uses.
In this tutorial we will make a simple Barcode Scanner that will display the barcode, product name and price in 3.5” TFT LCD display.
Here’s a sample video:
Hardware Components
You can buy it all here at CreateLabz.
Software Components
Application Discussion
Barcode Scanner
Is an electronic device that can read and output printed barcodes to a computer. Like a flatbed scanner, it consists of a light source, a lens and a light sensor translating for optical impulses into electrical signals.Additionally, nearly all barcode readers contain decoder circuitry analyzing the bar code’s image data provided by the sensor and sending the barcode’s content to the scanner’s output port.
How does it work:
A barcode scanner “scans” the black and white elements of a barcode by illuminating the code with a red light, which is then converted into matching text. More specifically, the sensor in the barcode scanner detects the reflected light from the illumination system (the red light) and generates an analog signal that is sent to the decoder. The decoder interprets that signal, validates the barcode using the check digit, and converts it into text.

USB Host Shield
USB Host Shield allows you to connect a USB device to your Arduino board. The Arduino USB Host Shield is based on the MAX3421E, which is a USB peripheral/host controller containing the digital logic and analog circuitry necessary to implement a full-speed USB peripheral or a full-/low-speed host compliant to USB specification rev 2.0. The shield is TinkerKit compatible, which means you can quickly create projects by plugging TinkerKit modules onto the board.

3.5” TFT LCD Shield
TFT LCD Shield contains a 16 bit color TFT screen with a large 3.5″ display and is designed to fit directly into the standard headers of an Arduino requiring no additional interface hardware. It support a relatively high resolution of 480 x 320 pixels.

Hardware Setup



1st Step: Mount the USB Host Shield on the Arduino Mega.


2nd Step: Connect the Barcode scanner to the USB Host Shield.



3rd Step: Mount the 3.5” TFT LCD Shield on the USB Host Shield.
Code
Libraries Included
Arduino Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
#include <usbhid.h> #include <usbcore.h> #include <usbhub.h> #include <hiduniversal.h> #include <hidboot.h> #include <SPI.h> #include <MCUFRIEND_kbv.h> MCUFRIEND_kbv tft; #define BLACK 0x0000 #define BLUE 0x001F #define RED 0xF800 #define GREEN 0x07E0 #define CYAN 0x07FF #define MAGENTA 0xF81F #define YELLOW 0xFFE0 #define WHITE 0xFFFF #define GRAY 0x8410 #define CUSTOM1 0x1FBC #define CUSTOM2 0x1107 #define CUSTOM3 0xDEC1 uint16_t version = MCUFRIEND_KBV_H_; uint8_t ascii; uint8_t code[13]; int scancounter = 0; int def = 160; int reg = 0; int width; int height; class MyParser : public HIDReportParser { public: MyParser(); void Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); protected: uint8_t KeyToAscii(bool upper, uint8_t mod, uint8_t key); virtual void OnKeyScanned(bool upper, uint8_t mod, uint8_t key); virtual void OnScanFinished(); }; MyParser::MyParser() {} void MyParser::Parse(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) { // If error or empty, return if (buf[2] == 1 || buf[2] == 0) return; for (uint8_t i = 7; i >= 2; i--) { // If empty, skip if (buf[i] == 0) continue; // If enter signal emitted, scan finished if (buf[i] == UHS_HID_BOOT_KEY_ENTER) { Serial.println(reg); //--------------------------------------------------------------------// if (reg == 686) { Serial.println(" - Barcode "); Serial.print("Product name:"); Serial.println(" Sprite 300mL "); Serial.println((char)code[1]); uint16_t ID = tft.readID(); tft.begin(ID); tft.setRotation(3); tft.fillScreen(CUSTOM1); tft.fillRoundRect(32, 50, width - 64, height - 64, 30, WHITE); tft.setTextSize(4); tft.setTextColor(CUSTOM2, WHITE); tft.setCursor(10, 10); tft.print("BARCODE SCANNER"); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 60); tft.print("Barcode: "); for (int i = 1; i <= 13; i++) { c += 18; tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(def, 90); tft.print((char)code[i]); //Serial.print((char)code[i]); if (i == 13) { def = 160; } } tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 120); tft.print("Product: "); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(175, 150); tft.print("Sprite 300mL"); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 180); tft.print("Price: "); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(175, 210); tft.print("Php 15.00"); } //-----------------------------------------------------------------------// else if (reg == 692 ) { Serial.println(" - Barcode "); Serial.print("Product name:"); Serial.println(" Kopiko Blanca "); uint16_t ID = tft.readID(); tft.begin(ID); tft.setRotation(3); tft.fillScreen(CUSTOM1); tft.fillRoundRect(32, 50, width - 64, height - 64, 30, WHITE); tft.setTextSize(4); tft.setTextColor(CUSTOM2, WHITE); tft.setCursor(10, 10); tft.print("BARCODE SCANNER"); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 60); tft.print("Barcode: "); for (int i = 1; i <= 13; i++) { c += 18; tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(def, 90); tft.print((char)code[i]); //Serial.print((char)code[i]); if (i == 13) { def = 160; } } tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 120); tft.print("Product: "); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(175, 150); tft.print("kopiko Blanca"); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 180); tft.print("Price: "); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(175, 210); tft.print("Php 7.00"); } //--------------------------------------------------------------------------// else if (reg == 670 ) { Serial.println(" - Barcode "); Serial.print("Product name:"); Serial.println(" Nescafe Original "); uint16_t ID = tft.readID(); tft.begin(ID); tft.setRotation(3); tft.fillScreen(CUSTOM1); tft.fillRoundRect(32, 50, width - 64, height - 64, 30, WHITE); tft.setTextSize(4); tft.setTextColor(CUSTOM2, WHITE); tft.setCursor(10, 10); tft.print("BARCODE SCANNER"); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 60); tft.print("Barcode: "); for (int i = 1; i <= 13; i++) { c += 18; tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(def, 90); tft.print((char)code[i]); //Serial.print((char)code[i]); if (i == 13) { def = 160; } } tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 120); tft.print("Product: "); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(175, 150); tft.print("Nescafe Original"); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 180); tft.print("Price: "); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(175, 210); tft.print("Php 7.00"); } OnScanFinished(); } // If not, continue normally else { // If bit position not in 2, it's uppercase words OnKeyScanned(i > 2, buf, buf[i]); } return; } } uint8_t MyParser::KeyToAscii(bool upper, uint8_t mod, uint8_t key) { // Letters if (VALUE_WITHIN(key, 0x04, 0x1d)) { if (upper) return (key - 4 + 'A'); else return (key - 4 + 'a'); } // Numbers else if (VALUE_WITHIN(key, 0x1e, 0x27)) { return ((key == UHS_HID_BOOT_KEY_ZERO) ? '0' : key - 0x1e + '1'); } return 0; } void MyParser::OnKeyScanned(bool upper, uint8_t mod, uint8_t key) { ascii = KeyToAscii(upper, mod, key); scancounter++; code[scancounter] = ascii; reg += code[scancounter]; Serial.print(ascii); Serial.print((char)ascii); } void MyParser::OnScanFinished() { Serial.println(" - Finished"); reg = 0; scancounter = 0; } USB Usb; USBHub Hub(&Usb); HIDUniversal Hid(&Usb); MyParser Parser; void setup() { Serial.begin( 115200 ); Serial.println("Start"); uint16_t ID = tft.readID(); tft.begin(ID); tft.setRotation(3); width = tft.width(); height = tft.height(); tft.drawRect(0, 0, width, height, WHITE); tft.drawRect(32, 32, width - 64, height - 64, WHITE); tft.fillScreen(CUSTOM1); tft.fillRoundRect(32, 50, width - 64, height - 64, 30, WHITE); tft.fillCircle(240, 190, 60, CUSTOM3); tft.fillCircle(310, 130, 60, CUSTOM2); tft.fillCircle(170, 130, 60, CUSTOM1); tft.fillCircle(310, 240, 60, CUSTOM1); tft.fillCircle(170, 240, 60, CUSTOM2); tft.setTextSize(4); tft.setTextColor(CUSTOM2, WHITE); tft.setCursor(10, 10); tft.print("BARCODE SCANNER"); if (Usb.Init() == -1) { Serial.println("OSC did not start."); } delay( 200 ); Hid.SetReportParser(0, &Parser); } void loop() { Usb.Task(); } |
Code Breakdown
1 2 3 4 5 6 7 8 |
void MyParser::OnKeyScanned(bool upper, uint8_t mod, uint8_t key) { ascii = KeyToAscii(upper, mod, key); scancounter++; code[scancounter] = ascii; reg += code[scancounter]; Serial.print((char)ascii); } |
This is the code where the barcode scanner will read the values stored in the barcode, and store it in an array. Then adds all the value and store it in the reg variable. And print it in serial monitor as a character.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
void setup() { Serial.begin( 115200 ); Serial.println("Start"); uint16_t ID = tft.readID(); tft.begin(ID); tft.setRotation(3); width = tft.width(); height = tft.height(); tft.drawRect(0, 0, width, height, WHITE); tft.drawRect(32, 32, width - 64, height - 64, WHITE); tft.fillScreen(CUSTOM1); tft.fillRoundRect(32, 50, width - 64, height - 64, 30, WHITE); tft.fillCircle(240, 190, 60, CUSTOM3); tft.fillCircle(310, 130, 60, CUSTOM2); tft.fillCircle(170, 130, 60, CUSTOM1); tft.fillCircle(310, 240, 60, CUSTOM1); tft.fillCircle(170, 240, 60, CUSTOM2); tft.setTextSize(4); tft.setTextColor(CUSTOM2, WHITE); tft.setCursor(10, 10); tft.print("BARCODE SCANNER"); if (Usb.Init() == -1) { Serial.println("OSC did not start."); } delay( 200 ); Hid.SetReportParser(0, &Parser); } |
In this code we begin the serial communication and initialize the TFT screen and display the “Barcode Scanner” text and the design elements.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
if (buf[i] == UHS_HID_BOOT_KEY_ENTER) { Serial.println(reg); //--------------------------------------------------------------------// if (reg == 686) { Serial.println(" - Barcode "); Serial.print("Product name:"); Serial.println(" Sprite 300mL "); Serial.println((char)code[1]); uint16_t ID = tft.readID(); tft.begin(ID); tft.setRotation(3); tft.fillScreen(CUSTOM1); tft.fillRoundRect(32, 50, width - 64, height - 64, 30, WHITE); tft.setTextSize(4); tft.setTextColor(CUSTOM2, WHITE); tft.setCursor(10, 10); tft.print("BARCODE SCANNER"); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 60); tft.print("Barcode: "); for (int i = 1; i <= 13; i++) { def += 18; tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(def, 90); tft.print((char)code[i]); //Serial.print((char)code[i]); if (i == 13) { def = 160; } } tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 120); tft.print("Product: "); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(175, 150); tft.print("Sprite 300mL"); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 180); tft.print("Price: "); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(175, 210); tft.print("Php 15.00"); } //-----------------------------------------------------------------------// else if (reg == 692 ) { Serial.println(" - Barcode "); Serial.print("Product name:"); Serial.println(" Kopiko Blanca "); uint16_t ID = tft.readID(); tft.begin(ID); tft.setRotation(3); tft.fillScreen(CUSTOM1); tft.fillRoundRect(32, 50, width - 64, height - 64, 30, WHITE); tft.setTextSize(4); tft.setTextColor(CUSTOM2, WHITE); tft.setCursor(10, 10); tft.print("BARCODE SCANNER"); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 60); tft.print("Barcode: "); for (int i = 1; i <= 13; i++) { def += 18; tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(def, 90); tft.print((char)code[i]); //Serial.print((char)code[i]); if (i == 13) { def = 160; } } tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 120); tft.print("Product: "); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(175, 150); tft.print("kopiko Blanca"); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 180); tft.print("Price: "); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(175, 210); tft.print("Php 7.00"); } //--------------------------------------------------------------------------// else if (reg == 670) { Serial.println(" - Barcode "); Serial.print("Product name:"); Serial.println(" Nescafe Original "); uint16_t ID = tft.readID(); tft.begin(ID); tft.setRotation(3); tft.fillScreen(CUSTOM1); tft.fillRoundRect(32, 50, width - 64, height - 64, 30, WHITE); tft.setTextSize(4); tft.setTextColor(CUSTOM2, WHITE); tft.setCursor(10, 10); tft.print("BARCODE SCANNER"); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 60); tft.print("Barcode: "); for (int i = 1; i <= 13; i++) { def += 18; tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(def, 90); tft.print((char)code[i]); //Serial.print((char)code[i]); if (i == 13) { def = 160; } } tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 120); tft.print("Product: "); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(175, 150); tft.print("Nescafe Original"); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(40, 180); tft.print("Price: "); tft.setTextSize(3); tft.setTextColor(WHITE, CUSTOM2); tft.setCursor(175, 210); tft.print("Php 7.00"); } |
In this code, we identify if the scanning of the barcode is complete. And displays the sum of all the values in a barcode and if the sum of the all the values in the barcode is equal to a registered value, then it will displays the product name, price and barcode in the TFT LCD. And then calls the OnScanFinished() function.
1 2 3 4 5 |
void MyParser::OnScanFinished() { Serial.println(" - Finished"); reg = 0; scancounter = 0; } |
In this code if the function is called it will just reset the value of the reg variable or set it back to zero and also the scancounter variable.
Important Note!
Standard-sized Arduino boards, such as Duemilanove and UNO have SPI signals routed to pins 11-13 in addition to ICSP connector, therefore shields using pins 11-13 combined with standard-sized Arduinos will interfere with SPI. And since we are using 3.5” TFT LCD Shield that uses 11-13 pins for SPI communication. So it would be better if we use an arduino board that doesn’t use the pins 11 -13 for SPI communication, like the arduino mega.
Conclusion
Barcodes eliminate the possibility of human. A barcode scan is fast and reliable, and takes less time than entering data by hand. So this tutorial can be a good help in doing business much more efficient, and you can also modify or upgrade it.
Reference
[1] https://www.circuitsathome.com/usb-host-shield-hardware-manual/
[2] http://www.waspbarcode.com/buzz/how-barcode-scanners-work/
[3] https://ee.hawaii.edu/~tep/EE160/Book/chap4/subsection2.1.1.1.html