Тахометр на arduino pro mini от датчика холла на LCD1602+I2C

viktorflam
Offline
Зарегистрирован: 09.09.2016

Добрый день господа и дамы!

тема затерта до дыр но тем не менее есть несколько моментов, в которых не могу найти ответа и разобраться сам. Собственно схема довольно простая: датчик Холла передает сигнал на ардуину, та в свою очередь обрабатывает аппаратные прерывания и выдает результат на дисплей и дисплей благополучно отображает данные, но сами данные на дисплее отображаются не совсем корректно, в частности в процессе уменьшения значения с 1000 до 100, последний символ продолжает оставаться на дисплее. Вот код:

#include <Wire.h> 
#include <LiquidCrystal_I2C.h> 
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display 

unsigned long lastflash; 
int RPM; 

void setup() { 
Serial.begin(9600); //открыть порт 
attachInterrupt(0, sens, RISING); //подключить прерывание на 2 пин при повышении сигнала 
pinMode(3, OUTPUT); //3 пин как выход 
digitalWrite(3, HIGH); //подать 5 вольт на 3 пин 
lcd.init(); 
lcd.backlight(); 
} 
void sens() { 
RPM = 60 / ((float)(micros() - lastflash) / 1000000); //расчет 
lastflash = micros(); //запомнить время последнего оборота 
} 

void loop() { 
if ((micros() - lastflash) > 1000000) { //если сигнала нет больше секунды 
RPM = 0; //считаем что RPM 0 

} 
 
lcd.setCursor(0, 0); 
lcd.print("RPM: "); 
lcd.print(RPM); 
lcd.setCursor(10, 0); 
lcd.print("ob/min"); 
delay(250); 
}

Если же строки 

lcd.init(); 
lcd.backlight();

унести в цикл ко всем остальным lcd, то значения обновляются 1 раз в секунду, что тоже не совсем удобно

видео тут: 

1. https://vk.com/video5613556_456239019

2. https://vk.com/video5613556_456239018

3. https://vk.com/video5613556_456239017

Подскажите, как можно добиться того, что бы данные на дисплее отображались корректно?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вместо строк 28-31 просто пишете

char buffer[32];
sprintf(buffer, "RPM: %d ob/min       ", RPM);
lcd.print(buffer);

Немного туповато, но работать будет.

При этом надпись "ob/min" будет ходить вправо-влево, в зависимости от количества знаков в числе оборотов.

Если надо, чтобы она стояла на месте (тогда её можно один раз написать и не трогать), тогда скажите максимальную ширину числа (сколько знаков) и куда его выравнивать - влево или вправо.

viktorflam
Offline
Зарегистрирован: 09.09.2016

а ларчик то просто открывался))) Спасибо уважаемый!

А может ты в курсе как снизу сделать шкалу, которая заполняется в зависимости оборотов??? что-то типа процесс-бара, как на этом видео https://www.youtube.com/watch?v=bs8tzhyimhw&index=4&list=LLAMNJYOU9Q8BAVDivgSktuQ 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, там в шрифте должны быть символы "полузакрашенное слева  знакоместо" и "закрашенное полностью знакоместо". Вот этими миволами и рисовать. Т.е. это просто "буквы такие". Ну составляйте строку из таких букв и рисуйте.

Строка делается таким образом:

Во время разработки

1. Считаете сколько у Вас в той строке символов (допустим 16)
2. Умножаете на 2 (получаем 32 "полусимвола")
3. Максимально возможное число оборотов (допустим 10000) делите на 32 - получаете "цену одного полусимвола" 10000/32 = 312,5

Теперь уже в реальной жизни - во время выполнения программы

4. Когда измерили реально клочиство оборотов (допустим 800), делите его на цену полусимвола N = 800/312.5 = 2.56.
5. Округляете - получаем N=3. Значит нам нужно показать 3 полусимвола
6. Сначала выводите N/2 (деление целочисленное) полностью закрашенных символов, а затем, N%2 полузакрашенных
7. Хвост полоски дозабиваете пробелами.

Получаете точно такую полоску.

Раельно всё выльется в несколько строк кода и такую же sprintf

viktorflam
Offline
Зарегистрирован: 09.09.2016

а если не париться с полусимволами, а сделать заполнение по принципу

uint8_t sumbol[8] = {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};

а шкалу сделать от координаты 0 до 9 а в конце при максимальных оборотах написать MAX

В моем примере обороты будут достигать 5000 об/мин, следовательно 1-500 - 1 символ полной заливки, 501-1000 - 2 сомвола полной заливки и так до 4501-5000... а если 5001 - то высвечивается MAX

поможешь код набросать, хотя бы начало с выводом первого символа... я с таким еще не сталкивался...

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, не знаю, Вы э спрашивали "как на видео", а на видео полусимволы тоже используются. там их чётко видно. А так, конечно, делайте как Вам нужно. 

Не, код я писать не буду. Помочь с Вашим могу, а сам писать не буду.

viktorflam
Offline
Зарегистрирован: 09.09.2016

Привет Евгений!

Помоги разобраться, правильно ли я двигаюсь. Вот рабочий скеч:

#include <Wire.h> 
#include <LiquidCrystal_I2C.h> 
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display 

unsigned long lastflash; 
int RPM; 

void setup() { 
Serial.begin(9600); //открыть порт 
attachInterrupt(0, sens, RISING); //подключить прерывание на 2 пин при повышении сигнала 
pinMode(3, OUTPUT); //3 пин как выход 
digitalWrite(3, HIGH); //подать 5 вольт на 3 пин 
lcd.init(); 
lcd.backlight(); 
} 
void sens() { 
RPM = 60 / ((float)(micros() - lastflash) / 1000000); //расчет 
lastflash = micros(); //запомнить время последнего оборота 
} 

void loop() { 
if ((micros() - lastflash) > 500000) { //если сигнала нет больше секунды 
RPM = 0; //считаем что RPM 0 
//lcd.init();
} 
//lcd.init(); 
//lcd.backlight();
lcd.noBlink(); 
lcd.setCursor(0, 0); 
//lcd.print("RPM: "); 
//lcd.print(RPM); 
//lcd.setCursor(10, 0); 
//lcd.print("ob/min"); 
char buffer[32];
sprintf(buffer, "RPM: %d ob/m.       ", RPM);
lcd.print(buffer);
delay(500); 
}

Теперь если я хочу сделать шкалу во втором ряду, пускай из символов "О" мне нужно сделать следущее:

1. в условии добавить еще одну переменную, например int RPM1

2. В void loop() добавить условие

if (RPM <= 500) RPM1 =  "O"; // Если RPM меньше или равно 500 то RPM1 присвоить "О"
if (RPM <= 1000) RPM1 =  "ОO"; // Если RPM меньше или равно 1000 то RPM1 присвоить "ОО"
if (RPM <= 1500) RPM1 =  "ООO"; // Если RPM меньше или равно 1000 то RPM1 присвоить "ООО"

...........

lcd.setCursor(0, 1); //поместить курсор на вторую строку, первую ячейку
lcd.print(RPM1); //вывести результат в ячейку

так будет правильно или есть какие-то другие решения??

или можно как то задействовать по этому примеру:

