Пультоскоп на Arduino 27МГц!!!

Koootyy
Offline
Зарегистрирован: 18.11.2020

Сори пока разобрался как отправить нафигарил

progrik
Offline
Зарегистрирован: 30.12.2018

Koootyy пишет:
Доброго времени суток. Токой вопрос как в скейче поминять пин для щупа? Спалил a2 к которому был подключин щуп. В скейче он не прописан. Собирал PULTOSCOPE_128x64_OLED_display.
найди в скетче ADMUX = 0bxxxx0010; (ищи "0010") и поменяй, чтоб последние четыре цифры были: для A0 - 0000, A1 - 0001, A2 - 0010, A3 - 0011, A4 - 0100, A5 - 0101, A6 - 0110, A7 - 0111

то есть, если был пин A2, то было так ADMUX = 0bxxxx0010;
хотим на пин, например, A5. делаешь ADMUX = 0bxxxx0101;
или для строки
ADMUX = vRef ? 0b01100010 : 0b11100010;
делаем так (для A5 - 0101):
ADMUX = vRef ? 0b01100101 : 0b11100101;

короче говоря, всё, что оканчивается на 0010 меняй на то, что надо)

ЗЫ: это хорошо, что люди интересуются самодельными осциллографами еще до того, как овладеют грамматикой))) жаль только, они не смогут при помощи даташытов и апноутов вызывать демонов и пронзать пространство и время...

Koootyy
Offline
Зарегистрирован: 18.11.2020

Спасибо огромное!!!

fly245
fly245 аватар
Offline
Зарегистрирован: 25.08.2013

progrik пишет:

 

ЗЫ: это хорошо, что люди интересуются самодельными осциллографами еще до того, как овладеют грамматикой))) жаль только, они не смогут при помощи даташытов и апноутов вызывать демонов и пронзать пространство и время...

Читать даташиты-путь олд скула )).Ттолько что скачал 5 штук даташитов начиная от тиньки 85 заканчивая 328

ironcover
Offline
Зарегистрирован: 29.11.2020

D.I.M пишет:

bpl , вот скетч с библиотеками, которые у меня работают IDE 1.6.7: https://drive.google.com/file/d/0B4prOxHsTkgtM1NaSmtwWDVoNDQ/view?usp=sharing

 Попробуйте сначала почистить все библиотеки, а эти установите, иначе будут конфликтовать. Еще может возникать конфликт из - за установленой в IDE платы Arduino Robot  мне пришлось удалить все файлы связанные с этой платой.

Подскажите пожалуйста.

Залил скетч через IDE 1.6.8, для этого снес все что было связано с другими версиями и почистил реестр (иначе были ошибки, заняло один день и три часа :)) под oled 128x64, схему собрал по сайту. У меня вроде шим показывает не правильно : 60% скважность при 100% шим с Uno, и батарея все время 5 вольт- не меряет ее вобщем, хотя она 3,7v. Вас не затруднит схемку от руки набросать: как пины на щуп выходят и акб, а то знаний не хватает довести до ума, уже три для паяю, макетки закончились и олово и резисторы :), а мне нужно вывести правильный сигнал на драйвер сервомотора.

И еще - как питание развести кнопки я так и не понял, ставлю в скетче  power - 1 чтобы сразу заводилась

 

Alex-Bee
Offline
Зарегистрирован: 13.03.2020

ironcover пишет:
мне нужно вывести правильный сигнал на драйвер сервомотора.

По-моему, вы выбрали для этого слишком витиеватый путь :)
Возможно, вам надо всего лишь NE555 (у нее 8 ног) и ElectroDroid из плей-маркета. Смотрите в нем "Расчёт NE555" - "Астабильный (Скв.>2)", если надо меньше 50%, и задаете частоту со скважностью. Или "Астабильный" если скважность больше 50%.  Программка сама подберёт вам конденсатор и пару резисторов. Схема там, в программке, тоже есть.

ironcover
Offline
Зарегистрирован: 29.11.2020

Нужна помощь.
Залил скеч от el83 который с авто синхронизацией: SSD1306_EL83_EDITION_auto. Всё в нем нравится вроде все правильно выводит до 10 kГц, мне нужен только шим сигнал мерять с ардуины и управлять базой симисторов и полевиков, ну и в режиме генератора подать шим. У меня в режиме осцилографа не показывается вертикальный спад сигнала, выводит только штрихи по горизонтали верхние и нижние. И толщина кривой слишком тонкая. Кто знает как подправить.
Ps форум пролистал от корки до корки три раза.

ironcover
Offline
Зарегистрирован: 29.11.2020

Нужна помощь.
Залил скеч от el83 который с авто синхронизацией: SSD1306_EL83_EDITION_auto. Всё в нем нравится вроде все правильно выводит до 10 kГц, мне нужен только шим сигнал мерять с ардуины и управлять базой симисторов и полевиков, ну и в режиме генератора подать шим. У меня в режиме осцилографа не показывается вертикальный спад сигнала, выводит только штрихи по горизонтали верхние и нижние. И толщина кривой слишком тонкая. Кто знает как подправить.
Ps форум пролистал от корки до корки три раза.

ironcover
Offline
Зарегистрирован: 29.11.2020

Дубль получился

ironcover
Offline
Зарегистрирован: 29.11.2020

Нужна помощь.
Залил скеч от el83 который с авто синхронизацией: SSD1306_EL83_EDITION_auto. Всё в нем нравится вроде все правильно выводит до 10 kГц, мне нужен только шим сигнал мерять с ардуины и управлять базой симисторов и полевиков, ну и в режиме генератора подать шим. У меня в режиме осцилографа не показывается вертикальный спад сигнала, выводит только штрихи по горизонтали верхние и нижние. И толщина кривой слишком тонкая. Кто знает как подправить.
Ps форум пролистал от корки до корки три раза.
Закину чуть позже проект в протеусе рабочий, поможет новичкам темы.

ironcover
Offline
Зарегистрирован: 29.11.2020

Вот ссылка проект протеус oled 128x64:

https://my-files.su/4x79y8/Vremenniy.zip

Proteus 8.9 SP2 Pro Portable какчаем с rutracer

AdmiralBlack
Offline
Зарегистрирован: 13.09.2016

Подскажите, пожалуйста, как быть, если на Ардуино вместо нормального кварцевого резонатора припаян smd керамический трёх выводной резонатор. Можно как то такую плату разогнать или заменить керамический резонатор на нормальный кварц. Хапнул не подумавши 10 шт. Чего их теперь в помойку.

AdmiralBlack
Offline
Зарегистрирован: 13.09.2016

Подскажите, пожалуйста, как быть, если на Ардуино вместо нормального кварцевого резонатора припаян smd керамический трёх выводной резонатор. Можно как то такую плату разогнать или заменить керамический резонатор на нормальный кварц. Хапнул не подумавши 10 шт. Чего их теперь в помойку.

volodya198024
Offline
Зарегистрирован: 26.12.2016

Можно. Я припаивал большой (27 МГц). И капельку термоклея для фиксации.

progrik
Offline
Зарегистрирован: 30.12.2018

потер... было много лишних букв...

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

AdmiralBlack пишет:
Подскажите, пожалуйста, как быть, если на Ардуино вместо нормального кварцевого резонатора припаян smd керамический трёх выводной резонатор. Можно как то такую плату разогнать или заменить керамический резонатор на нормальный кварц. Хапнул не подумавши 10 шт. Чего их теперь в помойку.

Зачем в помойку?

Использовать в тех проектах, для которых их характеристики подходят.

Xumuk
Xumuk аватар
Offline
Зарегистрирован: 03.03.2016

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

fly245
fly245 аватар
Offline
Зарегистрирован: 25.08.2013

Ткните носом по схемотехнике финальную версию на 5110.Залил скетч,зависло на адафруитском логотипе,дальше не идет.Скетч со страницы автора,плата-arduino uno

