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

Novice User
Offline
Зарегистрирован: 25.09.2017

Electronik83 пишет:

Только что увидел на дисплейчике 5 каналов - для меня - дак мелковато. Думаю, что 4 - самое то!

вот на 4 канала https://www.rlocman.ru/shem/schematics.html?di=113421 ,в обсуждении есть болеесвежие версии,собирал,работает

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Спасибо, интересно. Сам искал- этой статьи не видел. 

Из минусов- другая среда программирования, я привык к АрдуиноИДЕ. Ну и всё-таки хотелось бы с осциллоскопом скрестить, чтоб иметь один универсальный карманный прибор.

Novice User
Offline
Зарегистрирован: 25.09.2017

Там исходник есть,написан  на си,а си и ардуино сами знаете...

Electronik83
Offline
Зарегистрирован: 06.12.2015

Мне дак не понравился алгоритм чтения данных со входов и их буферизация. Уж больно заморочно как то.

smokok
smokok аватар
Offline
Зарегистрирован: 08.06.2018

Может у кого есть такая повышалка на 3.3в. Проверьте пожалуйста частоту стационарным осциллографом, откуда считывал отметил стрелкой. Хотелось бы удостовериться Может ли этот приборчик такое увидеть. 

Electronik83
Offline
Зарегистрирован: 06.12.2015

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

Новый (мой) релиз на подходе.....

smokok
smokok аватар
Offline
Зарегистрирован: 08.06.2018

[

Electronik83 пишет:

Новый (мой) релиз на подходе.....

предновогодний подарок :-). Будет мне тогда чем заняться, Я же люблю что-нибудь переделать под себя.  Например добавить меню экрана и твою автоматику побольше. Мне понравилось как я разместил всю информацию вверху, теперь график сигнала ничто не перекрывает и очень хорошо видно, + сделал сетку пореже. В общем нужно зачерпнуть всё самое лучшее и совместить в одном месте. (+_+)

(Кстати этот повышающий вкинул в мультик чтоб работал от дохлых батареек. От 1.8 раскачивает до 3.3).

Electronik83
Offline
Зарегистрирован: 06.12.2015

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

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Я надеюсь, это не уменьшило поле для отображения осциллограммы?

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Я надеюсь, это не уменьшило поле для отображения осциллограммы?

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Извините, смартфон (

smokok
smokok аватар
Offline
Зарегистрирован: 08.06.2018

seri0shka пишет:
Я надеюсь, это не уменьшило поле для отображения осциллограммы?
Сверху 2 строки под информацию и снизу всё остально место для осциллограммы предостаточно. Есть готовый мелкий шрифт от транзистор тестера, но я не смог его внедрить, запутался))).   https://www.mikrocontroller.net/svnbrowser/transistortester/Software/trunk/fonts/

И всёже как на счёт того чтобы как нить реализовать типо предупреждения если на входе поданно более 5 вольт? Может вывод картинки черепа??? или звуковой сигнал? Думаю многие случайно более 5в тыкали...

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Более мелкий шрифт видел, мне не понравился. И две строки под текст вверху меня пугают, опять придется скрещивать новую версию с предыдущей, а для меня это сложно, особенно с чужим кодом. Свою точку зрения никому не навязываю, но мне в версии 18 число внизу ничуть не мешало. Мне более важна большая картинка.

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

Скажите пожалуйста на какой странице самая свежая прошивка для этого осциллоскопа. Начну собирать Я КОРОБОЧКУ НАШЁЛ.

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Здесь нет понятия "самая свежая". За последние два года опубликовано много прошивок от разных пользователей, у каждой свои достоинства и недостатки, каждый пытается сделать "под себя". Советую начать со страницы автора форума: http://srukami.inf.ua/pultoscop_v25110.html

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

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

Я уже собирал. Роботало,не много переделывал под себя, кварц менял, У меня хорошо работал на 24Мгц. Затем розобрал. Прошло пол года. Теперь хочу занова собрать. Поэтому и прошу. Я вижу в нем появился транзистор тестер. В ПО не силён. Поэтому радуюсь тому что есть. Вот-бы ещё вход внешней синхронизации. Было-бы замечательно. 

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

http://arduino.ru/forum/proekty/pultoskop-na-arduino-27mgts?page=76#comment-403323

Одна из лучших версий от Electronik83 , мне понравилась. Но без тестера.

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

Спасибо на стр 76 нашёл. 

Electronik83
Offline
Зарегистрирован: 06.12.2015
Для экранчика 3310, отличия от 18-ой версии:
// === ver19 == 
//13. В осциле - Сделал автосинхронизацию по серединке амплитуды сигнала <= подумать над внешней синхрой !!!
//14. В осциле - показываем масимальное и минимальное значение амплитуды сигнала справа
//15. Оптимизация некоторых участков кода
//16. Атмега теперь сама меряет напряжение своего питания, не надо ничего мультиметром мерять
//17. В осцилле - сделал более удобный вывод верхней строки в осцилле, "устатичил" вывод частоты. 
//      - теперь нет этого дерганья из Гц в кГц (и обратно) - просто выводим в Мгц.
//18. Добавил цифровой анализатор (входы A1, A2, A3, A4, A5) - что то мне он не понравился
 
https://yadi.sk/d/ZtbYs4qY1YThMwPULTOSCOPE_LCD5110_EL83_19_OK
 
Дальше буду работать надо автоматикой в осцилле.... Всем спасибо:)))
smokok
smokok аватар
Offline
Зарегистрирован: 08.06.2018