char buffer[32];
sprintf(buffer, "RPM: %d ob/m.       ", RPM);
lcd.print(buffer);

тогда как вывести результаты из условий IF и как можно задать координаты для lcd.print(buffer);????????

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

viktorflam пишет:

1. в условии добавить еще одну переменную, например int RPM1

2. В void loop() добавить условие

if (RPM <= 500) RPM1 =  "O"; // Если RPM меньше или равно 500 то RPM1 присвоить "О"
if (RPM <= 1000) RPM1 =  "ОO"; // Если RPM меньше или равно 1000 то RPM1 присвоить "ОО"
if (RPM <= 1500) RPM1 =  "ООO"; // Если RPM меньше или равно 1000 то RPM1 присвоить "ООО"

1. Для чего это?
2. Если описана как int, почему ей присваиваются строки?

viktorflam пишет:

lcd.setCursor(0, 1); //поместить курсор на вторую строку, первую ячейку
lcd.print(RPM1); //вывести результат в ячейку

так будет правильно или есть какие-то другие решения??

или можно как то задействовать по этому примеру:

char buffer[32];
sprintf(buffer, "RPM: %d ob/m.       ", RPM);
lcd.print(buffer);

тогда как вывести результаты из условий IF и как можно задать координаты для lcd.print(buffer);????????

Ну уоодринаты Вы правильно установили, а как их ещё устанваливать.

А в остальном я не понял что Вы вообще хотите сделать, не понял, а потому и не могу сказать что правильно, а что - нет

viktorflam
Offline
Зарегистрирован: 09.09.2016

Я хочу на второй строке дисплея сделать шкалу по следующим условиям:

Если RPM = от 0 до 500, то на дисплее горит первый символ (например "О")

Если RPM = от 501 до 1000, то на дисплее горит два символа (например "ОО")

Если RPM = от 1001 до 1500, то на дисплее горит три символа (например "ООО") 

и так далее, на пример до 5000

отсюда пишу условия:

if (RPM <= 500) RPM1 =  "O"; // Если RPM меньше или равно 500 то RPM1 присвоить "О"
if (RPM <= 1000) RPM1 =  "ОO"; // Если RPM меньше или равно 1000 то RPM1 присвоить "ОО"
if (RPM <= 1500) RPM1 =  "ООO"; // Если RPM меньше или равно 1000 то RPM1 присвоить "ООО"

а после вывожу результат на экран:

lcd.setCursor(0, 1); //поместить курсор на вторую строку, первую ячейку
lcd.print(RPM1); //вывести результат в ячейку

Я не знаю как это сдлать правильно, и примеров подобных не могу найти, по этому заново придумываю велосипед... из толпы, тут находящейся, только ты соглашаешся мне помогать, за что тебе отдельное спасибо!Ф

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Ну и зачем так сложно.

Чем так не лучше

lcd.setCursor(0, 1);
for (int i=0; i <= RPM /500; i++)
        lcd.print("0");

ПС: Хотя, может месье больше разбирается в извращениях

http://cxem.net/arduino/arduino67.php  может поможет

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вы не слушаете.

Вы описали RPM1 как int. А присваиваете ему строки. Вас это не смущает?

Даже если бы Вы описали правильно, всё равно, зачем так делать. Ну вот вывели Вы три буквы О, а потом обороты уменьшились. Вы выводите одну, а те две старые стирать Пушкин будет?

Далее, Вы подряд делаете проверки

if (RPM <= 500) RPM1 =  "O"; // Если RPM меньше или равно 500 то RPM1 присвоить "О"
if (RPM <= 1000) RPM1 =  "ОO"; // Если RPM меньше или равно 1000 то RPM1 присвоить "ОО"
if (RPM <= 1500) RPM1 =  "ООO"; // Если RPM меньше или равно 1000 то RPM1 присвоить "ООО"

Ну, допустим, она равна 200. Первое условие сработает. А второе? 200 <= 1000, тоже ведь сработает! А третье? И оно сработает! Т.е. даже если бы Вы всё сделали описание правильно, у Вас всегда бы показывалось три буквы О!

Если уж так делать, то во-первых правильно описать, а во-вторых стирать за собой не нужные O, а в третьих разделить условия!

char * RPM1;
if (RPM <= 500) RPM1  =  "O  "; // Если RPM меньше или равно 500 то RPM1 присвоить "О"
else if (RPM <= 1000) RPM1 =  "ОO "; // Если RPM меньше или равно 1000 то RPM1 присвоить "ОО"
else if (RPM <= 1500) RPM1 =  "ООO"; // Если RPM меньше или равно 1000 то RPM1 присвоить "ООО"

Видите, там пробелы. Они как раз для стирания.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone, ну, зачем Вы так? Человеку сложно с циклом, а Вы его мордой об стол!

Да и уж если пишете, тем более так высокомерно

qwone пишет:

lcd.setCursor(0, 1);
for (int i=0; i <= RPM /500; i++)
        lcd.print("0");

ПС: Хотя, может месье больше разбирается в извращениях

то может месье позаботится о том, чтобы детских ошибок не делать?

Например, старые нули в конце строки стирать, а то ведь единожды показав три нуля, она больше ничего и никогда у Вас не покажет!

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Код для тех кто пережил удары судьбы мордой об стол.

/*
#1 переменый резистор +5V -> +5V
                        R1-> A0     (R1_pin)
                      GND -> GND                       
#2 I2C LCD1602        GND -> GND
                      +5V -> +5V
                      SDA -> A4(SDA)
                      SCL -> A5(SCL)
*/
//#1
const int R1_pin = A0;
uint16_t R1_value = 0;
//#2
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // Устанавливаем дисплей
uint8_t sign_0[8] = {   0,   0,   0,   0,   0,   0,   0};
uint8_t sign_1[8] = {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10};
uint8_t sign_2[8] = {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18};
uint8_t sign_3[8] = {0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C};
uint8_t sign_4[8] = {0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E};
uint8_t sign_5[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};
const int R1_value_step = 1024 / 16; // максим величина на количество знакомест в LCD

void setup() {
  //#1

  //#2
  lcd.init()             ;
  lcd.backlight()        ; // Включаем подсветку дисплея
  lcd.createChar(0, sign_0);// создаем символ и записываем его в память LCD
  lcd.createChar(1, sign_1);
  lcd.createChar(2, sign_2);
  lcd.createChar(3, sign_3);
  lcd.createChar(4, sign_4);
  lcd.createChar(5, sign_5);
}

void loop() {
  static uint32_t MILLIS ;
  MILLIS = millis() ;
  //#1
  R1_value = analogRead(R1_pin);
  //#2
  static uint32_t future2 = 0 ;
  if (MILLIS >= future2) {
    future2 = MILLIS + 500 ;
    lcd.clear();
    lcd.print("Value:");
    lcd.print(R1_value);
    lcd.setCursor(0, 1);
    for (int i = 1; i <= R1_value / R1_value_step; i++)
      lcd.write(byte(5));
    lcd.write(byte(R1_value % R1_value_step)*5/R1_value_step);
  }
}

 

saftik
Offline
Зарегистрирован: 08.04.2015

ЕвгенийП
подскажите пожалуйсто
1)  а можно ли в одну строку засунуть две переменные sprintf(buffer, "время: %d ч   %d м  ", часы, минуты);

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

