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

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

seri0shka пишет:

Какую бы функцию ещё добавить, чтоб задействовать оставшуюся программнную память?

А собирали по стандартной схеме? Имею в виду номиналы всех резисторов.

По функциям не плохо бы автоматики ещё добавить от Electronik83

Или посмотреть что тут интересного СЫЛКА1 ССЫЛКА2 и адаптировать под 1202.

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

Здравствуйте все. Я просто наблюдаю и что-то повторяю. Мне просто интересно, в ESR-метре есть дисплей большой и красивый и подключается к 328-меге по 6 или 7 проводков. Почему его ни кто не замечает ? вот такой, ну все его знают  ( 2016 V2.68 ESR-T4 Mega328 цифровой Транзистор тестер Диод Триод Емкость ESR метр MOS/PNP/NPN LCR 12864 ЖК-экран)

 

 

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

smokok пишет:

А собирали по стандартной схеме? Имею в виду номиналы всех резисторов.

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

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

без резисторов будут ложные срабатывания кнопок, без них нельзя

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

Внутренних резисторов на 20 кОм вполне достаточно (в скетче включена подтяжка), если к кнопкам не трёхметровые провода.

serhiy58
Offline
Зарегистрирован: 19.06.2019

diksen пишет:

в настройках как минимум когдато будет Контрастность и Вкл.Вкл подсветки - вон пин 2 и прочие аналоговые без дела болтаются

А когда будет продолжение? :-)

- нет еще % заряженности батареи, или хотя-бы напряжения батареи

- фильтр DDS висит на ТТестере

- индикация превышения напряжения (5В) на входе 

- можна организоватть измереие входного напряжения двумя аналоговыми пинами: при превышении входного напряжения (5В) на одном из пинов,  измерение производить с другого пинана, на  который подавать входное с делителя   1:10,  и тогда выводить на экран значение в 10 раз большее...

... Очень ждем, просто с нетерпением...

Пожалуйста, не забрасывайте данный проект...

"Пациент" ждет...

:-)

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

seri0shka

У меня LCD модуль HX1230 меню отображает, но переход по меню не работает, даже вольтметр сразу зависает после включения. ХЗ в чём не стыковка... Уже и корпус подобрал от пульта канд. LG

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

Только что скопировал с форума, залил, всё работает.

1. Какая версия ИДЕ?

2. Если под себя пины в скетче меняли, то весь скетч приведите. Не забудьте свернуть.

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

seri0shka пишет:

Только что скопировал с форума, залил, всё работает.

1. Какая версия ИДЕ?

2. Если под себя пины в скетче меняли, то весь скетч приведите. Не забудьте свернуть.

 версия ИДЕ 1.8.9, все тестовые скетчи работают, загрузчик стоит от Uno. Быстрее загружает и меньше места занимает. Думаю дело не в нём. Просто подключаю экран без кнопок и резисторов.

Пины пробовал как у вас, то же самое.

#define BUFSIZE 600
#define history 50

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}; //именнованный список триггеров-событий
bool flag = 0;

//#include <EEPROM.h>
#define RES 3
#define CS 4
#define Data 6
#define Clock 7
#define swap(a, b) { int t = a; a = b; b = t; }

#include <FreqCount.h>
#include <PWM.h>
// Настройки пользователя - можно менять
#define OVERCLOCK 16  // частота на которой работает Ардуино
float VCC = 5.0;      // напряжение питания
#define KEY_L  11 // кнопка ЛЕВО  (можно любой пин)
#define KEY_OK 12 // кнопка ОК    (можно любой пин)
#define KEY_R  12 // кнопка ПРАВО (можно любой пин)
#define KEY_P  8 // кнопка PAUSE (можно любой пин)
#define KEY_DELAY 200
#define LCDX 96
// Переменные, дефайны и прочяя хрень - менять со смыслом
#define GEN_PIN  9  // 9 пин для генератора сигналов (не менять)
#define DDS_PIN  10 // 10 пин для генератора dds (не менять)

#include <avr/pgmspace.h>
const char string_0[] PROGMEM = "Осциллограф";   // "String 0" и т.д. - это содержимое строк; если необходимо меняйте его
const char string_1[] PROGMEM = "Генератор";
const char string_2[] PROGMEM = "DDSгенератор";
const char string_3[] PROGMEM = "Терминал";
const char string_4[] PROGMEM = "Анализатор";
const char string_5[] PROGMEM = " ";
const char string_6[] PROGMEM = "V bat=";
const char string_7[] PROGMEM = " PWM=";
const char string_8[] PROGMEM = " Pause ";
const char string_9[] PROGMEM = "Частота";
const char string_10[] PROGMEM = "    Синус    ";
const char string_11[] PROGMEM = " Треугольник ";
const char string_12[] PROGMEM = "    Пила     ";
const char string_13[] PROGMEM = "Обратная пила";
const char string_14[] PROGMEM = "Скорость:";
// Теперь создаем таблицу с отсылками к этим строкам:
const char* const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7, string_8, string_9, string_10, string_11, string_12, string_13, string_14};
char buffer[13];    // массив должен быть достаточно велик, чтобы вместить даже самую большую строку

byte symbol1 = 0;
byte symbol2 = 0;
byte symbol3 = 0;
byte mode = 0; // пункт главного меню
byte menu = 0; // пункт меню
byte adcBuf[BUFSIZE];
byte vSync = 30; // уровень синхронизации
bool vRef = 1; // флаг опорного напряжения
bool pause = 0; // флаг режима паузы
byte TextColor = 1;
byte razv = 0;
byte trig = 0;
int grOffset = 0; // смещение графика в рабочем режиме
byte vMax, vMin; // максимальное и минимальное напряжение сигнала
// Переменные для генератора
int PWM = 50; // стартовое значение ШИМ от 0 до 100 для генератора
int temp = 0; // временная переменная***
unsigned long freq = 1000; // стартовое значение частоты в Гц для генератора
unsigned long stepFreq = 0;
unsigned long count = 1;
byte LCD_RAM[96 * 9]; // 96 * 9

static const char font[] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00 ,  // 0x20   space
  0x00, 0x00, 0x5f, 0x00, 0x00 ,  // 0x21   !
  0x00, 0x07, 0x00, 0x07, 0x00 ,  // 0x22   "
  0x14, 0x7f, 0x14, 0x7f, 0x14 ,  // 0x23   #
  0x24, 0x2a, 0x7f, 0x2a, 0x12 ,  // 0x24   $
  0x23, 0x13, 0x08, 0x64, 0x62 ,  // 0x25   %
  0x36, 0x49, 0x55, 0x22, 0x50 ,  // 0x26   &
  0x00, 0x05, 0x03, 0x00, 0x00 ,  // 0x27   '
  0x00, 0x1c, 0x22, 0x41, 0x00 ,  // 0x28   (
  0x00, 0x41, 0x22, 0x1c, 0x00 ,  // 0x29   )
  0x14, 0x08, 0x3e, 0x08, 0x14 ,  // 0x2a   *
  0x08, 0x08, 0x3e, 0x08, 0x08 ,  // 0x2b   +
  0x00, 0x50, 0x30, 0x00, 0x00 ,  // 0x2c   ,
  0x08, 0x08, 0x08, 0x08, 0x08 ,  // 0x2d   -
  0x00, 0x60, 0x60, 0x00, 0x00 ,  // 0x2e   .
  0x20, 0x10, 0x08, 0x04, 0x02 ,  // 0x2f   /
  0x3e, 0x51, 0x49, 0x45, 0x3e ,  // 0x30   0
  0x00, 0x42, 0x7f, 0x40, 0x00 ,  // 0x31   1
  0x42, 0x61, 0x51, 0x49, 0x46 ,  // 0x32   2
  0x21, 0x41, 0x45, 0x4b, 0x31 ,  // 0x33   3
  0x18, 0x14, 0x12, 0x7f, 0x10 ,  // 0x34   4
  0x27, 0x45, 0x45, 0x45, 0x39 ,  // 0x35   5
  0x3c, 0x4a, 0x49, 0x49, 0x30 ,  // 0x36   6
  0x01, 0x71, 0x09, 0x05, 0x03 ,  // 0x37   7
  0x36, 0x49, 0x49, 0x49, 0x36 ,  // 0x38   8
  0x06, 0x49, 0x49, 0x29, 0x1e ,  // 0x39   9
  0x00, 0x36, 0x36, 0x00, 0x00 ,  // 0x3a   :
  0x00, 0x56, 0x36, 0x00, 0x00 ,  // 0x3b   ;
  0x08, 0x14, 0x22, 0x41, 0x00 ,  // 0x3c   <
  0x14, 0x14, 0x14, 0x14, 0x14 ,  // 0x3d   =
  0x00, 0x41, 0x22, 0x14, 0x08 ,  // 0x3e   >
  0x02, 0x01, 0x51, 0x09, 0x06 ,  // 0x3f   ?
  0x32, 0x49, 0x79, 0x41, 0x3e ,  // 0x40   @
  0x7e, 0x11, 0x11, 0x11, 0x7e ,  // 0x41   A
  0x7f, 0x49, 0x49, 0x49, 0x36 ,  // 0x42   B
  0x3e, 0x41, 0x41, 0x41, 0x22 ,  // 0x43   C
  0x7f, 0x41, 0x41, 0x22, 0x1c ,  // 0x44   D
  0x7f, 0x49, 0x49, 0x49, 0x41 ,  // 0x45   E
  0x7f, 0x09, 0x09, 0x09, 0x01 ,  // 0x46   F
  0x3e, 0x41, 0x49, 0x49, 0x7a ,  // 0x47   G
  0x7f, 0x08, 0x08, 0x08, 0x7f ,  // 0x48   H
  0x00, 0x41, 0x7f, 0x41, 0x00 ,  // 0x49   I
  0x20, 0x40, 0x41, 0x3f, 0x01 ,  // 0x4a   J
  0x7f, 0x08, 0x14, 0x22, 0x41 ,  // 0x4b   K
  0x7f, 0x40, 0x40, 0x40, 0x40 ,  // 0x4c   L
  0x7f, 0x02, 0x0c, 0x02, 0x7f ,  // 0x4d   M
  0x7f, 0x04, 0x08, 0x10, 0x7f ,  // 0x4e   N
  0x3e, 0x41, 0x41, 0x41, 0x3e ,  // 0x4f   O
  0x7f, 0x09, 0x09, 0x09, 0x06 ,  // 0x50   P
  0x3e, 0x41, 0x51, 0x21, 0x5e ,  // 0x51   Q
  0x7f, 0x09, 0x19, 0x29, 0x46 ,  // 0x52   R
  0x46, 0x49, 0x49, 0x49, 0x31 ,  // 0x53   S
  0x01, 0x01, 0x7f, 0x01, 0x01 ,  // 0x54   T
  0x3f, 0x40, 0x40, 0x40, 0x3f ,  // 0x55   U
  0x1f, 0x20, 0x40, 0x20, 0x1f ,  // 0x56   V
  0x3f, 0x40, 0x38, 0x40, 0x3f ,  // 0x57   W
  0x63, 0x14, 0x08, 0x14, 0x63 ,  // 0x58   X
  0x07, 0x08, 0x70, 0x08, 0x07 ,  // 0x59   Y
  0x61, 0x51, 0x49, 0x45, 0x43 ,  // 0x5a   Z
  0x00, 0x7f, 0x41, 0x41, 0x00 ,  // 0x5b   [
  0x02, 0x04, 0x08, 0x10, 0x20 ,  // 0x5c   backslash
  0x00, 0x41, 0x41, 0x7f, 0x00 ,  // 0x5d   ]
  0x04, 0x02, 0x01, 0x02, 0x04 ,  // 0x5e   ^
  0x40, 0x40, 0x40, 0x40, 0x40 ,  // 0x5f   _
  0x00, 0x01, 0x02, 0x04, 0x00 ,  // 0x60   `
  0x20, 0x54, 0x54, 0x54, 0x78 ,  // 0x61   a
  0x7f, 0x48, 0x44, 0x44, 0x38 ,  // 0x62   b
  0x38, 0x44, 0x44, 0x44, 0x20 ,  // 0x63   c
  0x38, 0x44, 0x44, 0x48, 0x7f ,  // 0x64   d
  0x38, 0x54, 0x54, 0x54, 0x18 ,  // 0x65   e
  0x08, 0x7e, 0x09, 0x01, 0x02 ,  // 0x66   f
  0x0c, 0x52, 0x52, 0x52, 0x3e ,  // 0x67   g
  0x7f, 0x08, 0x04, 0x04, 0x78 ,  // 0x68   h
  0x00, 0x44, 0x7d, 0x40, 0x00 ,  // 0x69   i
  0x20, 0x40, 0x44, 0x3d, 0x00 ,  // 0x6a   j
  0x7f, 0x10, 0x28, 0x44, 0x00 ,  // 0x6b   k
  0x00, 0x41, 0x7f, 0x40, 0x00 ,  // 0x6c   l
  0x7c, 0x04, 0x18, 0x04, 0x78 ,  // 0x6d   m
  0x7c, 0x08, 0x04, 0x04, 0x78 ,  // 0x6e   n
  0x38, 0x44, 0x44, 0x44, 0x38 ,  // 0x6f   o
  0x7c, 0x14, 0x14, 0x14, 0x08 ,  // 0x70   p
  0x08, 0x14, 0x14, 0x18, 0x7c ,  // 0x71   q
  0x7c, 0x08, 0x04, 0x04, 0x08 ,  // 0x72   r
  0x48, 0x54, 0x54, 0x54, 0x20 ,  // 0x73   s
  0x04, 0x3f, 0x44, 0x40, 0x20 ,  // 0x74   t
  0x3c, 0x40, 0x40, 0x20, 0x7c ,  // 0x75   u
  0x1c, 0x20, 0x40, 0x20, 0x1c ,  // 0x76   v
  0x3c, 0x40, 0x30, 0x40, 0x3c ,  // 0x77   w
  0x44, 0x28, 0x10, 0x28, 0x44 ,  // 0x78   x
  0x0c, 0x50, 0x50, 0x50, 0x3c ,  // 0x79   y
  0x44, 0x64, 0x54, 0x4c, 0x44 ,  // 0x7a   z
  0x00, 0x08, 0x36, 0x41, 0x00 ,  // 0x7b   {
  0x00, 0x00, 0x7f, 0x00, 0x00 ,  // 0x7c   |
  0x00, 0x41, 0x36, 0x08, 0x00 ,  // 0x7d   }
  0x10, 0x08, 0x08, 0x10, 0x08 ,  // 0x7e   ~
  0x00, 0x00, 0x00, 0x00, 0x00 ,  // 0x7f
  0x7e, 0x11, 0x11, 0x11, 0x7e ,  // 0x80   A  // Русские символы
  0x7f, 0x49, 0x49, 0x49, 0x33 ,  // 0x81   Б
  0x7f, 0x49, 0x49, 0x49, 0x36 ,  // 0x82   В
  0x7f, 0x01, 0x01, 0x01, 0x03 ,  // 0x83   Г
  0xe0, 0x51, 0x4f, 0x41, 0xff ,  // 0x84   Д
  0x7f, 0x49, 0x49, 0x49, 0x41 ,  // 0x85   E
  0x77, 0x08, 0x7f, 0x08, 0x77 ,  // 0x86   Ж
  0x41, 0x49, 0x49, 0x49, 0x36 ,  // 0x87   З
  0x7f, 0x10, 0x08, 0x04, 0x7f ,  // 0x88   И
  0x7c, 0x21, 0x12, 0x09, 0x7c ,  // 0x89   Й
  0x7f, 0x08, 0x14, 0x22, 0x41 ,  // 0x8A   K
  0x20, 0x41, 0x3f, 0x01, 0x7f ,  // 0x8B   Л
  0x7f, 0x02, 0x0c, 0x02, 0x7f ,  // 0x8C   M
  0x7f, 0x08, 0x08, 0x08, 0x7f ,  // 0x8D   H
  0x3e, 0x41, 0x41, 0x41, 0x3e ,  // 0x8E   O
  0x7f, 0x01, 0x01, 0x01, 0x7f ,  // 0x8F   П
  0x7f, 0x09, 0x09, 0x09, 0x06 ,  // 0x90   P
  0x3e, 0x41, 0x41, 0x41, 0x22 ,  // 0x91   C
  0x01, 0x01, 0x7f, 0x01, 0x01 ,  // 0x92   T
  0x47, 0x28, 0x10, 0x08, 0x07 ,  // 0x93   У
  0x1c, 0x22, 0x7f, 0x22, 0x1c ,  // 0x94   Ф
  0x63, 0x14, 0x08, 0x14, 0x63 ,  // 0x95   X
  0x7f, 0x40, 0x40, 0x40, 0xff ,  // 0x96   Ц
  0x07, 0x08, 0x08, 0x08, 0x7f ,  // 0x97   Ч
  0x7f, 0x40, 0x7f, 0x40, 0x7f ,  // 0x98   Ш
  0x7f, 0x40, 0x7f, 0x40, 0xff ,  // 0x99   Щ
  0x01, 0x7f, 0x48, 0x48, 0x30 ,  // 0x9A   Ъ
  0x7f, 0x48, 0x30, 0x00, 0x7f ,  // 0x9B   Ы
  0x00, 0x7f, 0x48, 0x48, 0x30 ,  // 0x9C   Э
  0x22, 0x41, 0x49, 0x49, 0x3e ,  // 0x9D   Ь
  0x7f, 0x08, 0x3e, 0x41, 0x3e ,  // 0x9E   Ю
  0x46, 0x29, 0x19, 0x09, 0x7f ,  // 0x9F   Я
  0x20, 0x54, 0x54, 0x54, 0x78 ,  // 0xA0   a
  0x3c, 0x4a, 0x4a, 0x49, 0x31 ,  // 0xA1   б
  0x7c, 0x54, 0x54, 0x54, 0x28 ,  // 0xA2   в
  0x7c, 0x04, 0x04, 0x04, 0x0c ,  // 0xA3   г
  0xe0, 0x54, 0x4c, 0x44, 0xfc ,  // 0xA4   д
  0x38, 0x54, 0x54, 0x54, 0x18 ,  // 0xA5   e
  0x6c, 0x10, 0x7c, 0x10, 0x6c ,  // 0xA6   ж
  0x44, 0x44, 0x54, 0x54, 0x28 ,  // 0xA7   з
  0x7c, 0x20, 0x10, 0x08, 0x7c ,  // 0xA8   и
  0x7c, 0x41, 0x22, 0x11, 0x7c ,  // 0xA9   й
  0x7c, 0x10, 0x10, 0x28, 0x44 ,  // 0xAA   к
  0x20, 0x44, 0x3c, 0x04, 0x7c ,  // 0xAB   л
  0x7c, 0x08, 0x10, 0x08, 0x7c ,  // 0xAC   м
  0x7c, 0x10, 0x10, 0x10, 0x7c ,  // 0xAD   н
  0x38, 0x44, 0x44, 0x44, 0x38 ,  // 0xAE   o
  0x7c, 0x04, 0x04, 0x04, 0x7c ,  // 0xAF   п
  0x7C, 0x14, 0x14, 0x14, 0x08 ,  // 0xB0   p
  0x38, 0x44, 0x44, 0x44, 0x20 ,  // 0xB1   c
  0x04, 0x04, 0x7c, 0x04, 0x04 ,  // 0xB2   т
  0x0C, 0x50, 0x50, 0x50, 0x3C ,  // 0xB3   у
  0x30, 0x48, 0xfc, 0x48, 0x30 ,  // 0xB4   ф
  0x44, 0x28, 0x10, 0x28, 0x44 ,  // 0xB5   x
  0x7c, 0x40, 0x40, 0x40, 0xfc ,  // 0xB6   ц
  0x0c, 0x10, 0x10, 0x10, 0x7c ,  // 0xB7   ч
  0x7c, 0x40, 0x7c, 0x40, 0x7c ,  // 0xB8   ш
  0x7c, 0x40, 0x7c, 0x40, 0xfc ,  // 0xB9   щ
  0x04, 0x7c, 0x50, 0x50, 0x20 ,  // 0xBA   ъ
  0x7c, 0x50, 0x50, 0x20, 0x7c ,  // 0xBB   ы
  0x7c, 0x50, 0x50, 0x20, 0x00 ,  // 0xBC   ь
  0x28, 0x44, 0x54, 0x54, 0x38 ,  // 0xBD   э
  0x7c, 0x10, 0x38, 0x44, 0x38 ,  // 0xBE   ю
  0x08, 0x54, 0x34, 0x14, 0x7c ,  // 0xBF   я
};