Xumuk
Xumuk аватар
Offline
Зарегистрирован: 03.03.2016

подтяжка кнопок сделана?

fly245
fly245 аватар
Offline
Зарегистрирован: 25.08.2013

Xumuk пишет:

подтяжка кнопок сделана?

А разве меню без кнопок не должно появиться?

OLEGsan
Offline
Зарегистрирован: 03.02.2021

Дим пишет:

Здравствуйте, собрал девайс с экраном 2.4 tft ili9341. Но он от подсветки прилично греется. Можно ли как то программно убавить яркость?

Получил такой-же дисплей как у вас (вместо SPFD 5408 ,указанного у автора)

Он у вас работает на родном скетче (с сайта srukami)  или вы использовали другие библиотеки?

-кстати алиехспресс вернул деньги за дисплей (в споре привёл фото своего экрана без встроенного стаба)-

progrik
Offline
Зарегистрирован: 30.12.2018

OLEGsan пишет:
...или вы использовали другие библиотеки?
__а как вы id узнали?__ если китаец сказал - ну из китайца такой себе даташыт))
если дисплей вернул (скетч показал) - то все вроде должно работать.
на какой библиотеке заводится дисплей, ту и используйте. или попробуйте MCUFRIEND_kbv - это одна из самых быстрых из самых медленных библиотек, что я видел)) (просто, все библиотеки медленные))
еще, скорее всего, придется вручную прописывать id дисплея...
в setup что-то вроде id = tft.readID(); вместо этого нужно прописать id = 0x9341;
если не заводится на 0x9341, можно попробовать указывать другие чипы со схожим разрешением..
и вот это ID - это касается практически любой библиотеки, патамушта китайские дисплеи редко отдают свой id... по крайней мере у меня счет 3:0
так что, если не заводится - качайте всякие разные библиотеки, смотрите код примеров, ищите и меняйте id и пробуйте, пробуйте, пробуйте...

OLEGsan
Offline
Зарегистрирован: 03.02.2021

Спасибо.Буду пробовать.

ID узнал библиотекой "diagnose_TFT_support" из MCUFRIEND_kbv-master.

И попутно хотел узнать- ID своего дисплея в скетч надо вставлять?

Тестовые скетчи из папки examples проходят.Но вот дальше я не сдвинулся.

Исправил в скетче #include <Adafruit_TFTLCD.h> // Hardware-specific library

на #include <MCUFRIEND_kbv.h> // Hardware-specific library

И далее в скетче названия библиотеки тоже изменил.

Скетч компилируется ,загружается но ничего(белый экран)

Alexjon
Offline
Зарегистрирован: 01.01.2021

fly245 пишет:

Ткните носом по схемотехнике финальную версию на 5110.Залил скетч,зависло на адафруитском логотипе,дальше не идет.Скетч со страницы автора,плата-arduino uno

Попробуйте использовать ide 1.6.5 версию, на новых версиях почему то не получается прошить.

OLEGsan
Offline
Зарегистрирован: 03.02.2021

OLEG

progrik
Offline
Зарегистрирован: 30.12.2018

OLEGsan пишет:
Скетч компилируется ,загружается но ничего(белый экран)
нужно смотреть, как инициализируется дисплей в примере, который работает. сравнить с тем, что в скетче. исправить.
если дисплей возвращает ID, то в скетче можно не писать, но я бы прописал - меньше памяти съест. (сначала прописать в тестовом скетче, убедиться что id рабочий) ну и потом в скечте ослика поменять и посмотреть.
если не взлетит - сразу после инициализации дисплея в setup попробовать вставить что-нибудь из скетча-примера, например
tft.fillScreen(0x0000); //заливка черным
tft.drawFastHLine(10,10, 100, 0xF800); //красная линия
и дальше ставишь паузу delay(10000); чтобы увидеть, что происходит. или нет)
если работает - перемещай строки с выводом и паузой дальше по тексту, пока не исчезнет вывод. так найдешь место затыка...
дальше по обстоятельствам...

 

OLEGsan
Offline
Зарегистрирован: 03.02.2021

Всем спасибо запустил.

Не совсем понял про замену кварца в PULTOSCOPE_TFT с экраном 2.4.

В скетче что-то под кварц 27 Мгц надо менять ?

 

progrik
Offline
Зарегистрирован: 30.12.2018

дык, ищется число, похожее на 16, где-то наверху в дефайнах наверное, и меняется на 27... или проверить, может 27 уже там стоит...

Dotoro
Offline
Зарегистрирован: 14.02.2021

Привет, портирую замечательный проек японца RadioPench (http://radiopench.blog96.fc2.com/blog-entry-1043.html)
на  ESP32 для дисплея ILI9341  с помощью библиотеки "U8g2_for_Adafruit_GFX"
Пока в процессе но вроде получаеться, скажите плиз насколько это вообще имеет смысл
вроде бы проект японца получше, больше фич и поддержка ESP32 что с частотой 240мгц даст больший предел
измерений.

Alex-Bee
Offline
Зарегистрирован: 13.03.2020

Dotoro пишет:

насколько это вообще имеет смысл

Это вам решать. Обсуждалось тут уже. Автор забросил свой проект, назвав его бесперспективным. Отметив, что "вход АЦП ESP32 имеет большую ошибку при входе с высоким импедансом". Это проявляется невозможностью программно устранить спонтанное смещение нуля без дополнительной обвязки (как минимум - ОУ по входу).
"Если вы используете его для нормального считывания значения датчика (с низким выходным сопротивлением), существует высокая вероятность того, что этой проблемы не возникнет".
Если ОУ по входу - "это отклоняется от цели создания осциллографа с максимально простой схемой, так что это не то".

Так что: если вам подходит то, что не подошло японцу, можете пробовать...
 

Dotoro
Offline
Зарегистрирован: 14.02.2021

Да, я вкурсе поведения adc ESP32 это давно известная проблемма, и некоторые полу решения есть даже без использования adc модулей, вот к примеру алгоритм коррекции
https://www.instructables.com/Do-You-Know-About-ESP32-ADC-Adjustment/

насчет нуля пока не знаю, в любом случае я хочу сначала повторить проект а  уже потом улучшать (если получиться)

Alex-Bee
Offline
Зарегистрирован: 13.03.2020

Dotoro пишет:

насчет нуля пока не знаю

Этой части автор тоже уделил много времени и описал испробованное на странице:
http://radiopench.blog96.fc2.com/blog-entry-1040.html
Улучшения аналоговой входной цепи ESP32, убираем смещение
Тут и о "смещении нуля" и о "8%-ой «мёртвой зоне» в районе нуля"...
Именно после этих изысканий он и решил отказаться от дальнейшего развития проекта...

Dotoro
Offline
Зарегистрирован: 14.02.2021

Alex-Bee пишет:

Dotoro пишет:

насчет нуля пока не знаю

Этой части автор тоже уделил много времени и описал испробованное на странице:
http://radiopench.blog96.fc2.com/blog-entry-1040.html
Улучшения аналоговой входной цепи ESP32, убираем смещение
Тут и о "смещении нуля" и о "8%-ой «мёртвой зоне» в районе нуля"...
Именно после этих изысканий он и решил отказаться от дальнейшего развития проекта...

Грусненько, тоесть получаеться пультоскоп на ардуино нано в этом вопросе получше будет?
а также проект RadioPencha на ардуинке лучше esp32?

progrik
Offline
Зарегистрирован: 30.12.2018

Dotoro пишет:
, тоесть получаеться пультоскоп на ардуино нано в этом вопросе получше будет?
у нано при хорошем разгоне АЦП форма сигнала - это условность. дуня с кварцем 27МГц даст всего 1 MSPS - 1 Мега Семпл/сек, и то уже кривых) меандр 20+ КГц становится кривым синусом. так, чисто пощупать. если нужно что-то побыстрее раз в 10+ можно поискать проекты на stm32, их есть и с внешним ацп (100+- MSPS), и без него (до 10 MSPS).
по крайней мере хексы точно есть. за исходники не знаю, не искал, не нуждаюсь)
но там без операционного усилителя никак...
да и ардуино не сильно блещет без оного. как-то нужно было глянуть ШИМ 12В. глянул через резисторный делитель... вместо прямоугольника увидел треугольник) при этом, без делителя показывало прямоугольник (рискнул и кратковременно сунул щуп в 12В без делителя - дуня выдержала)) на этом я остановился)