saftik пишет:

1)  а можно ли в одну строку засунуть две переменные sprintf(buffer, "время: %d ч   %d м  ", часы, минуты);

Сколько угодно, только следите за правильным количеством и правильными типами, т.к. сама она не в состоянии проверить и, если ошибётесь, то результат непредсказуем.

viktorflam
Offline
Зарегистрирован: 09.09.2016

Отличный пример, только в моем примере не переменный резистор, а датчик холла и подцеплен он на pin2 и работает по функции attachInterrupt (обработка внешних прирываний) как под него переделать условие и цикл я пока не знаю, не разбирался еще... у меня сейчас так работает:

#include <Wire.h> 
#include <LiquidCrystal_I2C.h> 
LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display 

unsigned long lastflash; 
int RPM; 
char * RPM1;

void setup() { 
Serial.begin(9600); //открыть порт 
attachInterrupt(0, sens, RISING); //подключить прерывание на 2 пин при повышении сигнала 
pinMode(3, OUTPUT); //3 пин как выход 
digitalWrite(3, HIGH); //подать 5 вольт на 3 пин 
lcd.init(); 
lcd.backlight(); 
} 
void sens() { 
RPM = 60 / ((float)(micros() - lastflash) / 1000000); //расчет 
lastflash = micros(); //запомнить время последнего оборота 
} 

void loop() { 
if ((micros() - lastflash) > 500000) { //если сигнала нет больше секунды 
RPM = 0; //считаем что RPM 0 
}
{
if (RPM == 0) RPM1  =  "_             "; // Если RPM равно 0 то RPM1 присвоить "_"
else if (RPM <= 600) RPM1 =  "#            "; // Если RPM меньше или равно 600 то RPM1 присвоить "#"
else if (RPM <= 1200) RPM1 =  "##            ";
else if (RPM <= 1800) RPM1 =  "###           "; 
else if (RPM <= 2400) RPM1 =  "####          ";
else if (RPM <= 3000) RPM1 =  "#####         ";
else if (RPM <= 3600) RPM1 =  "######        ";
else if (RPM <= 4200) RPM1 =  "#######       ";
else if (RPM <= 4800) RPM1 =  "########      ";
else if (RPM <= 5400) RPM1 =  "#########     ";
else if (RPM <= 6000) RPM1 =  "##########    ";
else if (RPM > 7000) RPM1 =  "########## MAX";

//lcd.init();
} 
//lcd.init(); 
//lcd.backlight();
lcd.noBlink(); 
lcd.setCursor(0, 0); 
//lcd.print("RPM: "); 
//lcd.print(RPM); 
//lcd.setCursor(10, 0); 
//lcd.print("ob/min"); 
char buffer[32];
sprintf(buffer, "RPM: %d ob/m.       ", RPM);
lcd.print(buffer);
lcd.setCursor(0, 1); 
lcd.print(RPM1); 
delay(500); 
}

поможешь сделать шкалу как в твоем примере?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/*
#1 датчик Холла    Ucc -> 3 (Ucc_pin)
                   Sens-> 2  (Sens_pin)
                   GND -> GND
#2 I2C LCD1602      GND -> GND
                    +5V -> +5V
                    SDA -> A4(SDA)
                    SCL -> A5(SCL)
*/
//#1
const int Ucc_pin = 3; // на питание датчика Холла
volatile unsigned long time;// период между засечками на датчике Холла
volatile unsigned long lastMicros = 0;// последний микрос
int RPM;// обороты в минуту
void sens() {   // функция в прерывании
  time = micros() - lastMicros;
  lastMicros = micros(); //запомнить время последнего оборота
}
//#2
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // Устанавливаем дисплей
uint8_t sign_0[8] = {   0,   0,   0,   0,   0,   0,   0};
uint8_t sign_1[8] = {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10};
uint8_t sign_2[8] = {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18};
uint8_t sign_3[8] = {0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C};
uint8_t sign_4[8] = {0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E};
uint8_t sign_5[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};
char buffer[32];// буфер вывода на экран
const int RPM_step = 7500 / 16; // максим величина на количество знакомест в LCD

void setup() {
  //#1
  attachInterrupt(0, sens, RISING); //подключить прерывание на 2 пин при повышении сигнала
  pinMode(Ucc_pin, OUTPUT); //3 пин как выход
  digitalWrite(Ucc_pin, 1); //подать 5 вольт на датчик Холла
  //#2
  lcd.init()             ;
  lcd.backlight()        ; // Включаем подсветку дисплея
  lcd.createChar(0, sign_0);// создаем символ и записываем его в память LCD
  lcd.createChar(1, sign_1);
  lcd.createChar(2, sign_2);
  lcd.createChar(3, sign_3);
  lcd.createChar(4, sign_4);
  lcd.createChar(5, sign_5);
}
void loop() {
  static uint32_t MILLIS ;
  MILLIS = millis() ;
  //#1
  //#2
  static uint32_t future2 = 0 ;
  if (MILLIS >= future2) {
    future2 = MILLIS + 500 ;
    if (time == 0) RPM = 0;
    else RPM = 60000000 / time;
    sprintf(buffer, "RPM: %d ob/m.       ", RPM);
    lcd.clear();
    lcd.print(buffer);
    lcd.setCursor(0, 1);
    for (int i = 1; i <= RPM / RPM_step; i++)
      lcd.write(byte(5));
    lcd.write(byte(RPM % RPM_step) * 5 / RPM_step);
  }
}

 

viktorflam
Offline
Зарегистрирован: 09.09.2016

Привет qwone!

твой скеч именно то, что мне нужно, работает очень круто! и главное, если надо изменить максимальные показания, достаточно изменить 1 строку и все работает... Я проверял на закрепить магнит на шкив жесикх дисков 7200 об/мин и на 5400 об/мин и на кулер 2100 об/мин - показывае идеално и шкала отображает отлично! ОГРОМНОЕ тебе спасибо!

Есть маленькое замечание, когда обороты идут на убывание (например на жестком диске), в момент остановки вала на дисплее остаются последние минимальные показания, т.е. дисплей не обнуляется. Как правило, в разные моменты на дисплее остается число от 80 до 120, и если снизить число в строке

const int RPM_step = 1600 / 16; // максим величина на количество знакомест в LCD

то шкала тоже остается на месте последнего показания...

вот эта строка раньше у меня работала