//********************************************************
void setup()  {
//  pinMode(8, OUTPUT); // 7, 8- питание на дисплей
//  pinMode(7, OUTPUT);
//  digitalWrite(8, 1);
//  digitalWrite(7, 0);
  pinMode(KEY_OK, INPUT); pinMode(KEY_L, INPUT); pinMode(KEY_R, INPUT); pinMode(KEY_P, INPUT); // настраиваем кнопки на вход
  digitalWrite(KEY_OK, HIGH); digitalWrite(KEY_L, HIGH); digitalWrite(KEY_R, HIGH); digitalWrite(KEY_P, HIGH); // подтяжка к плюсу питания
  VCC = ReadVcc();
  Inicialize();  //Инициализация дисплея
  Clear_LCD();
  ukazatel();//fillTriangle(1, mode * 10); // указатель меню
  // drawChar(1, mode * 10, 1, ">");
  //char Str2[8] = {'a', 'r', 'd', 'u', 'i', 'n', 'o'};
  /*   print(10, 0, 1, "Oscillograf");
   print(10, 10, 1, "Generator");
   print(10, 20, 1, "DDSgenerator");
   print(10, 30, 1, "Terminal");
   print(10, 40, 1, "Analizator");*/
  for (byte i = 0; i < 7; i++)
  {
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // необходимые функции и расшифровки, просто скопируйте
    print(10, i * 10, 1, (buffer));
    //delay( 500 );
  }
  /*print(10, 0, 1, "Осциллограф");
  print(10, 10, 1, "Генератор");
  print(10, 20, 1, "DDSгенератор");
  print(10, 30, 1, "Терминал");
  print(10, 40, 1, "Анализатор");
  print(10, 60, 1, "V bat="); // *************/
  float_print(48, 60, 1, VCC, 2);
  Update();
  delay(KEY_DELAY);

  while (digitalRead(KEY_OK)) { // цикл, пока не нажали кнопку ОК
    // опрос кнопок
    if (!digitalRead(KEY_R)) {
      mode++;
      if (mode == 6  ) mode = 0;
      ukazatel();
    }
    if (!digitalRead(KEY_L)) {
      mode--;
      if (mode == 255) mode = 5;
      ukazatel();
    }
    Update();
  } // цикл нажатия ОК
  // нажали кнопку ОК из меню, инициализируем и выходим из меню
  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 || mode == 5) DDRC = 0x00; PORTC = 0x00; Serial.begin(115200); // razv = 0;// весь порт С (это A0...A5) на вход и без подтяжки
}
// беcконечный цикл - по сути прыгаем в подпрограммы
void loop() {
  switch (mode) {
    // Прыгаем в выбранный режим из главного меню
    case 0 : Oscil();        break; // "выпадаем" в осцилл
    case 1 : Generator();    break; // "выпадаем" в генератор
    case 2 : DdsGenerator(); break; // "выпадаем" в DDS генератор
    case 3 : Terminal();     break; // "выпадаем" в USART приемник
    case 4 : LogAnalyzer();  break; // "выпадаем" в Анализатор
    case 5 : LogAnalyzer();  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;             // записываем данные в массив
    }
  }
}

// === Чтение цифровых данных со всего порта 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);
    }
  }
}*/

// ==== функция вывода float ====
void float_print(byte x, byte y, boolean color, float num, byte zn) { // последняя переменная- кол знаков после запятой
  char c[20];
  long d = num;
  byte m = 1;
  while (d > 9) {
    d = d / 10;
    m++;
  }
  print(x, y, color, dtostrf(num, m, zn, c));
}

// ==== Считывание напряжения питания ардуинки (Vcc) ====
#define Vref11 1.212 // для точной подстройки результата измерений
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));        // результат преобразования в вольтах
}

/*int GetCountsOfDigits(int n) //найти количество цифр в числе <a href="https://habr.com/ru/post/269237/" rel="nofollow">https://habr.com/ru/post/269237/</a>
{
  return n < 10 ? 1 :
         n < 100 ? 2 :
         n < 1000 ? 3 :
         n < 10000 ? 4 :
         n < 100000 ? 5 :
         n < 1000000 ? 6 :
         n < 10000000 ? 7 :
         n < 100000000 ? 8 :
         n < 1000000000 ? 9 : 10;
}*/

// ==== найти количество цифр в числе   <a href="https://habr.com/ru/post/269237/" rel="nofollow">https://habr.com/ru/post/269237/</a>
/*static int stringSize(long x) {
  long p = 10;
  for (int i = 1; i < 19; i++) {
    if (x < p)
      return i;
    p = 10 * p;
  }
  return 19;
}*/

void vivod(byte x, byte y, byte n, byte k) { // //Печать цифры размером 24х48 пикселя (x, y, цифра, размер (1-24х48, 2-12х24))
  if ((n != 1) && (n != 4)) {
    fillRect(x + 3 / k, y, 15 / k, 5 / k, 1  ); // сегмент A
  }
  if ((n != 5) && (n != 6)) {
    fillRect(x + 16 / k, y + 3 / k, 5 / k, 20 / k, 1  ); // сегмент B
  }
  if (n != 2) {
    fillRect(x + 16 / k, y + 24 / k, 5 / k, 20 / k, 1  ); // сегмент C
  }
  if ((n != 1) && (n != 4) && (n != 7)) {
    fillRect(x + 3 / k, y + 42 / k,  15 / k, 5 / k, 1  ); // сегмент D
  }
  if ((n == 0) || (n == 2) || (n == 6) || (n == 8)) {
    fillRect(x, y + 24 / k, 5 / k, 20 / k, 1  ); // сегмент E
  }
  if ((n != 1) && (n != 2) && (n != 3) && (n != 7)) {
    fillRect(x, y + 3 / k, 5 / k, 20 / k, 1  ); // сегмент F
  }
  if ((n != 0) && (n != 1) && (n != 7)) {
    fillRect(x + 3 / k, y + 21 / k,  15 / k, 5 / k, 1  ); // сегмент G
  }
}

//====================================================указатель меню
void ukazatel() {
  fillRect(0, 0, 10, 60, 0);
  for (byte i = 0; i < 4; i++) {                                  // указатель меню
    drawLine(1 + i, mode * 10 + i, 1 + i, mode * 10 + 6 - i, 1);
  }
  Update();
  delay(KEY_DELAY);
}


//===================================================Инициализация дисплея
void Inicialize() {
  pinMode(RES,   OUTPUT);
  pinMode(CS,    OUTPUT);
  pinMode(Data,  OUTPUT);
  pinMode(Clock, OUTPUT);
  // Инициализация дисплея
  dWrite(RES, 1);
  dWrite(Clock, 0);
  dWrite(Data, 0);
  dWrite(CS, 0);
  delay(20);
  dWrite(CS, 1);
  SendByte(0, 0x2F);           // Power control set(charge pump on/off)
  SendByte(0, 0xA4);
  SendByte(0, 0xAF);           // экран вкл/выкл
  //Clear_LCD();
  //Update();
}

//=======================================================Управление пинами
void dWrite(byte pin, byte val) {
  byte bit = digitalPinToBitMask(pin);
  volatile byte *out;
  out = portOutputRegister(digitalPinToPort(pin));
  (val) ? *out |= bit : *out &= ~bit;
}

//=========================================================Отправка 9 байт
void SendByte(byte mode, byte c) {
  dWrite(CS, 0);
  (mode) ? dWrite(Data, 1) : dWrite(Data, 0);
  dWrite(Clock, 1);
  for (byte i = 0; i < 8; i++) {
    dWrite(Clock, 0);
    (c & 0x80) ? dWrite(Data, 1) : dWrite(Data, 0);
    dWrite(Clock, 1);
    c <<= 1;
  }
  dWrite(Clock, 0);
}

//======================================================Очистка дисплея
void Clear_LCD() {
  for (int index = 0; index < 864 ; index++) {
    LCD_RAM[index] = (0x00);
  }
}

//=====================================================Обновить дисплей
void Update() {
  for (byte p = 0; p < 9; p++) {
    SendByte(0, 0xB0 | p);
    SendByte(0, 0x00);
    SendByte(0, 0x10);
    for (byte col = 0; col < 96; col++) {
      SendByte(1, LCD_RAM[(96 * p) + col]);
    }
  }
}

//===================================================Нарисовать пиксель
void drawPixel (byte x, byte y, boolean color) {
  if ((x < 0) || (x >= 96) || (y < 0) || (y >= 68)) return;
  if (color) LCD_RAM[x + (y / 8) * 96] |= _BV(y % 8);
  else       LCD_RAM[x + (y / 8) * 96] &= ~_BV(y % 8);
}

//=====================================================Нарисовать букву
void drawChar(byte x, byte y, boolean color, unsigned char c) {
  if ((x >= 96) || (y >= 68) || ((x + 4) < 0) || ((y + 7) < 0)) return;
  if (c < 128)            c = c - 32;
  if (c >= 144 && c <= 175) c = c - 48;
  if (c >= 128 && c <= 143) c = c + 16;
  if (c >= 176 && c <= 191) c = c - 48;
  if (c > 191)  return;
  for (byte i = 0; i < 6; i++ ) {
    byte line;
    (i == 5) ? line = 0x0 : line = pgm_read_byte(font + (c * 5) + i); // line = EEPROM.read((c * 5) + i);
    for (byte j = 0; j < 8; j++) {
      (line & 0x1) ? drawPixel(x + i, y + j, color) : drawPixel(x + i, y + j, !color);
      line >>= 1;
    }
  }
}

//========================================================Вывод строки
void print(byte x, byte y, boolean color, char *str) {
  unsigned char type = *str;
  if (type >= 128) x = x - 3;
  while (*str) {
    drawChar(x, y, color, *str++);
    unsigned char type = *str;
    (type >= 128) ? x = x + 3 : x = x + 6;
  }
}

//========================================================Вывод числовых значений
void print(byte x, byte y, boolean color, long num) {
  char c[20];
  print(x, y, color, ltoa(num, c, 10));
}

//====================================================Рисование линии
void drawLine(byte x0, byte y0, byte x1, byte y1, boolean color) {
  int steep = abs(y1 - y0) > abs(x1 - x0);
  if (steep) {
    swap(x0, y0);
    swap(x1, y1);
  }
  if (x0 > x1) {
    swap(x0, x1);
    swap(y0, y1);
  }
  int dx, dy;
  dx = x1 - x0;
  dy = abs(y1 - y0);
  int err = dx / 2;
  int ystep;
  (y0 < y1) ?  ystep = 1 : ystep = -1;
  for (; x0 <= x1; x0++) {
    (steep) ? drawPixel(y0, x0, color) : drawPixel(x0, y0, color);
    err -= dy;
    if (err < 0) {
      y0 += ystep;
      err += dx;
    }
  }
}

//========================================Рисование вертикальной линии
void drawFastVLine(byte x, byte y, byte h, boolean color) {
  drawLine(x, y, x, y + h - 1, color);
}

//======================================Рисование горизонтальной линии
void drawFastHLine(byte x, byte y, byte w, boolean color) {
  drawLine(x, y, x + w - 1, y, color);
}

//=====================================Рисование залитый прямоугольник
void fillRect(byte x, byte y, byte w, byte h, boolean color) {
  for (byte i = x; i < x + w; i++) {
    drawFastVLine(i, y, h, color);
  }
}

//=====================================Рисование битового нолика
void printnull(byte a, byte i) {
  drawPixel(29 + a - i * 4, 64, 1);
  drawFastVLine(28 + a - i * 4, 65, 2, 1); // и вывести биты на дисплей
  drawFastVLine(30 + a - i * 4, 65, 2, 1);
  drawPixel(29 + a - i * 4, 67, 1);
}