Это тебе спасибо!  3310? 5110 пока нервно курит с стороне:-(

Electronik83
Offline
Зарегистрирован: 06.12.2015

smokok пишет:

Это тебе спасибо!  3310? 5110 пока нервно курит с стороне:-(

Ой, опечатался 5110:) Но у меня именно именно 3310 оригинал на моих испытаниях - может по этому у меня контраст не регулируется никак...

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

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

Electronik83
Offline
Зарегистрирован: 06.12.2015

Че там два часа разбираться? Я наверное столько же писал там че то....

Изменил алгоритмы осцилла - нахождение синхры и измерение частоты. Для юзера не заметно, зато кода меньше...

https://yadi.sk/d/92dxQxI3ji02XgPULTOSCOPE_LCD5110_EL83_19.1_OK

Думаю, может отказаться от "аппаратного" замера частоты - пи*ВРЕТ сильно, или я его не так юзаю.....

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Если не нравится аппаратный замер, можно закомментировать, убирать пока не стоит. Нужны лабораторные испытания, чтоб сделать выводы. У меня сейчас возможности нет.
А чем именно вам не понравился анализатор? Довольно перспективное направление. Есть мысль, как увеличить количество выборок с 700 до 1400. Еще бы придумать, как "ловить" нечастые сигналы ( отправку в уарт, например).
Два часа я разбирался, потому что нужно было скетч под свою схему подогнать и добавить кнопку паузы. Вечером попробую 19.1.

Electronik83
Offline
Зарегистрирован: 06.12.2015

Увеличить количество выборок с 700 до 1400 можно - сделать на 4 канала и "ложить" два полубайта в один байт. Но тогда потеряем в максимальной скорости. Ждущий режим тоже реализовать просто - че та типа триггерной развертки...

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

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

Electronik83
Offline
Зарегистрирован: 06.12.2015

Дак со ждущим я вижу один простое решение - ждем, пока все каналы в нуле или в еденице (два варианта).

Реализуется легко:

while ((PINC && mask)==0) {} // ждем, пока каналы в нуле...

Дальше делаем замер...

Но нужно предусмотреть выход из этого цикла по нажатию кнопки.

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Еще и порт неполноценный, сегодня только вспомнил. 6 бит

Electronik83
Offline
Зарегистрирован: 06.12.2015

Дак и что. Нам же нужно только 5 бит с него.

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

У меня в место буков крокозябры. Куда мне ткнутся.

drauger
Offline
Зарегистрирован: 20.02.2018

smokok пишет:

И всёже как на счёт того чтобы как нить реализовать типо предупреждения если на входе поданно более 5 вольт?

Вот в этой схеме http://arduino.ru/forum/proekty/pultoskop-na-arduino-27mgts?page=77#comment-407232 (сообщение 3892) последовательно с верхнм диодом светодиод поставьте и резистор Ом на 150-200. Будет загораться при входном напряжении более 5В. Правда, 220 не выдержит... :-)

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Не будет он загораться! Внутри кристалла стоит такой же диод (только слабее раз в 100), ток потечёт через него. А если бы и засветился светодиод, то на входе было бы напряжение 7,5 вольт при питании 5вольт. Ну и, я думаю, вопрос был о предупреждении на дисплее.

Electronik83
Offline
Зарегистрирован: 06.12.2015

Да блин сделаю я))) делов то строчка кода.

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Череп с костями- перебор. При резисторе хотя бы 4,7 кОм перед измерительным входом Ардуино и с защитными диодами даже 50 вольт не приведёт к серьёзным последствиям. Просто сигнал на дисплее будет обрезан сверху. Предупреждение стоит выодить, если превышение максимума на АЦП не меньше 20% времени, потому как одиночные выбросы и помехи могут проскакивать часто.

Electronik83
Offline
Зарегистрирован: 06.12.2015
Накидал ту самую строчку, думаю должно работать:
 
  if (vMax==0xFF) for(int y=0; y<4; y++) display.drawLine(y,9,y,47, BLACK);
 
 вставлять где нибудь в отрисовке, можно рядом с выводом минимального и максимального значения сигнала, главное попасть между display.clearDisplay() и display.display() ^)))
seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Попробовал дописал, подал на вход 5,5 вольт, выскочил череп с костями, потом дисплей разорвало и посыпались искры. Так и должно было быть?     )))

Electronik83
Offline
Зарегистрирован: 06.12.2015

Да, именно такой смысл в этот код и заложил)))

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Блин, изобретаем велосипед, а оказывается, всё  ̶у̶к̶р̶а̶д̶е̶н̶о̶ изобретено до нас! И полбайта в том числе. И триггеры.

Вот нашёл: http://robocraft.ru/blog/3637.html

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

Я, конечно, сидеть и ждать сложа руки не буду. Тоже буду пробовать.

Electronik83
Offline
Зарегистрирован: 06.12.2015

Позыре на досуге - но выходные - клубы)))

smokok
smokok аватар
Offline
Зарегистрирован: 08.06.2018

Electronik83 пишет:

Ой, опечатался 5110:) Но у меня именно именно 3310 оригинал на моих испытаниях - может по этому у меня контраст не регулируется никак...

Проверил контраст на твоей очередной 19 прошивке добавив код, всё регулируется и подсветка включается. )))) Вобщем на 5110 будет всё работать, добавляй смело, а то у меня чтото криво вышло. При включении картинка заменяется с не активного пункта слевой стороны, а в право прогонишь и все становится на свои места..  Ничего не вырезал, картинку сделал к меню экрана. Посмотри плиз что я упустил

//Страница проэкта  http://srukami.inf.ua/pultoscop_v25110.html
// === От меня [Electronik83] === mailTo: gsmkillersevsk@mail.ru
// 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) - что то мне он не понравился
//    Добавил Авто-опорное 5.0,1.1,0.2
//    Добавил Меню экрана (регулировка контрастности и включение подсвеки экрана).

#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <FreqCount.h> 
#include <PWM.h>
#include <EEPROM.h>
// Настройки пользователя - можно менять
#define Ekran     8  //Экран///Pin///Подсветka
#define OVERCLOCK 16  // частота на которой работает Ардуино
float VCC=5.0;        // напряжение питания (меряем мультиметром - СТАЛО НЕ НАДО)
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 4, 3, 2); // пины к которым у вас подключен дисплей
byte contrast; // контрастность дисплея
byte Set=0;       ///////////////////////Экран/////////////////////////////////
bool BL;          /////////////////////////Экран///////////////////////////////
#define KEY_L  11 // кнопка ЛЕВО  (можно любой пин)
#define KEY_OK 12 // кнопка ОК    (можно любой пин)
#define KEY_R  13 // кнопка ПРАВО (можно любой пин)
#define VBAT   A5 // любой свободный аналоговый пин для измерения напряжения АКБ 
#define KEY_DELAY 200

// Переменные, дефайны и прочяя хрень - менять со смыслом
#define GEN_PIN  9  // пин для генератора сигналов (не менять)
#define DDS_PIN  10 // пин для генератора dds (не менять)
byte mode=0; // пункт главного меню
byte menu=0; // пункт меню 

#define BUFSIZE 700
#define LCDX 80
byte adcBuf[BUFSIZE];
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 вольта

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

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

long speedTTL=9600; //скорость терминала 

void ShowMode(char y) { // выводим режим работы. y - строка, где рисовать
const char* const modeStr[] PROGMEM= { " Осциллоскоп ", "  Генератор  ", "DDS-генератор", "UART-терминал", " Снятие АЧХ  ", " Анализатор  ", "*   Экран   *"};
  display.setCursor(3, y);      // задаем позицию на экране
  display.print(modeStr[mode]); // выводим режим работы
}