if ((micros() - lastflash) > 500000) { //если сигнала нет больше секунды 
RPM = 0; //считаем что RPM 0 

в общем не знаешь как сделать так, что бы счетчик обнулялся при простое более 1 секунды?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
    if (time == 0) RPM = 0; //<----- здесь обороты обнуляется если стоит .
    else RPM = 60000000 / time;
if (MILLIS >= future2) {
    future2 = MILLIS + 500 ;  <--- здесь идет обновление экрана раз в 0,500 сек.

Так что у меня идет как надо. Можете поменять 500 на 100 или да же на 50. Но просто я думаю что обновление раз в 0,5 сек это приемлемо 

ПС: if (time == 0) RPM = 0; можно заменить на if (time <= time_min) RPM = 0;

и выше const unsigned long time_min = 100;// некое значение при котором вал считать стоящим на месте.

viktorflam
Offline
Зарегистрирован: 09.09.2016

Привет! сколько не пробовал не обнуляются, во вложении  ссылка на видео https://vk.com/videos5613556?z=video5613556_456239020

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

попробуйте этот код

/*
#1 датчик Холла    Ucc -> 3 (Ucc_pin)
                   Sens-> 2  (Sens_pin)
                   GND -> GND
#2 I2C LCD1602      GND -> GND
                    +5V -> +5V
                    SDA -> A4(SDA)
                    SCL -> A5(SCL)
*/
//#1
const int Ucc_pin = 3; // на питание датчика Холла
volatile unsigned long time;// период между засечками на датчике Холла
volatile unsigned long lastMicros = 0;// последний микрос
int RPM;// обороты в минуту
void sens() {   // функция в прерывании
  time = micros() - lastMicros;
  lastMicros = micros(); //запомнить время последнего оборота
}
//#2
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // Устанавливаем дисплей
uint8_t sign_0[8] = {   0,    0,    0,    0,    0,    0,    0,    0};
uint8_t sign_1[8] = {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10};
uint8_t sign_2[8] = {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18};
uint8_t sign_3[8] = {0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C};
uint8_t sign_4[8] = {0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E};
uint8_t sign_5[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};

//uint8_t sign_0[8] = {   0,   0,   0,   0,     0,    0,    0,    0}; это если захочется сделать полоску поуже
//uint8_t sign_1[8] = {   0,   0,   0,   0,  0x10, 0x10, 0x10, 0x10};
//uint8_t sign_2[8] = {   0,   0,   0,   0,  0x18, 0x18, 0x18, 0x18};
//uint8_t sign_3[8] = {   0,   0,   0,   0,  0x1C, 0x1C, 0x1C, 0x1C};
//uint8_t sign_4[8] = {   0,   0,   0,   0,  0x1E, 0x1E, 0x1E, 0x1E};
//uint8_t sign_5[8] = {   0,   0,   0,   0,  0x1F, 0x1F, 0x1F, 0x1F};

char buffer[32];// буфер вывода на экран
const int RPM_step = 7500 / 16; // максим величина на количество знакомест в LCD
const unsigned long time_max=60000000/200  ;//  мин. обороты вала при которых счет идет с ошибкой 200об/мин
// попробуйте постепено уменьшать так 200-> 100-> 50 -> и так до ошибки

void setup() {
  //#1
  attachInterrupt(0, sens, RISING); //подключить прерывание на 2 пин при повышении сигнала
  pinMode(Ucc_pin, OUTPUT); //3 пин как выход
  digitalWrite(Ucc_pin, 1); //подать 5 вольт на датчик Холла
  //#2
  lcd.init()             ;
  lcd.backlight()        ; // Включаем подсветку дисплея
  lcd.createChar(0, sign_0);// создаем символ и записываем его в память LCD
  lcd.createChar(1, sign_1);
  lcd.createChar(2, sign_2);
  lcd.createChar(3, sign_3);
  lcd.createChar(4, sign_4);
  lcd.createChar(5, sign_5);
}
void loop() {
  static uint32_t MILLIS ;
  MILLIS = millis() ;
  //#1
  //#2
  static uint32_t future2 = 0 ;
  if (MILLIS >= future2) {
    future2 = MILLIS + 500 ;
    if (time > time_max) RPM = 0; // скорее надо было здесь сделать такое условие
    else RPM = 60000000 / time;
    sprintf(buffer, "RPM: %d ob/m.       ", RPM);
    lcd.clear();
    lcd.print(buffer);
    lcd.setCursor(0, 1);
    for (int i = 1; i <= RPM / RPM_step; i++)
      lcd.write(byte(5));
    lcd.write(byte(RPM % RPM_step) * 5 / RPM_step);
  }
}

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Вот еще вариаент


/*
#1 датчик Холла    Ucc -> 3 (Ucc_pin)
                   Sens-> 2  (Sens_pin)
                   GND -> GND
#2 I2C LCD1602      GND -> GND
                    +5V -> +5V
                    SDA -> A4(SDA)
                    SCL -> A5(SCL)
*/
//#1
const int Ucc_pin = 3; // на питание датчика Холла
volatile unsigned long time;// период между засечками на датчике Холла
volatile unsigned long lastMicros = 0;// последний микрос
int RPM;// обороты в минуту
volatile uint8_t flag_stop;// флажек если вал стоит
void sens() {   // функция в прерывании
  flag_stop = 0; // поднять флаг - оборот произошел
  time = micros() - lastMicros;
  lastMicros = micros(); //запомнить время последнего оборота
}
//#2
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // Устанавливаем дисплей
uint8_t sign_0[8] = {   0,    0,    0,    0,    0,    0,    0,    0};
uint8_t sign_1[8] = {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10};
uint8_t sign_2[8] = {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18};
uint8_t sign_3[8] = {0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C};
uint8_t sign_4[8] = {0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E};
uint8_t sign_5[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};

//uint8_t sign_0[8] = {   0,   0,   0,   0,     0,    0,    0,    0}; это если захочется сделать полоску поуже
//uint8_t sign_1[8] = {   0,   0,   0,   0,  0x10, 0x10, 0x10, 0x10};
//uint8_t sign_2[8] = {   0,   0,   0,   0,  0x18, 0x18, 0x18, 0x18};
//uint8_t sign_3[8] = {   0,   0,   0,   0,  0x1C, 0x1C, 0x1C, 0x1C};
//uint8_t sign_4[8] = {   0,   0,   0,   0,  0x1E, 0x1E, 0x1E, 0x1E};
//uint8_t sign_5[8] = {   0,   0,   0,   0,  0x1F, 0x1F, 0x1F, 0x1F};

char buffer[32];// буфер вывода на экран
const int RPM_step = 7500 / 16; // максим величина на количество знакомест в LCD
const unsigned long time_max = 60000000 / 200  ; //  мин. обороты вала при которых счет идет с ошибкой 200об/мин
// попробуйте постепено уменьшать так 200-> 100-> 50 -> и так до ошибки

void setup() {
  //#1
  attachInterrupt(0, sens, RISING); //подключить прерывание на 2 пин при повышении сигнала
  pinMode(Ucc_pin, OUTPUT); //3 пин как выход
  digitalWrite(Ucc_pin, 1); //подать 5 вольт на датчик Холла
  //#2
  lcd.init()             ;
  lcd.backlight()        ; // Включаем подсветку дисплея
  lcd.createChar(0, sign_0);// создаем символ и записываем его в память LCD
  lcd.createChar(1, sign_1);
  lcd.createChar(2, sign_2);
  lcd.createChar(3, sign_3);
  lcd.createChar(4, sign_4);
  lcd.createChar(5, sign_5);
}
void loop() {
  static uint32_t MILLIS ;
  MILLIS = millis() ;
  //#1
  //#2
  static uint32_t future2 = 0 ;
  if (MILLIS >= future2) {
    future2 = MILLIS + 500 ;
    if (!flag_stop) RPM = 0;
    else{
      if (time > time_max) RPM = 0; // скорее надо было здесь cделать такое условие
      else RPM = 60000000 / time;
    }
    sprintf(buffer, "RPM: %d ob/m.       ", RPM);
    lcd.clear();
    lcd.print(buffer);
    lcd.setCursor(0, 1);
    for (int i = 1; i <= RPM / RPM_step; i++)
      lcd.write(byte(5));
    lcd.write(byte(RPM % RPM_step) * 5 / RPM_step);
    flag_stop = 0;
  }
}
viktorflam
Offline
Зарегистрирован: 09.09.2016

Привет!

С последним вариантом вообще счетчик стоит на 0 и шкала не заполняется... решил остановиться на предпоследнем твоем примере, уменьшил в 

const unsigned long time_max=60000000/100

до 100. В принципе в моей задаче нужно было сделать "тахометр" для станка, с минимальными оборотами вращения вала 120 об/мин, максимальные значения 5000 об/минут. задачу мы решили, завтра поеду показывать...

еще вопрос: Как можно записать символ, который мы сделали в строке 

uint8_t sign_5[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};

в условие 

if (RPM == 0) RPM1  =  "#             ";
else if (RPM <= 200) RPM1 =  "##             "; 
else if (RPM <= 400) RPM1 =  "###            "; 

и вместо решоток вывести "полностью залитый символ" в строке 

lcd.setCursor(0, 1); 
lcd.print(RPM1); 

подскажешь? этот на тот случай, если попросят упросиить все... как бы препод намекнул, что сделать проще всего на простых условиях "если" и "иначе если"

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

viktorflam пишет:

подскажешь? этот на тот случай, если попросят упросиить все... как бы препод намекнул, что сделать проще всего на простых условиях "если" и "иначе если"

http://arduino.ua/ru/prog/LiquidCrystalCreateChar

viktorflam
Offline
Зарегистрирован: 09.09.2016

суть вопроса то ясна как выводить эти символы в статическом виде, но у меня данные динамические, короче я не смог разобраться... и раз я не смог разобраться с этим, он мне решил подкинуть задачку по сложнее

1. Надо в схему тахонемтра добавить 3 кнопки

- 1я кнопка вводит и выводит режим изменения максимальных измеряемых оборотов (в твоем примере const int RPM_step = 7500 / 16;)

- 2я кнопка увеличивает это число с шагом 20

- 3я кнопка уменьшает это число, так же с шагом 20

2. Реализовать данный функционал в среде разработки 

3. Продемонстрировать работу устройства и предоставить программный код.

...хз даже с чего начать, сталкивался хоть раз с таким?

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Смысл. Все равно не поймете. А значит не объясните. Тем более вывод на экран был статическим, но с обновлением раз 0,5 сек. Тем болле я пишу с своем стиле, а он отличается от  стиля "классических новичков в ардуине".

ПС: Может просто утонуть до "трояка"?

viktorflam
Offline
Зарегистрирован: 09.09.2016

а с кнопками поможешь? с меня мороженое;)

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

30-40 строк, но как будет работать не поймешь и не раскажешь.

viktorflam
Offline
Зарегистрирован: 09.09.2016

это тема следующего зачета, неделька в запасе есть что бы разобрать на символы код и понять как все работает, а вот что бы самому написать, боюсь не успею...

В любим случае тебе спасибо! Помог очень мне!

П.С. хочешь, скинь на мыло номер телефона или что-нить типа яндекс.деньги, закину тебе пару соток "на мароженку", как обещал... viktorflam@gmail.com

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015
viktorflam пишет:
с меня пиво мороженое
 
Видимо, начало ника - сокращение от "Виктория"?
 
viktorflam пишет:
а с кнопками поможешь? ... это тема следующего зачета
 
Если не трудно, объясните пожалуйста, Вот Вы точно уверены, что Вам это в жизни никогда не пригодяится? Или ... почему? Никогда не возникало мысли чему-нибудь действительно научиться, а не просто обмануть преподавателя? Главное - смысл его обманывать? Кому хуже-то?
 
viktorflam
Offline
Зарегистрирован: 09.09.2016

Привет Евгений!

В нике целое имя, последние 4 буквы приставка...

Мне в жизни это очень пригодиться, по этому я тут прошу помощи и хочу сам научиться. Я не прошу предоставить мне конкретный код, а показать примеры и на примерах доработать так как требуют от меня. qwone мне помогает конкретными примерами и за это мне не жалко ему закинуть пару соток, а уж что он там себе купит его дело (пЫво или мороженое).

если бы я не хотел заморачиваться и разбираться как все работает, давно бы заказал кому-ниботь за деньги, сдал бы работу и не парился... но мне самому интересно... Препод понимает, что меня этот вопрос тоже интересует, по этому и усложняет задания. Остальным сокурсникам по барабану это все, они купили готовый набор с залитым скечем и сдали...

Отвечая на Ваш вопрос (Никогда не возникало мысли чему-нибудь действительно научиться...), хочу сказать, что такая мысль возникла очень давно, тема электроники мне очень интересна, но на данный момент одновременно учиться и рабоать достаточно тяжело, и дома маленький ребенок отнимает все свободное время... Вот по этому приходится изучать все мелкими шажками, по немногу, когда есть свободное время... а его почти нет.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/*
#1 датчик Холла    Ucc ->  Ucc   можно на прямую к +5В подключить
                   Sens-> 2  (Sens_pin)
                   GND -> GND
#2 I2C LCD1602      GND -> GND
                    +5V -> +5V
                    SDA -> A4(SDA)
                    SCL -> A5(SCL)
#3 кнопка 1            -> 3 (Btn1_pin) 0-нажата/ 1 нет  кнопка Select показ редактирование
                   GND -> GND
   кнопка 2            -> 4 (Btn2_pin) + 20
                   GND -> GND
   кнопка 3            -> 5 (Btn3_pin)  -20
                   GND -> GND

*/
//#1
volatile unsigned long count;// счетчик оборотов
uint16_t RPM = 0; // обороты в минуту
uint16_t RPM_max  = 7500;// максим величина оборотов которые можно отобразить.
uint16_t RPM_max_min  = 1000;// максим величина оборотов до которых можно опустится.

void sens() {   // функция в прерывании
  count++;
}
//#2 дисплей
const int time_update2 = 500; // обновление дисплея в миллисекундах
uint8_t mode_edit = 0; // установка режимов отображение 0 показавать обороты/ 1 показывать какие максим обороты можно поставить
uint16_t RPM_step = RPM_max / 16; // максим величина на количество знакомест в LCD
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // Устанавливаем дисплей
uint8_t sign_0[8] = {   0,    0,    0,    0,    0,    0,    0};
uint8_t sign_1[8] = {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10};
uint8_t sign_2[8] = {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18};
uint8_t sign_3[8] = {0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C};
uint8_t sign_4[8] = {0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E};
uint8_t sign_5[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};

//#3 кнопки
const int Btn1_pin = 3; // пин ноги кнопка 1
uint8_t   Btn1, Btn1_old; // состояние кнопики новое и старое
const int Btn2_pin = 4; // пин ноги кнопка 2
uint8_t   Btn2, Btn2_old; // состояние кнопики новое и старое
const int Btn3_pin = 5; // пин ноги кнопка 3
uint8_t   Btn3, Btn3_old; // состояние кнопики новое и старое


void setup() {
  //#1
  attachInterrupt(0, sens, RISING); //подключить прерывание на 2 пин при повышении сигнала
  //#2
  lcd.init()             ;
  lcd.backlight()        ; // Включаем подсветку дисплея
  lcd.createChar(0, sign_0);// создаем символ и записываем его в память LCD
  lcd.createChar(1, sign_1);
  lcd.createChar(2, sign_2);
  lcd.createChar(3, sign_3);
  lcd.createChar(4, sign_4);
  lcd.createChar(5, sign_5);
  //#3
  pinMode(Btn1_pin, INPUT_PULLUP); //инициализировать кнопку 1
  pinMode(Btn2_pin, INPUT_PULLUP); //инициализировать кнопку 2
  pinMode(Btn3_pin, INPUT_PULLUP); //инициализировать кнопку 3
}
void loop() {
  static uint32_t MILLIS ;
  MILLIS = millis() ;
  //#1
  //#2 0,500 секунды дисплей
  static uint32_t future2 = 0 ;
  if (MILLIS >= future2) {
    future2 = MILLIS + time_update2 ;
    RPM = count * 60000 / time_update2; // обороты в минуту
    count = 0; //сбросить счетчик
    lcd.clear();
    switch (mode_edit) {
      case 0:
        lcd.print("RPM: ");
        lcd.print(RPM);
        lcd.print("  ob/m.");
        lcd.setCursor(0, 1);
        for (int i = 1; i <= RPM / RPM_step; i++)
          lcd.write(byte(5));
        lcd.write(byte(RPM % RPM_step) * 5 / RPM_step);
        break;
      case 1:  
        lcd.print("Edit ");
        lcd.setCursor(0, 1);
        lcd.print("RPM_max ");
        lcd.print(RPM_max);
        lcd.print("  ob/m.");
        break;
    }
  }
  //#3 0,200 секунды кнопки
  static uint32_t future3 = 0 ;
  if (MILLIS >= future3) {
    future3 = MILLIS + 200 ;
    Btn1_old = Btn1;
    Btn1 = digitalRead(Btn1_pin);
    Btn2_old = Btn2;
    Btn2 = digitalRead(Btn2_pin);
    Btn3_old = Btn3;
    Btn1 = digitalRead(Btn3_pin);
    if (Btn1_old && ! Btn1) { // если нажата кнопка select старое состояние 1 новое состояние 0, значит кнопка нажата только что
      mode_edit = !mode_edit;
    }
    if (mode_edit && Btn2_old && ! Btn2) { // если нажата кнопка +20 в режиме редактирования
      RPM_max  = RPM_max + 20;
      uint16_t RPM_step = RPM_max / 16;
    }
    if (mode_edit && Btn3_old && ! Btn3) { // если нажата кнопка -20 в режиме редактирования
      RPM_max  = RPM_max - 20;
      if (RPM_max < RPM_max_min ) RPM_max = RPM_max_min ;
      uint16_t RPM_step = RPM_max / 16;
    }
  }
}

 

viktorflam
Offline
Зарегистрирован: 09.09.2016

Привет!

Начал пробовать скеч и с самого начала что-то пошло не так:

по нажатию Btn1 никуда не попадаю

по нажатию Btn3 попадаю в режим Edit

в режиме Edit могу только повышать значение, понижать не могу...

пол дня разбирал скеч, меня кнопки местами, потом менял в коде все равно одно и тоже, пока не стал читать по строчно весь код и нашел опечатку в строке 105:

Btn1 = digitalRead(Btn3_pin);

Все, думаю про себя, щя заработает... заливаю скеч, кнопки жмутся, значения увеличиваются и уменьшаются, все круто!!! Нооооооооооо...

Шкала почему-то остается привязанной к значению из строки 20

uint16_t RPM_max  = 7500;// максим величина оборотов которые можно отобразить.

То есть, сколько бы я не выставлял в режиме Edit, шкала все равно зависит от uint16_t RPM_max  = 7500;

...

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

пересмотрел код. Вот новый 

/*
#1 датчик Холла    Ucc ->  Ucc   можно на прямую к +5В подключить
                   Sens-> 2  (Sens_pin)
                   GND -> GND
#2 I2C LCD1602      GND -> GND
                    +5V -> +5V
                    SDA -> A4(SDA)
                    SCL -> A5(SCL)
#3 кнопка 1            -> 3 (Btn1_pin) 0-нажата/ 1 нет  кнопка Select показ редактирование
                   GND -> GND
   кнопка 2            -> 4 (Btn2_pin) + 20
                   GND -> GND
   кнопка 3            -> 5 (Btn3_pin)  -20
                   GND -> GND

*/
//#1
volatile unsigned long count;// счетчик оборотов
unsigned long RPM = 0; // обороты в минуту
unsigned long RPM_max  = 7500;// максим величина оборотов которые можно отобразить.
uint16_t RPM_max_min  = 1000;// максим величина оборотов до которых можно опустится.

void sens() {   // функция в прерывании
  count++;
}
//#2 дисплей
const int time_update2 = 500; // обновление дисплея в миллисекундах
uint8_t mode_edit = 0; // установка режимов отображение 0 показавать обороты/ 1 показывать какие максим обороты можно поставить
uint16_t RPM_step = RPM_max / 16; // максим величина на количество знакомест в LCD
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2); // Устанавливаем дисплей
uint8_t sign_0[8] = {   0,    0,    0,    0,    0,    0,    0};
uint8_t sign_1[8] = {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10};
uint8_t sign_2[8] = {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18};
uint8_t sign_3[8] = {0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C};
uint8_t sign_4[8] = {0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E};
uint8_t sign_5[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};