// === Осциллоскоп === //
void Oscil() {
  // установка опорного напряжения АЦП и настройка входа АЦП
  ADMUX = vRef ? 0b01100011 : 0b11100011;
  // === Обработка кнопок === //
  if (!digitalRead(KEY_L))   switch (menu) { // кнопка лево:)
      case 0 : vRef = !vRef;                                                             break; // меняем опорное напряжение
      case 1 : razv--; if (razv == 255) razv = 6;                                        break; // меняем развертку
      case 2 : grOffset -= 20; if (grOffset < 0) grOffset = 0;                           break; // листаем график в паузе
    }
  if (!digitalRead(KEY_R))  switch (menu) { // кнопка право:)
      case 0 : vRef = !vRef;                                                             break; // меняем опорное напряжение
      case 1 : razv++; if (razv == 7) razv = 0;                                          break; // меняем развертку
      case 2 : grOffset += 20; if (grOffset > BUFSIZE - LCDX) grOffset = BUFSIZE - LCDX; break; // листаем график в паузе
    }
  if (!digitalRead(KEY_OK))  switch (++menu) {
      case 2: grOffset = 0; pause = 1;                                                   break; // вход в паузу - антидребезг типа
      case 3: menu = 0; pause = 0;                                                       break; // перебор меню
    }
  if (!digitalRead(KEY_P)) {
    menu = 2; pause = 1;
  }
  // === Ведём рассчеты === //
  if (!pause) { // если нет паузы
    ReadAdc();  // то снимаем осциллограмму
    // == Вычисляем максимальное и минимальное значение сигнала == //
    vMax = 0; vMin = 0xFF;
    for (int y = 1; y < 255; y++) {
      if (vMax < adcBuf[y]) vMax = adcBuf[y];  // пока 255, но надо экспериментировать
      if (vMin > adcBuf[y]) vMin = adcBuf[y];
    }
    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; // пересчет частоты на разные кварцы
  } // закончили вести рассчеты
  Clear_LCD(); // чистим экран...
  // === Отрисовка меню осцилла ===
  if (menu == 0) TextColor = 0; else TextColor = 1;
  if (vRef) float_print(0, 0, TextColor, VCC, 1); else  print(0, 0, TextColor, "1.1");
  if (menu == 1) TextColor = 0; else TextColor = 1;
  print(24, 0, TextColor, razv);
  if (menu == 2) { // тут задержка для компенсации с остальными задержками
    delay(200);
    //print(48, 0, 0, " Pause ");
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[8]))); // необходимые функции и расшифровки, просто скопируйте
    print(48, 0, 0, (buffer));
  } else TextColor = 1;
  if (!pause) float_print (48, 0, 1, count / 1000000.0, 6); // вывод частоты
  else { // рисуем прокрутку в режиме паузы
    temp = grOffset / 8;
    drawFastHLine(temp, 10, 6, 1);  drawFastHLine(temp, 9, 6, 1);
  } // шкала прокрутки
  if (vRef && vMax * VCC / 255 > 2.7)  drawChar(42, 0, 1, 97); // если замер аппаратный - "a"
  else  drawChar(42, 0, 1, 112); // иначе "p"
  float_print(78, 14, 1, vMax * (vRef ? VCC : 1.1) / 255, 1); // рисуем максимальное напряжение сигнала
  float_print(78, 54, 1, vMin * (vRef ? VCC : 1.1) / 255, 1); // рисуем минимальное  напряжение сигнала
  // if (vMax==0xFF) for(int y=0; y<4; y++) display.drawLine(y,9,y,47, BLACK); // превышение максимума АЦП
  // == Отрисовка сетки == //
  for (byte i = 11; i < 68; i = i + 14) {
    drawFastHLine( 0, i, 2, 1);  // черточки слева
  }
  for (byte i = 67; i > 10; i = i - 4) {
    drawPixel(24, i, 1);
    drawPixel(48, i, 1);
    drawPixel(72, i, 1);
  }
  for (byte i = 8; i < 96; i = i + 4) {
    drawPixel(i, 39, 1);
  }
  // == Отрисовка графика == //
  for (int y = 0; y < 92; y++)  drawLine(y + 4, 67 - adcBuf[y + grOffset] / 7, y + 4, 67 - adcBuf[y + grOffset + 1] / 7, 1);
  Update();
}

//**********************************************************************************
void Generator() {
  // обработка кнопок и отрисовка одновременно
  Clear_LCD();
  //print(0, 0, 1, "Частота");
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[9]))); // необходимые функции и расшифровки, просто скопируйте
  print(0, 0, 1, (buffer));
  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); // задали ШИМ
    TextColor = 0; // если меняем шим, то рисуем его инверсным
  } 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); // задержка для кнопок
    }
    TextColor = 1; // если ШИМ не меняем, то выбираем обычный текст
#define XFREQ 10 // ======== // и, выделяем декаду частоты полосочками
    stepFreq = pow(10, (byte)menu); if (menu > 1) stepFreq++; // устраняем глючность pow, почему 10 в степени 2 = 99?
    temp = 42 - menu * 6;
    if (temp < 10) temp = 0;
    drawFastHLine(temp, XFREQ + 10, 5, 1); // выделяем декаду частоты полосочками
    drawFastHLine(temp, XFREQ + 9, 5, 1);
  }
  // рисуем уровень ШИМ (инверсия текста задана ранее)
  drawFastHLine(15, 39 , 54, !TextColor); // сверху полоска для большей инверсности
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[7]))); // необходимые функции и расшифровки, просто скопируйте
  print(15, 40, TextColor, (buffer));   print(45, 40, TextColor, PWM);
  print(57, 40, TextColor, "% "); // выводим уровень ШИМ
  if (PWM < 10) {
    drawChar(45, 40, TextColor, 32); // " "
    print(51, 40, TextColor, PWM);
  }
  drawChar(63, 40, TextColor, 32); // " "
  if (PWM == 100)  {
    print(45, 40, TextColor, 100);
    print(63, 40, TextColor, "%");
  }
  TextColor = 1; // убираем инверсию при выводе частоты
  // print(42 - stringSize(freq) * 6, XFREQ, 1, freq); // вывод частоты
  float_print (0, XFREQ, 1, freq / 1000000.0, 6); // вывод частоты
  print(50, XFREQ, 1, "MHz");
  // отрисовка графика PWM
  for (char x = 17; x < 67; ) {
    if (PWM != 0)  drawFastHLine(x, 26, PWM / 4, 1); x += PWM / 4;             // верх
    if (PWM != 0 && PWM != 100)  drawFastVLine(x, 26, 10, 1);                  // спад
    if (PWM != 100)  drawFastHLine(x, 36, 25 - PWM / 4, 1); x += 25 - PWM / 4; // низ
    if (PWM != 0 && PWM != 100 && x < 43)  drawFastVLine( x, 26, 11, 1);       // подъем
  }
  Update(); // вываливаем буфер на дисплей
}

//**********************************************************************************
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
  };
  byte ddsCount = 0;
  // Рисуем DDS-генератор
  Clear_LCD(); // режим работы, заголовок
  for (byte i = 0; i < 96;)  drawLine(i, 36 - pgm_read_byte(&ddsWave[menu][i % 32]) / 10, i, 36 - pgm_read_byte(&ddsWave[menu][(i++) % 32]) / 10, 1);
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[10 + menu]))); // необходимые функции и расшифровки, просто скопируйте
  print(5, 40, 1, (buffer));
  /*switch (menu) { //..........
    case 0:    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[10]))); // необходимые функции и расшифровки, просто скопируйте
      print(3, 40, 1, (buffer));  break;
    case 1:    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[11]))); // необходимые функции и расшифровки, просто скопируйте
      print(3, 40, 1, (buffer));  break;
    case 2:    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[12]))); // необходимые функции и расшифровки, просто скопируйте
      print(3, 40, 1, (buffer));  break;
    case 3:    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[13]))); // необходимые функции и расшифровки, просто скопируйте
      print(3, 40, 1, (buffer));  break;
  }*/
  Update();
  while (digitalRead(KEY_R)) { // выводим выбранный сигнал, пока не нажали кнопку
    pwmWrite(DDS_PIN, pgm_read_byte(&ddsWave[menu][(ddsCount++) & 0x1F]));
  }
  if (++menu == 4) menu = 0; // нажали кнопку - переключаем режим
  delay(KEY_DELAY); // чтоб кнопки нормально нажимались
}

//**********************************************************************************
void Terminal() {
  //const long speedUart[] = { 9600, 19200, 38400, 57600, 115200, 300, 600, 1200, 2400, 4800 };
  const PROGMEM  uint32_t speedUart[] = { 9600, 19200, 38400, 57600, 115200, 250000, 300, 600, 1200, 2400, 4800 }; // ------
  Clear_LCD();
  //print(10, 0, 1, "Скорость:");
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[14]))); // необходимые функции и расшифровки, просто скопируйте
  print(10, 0, 1, (buffer));
  print(10, 10, 1, speedUart[menu]);
  Update();
  if (!digitalRead(KEY_L))  {
    menu--;
    if (menu == 255) menu = 10;
    // print(28, 10, 1, "   ");
    print(10, 10, 1, speedUart[menu]);
    Update();
    delay(KEY_DELAY);
  }
  if (!digitalRead(KEY_R))  {
    menu++;
    if (menu == 11)   menu = 0;
    // print(28, 10, 1, "   ");
    print(10, 10, 1, speedUart[menu]);
    Update();
    delay(KEY_DELAY);
  }
  if (!digitalRead(KEY_OK)) {
    Clear_LCD();
    if (!digitalRead(KEY_P)) pause = 1; // включаем флаг, что пауза была нажата для вкл дополн функции
    else  drawFastHLine(10, 66 , 75, 1);
    Serial.begin(speedUart[menu] * (16 / OVERCLOCK));
    drawChar(0, 0, 0, 62);
    Update();
    delay(KEY_DELAY);
    Update();
    byte x = 0;
    byte y = 0;
    while (1) {
      if (Serial.available()) { // Если в буфере есть данные
        if (x > 90) { // проверяем, не заполнен ли экран
          x = 0;
          y = y + 8;
        }
        byte symbol = (Serial.read());
        if ((symbol == 10 || symbol == 13) && x != 0) {
          x = 0;
          y = y + 8;
        }
        if (y > 56) {
          y = 0;
          x = 0;
        }
        if (symbol != 10 && symbol != 13) {
          if (symbol == 127 || symbol == 8) { // Del
            if (x == 0) {
              x = 90;
              if (y != 0) {
                y = y - 8;
              }
              else y = 56;
            }
            else
            {
              x += -6;
            }
            drawChar(x, y, 1, 32); // " "
          }
          else {
            symbol3 = symbol2;
            symbol2 = symbol1;
            symbol1 = symbol;
            if (symbol > 191) { //русские буквы
              if (symbol > 239) {
                drawChar(x, y, 1, symbol - 112); // 
              }
              else drawChar(x, y, 1, symbol - 48); // 
            }
            else drawChar(x, y, 1, symbol);  // печать байта в дисплей
            // print(x + 6, y, 1, "               ");
            //for (byte i = 0; i < 7; i++) drawLine(x + 6, y + i, 95, y + i, 0); // очистить место
            //for (byte i = 0; i < 7; i++) drawFastHLine(x + 6, y + i, 90, 0);// не работает
            x = x + 6;
          }
        }
        for (byte i = 0; i < 7; i++) drawLine(x, y + i, 95, y + i, 0); // очистить место
        if (pause == 1) { // вывод бинарных кодов символов только если были нажаты ДВЕ кнопки
          /*char p[17]; //
          itoa (symbol, p, 16); // перевод в шестнадцатеричное
           print(0, 60, 1, p); // отображение шестнадцатеричного*/
          drawFastHLine(0, 65, 96, 0); // очистить место
          drawFastHLine(0, 66, 96, 0);
          drawPixel(31, 67, 1); // разделение байтов
          drawPixel(63, 67, 1);
          for (byte i = 0; i < 8; i++) { // разложить код символа на биты
            if (bitRead(symbol3, i)) drawFastVLine(29 - i * 4, 64, 4, 1); // биты предпредпоследнего байта
            else printnull(0, i);
            if (bitRead(symbol2, i)) drawFastVLine(61 - i * 4, 64, 4, 1); // биты предпоследнего байта
            else printnull(32, i);
            if (bitRead(symbol1, i)) drawFastVLine(94 - i * 4, 64, 4, 1); // биты последнего байта смещены на пиксель вправо
            else printnull(65, i); // биты последнего байта смещены на пиксель вправо
          }
          /*for (byte i = 0; i < 8; i++) { // разложить код символа на биты
            if (bitRead(symbol2, i) == 1)  drawFastVLine(29 + 32 - i * 4, 64, 4, 1); //  drawChar(i * 6, 56, 1, 49);
            else {//  drawChar(i * 6, 56, 1, 48);
              drawPixel(29 + 32 - i * 4, 64, 1);
              drawFastVLine(28 + 32 - i * 4, 65, 2, 1); // и вывести биты на дисплей
              drawFastVLine(30 + 32 - i * 4, 65, 2, 1);
              drawPixel(29 + 32 - i * 4, 67, 1);
            }
          }
          for (byte i = 0; i < 8; i++) { // разложить код символа на биты
            if (bitRead(symbol1, i) == 1)  drawFastVLine(29 + 64 - i * 4, 64, 4, 1); //  drawChar(i * 6, 56, 1, 49);
            else {//  drawChar(i * 6, 56, 1, 48);
              drawPixel(29 + 64 - i * 4, 64, 1);
              drawFastVLine(28 + 64 - i * 4, 65, 2, 1); // и вывести биты на дисплей
              drawFastVLine(30 + 64 - i * 4, 65, 2, 1);
              drawPixel(29 + 64 - i * 4, 67, 1);
            }
          }*/
        }
        Update();
      }
    }
  }
  Update();
}

//*********************************************************************************
void LogAnalyzer() {
  // обрабатываем кнопки
  if (!digitalRead(KEY_L)) switch (menu) {
      case 0 : razv--; if (razv == 255) razv = 19; delay(KEY_DELAY);                       break; // меняем развертку
      case 1 : trig--; if (trig == 255) trig = 3; delay(KEY_DELAY);                        break; // меняем trigger
      case 2 : grOffset -= 10; if (grOffset < 0) grOffset = 0;                             break; // листаем график в паузе
    }
  if (!digitalRead(KEY_R)) switch (menu) {
      case 0 : razv++; if (razv == 20) razv = 0; delay(KEY_DELAY);                         break; // меняем развертку
      case 1 : trig++; if (trig == 4) trig = 0; delay(KEY_DELAY);                          break; // меняем trigger
      case 2 : grOffset += 5; if (grOffset >= BUFSIZE - 50) grOffset = BUFSIZE - 50;       break; // листаем график в паузе
    }
  if (!digitalRead(KEY_OK)) switch (++menu) {
      //case 2 : grOffset = 0; pause = 1;                                                    break; // вход в паузу
      case 3 : menu = 0;     pause = 0;                                                    break; // перебор меню
        delay(KEY_DELAY);
    }
  if (!digitalRead(KEY_P)) {
    menu = 2; grOffset = 0; pause = 1; flag = 0;// вход в паузу
  }

  //if (!pause) ReadDig(); // если нет паузы - читаем данные

  Clear_LCD(); // чистим дисплей
  if ( menu == 0 ) print(0, 0, 0, razv);  // выводим развертку
  else print(0, 0, 1, razv);              // выводим развертку
  if ( menu == 1 ) print(24, 0, 0, trig); // выводим trigger
  else print(24, 0, 1, trig);             // выводим trigger
  if (pause) {
    if (flag == 0) {
      print(50, 0, 1, "Waiting");
      Update();
      switch (trig) {
        case 0 : scanLoadBus(BURST); flag = 1; menu = 2;           break;
        case 1 : scanLoadBus(MASTER_RISE); flag = 1; menu = 2;     break;
        case 2 : scanLoadBus(MASTER_FALL); flag = 1; menu = 2;     break;
        case 3 : scanLoadBus(PATTERN); flag = 1; menu = 2;         break;
      }
    }
    //print(8, 0, 1, " Pause ");
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[8]))); // необходимые функции и расшифровки, просто скопируйте
    print(50, 0, 1, (buffer));
    // рисуем прокрутку в режиме паузы
    drawLine( grOffset / 8, 8, grOffset / 8 + 6, 8,  1); // шкала прокрутки
    drawLine( grOffset / 8, 9, grOffset / 8 + 6, 9,  1); // шкала прокрутки
    delay(200);
  }
  for (byte chan = 0; chan < 4; chan++) // последовательный перебор 4-х каналов
  { int show_index = StartIndex >> 1;
    int read_index;
    print(0, 10, 1, (show_index + grOffset));
    drawLine(50, 10, 50, 15, 1);
    print(54, 10, 1, (grOffset + grOffset + 50));
    for (int x = 0; x < 48; x++ ) {
      read_index = show_index + grOffset + x;
      if (read_index >= BUFSIZE) read_index = read_index - BUFSIZE;
      if ((x % 5) == 0) {
        drawLine(x + x, 60, x + x, 64, 1); // если номер отсчета кратен 10 - рисуем черточку
        if (((grOffset + x - 100) / 5 % 10) == 0) print (x + x - 2, 60, 1, (grOffset + x) / 50);
      }
      //Декомпресиия старшей части
      if ((adcBuf[read_index] >> 4) & (1 << chan)) // выделяем соответствующий бит текущего канала
      {
        drawLine(x + x, chan * 10 + 20, x + x, chan * 10 + 24, 1); //если высокий уровень
      }
      else
      {
        drawPixel(x + x, chan * 10 + 24, 1); // если низкий уровень
      }
      //Декомпресиия младшей части
      if (adcBuf[read_index] & (1 << chan)) // выделяем соответствующий бит текущего канала
      {
        drawLine(x + x + 1, chan * 10 + 20, x + x + 1, chan * 10 + 24, 1); //если высокий уровень
      }
      else
      {
        drawPixel(x + x + 1, chan * 10 + 24, 1); // если низкий уровень
      }
    } // end y loop
  }
  Update();
}