Alex-Bee
Offline
Зарегистрирован: 13.03.2020

А если ещё Мегу на её клон поменять - LGT8F328P... у которого, как пишут:
АЦП вполне годный, и, на мой взгляд, существенно превосходит АЦП Atmega 328.
И тактовая частота у него - до 32МГц.
http://arduino.ru/forum/apparatnye-voprosy/obzor-klona-megi328-lgt8f328p?page=6#comment-589320
Я на эту платку заливал гайверовскую цветомузыку под Мегу, так даже править в скетче ничего не пришлось: скомпилировался, залился, заработало...

NickF
Offline
Зарегистрирован: 11.12.2020

Alex-Bee пишет:

А если ещё Мегу на её клон поменять - LGT8F328P... у которого, как пишут:
АЦП вполне годный, и, на мой взгляд, существенно превосходит АЦП Atmega 328.
И тактовая частота у него - до 32МГц.

32 МГц внутренний генератор, АЦП - 12 бит и встроенный ОУ. Не родился наверно еще такой разработчик, который бы все это использовал.

Shurik2975
Offline
Зарегистрирован: 30.01.2019

Добрый вечер. Подскажите пожалуйста как вот в этом скетче ТЫЦ програмно перевернуть изображение на 180 градусов. Собрал но ступил не так припаял дисплэйчик ( в верх ногами). И второй вопрос. Где опять таки в этом скетче добавить множитель на 10 чтобы при использовании делителя *10 хотя бы частота отображалась правильно.

progrik
Offline
Зарегистрирован: 30.12.2018

NickF пишет:
32 МГц внутренний генератор, АЦП - 12 бит и встроенный ОУ. Не родился наверно еще такой разработчик, который бы все это использовал.
ну да. ведь 32 МГц и 12 бит освоить куда сложнее, чем 16 МГц и 10 бит))

Alex-Bee
Offline
Зарегистрирован: 13.03.2020

Shurik2975, думаю, вам надо воспользоваться в скетче функцией setRotation().

https://robotchip.ru/obzor-lcd-displeya-nokia-5110/

display.setRotation(2); //поворот на 180

Shurik2975
Offline
Зарегистрирован: 30.01.2019

Спасибо попробую.

 

Hy6yk
Offline
Зарегистрирован: 14.06.2020

Здравствуйте, Уважаемые!

Решил я выложить фото своего пультоскопа. Помнится по началу хотел сделать эдакий "мегакомбайн" - чтоб и транзистор-тестер и пультоскоп и прозвонка и всё всё всё, да и в одном корпусе. Но т.к. объективных причин (ну т.е. потребностей) собирать такой аппарат не было, а лишь изредка, по необходимости на брэдборде собирал пультоскоп чтобы чего-нибудь глянуть, то решил в итоге не заморачиваться сильно и собрать пультоскоп в аскетичном дизайне и разборным для того чтобы ардуинку или дисплей при необходимости вытащить и использовать для чего-нибудь другого.

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

Функционал приборчика только осцил и шим-генератор, ну и настройка экрана. Сам особо ничего не добавлял, только вырезал)). Вход сигнала через делитель 1/2 или 1/10, переключение фиксирующейся кнопкой (синяя справа). Программная коррекция индикации напряжения сигнала в соответствии с включённым в данный момент делителем. Аппаратный замер частоты убрал совсем (не знаю, может зря?). Использовал библиотеку "сайберлиб", которая ещё у bodriy2014 была включена, но почему-то не использовалась - размер скетча немного уменьшает)). Питание по usb - либо от ноута, либо от повербанка.

Alex-Bee
Offline
Зарегистрирован: 13.03.2020

Hy6yk, А у меня вот так вот получилось приспособить "умерший" плеер:

Внутри и аккумулятор и "повышайка" до 5 Вольт. Показывает на экране напряжение батарейки, чтобы в ноль не высадить. Модуль зарядки правда внешний...
В микрофонный разъем щуп-иголку вставил - и вот тебе переносной автономный пробник. Разъем для наушников - PWM выход.

uldin@mail.ru
Offline
Зарегистрирован: 15.02.2012

Мне бы схему и исходники этой версии. uldin@mail.ru

Alex-Bee
Offline
Зарегистрирован: 13.03.2020

uldin@mail.ru, не знаю к кому вы обращаетесь, но схема тут, почти везде, одна ;):
http://srukami.inf.ua/pultoscop_v25110.html

Hy6yk
Offline
Зарегистрирован: 14.06.2020

Alex-Bee, Симпатишно у Вас вышло!

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

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

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

Hy6yk
Offline
Зарегистрирован: 14.06.2020

uldin@mail.ru пишет:

Мне бы схему и исходники этой версии. uldin@mail.ru

Да, к кому это обращение? 

uldin@mail.ru
Offline
Зарегистрирован: 15.02.2012

Hy6yk

Hy6yk
Offline
Зарегистрирован: 14.06.2020

Завтра постараюсь нарисовать схему и выложу скетч.

uldin@mail.ru
Offline
Зарегистрирован: 15.02.2012

Можно в личку - uldin@mail.ru

Hy6yk
Offline
Зарегистрирован: 14.06.2020

uldin@mail.ru пишет:

Можно в личку - uldin@mail.ru

Выложу здесь, и продублирую на мыло. 

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

Итак, общая информация:

 - Функционал урезан до собственно осцила, шим-генератора и меню экрана.

 - Аппаратный замер частоты отключил (закомментировал) и потому пин D5 с A3 не соединял. 

 - Питание прибора через usb ардуинки

 - Подтяжку  к питанию кнопок ЛЕВО, ОК, ПРАВО делал внешнюю просто для "красоты")), было свободное место над кнопками и несколько резисторов на 47 кОм - эдакий стиль кибер-панк)) При необходимости можно включить подтяжку внутреннюю, раскомментировав соответствующую строку в void setup().

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

 - Сигнальные пины дисплея (CLK, DIN, DC, RST) подключил напрямую к ардуине, пин CE напрямую к земле.

 - Подсветка дисплея через резистор 200 Ом к выводу ардуины.

 - Вход сигнала через делитель - либо 1/2 либо 1/10, переключение фиксирующейся кнопкой с двумя группами контактов. Первая группа контактов (на схеме контакты 1,2,3 кнопки SW1) переключает входной сигнал. Вторая группа контактов (контакты 4,5,6) подтягивает пин указателя включённого делителя к земле, у этого пина включена внутренняя подтяжка к питанию.

 

Распиновка такая:

Подсветка дисплея ->  D2
Пин указателя включённого делителя -> D3
CLK -> D6
DIN -> D7
DC -> D8
RST -> D9
ПРАВО -> D10
Выход ШИМ -> D11
ЛЕВО -> D12
OK ->  D13
Вход сигнала -> А3

Схема

Скетч (имеет комментарии в начале, которые могут быть неактуальны из-за моих переделок)

