Секундомер + U8glib
- Войдите на сайт для отправки комментариев
Сб, 02/12/2017 - 21:40
Привет форум.
Как обычно вопрос из рубрики "я в трёх соснах .. "
Есть програмный секундомер (взятый из примера) и библиотека для отрисовки графики U8glib. В моём случае это ОЛЕД дисплей 128х64 I2C.
В чем собственно проблема. Когда запускаю секундомер на монитор порта , без графики, всё нормально. Секундомер не врёт и идёт ровно. Но как только подключаю библиотеку и пытаюсь отрисовать это на дисплее появляется отставание и существенное.
Я так понимаю пока draw() отрисует графику это тормозит loop() (ну или непонимаю). Хотелось бы оставить эту графику, красиво рисует. Но секундомер нужен.
Скажите реально ли вообще подружить эту графическую библиотеку с секундомером?
unsigned long time; #include "U8glib.h" U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0); // инициализируем библиотеку для OLED 128х64 0,96" volatile bool timer1On; //переменная вкл/выкл таймера volatile unsigned long int timer1; //переменная подсчета миллисекунд unsigned long int timer1Loop; //переменная для хранения значения таймера bool T1_On; //переменная для хранения состояния светодиода byte Knopka=4; // Кнопка активации таймера byte Sek =0; // значение секунд byte Min =0; // значение минут byte Hour =0; // значение часов bool Timer_On_Off = 0; // тригер кнопки таймера, включение и выключение bool K1 = 0; // Вспомогательная переменная для тригера нопки включения таймера bool T1 = 0; // Вспомогательная переменная byte In_Pedal=3; bool Sost_SS_Sec=0; byte Sec; // Счет секунд внутри таймер-счетчика byte Sekund; // Переменная для функции byte Format_Secund(byte Sekund) byte Minute; // Переменная для функции byte Format_Minute(byte Minute) byte Sbros=0; bool _bounseInputD5S = 0; // Вспомогательная переменная антидребезг bool _In_Button_4= 0; // переменная вкючения таймера 1/0 unsigned long _bounseInputD5P = 0UL; // Вспомогательная переменная антидребезг bool Tmp; ISR (TIMER0_COMPA_vect) //функция, вызываемая таймером-счетчиком каждые 0,001 сек. { if ((Sost_SS_Sec) || (_In_Button_4)) //если нажата педаль (для секундомера) или нажата кнопка включения таймера { // более 2 секунд то таймер работает timer1++; //инкремент переменной таймера (+1) } } //++++++++++++++++++++++++++ отдельная функция Секундомера +++++++++++++ byte SS_Sekundomer(bool SS_Sec) { if (SS_Sec == 1) // Если педаль нажата { cli(); // остановка прерываний для того чтобы считать значение timer1 // остановили - считали - запустили timer1Loop = timer1; // сохранение текущего значения таймера sei(); // разрешение прерываний if (timer1Loop >= 1000) //если таймер отсчитал больше заданного значения, 1сек { Sek = ++Sek; // Увеличиваем значение секунд Sek на 1 cli(); // остановка прерываний для того чтобы считать значение timer1 // остановили - считали - запустили timer1 = 0; //обнулить таймер sei(); //запустить прерывания } } } void draw(void) { u8g.drawFrame(1, 1, 127, 63); // отрисовка прямоугольника по периметру // для настройки графики u8g.setFont(u8g_font_courB18); // Установка шрифта u8g_font_cour18 для секундомера if (Hour<=9) { u8g.setPrintPos(26, 24); // Начало координат x-верх лево и y-верх u8g.print("0"); u8g.print(Hour); // Вывод часов } else { u8g.setPrintPos(26, 24); u8g.print(Hour); } if (Min<=9) { u8g.setPrintPos(62, 24); u8g.print("0"); u8g.print(Min); } else { u8g.setPrintPos(62, 24); // Начало координат x-верх лево и y-верх u8g.print(Min); // Вывод минут } if (Sek<=9) { u8g.setPrintPos(98, 24); u8g.print("0"); u8g.print(Sek); } else { u8g.setPrintPos(98, 24); // Начало координат x-верх лево и y-верх u8g.print(Sek); // Вывод секунд } u8g.drawDisc(58, 12, 1); // Отрисовываем двоеточие для u8g.drawDisc(58, 19, 1); // разделения часов и минут u8g.drawDisc(94, 12, 1); // Отрисовываем двоеточие для u8g.drawDisc(94 , 19, 1); // разделения минут и секунд } void setup(void){ Serial.begin(9600); // TCCR1B = TCCR1B & 0b11111000 | 0x02; // устанавливает частоту ШИМ до 3906.25 Гц /**** настройка прерывания по таймеру каждую 0,001 сек (вызов функции ISR (TIMER0_COMPA_vect)) ****/ TCCR0A |= (1 << WGM01); //сброс при совпадении OCR0A = 0xF9; //начало отсчета до переполнения (249) TIMSK0 |= (1 << OCIE0A); //разрешить прерывание при совпадении с регистром А TCCR0B |= (1 << CS01) | (1 << CS00); //установить делитель частоты на 64 sei(); // разрешение прерываний (взято из примера) } void loop(void) { //+++++++++++++++++++++++++++++++ Секундомер Start Stop по нажатию педали ++++++++++++++++++++++++++++ if (Timer_On_Off == 1) // Активирован или нет таймер. { // Разрешение на запуск секундомера дан Sost_SS_Sec = digitalRead(In_Pedal); // Считываем состояние педали SS_Sekundomer(Sost_SS_Sec); // функция секундомера } //+++++++++++++++++++++++++++++ форматирования времени секундомера+++++++++++++ if (Sek == 60) { Min = ++ Min; Sek = 0; if (Min == 60) { Hour = 1; Min =0; Sek =0; if (Hour =12) { Hour = 0; Min =0; Sek =0; } } } // ++++++++++++++++++++++++++++ антидребезг кнопки вкючение таймера ++++++++++ bool Tmp_4 = (digitalRead (Knopka)); if (_bounseInputD5S) { if (millis() >= (_bounseInputD5P + 40)) { _In_Button_4= Tmp_4; _bounseInputD5S=0; } } else { if (Tmp_4 != _In_Button_4) { _bounseInputD5S=1; _bounseInputD5P = millis(); } } //+++++++++++++++++++++++++ Сброс секундомера-таймера после 2 сек нажатой кнопки вклч/выкл таймера++++++ if (_In_Button_4 == HIGH) // Удержание кнопки более 2 секунд { cli(); //остановка прерываний для того чтобы считать значение timer1 // остановили - считали - запустили timer1Loop = timer1; //сохранение текущего значения таймера sei(); //разрешение прерываний if (timer1Loop >= 2000) //если таймер отсчитал больше заданного значения (более 2сек) { Hour = 0; // Обнуляем значение "Часы" Min =0; // Обнуляем значение "Минуты" Sek =0; // Обнуляем значение "Секунды" cli(); //остановить прерыания (остановили - считали - запустили) timer1 = 0; //обнулить таймер sei(); //запустить прерывания } } Tmp = _In_Button_4; // переменная получила чёткое состояние (после антидребезга) // от кнопки на выводе 4(активация таймера), записана в Tmp 0/1 // ++++++++ тригер кнопки, одно нажатие активируем таймер следуюющте нажатие деактивируем таймер +++++++++ // действие первое // Действие второе if (Tmp) // Если активировали таймер ( Tmp = 1) // Если деактивировали таймер ( Tmp = 0) { // (кнопка-тригер) // if (! T1) // если T1=0 (кнопка не нажималась) // если T1=1 (кнопка нажималась) K1 = ! K1; // инвертируем переменную K1 (с 0 на 1) // инвертируем переменную K1 (с 1 на 0) } // T1 = Tmp; // в T1 записываем значение Tmp (1) // в T1 записываем значение Tmp (0) Timer_On_Off = K1; // Таймер активируем Timer_On_Off=1 // Таймер активируем Timer_On_Off=0 // +++++++++++++++++++++++++++++++ picture loop ++++++++++++++++++++++++ Serial.print(Timer_On_Off); Serial.print(" "); Serial.print(Sost_SS_Sec); Serial.print(" "); Serial.print(Sek); Serial.print(":"); Serial.print(Min); Serial.print(":"); Serial.println(Hour); u8g.firstPage(); do { draw(); } while( u8g.nextPage() ); }собственно сам код. там реализовано старт/пауза и сброс после ужержания более 2 сек.(1 кнопка) и активация/деактивация (вторая кнопка)
понимаю что там никоторые вещи можно было так не раздувать и сделать поменьше, но чайники пишут так, только так =)
код совершенно бредовый. Начнем с того, что таймер на прерывании, тикающий раз в миллисекунду, в контроллере уже есть, называется миллис - совершенно непонятно, зачем изобретать велосипед заново.
Во-вторых - и это главное - зачем вы ПРИ КАЖДОМ цикле loop() заново отрисовываете всю картинку - рамку. ЧАСЫ!!!! МИНУТЫ! СЕКУНДЫ! - это же бред. Поэтому все безбожно тормозит. Обновляйте на экране только то, что изменилось - раз в секунду всего один символ - последний знак секунд.
Есть и прямые ошибки. Секундомер считает только до 1:59:59, так как при достижении 60 минут часы не увеличиваются на единицу, а всегда выставляются в "1"
реально ли вообще подружить эту графическую библиотеку с секундомером?
С этим секундомером - нет.
С этим секундомером - нет.
ну почему? - если обновлять экран не чаще раза в секунду - наверно будет работать...
Другой вопрос, что я бы вообще весь код секундомера выкинул, эти десятки строк можно заменить одной-двумя на основе миллис :)
Что-то мне вдруг подумалось - как все-таки полезно, что атмел относительно медленный контроллер :) На каком-нить пентиуме этот код, наверно, успевал был исполнятся и автор бы думал, что написал отличную программу. А на атмеле все подобные писатели получают от жизни мощнейшую плюху в строгом соответсвии со своими навыками оптимизации кода :)
ну почему? - если обновлять экран не чаще раза в секунду - наверно будет работать...
Ну, во-первых, не будет - Вы сами на ошибку указали и она там не одна такая.
А во-вторых - служба времени, зависящая от скорости выполнения loop - это уже само по себе ошибка. Сейчас Вы ему рисование сократите, он опрос датчиков вставит или ещё чего-нибудь - так просто не делается.
очень смешной код. вообще не рабочий, но смешной.
Типа "что-то где-то слышал" про микроконтроллеры.
========================
Я, ну чтобы не голословно хаять, скажу, что миллис() работаетот Таймера0, раз его перенастроили, то миллис() уже не работает.
Этого уже достаточно.
Не очень внимательно смотрел, но, вроде, должно работать. Делитель там 64 (такой же) и прервание не запретили, а просто своё добавили. Так что, вроде, молли не обидели, разве что я чего-то не заметил.
У него в таймере сброс по совпадению. Переполнение не наступит, миллис не обновица
Тоже верно.
Кстати, посмотрел повнимательнее и сделал вывод, что заявление ТС о том, что без графики секундомер работает правильно - есть "типичный случай так-называемого вранья".
код совершенно бредовый...
Согласен, но по другому пока неумею. Мы чайники такие. Пишем бредятину, а потом бегаем плакаться к вам на форум "мол, помогите ... не работает..." Тем самым поднимаем свой уровень и вашу самооценку =) . И слава богу, что вы есть. И до тех пор пока этот симбиоз существует, нас таких будет еще ооочень много. =)
Во-вторых - и это главное - зачем вы ПРИ КАЖДОМ цикле loop() заново отрисовываете всю картинку - рамку. ЧАСЫ!!!! МИНУТЫ! СЕКУНДЫ! - это же бред. Поэтому все безбожно тормозит. Обновляйте на экране только то, что изменилось - раз в секунду всего один символ - последний знак секунд.
Насколько я понял как раболтает эта библиотека, то .. Она отрисовывает всё в контроллере а потом выкидавает это на дисплей двумя половинками экрана. Как отрисовать отдельно я незнаю. Знаете поскажите.
Есть и прямые ошибки. Секундомер считает только до 1:59:59, так как при достижении 60 минут часы не увеличиваются на единицу, а всегда выставляются в "1"
Спасибо. Увидел. исправил.
А во-вторых - служба времени, зависящая от скорости выполнения loop - это уже само по себе ошибка.
Вот тут полностью согласен. Я это понял до того как сюда писать стал, но как сделать то, без loop() ?
Сейчас Вы ему рисование сократите, он опрос датчиков вставит или ещё чего-нибудь - так просто не делается.
ЕССТЕСТВЕННО , это еще не вся программа. И при каждой добавленной строкой loop() растягивается.
А можно имея модуль часов реального времени (например на DS1307) реализовать секундомер ?
А можно имея модуль часов реального времени (например на DS1307) реализовать секундомер ?
легко, в сети примеров тыщи))))
тыщу не надо.. хоть бы один. а то гугл непоказывает
вы барин или ленитесь или гуглить не умеете.
вот за вас сделал
https://www.google.com.ua/search?q=+DS1307+%D1%87%D0%B0%D1%81%D1%8B+%D0%...
Ну спасибо конечно. Просто у меня секундомер должен не просто идти, а останавливаться и потом опять идти. И потом его надо обнулять. Вопрос, я смогу такое реализовать используя библиотеку ....RTC.h ? ( пойду покопаю в эту сторону)
Насколько я понял как раболтает эта библиотека, то .. Она отрисовывает всё в контроллере а потом выкидавает это на дисплей двумя половинками экрана. Как отрисовать отдельно я незнаю. Знаете поскажите.
Ну, то есть это библиотека заставляет Вас вызывать свои методы на каждом проходе loop().
Какая настойчивая библиотека, однако.
Ну спасибо конечно. Просто у меня секундомер должен не просто идти, а останавливаться и потом опять идти. И потом его надо обнулять. Вопрос, я смогу такое реализовать используя библиотеку ....RTC.h ? ( пойду покопаю в эту сторону)
я вам больше скажу - это можно реализовать и без RTC.h :)
я вам больше скажу - это можно реализовать и без RTC.h :)
а поподробнее ?
Ну, то есть это библиотека заставляет Вас вызывать свои методы на каждом проходе loop()....
Т.е. вызывать процедуру отрисовки только при смене значений секунд?
Т.е. вызывать процедуру отрисовки только при смене значений секунд?
по-моему, вам уже несколько человек посоветовали это очевидное решение
а поподробнее ?
а что "подробнее"? - вот, к примеру. в вашем собственном коде секундомер реализован без библиотеки. Не так важно, что написано громоздко и с ошибками - их можно поправить, важнее то, что практически любую задачу в программировании можно решить 1001 способом