//============================================
// Функция расчета номера замера с которого начинается вывод данных включая предисторию
// иными словами, от замера сработки тригера отнимаем (с учетом перекрутки буффера) величину предистории
//============================================
int calc_StartIndex() {
  //=========== расчет точки останова чтобы не затереть начало сработки триггера
  if (cur_index < history) //если значение тек. индекса меньше, чем размер истории
  {
    return ((BUFSIZE + BUFSIZE) + cur_index - history); //считаем таким образом
  }
  else
  {
    return (cur_index - history); // ну и если больше, то просто отнимаем
  }//=========== End расчет точки останова чтобы не затереть начало сработки триггера
}

//===========================================================
// Процедура записи данных данных в буфер
// тут происходит запись сжатых данных и увеличение текущего индекса замера
// запись будет происходить при нечетном значении индекса (т.е., считаны уже два значения)
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 == (BUFSIZE + BUFSIZE)) cur_index = 0; //если достигли конца буфера - сброс и все сначала
} //end rec_data

//============================================
// Процедура сканирования шины и отлов сработки триггеров
// При сканировании шины будем учитывать тип триггера: typeTriggerEvent
// Чтобы считать значения младших четырех бит (PORTC0, PORTC1, PORTC2, PORTC3)
// нужно делать так: my_var1 = PINC & b00001111; // такой операцией мы обнулим старшие 4 бит и получим ТОЛЬКО младшие 4-ре
//============================================
void scan_bus(byte typeTriggerEvent) {
  while (!trigger_event)
  {
    // ПЕРВЫМ делом нужно считать данные с шины, а уже потом будем разбираться со всякими сверками и расчетами
    byte cur_data = (PINC & B00001111); //сразу же считываем состояние пинов порта
    // ниже отладочная пришлепка для примерной оценки скорости оцифровки
    // по частоте переключения пина будем судить о скорости
    // данные считаны, теперь проверяем есть ли условия сработки триггера и если ДА, запоминаем номер замера (0-1024)
    switch (typeTriggerEvent) //ветвимся в зависимости от режима триггера
    {
      // BURST Mode Любое изменение на любом канале
      case (BURST):
        if (cur_data != prev_data)
        {
          trigger_event = true; //ставим признак сработки триггера
          StartIndex = calc_StartIndex(); // расчет номера замера с которого будем делать вывод
        }
        break;
      //---------------------------------
      // master channel RISE (переход из 0 в 1)
      case (MASTER_RISE):
        if (~prev_data & cur_data & 1)
        {
          trigger_event = true; //ставим признак сработки триггера
          StartIndex = calc_StartIndex(); // расчет номера замера с которого будем делать вывод
        }
        break;
      //---------------------------------
      // master chanel FALL (переход из 1 в 0)
      case (MASTER_FALL):
        if (prev_data & ~cur_data & 1)
        {
          trigger_event = true; //ставим признак сработки триггера
          StartIndex = calc_StartIndex(); // расчет номера замера с которого будем делать вывод
        }
        break;
      //---------------------------------
      // PATTERN (определенное состояние шины)
      case (PATTERN):
        //if ((cur_data & pattern_mask) == pattern_value) // если проверка на совпадение условий прошла
        if ((cur_data & 7) == 5) // если проверка на совпадение условий прошла
        {
          trigger_event = true; //ставим признак сработки триггера
          StartIndex = calc_StartIndex(); // расчет номера замера с которого будем делать вывод
        }
        break;
    } //End switch (typeTriggerEvent)
    rec_data(cur_data); //запись данных в буффер
    if ((cur_index == 0) && Serial.available()) break; //единственный способ прервать - при нулевом индексе что-то появилось в ком-порту
    delayMicroseconds(razv * 4);
  } //end while
}// end load data

//====== read_bus ============
// тупо пишем состояние каналов
void read_bus() {
  prevMillis = millis(); //запоминаем время начала записи истории
  while (cur_index != StartIndex)
  {
    rec_data(PINC & B00001111); //запись данных в буффер
    delayMicroseconds(razv * 4);
  } //end while
  curMillis = millis(); //время конца записи истории
}

//==================
// инициализация перед замерами
//Обнуляем буффер, сбрасываем индексы и запоминаем состояние шины
void init_logic() {
  for (int i = 0; i <= BUFSIZE; i++) //в цикле затиранием рабочий массив
  {
    adcBuf[i] = 0;
  }
  cur_index = 0; // сбрасываем счетчик замеров
  StartIndex = 0; // сбрасываем положение начала данных для вывода
  time_disc = 0; // сбрасываем значения интервала одной выборки
  trigger_event = false; //сбрасываем признак сработки триггера
  prev_data = (PINC & B00001111); //сформируем пред. замер состояние пинов порта
} // end logic init

//========================================================
// процедура отображения полезной (и не очень) информации
void show_info(byte typeTriggerEvent) {
  // немного расчетов "для красоты": для считывания ((BUFSIZE+BUFSIZE)-history) количества замеров требуется
  // сколько-то милисекунд (или, если умножить на 1000 - микросекунд) посчитаем, сколько микросекунд уходит на одну выборку (естественно, ОЧЕНЬ-ОЧЕНЬ ПРИМЕРНО)
  time_disc = ((curMillis - prevMillis) * 1000) / (((BUFSIZE + BUFSIZE) - history)); //время выборки одного замера
  Serial.println(F("---------------------------------------------------------"));
  Serial.print(F("Record size=")); Serial.print((BUFSIZE + BUFSIZE) - history, DEC); Serial.print(F("  Pre-history size=")); Serial.println(history, DEC);
  Serial.print(F("Current Trigger: "));
  switch (typeTriggerEvent) {
    case (MASTER_RISE):
      Serial.println(F("Master (Ch0) RISE (0->1)"));
      break;
    case (MASTER_FALL):
      Serial.println(F("Master (Ch0) FALL (1->0)"));
      break;
    case (BURST):
      Serial.println(F("Change on any channel"));
      break;
    case (PATTERN):
      Serial.print(F("Bus status"));
      Serial.print(F("  MASK / VALUE =")); Serial.print(pattern_mask, HEX); Serial.print(F(" / ")); Serial.println(pattern_value, HEX);
      break;
  } //end switch
  //Serial.print("Start/Stop =");Serial.print(prevMillis);Serial.print(" / "); Serial.print(curMillis);
  //Serial.print("[Ind Start = ");Serial.print(StartIndex);Serial.print("] ");
  Serial.print(F("Time: 1 div = ")); Serial.print(time_disc); Serial.println(F(" (uSec)"));
  Serial.println(F("******************************************"));
}

//==============================
// Процедура орисовки результатов в виде псевдографика
// процедура достаточно медленная, но буфер к этому моменту заполнен, так что скорость тут УЖЕ не важна
//==============================
void show_graph() {
  for (byte chan = 0; chan < 4; chan++) // последовательный перебор 4-х каналов
  {
    Serial.print(F("Ch N")); Serial.print(chan);
    int show_index = StartIndex >> 1;
    Serial.print(F("\t"));
    for (int y = 0; y < BUFSIZE; y++ )
    {
      if (show_index == BUFSIZE) show_index = 0;
      //Декомпресиия старшей части
      if ((adcBuf[show_index] >> 4) & (1 << chan)) // выделяем соответствующий бит текущего канала
      {
        Serial.print(F("-")); //если высокий уровень
      }
      else
      {
        Serial.print(F("_")); // если низкий уровень
      }
      //Декомпресиия младшей части
      if (adcBuf[show_index] & (1 << chan)) // выделяем соответствующий бит текущего канала
      {
        Serial.print(F("-")); //если высокий уровень
      }
      else
      {
        Serial.print(F("_")); // если низкий уровень
      }
      show_index++;
    }// end y loop
    Serial.println();
  } //end loop chan
  // ===========================================
  // для красоты - типа вывод шкалы разметки :)
  // ===========================================
  Serial.print(F("\t")); //код TAB для ровности вывода
  for (int x = 0; x < (BUFSIZE + BUFSIZE); x++)
  {
    if (x == history) Serial.print(F("^")); //обозначим начало отсчета
    if ((x % 10) == 0) Serial.print(F("|")); // если номер отсчета кратен 10 - рисуем черточку
    if ((x % 10 != 0) && (x != history)) Serial.print(F(".")); // иначе рисуем точку
  }
  Serial.println(F(".")); //завершающая точка и перевод строки
  // рисуем "типа" разметку
  Serial.print(F("\t"));//код TAB для ровности вывода
  for (int x = 0; x < (BUFSIZE + BUFSIZE); x++)
  {
    if ((x % 10) == 0)
    {
      Serial.print(x / 10);
      if (x < 100)                  Serial.print(F("         ")); //чтобы не плыли значения относительно шкалы, в зависимости от разрядности тек. замера
      else if ((x >= 100) && (x < 1000))   Serial.print(F("        ")); // для случая ЗАМЕР - два знака
      else if ((x >= 1000) && (x < 10000)) Serial.print(F("       ")); // для случая ЗАМЕР - три знака
    }
  }
  Serial.println();

}//end show_graph

//===================================================
//фантик обертка сканирования шины (scan_bus+read_bus)
//1 фаза - ждем триггер или отмену пользователем
//2 фаза - заполнение буфера данными
void scanLoadBus(byte typeTriggerEvent)
{
  Serial.print(F("Waiting......"));
  //digitalWrite(TriggerPin, LOW); // светрдиод TRG выключаем
  init_logic(); //инициализируем буфер и переменные
  scan_bus(typeTriggerEvent);
  if (trigger_event) //если триггер сработал
  {
    read_bus(); // пишем историю в буфер
    //digitalWrite(TriggerPin,HIGH); // светoдиод TRG включаем
    Serial.println(F("Ok!"));
    show_info(typeTriggerEvent); //выводим информацию
    show_graph(); //и следом выводим график
  }
  else
  {
    Serial.println(F("User break")); //а если мы вернулись без признака сработки триггера - значит ожидание было прервано пользователем
    Serial.flush(); //очищаем буфер
  }
} //end scanLoadBus

 

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

Попробовал в arduino-1.8.5, работает, более новых версий ИДЕ у меня нет.

Хотя по традиии все действия с пультоскопом делаю в arduino-1.6.5 от автора форума, там и с русским шрифтом проблем нет. На макете единственный резистор на подсветку дисплея. Плата arduino-нано с 328 атмегой.

Попробуйте поменять версию ИДЕ (обычную сносить не надо). А может как раз дело в загрузчике.

И что значит фраза "вольтметр сразу зависает после включения."?

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

вольтметр питания ардуино не изменяет показатели вольт при изменении напряжения после включения.  И также пробежка по меню не возможна. Короче висит. 

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

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

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

Треугольник стоит на первом пункте. Резисторы на + и ардуино, кнопки замыкаются на минус.

seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018
#define KEY_OK 12 // кнопка ОК    (можно любой пин)
#define KEY_R  12 // кнопка ПРАВО (можно любой пин)

Это что за безобразие?

 

vasska
Offline
Зарегистрирован: 21.04.2016

 Ардуино Осциллограф Проекты

Автор: Роберт Дэвис

Год: 2017

Страниц: 70

Формат: PDF

Размер: 3 Мб 

Язык: русский

Думаю пригодиться.

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

seri0shka пишет:

#define KEY_OK 12 // кнопка ОК    (можно любой пин)
#define KEY_R  12 // кнопка ПРАВО (можно любой пин)

Это что за безобразие?

 

Это ерунда. Я так случайно скопировал для форума. 13 пин по реальному прошит. На фото всё правитьно!?

#define KEY_R  13  
seri0shka
seri0shka аватар
Offline
Зарегистрирован: 19.11.2018

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

Попробуйте заменить кусочек скетча для проверки со строки 277:

  while (digitalRead(KEY_OK)) { // цикл, пока не нажали кнопку ОК
    // опрос кнопок
    if (!digitalRead(KEY_R)) {
      mode++;
      if (mode == 6  ) mode = 0;
      print(0, mode*10, 1, ">");
    }
    if (!digitalRead(KEY_L)) {
      mode--;
      if (mode == 255) mode = 5;
      print(0, mode*10, 1, ">");
    }
    Update();
  } // цикл нажатия ОК

Или вместо всего этого участка впишите одну строку:

mode = 0;

0- переход в режим осцил., можно другое число. Это для проверки.

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

Заменил первый кусок завелость. Но в меню при нажатии дублируются указатель.

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

Попробуйте в исходном варианте этот кусок

	//====================================================указатель меню
	void ukazatel() {
	  fillRect(0, 0, 10, 60, 0);
	  for (byte i = 0; i < 4; i++) {                                  // указатель меню
	    drawLine(1 + i, mode * 10 + i, 1 + i, mode * 10 + 6 - i, 1);
	  }
	  Update();
	  delay(KEY_DELAY);
	}

заменить на

	//====================================================указатель меню
	void ukazatel() {
	  fillRect(1, 1, 10, 60, 0);
	  for (byte i = 0; i < 4; i++) {                                  // указатель меню
	    drawLine(1 + i, mode * 10 + i, 1 + i, mode * 10 + 6 - i, 1);
	  }
	  Update();
	  delay(KEY_DELAY);
	}

Ещё можете для правильного отображения напряжения замерить реальное напряжение на ардуинке и уменьшить число в 363 строке:

// ==== Считывание напряжения питания ардуинки (Vcc) ====
	#define Vref11 1.212 // для точной подстройки результата измерений

Я подгонял для работы от 3,5 до 4,2 вольт, при большем начинает врать.

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

Не помогло, треугольник пропадает после пробежки по меню, забивает горизонтальными галочками вместо его. После прокрутки DDSгенератора автоматом открывается Осциллограф. Резисторы на кнопки все 10 кОм. Во запара))))).

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

Ещё раз: в исходном варианте без галочек (скетч в посте 4209) внесите изменения, как написал в посте 4221. На пине 13 резистор поменьше поставьте пока для прояснения ситуации (100...470ом), светодиод на 13 пине может влиять.

 

smokok пишет:

Не помогло

Ну как там? Я ж не сплю по ночам!

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