//#3 кнопки
const int Btn1_pin = 3; // пин ноги кнопка 1
uint8_t   Btn1, Btn1_old; // состояние кнопики новое и старое
const int Btn2_pin = 4; // пин ноги кнопка 2
uint8_t   Btn2, Btn2_old; // состояние кнопики новое и старое
const int Btn3_pin = 5; // пин ноги кнопка 3
uint8_t   Btn3, Btn3_old; // состояние кнопики новое и старое


void setup() {
  //#1
  attachInterrupt(0, sens, RISING); //подключить прерывание на 2 пин при повышении сигнала
  //#2
  lcd.init()             ;
  lcd.backlight()        ; // Включаем подсветку дисплея
  lcd.createChar(0, sign_0);// создаем символ и записываем его в память LCD
  lcd.createChar(1, sign_1);
  lcd.createChar(2, sign_2);
  lcd.createChar(3, sign_3);
  lcd.createChar(4, sign_4);
  lcd.createChar(5, sign_5);
  //#3
  pinMode(Btn1_pin, INPUT_PULLUP); //инициализировать кнопку 1
  Btn1 = digitalRead(Btn1_pin);
  pinMode(Btn2_pin, INPUT_PULLUP); //инициализировать кнопку 2
  Btn2 = digitalRead(Btn2_pin);
  pinMode(Btn3_pin, INPUT_PULLUP); //инициализировать кнопку 3
  Btn3 = digitalRead(Btn3_pin);
}
void loop() {
  static uint32_t MILLIS ;
  MILLIS = millis() ;
  //#1
  //#2 0,500 секунды дисплей
  static uint32_t future2 = 0 ;
  if (MILLIS >= future2) {
    future2 = MILLIS + time_update2 ;
    RPM = (unsigned long)count * 60000 / time_update2; // обороты в минуту
    count = 0; //сбросить счетчик
    lcd.clear();
    switch (mode_edit) {
      case 0:
        lcd.print("RPM: ");
        lcd.print(RPM);
        lcd.print("  ob/m.");
        lcd.setCursor(0, 1);
        for (int i = 1; i <= RPM / RPM_step; i++)
          lcd.write(byte(5));
        lcd.write(byte(RPM % RPM_step) * 5 / RPM_step);
        break;
      case 1:  
        lcd.print("Edit RPMmax");
        lcd.setCursor(0, 1);
        lcd.print(RPM_max);
        lcd.print(" ob/m");
        break;
    }
  }
  //#3 0,200 секунды кнопки
  static uint32_t future3 = 0 ;
  if (MILLIS >= future3) {
    future3 = MILLIS + 200 ;
    Btn1_old = Btn1;
    Btn1 = digitalRead(Btn1_pin);
    Btn2_old = Btn2;
    Btn2 = digitalRead(Btn2_pin);
    Btn3_old = Btn3;
    Btn3 = digitalRead(Btn3_pin);
    if (Btn1_old && ! Btn1) { // если нажата кнопка select старое состояние 1 новое состояние 0, значит кнопка нажата только что
      mode_edit = !mode_edit;
    }
    if (mode_edit && Btn2_old && ! Btn2) { // если нажата кнопка +20 в режиме редактирования
      RPM_max  = RPM_max + 20;
      RPM_step = RPM_max / 16;
    }
    if (mode_edit && Btn3_old && ! Btn3) { // если нажата кнопка -20 в режиме редактирования
      RPM_max  = RPM_max - 20;
      if (RPM_max < RPM_max_min ) RPM_max = RPM_max_min ;
      RPM_step = RPM_max / 16;
    }
  }
}