void ShowModeInv(char y) { // выводим режим работы инверсно. 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 logoDDS[] = { // берем картинку 48x27 и конвертим тут http://git.robotclass.ru/tools/bmptobin.html
  0x07, 0x80, 0x01, 0x00, 0x18, 0x00, 0x0c, 0xc0, 0x01, 0x00, 0x3c, 0x00, 0x18, 0x60, 0x00, 0x00, 0x66, 0x00, 0x18, 0x60, 0x01, 0x00, 0xc3, 0x00, 
  0x30, 0x30, 0x01, 0x01, 0x81, 0x80, 0x30, 0x30, 0x10, 0x03, 0x00, 0xc0, 0x20, 0x30, 0x31, 0x06, 0x00, 0x60, 0x00, 0x30, 0x31, 0x0c, 0x00, 0x30, 
  0x00, 0x18, 0x60, 0x18, 0x00, 0x18, 0x00, 0x18, 0x61, 0x30, 0x00, 0x0c, 0x00, 0x0c, 0xc1, 0x60, 0x00, 0x06, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x6d, 0xb6, 0xda, 0xb6, 0xdb, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x30, 0x04, 0x40, 0x18, 0x00, 
  0x00, 0x70, 0x0d, 0x60, 0x1c, 0x00, 0x00, 0xd0, 0x19, 0x30, 0x16, 0x00, 0x01, 0x90, 0x30, 0x18, 0x13, 0x00, 0x03, 0x10, 0x61, 0x0c, 0x11, 0x80, 
  0x06, 0x10, 0xc1, 0x06, 0x10, 0xc0, 0x0c, 0x11, 0x80, 0x03, 0x10, 0x60, 0x18, 0x13, 0x01, 0x01, 0x90, 0x30, 0x30, 0x16, 0x01, 0x00, 0xd0, 0x18, 
  0x60, 0x1c, 0x00, 0x00, 0x70, 0x0c, 0xc0, 0x18, 0x01, 0x00, 0x30, 0x06, 0x80, 0x10, 0x01, 0x00, 0x10, 0x03};

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 logoGEN[] = {
  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 logoTRM[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc1, 0xc0, 0x00, 0x00, 0x00, 
  0x00, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x01, 0xe0, 0xc0, 0x00, 0x00, 0x00, 0x01, 0xe0, 0xf8, 0x1f, 0x80, 0x00, 0x03, 0x30, 0xee, 0x73, 0x80, 0x00, 
  0x03, 0x30, 0xc6, 0x60, 0x00, 0x00, 0x03, 0xf0, 0xc6, 0x60, 0x00, 0x00, 0x06, 0x18, 0xc6, 0x60, 0x00, 0x00, 0x06, 0x18, 0xee, 0x73, 0x80, 0x00, 
  0x0f, 0x3d, 0xf8, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

const unsigned char PROGMEM logoOSS[] = {
  0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 
  0x00, 0x7f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x01, 0xff, 0xf0, 0x00, 0x00, 0x00, 
  0x01, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x03, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xff, 0xfc, 0x00, 0x00, 0x30, 
  0x07, 0xff, 0xfc, 0x00, 0x00, 0x18, 0x2f, 0xff, 0xfe, 0xaa, 0xae, 0xfc, 0x0f, 0xff, 0xfe, 0x00, 0x0c, 0x18, 0x0f, 0xff, 0xfe, 0x00, 0x0c, 0x30, 
  0x0f, 0xff, 0xff, 0x00, 0x1c, 0x00, 0x0f, 0xff, 0xff, 0x00, 0x1c, 0x60, 0x0f, 0xff, 0xff, 0x80, 0x3c, 0x60, 0x0f, 0xff, 0xff, 0x80, 0x3d, 0xfc, 
  0x0f, 0xff, 0xff, 0xc0, 0x7c, 0x60, 0x0f, 0xff, 0xff, 0xc0, 0x7c, 0x60, 0x0f, 0xff, 0xff, 0xe0, 0xfc, 0x60, 0x0f, 0xff, 0xff, 0xe0, 0xfc, 0x60, 
  0x0f, 0xff, 0xff, 0xf1, 0xfc, 0x66, 0x0f, 0xff, 0xff, 0xfb, 0xfc, 0x3c, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00};

const unsigned char PROGMEM logoDA[] = {
  0x00, 0x00, 0x00, 0x1d, 0x1d, 0xc2, 0x00, 0x00, 0x00, 0x11, 0x14, 0x49, 0x7f, 0xff, 0xff, 0xd9, 0x1c, 0xc1, 0x40, 0x00, 0x00, 0x51, 0x14, 0x49, 
  0x40, 0x00, 0x00, 0x5d, 0xdd, 0xc2, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xd5, 0x55, 0x55, 0x7f, 0xff, 0xff, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x7f, 0xfc, 0x00, 0x40, 0x04, 0x00, 0x40, 0x04, 0x00, 0x40, 0x04, 0x00, 0x40, 0x04, 0x00, 
  0x40, 0x04, 0x00, 0x40, 0x04, 0x00, 0x40, 0x04, 0x00, 0x40, 0x04, 0x00, 0xd5, 0x57, 0xff, 0xd5, 0x57, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x7f, 0x07, 0xf0, 0x7f, 0x07, 0xf0, 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 
  0xd5, 0xfd, 0x5f, 0xd5, 0xfd, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0xe7, 0x9e, 0x79, 0xe7, 0x9e, 0x49, 0x24, 0x92, 0x49, 0x24, 0x92, 
  0x49, 0x24, 0x92, 0x49, 0x24, 0x92, 0x49, 0x24, 0x92, 0x49, 0x24, 0x92, 0xcf, 0x3c, 0xf3, 0xcf, 0x3c, 0xf3};
  
const unsigned char PROGMEM logoSET[] = {
  0x00, 0x3c, 0x20, 0x83, 0xf0, 0x00, 0x03, 0xff, 0x31, 0xc7, 0xf0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x8f, 0x80, 0x1c, 0x0f, 0xff, 0xff, 0xff, 0xe0, 
  0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xfe, 0x1c, 0x03, 0xff, 0xf4, 0x0f, 0xfe, 0x00, 0x07, 0xff, 0x80, 0x01, 0xff, 0xe0, 
  0x0f, 0xff, 0x0b, 0xf0, 0x7f, 0xf8, 0x1f, 0xfe, 0x3f, 0xfc, 0x7f, 0xdc, 0x7e, 0xfc, 0x78, 0xfe, 0x3f, 0x0a, 0x7c, 0xfc, 0x71, 0xfe, 0x1e, 0x00, 
  0x60, 0x78, 0xf3, 0xff, 0x1f, 0xc0, 0x40, 0xf8, 0xef, 0xff, 0x1f, 0xf0, 0x01, 0xf8, 0xef, 0xff, 0x1f, 0xf0, 0x01, 0xfc, 0xff, 0xfe, 0x1f, 0xbe, 
  0x01, 0xfc, 0x7f, 0xfe, 0x3f, 0x1c, 0x03, 0xfc, 0x3f, 0xfc, 0x3f, 0x80, 0x1f, 0xdf, 0x0f, 0xe0, 0x7f, 0x80, 0x3e, 0x1f, 0xa0, 0x05, 0xff, 0x80, 
  0x3e, 0x3f, 0xf6, 0x6f, 0xff, 0xc0, 0x38, 0x3f, 0xff, 0xff, 0xf3, 0xe0, 0x60, 0x3f, 0xff, 0xff, 0xf1, 0xf8, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0xf8, 
  0x00, 0x73, 0xff, 0xf9, 0xc0, 0x18, 0x00, 0xc1, 0x87, 0xc8, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 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)%588 , 9+a, BLACK); 
        if(pgm_read_byte(&(logoSET[b+a*6])) & (0x80 >> c)) display.drawPixel(18+c+b*8+count- 84   , 9+a, BLACK);
        if(pgm_read_byte(&(logoDA [b+a*6])) & (0x80 >> c)) display.drawPixel(18+c+b*8+count-168   , 9+a, BLACK);
        if(pgm_read_byte(&(logoOSS[b+a*6])) & (0x80 >> c)) display.drawPixel(18+c+b*8+count-252   , 9+a, BLACK);
        if(pgm_read_byte(&(logoTRM[b+a*6])) & (0x80 >> c)) display.drawPixel(18+c+b*8+count-336   , 9+a, BLACK);
        if(pgm_read_byte(&(logoDDS[b+a*6])) & (0x80 >> c)) display.drawPixel(18+c+b*8+count-420   , 9+a, BLACK);
        if(pgm_read_byte(&(logoGEN[b+a*6])) & (0x80 >> c)) display.drawPixel(18+c+b*8+count-504   , 9+a, BLACK);
    }
}
// ==== Считывание напряжения питания ардуинки (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()  {  
  