Спать надо))). Ну как, всё по старому как на фото (не прёт). светодиод на 13 пине убрал с резистором и остальное сделал как советуете. В DdsGenerator заменил код чтобы остальные кнопки проверить, всеравно после прокрутки любых кнопок перекидывает в осццил ... 

while(digitalRead(KEY_R) && digitalRead(KEY_L) && digitalRead(KEY_OK)) { 

 

LegionerGUR
Offline
Зарегистрирован: 08.09.2018

вместо этих строк

 while (digitalRead(KEY_OK)) { // цикл, пока не нажали кнопку ОК

0278     // опрос кнопок
0279     if (!digitalRead(KEY_R)) {
0280       mode++;
0281       if (mode == 6  ) mode = 0;
0282       ukazatel();
0283     }
0284     if (!digitalRead(KEY_L)) {
0285       mode--;
0286       if (mode == 255) mode = 5;
0287       ukazatel();
0288     }

 попробуй вставить это

 while (digitalRead(KEY_OK)) { // цикл, пока не нажали кнопку ОК
0278     // опрос кнопок
0279     if (!digitalRead(KEY_R)) {
0280       mode = mode + 1;
0281       if (mode > 5  ) {mode = 0;}
0282       ukazatel();
0283     }
0284     if (!digitalRead(KEY_L)) {
0285       mode = mode - 1;
0286       if (mode < 0){mode = 5;

}

0287       ukazatel();
0288     }

 

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

LegionerGUR пишет:

if (mode < 0){mode = 5;

Ни в коем случае! Я когда-то сильно обжёгся на этом. Условие никогда не сработает, потому что mode- байтовая переменная, а байт никогда не может быть меньше нуля, только от 0 до 255.

svm
Offline
Зарегистрирован: 06.11.2016

seri0shka пишет:

LegionerGUR пишет:

if (mode < 0){mode = 5;

Ни в коем случае! Я когда-то сильно обжёгся на этом. Условие никогда не сработает, потому что mode- байтовая переменная, а байт никогда не может быть меньше нуля, только от 0 до 255.

А если заменить 0 на 255 ?

svm
Offline
Зарегистрирован: 06.11.2016

Уже двоиться начало. Пора завязывать.

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

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

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

svm пишет:

А если заменить 0 на 255 ?

if (mode < 255) будет действительно всегда, кроме если mode=255

У меня, я уже писал, работает всё в исходном виде. Сдаётся мне, не в коде дело.

svm
Offline
Зарегистрирован: 06.11.2016

seri0shka пишет:

svm пишет:

А если заменить 0 на 255 ?

if (mode < 255) будет действительно всегда, кроме если mode=255

У меня, я уже писал, работает всё в исходном виде. Сдаётся мне, не в коде дело.

if (mode < 255) заменить на if (mode == 255) т.к. 0-1=255

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

svm пишет:

if (mode < 255) заменить на if (mode == 255) т.к. 0-1=255

А теперь ещё раз просмотрите пост 4225. Так и было изначально. Не в коде дело.

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

В коде или нет вам решать. Вот в таком виде все работает. Но))))  результат есть!

1. Прокрутка меню в верх, пропадает треугольник (вниз как положено бегает по кругу) -не критично

2. Не правильно показывает частоту когда появляется "а" (завышает сильно).

#define BUFSIZE 700 стали работать кнопки везде, а 600 только меню и осццил.

#define BUFSIZE 700
#define history 50

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}; //именнованный список триггеров-событий
bool flag = 0;

//#include <EEPROM.h>
#define RES 3
#define CS 4
#define Data 6
#define Clock 7
#define swap(a, b) { int t = a; a = b; b = t; }

#include <FreqCount.h>
#include <PWM.h>
// Настройки пользователя - можно менять
#define OVERCLOCK 16  // частота на которой работает Ардуино
float VCC = 5.0;      // напряжение питания
#define KEY_L  11 // кнопка ЛЕВО  (можно любой пин)
#define KEY_OK 12 // кнопка ОК    (можно любой пин)
#define KEY_R  13 // кнопка ПРАВО (можно любой пин)
#define KEY_P  8 // кнопка PAUSE (можно любой пин)
#define KEY_DELAY 200
#define LCDX 96
// Переменные, дефайны и прочяя хрень - менять со смыслом
#define GEN_PIN  9  // 9 пин для генератора сигналов (не менять)
#define DDS_PIN  10 // 10 пин для генератора dds (не менять)

#include <avr/pgmspace.h>
const char string_0[] PROGMEM = "Осциллограф";   // "String 0" и т.д. - это содержимое строк; если необходимо меняйте его
const char string_1[] PROGMEM = "Генератор";
const char string_2[] PROGMEM = "DDSгенератор";
const char string_3[] PROGMEM = "Терминал";
const char string_4[] PROGMEM = "Анализатор";
const char string_5[] PROGMEM = " ";
const char string_6[] PROGMEM = "V bat=";
const char string_7[] PROGMEM = " PWM=";
const char string_8[] PROGMEM = " Pause ";
const char string_9[] PROGMEM = "Частота";
const char string_10[] PROGMEM = "    Синус    ";
const char string_11[] PROGMEM = " Треугольник ";
const char string_12[] PROGMEM = "    Пила     ";
const char string_13[] PROGMEM = "Обратная пила";
const char string_14[] PROGMEM = "Скорость:";
// Теперь создаем таблицу с отсылками к этим строкам:
const char* const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7, string_8, string_9, string_10, string_11, string_12, string_13, string_14};
char buffer[13];    // массив должен быть достаточно велик, чтобы вместить даже самую большую строку

byte symbol1 = 0;
byte symbol2 = 0;
byte symbol3 = 0;
byte mode = 0; // пункт главного меню
byte menu = 0; // пункт меню
byte adcBuf[BUFSIZE];
byte vSync = 30; // уровень синхронизации
bool vRef = 1; // флаг опорного напряжения
bool pause = 0; // флаг режима паузы
byte TextColor = 1;
byte razv = 3;
byte trig = 0;
int grOffset = 0; // смещение графика в рабочем режиме
byte vMax, vMin; // максимальное и минимальное напряжение сигнала
// Переменные для генератора
int PWM = 50; // стартовое значение ШИМ от 0 до 100 для генератора
int temp = 0; // временная переменная***
unsigned long freq = 1000; // стартовое значение частоты в Гц для генератора
unsigned long stepFreq = 0;
unsigned long count = 1;
byte LCD_RAM[96 * 9]; // 96 * 9

static const char font[] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00 ,  // 0x20   space
  0x00, 0x00, 0x5f, 0x00, 0x00 ,  // 0x21   !
  0x00, 0x07, 0x00, 0x07, 0x00 ,  // 0x22   "
  0x14, 0x7f, 0x14, 0x7f, 0x14 ,  // 0x23   #
  0x24, 0x2a, 0x7f, 0x2a, 0x12 ,  // 0x24   $
  0x23, 0x13, 0x08, 0x64, 0x62 ,  // 0x25   %
  0x36, 0x49, 0x55, 0x22, 0x50 ,  // 0x26   &
  0x00, 0x05, 0x03, 0x00, 0x00 ,  // 0x27   '
  0x00, 0x1c, 0x22, 0x41, 0x00 ,  // 0x28   (
  0x00, 0x41, 0x22, 0x1c, 0x00 ,  // 0x29   )
  0x14, 0x08, 0x3e, 0x08, 0x14 ,  // 0x2a   *
  0x08, 0x08, 0x3e, 0x08, 0x08 ,  // 0x2b   +
  0x00, 0x50, 0x30, 0x00, 0x00 ,  // 0x2c   ,
  0x08, 0x08, 0x08, 0x08, 0x08 ,  // 0x2d   -
  0x00, 0x60, 0x60, 0x00, 0x00 ,  // 0x2e   .
  0x20, 0x10, 0x08, 0x04, 0x02 ,  // 0x2f   /
  0x3e, 0x51, 0x49, 0x45, 0x3e ,  // 0x30   0
  0x00, 0x42, 0x7f, 0x40, 0x00 ,  // 0x31   1
  0x42, 0x61, 0x51, 0x49, 0x46 ,  // 0x32   2
  0x21, 0x41, 0x45, 0x4b, 0x31 ,  // 0x33   3
  0x18, 0x14, 0x12, 0x7f, 0x10 ,  // 0x34   4
  0x27, 0x45, 0x45, 0x45, 0x39 ,  // 0x35   5
  0x3c, 0x4a, 0x49, 0x49, 0x30 ,  // 0x36   6
  0x01, 0x71, 0x09, 0x05, 0x03 ,  // 0x37   7
  0x36, 0x49, 0x49, 0x49, 0x36 ,  // 0x38   8
  0x06, 0x49, 0x49, 0x29, 0x1e ,  // 0x39   9
  0x00, 0x36, 0x36, 0x00, 0x00 ,  // 0x3a   :
  0x00, 0x56, 0x36, 0x00, 0x00 ,  // 0x3b   ;
  0x08, 0x14, 0x22, 0x41, 0x00 ,  // 0x3c   <
  0x14, 0x14, 0x14, 0x14, 0x14 ,  // 0x3d   =
  0x00, 0x41, 0x22, 0x14, 0x08 ,  // 0x3e   >
  0x02, 0x01, 0x51, 0x09, 0x06 ,  // 0x3f   ?
  0x32, 0x49, 0x79, 0x41, 0x3e ,  // 0x40   @
  0x7e, 0x11, 0x11, 0x11, 0x7e ,  // 0x41   A
  0x7f, 0x49, 0x49, 0x49, 0x36 ,  // 0x42   B
  0x3e, 0x41, 0x41, 0x41, 0x22 ,  // 0x43   C
  0x7f, 0x41, 0x41, 0x22, 0x1c ,  // 0x44   D
  0x7f, 0x49, 0x49, 0x49, 0x41 ,  // 0x45   E
  0x7f, 0x09, 0x09, 0x09, 0x01 ,  // 0x46   F
  0x3e, 0x41, 0x49, 0x49, 0x7a ,  // 0x47   G
  0x7f, 0x08, 0x08, 0x08, 0x7f ,  // 0x48   H
  0x00, 0x41, 0x7f, 0x41, 0x00 ,  // 0x49   I
  0x20, 0x40, 0x41, 0x3f, 0x01 ,  // 0x4a   J
  0x7f, 0x08, 0x14, 0x22, 0x41 ,  // 0x4b   K
  0x7f, 0x40, 0x40, 0x40, 0x40 ,  // 0x4c   L
  0x7f, 0x02, 0x0c, 0x02, 0x7f ,  // 0x4d   M
  0x7f, 0x04, 0x08, 0x10, 0x7f ,  // 0x4e   N
  0x3e, 0x41, 0x41, 0x41, 0x3e ,  // 0x4f   O
  0x7f, 0x09, 0x09, 0x09, 0x06 ,  // 0x50   P
  0x3e, 0x41, 0x51, 0x21, 0x5e ,  // 0x51   Q
  0x7f, 0x09, 0x19, 0x29, 0x46 ,  // 0x52   R
  0x46, 0x49, 0x49, 0x49, 0x31 ,  // 0x53   S
  0x01, 0x01, 0x7f, 0x01, 0x01 ,  // 0x54   T
  0x3f, 0x40, 0x40, 0x40, 0x3f ,  // 0x55   U
  0x1f, 0x20, 0x40, 0x20, 0x1f ,  // 0x56   V
  0x3f, 0x40, 0x38, 0x40, 0x3f ,  // 0x57   W
  0x63, 0x14, 0x08, 0x14, 0x63 ,  // 0x58   X
  0x07, 0x08, 0x70, 0x08, 0x07 ,  // 0x59   Y
  0x61, 0x51, 0x49, 0x45, 0x43 ,  // 0x5a   Z
  0x00, 0x7f, 0x41, 0x41, 0x00 ,  // 0x5b   [
  0x02, 0x04, 0x08, 0x10, 0x20 ,  // 0x5c   backslash
  0x00, 0x41, 0x41, 0x7f, 0x00 ,  // 0x5d   ]
  0x04, 0x02, 0x01, 0x02, 0x04 ,  // 0x5e   ^
  0x40, 0x40, 0x40, 0x40, 0x40 ,  // 0x5f   _
  0x00, 0x01, 0x02, 0x04, 0x00 ,  // 0x60   `
  0x20, 0x54, 0x54, 0x54, 0x78 ,  // 0x61   a
  0x7f, 0x48, 0x44, 0x44, 0x38 ,  // 0x62   b
  0x38, 0x44, 0x44, 0x44, 0x20 ,  // 0x63   c
  0x38, 0x44, 0x44, 0x48, 0x7f ,  // 0x64   d
  0x38, 0x54, 0x54, 0x54, 0x18 ,  // 0x65   e
  0x08, 0x7e, 0x09, 0x01, 0x02 ,  // 0x66   f
  0x0c, 0x52, 0x52, 0x52, 0x3e ,  // 0x67   g
  0x7f, 0x08, 0x04, 0x04, 0x78 ,  // 0x68   h
  0x00, 0x44, 0x7d, 0x40, 0x00 ,  // 0x69   i
  0x20, 0x40, 0x44, 0x3d, 0x00 ,  // 0x6a   j
  0x7f, 0x10, 0x28, 0x44, 0x00 ,  // 0x6b   k
  0x00, 0x41, 0x7f, 0x40, 0x00 ,  // 0x6c   l
  0x7c, 0x04, 0x18, 0x04, 0x78 ,  // 0x6d   m
  0x7c, 0x08, 0x04, 0x04, 0x78 ,  // 0x6e   n
  0x38, 0x44, 0x44, 0x44, 0x38 ,  // 0x6f   o
  0x7c, 0x14, 0x14, 0x14, 0x08 ,  // 0x70   p
  0x08, 0x14, 0x14, 0x18, 0x7c ,  // 0x71   q
  0x7c, 0x08, 0x04, 0x04, 0x08 ,  // 0x72   r
  0x48, 0x54, 0x54, 0x54, 0x20 ,  // 0x73   s
  0x04, 0x3f, 0x44, 0x40, 0x20 ,  // 0x74   t
  0x3c, 0x40, 0x40, 0x20, 0x7c ,  // 0x75   u
  0x1c, 0x20, 0x40, 0x20, 0x1c ,  // 0x76   v
  0x3c, 0x40, 0x30, 0x40, 0x3c ,  // 0x77   w
  0x44, 0x28, 0x10, 0x28, 0x44 ,  // 0x78   x
  0x0c, 0x50, 0x50, 0x50, 0x3c ,  // 0x79   y
  0x44, 0x64, 0x54, 0x4c, 0x44 ,  // 0x7a   z
  0x00, 0x08, 0x36, 0x41, 0x00 ,  // 0x7b   {
  0x00, 0x00, 0x7f, 0x00, 0x00 ,  // 0x7c   |
  0x00, 0x41, 0x36, 0x08, 0x00 ,  // 0x7d   }
  0x10, 0x08, 0x08, 0x10, 0x08 ,  // 0x7e   ~
  0x00, 0x00, 0x00, 0x00, 0x00 ,  // 0x7f
  0x7e, 0x11, 0x11, 0x11, 0x7e ,  // 0x80   A  // Русские символы
  0x7f, 0x49, 0x49, 0x49, 0x33 ,  // 0x81   Б
  0x7f, 0x49, 0x49, 0x49, 0x36 ,  // 0x82   В
  0x7f, 0x01, 0x01, 0x01, 0x03 ,  // 0x83   Г
  0xe0, 0x51, 0x4f, 0x41, 0xff ,  // 0x84   Д
  0x7f, 0x49, 0x49, 0x49, 0x41 ,  // 0x85   E
  0x77, 0x08, 0x7f, 0x08, 0x77 ,  // 0x86   Ж
  0x41, 0x49, 0x49, 0x49, 0x36 ,  // 0x87   З
  0x7f, 0x10, 0x08, 0x04, 0x7f ,  // 0x88   И
  0x7c, 0x21, 0x12, 0x09, 0x7c ,  // 0x89   Й
  0x7f, 0x08, 0x14, 0x22, 0x41 ,  // 0x8A   K
  0x20, 0x41, 0x3f, 0x01, 0x7f ,  // 0x8B   Л
  0x7f, 0x02, 0x0c, 0x02, 0x7f ,  // 0x8C   M
  0x7f, 0x08, 0x08, 0x08, 0x7f ,  // 0x8D   H
  0x3e, 0x41, 0x41, 0x41, 0x3e ,  // 0x8E   O
  0x7f, 0x01, 0x01, 0x01, 0x7f ,  // 0x8F   П
  0x7f, 0x09, 0x09, 0x09, 0x06 ,  // 0x90   P
  0x3e, 0x41, 0x41, 0x41, 0x22 ,  // 0x91   C
  0x01, 0x01, 0x7f, 0x01, 0x01 ,  // 0x92   T
  0x47, 0x28, 0x10, 0x08, 0x07 ,  // 0x93   У
  0x1c, 0x22, 0x7f, 0x22, 0x1c ,  // 0x94   Ф
  0x63, 0x14, 0x08, 0x14, 0x63 ,  // 0x95   X
  0x7f, 0x40, 0x40, 0x40, 0xff ,  // 0x96   Ц
  0x07, 0x08, 0x08, 0x08, 0x7f ,  // 0x97   Ч
  0x7f, 0x40, 0x7f, 0x40, 0x7f ,  // 0x98   Ш
  0x7f, 0x40, 0x7f, 0x40, 0xff ,  // 0x99   Щ
  0x01, 0x7f, 0x48, 0x48, 0x30 ,  // 0x9A   Ъ
  0x7f, 0x48, 0x30, 0x00, 0x7f ,  // 0x9B   Ы
  0x00, 0x7f, 0x48, 0x48, 0x30 ,  // 0x9C   Э
  0x22, 0x41, 0x49, 0x49, 0x3e ,  // 0x9D   Ь
  0x7f, 0x08, 0x3e, 0x41, 0x3e ,  // 0x9E   Ю
  0x46, 0x29, 0x19, 0x09, 0x7f ,  // 0x9F   Я
  0x20, 0x54, 0x54, 0x54, 0x78 ,  // 0xA0   a
  0x3c, 0x4a, 0x4a, 0x49, 0x31 ,  // 0xA1   б
  0x7c, 0x54, 0x54, 0x54, 0x28 ,  // 0xA2   в
  0x7c, 0x04, 0x04, 0x04, 0x0c ,  // 0xA3   г
  0xe0, 0x54, 0x4c, 0x44, 0xfc ,  // 0xA4   д
  0x38, 0x54, 0x54, 0x54, 0x18 ,  // 0xA5   e
  0x6c, 0x10, 0x7c, 0x10, 0x6c ,  // 0xA6   ж
  0x44, 0x44, 0x54, 0x54, 0x28 ,  // 0xA7   з
  0x7c, 0x20, 0x10, 0x08, 0x7c ,  // 0xA8   и
  0x7c, 0x41, 0x22, 0x11, 0x7c ,  // 0xA9   й
  0x7c, 0x10, 0x10, 0x28, 0x44 ,  // 0xAA   к
  0x20, 0x44, 0x3c, 0x04, 0x7c ,  // 0xAB   л
  0x7c, 0x08, 0x10, 0x08, 0x7c ,  // 0xAC   м
  0x7c, 0x10, 0x10, 0x10, 0x7c ,  // 0xAD   н
  0x38, 0x44, 0x44, 0x44, 0x38 ,  // 0xAE   o
  0x7c, 0x04, 0x04, 0x04, 0x7c ,  // 0xAF   п
  0x7C, 0x14, 0x14, 0x14, 0x08 ,  // 0xB0   p
  0x38, 0x44, 0x44, 0x44, 0x20 ,  // 0xB1   c
  0x04, 0x04, 0x7c, 0x04, 0x04 ,  // 0xB2   т
  0x0C, 0x50, 0x50, 0x50, 0x3C ,  // 0xB3   у
  0x30, 0x48, 0xfc, 0x48, 0x30 ,  // 0xB4   ф
  0x44, 0x28, 0x10, 0x28, 0x44 ,  // 0xB5   x
  0x7c, 0x40, 0x40, 0x40, 0xfc ,  // 0xB6   ц
  0x0c, 0x10, 0x10, 0x10, 0x7c ,  // 0xB7   ч
  0x7c, 0x40, 0x7c, 0x40, 0x7c ,  // 0xB8   ш
  0x7c, 0x40, 0x7c, 0x40, 0xfc ,  // 0xB9   щ
  0x04, 0x7c, 0x50, 0x50, 0x20 ,  // 0xBA   ъ
  0x7c, 0x50, 0x50, 0x20, 0x7c ,  // 0xBB   ы
  0x7c, 0x50, 0x50, 0x20, 0x00 ,  // 0xBC   ь
  0x28, 0x44, 0x54, 0x54, 0x38 ,  // 0xBD   э
  0x7c, 0x10, 0x38, 0x44, 0x38 ,  // 0xBE   ю
  0x08, 0x54, 0x34, 0x14, 0x7c ,  // 0xBF   я
};