ПС: Для того что бы был рабочий код, надо его не только залить , но и оттестировать. Вот я не сделал это. Как результат.

1 замечание 

    111  uint16_t RPM_step = RPM_max / 16;    uint16_t лишнее . Это объявление новой переменной RPM_step. А вот старая RPM_step не меняется. А эта переменая как раз маштабирует шкалу.

 074 RPM = count * 60000 / time_update2; // обороты в минуту

В RPM размерность 16 бит (uint16_t)

Поэтому я заменил на эту строку RPM = (unsigned long)count * 60000 / time_update2; // обороты в минуту

и unsigned long RPM = 0; то есть сейчас разряность RPM = 32 бита.

ПС. Что бы менять величину надо челкать на кнопку. Долгое удержание ничего не даст.

viktorflam
Offline
Зарегистрирован: 09.09.2016

С этим я разобрался!

Теперь я хочу вместо кнопок поставить потенциометр, только который не фиксированный и с нажатием (типа как колесик на мышке), что бы можно были по нажатию перейти в режим редактирования, а поворотами влево и вправо менять значение для шкалы, но это я уже сам, сначало надо найти такой потенциометр, короче как сделаю - расскажу!

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Так энкодер подойдет . Например такой https://goo.gl/iVP1Kv

Кнопка это SELECT, а повороты по часовой + , против -