/* Hy6yk - скетч взял тут  http://arduino.ru/forum/proekty/pultoskop-na-arduino-27mgts?page=88#comment-543439
Вариант пультоскопа для макетки.
Хочу редактировать исходный скетч, а именно:

- ==Сделано== Удалить DDS-генератор
- ==Сделано== Удалить температуру
- ==Сделано== Удалить Медленный осцилл
- ==Сделано== Добавить измерение до 50 вольт 
- ==Сделано== Попробовать ускорить посредством cyberlib.
- ==Сделано== Вывод частоты в Гц или кГц
- Врёт аппаратный замер чатоты? == Пока увеличил границу перехода на аппаратный замер до "APP 5.7" (в итоге всё закоментировал) ==
- ==Сделано== Вставить анимированное меню от Electronik83

*/

//Страница проэкта  <a href="<a href="<a href="http://srukami.inf.ua/pultoscop_v25110.html" rel="nofollow">http://srukami.inf.ua/pultoscop_v25110.html</a>" rel="nofollow"><a href="http://srukami.inf.ua/pultoscop_v25110.html" rel="nofollow">http://srukami.inf.ua/pultoscop_v25110.html</a></a>" title="<a href="<a href="http://srukami.inf.ua/pultoscop_v25110.html" rel="nofollow">http://srukami.inf.ua/pultoscop_v25110.html</a>" rel="nofollow"><a href="http://srukami.inf.ua/pultoscop_v25110.html" rel="nofollow">http://srukami.inf.ua/pultoscop_v25110.html</a></a>" rel="nofollow"><a href="<a href="http://srukami.inf.ua/pultoscop_v25110.html" rel="nofollow">http://srukami.inf.ua/pultoscop_v25110.html</a>" rel="nofollow"><a href="http://srukami.inf.ua/pultoscop_v25110.html" rel="nofollow">http://srukami.inf.ua/pultoscop_v25110.html</a></a></a>
// === От меня [Electronik83] === mailTo: <a href="mailto:gsmkillersevsk@mail.ru">gsmkillersevsk@mail.ru</a>
// 1. Оптимизировал, причесал код
// 2. Сделал красивей главное меню, добавил новый пункт
// 3. Отображение частатоы и напряжения в осцилле при 1Кгц и 2,5в (был баг автора)
// 4. Новый режим - медленный осцилл - доделал...
// 5. Оптимизация.....
// 6. Убрал програмную растяжку сигнала из осцилла (развертка 7 и 8)
// 7. Изменил отрисовку сигнала в осцилле (больше нету этих раздвоений сигнала)
// 8. Убрал нахрен кнопку питания, и все что с ней сязано - проще тумблер (переключатель) поставить...
// 9. Анимировал главное меню. Пофиксил мерцание.
//10. Вставил свое меню генератора, DDS-генератора, терминала.
//11. Добавил немного новой анимации.
//12. Провел эксперимент с DDS-генератором и регулировкой частоты - не сделать.
// === ver19 ==
//13. В осциле - Сделал автосинхронизацию по серединке амплитуды сигнала <= подумать над внешней синхрой !!!
//14. В осциле - показываем масимальное и минимальное значение амплитуды сигнала справа
//15. Оптимизация некоторых участков кода
//16. Атмега теперь сама меряет напряжение своего питания, не надо ничего мультиметром мерять
//17. В осцилле - сделал более удобный вывод верхней строки в осцилле, "устатичил" вывод частоты.
//      - теперь нет этого дерганья из Гц в кГц (и обратно) - просто выводим в Мгц.
//18. Добавил цифровой анализатор (входы A1, A2, A3, A4, A5) - что то мне он не понравился (и мне тоже).
/////////////// smokok ///////////////  
//19. Добавил Авто-опорное 5.0,1.1,0.2 
//20. Добавил Меню экрана (регулировка контрастности и включение подсвеки экрана).
//21. Добавил температуру. Пин термистора (10к) в А0 и +5, доп резистор (10к) в А0 и -5
//22. Разогнал PULTOSCOPE благодаря progrik
//23. Пока только вырезал  UART приемник
//24. И ещё вырезал цифровой анализатор
//25. Благодаря progrik добавил оттключение АвтоРазвёртки на длительное нажатие "ОК"
//    В планах внедрить Коэффициент заполнения
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
//#include <FreqCount.h>
#include <EEPROM.h>
#include <math.h>
#include <PWM.h>

#include "CyberLib.h"

/*
  ####### Описание работы некоторых функций библиотеки <CyberLib.h> #######

********Управление пинами:
  Dx_Out;  - установка пина x как выход
  Dx_In; - установка пина x  как вход
  Dx_Hihg;-  установка высокого уровна на пине x
  Dx_Low; - установка низкого уровня на пине x
  Ax_Read; - чтение аналогового пина x
  Dx_Read; - чтение цифрового пина x
  аналоговые пины в цифровом режиме - D14...D19
  A6 и A7 могут работать только в аналоговом режиме

******** delay_us() и delay_ms()
  Функции delay_us() и delay_ms() можно применять в прерываниях так как они не используют таймер, но следует не забывать что точность этих функций зависит от использования в коде обработчиков прерываний. Если Вы не используете в коде прерывания то и точность будет высокая
  delay_us(n); //где n - задержка в мкс, максимальная задержка может быть не больше 16000мкс
  delay_ms(n); //где n - задержка в мс, максимальная задержка может быть не больше 65000мс это равно 65сек

*********Бесконечный цикл  - уменьшает размер скетча при использовании в void loop()
  Start - Начало цикла
  End - Конец цикла

  ###############################################################
*/
/*Чтобы использовать Конструкцию вида:
  D_in(<предопределенный номер пина>)*/
#define _D_In(x) D##x##_In
#define D_In(x) _D_In(x)
#define _D_Out(x) D##x##_Out
#define D_Out(x) _D_Out(x)
#define _D_High(x) D##x##_High
#define D_High(x) _D_High(x)
#define _D_Low(x) D##x##_Low
#define D_Low(x) _D_Low(x)
#define _D_Inv(x) D##x##_Inv
#define D_Inv(x) _D_Inv(x)
#define _D_Read(x) D##x##_Read
#define D_Read(x) _D_Read(x)
#define _A_Read(x) A##x##_Read
#define A_Read(x) _A_Read(x)


//***************************************************************************************************************************
float VCC; // = 5.0;      // напряжение питания (меряем мультиметром - СТАЛО НЕ НАДО)
Adafruit_PCD8544 display = Adafruit_PCD8544(6, 7, 8, 9); // пины к которым у вас подключен дисплей (CLK,DIN,DC,CE,RST или CLK,DIN,DC,RST а СЕ на GND)
byte contrast; // контрастность дисплея
byte Set = 0; // Настройка экрана
bool BL; // Подсветка

//***************************************************************************************************************************
// Настройки пользователя - можно менять
#define Ekran 2  
//Экран///Pin///Подсветka
#define OVERCLOCK 16  // частота на которой работает Ардуино
#define KEY_L  12 
// кнопка ЛЕВО  (можно любой пин)
#define KEY_OK 13 
// кнопка ОК    (можно любой пин)
#define KEY_R  10 
// кнопка ПРАВО (можно любой пин)
//#define VBAT   5 // любой свободный аналоговый пин для измерения напряжения АКБ 
#define KEY_DELAY 200
#define KEY_PRESSED 0 //progrik: логическое состояние нажатой кнопки 0 или 1

// Переменные, дефайны и прочяя хрень - менять со смыслом
#define GEN_PIN  11  // пин для генератора сигналов (не менять)

#define PIN_DEL 3
// цифровой вход указателя включённого делителя
#define K_DEL_1 2 
// коэффициент первого делителя 
#define K_DEL_2 10 
// коэффициент второго делителя

#define COUNTMAX 252 // максимальное количество пикселей в ленте прокрутки  
#define DISP_W 84 // ширина дисплея, в пикселях