//********************************************************
void setup()  {
//  pinMode(8, OUTPUT); // 7, 8- питание на дисплей
//  pinMode(7, OUTPUT);
//  digitalWrite(8, 1);
//  digitalWrite(7, 0);
  pinMode(KEY_OK, INPUT); pinMode(KEY_L, INPUT); pinMode(KEY_R, INPUT); pinMode(KEY_P, INPUT); // настраиваем кнопки на вход
  digitalWrite(KEY_OK, HIGH); digitalWrite(KEY_L, HIGH); digitalWrite(KEY_R, HIGH); digitalWrite(KEY_P, HIGH); // подтяжка к плюсу питания
  VCC = ReadVcc();
  Inicialize();  //Инициализация дисплея
  Clear_LCD();
  ukazatel();//fillTriangle(1, mode * 10); // указатель меню
  // drawChar(1, mode * 10, 1, ">");
  //char Str2[8] = {'a', 'r', 'd', 'u', 'i', 'n', 'o'};
  /*   print(10, 0, 1, "Oscillograf");
   print(10, 10, 1, "Generator");
   print(10, 20, 1, "DDSgenerator");
   print(10, 30, 1, "Terminal");
   print(10, 40, 1, "Analizator");*/
  for (byte i = 0; i < 7; i++)
  {
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // необходимые функции и расшифровки, просто скопируйте
    print(10, i * 10, 1, (buffer));
    //delay( 500 );
  }
  /*print(10, 0, 1, "Осциллограф");
  print(10, 10, 1, "Генератор");
  print(10, 20, 1, "DDSгенератор");
  print(10, 30, 1, "Терминал");
  print(10, 40, 1, "Анализатор");
  print(10, 60, 1, "V bat="); // *************/
  float_print(48, 60, 1, VCC, 2);
  Update();
  delay(KEY_DELAY);

  while (digitalRead(KEY_OK)) { // цикл, пока не нажали кнопку ОК
  // опрос кнопок
  if (!digitalRead(KEY_R)) {
    mode = mode + 1;
    if (mode > 5  ) {mode = 0;}
    ukazatel();
  }
  if (!digitalRead(KEY_L)) {
    mode = mode - 1;
    if (mode < 0) {mode = 5;}
    ukazatel();
 }   
  Update();
} // цикл нажатия ОК
  // нажали кнопку ОК из меню, инициализируем и выходим из меню
  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 || mode == 5) DDRC = 0x00; PORTC = 0x00; Serial.begin(115200); // razv = 0;// весь порт С (это A0...A5) на вход и без подтяжки
}
// беcконечный цикл - по сути прыгаем в подпрограммы
void loop() {
  switch (mode) {
    // Прыгаем в выбранный режим из главного меню
    case 0 : Oscil();        break; // "выпадаем" в осцилл
    case 1 : Generator();    break; // "выпадаем" в генератор
    case 2 : DdsGenerator(); break; // "выпадаем" в DDS генератор
    case 3 : Terminal();     break; // "выпадаем" в USART приемник
    case 4 : LogAnalyzer();  break; // "выпадаем" в Анализатор
    case 5 : LogAnalyzer();  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;             // записываем данные в массив
    }
  }
}

// === Чтение цифровых данных со всего порта 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);
    }
  }
}*/

// ==== функция вывода float ====
void float_print(byte x, byte y, boolean color, float num, byte zn) { // последняя переменная- кол знаков после запятой
  char c[20];
  long d = num;
  byte m = 1;
  while (d > 9) {
    d = d / 10;
    m++;
  }
  print(x, y, color, dtostrf(num, m, zn, c));
}

// ==== Считывание напряжения питания ардуинки (Vcc) ====
#define Vref11 1.104 // для точной подстройки результата измерений
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));        // результат преобразования в вольтах
}

/*int GetCountsOfDigits(int n) //найти количество цифр в числе <a href="<a href="https://habr.com/ru/post/269237/" rel="nofollow">https://habr.com/ru/post/269237/</a>" rel="nofollow"><a href="https://habr.com/ru/post/269237/" rel="nofollow">https://habr.com/ru/post/269237/</a></a>
{
  return n < 10 ? 1 :
         n < 100 ? 2 :
         n < 1000 ? 3 :
         n < 10000 ? 4 :
         n < 100000 ? 5 :
         n < 1000000 ? 6 :
         n < 10000000 ? 7 :
         n < 100000000 ? 8 :
         n < 1000000000 ? 9 : 10;
}*/

// ==== найти количество цифр в числе   <a href="<a href="https://habr.com/ru/post/269237/" rel="nofollow">https://habr.com/ru/post/269237/</a>" rel="nofollow"><a href="https://habr.com/ru/post/269237/" rel="nofollow">https://habr.com/ru/post/269237/</a></a>
/*static int stringSize(long x) {
  long p = 10;
  for (int i = 1; i < 19; i++) {
    if (x < p)
      return i;
    p = 10 * p;
  }
  return 19;
}*/

void vivod(byte x, byte y, byte n, byte k) { // //Печать цифры размером 24х48 пикселя (x, y, цифра, размер (1-24х48, 2-12х24))
  if ((n != 1) && (n != 4)) {
    fillRect(x + 3 / k, y, 15 / k, 5 / k, 1  ); // сегмент A
  }
  if ((n != 5) && (n != 6)) {
    fillRect(x + 16 / k, y + 3 / k, 5 / k, 20 / k, 1  ); // сегмент B
  }
  if (n != 2) {
    fillRect(x + 16 / k, y + 24 / k, 5 / k, 20 / k, 1  ); // сегмент C
  }
  if ((n != 1) && (n != 4) && (n != 7)) {
    fillRect(x + 3 / k, y + 42 / k,  15 / k, 5 / k, 1  ); // сегмент D
  }
  if ((n == 0) || (n == 2) || (n == 6) || (n == 8)) {
    fillRect(x, y + 24 / k, 5 / k, 20 / k, 1  ); // сегмент E
  }
  if ((n != 1) && (n != 2) && (n != 3) && (n != 7)) {
    fillRect(x, y + 3 / k, 5 / k, 20 / k, 1  ); // сегмент F
  }
  if ((n != 0) && (n != 1) && (n != 7)) {
    fillRect(x + 3 / k, y + 21 / k,  15 / k, 5 / k, 1  ); // сегмент G
  }
}

//====================================================указатель меню
void ukazatel() {
  fillRect(1, 1, 8, 60, 0);
  for (byte i = 0; i < 4; i++) {                                  // указатель меню
    drawLine(1 + i, mode * 10 + i, 1 + i, mode * 10 + 6 - i, 1);
  }
  Update();
  delay(KEY_DELAY);
}


//===================================================Инициализация дисплея
void Inicialize() {
  pinMode(RES,   OUTPUT);
  pinMode(CS,    OUTPUT);
  pinMode(Data,  OUTPUT);
  pinMode(Clock, OUTPUT);
  // Инициализация дисплея
  dWrite(RES, 1);
  dWrite(Clock, 0);
  dWrite(Data, 0);
  dWrite(CS, 0);
  delay(20);
  dWrite(CS, 1);
  SendByte(0, 0x2F);           // Power control set(charge pump on/off)
  SendByte(0, 0xA4);
  SendByte(0, 0xAF);           // экран вкл/выкл
  //Clear_LCD();
  //Update();
}

//=======================================================Управление пинами
void dWrite(byte pin, byte val) {
  byte bit = digitalPinToBitMask(pin);
  volatile byte *out;
  out = portOutputRegister(digitalPinToPort(pin));
  (val) ? *out |= bit : *out &= ~bit;
}

//=========================================================Отправка 9 байт
void SendByte(byte mode, byte c) {
  dWrite(CS, 0);
  (mode) ? dWrite(Data, 1) : dWrite(Data, 0);
  dWrite(Clock, 1);
  for (byte i = 0; i < 8; i++) {
    dWrite(Clock, 0);
    (c & 0x80) ? dWrite(Data, 1) : dWrite(Data, 0);
    dWrite(Clock, 1);
    c <<= 1;
  }
  dWrite(Clock, 0);
}

//======================================================Очистка дисплея
void Clear_LCD() {
  for (int index = 0; index < 864 ; index++) {
    LCD_RAM[index] = (0x00);
  }
}

//=====================================================Обновить дисплей
void Update() {
  for (byte p = 0; p < 9; p++) {
    SendByte(0, 0xB0 | p);
    SendByte(0, 0x00);
    SendByte(0, 0x10);
    for (byte col = 0; col < 96; col++) {
      SendByte(1, LCD_RAM[(96 * p) + col]);
    }
  }
}

//===================================================Нарисовать пиксель
void drawPixel (byte x, byte y, boolean color) {
  if ((x < 0) || (x >= 96) || (y < 0) || (y >= 68)) return;
  if (color) LCD_RAM[x + (y / 8) * 96] |= _BV(y % 8);
  else       LCD_RAM[x + (y / 8) * 96] &= ~_BV(y % 8);
}

//=====================================================Нарисовать букву
void drawChar(byte x, byte y, boolean color, unsigned char c) {
  if ((x >= 96) || (y >= 68) || ((x + 4) < 0) || ((y + 7) < 0)) return;
  if (c < 128)            c = c - 32;
  if (c >= 144 && c <= 175) c = c - 48;
  if (c >= 128 && c <= 143) c = c + 16;
  if (c >= 176 && c <= 191) c = c - 48;
  if (c > 191)  return;
  for (byte i = 0; i < 6; i++ ) {
    byte line;
    (i == 5) ? line = 0x0 : line = pgm_read_byte(font + (c * 5) + i); // line = EEPROM.read((c * 5) + i);
    for (byte j = 0; j < 8; j++) {
      (line & 0x1) ? drawPixel(x + i, y + j, color) : drawPixel(x + i, y + j, !color);
      line >>= 1;
    }
  }
}

//========================================================Вывод строки
void print(byte x, byte y, boolean color, char *str) {
  unsigned char type = *str;
  if (type >= 128) x = x - 3;
  while (*str) {
    drawChar(x, y, color, *str++);
    unsigned char type = *str;
    (type >= 128) ? x = x + 3 : x = x + 6;
  }
}

//========================================================Вывод числовых значений
void print(byte x, byte y, boolean color, long num) {
  char c[20];
  print(x, y, color, ltoa(num, c, 10));
}

//====================================================Рисование линии
void drawLine(byte x0, byte y0, byte x1, byte y1, boolean color) {
  int steep = abs(y1 - y0) > abs(x1 - x0);
  if (steep) {
    swap(x0, y0);
    swap(x1, y1);
  }
  if (x0 > x1) {
    swap(x0, x1);
    swap(y0, y1);
  }
  int dx, dy;
  dx = x1 - x0;
  dy = abs(y1 - y0);
  int err = dx / 2;
  int ystep;
  (y0 < y1) ?  ystep = 1 : ystep = -1;
  for (; x0 <= x1; x0++) {
    (steep) ? drawPixel(y0, x0, color) : drawPixel(x0, y0, color);
    err -= dy;
    if (err < 0) {
      y0 += ystep;
      err += dx;
    }
  }
}

//========================================Рисование вертикальной линии
void drawFastVLine(byte x, byte y, byte h, boolean color) {
  drawLine(x, y, x, y + h - 1, color);
}