////////////////////////////Экран//////////////////////////////
//  Примечание. Экран становится темным,  решение проблемы.///////////////////////////////////////
//  EEPROM.write(0, 50);  //  Записать закрытую строку,  Обновить  и начать использовать.
  contrast = EEPROM.read(0);
  BL       = EEPROM.read(1);
  pinMode(Ekran, OUTPUT);
  digitalWrite(Ekran, BL);
//////////////////////////////////////////////////////
  pinMode(KEY_OK, INPUT); pinMode(KEY_L, INPUT); pinMode(KEY_R, INPUT); // настраиваем кнопки на вход
  display.begin();
  display.setContrast(contrast);
  VCC = ReadVcc();
  count = 7; countX=7; // нужно для вывода первого режима при включении приборчика
  
  while(digitalRead(KEY_OK)) {  // цикл, пока не нажали кнопку ОК    
    // опрос кнопок  
    if (!digitalRead(KEY_R)) { countX=-7; if (mode==0) count = 588; mode++; if (mode==7  ) mode = 0; count+=countX;}
    if (!digitalRead(KEY_L)) { countX=+7; if (count ==588) count = 0; mode--; if (mode==255) mode = 6; count+=countX;}

    while (countX!=0) { // если нужно анимировать (скролл)
      display.clearDisplay();  // чистим буфер экранчика
      // динамическая графика в скролле
      #define COUNT 84 // ширина дисплея, в пикселях
      for (char a=3; a<14; a+=2) {
        display.drawLine((count+a   )%COUNT, a+4, (count+a   )%COUNT, 40-a, BLACK); // левые  полосочки по бокам
        display.drawLine((count-a+83)%COUNT, a+4, (count-a+83)%COUNT, 40-a, BLACK); // правые полосочки по бокам
      }
      myDrawPict(); // 16..20ms. Если рисовать drawBitmap, то в два раза дольше...
      display.drawRect(0, 0, 83, 5, BLACK); display.drawLine(83, 1, 83,  3, BLACK); // корпус батарейки
      display.drawLine(0, 1, d-2, 1, BLACK); display.drawLine(0, 2, d-1, 2, BLACK); display.drawLine(0, 3, d  , 3, BLACK); // рисуем значение батарейки
      if(count % 84 == 0) { // если больше не надо скроллить
        countX=0; // говорим, что скроллить не надо и работаем со статикой...
        ShowModeInv(39);
        display.drawRect(16, 7, 52, 31, BLACK); // рамка вокруг картинки
        display.drawRect(0, 0, 83, 5, BLACK); display.drawLine(83, 1, 83,  3, BLACK); // корпус батарейки
      }
      count += countX;
      display.display();       
    }
    // динамическая графика не в скролле - рисуем батарейки
    d = analogRead(VBAT)*84.0/1024; // считываем напряжние АКБ при дефолтных настройках АЦП
    display.drawLine(0, 1,  81, 1, WHITE); display.drawLine(0, 2,  81, 2, WHITE); display.drawLine(0, 3, 81 , 3, WHITE); // закрашиваем белым старое значение
    display.drawLine(0, 1, d-2, 1, BLACK); display.drawLine(0, 2, d-1, 2, BLACK); display.drawLine(0, 3, d  , 3, BLACK); // рисуем новое значение батарейки
    //delay(50); // задержка отображения уровня заряда и кнопок заодно    
    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) { InitTimersSafe(); bool success = SetPinFrequencySafe(GEN_PIN, 200000); }
  if (mode==4) razv = 0;
  if (mode==5) { DDRC = 0x00; PORTC=0x00; } // весь порт С (это A0...A5) на вход и без подтяжки 
  // антидребезг кнопки ОК
  for (char a=37; a>0; a-=2) { display.clearDisplay(); ShowModeInv(a); display.display(); } // - это вместо delay(200); 
}
// безконечный цикл - по сути прыгаем в подпрограммы
void loop() {
  switch (mode) { // Прыгаем в выбранный режим из главного меню
    case 0 : Oscil();        break; // "выпадаем" в осцилл
    case 1 : Generator();    break; // "выпадаем" в генератор 
    case 2 : DdsGenerator(); break; // "выпадаем" в DDS генератор
    case 3 : Terminal();     break; // "выпадаем" в USART приемник
    case 4 : OscilSlow();    break; // "выпадаем" в медленный осцилл
    case 5 : LogAnalyzer();  break; // "выпадаем" в анализатор 
    case 6 : Menu_ekrana();  break; // "выпадаем" в меню экрана
  }  
}
//  === Читаем с АЦП данные и помещаем их в буфер === // 
void ReadAdc() {
  if (razv%10) { // (razv>0)        // если развертка без задержек всяких (с 1 по 7)
    ADCSRA = 0b11100000 | (8-(razv%10)); // установили делитель (/2 - не работает, так что начинаем с /4)
    for(int i=0; i<BUFSIZE; i++) {  // цикл для чтения  
      while (!(ADCSRA & 0x10));     // ждем готовность АЦП
      ADCSRA|=0x10;                 // запускаем следующее преобразование
      adcBuf[i]=ADCH;               // записываем данные в массив
    }
    delay(0.3*BUFSIZE);             // компенсация задержки по сравнению с разверткой 0...
  } else {                          // развертка с задержками (delay)
    ADCSRA = 0b11100111;            // делитель на /128
    for(int i=0; i<BUFSIZE; i++) {  // цикл для чтения
      while (!(ADCSRA & 0x10));     // ждем готовность АЦП
      ADCSRA|=0x10;                 // запускаем следующее преобразование
      delayMicroseconds(500);       // делаем задержку
      adcBuf[i]=ADCH;               // записываем данные в массив
    }
  }
}