viktorflam
Offline
Зарегистрирован: 09.09.2016

Ага, то, что надо!

Уже заказал!

Работу сдал, рассказал как все работает на примере скеча, результать Отлично!

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Поздравляю.

oleg39
Offline
Зарегистрирован: 13.08.2017
#include <Wire.h> 
#include <LiquidCrystal_I2C.h> 
LiquidCrystal_I2C lcd(0x3f, 16, 2); // set the LCD address to 0x3f for a 16 chars and 2 line display 
 
   byte Ioooo                    [8]  = { 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000, 0b10000 };       //       |****
   byte IIooo                    [8]  = { 0b11000, 0b11000, 0b11000, 0b11000, 0b11000, 0b11000, 0b11000, 0b11000 };       //       ||***
   byte IIIoo                    [8]  = { 0b11100, 0b11100, 0b11100, 0b00100, 0b11100, 0b11100, 0b11100, 0b11100 };       //       |||**
   byte IIIIo                    [8]  = { 0b11110, 0b11110, 0b11110, 0b11110, 0b11110, 0b11110, 0b11110, 0b11110 };       //       ||||*
   byte IIIII                    [8]  = { 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111 };      //        |||||
 
 
 
unsigned long lastflash; 
int RPM; 
char * RPM1;
 
void setup() { 
Serial.begin(9600);                                                   //открыть порт 
attachInterrupt(0, sens, RISING);                                     //подключить прерывание на 2 пин при повышении сигнала 
pinMode(3, OUTPUT);                                                   //3 пин как выход 
digitalWrite(3, HIGH);                                               //подать 5 вольт на 3 пин 
lcd.init(); 
lcd.backlight(); 
 
lcd.createChar(1, Ioooo); 
lcd.createChar(2, IIooo); 
lcd.createChar(3, IIIoo); 
lcd.createChar(4, IIIIo); 
lcd.createChar(5, IIIII); 
void sens() { 
RPM = 60 / ((float)(micros() - lastflash) / 1000000);                 //расчет 
lastflash = micros(); //запомнить время последнего оборота 
 
void loop() { 
if ((micros() - lastflash) > 5000000) {                                //если сигнала нет больше секунды 
RPM = 0;                                                              //считаем что RPM 0 
}
 
//lcd.init(); 
//lcd.backlight();
lcd.noBlink(); 
lcd.setCursor(0, 0); 
//lcd.print("RPM: "); 
//lcd.print(RPM); 
//lcd.setCursor(10, 0); 
//lcd.print("ob/min"); 
char buffer[32];
sprintf(buffer, "RPM: %d ob/m.       ", RPM);
lcd.print(buffer);
 
 
 
lcd.setCursor(0, 1);
 
 if (RPM  ==   0)                {lcd.print                   ("_               ");}    
 
 if (RPM  >  0 && RPM <=    50) {lcd.print(char(1));lcd.print("                ");}    
 if (RPM  >  50&& RPM  <=   100) {lcd.print(char(2));lcd.print("                ");}    
 if (RPM  > 100&& RPM  <=   150) {lcd.print(char(3));lcd.print("                ");}    
 if (RPM  > 150&& RPM  <=   200) {lcd.print(char(4));lcd.print("                ");}    
 if (RPM  > 200&& RPM  <=   250) {lcd.print(char(5));lcd.print("                ");} 
 
 if (RPM  > 250&& RPM  <=   300) {lcd.print(char(5));lcd.print(char(1));lcd.print("                ");}    
 if (RPM  > 300&& RPM  <=   350) {lcd.print(char(5));lcd.print(char(2));lcd.print("                ");}    
 if (RPM  > 350&& RPM  <=   400) {lcd.print(char(5));lcd.print(char(3));lcd.print("                ");}    
 if (RPM  > 400&& RPM  <=   450) {lcd.print(char(5));lcd.print(char(4));lcd.print("                ");}    
 if (RPM  > 450&& RPM  <=   500) {lcd.print(char(5));lcd.print(char(5));lcd.print("                ");} 
 
 if (RPM  > 500&& RPM  <=   550) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(1));lcd.print("                ");}    
 if (RPM  > 550&& RPM  <=   600) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(2));lcd.print("                ");}    
 if (RPM  > 600&& RPM  <=   650) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(3));lcd.print("                ");}    
 if (RPM  > 650&& RPM  <=   700) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(4));lcd.print("                ");}    
 if (RPM  > 700&& RPM  <=   750) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print("                ");} 
 
 if (RPM  > 750&& RPM  <=    800) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(1));lcd.print("                ");}    
 if (RPM  > 800&& RPM  <=    850) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(2));lcd.print("                ");}    
 if (RPM  > 850&& RPM  <=    900) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(3));lcd.print("                ");}    
 if (RPM  > 900&& RPM  <=    950) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(4));lcd.print("                ");}    
 if (RPM  > 950&& RPM  <=  1000) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print("                ");} 
 
 if (RPM  > 1000&& RPM  <=   1050) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(1));lcd.print("                ");}    
 if (RPM  > 1050&& RPM  <=   1100) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(2));lcd.print("                ");}    
 if (RPM  > 1100&& RPM  <=   1150) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(3));lcd.print("                ");}    
 if (RPM  > 1150&& RPM  <=   1200) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(4));lcd.print("                ");}    
 if (RPM  > 1200&& RPM  <=   1250) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print("                ");} 
 
 if (RPM  > 1250&& RPM  <=   1300) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(1));lcd.print("                ");}    
 if (RPM  > 1300&& RPM  <=   1350) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(2));lcd.print("                ");}    
 if (RPM  > 1350&& RPM  <=   1400) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(3));lcd.print("                ");}    
 if (RPM  > 1400&& RPM  <=   1450) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(4));lcd.print("                ");}    
 if (RPM  > 1450&& RPM  <=   1500) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print("                ");} 
 
 if (RPM  > 1500&& RPM  <=   1550) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(1));lcd.print("                ");}    
 if (RPM  > 1550&& RPM  <=   1600) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(2));lcd.print("                ");}    
 if (RPM  > 1600&& RPM  <=   1650) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(3));lcd.print("                ");}    
 if (RPM  > 1650&& RPM  <=   1700) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(4));lcd.print("                ");}    
 if (RPM  > 1700&& RPM  <=   1750) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print("                ");} 
 
 if (RPM  > 1750&& RPM  <=   1800) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(1));lcd.print("                ");}    
 if (RPM  > 1800&& RPM  <=   1850) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(2));lcd.print("                ");}    
 if (RPM  > 1850&& RPM  <=   1900) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(3));lcd.print("                ");}    
 if (RPM  > 1900&& RPM  <=   1950) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(4));lcd.print("                ");}    
 if (RPM  > 1950&& RPM  <=   2000) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print("                ");} 
 
 if (RPM  > 2000&& RPM  <=   2050) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(1));lcd.print("                ");}    
 if (RPM  > 2050&& RPM  <=   2100) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(2));lcd.print("                ");}    
 if (RPM  > 2100&& RPM  <=   2150) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(3));lcd.print("                ");}    
 if (RPM  > 2150&& RPM  <=   2200) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(4));lcd.print("                ");}    
 if (RPM  > 2200&& RPM  <=   2250) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print("                ");}  
 
 if (RPM  > 2250&& RPM  <=   2300) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(1));lcd.print("                ");}    
 if (RPM  > 2300&& RPM  <=   2350) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(2));lcd.print("                ");}    
 if (RPM  > 2350&& RPM  <=   2400) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(3));lcd.print("                ");}    
 if (RPM  > 2400&& RPM  <=   2450) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(4));lcd.print("                ");}    
 if (RPM  > 2450&& RPM  <=   2500) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print("                ");}  
 
 if (RPM  > 2500&& RPM  <=   2550) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(1));lcd.print("                ");}    
 if (RPM  > 2550&& RPM  <=   2600) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(2));lcd.print("                ");}    
 if (RPM  > 2600&& RPM  <=   2650) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(3));lcd.print("                ");}    
 if (RPM  > 2650&& RPM  <=   2700) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(4));lcd.print("                ");}    
 if (RPM  > 2700&& RPM  <=   2750) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print("                ");}
 
 if (RPM  > 2750&& RPM  <=   2800) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(1));lcd.print("                ");}    
 if (RPM  > 2800&& RPM  <=   2850) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(2));lcd.print("                ");}    
 if (RPM  > 2850&& RPM  <=   2900) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(3));lcd.print("                ");}    
 if (RPM  > 2900&& RPM  <=   2950) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(4));lcd.print("                ");}    
 if (RPM  > 2950&& RPM  <=   3000) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print("                ");}
 
 if (RPM  > 3000&& RPM  <=   3050) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(1));lcd.print("                ");}    
 if (RPM  > 3050&& RPM  <=   3100) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(2));lcd.print("                ");}    
 if (RPM  > 3100&& RPM  <=   3150) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(3));lcd.print("                ");}    
 if (RPM  > 3150&& RPM  <=   3200) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(4));lcd.print("                ");}    
 if (RPM  > 3200&& RPM  <=   3250) {lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print(char(5));lcd.print("                ");}
 
 