#define BUFSIZE_SHORT 256 //progrik: буфер для рабочего режима, чем короче - тем быстрее отображение. чем длиннее - тем медленнее, но синхра сможет ловить более "растянутый" сигнал
#define BUFSIZE_LONG  512 //progrik: буфер для паузы. старый буфер был 800
#define PAUSE_OFFSET 2    //progrik: смещение графика за один кадр в режиме паузы. если для паузы указан достаточно длинный буфер, то можно увеличить до 2-3-4.., чтоб быстрее мотало
#define APP 5.7           //         2.7) это переход на аппаратный замер
#define NAPR 255          //         это напряжение сигнала
#define LCDX 80

//***************************************************************************************************************************
byte mode = 0; // пункт главного меню
byte menu = 0; // пункт меню
byte adcBuf[BUFSIZE_LONG];
byte vSync = 30;   // уровень синхронизации
bool vRef = 1; // флаг опорного напряжения
bool pause = 0; // флаг режима паузы
byte razv = 4;
int grOffset = 0; // смещение графика в рабочем режиме
byte vMax, vMin;// максимальное и минимальное напряжение сигнала
int kdel = 5;         //bulat  автопредел 1,1/0,2 вольта
bool avtorazv = 1;    // Автоматический выбор развертки
bool flag = 0;
unsigned long ok_last_time; //была ok_press_time
unsigned long ok_start_time;
bool ok_short_press = false;

// Переменные для генератора
int PWM = 50;//стартовое значение ШИМ от 0 до 100 для генератора
unsigned long freq = 500; // стартовое значение частоты в Гц для генератора
unsigned long stepFreq = 0;

int d=0; // можно подменить чем нибудь. count например....
unsigned long count = 0;
long countX=0;

const char modeStr0[] PROGMEM = " Осциллоскоп ";
const char modeStr1[] PROGMEM = "PWM-генератор";
const char modeStr2[] PROGMEM = "  Настройки  ";

//***************************************************************************************************************************
void ShowMode(char y) { // выводим режим работы. y - строка, где рисовать
	display.setCursor(3, y);  
  switch (mode) {
    case 0: lcd_pgm_string(modeStr0); break;
    case 1: lcd_pgm_string(modeStr1); break;
    case 2: lcd_pgm_string(modeStr2); break;
  }
}

//***************************************************************************************************************************
void ShowModeInv(char y) { // выводим режим работы. m - режим, y - строка, где рисовать
  display.drawLine(0, y, 83, y, BLACK);
  display.setTextColor(WHITE, BLACK);
  display.setCursor(0, y+1); display.println(" "); display.setCursor(78, y+1); display.println(" ");  // для красоты только
  ShowMode(y+1);
  display.setTextColor(BLACK);
}

//***************************************************************************************************************************
const unsigned char PROGMEM logoOSC[]={0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x80, 0x00, 0x00, 0x00, 
   0x00, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x60, 0x00, 0x00, 0x00, 
   0x01, 0x80, 0x30, 0x00, 0x00, 0x00, 0x01, 0x80, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 
   0x06, 0x00, 0x0c, 0x00, 0x00, 0x30, 0x06, 0x00, 0x0c, 0x00, 0x00, 0x18, 0x2e, 0xaa, 0xae, 0xaa, 0xae, 0xfc, 0x00, 0x00, 0x06, 0x00, 0x0c, 0x18,
   0x00, 0x00, 0x06, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x18, 0x60, 0x00, 0x00, 0x01, 0x80, 0x30, 0x60, 
   0x00, 0x00, 0x01, 0x80, 0x31, 0xfc, 0x00, 0x00, 0x00, 0xc0, 0x60, 0x60, 0x00, 0x00, 0x00, 0xc0, 0x60, 0x60, 0x00, 0x00, 0x00, 0x60, 0xc0, 0x60,
   0x00, 0x00, 0x00, 0x60, 0xc0, 0x60, 0x00, 0x00, 0x00, 0x31, 0x80, 0x66, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00};
  
const unsigned char PROGMEM logoSET[]={0x0f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00,
   0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00,
   0x5d, 0x5d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00,
   0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00,
   0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00,
   0x00, 0x00, 0x00, 0xc1, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x33, 0x00, 0x00, 0x01, 0xf0, 0x03, 0x33};

const unsigned char PROGMEM logoGEN[]={0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00,
   0x00, 0xf0, 0x3f, 0xfc, 0x0f, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xc0, 0x03, 0xff, 0xc0,
   0x01, 0xfe, 0x0f, 0x00, 0x7f, 0x80, 0x01, 0xf8, 0x1f, 0xe0, 0x3f, 0x80, 0x01, 0xf0, 0x07, 0xf8, 0x0f, 0x80, 0x07, 0xe0, 0x01, 0xfc, 0x07, 0xe0,
   0xff, 0xe3, 0x81, 0xfc, 0x07, 0xfe, 0xff, 0xc7, 0xe1, 0xfc, 0x03, 0xff, 0xff, 0xc3, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xc1, 0xff, 0xfe, 0x03, 0xff,
   0x7f, 0xe0, 0xff, 0xff, 0x07, 0xff, 0x07, 0xe0, 0x3f, 0xff, 0xc7, 0xe0, 0x01, 0xf0, 0x00, 0x1f, 0xff, 0x80, 0x01, 0xf8, 0x00, 0x07, 0xff, 0x80,
   0x01, 0xfe, 0x00, 0x03, 0xff, 0x80, 0x03, 0xff, 0xc0, 0x03, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0,
   0x00, 0xf0, 0x3f, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00};


//***************************************************************************************************************************  
void myDrawPict() {
  for (char a=0; a<27; a++)
    for (char b=0; b<6; b++)
      for (char c=0; c<8; c++) {
        if(pgm_read_byte(&(logoOSC[b+a*6])) & (0x80 >> c)) display.drawPixel((18+c+b*8+count)%COUNTMAX , 9+a, BLACK); // тут потом можно запихать все в двухмерный массив и оптимизировать
        if(pgm_read_byte(&(logoGEN[b+a*6])) & (0x80 >> c)) display.drawPixel(18+c+b*8+count- 84   , 9+a, BLACK);      // и отсекать отрисовку ненужных массивов
        if(pgm_read_byte(&(logoSET[b+a*6])) & (0x80 >> c)) display.drawPixel(18+c+b*8+count-168   , 9+a, BLACK);

    }
}

//***************************************************************************************************************************
/*void print_My_Ver(void) {
  display.setTextColor(BLACK);
  display.setCursor(10, 37);
  display.print("Версия ");
  display.print("1.00"); 
}*/

//***************************************************************************************************************************
// ==== Считывание напряжения питания ардуинки (Vcc) ====
#define Vref11 1.095 // для точной подстройки результата измерений
float ReadVcc() {
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // устанавливаем вход АЦП на VCC !!!
  delay(1);  // задержка для устаканивания АЦП. Можно её избежать, если ADMUX как в строке выше (не менялся)
  ADCSRA |= _BV(ADSC);                                    // запуск АЦП преобразования
  while (bit_is_set(ADCSRA, ADSC));                       // ждем, пока АЦП отработает (выставит бит)
  return (Vref11 * 1023.0) / (ADCL | (ADCH << 8));        // результат преобразования в вольтах
}

