Наверное многие уже видели автомойки самообслуживания. Можно ли создать такой аппарат на Arduino?
… следующая волна экономических бедствий… будет результатом быстрой поступи автоматизации, которая упраздняет многие хорошие рабочие места уровня среднего класса (Б. Обама)
Как это работает
- Клиент приезжает на мойку
- Вносит деньги через купюроприёмник (на табло отображается сумма)
- Нажимает кнопку необходимого оборудования
- Клиент самостоятельно моет машину
- При желании нажимает стоп, либо выбирает другое оборудование
- Табло отсчитывает сумму за услуги (в зависимости от включенного оборудования)
- При обнулении оборудование выключается
- При необходимости повторить с п.2
При этом сетевые возможности аппарата позволяют:
- Видеть все внесённые платежи
- Менять настройки цен за услуги
- Включать/выключать оборудование
- Вести лог операций и ошибок на сервере
Состав оборудования
- Arduino Uno R3
- Матричный модуль типа MAX7219 на 4 знака
- Ethernet шилд W5100
- Модуль на 8 реле
- Кнопки
- Резисторы
- Провода
- Купюроприёмник Cashcode SM
- Щит электрический (степень защиты чем больше, тем лучше)
Всё закуплено на Aliexpress (кроме купюроприёмника и щита).
Схема сборки
Сетевой шилд просто втыкается сверху. Далее всё собирается через него.
Arduino — Cashcode
A0 — 11 (TxD TTL)
A1 — 16 (RxD TTL)
GND — 4 (GND)
Arduino — MAX7219
A4 — CLK
A3 — CS
A2 — DIN
GND — GND
+5V — VCC
Arduino — Реле
2-7 — in1-in6
GND — GND
+5V — VCC
Кнопки собираются по схеме делителя напряжения и подключены на A5. У меня резисторы от 200Ом до 3,2КОм.
Программирование
Инициализация табло и реле:
#define DIN 16
#define CS 17
#define CLK 18
#define max7219_reg_decodeMode 0x09
#define max7219_reg_intensity 0x0a
#define max7219_reg_scanLimit 0x0b
#define max7219_reg_shutdown 0x0c
#define max7219_reg_displayTest 0x0f
const unsigned char alf[] = {0,
28, 34, 34, 34, 34, 34, 34, 28,
8, 24, 8, 8, 8, 8, 8, 28,
28, 34, 2, 4, 8, 16, 32, 62,
28, 34, 2, 4, 2, 2, 34, 28,
34, 34, 34, 34, 62, 2, 2, 2,
62, 32, 32, 60, 2, 2, 2, 60,
28, 32, 32, 60, 34, 34, 34, 28,
62, 2, 2, 4, 8, 16, 32, 32,
28, 34, 34, 28, 34, 34, 34, 28,
28, 34, 34, 30, 2, 2, 2, 28
};
void setup()
{
pinMode(DIN,OUTPUT); pinMode(CS,OUTPUT); pinMode(CLK,OUTPUT); digitalWrite(CS, HIGH);
initLed();
pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); pinMode(6, OUTPUT); pinMode(7, OUTPUT);
pinMode (A5, INPUT);
}
void setCommand(byte command, byte value)
{
digitalWrite(CS, LOW);
for (int i=0; i<4; i++) { shiftOut(DIN,CLK, MSBFIRST, command); shiftOut(DIN,CLK, MSBFIRST, value); }
digitalWrite(CS, HIGH);
}
void initLed()
{
setCommand(max7219_reg_scanLimit, 0x07);
setCommand(max7219_reg_decodeMode, 0x00);
setCommand(max7219_reg_shutdown, 0x01);
setCommand(max7219_reg_displayTest, 0x00);
setCommand(max7219_reg_intensity, 1);
}
Отображение числа на табло (текущее значение на случай отключения питания хранится в ячейках EEPROM 10 и 11):
int printNumber(int add)
{
int n=EEPROM.read(10)+EEPROM.read(11)*256;
if(add!=0) { n+=add; EEPROM.write(10, n%256); EEPROM.write(11, n>>8); }
int k;
for (char i=1; i<=8; i++)
{
digitalWrite(CS, LOW);
for (char j=3; j>=0; j--) { k=n/pow(10,j); shiftOut(DIN,CLK, MSBFIRST,i); shiftOut(DIN,CLK, MSBFIRST,alf[i+(k%10)*8]); }
digitalWrite(CS, HIGH);
}
return n;
}
Считывание кнопки (keydown отслеживает возврат кнопок в исходное для исключения дребезга реле, числа в условиях подбираются опытным путём):
int key = analogRead (5);
if(keydown && key<100) keydown=0;
if((EEPROM.read(10)>0 || EEPROM.read(11)>0) && !keydown)
{
if(key>910 && key<980) setRele(1);
if(key>810 && key<880) setRele(2);
if(key>710 && key<760) setRele(3);
if(key>550 && key<690) setRele(4);
if(key>400 && key<500) setRele(5);
if(key>330 && key<400) setRele(0);
}
Работа реле (в ячейках EEPROM 1-9 хранятся цены услуг за минуту использования):
void setRele(char r)
{
rele=r;
keydown=1;
for(char i=1;i<6;i++) digitalWrite(i+1, HIGH);
if(rele)
{
digitalWrite(rele+1, LOW);
timeRele=millis();
timeAllRele=60000/EEPROM.read(rele);
}
}
Счетчик денег (при включенном реле и превышении счетчика милисекунд заданного значения вычитаем 1):
if(rele>0 && rele<=5 && (millis()-timeRele)>timeAllRele)
{
if(printNumber(-1)==0) setRele(0);
timeRele+=timeAllRele;
}
Сетевые клиент и сервер взяты из стандартных библиотек Arduino. Купюроприёмник работает по протоколу CCNET.
В следующих частях более подробное описание их работы и аппарата следующего поколения на одноплатнике Orange Pi с экраном 17" и тачскрином.
Автор: paul_155