Тахометр на arduino pro mini от датчика холла на LCD1602+I2C
- Войдите на сайт для отправки комментариев
Добрый день господа и дамы!
тема затерта до дыр но тем не менее есть несколько моментов, в которых не могу найти ответа и разобраться сам. Собственно схема довольно простая: датчик Холла передает сигнал на ардуину, та в свою очередь обрабатывает аппаратные прерывания и выдает результат на дисплей и дисплей благополучно отображает данные, но сами данные на дисплее отображаются не совсем корректно, в частности в процессе уменьшения значения с 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
Подскажите, как можно добиться того, что бы данные на дисплее отображались корректно?
Вместо строк 28-31 просто пишете
Немного туповато, но работать будет.
При этом надпись "ob/min" будет ходить вправо-влево, в зависимости от количества знаков в числе оборотов.
Если надо, чтобы она стояла на месте (тогда её можно один раз написать и не трогать), тогда скажите максимальную ширину числа (сколько знаков) и куда его выравнивать - влево или вправо.
а ларчик то просто открывался))) Спасибо уважаемый!
А может ты в курсе как снизу сделать шкалу, которая заполняется в зависимости оборотов??? что-то типа процесс-бара, как на этом видео https://www.youtube.com/watch?v=bs8tzhyimhw&index=4&list=LLAMNJYOU9Q8BAVDivgSktuQ
Ну, там в шрифте должны быть символы "полузакрашенное слева знакоместо" и "закрашенное полностью знакоместо". Вот этими миволами и рисовать. Т.е. это просто "буквы такие". Ну составляйте строку из таких букв и рисуйте.
Строка делается таким образом:
Во время разработки
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
а если не париться с полусимволами, а сделать заполнение по принципу
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
поможешь код набросать, хотя бы начало с выводом первого символа... я с таким еще не сталкивался...
Ну, не знаю, Вы э спрашивали "как на видео", а на видео полусимволы тоже используются. там их чётко видно. А так, конечно, делайте как Вам нужно.
Не, код я писать не буду. Помочь с Вашим могу, а сам писать не буду.
Привет Евгений!
Помоги разобраться, правильно ли я двигаюсь. Вот рабочий скеч:
#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 и как можно задать координаты для lcd.print(buffer);????????
1. в условии добавить еще одну переменную, например int RPM1
2. В void loop() добавить условие
1. Для чего это?
2. Если описана как int, почему ей присваиваются строки?
так будет правильно или есть какие-то другие решения??
или можно как то задействовать по этому примеру:
тогда как вывести результаты из условий IF и как можно задать координаты для lcd.print(buffer);????????
Ну уоодринаты Вы правильно установили, а как их ещё устанваливать.
А в остальном я не понял что Вы вообще хотите сделать, не понял, а потому и не могу сказать что правильно, а что - нет
Я хочу на второй строке дисплея сделать шкалу по следующим условиям:
Если RPM = от 0 до 500, то на дисплее горит первый символ (например "О")
Если RPM = от 501 до 1000, то на дисплее горит два символа (например "ОО")
Если RPM = от 1001 до 1500, то на дисплее горит три символа (например "ООО")
и так далее, на пример до 5000
отсюда пишу условия:
а после вывожу результат на экран:
Я не знаю как это сдлать правильно, и примеров подобных не могу найти, по этому заново придумываю велосипед... из толпы, тут находящейся, только ты соглашаешся мне помогать, за что тебе отдельное спасибо!Ф
Ну и зачем так сложно.
Чем так не лучше
lcd.setCursor(0, 1); for (int i=0; i <= RPM /500; i++) lcd.print("0");ПС: Хотя, может месье больше разбирается в извращениях
http://cxem.net/arduino/arduino67.php может поможет
Вы не слушаете.
Вы описали RPM1 как int. А присваиваете ему строки. Вас это не смущает?
Даже если бы Вы описали правильно, всё равно, зачем так делать. Ну вот вывели Вы три буквы О, а потом обороты уменьшились. Вы выводите одну, а те две старые стирать Пушкин будет?
Далее, Вы подряд делаете проверки
Ну, допустим, она равна 200. Первое условие сработает. А второе? 200 <= 1000, тоже ведь сработает! А третье? И оно сработает! Т.е. даже если бы Вы всё сделали описание правильно, у Вас всегда бы показывалось три буквы О!
Если уж так делать, то во-первых правильно описать, а во-вторых стирать за собой не нужные O, а в третьих разделить условия!
Видите, там пробелы. Они как раз для стирания.
qwone, ну, зачем Вы так? Человеку сложно с циклом, а Вы его мордой об стол!
Да и уж если пишете, тем более так высокомерно
lcd.setCursor(0, 1); for (int i=0; i <= RPM /500; i++) lcd.print("0");ПС: Хотя, может месье больше разбирается в извращениях
то может месье позаботится о том, чтобы детских ошибок не делать?
Например, старые нули в конце строки стирать, а то ведь единожды показав три нуля, она больше ничего и никогда у Вас не покажет!
Код для тех кто пережил удары судьбы мордой об стол.
/* #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); } }ЕвгенийП
подскажите пожалуйсто
1) а можно ли в одну строку засунуть две переменные
sprintf(buffer,"время: %d ч%d м", часы, минуты);1) а можно ли в одну строку засунуть две переменные
sprintf(buffer,"время: %d ч%d м", часы, минуты);Сколько угодно, только следите за правильным количеством и правильными типами, т.к. сама она не в состоянии проверить и, если ошибётесь, то результат непредсказуем.
Отличный пример, только в моем примере не переменный резистор, а датчик холла и подцеплен он на 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); }поможешь сделать шкалу как в твоем примере?
/* #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); } }Привет qwone!
твой скеч именно то, что мне нужно, работает очень круто! и главное, если надо изменить максимальные показания, достаточно изменить 1 строку и все работает... Я проверял на закрепить магнит на шкив жесикх дисков 7200 об/мин и на 5400 об/мин и на кулер 2100 об/мин - показывае идеално и шкала отображает отлично! ОГРОМНОЕ тебе спасибо!
Есть маленькое замечание, когда обороты идут на убывание (например на жестком диске), в момент остановки вала на дисплее остаются последние минимальные показания, т.е. дисплей не обнуляется. Как правило, в разные моменты на дисплее остается число от 80 до 120, и если снизить число в строке
то шкала тоже остается на месте последнего показания...
вот эта строка раньше у меня работала
if ((micros() - lastflash) > 500000) { //если сигнала нет больше секунды RPM = 0; //считаем что RPM 0в общем не знаешь как сделать так, что бы счетчик обнулялся при простое более 1 секунды?
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
unsignedlongtime_min = 100;// некое значение при котором вал считать стоящим на месте.Привет! сколько не пробовал не обнуляются, во вложении ссылка на видео https://vk.com/videos5613556?z=video5613556_456239020
попробуйте этот код
/* #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); } }Вот еще вариаент
/* #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; } }Привет!
С последним вариантом вообще счетчик стоит на 0 и шкала не заполняется... решил остановиться на предпоследнем твоем примере, уменьшил в
до 100. В принципе в моей задаче нужно было сделать "тахометр" для станка, с минимальными оборотами вращения вала 120 об/мин, максимальные значения 5000 об/минут. задачу мы решили, завтра поеду показывать...
еще вопрос: Как можно записать символ, который мы сделали в строке
uint8_t sign_5[8] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};в условие
и вместо решоток вывести "полностью залитый символ" в строке
подскажешь? этот на тот случай, если попросят упросиить все... как бы препод намекнул, что сделать проще всего на простых условиях "если" и "иначе если"
подскажешь? этот на тот случай, если попросят упросиить все... как бы препод намекнул, что сделать проще всего на простых условиях "если" и "иначе если"
http://arduino.ua/ru/prog/LiquidCrystalCreateChar
суть вопроса то ясна как выводить эти символы в статическом виде, но у меня данные динамические, короче я не смог разобраться... и раз я не смог разобраться с этим, он мне решил подкинуть задачку по сложнее
1. Надо в схему тахонемтра добавить 3 кнопки
- 1я кнопка вводит и выводит режим изменения максимальных измеряемых оборотов (в твоем примере
constintRPM_step = 7500 / 16;)- 2я кнопка увеличивает это число с шагом 20
- 3я кнопка уменьшает это число, так же с шагом 20
2. Реализовать данный функционал в среде разработки
3. Продемонстрировать работу устройства и предоставить программный код.
...хз даже с чего начать, сталкивался хоть раз с таким?
Смысл. Все равно не поймете. А значит не объясните. Тем более вывод на экран был статическим, но с обновлением раз 0,5 сек. Тем болле я пишу с своем стиле, а он отличается от стиля "классических новичков в ардуине".
ПС: Может просто утонуть до "трояка"?
а с кнопками поможешь? с меня мороженое;)
30-40 строк, но как будет работать не поймешь и не раскажешь.
это тема следующего зачета, неделька в запасе есть что бы разобрать на символы код и понять как все работает, а вот что бы самому написать, боюсь не успею...
В любим случае тебе спасибо! Помог очень мне!
П.С. хочешь, скинь на мыло номер телефона или что-нить типа яндекс.деньги, закину тебе пару соток "на мароженку", как обещал... viktorflam@gmail.com
Похоже мой кошелек такой https://money.yandex.ru/to/410013443842505?_openstat=settings%3Baccount%3Bpassport%3Btopupme
пивомороженоеПривет Евгений!
В нике целое имя, последние 4 буквы приставка...
Мне в жизни это очень пригодиться, по этому я тут прошу помощи и хочу сам научиться. Я не прошу предоставить мне конкретный код, а показать примеры и на примерах доработать так как требуют от меня. qwone мне помогает конкретными примерами и за это мне не жалко ему закинуть пару соток, а уж что он там себе купит его дело (пЫво или мороженое).
если бы я не хотел заморачиваться и разбираться как все работает, давно бы заказал кому-ниботь за деньги, сдал бы работу и не парился... но мне самому интересно... Препод понимает, что меня этот вопрос тоже интересует, по этому и усложняет задания. Остальным сокурсникам по барабану это все, они купили готовый набор с залитым скечем и сдали...
Отвечая на Ваш вопрос (Никогда не возникало мысли чему-нибудь действительно научиться...), хочу сказать, что такая мысль возникла очень давно, тема электроники мне очень интересна, но на данный момент одновременно учиться и рабоать достаточно тяжело, и дома маленький ребенок отнимает все свободное время... Вот по этому приходится изучать все мелкими шажками, по немногу, когда есть свободное время... а его почти нет.
/* #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; } } }Привет!
Начал пробовать скеч и с самого начала что-то пошло не так:
по нажатию Btn1 никуда не попадаю
по нажатию Btn3 попадаю в режим Edit
в режиме Edit могу только повышать значение, понижать не могу...
пол дня разбирал скеч, меня кнопки местами, потом менял в коде все равно одно и тоже, пока не стал читать по строчно весь код и нашел опечатку в строке 105:
Все, думаю про себя, щя заработает... заливаю скеч, кнопки жмутся, значения увеличиваются и уменьшаются, все круто!!! Нооооооооооо...
Шкала почему-то остается привязанной к значению из строки 20
То есть, сколько бы я не выставлял в режиме Edit, шкала все равно зависит от uint16_t RPM_max = 7500;
...
пересмотрел код. Вот новый
/* #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 замечание
111uint16_t RPM_step = RPM_max / 16; uint16_t лишнее . Это объявление новой переменнойRPM_step. А вот старая RPM_step не меняется. А эта переменая как раз маштабирует шкалу.074RPM = count * 60000 / time_update2;// обороты в минутуВRPM размерность 16 бит (uint16_t)Поэтому я заменил на эту строку
RPM = (unsignedlong)count * 60000 / time_update2;// обороты в минутуиunsignedlongRPM = 0; то есть сейчас разряностьRPM = 32 бита.ПС. Что бы менять величину надо челкать на кнопку. Долгое удержание ничего не даст.
С этим я разобрался!
Теперь я хочу вместо кнопок поставить потенциометр, только который не фиксированный и с нажатием (типа как колесик на мышке), что бы можно были по нажатию перейти в режим редактирования, а поворотами влево и вправо менять значение для шкалы, но это я уже сам, сначало надо найти такой потенциометр, короче как сделаю - расскажу!
Так энкодер подойдет . Например такой https://goo.gl/iVP1Kv
Кнопка это SELECT, а повороты по часовой + , против -
Ага, то, что надо!
Уже заказал!
Работу сдал, рассказал как все работает на примере скеча, результать Отлично!
Поздравляю.
нахрена этот авнакод здесь?
Занимаюсь пол года а тахометр нужен для дела.Быстрее железку в космос забросить чем научиться библиотеки создовать.
Зачем создавать библиотеки? Можно просто всё написать прямо. Мне почему то редко удается использовать чужие библиотеки без правок или добавлений.
Не, мне мой вариант больше нравится! Тем более я к нему прикрутил шкалу, и кстати, очень полезно! С далека цифры не видно, а по шкале понятно приблизительно какая скорость.
А чем тебе мой вариант не нравится? там всего 2 стандартные библиотеки, и их достаточно для полноценного функционирования, и все предельно просто и наглядно!