//***************************************************************************************************************************
void setup()  {

D_In(PIN_DEL); D_High(PIN_DEL); // Устанавливаем пин делителя на вход и включаем подтяжку к питанию

  ////////////////////////////Экран//////////////////////////////
  //  Примечание. Экран становится темным,  решение проблемы.///////////////////////////////////////
  //EEPROM.write(0, 50);  //  Записать закрытую строку,  Вгрузить,  и начать использовать.
  contrast = EEPROM.read(0);
  BL       = EEPROM.read(1);
  D_Out(Ekran); //Устанавливаем пин подсветки экрана на выход
  digitalWrite(Ekran, BL);
  //////////////////////////////////////////////////////
  D_In(KEY_OK); D_In(KEY_L); D_In(KEY_R); // настраиваем кнопки на вход
  //D_High(KEY_OK); D_High(KEY_L); D_High(KEY_L); //раскоменнтировать для включения внутренней подтяжки к питанию
  display.begin();
  display.setContrast(contrast);
  VCC = ReadVcc();
 

///////  *********************************** Отсюда идёт тест анимированного скрола  ***********************************//////////

  count = 1; countX=-1; // нужно для вывода первого режима при включении приборчика
	mode=0;

  while (D_Read(KEY_OK) != KEY_PRESSED) { // цикл, пока не нажали кнопку ОК
    // опрос кнопок
    if (D_Read(KEY_R) == KEY_PRESSED) { countX=-3; if (mode ==0) count=COUNTMAX; mode++; if (mode==3  ) mode = 0; count+=countX;}
    if (D_Read(KEY_L) == KEY_PRESSED) { countX=+3; if (count==COUNTMAX) count=0; mode--; if (mode==255) mode = 2; count+=countX;}

    while (countX!=0) { // если нужно анимировать (скролл)
      display.clearDisplay();  // чистим буфер экранчика
      // динамическая графика в скролле
      for (char a=3; a<14; a+=2) {
        display.drawFastVLine((count+a)%DISP_W+68   , a+4, 37-2*a, BLACK); // полосочки по бокам        
        display.drawFastVLine((count-a+83)%DISP_W-68, a+4, 37-2*a, BLACK);       
      }
      myDrawPict(); // 16..20ms. Если рисовать drawBitmap, то в два раза дольше...
	  display.drawRect(0, 0, 84, 5, BLACK); // прямоугольник вместо батарейки
      //display.drawRect(0, 0, 83, 5, BLACK); display.drawFastVLine(83, 1, 3, BLACK); // корпус батарейки + плюс
      //display.drawFastHLine(0, 1, d-1, BLACK); display.drawFastHLine(0, 2, d, BLACK); display.drawFastHLine(0, 3, d+1, BLACK); // рисуем значение батарейки
      if(count % 84 == 0) { // если больше не надо скроллить
        countX=0; // говорим, что скроллить не надо и работаем со статикой...
        ShowModeInv(39);
        display.drawRect(16, 7, 52, 31, BLACK); // рамка вокруг картинки
		display.drawRect(0, 0, 84, 5, BLACK); // прямоугольник вместо батарейки
        //display.drawRect(0, 0, 83, 5, BLACK); display.drawFastVLine(83, 1, 3, BLACK); // корпус батарейки + плюс
      }
      count += countX;
      display.display();       
    }

/* // Пока не выводим напряжение батарейки
    display.setCursor(4, 0);  // выводим напряжение батареи
    display.setTextColor(WHITE, BLACK);
    display.print(" V_bat=");
    display.print(A_Read(VBAT)*VCC / 1024, 1);
    display.print(" V ");
    display.display();    
    */
  } // цикл нажатия ОК  
  // нажали кнопку ОК из меню, инициализируем и выходим из меню
  count=0; countX=0; // восстанавливаем на всякий случай переменные

	//if (mode == 0) FreqCount.begin(1000);
	if (mode == 1) {
    InitTimersSafe();
    bool success = SetPinFrequencySafe(GEN_PIN, freq);
    pwmWrite(GEN_PIN, PWM * 2.55);
  }
//  if (mode == 2) razv = 0;

  
  // антидребезг кнопки ОК
  for (char a = 37; a > 0; a -= 2) {
    display.clearDisplay();  // - это вместо delay(200);
    ShowModeInv(a);
    display.display();
  }
  ok_last_time = millis(); //progrik: запоминаем время последнего нажатия
	
	delay(500);

}
 ///////  *********************************** Досюда идёт тест анимированного скрола  ***********************************////////// 

// безконечный цикл - по сути прыгаем в подпрограммы
void loop() {
  Start
  switch (mode) { // Прыгаем в выбранный режим из главного меню
    case 0 : Oscil();        break; // "выпадаем" в осцилл
    case 1 : Generator();    break; // "выпадаем" в генератор
    case 2 : Menu_ekrana();  break; // "выпадаем" в меню экрана
  }
  End
}

//***************************************************************************************************************************
//  === Читаем с АЦП данные и помещаем их в буфер === //
void ReadAdc() {
  uint16_t len;
  len = (pause) ? BUFSIZE_LONG : BUFSIZE_SHORT;
  if (razv % 10) { // (razv>0)        // если развертка без задержек всяких (с 1 по 7)
    ADCSRA = 0b11100000 | (8 - (razv % 10)); // установили делитель (/2 - не работает, так что начинаем с /4)
    for (uint16_t i = 0; i < len; i++) { // цикл для чтения
      while (!(ADCSRA & 0x10));     // ждем готовность АЦП
      ADCSRA |= 0x10;               // запускаем следующее преобразование
      adcBuf[i] = ADCH;             // записываем данные в массив
    }
    //    delay(0.3 * BUFSIZE);           // компенсация задержки по сравнению с разверткой 0...
  } else {                          // развертка с задержками (delay)
    ADCSRA = 0b11100111;            // делитель на /128
    for (uint16_t i = 0; i < len; i++) { // цикл для чтения
      while (!(ADCSRA & 0x10));     // ждем готовность АЦП
      ADCSRA |= 0x10;               // запускаем следующее преобразование
      delayMicroseconds(500);       // делаем задержку
      adcBuf[i] = ADCH;             // записываем данные в массив
    }
  }
}
//***************************************************************************************************************************
//progrik: для расчета напряжений ---------------
void calc_val()
{
  vMax = 0; vMin = 0xFF;
  uint16_t l = (pause) ? BUFSIZE_LONG : BUFSIZE_SHORT;
  for (uint16_t x = 0; x < l; x++) {
    if (vMax < adcBuf[x]) vMax = adcBuf[x];  // пока 255, но надо экспериментировать
    if (vMin > adcBuf[x]) vMin = adcBuf[x];
  }

  // == Вычисляем максимальное и минимальное значение сигнала == //
  vSync = (vMax - vMin) / 2 + vMin; // уровень синхронизации по середине уровня сигнала
  // == Определение точки синхронизации == //
  bool flagZero = 0; grOffset = 0; // сброс флага и точки синхронизации
  // Ищем перепад от меньшего уровня к большему
  for (uint8_t x = 1; x < BUFSIZE_SHORT - LCDX; x++) { // смотрим весь массив данных АЦП
    if (adcBuf[x] < vSync) flagZero = 1; // нашли меньше, чем синхра (перепад сигнала в минус) - ставим флаг
    if (flagZero && adcBuf[x] > vSync) {
      grOffset = x;  // нашли больше, чем синхра (перепад сигнала в плюс) - запомнили и выходим из цикла
      break;
    }
  }
  // === Считаем частоту сигнала === //
/*  if (vRef && vMax * VCC / NAPR > APP) { // если можем замерить аппаратно - меряем
    if (FreqCount.available()) count = FreqCount.read(); // вывод частоты по готовности счетчика частоты сигнала
  } else { */// === Меряем частоту сигнала программно === //
    flagZero = 0; count = 0; // сброс флага и счетчика
    for (uint8_t x = grOffset; x < BUFSIZE_SHORT - LCDX; x++)  { // смотрим массив от точки синхронизации до конца
      if (adcBuf[x] < vSync) flagZero = 1; // нашли меньше, чем синхра (перепад сигнала в минус) - выставляем флаг
      if (flagZero && adcBuf[x] > vSync) { // нашли больше, чем синхра (перепад сигнала в плюс) - отловили полный период
        switch (razv) { // считем частоту периода
          case 6: count = 1000000 / ((x - grOffset - 1) * 3.25);    break; // делитель 4
          case 5: count = 1000000 / ((x - grOffset)  * 3.25) / 2;  break; // делитель 8
          case 4: count = 1000000 / ((x - grOffset)  * 3.25) / 4;  break; // делитель 16
          case 3: count = 1000000 / ((x - grOffset)  * 3.25) / 8;  break; // делитель 32
          case 2: count = 1000000 / ((x - grOffset)  * 3.25) / 16; break; // делитель 64
          case 1: count = 1000000 / ((x - grOffset)  * 3.25) / 32; break; // делитель 128
          case 0: count = 1000000 / ((x - grOffset)  * 510);     break; // делитель 128 тоже
        }
        break;
      }
    }
 // }
  count = count * OVERCLOCK / 16.0; // пересчет частоты на разные кварцы
}