// === Осциллоскоп === //
void Oscil() {
  // установка опорного напряжения АЦП и настройка входа АЦП
  ADMUX = vRef ? 0b01100011 : 0b11100011;   
   label_ReadAdc:
  // === Обработка кнопок === // 
  if (!digitalRead(KEY_L))   switch (menu) { // кнопка лево:)
//    case 0 : vRef=!vRef;                                                    break; // меняем опорное напряжение
    case 0 : razv--; if(razv==255) razv=6;                                  break; // меняем развертку
    case 1 : grOffset-=20; if (grOffset<0) grOffset=0;                      break; // листаем график в паузе
  }
  if (!digitalRead(KEY_R))  switch (menu) { // кнопка право:)
//    case 0 : vRef=!vRef;                                                    break; // меняем опорное напряжение
    case 0 : razv++; if (razv==7) razv=0;                                   break; // меняем развертку
    case 1 : grOffset+=20; if(grOffset>BUFSIZE-LCDX) grOffset=BUFSIZE-LCDX; break; // листаем график в паузе
  }       
  if (!digitalRead(KEY_OK))  switch (++menu) {
    case 1: grOffset=0; pause=1;  break; // вход в паузу - антидребезг типа
    case 2: menu=0; pause=0;      break; // перебор меню
  }

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

  display.clearDisplay(); // чистим экран...
  // === Отрисовка меню осцилла ===
  if (vRef) display.print(VCC,1); else { 
        if(kdel==5)display.print("1.1"); else display.print("0.2");
        }
  if (menu==0) display.setTextColor(WHITE, BLACK); else display.setTextColor(BLACK);
  display.print(" ");  display.print(razv); 
  if (menu==1) { display.print(" "); display.setTextColor(WHITE, BLACK); delay(200);  display.print(" Пауза "); } else display.setTextColor(BLACK); // тут задержка для компенсации с остальными задержками
  display.setTextColor( BLACK);
  display.print(" ");
  
  if (!pause) display.print (count/1000000.0, 6); // вывод частоты
    else { // рисуем прокрутку в режиме паузы
    display.drawLine(grOffset/8,8,grOffset/8+6,8, BLACK); display.drawLine(grOffset/8,9,grOffset/8+6,9, BLACK); } // шкала прокрутки
 
  if (vRef && vMax*VCC/255 > 2.7) { display.setCursor(42, 0); display.print("^"); }  // если замер аппаратный - "ужирняем" точку
  
  display.setCursor(66, 10); display.print(vMax * (vRef ? VCC : 1.1) / 255, 1); // рисуем максималоное напряжение сигнала  
  display.setCursor(66, 40); display.print(vMin * (vRef ? VCC : 1.1) / 255, 1); // рисуем минимальное  напряжение сигнала  
  if (vMax==0xFF) for(int y=0; y<5; y++) display.drawLine(y,10,y,47, BLACK);     // указатель привышения напряжения на входе осцила
  // == Отрисовка сетки == //
  for(byte i=47;i>5;i=i-7) { display.drawLine( 0, i, 2, i, BLACK); } // черточки слева 
  for(byte i=10;i>3;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);}    
    //bulat если зашкаливает включаем предел 5 в  
  if (vMax==255){
    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(int y=0; y<80; y++) display.drawLine(y+4, 47-adcBuf[y+grOffset]/kdel/1.5, y+4, 47-adcBuf[y+grOffset+1]/kdel/1.5, BLACK);
  display.display(); // вываливаем буфер экрана на экран
}