//======================================Рисование горизонтальной линии
void drawFastHLine(byte x, byte y, byte w, boolean color) {
  drawLine(x, y, x + w - 1, y, color);
}

//=====================================Рисование залитый прямоугольник
void fillRect(byte x, byte y, byte w, byte h, boolean color) {
  for (byte i = x; i < x + w; i++) {
    drawFastVLine(i, y, h, color);
  }
}

//=====================================Рисование битового нолика
void printnull(byte a, byte i) {
  drawPixel(29 + a - i * 4, 64, 1);
  drawFastVLine(28 + a - i * 4, 65, 2, 1); // и вывести биты на дисплей
  drawFastVLine(30 + a - i * 4, 65, 2, 1);
  drawPixel(29 + a - i * 4, 67, 1);
}


// === Осциллоскоп === //
void Oscil() {
  // установка опорного напряжения АЦП и настройка входа АЦП
  ADMUX = vRef ? 0b01100011 : 0b11100011;
  // === Обработка кнопок === //
  if (!digitalRead(KEY_L))   switch (menu) { // кнопка лево:)
      case 0 : vRef = !vRef;                                                             break; // меняем опорное напряжение
      case 1 : razv--; if (razv == 255) razv = 6;                                        break; // меняем развертку
      case 2 : grOffset -= 20; if (grOffset < 0) grOffset = 0;                           break; // листаем график в паузе
    }
  if (!digitalRead(KEY_R))  switch (menu) { // кнопка право:)
      case 0 : vRef = !vRef;                                                             break; // меняем опорное напряжение
      case 1 : razv++; if (razv == 7) razv = 0;                                          break; // меняем развертку
      case 2 : grOffset += 20; if (grOffset > BUFSIZE - LCDX) grOffset = BUFSIZE - LCDX; break; // листаем график в паузе
    }
  if (!digitalRead(KEY_OK))  switch (++menu) {
      case 2: grOffset = 0; pause = 1;                                                   break; // вход в паузу - антидребезг типа
      case 3: menu = 0; pause = 0;                                                       break; // перебор меню
    }
  if (!digitalRead(KEY_P)) {
    menu = 2; pause = 1;
  }
  // === Ведём рассчеты === //
  if (!pause) { // если нет паузы
    ReadAdc();  // то снимаем осциллограмму
    // == Вычисляем максимальное и минимальное значение сигнала == //
    vMax = 0; vMin = 0xFF;
    for (int y = 1; y < 255; y++) {
      if (vMax < adcBuf[y]) vMax = adcBuf[y];  // пока 255, но надо экспериментировать
      if (vMin > adcBuf[y]) vMin = adcBuf[y];
    }
    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; // пересчет частоты на разные кварцы
  } // закончили вести рассчеты
  Clear_LCD(); // чистим экран...
  // === Отрисовка меню осцилла ===
  if (menu == 0) TextColor = 0; else TextColor = 1;
  if (vRef) float_print(0, 0, TextColor, VCC, 1); else  print(0, 0, TextColor, "1.1");
  if (menu == 1) TextColor = 0; else TextColor = 1;
  print(24, 0, TextColor, razv);
  if (menu == 2) { // тут задержка для компенсации с остальными задержками
    delay(200);
    //print(48, 0, 0, " Pause ");
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[8]))); // необходимые функции и расшифровки, просто скопируйте
    print(48, 0, 0, (buffer));
  } else TextColor = 1;
  if (!pause) float_print (48, 0, 1, count / 1000000.0, 6); // вывод частоты
  else { // рисуем прокрутку в режиме паузы
    temp = grOffset / 8;
    drawFastHLine(temp, 10, 6, 1);  drawFastHLine(temp, 9, 6, 1);
  } // шкала прокрутки
  if (vRef && vMax * VCC / 255 > 2.7)  drawChar(42, 0, 1, 97); // если замер аппаратный - "a"
  else  drawChar(42, 0, 1, 112); // иначе "p"
  float_print(78, 14, 1, vMax * (vRef ? VCC : 1.1) / 255, 1); // рисуем максимальное напряжение сигнала
  float_print(78, 54, 1, vMin * (vRef ? VCC : 1.1) / 255, 1); // рисуем минимальное  напряжение сигнала
  // if (vMax==0xFF) for(int y=0; y<4; y++) display.drawLine(y,9,y,47, BLACK); // превышение максимума АЦП
  // == Отрисовка сетки == //
  for (byte i = 11; i < 68; i = i + 14) {
    drawFastHLine( 0, i, 2, 1);  // черточки слева
  }
  for (byte i = 67; i > 10; i = i - 4) {
    drawPixel(24, i, 1);
    drawPixel(48, i, 1);
    drawPixel(72, i, 1);
  }
  for (byte i = 8; i < 96; i = i + 4) {
    drawPixel(i, 39, 1);
  }
  // == Отрисовка графика == //
  for (int y = 0; y < 92; y++)  drawLine(y + 4, 67 - adcBuf[y + grOffset] / 4.6, y + 4, 67 - adcBuf[y + grOffset + 1] / 4.6, 1);
  Update();
}

//**********************************************************************************
void Generator() {
  // обработка кнопок и отрисовка одновременно
  Clear_LCD();
  //print(0, 0, 1, "Частота");
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[9]))); // необходимые функции и расшифровки, просто скопируйте
  print(0, 0, 1, (buffer));
  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); // задали ШИМ
    TextColor = 0; // если меняем шим, то рисуем его инверсным
  } 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); // задержка для кнопок
    }
    TextColor = 1; // если ШИМ не меняем, то выбираем обычный текст
#define XFREQ 10 // ======== // и, выделяем декаду частоты полосочками
    stepFreq = pow(10, (byte)menu); if (menu > 1) stepFreq++; // устраняем глючность pow, почему 10 в степени 2 = 99?
    temp = 42 - menu * 6;
    if (temp < 10) temp = 0;
    drawFastHLine(temp, XFREQ + 10, 5, 1); // выделяем декаду частоты полосочками
    drawFastHLine(temp, XFREQ + 9, 5, 1);
  }
  // рисуем уровень ШИМ (инверсия текста задана ранее)
  drawFastHLine(15, 39 , 54, !TextColor); // сверху полоска для большей инверсности
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[7]))); // необходимые функции и расшифровки, просто скопируйте
  print(15, 40, TextColor, (buffer));   print(45, 40, TextColor, PWM);
  print(57, 40, TextColor, "% "); // выводим уровень ШИМ
  if (PWM < 10) {
    drawChar(45, 40, TextColor, 32); // " "
    print(51, 40, TextColor, PWM);
  }
  drawChar(63, 40, TextColor, 32); // " "
  if (PWM == 100)  {
    print(45, 40, TextColor, 100);
    print(63, 40, TextColor, "%");
  }
  TextColor = 1; // убираем инверсию при выводе частоты
  // print(42 - stringSize(freq) * 6, XFREQ, 1, freq); // вывод частоты
  float_print (0, XFREQ, 1, freq / 1000000.0, 6); // вывод частоты
  print(50, XFREQ, 1, "MHz");
  // отрисовка графика PWM
  for (char x = 17; x < 67; ) {
    if (PWM != 0)  drawFastHLine(x, 26, PWM / 4, 1); x += PWM / 4;             // верх
    if (PWM != 0 && PWM != 100)  drawFastVLine(x, 26, 10, 1);                  // спад
    if (PWM != 100)  drawFastHLine(x, 36, 25 - PWM / 4, 1); x += 25 - PWM / 4; // низ
    if (PWM != 0 && PWM != 100 && x < 43)  drawFastVLine( x, 26, 11, 1);       // подъем
  }
  Update(); // вываливаем буфер на дисплей
}

//**********************************************************************************
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
  };
  byte ddsCount = 0;
  // Рисуем DDS-генератор
  Clear_LCD(); // режим работы, заголовок
  for (byte i = 0; i < 96;)  drawLine(i, 36 - pgm_read_byte(&ddsWave[menu][i % 32]) / 10, i, 36 - pgm_read_byte(&ddsWave[menu][(i++) % 32]) / 10, 1);
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[10 + menu]))); // необходимые функции и расшифровки, просто скопируйте
  print(5, 40, 1, (buffer));
  /*switch (menu) { //..........
    case 0:    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[10]))); // необходимые функции и расшифровки, просто скопируйте
      print(3, 40, 1, (buffer));  break;
    case 1:    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[11]))); // необходимые функции и расшифровки, просто скопируйте
      print(3, 40, 1, (buffer));  break;
    case 2:    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[12]))); // необходимые функции и расшифровки, просто скопируйте
      print(3, 40, 1, (buffer));  break;
    case 3:    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[13]))); // необходимые функции и расшифровки, просто скопируйте
      print(3, 40, 1, (buffer));  break;
  }*/
  Update();
  while (digitalRead(KEY_R) && digitalRead(KEY_L) && digitalRead(KEY_OK)) { // выводим выбранный сигнал, пока не нажали кнопку
    pwmWrite(DDS_PIN, pgm_read_byte(&ddsWave[menu][(ddsCount++) & 0x1F]));
  }
  if (++menu == 4) menu = 0; // нажали кнопку - переключаем режим
  delay(KEY_DELAY); // чтоб кнопки нормально нажимались
}

//**********************************************************************************
void Terminal() {
  //const long speedUart[] = { 9600, 19200, 38400, 57600, 115200, 300, 600, 1200, 2400, 4800 };
  const PROGMEM  uint32_t speedUart[] = { 9600, 19200, 38400, 57600, 115200, 250000, 300, 600, 1200, 2400, 4800 }; // ------
  Clear_LCD();
  //print(10, 0, 1, "Скорость:");
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[14]))); // необходимые функции и расшифровки, просто скопируйте
  print(10, 0, 1, (buffer));
  print(10, 10, 1, speedUart[menu]);
  Update();
  if (!digitalRead(KEY_L))  {
    menu--;
    if (menu == 255) menu = 10;
    // print(28, 10, 1, "   ");
    print(10, 10, 1, speedUart[menu]);
    Update();
    delay(KEY_DELAY);
  }
  if (!digitalRead(KEY_R))  {
    menu++;
    if (menu == 11)   menu = 0;
    // print(28, 10, 1, "   ");
    print(10, 10, 1, speedUart[menu]);
    Update();
    delay(KEY_DELAY);
  }
  if (!digitalRead(KEY_OK)) {
    Clear_LCD();
    if (!digitalRead(KEY_P)) pause = 1; // включаем флаг, что пауза была нажата для вкл дополн функции
    else  drawFastHLine(10, 66 , 75, 1);
    Serial.begin(speedUart[menu] * (16 / OVERCLOCK));
    drawChar(0, 0, 0, 62);
    Update();
    delay(KEY_DELAY);
    Update();
    byte x = 0;
    byte y = 0;
    while (1) {
      if (Serial.available()) { // Если в буфере есть данные
        if (x > 90) { // проверяем, не заполнен ли экран
          x = 0;
          y = y + 8;
        }
        byte symbol = (Serial.read());
        if ((symbol == 10 || symbol == 13) && x != 0) {
          x = 0;
          y = y + 8;
        }
        if (y > 56) {
          y = 0;
          x = 0;
        }
        if (symbol != 10 && symbol != 13) {
          if (symbol == 127 || symbol == 8) { // Del
            if (x == 0) {
              x = 90;
              if (y != 0) {
                y = y - 8;
              }
              else y = 56;
            }
            else
            {
              x += -6;
            }
            drawChar(x, y, 1, 32); // " "
          }
          else {
            symbol3 = symbol2;
            symbol2 = symbol1;
            symbol1 = symbol;
            if (symbol > 191) { //русские буквы
              if (symbol > 239) {
                drawChar(x, y, 1, symbol - 112); // 
              }
              else drawChar(x, y, 1, symbol - 48); // 
            }
            else drawChar(x, y, 1, symbol);  // печать байта в дисплей
            // print(x + 6, y, 1, "               ");
            //for (byte i = 0; i < 7; i++) drawLine(x + 6, y + i, 95, y + i, 0); // очистить место
            //for (byte i = 0; i < 7; i++) drawFastHLine(x + 6, y + i, 90, 0);// не работает
            x = x + 6;
          }
        }
        for (byte i = 0; i < 7; i++) drawLine(x, y + i, 95, y + i, 0); // очистить место
        if (pause == 1) { // вывод бинарных кодов символов только если были нажаты ДВЕ кнопки
          /*char p[17]; //
          itoa (symbol, p, 16); // перевод в шестнадцатеричное
           print(0, 60, 1, p); // отображение шестнадцатеричного*/
          drawFastHLine(0, 65, 96, 0); // очистить место
          drawFastHLine(0, 66, 96, 0);
          drawPixel(31, 67, 1); // разделение байтов
          drawPixel(63, 67, 1);
          for (byte i = 0; i < 8; i++) { // разложить код символа на биты
            if (bitRead(symbol3, i)) drawFastVLine(29 - i * 4, 64, 4, 1); // биты предпредпоследнего байта
            else printnull(0, i);
            if (bitRead(symbol2, i)) drawFastVLine(61 - i * 4, 64, 4, 1); // биты предпоследнего байта
            else printnull(32, i);
            if (bitRead(symbol1, i)) drawFastVLine(94 - i * 4, 64, 4, 1); // биты последнего байта смещены на пиксель вправо
            else printnull(65, i); // биты последнего байта смещены на пиксель вправо
          }
          /*for (byte i = 0; i < 8; i++) { // разложить код символа на биты
            if (bitRead(symbol2, i) == 1)  drawFastVLine(29 + 32 - i * 4, 64, 4, 1); //  drawChar(i * 6, 56, 1, 49);
            else {//  drawChar(i * 6, 56, 1, 48);
              drawPixel(29 + 32 - i * 4, 64, 1);
              drawFastVLine(28 + 32 - i * 4, 65, 2, 1); // и вывести биты на дисплей
              drawFastVLine(30 + 32 - i * 4, 65, 2, 1);
              drawPixel(29 + 32 - i * 4, 67, 1);
            }
          }
          for (byte i = 0; i < 8; i++) { // разложить код символа на биты
            if (bitRead(symbol1, i) == 1)  drawFastVLine(29 + 64 - i * 4, 64, 4, 1); //  drawChar(i * 6, 56, 1, 49);
            else {//  drawChar(i * 6, 56, 1, 48);
              drawPixel(29 + 64 - i * 4, 64, 1);
              drawFastVLine(28 + 64 - i * 4, 65, 2, 1); // и вывести биты на дисплей
              drawFastVLine(30 + 64 - i * 4, 65, 2, 1);
              drawPixel(29 + 64 - i * 4, 67, 1);
            }
          }*/
        }
        Update();
      }
    }
  }
  Update();
}