//***************************************************************************************************************************
// === Осциллоскоп === //
void Oscil() {
  // установка опорного напряжения АЦП и настройка входа АЦП
  ADMUX = vRef ? 0b01100011 : 0b11100011;
label_ReadAdc:
  // === Обработка кнопок === //
  if (D_Read(KEY_L) == KEY_PRESSED)   switch (menu) { // кнопка лево:)
      case 0 : razv--; if (razv == NAPR) razv = 6; delay(200);                                 break; // меняем развертку
      case 1 : grOffset -= PAUSE_OFFSET; if (grOffset < 0) grOffset = 0;                      break; // листаем график в паузе
    }
  if (D_Read(KEY_R) == KEY_PRESSED)  switch (menu) { // кнопка право:)
      case 0 : razv++; if (razv == 7) razv = 0; delay(200);                                  break; // меняем развертку
      case 1 : grOffset += PAUSE_OFFSET; if (grOffset > BUFSIZE_LONG - LCDX) grOffset = BUFSIZE_LONG - LCDX; break; // листаем график в паузе
    }
  if (D_Read(KEY_OK) == KEY_PRESSED)
   {
     if(ok_short_press && (millis() - ok_start_time) > 600) //progrik: задержка для длинного нажатия
     {
       avtorazv = !avtorazv;   //progrik: переключит авторазвертку после длительного нажатия ^^^ 600ms
       ok_short_press = false;
     }
     if((millis() - ok_last_time) > 200) //progrik: подавление дребезга - ждем 200 мс со времени последнего нажатия
     {
       ok_start_time = millis(); //progrik: запоминаем время первого нажатия кнопки OK
       ok_short_press = true;   //progrik: отмечаем флаг короткого нажатия
     }
     ok_last_time = millis(); //progrik: запоминаем время последнего нажатия кнопки OK
   }
   else
   {
     if(ok_short_press) //progrik: если нужно отработать короткое нажатие (флаг установлен)
     {
       ok_short_press = false; //progrik: снимаем флаг короткого нажатия
       switch (++menu)
       {
         case 1: grOffset = 0; pause = 1; ReadAdc(); calc_val(); break; 
// вход в паузу - антидребезг типа
         case 2: menu = 0;  pause = 0; break; // перебор меню
       }
     }
   }
  // === Ведём рассчеты === //
  if (!pause) { // если нет паузы
    ReadAdc();  // то снимаем осциллограмму
    calc_val();
  } // закончили вести рассчеты

  display.clearDisplay(); // чистим экран...

  // === Отрисовка меню осцилла ===
//Отображение второго диапазона измерений Hy6yk
if (D_Read(PIN_DEL)==HIGH){ // Если на пине указателе включенного делителя высокий сигнал то выводим предел х K_DEL_1
  if (vRef) display.print(VCC * K_DEL_1, 0); else {
if (kdel == 5)display.print(1.1 * K_DEL_1, 1); else display.print(0.22 * K_DEL_1, 1);
  }
  display.setCursor(60, 11); display.print(vMax * K_DEL_1 * (vRef ? VCC : 1.1) / NAPR, 2); // рисуем максимальное значение сигнала х K_DEL_1
  display.setCursor(65, 40); display.print(vMin * K_DEL_1 * (vRef ? VCC : 1.1) / NAPR, 1); // рисуем минимальное  значение сигнала х K_DEL_1
  }
if (D_Read(PIN_DEL)==LOW){ // Если на пине указателе включенного делителя низкий сигнал то выводим предел х K_DEL_2 
  if (vRef) display.print(VCC*K_DEL_2, 0); else {
    if (kdel == 5)display.print(1.1*K_DEL_2,0); else display.print(0.22*K_DEL_2,1);
  }
  display.setCursor(60, 11); display.print(vMax * K_DEL_2 * (vRef ? VCC : 1.1) / NAPR, 1); // рисуем максимальное значение сигнала x K_DEL_2
  display.setCursor(65, 40); display.print(vMin * K_DEL_2 * (vRef ? VCC : 1.1) / NAPR, 1); // рисуем минимальное  значение сигнала x K_DEL_2
  }

  
  if (menu == 0) display.setTextColor(BLACK, WHITE);
  display.setCursor(22, 0);

  display.print(razv); 
  display.print(avtorazv?'a':'p');   // указатель состояния авторазвёртки
  if (menu == 1)
    if (!pause)  display.setTextColor(BLACK);
  else {   // рисуем прокрутку в режиме паузы
  display.setCursor(5, 11); display.print("Pause");  display.drawLine(grOffset / 5.7, 8, grOffset / 5.7 + 7, 8, BLACK); display.drawLine(grOffset / 5.7, 9, grOffset / 5.7 + 7, 9, BLACK);
   }  // шкала прокрутки

display.setCursor(35, 0);
countX=count;
  if (countX<1000) { display.print(countX); display.print("Hz");} // Вывод частоты в герцах
             else  { float countXK=countX/1000.0; display.print(countXK,2); display.print("кHz");} // Вывод частоты в килогерцах
   
  if (vMax == 0xFF) for (uint8_t x = 0; x < 5; x++) display.drawLine(x, 9, x, 47, BLACK); // указатель привышения напряжения на входе осцила

  // == Отрисовка сетки == //
  for (byte i = 47; i > 5; i = i - 7) {
    display.drawLine( 0, i, 2, i, BLACK);  // черточки слева
  }
  for (byte i = 47; i > 5; i = i - 3) {
    display.drawPixel(21, i, BLACK);  // вертикальный пунктир
    display.drawPixel(42, i, BLACK);
    display.drawPixel(63, i, BLACK);
  }
  for (byte i = 3; i < 84; i = i + 3) {
    display.drawPixel(i, 33, BLACK);
    display.drawPixel(i, 19, BLACK);
  }

  ///////////////авто razv//////////////
  if (avtorazv)
#define PER 1.3
  if (count > 4323.3 * PER) razv = 6;
  else if (count > 2434.5 * PER) razv = 5;
  else if (count > 0969.3 * PER) razv = 4;
  else if (count > 0486.8 * PER) razv = 3;
  else if (count > 0245.8 * PER) razv = 2;
  else if (count > 0120.1 * PER) razv = 1;
  else razv = 0;
  //bulat если зашкаливает включаем предел 5 в
  if (vMax == NAPR) {
    if (vRef == 0)
    {
      vRef = 1;
      ADMUX = 0b01100011;// выбор внутреннего опорного 5.0 В
      goto   label_ReadAdc;
    }
  }
  //bulat если  5 в  и уровень менее 1,1 в то вкл предел 1,1 в
  if (vMax <= 55) {
    if (vRef == 1)
    {
      vRef = 0;
      ADMUX = 0b11100011;// выбор внутреннего опорного 1,1В
      goto   label_ReadAdc;
    }
  }
  //bulat здесь автопредел 1,1/0,22 в,программный
  kdel = 5;
  if (vMax <= 55) {
    if (vRef == 0)
    {
      kdel = 1;
    }
  }
  // == Отрисовка графика == //
  for (uint8_t x = 0; x < 80; x++)
    display.drawLine(x + 4, 47 - adcBuf[x + grOffset] / kdel / 1.35, x + 4, 47 - adcBuf[x + grOffset + 1] / kdel / 1.35, BLACK);
  display.display(); // вываливаем буфер экрана на экран
}
////////////////////////////////////////////////////////////////////////////////////////////