// РЕЖИМ ГЕНЕРАТОРА
void Generator() {  
  // обработка кнопок и отрисовка одновременно
  display.clearDisplay();
  ShowModeInv(0);
  if(!digitalRead(KEY_OK)) { if(menu++==7) menu=0; delay(KEY_DELAY); } // переходим по разрядам / меняем ШИМ
  if (menu==7) { // меняем ШИМ
    if(!digitalRead(KEY_L)) { PWM--; if(PWM<0)   PWM=100; delay(KEY_DELAY); }
    if(!digitalRead(KEY_R)) { 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(!digitalRead(KEY_L)) {
      if (freq>stepFreq)  freq-=stepFreq;              // не даем выйти за допустимый диаппазон
      SetPinFrequencySafe(GEN_PIN, freq/(OVERCLOCK/16.0)); // задали частоту
      delay(KEY_DELAY); // задержка для кнопок 
    }
    if(!digitalRead(KEY_R)) {
      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(); // вываливаем буфер на дисплей
}

// === DDS генератор ===
void DdsGenerator() {
  static const byte ddsWave[][32] PROGMEM = {        
    2,10,21,37,57,79,103,127,152,176,198,218,234,245,253,255,253,245,233,218,198,176,152,128,103,79,57,37,21,10,2,0,   // El83_sinNew    
    16,32,48,64,80,96,112,128,143,159,175,191,207,223,239,255,239,223,207,191,175,159,143,128,112,96,80,64,48,32,16,0, // El83_treugNew    
    8,16,25,33,41,49,58,66,74,82,90,99,107,115,123,132,140,148,156,165,173,181,189,197,206,214,222,230,239,247,255,0,  // El83_pilaNew
    255,247,239,230,222,214,206,197,189,181,173,165,156,148,140,132,123,115,107,99,90,82,74,66,58,49,41,33,25,16,8,0 };// El83_pilaObrNew
  const char* const ddsStr[] PROGMEM = { "    Синус", " Треугольник", "    Пила", "Обратная пила"};
  byte ddsCount=0;
  // Рисуем DDS-генератор
  display.clearDisplay(); ShowModeInv(0); // режим работы, заголовок
  for (byte i=0; i<84;) display.drawLine(i, 36-pgm_read_byte(&ddsWave[menu][i%32])/10, i, 36-pgm_read_byte(&ddsWave[menu][(i++)%32])/10, BLACK);
  display.setCursor(3, 40);  display.print(ddsStr[menu]);  display.display(); // отрисовали все  
  while(digitalRead(KEY_R) && digitalRead(KEY_L) && digitalRead(KEY_OK)) { // выводим выбранный сигнал, пока не нажали кнопку
    pwmWrite(DDS_PIN, pgm_read_byte(&ddsWave[menu][(ddsCount++)&0x1F]));
    //ResetAvrCheck();
  }
  if (++menu==4) menu = 0; // нажали кнопку - переключаем режим
  delay(KEY_DELAY); // чтоб кнопки нормально нажимались
}


// UART приемник
void Terminal() {
  const long speedUart[] = { 1200,2400,4800,9600,19200,38400,57600,115200 };
  display.clearDisplay(); 
  ShowModeInv(0);  
  display.setCursor(15,15); display.println("Скорость:");
  display.setTextColor(WHITE, BLACK); 
  display.setCursor(66, 25); display.println("+");
  display.setCursor(13, 25); display.print("-");
  display.setTextColor(BLACK);
  display.println(" ");      
  display.print(speedUart[menu]);
  display.println(" ");
  display.setCursor(9,40); display.println("ОК - запуск");
  if(!digitalRead(KEY_L))  { menu--; if(menu==255) menu=7;   delay(KEY_DELAY);  }
  if(!digitalRead(KEY_R))  { menu++; if(menu==8)   menu=0;   delay(KEY_DELAY);  }
  if(!digitalRead(KEY_OK)) {
    Serial.begin(speedUart[menu]*(16/OVERCLOCK));
    display.clearDisplay();
    display.print(">"); 
    delay(KEY_DELAY);  
    display.display();
    int x=83;
    while (1) {
      //ResetAvrCheck();     
      if (Serial.available()) { // Если в буфере есть данные
        if(++x==84) { // проверяем, не пора ли экран очистить
          x=0;
          display.clearDisplay();
        }
        display.print((char)(Serial.read())); // печать байта в дисплей
        display.display(); // выводим символ
      } 
    }         
  } 
  display.display();  
}

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

void OscilSlow() { 
// надо найти главного тормазоглу!!!!!!!!!
  
  ADMUX = vRef ? 0b01100011 : 0b11100011; // установка опорного напряжения АЦП  
  //ADCSRA = 0b11100110; // делитель частоты АЦП - 64 
  //ADCSRA = 0b11100010; //delitel 4 // кондер не успевает разряжаться
  ADCSRA = 0b11100011; //delitel 8
  ADCSRA|=0x10; // запуск преобразования АЦП
    
  // === Обработка кнопок ===
  if (!digitalRead(KEY_L )) { switch (menu) { // тут идея такая - один раз опрашиваем кнопку, т.к. это медленно делается, потом через кейсы прыгаем.
    case 0 : vRef = !vRef;                      break;   // выбор опорного напряжения
    case 1 : razv--; if (razv==255)  razv=2;    break;   // выбор развертки : 1000мс 500мс 100мс на клетку
    case 2 : grOffset-=10; if(grOffset<0)  grOffset=700; break;  // режим паузы - прокручиваем осциллограмму
    case 3 : for (int y=0; y<700; y++) adcBuf[y] = 0; count=0; grOffset=0;
             display.clearDisplay(); display.setCursor(3, 20); display.print("Буфер очищен!"); 
             display.display(); delay(1000);    break; 
    } delay(200); } // антидребезг кнопки
  if (!digitalRead(KEY_R )) { switch (menu) {
    case 0 : vRef = !vRef;                      break;   // выбор опорного напряжения
    case 1 : razv++; if (razv==3)    razv=0;    break;   // выбор развертки : 1000мс 500мс 100мс на клетку
    case 2 : grOffset+=10; if(grOffset>1402) grOffset=0;  break;   // режим паузы - прокручиваем осциллограмму
  } delay(200); } // антидребезг кнопки
  if (!digitalRead(KEY_OK)) { menu++; if (menu==4) { menu=0; pause=0; } // перебор меню
                                        if (menu==2) { pause=1; 
    adcBuf[(count++)%701] = 255; adcBuf[(count++)%701] = 0; adcBuf[(count++)%701] = 255; if (count>79) grOffset = count - 80; } // отметка паузы на графике
    delay(200);    } // антидребезг кнопки
  // === Отрисовка менюшки ===
  display.clearDisplay();  display.setCursor(0,0);
  SetTextColor(menu==0); if (vRef) display.print(VCC,1); else display.print("1.1");
  SetTextColor(menu==1); display.print(" ");   display.print(razv);
  SetTextColor(menu==2); display.print(" П");  display.print(" ");
  display.print((grOffset%701)/7.04, 0);  display.print("%");
  SetTextColor(menu==3); display.print(" C");
  display.setTextColor( 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);}                                 // горизонтальный пунктир
  // === Отрисовка графика ===    
  for (int y=0; y<80; y++) display.drawLine(y+4, 47, y+4, 47-adcBuf[(y + grOffset)%701]/7, BLACK);
  if (pause) { // если пауза - рисуем шкалу прокрутки
    display.drawLine((grOffset%701)/9,8,(grOffset%701)/9+6,8, BLACK); // шкала прокрутки
    display.drawLine((grOffset%701)/9,9,(grOffset%701)/9+6,9, BLACK); // шкала прокрутки                
  } else { // если не пауза, то снимаем показания
     while (!(ADCSRA & 0x10)); // ждем, пока АЦП считает    
     adcBuf[count%701]=ADCH; // сохраняем число из АЦП в массив
     if (count>79) grOffset = count - 80;
     count++;
     if (count>1401) count=701; // зацикливаем счетчик
     //45мс - программа выполняется
     switch (razv) {
       case 0 : delay(55*(OVERCLOCK/16.0)); break; // секунда на клетку
       case 1 : delay(05*(OVERCLOCK/16.0)); break; // пол секунды на клетку
       case 2 : break; // без задержки.......
     }
  }  
  display.display();    
}

// === Чтение цифровых данных со всего порта C (A0...A5) === // 
void ReadDig() {
  if (razv==9) {
    for(int i=0; i<BUFSIZE; i++) adcBuf[i]=PINC;  // быстро читаем данные
  } else {
    for(int i=0; i<BUFSIZE; i++) { adcBuf[i]=PINC; delayMicroseconds((9-razv)*100); } // читаем данные
  } 
}

// ==== Логический анализатор ==== //
void LogAnalyzer() {
  // обрабатываем кнопки
  if (!digitalRead(KEY_L))   switch (menu) {
    case 0 : razv--; if(razv==255) razv=9; delay(400);                        break;
    case 1 : grOffset-=20; if (grOffset<0) grOffset=0;                        break;    
  }
  if (!digitalRead(KEY_R))  switch (menu) {
    case 0 : razv++; if (razv==10) razv=0; delay(400);                        break;
    case 1 : grOffset+=20; if(grOffset>BUFSIZE-LCDX) grOffset=BUFSIZE-LCDX;   break;
  }       
  if (!digitalRead(KEY_OK))  switch (++menu) { 
    case 1: grOffset=0; pause=1; break; // вход в паузу
    case 2: menu=0;     pause=0; break; // перебор меню
  }
  
  if (!pause) ReadDig(); // если нет паузы - читаем данные

  display.clearDisplay(); // чистим дисплей  
  display.print(razv);    // выводим развертку
  display.print(" ");
  if (pause) { 
    display.print(" Пауза ");
    // рисуем прокрутку в режиме паузы
    display.drawLine(grOffset/8,8,grOffset/8+6,8, BLACK); // шкала прокрутки
    display.drawLine(grOffset/8,9,grOffset/8+6,9, BLACK); // шкала прокрутки
    delay(200); 
  }   
  for(byte i=47;i>12;i=i-7) { display.drawLine( 0, i-5, 2, i-5, BLACK); display.drawPixel(0, i, BLACK); display.drawPixel(2, i, BLACK); } // черточки слева  
  // горизонтальный пунктир
  for(byte i=5;i<84;i=i+3) { display.drawPixel(i,47, BLACK); display.drawPixel(i,40, BLACK); display.drawPixel(i,33, BLACK); display.drawPixel(i,26, BLACK); display.drawPixel(i,19, BLACK); } 
  for (int y=0; y<80; y++) {
  for (int x=0; x<5; x++) { display.drawLine(y+4, 47-(x*7)-(bit_is_set(adcBuf[y+grOffset], 5-x)?5:0), y+4, 47-(x*7)-(bit_is_set(adcBuf[y+1+grOffset], 5-x)?5:0), BLACK);
    }   
  }
  display.display();
} 
//////////////////////////////Экран/////////////////////////////////
void Menu_ekrana() {
  Set=0; delay(200);
  while (digitalRead(KEY_OK)){
    display.clearDisplay();
    if (Set == 0) display.setTextColor(WHITE, BLACK); else display.setTextColor(BLACK);
    display.setCursor(0 , 0); display.println("Контраст:"); display.setTextColor(BLACK);
    display.setCursor(60 , 0); display.println(contrast);
    display.setCursor(0 , 10); display.println("Подсветк:"); display.setTextColor(BLACK);
    if (BL == 1) { display.setCursor(60 , 10); display.println("Вкл");} else
                 { display.setCursor(60 , 10); display.println("Отк");} display.display();
    if (!digitalRead(KEY_R))  contrast++;
    if (!digitalRead(KEY_L))  contrast--;
    if (contrast<30) contrast=30;
    if (contrast>70) contrast=70;
    display.setContrast(contrast); 
    delay(150);
  }
  Set=1; delay(200);
  while (digitalRead(KEY_OK)){
    display.clearDisplay();
    display.setCursor(0 , 0); display.println("Контраст:");
    display.setCursor(60 , 0); display.println(contrast);
    if (Set == 1) display.setTextColor(WHITE, BLACK); else display.setTextColor(BLACK);
    display.setCursor(0 , 10); display.println("Подсветк:"); display.setTextColor(BLACK);
    if (BL == 1) { display.setCursor(60 , 10); display.println("Вкл"); digitalWrite(Ekran, BL); } else
                 { display.setCursor(60 , 10); display.println("Отк"); digitalWrite(Ekran, BL);  }
    if (!digitalRead(KEY_R))  BL=1;
    if (!digitalRead(KEY_L))  BL=0;
    display.display();
    delay(150);
  }
  display.display();
  display.clearDisplay();
  EEPROM.write(0, contrast);
  EEPROM.write(1, BL);
  setup();
}

И за предупреждалку спасибо,   робит))).

