Ta zabawka udaje prawdziwą kasę fiskalną – drukuje paragony, liczy ceny i pozwala wybierać produkty.
Opis
Zobacz film z działania:
Schemat wewnętrzny:
Kod źródłowy dla Arduino: https://pastebin.com/vuE97mH7
/*
* Zabawkowa kasa fiskalna
* 2019-01-31 Aleksander Kawęczyński e.vt0.pl
* Arduino pro mini, klawiatura membranowa 4x4, LCD 16x2, drukarka DP-Q58A
*
* Układ na wejściu zasilania z szeregowo podłączonym mosfetem-p, załączanie: microswitch chwilowy, podtrzymanie włączenia przez pin A3.
*
* 13 - power control: high - on, low - off; connected to gate of transistor, pobór prądu w stanie wyłączonym: 0,1uA
* 2 - printer software serial
* 3 .. 10 - 4x4 keyboard matrix
* 11 - LCD RS (4)
* 12 - LCD E (6)
* A0 - LCD D4 (11)
* A1 - LCD D5 (12)
* A2 - LCD D6 (13)
* A3 - LCD D7 (14)
* A6 - Vbat przez dzielnik 100K/100K
*/
#include <LiquidCrystal.h>
#include <SendOnlySoftwareSerial.h>
#include <EEPROM.h>
#include <avr/pgmspace.h>
#define POWER_CTL 13
#define VBATMIN 6000 //minimum battery voltage in mV
#define VERSION "1.1"
SendOnlySoftwareSerial drukarka(2); // Tx pin
LiquidCrystal lcd(11, 12, A0, A1, A2, A3);
unsigned long lastAction=0;
const unsigned long idle=(5UL*60UL*1000UL); //2 minutes
uint16_t keyState=0, lastKeyState=0;
char buff[80];
uint16_t suma_cen = 0, powerCounter = 0, printCounter = 0;
const uint8_t baza = 5;
uint8_t cashier=0;
const char s0[] PROGMEM = "BUx02KA";
const char s1[] PROGMEM = "SER";
const char s2[] PROGMEM = "MLEKO";
const char s3[] PROGMEM = "Px02ATKI";
const char s4[] PROGMEM = "ZESZYT";
const char s5[] PROGMEM = "LODY";
const char s6[] PROGMEM = "PIZZA";
const char s7[] PROGMEM = "WARZYWA";
const char s8[] PROGMEM = "SOK";
const char s9[] PROGMEM = "Sx02ODYCZE";
const char s10[] PROGMEM = "KAKAO";
const char s11[] PROGMEM = "CZYTANKA";
PGM_P const produkty[] PROGMEM = {s0,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11};
const char t0[] PROGMEM = " Sklep "Julka"";
const char t1[] PROGMEM = " Sklep "Franek"";
const char t2[] PROGMEM = " Sklep "Maja"";
const char t3[] PROGMEM = "Z A P R A S Z A";
const char t4[] PROGMEM = " DO ZOBACZENIA!";
PGM_P const powitania[] PROGMEM = {t0,t1,t2,t3,t4};
const uint16_t ceny[] PROGMEM = {
1,//0
6,//1
3,//2
4,//3
2,//4
2,//5
10,//6
7,//7
5,//8
8,//9
9,//10
20//11
};
byte el[8] = {
0b01000,
0b01001,
0b01010,
0b01100,
0b01000,
0b11000,
0b01111,
0b00000
};
void setup() {
// pin configuration
pinMode(POWER_CTL, OUTPUT);
digitalWrite(POWER_CTL, HIGH);
//licznik uruchomien
powerCounter = EEPROM.read(0);
powerCounter += (EEPROM.read(1) << 8);
printCounter = EEPROM.read(2);
printCounter += (EEPROM.read(3) << 8);
if( (printCounter == 255) && (analogRead(A6)<5)){
//po przeprogramowaniu, trzeba wyczyścić zmienne
powerCounter =0;
printCounter = 0;
EEPROM.write(2, ++printCounter);
}
++powerCounter;
EEPROM.write(0, powerCounter);
lcd.begin(16, 2);
lcd.createChar(2, el);
lcd.clear();
cashier = (powerCounter % 3);
strcpy_P(buff, (PGM_P)pgm_read_word(&(powitania[cashier])));
lcd.print(buff);
lcd.setCursor(0, 1);
strcpy_P(buff, (PGM_P)pgm_read_word(&(powitania[3])));
lcd.print(buff);
drukarka.begin(9600);
//wait until power button is not pressed
delay(100);
drukarka.print("x1Bx40x1Bx61x49");
lastAction = millis();
}
void loop() {
//Keyboard module:
uint16_t keys = keyDown();
uint8_t wybranyProdukt = 0;
//logic module
if(keys) lastAction = millis();
//battery voltage check
switch (keys){
case 0:
delay(100);
if((analogRead(A6)*10) < VBATMIN){
lcd.clear();
lcd.print("Bateria");
lcd.setCursor(0, 1);
lcd.print("Rozx02adowana!");
delay(2000);
wylacz();
}
break;
case (1<<0)://D -- zakonczenie paragonu
if(suma_cen == 0){
lcd.clear();
sprintf(buff, "Vb=%d mV; v" VERSION,analogRead(A6)*10 );
lcd.print(buff);
lcd.setCursor(0, 1);
sprintf(buff, "PWc=%d PrC=%d",powerCounter, printCounter);
lcd.print(buff);
delay(2000);
lcd_powitanie();
}
else{
printFooter();
}
break;
case (1<<1)://#
wybranyProdukt = 12;
break;
case (1<<2)://0
wybranyProdukt = 10;
break;
case (1<<3)://*
wybranyProdukt = 11;
break;
case (1<<4)://C
//change cashier
if(suma_cen == 0){
cashier = (++cashier) % 3;
lcd_powitanie();
}
break;
case (1<<5)://9
wybranyProdukt = 9;
break;
case (1<<6)://8
wybranyProdukt = 8;
break;
case (1<<7)://7
wybranyProdukt = 7;
break;
case (1<<8)://B
if(suma_cen == 0){
//wydrukuj cos innego
drukarka.print("x1Bx61x48"); //alignment left
drukarka.print(" ,~~.r
( 6 )-_,r
('___ )=='-' KACZKAr
\ . ) )r
\ `-' / r
~'`~'`~'`~'`~rrr");
drukarka.print("x1Bx61x49"); //alignment middle
}
break;
case (1<<9)://6
wybranyProdukt = 6;
break;
case (1<<10)://5
wybranyProdukt = 5;
break;
case (1<<11)://4
wybranyProdukt = 4;
break;
case (1<<12)://A
if(suma_cen > 0)
printFooter(); //zakoncz paragon przed wylaczeniem
wylacz();
break;
case (1<<13)://3
wybranyProdukt = 3;
break;
case (1<<14)://2
wybranyProdukt = 2;
break;
case (1<<15)://1
wybranyProdukt = 1;
break;
}
if(wybranyProdukt){
int isFirst=0;
if(suma_cen == 0) isFirst=1;//pierwszy produkt na tym paragonie,
strcpy_P(buff, (PGM_P)pgm_read_word(&(produkty[wybranyProdukt-1])));
uint8_t a = strlen(buff);
uint16_t cena = pgm_read_word(&(ceny[wybranyProdukt-1]));
suma_cen += cena;
lcd.clear();
lcd.print(buff);
itoa(cena, buff, 10);
lcd.setCursor(15-2-strlen(buff), 0);
lcd.print(buff);
lcd.print(" Zx02");
lcd.setCursor(0, 1);
sprintf(buff, "SUMA: %7d Zx02",suma_cen);
lcd.print(buff);
;
if(isFirst) {
printHeader();
isFirst=0;
}
//drukowanie pozycji na paragonie
strcpy_P(buff, (PGM_P)pgm_read_word(&(produkty[wybranyProdukt-1])));
//zamiana x02 na x9D
for (char* p = buff; p = strchr(p, 0x02); ++p) {
*p = 0x9D;
}
drukarka.print(buff);
int spacje = 32-7-a;
for(uint8_t k=0;k<spacje;++k){drukarka.print(" ");}
sprintf(buff, "%4d Zx9Dr", cena);
drukarka.print(buff);
delay(500);
wybranyProdukt = 0;
}
//test odczytu klawiatury
/*
lcd.clear();
lcd16Bit(keys);
lcd.setCursor(0, 1);
lcd16Bit(keyState);
*/
//test odczytu z pamieci FLASH i wyswietlania
/*
for (unsigned char i = 0; i < baza; i++)
{
delay(1000);
}
*/
powerFunction();
delay(10);
}
uint16_t getKeyState(){
//3 .. 10 - 4x4 keyboard matrix
uint16_t reads=0;
pinMode(3, INPUT_PULLUP);
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(7, INPUT);
pinMode(8, INPUT);
pinMode(9, INPUT);
pinMode(10, INPUT);
digitalWrite(7, LOW);
digitalWrite(8, LOW);
digitalWrite(9, LOW);
digitalWrite(10, LOW);
//col A
pinMode(7, OUTPUT);
delay(1);
reads += (((PIND & 0x78)>>3) << 0);
pinMode(7, INPUT);
//col B
pinMode(8, OUTPUT);
delay(1);
reads += (((PIND & 0x78)>>3) << 4);
pinMode(8, INPUT);
//col C
pinMode(9, OUTPUT);
delay(1);
reads += (((PIND & 0x78)>>3) << 8);
pinMode(9, INPUT);
//col D
pinMode(10, OUTPUT);
delay(1);
reads += (((PIND & 0x78)>>3) << 12);
pinMode(10, INPUT);
return ~reads;
}
void lcd_powitanie()
{
lcd.clear();
strcpy_P(buff, (PGM_P)pgm_read_word(&(powitania[cashier])));
lcd.print(buff);
lcd.setCursor(0, 1);
strcpy_P(buff, (PGM_P)pgm_read_word(&(powitania[3])));
lcd.print(buff);
}
void lcd16Bit(uint16_t number)
{
for (uint8_t i=0;i<16;i++)
{
if (((number >> (15-i)) & 0x01))
{
lcd.print("1");
}
else
{
lcd.print("0");
}
}
}
///drukuje nagłówek paragonu
void printHeader(){
EEPROM.write(2, ++printCounter);
strcpy_P(buff, (PGM_P)pgm_read_word(&(powitania[cashier])));
drukarka.print("x1Bx61x49"); //alignment middle
drukarka.print("x1Bx45x01"); //bold print
drukarka.print("x1Bx0Ex02"); //times 2 wider pattern
drukarka.print(buff);
drukarka.print("x1Bx45x00"); //bold print off
drukarka.print("x1Bx14x02"); //cancel times wider pattern
delay(30);
sprintf(buff, "DZIEN DOBRY! rnPARAGON NR %drnx1Dx6Bx03",printCounter);
drukarka.print(buff);
sprintf(buff,"%08d", printCounter);
drukarka.write((uint8_t)0);
sprintf(buff, "xCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDxCDr",printCounter);
drukarka.print(buff);
//delay(2000);
}
void printFooter(){
lcd.clear();
lcd.print("Drukowanie ...");
lcd.setCursor(0, 1);
sprintf(buff, "SUMA: %7d Zx02",suma_cen);
lcd.print(buff);
sprintf(buff, "x1Bx61x50+ rx1Bx61x49================================rn");
drukarka.print(buff);
delay(100);
sprintf(buff, "RAZEM:%23d Zx9DrrDO WIDZENIA!rrrr",suma_cen);
drukarka.print(buff);
delay(100);
suma_cen = 0;
lcd_powitanie();
}
uint16_t keyDown(){
uint16_t ret;
lastKeyState = keyState;
keyState = getKeyState();
ret = ((keyState^lastKeyState)&keyState);
return ret;
}
void powerFunction(){
//Power function:
unsigned long czas = millis();
if((lastAction+idle) < czas )
wylacz();
//actions:
//lastAction = millis();
}
void wylacz(){
lcd.clear();
strcpy_P(buff, (PGM_P)pgm_read_word(&(powitania[(powerCounter % 3)])));
lcd.print(buff);
lcd.setCursor(0, 1);
strcpy_P(buff, (PGM_P)pgm_read_word(&(powitania[4])));
lcd.print(buff);
delay(2000);
lcd.clear();
digitalWrite(POWER_CTL, LOW);
for(;;){};
}
Więcej zdjęć:
Szablon do wycięcia obudowy ze sklejki (uwaga: wymiary dostosowane do sklejki o grubości 6,3mm!) obudowa_cnc.pdf
Dokumentacja techniczna drukarki: Embedded printer DP-Q58A Technical Manual.pdf
W kodzie Arduino użyłem biblioteki SendOnlySoftwareSerial.zip: SendOnlySoftwareSerial.zip





Najnowsze komentarze