//*********************************************************************************
void LogAnalyzer() {
  // обрабатываем кнопки
  if (!digitalRead(KEY_L)) switch (menu) {
      case 0 : razv--; if (razv == 255) razv = 19; delay(KEY_DELAY);                       break; // меняем развертку
      case 1 : trig--; if (trig == 255) trig = 3; delay(KEY_DELAY);                        break; // меняем trigger
      case 2 : grOffset -= 10; if (grOffset < 0) grOffset = 0;                             break; // листаем график в паузе
    }
  if (!digitalRead(KEY_R)) switch (menu) {
      case 0 : razv++; if (razv == 20) razv = 0; delay(KEY_DELAY);                         break; // меняем развертку
      case 1 : trig++; if (trig == 4) trig = 0; delay(KEY_DELAY);                          break; // меняем trigger
      case 2 : grOffset += 5; if (grOffset >= BUFSIZE - 50) grOffset = BUFSIZE - 50;       break; // листаем график в паузе
    }
  if (!digitalRead(KEY_OK)) switch (++menu) {
      //case 2 : grOffset = 0; pause = 1;                                                    break; // вход в паузу
      case 3 : menu = 0;     pause = 0;                                                    break; // перебор меню
        delay(KEY_DELAY);
    }
  if (!digitalRead(KEY_P)) {
    menu = 2; grOffset = 0; pause = 1; flag = 0;// вход в паузу
  }

  //if (!pause) ReadDig(); // если нет паузы - читаем данные

  Clear_LCD(); // чистим дисплей
  if ( menu == 0 ) print(0, 0, 0, razv);  // выводим развертку
  else print(0, 0, 1, razv);              // выводим развертку
  if ( menu == 1 ) print(24, 0, 0, trig); // выводим trigger
  else print(24, 0, 1, trig);             // выводим trigger
  if (pause) {
    if (flag == 0) {
      print(50, 0, 1, "Waiting");
      Update();
      switch (trig) {
        case 0 : scanLoadBus(BURST); flag = 1; menu = 2;           break;
        case 1 : scanLoadBus(MASTER_RISE); flag = 1; menu = 2;     break;
        case 2 : scanLoadBus(MASTER_FALL); flag = 1; menu = 2;     break;
        case 3 : scanLoadBus(PATTERN); flag = 1; menu = 2;         break;
      }
    }
    //print(8, 0, 1, " Pause ");
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[8]))); // необходимые функции и расшифровки, просто скопируйте
    print(50, 0, 1, (buffer));
    // рисуем прокрутку в режиме паузы
    drawLine( grOffset / 8, 8, grOffset / 8 + 6, 8,  1); // шкала прокрутки
    drawLine( grOffset / 8, 9, grOffset / 8 + 6, 9,  1); // шкала прокрутки
    delay(200);
  }
  for (byte chan = 0; chan < 4; chan++) // последовательный перебор 4-х каналов
  { int show_index = StartIndex >> 1;
    int read_index;
    print(0, 10, 1, (show_index + grOffset));
    drawLine(50, 10, 50, 15, 1);
    print(54, 10, 1, (grOffset + grOffset + 50));
    for (int x = 0; x < 48; x++ ) {
      read_index = show_index + grOffset + x;
      if (read_index >= BUFSIZE) read_index = read_index - BUFSIZE;
      if ((x % 5) == 0) {
        drawLine(x + x, 60, x + x, 64, 1); // если номер отсчета кратен 10 - рисуем черточку
        if (((grOffset + x - 100) / 5 % 10) == 0) print (x + x - 2, 60, 1, (grOffset + x) / 50);
      }
      //Декомпресиия старшей части
      if ((adcBuf[read_index] >> 4) & (1 << chan)) // выделяем соответствующий бит текущего канала
      {
        drawLine(x + x, chan * 10 + 20, x + x, chan * 10 + 24, 1); //если высокий уровень
      }
      else
      {
        drawPixel(x + x, chan * 10 + 24, 1); // если низкий уровень
      }
      //Декомпресиия младшей части
      if (adcBuf[read_index] & (1 << chan)) // выделяем соответствующий бит текущего канала
      {
        drawLine(x + x + 1, chan * 10 + 20, x + x + 1, chan * 10 + 24, 1); //если высокий уровень
      }
      else
      {
        drawPixel(x + x + 1, chan * 10 + 24, 1); // если низкий уровень
      }
    } // end y loop
  }
  Update();
}

//============================================
// Функция расчета номера замера с которого начинается вывод данных включая предисторию
// иными словами, от замера сработки тригера отнимаем (с учетом перекрутки буффера) величину предистории
//============================================
int calc_StartIndex() {
  //=========== расчет точки останова чтобы не затереть начало сработки триггера
  if (cur_index < history) //если значение тек. индекса меньше, чем размер истории
  {
    return ((BUFSIZE + BUFSIZE) + cur_index - history); //считаем таким образом
  }
  else
  {
    return (cur_index - history); // ну и если больше, то просто отнимаем
  }//=========== End расчет точки останова чтобы не затереть начало сработки триггера
}

//===========================================================
// Процедура записи данных данных в буфер
// тут происходит запись сжатых данных и увеличение текущего индекса замера
// запись будет происходить при нечетном значении индекса (т.е., считаны уже два значения)
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 == (BUFSIZE + BUFSIZE)) cur_index = 0; //если достигли конца буфера - сброс и все сначала
} //end rec_data

//============================================
// Процедура сканирования шины и отлов сработки триггеров
// При сканировании шины будем учитывать тип триггера: typeTriggerEvent
// Чтобы считать значения младших четырех бит (PORTC0, PORTC1, PORTC2, PORTC3)
// нужно делать так: my_var1 = PINC & b00001111; // такой операцией мы обнулим старшие 4 бит и получим ТОЛЬКО младшие 4-ре
//============================================
void scan_bus(byte typeTriggerEvent) {
  while (!trigger_event)
  {
    // ПЕРВЫМ делом нужно считать данные с шины, а уже потом будем разбираться со всякими сверками и расчетами
    byte cur_data = (PINC & B00001111); //сразу же считываем состояние пинов порта
    // ниже отладочная пришлепка для примерной оценки скорости оцифровки
    // по частоте переключения пина будем судить о скорости
    // данные считаны, теперь проверяем есть ли условия сработки триггера и если ДА, запоминаем номер замера (0-1024)
    switch (typeTriggerEvent) //ветвимся в зависимости от режима триггера
    {
      // BURST Mode Любое изменение на любом канале
      case (BURST):
        if (cur_data != prev_data)
        {
          trigger_event = true; //ставим признак сработки триггера
          StartIndex = calc_StartIndex(); // расчет номера замера с которого будем делать вывод
        }
        break;
      //---------------------------------
      // master channel RISE (переход из 0 в 1)
      case (MASTER_RISE):
        if (~prev_data & cur_data & 1)
        {
          trigger_event = true; //ставим признак сработки триггера
          StartIndex = calc_StartIndex(); // расчет номера замера с которого будем делать вывод
        }
        break;
      //---------------------------------
      // master chanel FALL (переход из 1 в 0)
      case (MASTER_FALL):
        if (prev_data & ~cur_data & 1)
        {
          trigger_event = true; //ставим признак сработки триггера
          StartIndex = calc_StartIndex(); // расчет номера замера с которого будем делать вывод
        }
        break;
      //---------------------------------
      // PATTERN (определенное состояние шины)
      case (PATTERN):
        //if ((cur_data & pattern_mask) == pattern_value) // если проверка на совпадение условий прошла
        if ((cur_data & 7) == 5) // если проверка на совпадение условий прошла
        {
          trigger_event = true; //ставим признак сработки триггера
          StartIndex = calc_StartIndex(); // расчет номера замера с которого будем делать вывод
        }
        break;
    } //End switch (typeTriggerEvent)
    rec_data(cur_data); //запись данных в буффер
    if ((cur_index == 0) && Serial.available()) break; //единственный способ прервать - при нулевом индексе что-то появилось в ком-порту
    delayMicroseconds(razv * 4);
  } //end while
}// end load data

//====== read_bus ============
// тупо пишем состояние каналов
void read_bus() {
  prevMillis = millis(); //запоминаем время начала записи истории
  while (cur_index != StartIndex)
  {
    rec_data(PINC & B00001111); //запись данных в буффер
    delayMicroseconds(razv * 4);
  } //end while
  curMillis = millis(); //время конца записи истории
}

//==================
// инициализация перед замерами
//Обнуляем буффер, сбрасываем индексы и запоминаем состояние шины
void init_logic() {
  for (int i = 0; i <= BUFSIZE; i++) //в цикле затиранием рабочий массив
  {
    adcBuf[i] = 0;
  }
  cur_index = 0; // сбрасываем счетчик замеров
  StartIndex = 0; // сбрасываем положение начала данных для вывода
  time_disc = 0; // сбрасываем значения интервала одной выборки
  trigger_event = false; //сбрасываем признак сработки триггера
  prev_data = (PINC & B00001111); //сформируем пред. замер состояние пинов порта
} // end logic init

//========================================================
// процедура отображения полезной (и не очень) информации
void show_info(byte typeTriggerEvent) {
  // немного расчетов "для красоты": для считывания ((BUFSIZE+BUFSIZE)-history) количества замеров требуется
  // сколько-то милисекунд (или, если умножить на 1000 - микросекунд) посчитаем, сколько микросекунд уходит на одну выборку (естественно, ОЧЕНЬ-ОЧЕНЬ ПРИМЕРНО)
  time_disc = ((curMillis - prevMillis) * 1000) / (((BUFSIZE + BUFSIZE) - history)); //время выборки одного замера
  Serial.println(F("---------------------------------------------------------"));
  Serial.print(F("Record size=")); Serial.print((BUFSIZE + BUFSIZE) - history, DEC); Serial.print(F("  Pre-history size=")); Serial.println(history, DEC);
  Serial.print(F("Current Trigger: "));
  switch (typeTriggerEvent) {
    case (MASTER_RISE):
      Serial.println(F("Master (Ch0) RISE (0->1)"));
      break;
    case (MASTER_FALL):
      Serial.println(F("Master (Ch0) FALL (1->0)"));
      break;
    case (BURST):
      Serial.println(F("Change on any channel"));
      break;
    case (PATTERN):
      Serial.print(F("Bus status"));
      Serial.print(F("  MASK / VALUE =")); Serial.print(pattern_mask, HEX); Serial.print(F(" / ")); Serial.println(pattern_value, HEX);
      break;
  } //end switch
  //Serial.print("Start/Stop =");Serial.print(prevMillis);Serial.print(" / "); Serial.print(curMillis);
  //Serial.print("[Ind Start = ");Serial.print(StartIndex);Serial.print("] ");
  Serial.print(F("Time: 1 div = ")); Serial.print(time_disc); Serial.println(F(" (uSec)"));
  Serial.println(F("******************************************"));
}

//==============================
// Процедура орисовки результатов в виде псевдографика
// процедура достаточно медленная, но буфер к этому моменту заполнен, так что скорость тут УЖЕ не важна
//==============================
void show_graph() {
  for (byte chan = 0; chan < 4; chan++) // последовательный перебор 4-х каналов
  {
    Serial.print(F("Ch N")); Serial.print(chan);
    int show_index = StartIndex >> 1;
    Serial.print(F("\t"));
    for (int y = 0; y < BUFSIZE; y++ )
    {
      if (show_index == BUFSIZE) show_index = 0;
      //Декомпресиия старшей части
      if ((adcBuf[show_index] >> 4) & (1 << chan)) // выделяем соответствующий бит текущего канала
      {
        Serial.print(F("-")); //если высокий уровень
      }
      else
      {
        Serial.print(F("_")); // если низкий уровень
      }
      //Декомпресиия младшей части
      if (adcBuf[show_index] & (1 << chan)) // выделяем соответствующий бит текущего канала
      {
        Serial.print(F("-")); //если высокий уровень
      }
      else
      {
        Serial.print(F("_")); // если низкий уровень
      }
      show_index++;
    }// end y loop
    Serial.println();
  } //end loop chan
  // ===========================================
  // для красоты - типа вывод шкалы разметки :)
  // ===========================================
  Serial.print(F("\t")); //код TAB для ровности вывода
  for (int x = 0; x < (BUFSIZE + BUFSIZE); x++)
  {
    if (x == history) Serial.print(F("^")); //обозначим начало отсчета
    if ((x % 10) == 0) Serial.print(F("|")); // если номер отсчета кратен 10 - рисуем черточку
    if ((x % 10 != 0) && (x != history)) Serial.print(F(".")); // иначе рисуем точку
  }
  Serial.println(F(".")); //завершающая точка и перевод строки
  // рисуем "типа" разметку
  Serial.print(F("\t"));//код TAB для ровности вывода
  for (int x = 0; x < (BUFSIZE + BUFSIZE); x++)
  {
    if ((x % 10) == 0)
    {
      Serial.print(x / 10);
      if (x < 100)                  Serial.print(F("         ")); //чтобы не плыли значения относительно шкалы, в зависимости от разрядности тек. замера
      else if ((x >= 100) && (x < 1000))   Serial.print(F("        ")); // для случая ЗАМЕР - два знака
      else if ((x >= 1000) && (x < 10000)) Serial.print(F("       ")); // для случая ЗАМЕР - три знака
    }
  }
  Serial.println();

}//end show_graph

//===================================================
//фантик обертка сканирования шины (scan_bus+read_bus)
//1 фаза - ждем триггер или отмену пользователем
//2 фаза - заполнение буфера данными
void scanLoadBus(byte typeTriggerEvent)
{
  Serial.print(F("Waiting......"));
  //digitalWrite(TriggerPin, LOW); // светрдиод TRG выключаем
  init_logic(); //инициализируем буфер и переменные
  scan_bus(typeTriggerEvent);
  if (trigger_event) //если триггер сработал
  {
    read_bus(); // пишем историю в буфер
    //digitalWrite(TriggerPin,HIGH); // светoдиод TRG включаем
    Serial.println(F("Ok!"));
    show_info(typeTriggerEvent); //выводим информацию
    show_graph(); //и следом выводим график
  }
  else
  {
    Serial.println(F("User break")); //а если мы вернулись без признака сработки триггера - значит ожидание было прервано пользователем
    Serial.flush(); //очищаем буфер
  }
} //end scanLoadBus

 

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

удалил

 

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

удалил

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

smokok пишет:

Не правильно показывает частоту когда появляется "а" (завышает сильно).

#define BUFSIZE 700 стали работать кнопки везде, а 600 только меню и осццил.

Не правильно показывает частоту- а соединены A3 и D5 ? Насколько врёт? У меня на 50 Гц одинаково показывает, на больше пока не пробовал.

#define BUFSIZE 700- объём буфера для записи данных при измерении, на кнопки никак не должно влиять. Очень странно.

Про треугольник- на досуге пересмотрю код, может там что.

 

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

удалил

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

Больше не врёт, D5 профукал)))). Извиняюсь...  Можно сделать чтоб треугольник не заходил на пустой пункт?

А пин для измерения напряжения АКБ А5? Но он же занят. Тогда можно А6 или А7?

Почему их два?

    case 4 : LogAnalyzer();  break; // "выпадаем" в Анализатор
    case 5 : LogAnalyzer();  break; // "выпадаем" в Анализатор

 

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

Напряжение питания измеряется внутренними средствами контроллера, пины не задействованы. А чем увас занят А5? Для анализатора А0, А1, А2, А3. Для осциллографа тоже А3, только уже в аналоговом режиме.

case 4 : LogAnalyzer();  break; // "выпадаем" в Анализатор
case 5 : LogAnalyzer();  break; // "выпадаем" в Анализатор

Это на будущее, для ещё одного режима. Поэтому и треугольник на пустой пункт. Можете убрать, пора учиться.

Когда всё отполирую, выложу последнюю версию прошивки. Но для этого мне нужно собрать не на макетке. Так что не скоро.

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

Понял спасибо! А5 пустой. 

if (menu == 1) TextColor = 0; else TextColor = 1;  print(20, 0, TextColor, avtorazv?'A':'M');

Я добавил авторазвёртку (только вместо букв цифры показавает)))), позже добавлю автоопорное. Скину черновик, если понравится то поправите и в проект можно добавить. Так легче работать когда всё само настраивается. 

Учусь и учусь))))

tig-rrr
Offline
Зарегистрирован: 26.08.2018

Всем привет, уважаемые пользователи пробовал ли кто нибудь из Вас пенести проек на Mega 2560?Т.к плата имеет большой потенциал (воды, выходы, память ....), а 328 уже не хватает ни памяти ни пинов чтоб собрать все наработки в один проект. А с выпуском платы  Mega 2560 PRO   https://ru.aliexpress.com/item/32802420999.html?spm=a2g0v.12010608.0.0.60ff3638fp42km   или от других производителей , как пример.. Имея небольшие размеры может получится очень замечательный ПРИБОРЧИК....

240265
240265 аватар
Offline
Зарегистрирован: 12.08.2015

Тогда лучше сразу на такой

https://ru.aliexpress.com/item/32985219862.html?spm=a2g0o.detail.1000014...

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

tig-rrr пишет:

Всем привет, уважаемые пользователи пробовал ли кто нибудь из Вас пенести проек на Mega 2560?

Тогда цена приблизится к готовому осциллографу с гораздо лучшими характеристиками. Так что смысла нет. Мне вот интересно было бы сделать на Атмега128, потому как для меня они доступны вдвое дешевле, чем 328, при гораздо лучших параметрах. Но это уже отдельная тема.