Глюк с энкодером
- Войдите на сайт для отправки комментариев
Добрый вечер. Сразу скажу я в коде полный 0. Кто понимает в коде помогите пожалуйста. Собрал регулятор тока на Ардуино про мини. Скетч и как всё собрать есть на одноимённом форуме, тема "Регулятор напряжения и тока на Arduino Pro Mini" Гугл в первой строке по этому запросу ссылку на форум выдаёт.
Так вот в чем проблема. При вращении энкодера значения изменяется и как только перестал крутить всё сбрасывается в 0 . Я не могу изменить значения в настройках. Если кто сталкивался с таким глюком подскажите как решить. Возможно дело не в скетче а в монтаже. Но проверял несколько раз подключение вроде как всё правельно. Если дело в железе то куда копать?
Вот скетч. На том форуме на него нареканий нет а почему у меня так не пойму.
Написал сюда потому как на том форуме помогать не горят желанием.
efine detect 3 //детектор нуля #define triac 5 //тиристор #include <Wire.h> #include <LCD_1602_RUS.h> // подключаем библиотеку LCD_1602_RUS.h #include <EEPROM.h> LCD_1602_RUS lcd(0x3F, 16, 2);// Для подключения ЛСД экрана через I2C #define button1 10 // 1 кнопка #define button2 11 // 2 кнопка #define SW 7 // энкодер SW кнопка #define CLK 8 // энкодер CLK #define DT 9 // энкодер DT #define ACCELERATOR 12 //Вывод разгона (подтянут вверх, активен когда замкнут на GND, при отпускании вызывает мощность из памяти) #define STOP 13 //Вывод стоп (подтянут вверх, активен когда замкнут на GND, имеет приоритет // над разгоном, при отпускании и активном разгоне - переход в разгон, // при отпускании и неактивном разгоне - переход в 0 Ватт) double resist_ten = 18.45; //сопротивление ТЭНа 3кВт double ACS_coeff = 0.048828125; // Коэффициент датчика ACS712 |5А - 0.024414063 | 20А - 0.048828125 | 30A - 0.073242188 | //------------------------------------ double max_W = 3000; //максимальная мощность ТЭНа W double step_W = 5; //шаг установки мощности W для энкодера //------------------------------------ int preset_max = 4; //число предустановок + 1 (0) = 5 //------------------------------------ char* name_preset[] = {"РЕКТ ", "ДИСТ ", "УСТ1 ", "УСТ2 ", "УСТ3 "}; //------------------------------------ String Var; String T1, T2; volatile unsigned long Iism = 0; // мгновенные значения тока volatile int cntr = 0; // счетчик в обработчике прерывания volatile unsigned long Isumm = 0; // переменная для хранения суммы квадратов double real_I = 0; // переменная расчета RMS тока double real_W = 0; // рассчитанная мощность double total_W = 0; // расход Ватт double sqrtUsum = 0; // переменная расчете квадратного корня double ust_W = 0; // установленная мощность unsigned long previousMillis = 0; unsigned long previousMillis_info = 0; unsigned long displayMillis = 0; unsigned long countMillis = 0; unsigned long reg_time = 0; byte set = 0; // переменная включения разгона int step_ = 0; // шаг регулировки угла int angle_W = 2250; int angle_W_ocr = 2250; int zero = 0; int preset = 0; unsigned long showTime = 0; // время обновления экрана int buffer_ust_W[10]; unsigned long encoderMillis = 0; int encoder_CLK = 0; int encoder_DT = 0; int encoder_CLK_prev = 0; byte set_menu_I = false; byte set_W = false; unsigned long SW_time_press = 0; int SW_press_time = 0; unsigned long button1_time_press = 0; int button1_press_time = 0; unsigned long button2_time_press = 0; int button2_press_time = 0; int ACCELERATOR_press_time = 0; unsigned long ACCELERATOR_time_press = 0; int STOP_press_time = 0; unsigned long STOP_time_press = 0; unsigned long timer1 = 0; unsigned long work_timer = 0; unsigned long work_timer_buffer = 0; unsigned char timerS; unsigned char timerM; unsigned char timerH; int tic1; char TimeDate[20]; byte menu_1 = true; unsigned long work_timer_buffer2 = 0; void setup(void) { Serial.begin(9600); // активируем прием сообщения pinMode(detect, INPUT); // детектор нуля pinMode(triac, OUTPUT); // тиристор pinMode(CLK, INPUT); // выходы энкодера pinMode(DT, INPUT); pinMode(SW, INPUT); pinMode(button1, INPUT); // кнопки pinMode(button2, INPUT); pinMode(ACCELERATOR, INPUT); // разгон pinMode(STOP, INPUT); // стоп digitalWrite(SW, HIGH); // включаем подтягивающий резистор digitalWrite(button1, HIGH); // включаем подтягивающий резистор digitalWrite(button2, HIGH); // включаем подтягивающий резистор digitalWrite(ACCELERATOR, HIGH); // включаем подтягивающий резистор digitalWrite(STOP, HIGH); // включаем подтягивающий резистор lcd.init(); // для подключения ЛСД экрана через I2C lcd.backlight(); // для подключения ЛСД экрана через I2C lcd.clear(); lcd.setCursor(1, 0); lcd.print("РЕГУЛЯТОР ТОКА"); lcd.setCursor(0, 1); lcd.print("Версия 2.2 3 кВт"); // изменения от 06.12.17 _delay_ms(2000); lcd.clear(); for (preset = preset_max ; preset >= 0 ; preset--) // загружаем значения из памяти { buffer_ust_W[preset] = EEPROM_read(preset * 2); } preset = 0; //===========================================================Настройка АЦП ADMUX = (0 << REFS1) | (1 << REFS0) | (0 << MUX2) | (0 << MUX1) | (1 << MUX0); // /* Биты 7:6 – REFS1:REFS0. Биты выбора опорного напряжения. Если мы будем менять эти биты во время преобразования, то изменения вступят в силу только после текущего преобразования. В качестве опорного напряжения может быть выбран AVcc (ток источника питания), AREF или внутренний 2.56В источник опорного напряжения. Рассмотрим какие же значения можно записать в эти биты: REFS1:REFS0 00 AREF 01 AVcc, с внешним конденсатором на AREF 10 Резерв 11 Внутренний 2.56В источник, с внешним конденсатором на AREF Бит 5 – ADLAR. Определяет как результат преобразования запишется в регистры ADCL и ADCH. ADLAR = 0 Биты 3:0 – MUX3:MUX0 – Биты выбора аналогового канала. MUX3:0 0000 ADC0 0001 ADC1 0010 ADC2 0011 ADC3 0100 ADC4 0101 ADC5 0110 ADC6 0111 ADC7*/ //======================================================================================= ADCSRA = B11101111; //Включение АЦП /* Бит 7 – ADEN. Разрешение АЦП. 0 – АЦП выключен 1 – АЦП включен Бит 6 – ADSC. Запуск преобразования (в режиме однократного преобразования) 0 – преобразование завершено 1 – начать преобразование Бит 5 – ADFR. Выбор режима работы АЦП 0 – режим однократного преобразования 1 – режим непрерывного преобразования Бит 4 – ADIF. Флаг прерывания от АЦП. Бит устанавливается, когда преобразование закончено. Бит 3 – ADIE. Разрешение прерывания от АЦП 0 – прерывание запрещено 1 – прерывание разрешено Прерывание от АЦП генерируется (если разрешено) по завершении преобразования. Биты 2:1 – ADPS2:ADPS0. Тактовая частота АЦП ADPS2:ADPS0 000 СК/2 001 СК/2 010 СК/4 011 СК/8 100 СК/16 101 СК/32 110 СК/64 111 СК/128*/ //=========================================================== ACSR = (1 << ACD); //------ Timer1 ---------- Таймер задержки времени открытия триака после детектирования нуля (0 триак не откроется) TCCR1A = 0x00; // TCCR1B = 0x00; // TCCR1B = (0 << CS12) | (1 << CS11) | (1 << CS10); // Тактирование от CLK. // Если нужен предделитель : // TCCR1B |= (1<<CS10); // CLK/1 = 0,0000000625 * 1 = 0,0000000625, 0,01с / 0,0000000625 = 160000 отсчетов 1 полупериод // TCCR1B |= (1<<CS11); // CLK/8 = 0,0000000625 * 8 = 0,0000005, 0,01с / 0,0000005 = 20000 отсчетов 1 полупериод // TCCR1B |= (1<<CS10)|(1<<CS11); // CLK/64 = 0,0000000625 * 64 = 0,000004, 0,01с / 0,000004 = 2500 отсчетов 1 полупериод // TCCR1B |= (1<<CS12); // CLK/256 = 0,0000000625 * 256 = 0,000016, 0,01с / 0,000016 = 625 отсчетов 1 полупериод // TCCR2B |= (1<<CS20)|(1<<CS21)|(1<<CS22); // CLK/1024 OCR1A = 2250; // Верхняя граница счета. Диапазон от 0 до 65535. // Частота прерываний будет = Fclk/(N*(1+OCR1A)) // где N - коэф. предделителя (1, 8, 64, 256 или 1024) TIMSK1 = 0x00; attachInterrupt(1, zero_crosss_int, RISING);//вызов прерывания при детектировании нуля } //======================================================== Прерывание по нулю void zero_crosss_int() { TCNT1 = 0; OCR1A = angle_W_ocr; zero++; } //======================================================== Обработка таймера по совпадению нуля ISR (TIMER1_COMPA_vect) { PORTD |= (1 << PORTD5); TCNT1 = 65535 - 200; // Импульс включения симистора 65536 - 1 - 4 мкс, 2 - 8 мкс, 3 - 12 мкс и тд } ISR (TIMER1_OVF_vect) { //timer1 overflow PORTD &= ~(1 << PORTD5); TCNT1 = OCR1A + 1; } //======================================================== Обработка прерывания АЦП для расчета среднеквадратичного тока ISR(ADC_vect) { byte An_pin = ADCL; byte An = ADCH; Iism = ((An << 8) + An_pin) - 512; Iism *= Iism;// возводим значение в квадрат Isumm += Iism; // складываем квадраты измерений cntr++; } //======================================================== Обработка таймеров // Резерв /*ISR (TIMER2_COMPA_vect) { ++timer1; if (timer1 == 250) { // ++systimer; //общий таймер timer1 = 0; } }*/ //=====================================================================================EEPROM // чтение int EEPROM_read(int addr) { byte raw[2]; for (byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr + i); int &num = (int&)raw; return num; } // запись void EEPROM_write(int addr, int num) { byte raw[2]; (int&)raw = num; for (byte i = 0; i < 2; i++) EEPROM.update(addr + i, raw[i]); } //======================================================================================== void parseParams(String inputString) { //Функция разбора принятой в Serial port строки String bb = inputString; if (bb.substring(0, 2) == "TW") { T1 = bb.substring(bb.indexOf("TW", 2) + 3); //команда ust_W = T1.toFloat(); //Выставленная мощность с Serial порта buffer_ust_W[preset] = ust_W; } } //======================================================================================== void loop(void) { //================================================================================== while (Serial.available()) { // Serial port, пока не конец сообщения, читаем данные и формируем строку char ch = Serial.read(); Var += ch; if (ch == '\n') { parseParams(Var); // вызываем функцию разбора принятой строки Var = ""; } } if (zero >= 6) { // расчет среднеквадратичного // zero - количество полупериодов для рассчета среднеквадратичного sqrtUsum = Isumm / cntr; // real_I = sqrt(sqrtUsum) * ACS_coeff; // cntr = 0; Isumm = 0;// обнуляем суммы напряжений zero = 0; real_W = (real_I * real_I * resist_ten); } //===================================================================Меню установки if (digitalRead(STOP) == LOW ) { // считаем сколько времени активен стоп if (millis() - STOP_time_press > 1) { STOP_press_time++; STOP_time_press = millis(); } } if ( STOP_press_time > 1000) { // если стоп более ХХХХ мс, валим мощность в ноль STOP_press_time = 0; buffer_ust_W[preset] = 0; set = 3; } if (digitalRead(STOP) == HIGH && set == 3) { // очищаем счетчик, если стоп отпущен и перед этим был включен, // на заданную мощность buffer_ust_W[preset] = EEPROM_read(preset * 2); set = 0; } if (digitalRead(ACCELERATOR) == LOW ) { // считаем сколько времени активен разгон if (millis() - ACCELERATOR_time_press > 1) { ACCELERATOR_press_time++; ACCELERATOR_time_press = millis(); } } if (digitalRead(STOP) == HIGH && ACCELERATOR_press_time > 1000) { // если разгон активен более ХХХХ мс и нет стопа, // ставим 3000 Ватт и взводим флаг разгона ACCELERATOR_press_time = 0; buffer_ust_W[preset] = 3000; set = 1; } if (digitalRead(ACCELERATOR) == HIGH && set == 1) { // очищаем счетчик, если разгон отпущен и перед этим был включен, // и на заданную мощность buffer_ust_W[preset] = EEPROM_read(preset * 2); set = 0; } if (digitalRead(SW) == LOW) { // считаем сколько времени нажата кнопка энкодера if (millis() - SW_time_press > 1) { SW_press_time++; SW_time_press = millis(); } } if (digitalRead(button1) == LOW) { // считаем сколько времени нажата 1 кнопка if (millis() - button1_time_press > 1) { button1_press_time++; button1_time_press = millis(); } } if (digitalRead(button2) == LOW) { // считаем сколько времени нажата 2 кнопка if (millis() - button2_time_press > 1) { button2_press_time++; button2_time_press = millis(); } } if (digitalRead(SW) == HIGH) { // очищаем счетчик если кнопка энкодера отпущена SW_press_time = 0; } if (digitalRead(button1) == HIGH) { // очищаем счетчик если кнопка 1 отпущена button1_press_time = 0; } if (digitalRead(button2) == HIGH) { // очищаем счетчик если кнопка 2 отпущена button2_press_time = 0; } if ( SW_press_time >= 300 && !set_menu_I) { // если более ХХХ мс то кнопка 0 нажата - режим отображения времени / потребленной мощности if (!menu_1) {// menu_1 = true; } else { menu_1 = false; } SW_press_time = 0; lcd.clear(); } if ( SW_press_time >= 300 && set_menu_I) { // если более ХХХ мс то кнопка 0 нажата - запись в память SW_press_time = 0; EEPROM_write(preset * 2, buffer_ust_W[preset]); lcd.setCursor(14, 1); lcd.print("WR"); } if ( button1_press_time >= 300) { // если более ХХХ мс то кнопка 1 нажата - режим установки if (!set_menu_I) {// set_menu_I = true; } else { set_menu_I = false; } button1_press_time = 0; lcd.clear(); } if ( button2_press_time >= 300 && !set_menu_I) { // если более ХХХ мс и менее хх мс то кнопка 2 нажата - режим включения/выключения if (!set_W) {// set_W = true; } else { set_W = false; } button2_press_time = 0; lcd.clear(); } //=========================================================================Энкодер //меню установки мощности if (set_menu_I) { if (millis() >= (encoderMillis + 1)) { // проверяем каждые 1 мс encoder_CLK = digitalRead(CLK); // считываем состояние выхода А энкодера encoder_DT = digitalRead(DT); // считываем состояние выхода B энкодера if ((!encoder_CLK) && (encoder_CLK_prev)) { // если состояние изменилось с положительного к нулю if (encoder_DT) { // выход DT в полож. сост., значит вращение по часовой стрелке // увеличиваем if (buffer_ust_W[preset] <= max_W - step_W) buffer_ust_W[preset] = buffer_ust_W[preset] + step_W; } else { // выход DT в 0 сост., значит вращение против часовой стрелки // уменьшаем if (buffer_ust_W[preset] >= 0 + step_W) buffer_ust_W[preset] = buffer_ust_W[preset] - step_W; } } encoder_CLK_prev = encoder_CLK; // сохраняем значение А для следующего цикла encoderMillis = millis(); } } //крутилка пресетов if (!set_menu_I) { if (millis() >= (encoderMillis + 1)) { // проверяем каждые 1 мс encoder_CLK = digitalRead(CLK); // считываем состояние выхода А энкодера encoder_DT = digitalRead(DT); // считываем состояние выхода B энкодера if ((!encoder_CLK) && (encoder_CLK_prev)) { // если состояние изменилось с положительного к нулю if (encoder_DT) { // выход DT в полож. сост., значит вращение по часовой стрелке // увеличиваем preset = preset + 1; if (preset > preset_max) preset = 0; } else { // выход DT в 0 сост., значит вращение против часовой стрелки // уменьшаем preset = preset - 1; if (preset < 0) preset = preset_max; } } encoder_CLK_prev = encoder_CLK; // сохраняем значение А для следующего цикла encoderMillis = millis(); } } //==============================================регулятор if (millis() - countMillis >= 15) { // раз в пол секунды регулируем, индицируем countMillis = millis(); if (real_W >= (ust_W - 5) && real_W <= (ust_W + 5)) { angle_W = angle_W; } if (real_W > (ust_W + 5)) { angle_W ++; } if (real_W < (ust_W - 5)) { angle_W --; } } //-------------------------------------- if (angle_W >= 2250) { angle_W = 2250; } if (angle_W <= 1) { angle_W = 1; } //-------------------------------------- if (ust_W < 0 || buffer_ust_W[preset] < 0) { //Если меньше 0, то 0 ust_W = 0; buffer_ust_W[preset] = 0; } if (set_W) { ust_W = (buffer_ust_W[preset] > 0) ? buffer_ust_W[preset] : 0; TIMSK1 |= (1 << OCIE1A) | (1 << TOIE1); } else { ust_W = 0; TIMSK1 = 0x00; PORTD &= ~(1 << PORTD5); } //------------------------------------ angle_W_ocr = angle_W; //=========================Часы работы if (set_W) { if (millis() - work_timer_buffer >= 1000) { work_timer ++; work_timer_buffer = millis(); } } timerH = work_timer / 3600; tic1 = work_timer % 3600; timerM = tic1 / 60; timerS = tic1 % 60; sprintf(TimeDate, "%02u:%02u:%02u", timerH, timerM, timerS); //=======================Расход Ватт if (work_timer - work_timer_buffer2 >= 5) // снимаем показания каждые пять секунд { work_timer_buffer2 = work_timer; total_W = total_W + (real_W / 720); // и делим на 720 значений 5*720=3600 сек = 1 час. Итого средняя мощность за час из 720 измерений } //=========================Дисплей if (millis() - displayMillis >= 1000) { displayMillis = millis(); if (menu_1 && !set_menu_I) { lcd.setCursor(0, 0); lcd.print("ФАКТ "); if (set==3) lcd.print("СТОП"); else { lcd.print(int(real_W)); lcd.print(" ");} lcd.setCursor(9, 0); lcd.print(" Вт"); lcd.setCursor(0, 1); lcd.print(name_preset[preset]); if (set==1) lcd.print("РЗГН"); else { lcd.print(buffer_ust_W[preset]); lcd.print(" ");} lcd.setCursor(9, 1); lcd.print(" Вт"); } if (!menu_1 && !set_menu_I) { lcd.setCursor(0, 0); lcd.print("BPM "); lcd.print(TimeDate); lcd.setCursor(0, 1); lcd.print("Вт*ч "); lcd.print(total_W); } if (set_menu_I) { lcd.setCursor(0, 0); lcd.print("УСТАНОВКА:"); lcd.setCursor(0, 1); lcd.print(name_preset[preset]); lcd.print(">>"); lcd.print(buffer_ust_W[preset]); lcd.print(" "); } if (set_W) { lcd.setCursor(13, 0); lcd.print("ВКЛ"); } else { lcd.setCursor(12, 0); lcd.print("ВЫКЛ"); } } //=========================Информация в порт раз в секунду if (millis() - previousMillis_info >= 1000) { previousMillis_info = millis(); Serial.print("realW "); //Измеренная мощность Serial.println(real_W); Serial.print("ustW "); //Установленная мощность Serial.println(ust_W); Serial.print("angleW "); //Угол установленный Serial.println(angle_W); // Serial.print("step "); //Угол установленный // Serial.println(step_); Serial.println("-----------------"); } //======================================================== }
[quote]
При вращении энкодера значения изменяется и как только перестал крутить всё сбрасывается в 0.
[\quote]
вы о каком то конкретном значении или обо все вообще ?
можете более подробно описать что вы видите когда на lcd экране устройства "При вращении энкодера значения изменяется и как только перестал крутить всё сбрасывается в 0."
в каком состоянии тэн ? включен,выключен,нагревается,остывает ?
Нет не о конкретном. Все изменяемые значения.
Например в скетче есть 4 предустановки (char* name_preset[] = {"РЕКТ ", "ДИСТ ", "УСТ1 ", "УСТ2 ", "УСТ3 "};) все они при первом включении на 0. Я выбираю любую начинаю крутить энкодер значения меняются по 5 единиц как и задано в скетче (double step_W = 5; //шаг установки мощности W для энкодера) могу накрутить и 80 на ЛСД значения изменяются но как только перестаю крутить сбрасывается в 0. И так любое значение которое можно изменять.
[/quote]в каком состоянии тэн ? включен,выключен,нагревается,остывает ? [/quote]
Тен я пока не подключал но пробовал и с включенным симистором и нет. Да и задовать предустановки можно перед включением нагрузки.
Вот описание от автора:
Программа имеет три меню:
1. Текущая мощность (ВАТТ), включен или выключен регулятор (OFF/ON)
Название предустановки, установленная мощность.
2. Время работы, включен или выключен регулятор (OFF/ON)
Потребленная мощность в ваттах.
3. Установка, включен или выключен регулятор (OFF/ON)
Название предустановки >> устанавливаемая мощность.
Переключение между меню 1 и 2 с помощью кнопки энкодера;
Переключение между предустановками с помощью энкодера;
Переход в меню 3 и выход из него нажатием кнопки 1 , установка мощности с помощью энкодера;
Запись в память установки с помощью кнопки энкодера в меню 3, в качестве подтверждения появится надпись WR;
Включение регулятора кнопкой 2 в меню 1 или 2. Если требуется регулировка на «ходу» то при включенном регуляторе нажать кнопку 1 и производить регулировку из меню 3 установки;
емкости между выводами энкодера и выводом GND есть?
если нет, ставьте по 0,1 мкф потом смотрите
У меня шилд и раньше нет не так, другой скетч от другого автора работает без нареканий. Я бы им и пользовался но в нём нет некоторых функций которые есть в этом.
если смотреть на строчки : 303 - 314 : если STOP активен ,то вбранный данный пресет обнулять
STOP ,в вашем случае, пин 13 ,активен когда подтянут к 0 :
убедитесь что написанное соотвествует дейстивтельности.
далее сточках 496-498 тоже есть обнуление.
ради эксперимента в строчке 312 напишите
а в строчке 498 :
и попробуйте повторить ваши дейстивя с крутилками
Окей спасибо попробую, не знаю успею ли сегодня но как попробую отпишусь.
ну там код, прямо скажем, очень и очень кривой. При вращении энкодера данные с него считываются 1000 раз в сек, а значение на экране обновляется лишь раз в секунду. При этом код энкодера написан так, что при его "перекручивании" значния сбрасываются на ноль.
Попробуйте крутить ручку ОЧЕНЬ медленно, чтобы увеличение уставок происходило раз в 5-10 секунд, должно помочь.
ну там код, прямо скажем, очень и очень кривой. При вращении энкодера данные с него считываются 1000 раз в сек, а значение на экране обновляется лишь раз в секунду. При этом код энкодера написан так, что при его "перекручивании" значния сбрасываются на ноль.
Попробуйте крутить ручку ОЧЕНЬ медленно, чтобы увеличение уставок происходило раз в 5-10 секунд, должно помочь.
Не помогло.
далее сточках 496-498 тоже есть обнуление.
Спасибо вот кажись оно:
if (ust_W < 0 || buffer_ust_W[preset] < 0) { //Если меньше 0, то 0
ust_W = 0;