delay(500); 
}
 
 
//                  lcd.print(char(5));
 
 
/*
 
{
         if (RPM ==     0)   RPM1 =  "                ";                   // Если RPM равно 0 то RPM1 присвоить "#"
else if (RPM <= 600)   RPM1 =  "X#              ";
else if (RPM <= 900)   RPM1 =  "X##             "; 
else if (RPM <= 1200) RPM1 =  "X###            ";
else if (RPM <= 1500) RPM1 =  "X####           ";
else if (RPM <= 1800) RPM1 =  "X#####          ";
else if (RPM <= 2100) RPM1 =  "X######         ";
else if (RPM <= 2400) RPM1 =  "X#######        ";
else if (RPM <= 2700) RPM1 =  "X########       ";
else if (RPM <= 3000) RPM1 =  "X#########      ";
else if (RPM <= 3300) RPM1 =  "X##########     ";
else if (RPM <= 3600) RPM1 =  "X###########    ";
else if (RPM <= 3900) RPM1 =  "X############   ";
else if (RPM <= 4200) RPM1 =  "X#############  ";
else if (RPM >= 4500) RPM1 =  "X###########MAX ";
 
*/
 
 
 
 На пределе но работает.
 
 
 
DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

нахрена этот авнакод здесь?

oleg39
Offline
Зарегистрирован: 13.08.2017

Занимаюсь пол года а тахометр нужен для дела.Быстрее железку в космос забросить чем научиться библиотеки создовать.

nik182
Offline
Зарегистрирован: 04.05.2015

Зачем создавать библиотеки? Можно просто всё написать прямо. Мне почему то редко удается использовать чужие библиотеки без правок или добавлений.

viktorflam
Offline
Зарегистрирован: 09.09.2016

Не, мне мой вариант больше нравится! Тем более я к нему прикрутил шкалу, и кстати, очень полезно! С далека цифры не видно, а по шкале понятно приблизительно какая скорость.

viktorflam
Offline
Зарегистрирован: 09.09.2016

А чем тебе мой вариант не нравится? там всего 2 стандартные библиотеки, и их достаточно для полноценного функционирования, и все предельно просто и наглядно!