//***************************************************************************************************************************
// РЕЖИМ ГЕНЕРАТОРА
void Generator() {
  // обработка кнопок и отрисовка одновременно
  display.clearDisplay();
  ShowModeInv(1);
  if (D_Read(KEY_OK) == KEY_PRESSED) {
    if (menu++ == 7) menu = 0;  // переходим по разрядам / меняем ШИМ
    delay(KEY_DELAY);
  }
  if (menu == 7) { // меняем ШИМ
    if (D_Read(KEY_L) == KEY_PRESSED) {
      PWM--;
      if (PWM < 0)   PWM = 100;
      delay(KEY_DELAY);
    }
    if (D_Read(KEY_R) == KEY_PRESSED) {
      PWM++;
      if (PWM > 100) PWM = 0;
      delay(KEY_DELAY);
    }
    pwmWrite(GEN_PIN, PWM * 2.55); // задали ШИМ
    display.setTextColor(WHITE, BLACK); // если меняем шим, то рисуем его инверсным
    display.drawLine(15, 39, 68 + (PWM == 100 ? 6 : 0) + (PWM < 10 ? -6 : 0), 39, BLACK); // сверху полоска для большей инверсности
  } else { // меняем частоту
    if (D_Read(KEY_L) == KEY_PRESSED) {
      if (freq > stepFreq)  freq -= stepFreq;          // не даем выйти за допустимый диаппазон
      SetPinFrequencySafe(GEN_PIN, freq / (OVERCLOCK / 16.0)); // задали частоту
      delay(KEY_DELAY); // задержка для кнопок
    }
    if (D_Read(KEY_R) == KEY_PRESSED) {
      if ((freq + stepFreq) < 10000000) freq += stepFreq; // не даем выйти за допустимый диаппазон
      SetPinFrequencySafe(GEN_PIN, freq / (OVERCLOCK / 16.0)); // задали частоту
      delay(KEY_DELAY); // задержка для кнопок
    }
    display.setTextColor(BLACK); // если ШИМ не меняем, то выбираем обычный текст
#define XFREQ 14 // ======== // и, выделяем декаду частоты полосочками
    stepFreq = pow(10, (byte)menu); if (menu > 1) stepFreq++; // устраняем глючность pow, почему 10 в степени 2 = 99?
    byte menu_t = menu; if (menu > 2) menu_t++; if (menu == 6) menu_t++; // делаем табуляцию частоты
    menu_t = 54 - menu_t * 6; // считаем положение полосочек
    display.drawLine(menu_t, XFREQ - 2, menu_t + 4, XFREQ - 2, BLACK); // рисуем полоски
    display.drawLine(menu_t, XFREQ - 3, menu_t + 4, XFREQ - 3, BLACK);
    display.drawLine(menu_t, XFREQ + 8, menu_t + 4, XFREQ + 8, BLACK);
    display.drawLine(menu_t, XFREQ + 9, menu_t + 4, XFREQ + 9, BLACK);
  }
  // рисуем уровень ШИМ (инверсия текста задана ранее)
  display.setCursor(15, 40); // ставим курсор))
  display.print(" PWM=");  display.print(PWM);  display.print("% "); // выводим уровень ШИМ
  display.setTextColor(BLACK); // убираем инверсию при выводе частоты
  // рисуем частоту с табуляцией
  display.setCursor(6, XFREQ);
  for (unsigned long freq_t = 1000000; freq_t>0; freq_t/=10) {
  if (freq>=freq_t) {
    display.print((freq/freq_t)%10); if (freq_t==1000000 || freq_t==1000) display.print("'"); }  else { 
    display.print("_");              if (freq_t==1000000 || freq_t==1000) display.print(" "); }
  }
  display.print(" Hz");
  // отрисовка графика PWM
  for (char x = 17; x < 67; ) {
    if (PWM != 0)             display.drawLine(x, 26, x + PWM / 4, 26, BLACK); x += PWM / 4; // верх
    if (PWM != 0 && PWM != 100) display.drawLine(x, 26, x, 36, BLACK);                   // спад
    if (PWM != 100)           display.drawLine(x, 36, x + 25 - PWM / 4, 36, BLACK); x += 25 - PWM / 4; // низ
    if (PWM != 0 && PWM != 100 && x < 43) display.drawLine( x, 36, x, 26, BLACK);        // подъем
  }
  display.display(); // вываливаем буфер на дисплей
}

//***************************************************************************************************************************
//////////////////////////////Экран/////////////////////////////////
void Menu_ekrana() {
  Set = 0; delay(200);

  while (D_Read(KEY_OK) != KEY_PRESSED) {
    display.clearDisplay();
    ShowModeInv(1);
    if (Set == 0) display.setTextColor(WHITE, BLACK); else display.setTextColor(BLACK);
    display.setCursor(0 , 12); display.println("Сontr:"); display.setTextColor(BLACK);
    display.setCursor(60 , 12); display.println(contrast);
    display.setCursor(0 , 22); display.println("Light:"); display.setTextColor(BLACK);
    if (BL == 1) { display.setCursor(60 , 22); display.println("ON");} else
                 { display.setCursor(60 , 22); display.println("OFF");} display.display();
    if (D_Read(KEY_R) == KEY_PRESSED)  contrast++;
    if (D_Read(KEY_L) == KEY_PRESSED)  contrast--;
    if (contrast < 30) contrast = 30;
    if (contrast > 80) contrast = 80;
    display.setContrast(contrast);
//    print_My_Ver(); //вывод информации о версии
    display.display();
    delay(150);
  }
  Set = 1; delay(200);
  while (D_Read(KEY_OK) != KEY_PRESSED) {
    display.clearDisplay();
    ShowModeInv(1);
    display.setCursor(0 , 12); display.println("Сontr:");
    display.setCursor(60 , 12); display.println(contrast);
    if (Set == 1) display.setTextColor(WHITE, BLACK); else display.setTextColor(BLACK);
    display.setCursor(0 , 22); display.println("Light:"); display.setTextColor(BLACK);
    if (BL == 1) { display.setCursor(60 , 22); display.println("ON"); digitalWrite(Ekran, BL); } else
                 { display.setCursor(60 , 22); display.println("OFF"); digitalWrite(Ekran, BL);  }
    if (D_Read(KEY_R) == KEY_PRESSED)  BL=1;
    if (D_Read(KEY_L) == KEY_PRESSED)  BL=0;
//    print_My_Ver(); //вывод информации о версии
    display.display();
    delay(150);
  }
  display.display();
  display.clearDisplay();  // чистим буфер экранчика
  EEPROM.write(0, contrast);
  EEPROM.write(1, BL);
  void (* reboot)(void) = 0;
  reboot();
}

//***************************************************************************************************************************
void SetTextColor(char c) {
  if (c) display.setTextColor(WHITE, BLACK); else display.setTextColor(BLACK);
}

//***************************************************************************************************************************
void lcd_pgm_string(const char *data) {
  unsigned char cc;
  while(1) {
    cc = pgm_read_byte(data);
    if((cc == 0)) return;
     display.write(cc);
    data++;
  }
}

- В скетче некоторые дефайны имеют комментарии на следующей после него строке - если комментарий оставить на той же строке, что и дефайн, то компилятор (ArduinoIDE) ругается. Методом тыка определено, что это те дефайны, которые используются библиотекой сайберлиб.

- Для вывода значений сигнала на дисплее измеренное значение просто умножается на 2 или 10 в зависимости от того какой делитель в данный момент включён.

- Вывод частоты сигнала вернул в Гц и кГц, в исходном скетче, который я курочил, он был просто в Гц