Electronik83 пишет:

Дальше буду работать надо автоматикой в осцилле....

Дык я уже авто опорное добавил))) + 0.2 вольта к 1.1 и 5.0. Уже веселей чемто помочь.

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Я, наверное, что-то пропустил. Объясните мне, что за опорное 0,2 вольта? Для чего и откуда?

smokok
smokok аватар
Offline
Зарегистрирован: 08.06.2018

Всё от туда где 1.1 вольта сигнал после 5.0, а если сигнал очень слабёханький ниже 0.2 вольта, то увеличивается осциллограма как 1.1 или 5.0 только будет уже 0.2 и сигнал хорошо виден. Можно ещё режим лупы добавить, но для 5110 будет бильбирда или барбамбия. Теперь там принажатиии ОК сразу в режим паузы попадаешь и не нада дополнительные кнопка паять. Скетч тестовый.

Вродишь всё понятно... :)

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Насчёт увеличения амплитуды я понял, а берётся откуда? 1,1 в берётся от внутреннего источника, а 0,2 в?

smokok
smokok аватар
Offline
Зарегистрирован: 08.06.2018

Извиняюсь, не 0.2 а 0.22в

//bulat здесь автопредел 1,1/0,22 в,программный

bulat943 и Electronik83  лучше знают, это их коды, гдето в середине темы нашел. Попробовал, понравилось :)

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Electronik83, боролся сегодня (и не только) с анализатором. Просмотрел много примеров, сделал следующие выводы:
После входа в режим "анализатор" выбираем скорость (у вас уже реализовано) и тип триггера запуска:
— переход канала из «0» -> «1» (RISE) — "0-1" на дисплее
— переход канала из «1» -> «0» (FALL) — "1-0" на дисплее
— любое изменение на любом канале (BURST) — "ИЗМ" на дисплее
— по кнопке (без триггера) — "OFF" на дисплее
Потом переходим на пункт меню "старт"
Далее ТОЛЬКО после нажатия кнопки ОК и срабатывания триггера начинается запись в буфер до заполнения, после чего автоматически переходим в режим "пауза" для просмотра и прокрутки. В идеале в буфере должны быть ещё несколько выборок, предшествующие срабатыванию триггера, здесь мне не очень понятно пока.
Триггеры реализовать только для одного канала (если нужен другой, просто меняем провода местами, всё-таки анализатор не основная функция в пультоскопе). Практически всё можно сделать на основе вышеупоминаемого анализатора (ссылка в сообщении 3938).
При входе в анализатор можно добавить выбор режима- 1400 выборок на 4 канала (кстати, каналы А0...А3, как в примере) или 700 выборок на 5 каналов (иногда нужно).
Сам пробовал переписывать, пока не очень. Хоть вроде и в примере всё очень доходчиво прокомментировано.
И по другой теме вопрос: не поясните мне про опорное 0,22 вольта, откуда берётся в Атмеге?

renoshnik
Offline
Зарегистрирован: 11.04.2013

https://www.drive2.ru/b/517135229110976754/

может пригодится кому-то.

diksen
Offline
Зарегистрирован: 11.10.2013

Плата вемос версии 1.0.0 базировалась на LGT8F328D он на 20ке только запускался а сейчас продают вемос 1.1.0 она на LGT8F328P так она на внутренней 32ке запускается . Я покупал на алике за $1.65 с юсб-ттл и $1.20 голый.

renoshnik
Offline
Зарегистрирован: 11.04.2013

diksen пишет:
Плата вемос версии 1.0.0 базировалась на LGT8F328D он на 20ке только запускался а сейчас продают вемос 1.1.0 она на LGT8F328P так она на внутренней 32ке запускается . Я покупал на алике за $1.65 с юсб-ттл и $1.20 голый.

все правильно. Просто тут ранее видел пост с картинкой 1.0.0 

 

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

Жду ответа от Electronik83, но он, похоже, не вернулся из клубов после выходных )
Пробовал развивать тему логического анализатора в пультоскопе. Пытался скрестить ужа с ежом, а именно анализатор из последней прошивки от Electronik83 и тот, что я упоминал в посте 3938. Три вечера практически безрезультатно. Привожу код, возможно кто-нибудь укажет на ошибки, а может даже допилит до рабочего состояния. Та логика работы, что в исходнике от Electronik83, не позволяет воспользоваться анализатором по назначению, хотя для постоянных сигналов неплохо. За код не пинайте, я не спец. Привожу только часть, относящуюся к анализатору.

