Опубликовано: 23.07.2017 01:11
Автор: jazon
Всем доброго... В этой статье мы будем знакомиться с прототипом счетчика готовой продукции. В прототипе реализована возможность записи подсчитанного количества единиц продукта в энергонезависимую память EEPROM. Итак, какие компоненты мы использовали в данной реализации? Давайте перечислим их, это:
Вообще, за основу можно взять любую плату Arduino, будь то Mega, UNO, и др. Главное условие - наличие в чипе энергонезависимой памяти EEPROM. Что еще? Думаю что схема тут не будет лишней !!!
Очень неплохо будет собрать прототип где нибудь на стенде, что мы и сделали. Хотя, в общем то можно его собрать уже в готовый корпус, если есть желание... Посмотрев видео ниже, вы сами решите какой вам удобен вариант, у нас он всё равно собран на стенде. Немного о кнопках:
Принцип работы прототипа тоже нужно расписать поподробнее... Итак, после подачи питания на дисплей будет выведено сообщение о том что память EEPROM используется. Это произойдет потому что в скетче предусмотрена единократная операция подготовки участка памяти EEPROM для хранения будущего значения общего количества единиц продукта. Обычно каждая ячейка памяти EEPROM заполнена значением 255, это конечно в том случае если память EEPROM никогда не использовалась и не перезаписывалась с конкретно определённой целью. Но если в ваших проектах всё же когда то использовалась память EEPROM, ниже следующий скетч поможет привести её в первоначальное состояние(заполнить все ячейки значением 255). Здесь главное задать размер памяти EEPROM в строке #define SIZE_OF_EEPROM
Листинг скетча №1
#include "EEPROM.h"
#define SIZE_OF_EEPROM 1024
void setup()
{
for(int i = 0; i < SIZE_OF_EEPROM; i ++)
EEPROM.write(i , 255);
}
void loop()
{
}
Что же, достаточно загрузить этот скетч всего один раз, далее можно загружать именно программу счетчика, но до неё мы еще дойдём ниже. Далее, после сообщения что память EEPROM используется будет отрисовка стандартного экрана, с двуми строками:
Собрав данный прототип(по схеме конечно), можно его протестировать. К примеру, вот несколько тестов, которые можно в общем то увидеть посмотрев нижеследующее видео. Но обо всём по порядку... Итак:
Дальнейшее видео продемонстрирует работу скетча:
Ну и наконец, скетч, который был реализован для данного прототипа, сразу предупреждаем - скетч очень длинный(ну ооочень многа букафф), собрав прототип можете просто залить скетч в плату Arduino, его можно скачать архивом здесь, либо можно просто скопировать из окна браузера:
Листинг скетча №2
#include "EEPROM.h"
#include "Wire.h"
#include "LiquidCrystal_I2C.h"
#define INCRES 2
#define WRT_EEPROM 3
#define STATUS_EEPROM_ADDR 8
#define SIZE_OF_EEPROM 1024
#define COLS 16
#define ROWS 2
#define DISPLAY_ADDR 0x27
#define DELAY_RENDERING 40
LiquidCrystal_I2C LCD(DISPLAY_ADDR, COLS, ROWS);
//Функция печатания символов при отрисовке сообщения
void Show_Messages(char msg[],
int msgLength,
int delayRendering, int strPosition);
//Различные сообщения выводимые на дисплей
char EEPROM_Status[16] = "EEPROM Status: ";
char MemoryIsClean[16] = "Memory is clean.";
char MemoryIsUsed[16] = "Memory used...";
char MemoryErased[16] = "Memory erased...";
char WritingValue[16] = "Writing a value";
char PreparingMem[16] = "Preparing memory";
char ErasingAfter[16] = "Erasing after";
char MSG_Shift[8] = "Shift ";
char MSG_Total[8] = "Total ";
//Переменные для хранения подсчитанных единиц продукта
unsigned long CurrentCounter = 0;
unsigned long EEPROM_Counter = 0;
//Переменные для отсчета перед операция обнуления EEPROM
unsigned long previousMillis = 0;
int resetCounter = 10;
int period = 1000;
//Переменные для подавления дребезга контактов кнопок
bool PressCurrEvent = false;
bool PressPrevEvent = false;
bool SensCurrEvent = false;
bool SensPrevEvent = false;
//Режимы работы
//0 - Стандартный режим, отображать подсчитанные единицы
//в строках Shift и Total
//1 - Режим обнуления памяти EEPROM
short int Mode = 0;
void setup()
{
//Назначение портов
pinMode(INCRES, INPUT);
pinMode(WRT_EEPROM, INPUT);
//Стандартные инструкции инициализации дисплея
LCD.begin();
LCD.clear();
LCD.backlight();
//Считать значение из EEPROM, либо обработать
//для последующей работы участок памяти
ReadEEPROM();
}
void loop()
{
unsigned long currentMillis = millis();
//Считываем событие с датчика, через который проходит продукт
SensCurrEvent = Debounce(INCRES, SensPrevEvent);
if(SensPrevEvent == false && SensCurrEvent == true)
{
if(CurrentCounter == 99999999)
CurrentCounter = 0;
else
CurrentCounter ++;
}
SensPrevEvent = SensCurrEvent;
//Считываем событие с кнопки записи/обнуления EEPROM
PressCurrEvent = Debounce(WRT_EEPROM, PressPrevEvent);
if(PressPrevEvent == false && PressCurrEvent == true)
{
WriteEEPROM();
}
PressPrevEvent = PressCurrEvent;
// Далее работа с режимами
switch(Mode)
{
//В режиме 0 показать основные параметры
case(0):
UpdateDisplay();
break;
//В режиме 1 вызов функции обнуления EEPROM
case(1):
EraseEEPROM();
break;
}
}
//Функция подавления дребезга контактов кнопок и фильтрации
//ложных срабатываний
boolean Debounce(int ScanPort, boolean last)
{
boolean current = digitalRead(ScanPort);
if(current != last)
{
delay(5);
current = digitalRead(ScanPort);
}
return current;
}
//Функция подготовки строк Shift и Total
//к выводу их на дисплей со значениями
void UpdateDisplay()
{
unsigned long CountValue = CurrentCounter;
//Блок подготовки верхней строки дисплея
LCD.setCursor(0, 0);
LCD.print("Shift ");
for(int i = 15; i >= 8; i --)
{
if(CountValue == 0)
{
if(i == 15)
{
LCD.setCursor(i, 0);
LCD.print(CountValue);
}
else
{
LCD.setCursor(i, 0);
LCD.print(" ");
}
}
else
{
LCD.setCursor(i, 0);
LCD.print(CountValue % 10);
CountValue = CountValue / 10;
}
}
//Блок подготовки нижней строки дисплея
LCD.setCursor(0, 1);
LCD.print("Total ");
CountValue = EEPROM_Counter;// + CurrentCounter;
for(int i = 15; i >= 8; i --)
{
if(CountValue == 0)
{
if(i == 15)
{
LCD.setCursor(i, 1);
LCD.print(CountValue);
}
else
{
LCD.setCursor(i, 1);
LCD.print(" ");
}
}
else
{
LCD.setCursor(i, 1);
LCD.print(CountValue % 10);
CountValue = CountValue / 10;
}
}
}
//Функция получения и форматирования значения из
//участка памяти EEPROM
unsigned long getEEPROMValue()
{
unsigned long rValue = 0;
unsigned long tValue = 10000000;
for(int i = 0; i < 8; i ++)
{
rValue = (EEPROM.read(i) * tValue) + rValue;
tValue = tValue / 10;
}
return rValue;
}
//Функция обнуления памяти EEPROM с отрисовкой
//сообщений о статусе устройства
void EraseEEPROM()
{
LCD.setCursor(0, 1);
LCD.print(ErasingAfter);
LCD.setCursor(14, 1);
LCD.print(resetCounter);
LCD.setCursor(15, 1);
LCD.print("s");
unsigned long currentMillis = millis();
if(digitalRead(WRT_EEPROM))
{
if(currentMillis - previousMillis > period)
{
resetCounter --;
if(resetCounter == 0)
{
LCD.clear();
LCD.setCursor(0, 0);
LCD.print(EEPROM_Status);
Show_Messages(MemoryErased, strlen(MemoryErased), DELAY_RENDERING, 1);
for(int i = 0; i < SIZE_OF_EEPROM; i ++)
EEPROM.write(i , 255);
ReadEEPROM();
resetCounter = 10;
Mode = 0;
}
previousMillis = currentMillis;
}
}
else
{
resetCounter = 10;
Mode = 0;
}
}
//Функция записи/суммирования в память EEPROM текущего
//значения Shift
void WriteEEPROM()
{
unsigned long CountValue = CurrentCounter + EEPROM_Counter;
LCD.clear();
Show_Messages(EEPROM_Status, strlen(EEPROM_Status), DELAY_RENDERING, 0);
Show_Messages(WritingValue, strlen(WritingValue), DELAY_RENDERING, 1);
delay(1500);
for(int i = 7; i >= 0; i --)
{
EEPROM.write(i, CountValue % 10);
CountValue = CountValue / 10;
}
CurrentCounter = 0;
EEPROM_Counter = getEEPROMValue();
if(digitalRead(WRT_EEPROM))
{
LCD.setCursor(0, 1);
LCD.print(" ");
delay(100);
Mode = 1;
}
}
//Функция первичного считывания участка памяти EEPROM
void ReadEEPROM()
{
//Считать ячейку которая хранит статус записи EEPROM
//может содержать два значения:
//255 - ячейка и EEPROM никогда не перезаписывались
//0 - ячейка и EEPROM уже включены в работу и содержат данные
switch(EEPROM.read(STATUS_EEPROM_ADDR))
{
//Считать значение из EEPROM
case(0):
Show_Messages(EEPROM_Status, strlen(EEPROM_Status), DELAY_RENDERING, 0);
Show_Messages(MemoryIsUsed, strlen(MemoryIsUsed), DELAY_RENDERING, 1);
delay(1500);
LCD.clear();
break;
//Подготовить EEPROM к работе
case(255):
for(int i = 0; i < 9; i ++)
EEPROM.write(i , 0);
Mode = 0;
break;
}
EEPROM_Counter = getEEPROMValue();
}
//Простая функция для отрисовки сообщений на дисплее
//в стиле фильма "Терминатор"
void Show_Messages(char msg[], int msgLength, int delayRendering, int strPosition)
{
LCD.leftToRight();
for(int j = 0; j < msgLength; j ++)
{
LCD.setCursor(j, strPosition);
LCD.write(msg[j]);
delay(delayRendering);
}
}
Ну вот на этом как бы и всё, кому понравилось или кто то уже применил данный прототип в деле - пишите свои отзывы ниже в комментариях, также с уважением отнесёмся к вашей критике. Всем спасибо !!!
Если у Вас есть опыт в работе с Arduino и собственно есть время для творчества, мы приглашаем всех желающих стать авторами статей публикуемых на нашем портале. Это могут быть как уроки, так и рассказы о ваших экспериментах с Arduino. Описание различных датчиков и модулей. Советы и наставления начинающим. Пишите и размещайте свои статьи в соответсвующей ветке форума.