// ==== Логический анализатор ==== //
void LogAnalyzer() {
  // обрабатываем кнопки
 /* После входа в режим "анализатор" выбираем скорость (у вас уже реализовано) и тип триггера запуска:
 — переход канала из «0» -> «1» (RISE) — "0-1" на дисплее
 — переход канала из «1» -> «0» (FALL) — "1-0" на дисплее
 — любое изменение на любом канале (BURST) — "ИЗМ" на дисплее
 — по кнопке (без триггера) — "OFF" на дисплее
 Потом переходим на пункт меню "старт"
 Далее ТОЛЬКО после нажатия кнопки ПРАВО или ЛЕВО и срабатывания триггера начинается запись в буфер до заполнения,
 после чего автоматически переходим в режим "пауза" для просмотра и прокрутки.*/
  if (digitalRead(KEY_L))   switch (menu) {
      case 0 : razv--; if (razv == 255) razv = 9; delay(200);break; // выбор развёртки
      case 1 : trig--; if (trig == 0) trig = 3;              break; // выбор триггера
      case 2 : if (pause) {
          grOffset -= 20;
          if (grOffset < 0) grOffset = 0;
        }
        else read_ = 2; break; // включить ожидание триггера
    }
  if (digitalRead(KEY_R))  switch (menu) {
      case 0 : razv++; if (razv == 10) razv = 0; delay(200);break;
      case 1 : trig++; if (trig == 5) trig = 1;             break;
      case 2 : if (pause) {
          grOffset += 20;
          if (grOffset > BUFSIZE - LCDX) grOffset = BUFSIZE - LCDX;
        }
        else read_ = 2; break; // включить ожидание триггера
    }
  if (digitalRead(KEY_OK))  switch (++menu) {
      case 2: grOffset = 0; read_ = 1; pause = 0; break; // вход в read, включить ожидание чтения
      case 3: menu = 0;     read_ = 0; break; // перебор меню
    }
  if (digitalRead(KEY_P)) { // кнопка ПАУЗА, не обязательно, но удобнее
    menu = 2; grOffset = 0; read_ = 2; pause = 0; // включить ожидание триггера
  }
 
  display.clearDisplay(); // чистим дисплей
  if (menu == 0) display.setTextColor(WHITE, BLACK); else display.setTextColor(BLACK);
  display.print(" "); display.print(razv);  display.print(" "); // печать развёртки
  if (menu == 1) display.setTextColor(WHITE, BLACK); else display.setTextColor(BLACK);
  delay(200);
  if (trig == 1) display.print("0-1"); // печать типа триггера
  if (trig == 2) display.print("1-0");
  if (trig == 3) display.print("ИЗМ");
  if (trig == 4) display.print("OFF");

  if (menu == 2) { // включено ожидание триггера
    display.print(" ");
    display.setTextColor(WHITE, BLACK);
    delay(200);
    if ((read_ == 1))display.print(" START "); //ожидание нажатия
    if ((read_ == 2)) {
      display.print(" Ждём  "); // ожидание срабатывания триггера
     init_logic(); //инициализируем буфер и переменные
  scan_bus(); // считываем состояние порта, пока не сработает триггер
  if (trigger_event) //если триггер сработал

  // далее кусочек кода от Electronik83, нужно заменить на тот, что далее, для увеличения выборки в 2 раза
     {
        if (razv==9) {
    for(int i=0; i<BUFSIZE; i++) adcBuf[i]=PINC;  // быстро читаем данные
  } else {
    for(int i=0; i<BUFSIZE; i++) { adcBuf[i]=PINC; delayMicroseconds((9-razv)*100); } // читаем данные
  }
      //read_bus(); // пишем историю в буфер******* ВОТ ЭТОТ должен работать, но что-то не срослось, возможно ошибка
      pause = 1; //флаг паузы для вывода данных и прокрутки
     }
    }
    if ((pause == 1))display.print(" PAUSE ");
  }

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

  if (pause) {
    // рисуем прокрутку в режиме паузы
    display.drawLine(grOffset / 8, 8, grOffset / 8 + 6, 8, BLACK); // шкала прокрутки
    display.drawLine(grOffset / 8, 9, grOffset / 8 + 6, 9, BLACK); // шкала прокрутки
    delay(200);
  }
  for (byte i = 47; i > 12; i = i - 7) {
    display.drawLine( 0, i - 5, 2, i - 5, BLACK);  // черточки слева
    display.drawPixel(0, i, BLACK);
    display.drawPixel(2, i, BLACK);
  }
  // горизонтальный пунктир
  for (byte i = 5; i < 84; i = i + 3) {
    display.drawPixel(i, 47, BLACK);
    display.drawPixel(i, 40, BLACK);
    display.drawPixel(i, 33, BLACK);
    display.drawPixel(i, 26, BLACK);
    display.drawPixel(i, 19, BLACK);
  }
  for (int y = 0; y < 80; y++) {
    for (int x = 0; x < 5; x++)  {
      display.drawLine(y + 4, 47 - (x * 7) - (bit_is_set(adcBuf[y + grOffset], 5 - x) ? 5 : 0), y + 4, 47 - (x * 7) - (bit_is_set(adcBuf[y + 1 + grOffset], 5 - x) ? 5 : 0), BLACK);
    }
  }
  display.display();
}
//============================================
void scan_bus()
{
  while (!trigger_event)
  {
    // ПЕРВЫМ делом нужно считать данные с шины, а уже потом будем разбираться со всякими сверками и расчетами
    byte cur_data = (PINC & B00001111); //сразу же считываем состояние пинов порта

    // ниже отладочная пришлепка для примерной оценки скорости оцифровки
    // по частоте переключения пина будем судить о скорости

    // данные считаны, теперь проверяем есть ли условия сработки триггера и если ДА, запоминаем номер замера (0-1024)
    switch (trig) //ветвимся в зависимости от режима триггера
    {
      // BURST Mode Любое изменение на любом канале
      case (3):
        if (cur_data != prev_data)
        {
          trigger_event = true; //ставим признак сработки триггера
          StartIndex = 5; // расчет номера замера с которого будем делать вывод

        }
        break;
      //---------------------------------
      // master channel RISE (переход из 0 в 1)
      case (1):
        if (~prev_data & cur_data & 1)
        {
          trigger_event = true; //ставим признак сработки триггера
          StartIndex = 5; // расчет номера замера с которого будем делать вывод
        }
        break;
      //---------------------------------
      // master chanel FALL (переход из 1 в 0)
      case (2):
        if (prev_data & ~cur_data & 1)
        {
          trigger_event = true; //ставим признак сработки триггера
          StartIndex = 5; // расчет номера замера с которого будем делать вывод
        }
        break;
        //---------------------------------
      // без триггера
      case (4):
        {
          trigger_event = true; //ставим признак сработки триггера
          StartIndex = 5; // расчет номера замера с которого будем делать вывод
        }
        break;
        //---------------------------------
    } //End switch (typeTriggerEvent)

    rec_data(cur_data); //запись данных в буффер

  } //end while
}// end load data
//===========================================================

//====== read_bus ============
// тупо пишем состояние каналов
void read_bus()
{
  while (cur_index < BUFSIZE)
  {
    rec_data(PINC & B00001111); //запись данных в буффер
  } //end while
}

//==================
// инициализация перед замерами
//Обнуляем буффер, сбрасываем индексы и запоминаем состояние шины
void init_logic()
{
  cur_index = 0; // сбрасываем счетчик замеров
  StartIndex = 0; // сбрасываем положение начала данных для вывода
  //time_disc=0; // сбрасываем значения интервала одной выборки
  trigger_event = false; //сбрасываем признак сработки триггера
  prev_data = (PINC & B00001111); //сформируем пред. замер состояние пинов порта
} // end logic init
//========================================================
void rec_data(byte cur_data)
{
  if ((cur_index & 1)) //если текущее значение индекса нечетное (нечетные числа в двоичном виде всегда заканчиваются на 1)
  {
    adcBuf[cur_index >> 1] = ((prev_data << 4) | cur_data); // пишим объединённое число так сказать КОМПРЕССИЯ :)
  }

  prev_data = cur_data; //запоминаем текущее состояние шины
  cur_index++; //увеличиваем номер замера
  if (cur_index == 700) cur_index = 0; //если достигли конца буфера - сброс и все сначала
} //end rec_data
//============================================

 Естественно, в начале скетча добавлены все переменные из доработки

volatile int cur_index = 0; //переменная для отсчета замеров
volatile int StartIndex = 0; // номер замера с которого нужно выводить результат (считается так: (замер сработки триггера-предистория))
volatile byte prev_data; // предыдущее состояние шины
volatile byte pattern_mask; // маска для события PATTERN
volatile byte pattern_value; // ЗНАЧЕНИЕ состояния для события PATTERN
volatile boolean trigger_event = false; //признак сработки триггера
volatile int time_disc = 0; // время выборки 1-го значения
unsigned long prevMillis, curMillis;
enum triggerEvents {BURST, MASTER_RISE, MASTER_FALL, PATTERN}; //именнованный список триггеров-событий


byte cmdIndex; // индекс строки для обработки команд

byte typeTriggerEvent;

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

bulat943
Offline
Зарегистрирован: 19.09.2016

2 раза отправилось...