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

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

b707 пишет:
во втором коде в строчке 6 вместо len поставьте 2 или скажем 5
ну, это если совсем медленно нужно... но тогда лучше читать или по таймеру, или по прерыванию ацп. не гоже долго висеть в функции сбора данных, кнопки "тормозить" начнут и фпс сильно просядет.
если, к примеру, замедлить раз в 5 с буфером 512, то наполнение буфера займет четверть секунды - 4 фпс и миссклики... если падение фпс - это неизбежность, то кнопки можно спасти)

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

Сделал, всё как Вы советовали. Всё работает. Единственный нюанс который заметил после внесения изменений -  минимальная частота, которую можно теперь посчитать, равняется 43 Гц. До внесения изменений - была в районе 30 Гц. Интересно конечно почему, но для меня не принципиально. Тем более что для медленных сигналов есть специально обученный медленный осцилл.

Спасибо за помощь!!

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

частота ушла, ибо delay пропускал не 1 цикл ацп, и не 2, а сколько получится)) около 4-5-6..
кстати, не понятно, почему такая маленькая разница 43Гц и 30Гц. одно чтение грубо 100мкс. и одна задержка 100. всего 200мкс на чтение. а с делей будет 100мкс чтение + 500делей = 600мкс. в 3 раза... я хз, мне не надо))

смысл всего этого в том, чтобы уйти от delay - так мы больше не привязаны к скорости МК и АЦП, и задержку делаем кратно скорости семплирования АЦП, а не на какие-то мифические 500мкс.

надо понизить частоту - втули еще раз те-же 2 строки (или уже for как писал b707), тогда будет пропускать еще X тактов, ну и делитель для расчета частоты правильный прописать не забыть. было одно чтение - частота Х. один пропуск (стало два чтения) - Х/2, два пропуска (стало три чтения) - Х/3... все просто и безо всяких эмпирических экспериментов)

 

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

progrik пишет:

...нужно просто посчитать... кварц 16 млн., делим на делитель АЦП))) и еще делим на 13 - столько тактов уходит на цикл АЦП.

делители АЦП - 2(не во всех скетчах), 4, 8, 16, 32, 64, 128 - выставляется при переключении развертки
то есть, в самом медленном режиме получаем 16млн/128/13 = 9615,38 замеров/сек
если нужно этот режим разметить допустим по 2мс, получаем 9615*2мс/1000 = 19,2. - каждые 19,2 точек рисуем разметку, всё.
каждое последующее уменьшение делителя уменьшает время разметки ровно в 2 раза....

Сделал таки масштаб оси времени. Собственно всё как Вы и писали, только с одним нюансом - развёртка 0 (самая медленная), как и развёртка 1 (чуть побыстрее) работают с делителем 128. Мы с Вами самую медленную развёртку чуть ранее замедляли в два раза вставкой пустого цикла АЦП. Поэтому получилось следующее - каждые 19 точек на самой медленной развёртке - 4 мс и каждая следующая развёртка уменьшает время в два раза. Вывод номера развёртки убрал за ненадобностью, вместо него масштаб времени. Спасибо Вам за науку.

Также перевёл свой пультоскоп на дисплей нокиа 1202 - отдельное спасибо пользователю Serioshka, всё на основании его скетча, сам бы наверняка не справился)). Перерисовал меню ну и сопутствующие мелочи. На мой взгляд с этим экранчиком смотрится приятней.

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

Hy6yk пишет:
...только с одним нюансом - развёртка 0 (самая медленная), как и развёртка 1 (чуть побыстрее) работают с делителем 128..
конечно-же можно хоть черточки чаще рисовать, хоть время умножать, можно как угодно) фантазия должна сопутствовать уму)) это нормально)
Hy6yk пишет:
перевёл свой пультоскоп на дисплей нокиа 1202 - отдельное спасибо пользователю Serioshka, всё на основании его скетча
да, такой экранчик посовременнее выглядит)
скетч, надеюсь, уже с разгоном вывода? а то если все дергается 2-3 кадра/сек и кнопки работают через раз - надо что-то менять)) я под этот дисплей допиливал вывод, ускорил раз в 10 или 20, хз))

вот видео из сообщения
как было НХ1230 КЛАЦ
как стало НХ1230 КЛАЦ
 
если залипоны как на первом видосе - значит всё плохо) если летает как на втором - знач уже с разгоном, можно спать спокойно)
ЗЫ: разные цифры в модели дисплеев (1202 и 1230) для меня не помеха думать, что это один и тот-же дисплей))
 
скучно у вас, чёрно-бело) делайте уже на цветных дисплеях!)) а я помогу разогнать раз в 10-20)))
Hy6yk
Offline
Зарегистрирован: 14.06.2020

Залипонов нет, кнопки отрабатывают как надо, но субъективно у меня в режиме паузы медленней вывод чем у Вас на втором видео, хоть и не такой медленный как на первом. Бегло посмотрел тот код, на основании которого делал я и тот который у Вас - различия однозначно есть. Во всяком случае функция drawPixel точно немного по-другому выглядит. Значит у меня не самый шустрый вариант)). Вечерком гляну и приведу в соответствие. О результатах сообщу дополнительно)

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

Признаю, был не прав. У меня был очень медленный вывод)) Подкорректировал код - теперь летает!. Уж не знаю как я пропустил то сообщение с ускорением вывода. Вернее знаю конечно - в моём случае, разные цифры в модели дисплеев, это была как раз помеха думать, что это один и тот же экран.)) Ещё раз спасибо за наставления на путь истинный! Вот прям от всей души!

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

рад помочь) особенно, когда ничего делать не надо)) так что, пожалуйста))
вывод побежден. осталось теперь все остальное переписать - и будет норм))
например, 8 строк кода расчета частоты пишутся в одну безо всяких switch (это стало возможно, когда избавились от delay)... нужно в формулу впилить (1<<(8-razv)) то есть, при расчете нужно использовать делитель, рассчитанный по номеру развертки.
частота = бла*бла/бла*(1<<(8-razv));
если razv=0, то 1<<(8-0) это 256, если razv=1, то 1<<(8-1) это 128, и т.д...
что-то в этом роде...
да и буфер для усреднения частоты сделать не помешало-бы... и считается частота там по одному периоду, а нужно по всем доступным для точности... короче, пилить - не перепилить...
но все это не обязательно. это интересно больше программисту, чем пользователю...

 

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

Красиво выглядит. Вы очень старались.

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

progrik пишет:

рад помочь) особенно, когда ничего делать не надо)) так что, пожалуйста))
вывод побежден. осталось теперь все остальное переписать - и будет норм))
например, 8 строк кода расчета частоты пишутся в одну безо всяких switch (это стало возможно, когда избавились от delay)... нужно в формулу впилить (1<<(8-razv)) то есть, при расчете нужно использовать делитель, рассчитанный по номеру развертки.
частота = бла*бла/бла*(1<<(8-razv));
если razv=0, то 1<<(8-0) это 256, если razv=1, то 1<<(8-1) это 128, и т.д...
что-то в этом роде...
да и буфер для усреднения частоты сделать не помешало-бы... и считается частота там по одному периоду, а нужно по всем доступным для точности... короче, пилить - не перепилить...
но все это не обязательно. это интересно больше программисту, чем пользователю...

К сожалению я совсем не программист, даже "адруинщик" и тот поверхностный)) Многое из того, что вы пишете, для меня сродни магическим заклинаниям. Хотя надо отдать Вам должное - Вы стараетесь довольно доходчиво истолковать. И за это Вам огромный, как говорится, респект! И я уже писал, но повторюсь - Ваши труды не напрасны, интернет всё помнит. Найдутся пользователи которые захотят "зачерпнуть чуть поглубже" и эта информация будет очень полезна. Мне и самому интересно до чёртиков как там всё это крутится, одна беда - времени катастрофически не хватает на то, чтобы глубоко вникнуть в тему, поэтому приходится довольствоваться поверхностными знаниями и копированием чужого опыта. Но вы знаете как заинтересовать - заменить восемь строк на одну - хорошая мотивация, потому при удобном случае обязательно буду пробовать))

Кстати, тут заметил на мой взгляд странность, которой никак не могу найти объяснения. Скорее всего, конечно, плохо искал. Для вывода строк мы используем конструкцию вида:

  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i])));
  print(x, y, TextColor, (buffer));
 
При объявлении массива  (char buffer[xx];) мы задаём ему размер, и в комментариях указано, что размер массива должен быть достаточно велик для того, чтобы вместить даже самую большую строку. Сейчас я остановился на размере 26, когда всё вроде работает. И как я понимаю, даже если указать массив большей размерности, то ничего плохого не должно случиться, кроме того что прошивка займёт больше места в памяти. Но стоит его изменить (даже в большую сторону), то происходят глюки. То в ШИМ генераторе не работает кнопка ОК, то в осциллографе отображается не то что должно - ну например, не отображается горизонтальный пунктир, или совсем ничего не выводится - белый экран, или мусор какой-то выводится... С разными значениями размера разные глюки.
Может это конечно у меня дома на компе какой-то глюк, завтра попробую на работе залить прошивку. Сегодня уже поздно для экспериментов.

volodya198024 пишет:

Красиво выглядит. Вы очень старались.

Это Вы об общем виде? если да - то Вы серьёзно? Мне бы хотелось чтобы Вы шутили)) потому как выглядит довольно... никак)) А если Вы про отображение пунктов меню - то тут дело не хитрое - берёшь картинку, правишь при необходимости, конвертируешь и в код.

 

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

Несколько месяцев не заходил в форум, сегодня вот заглянул, и, надо же, как раз сегодня поблагодарили )

Вывод на 1202 я уже полностью переписал, быстрее уж некуда, но довести до ума и выложить всё некогда, и времени на хобби не хватает сейчас, и направления другие. Последний адаптировал под Атмега8, так что с Атмега168 и 328 может не работать. Если быстро найду, выложу как есть, разбирайтесь сами, может progrik поможет, хоть и грозил уйти с форума ещё год назад.

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

Вот код для Атмега8 и дисплея Нокиа1202, только осцил без всего прочего, экранный буфер не используется, поэтому нужно намного меньше флеша. SPI программный. Дефайны все под мою платку, чтоб поменять- нужно слегка понимать как. Вроде должно работать и с ардуинами (Атмега168, 328). Работает без библиотек, и вроде в любой версии ИДЕ. Я компилирую по привычке в ИДЕ топикстартера (1.6.5).

//#define NALADKA 1

// Размер буфера для хранения результатов замера
#define BUFSIZE 384
byte adcBuf[BUFSIZE];

bool u;
byte menu = 0; // пункт меню
byte razv = 0;
byte trig = 0;
byte vSync = 30; // уровень синхронизации
bool vRef = 1; // флаг опорного напряжения
bool pause = 0; // флаг режима паузы
int grOffset = 0; // смещение графика в рабочем режиме
byte vMax, vMin; // максимальное и минимальное напряжение сигнала
unsigned long count = 1;

//
// Настройки пользователя - можно менять
// Выводы контроллера на дисплей Нокиа1202
#define CS 0
#define Clock 6
#define Data 7
#define RES 8
#define CS0 bitWrite(PORTD,0,0)
#define CS1 bitWrite(PORTD,0,1)
#define Clock0 bitWrite(PORTD,6,0)
#define Clock1 bitWrite(PORTD,6,1)
#define Data0 bitWrite(PORTD,7,0)
#define Data1 bitWrite(PORTD,7,1)
#define RES1 bitWrite(PORTB,0,1)
// Выводы для кнопок, подтяжка внутренняя, кнопки замыкаются на минус
#define KEY_OK 2 // кнопка ОК    (можно любой пин)
#define KEY_R  3 // кнопка ПРАВО (можно любой пин)
#define KEY_L  4 // кнопка ЛЕВО  (можно любой пин)
#define Key_OK_0  bit_is_clear(PIND,2) // кнопка ОК  (можно любой пин)
#define Key_R_0  bit_is_clear(PIND,3) // кнопка ПРАВО  (можно любой пин)
#define Key_L_0  bit_is_clear(PIND,4) // кнопка ЛЕВО  (можно любой пин)
#define KEY_P  11 // кнопка PAUSE (можно любой пин)
#define Key_P_0  bit_is_clear(PINB,3) // кнопка PAUSE  (можно любой пин)
#define LCDX 96
#define swap(a, b) { int t = a; a = b; b = t; }


static const char font[] PROGMEM = {
  //HEX B DEC переводим
  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(RES, OUTPUT);
  RES1;
  SendByte(0, 0xE2);//reset
  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); // подтяжка к плюсу питания
  pinMode(10, OUTPUT);
  analogWrite(10, 127);//ШИМ-сигнал 490 Гц 50%
#if (NALADKA == 1)
  Serial.begin(115200);
#endif
}

void loop() {
  Oscil();
}

//  === Читаем с АЦП данные и помещаем их в буфер === //
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(BUFSIZE / 3);         // компенсация задержки по сравнению с разверткой 0...
  } else {                          // развертка с задержками (delay)
    ADCSRA = 0b11100111;            // делитель на /128
    for (int i = 0; i < BUFSIZE; i++) { // цикл для чтения
      while (!(ADCSRA & 0x10));     // ждем готовность АЦП
      ADCSRA |= 0x10;               // запускаем следующее преобразование
      delayMicroseconds(500);       // делаем задержку
      adcBuf[i] = ADCH;             // записываем данные в массив
    }
  }
}

// === Осциллоскоп === //
void Oscil() {
  Inicialize();  //Инициализация дисплея
  while (1)
  {
    // установка опорного напряжения АЦП и настройка входа АЦП
    ADMUX = vRef ? 0b01100011 : 0b11100011;
    // === Обработка кнопок === //
    if (Key_L_0)switch (menu) { // кнопка лево:)
        case 0 : vRef = !vRef;                                                             break; // меняем опорное напряжение
        case 1 : razv--; if (razv == 255) razv = 6;                                        break; // меняем развертку
        case 2 : grOffset -= 6; if (grOffset < 0) grOffset = 0;                           break; // листаем график в паузе
      }
    if (Key_R_0)switch (menu) { // кнопка право:)
        case 0 : vRef = !vRef;                                                             break; // меняем опорное напряжение
        case 1 : razv++; if (razv == 7) razv = 0;                                          break; // меняем развертку
        case 2 : grOffset += 6; if (grOffset > BUFSIZE - LCDX) grOffset = BUFSIZE - LCDX; break; // листаем график в паузе
      }
    if (Key_OK_0) {
      delay(150); switch (++menu) {
        case 2: grOffset = 0; pause = 1;                                                   break; // вход в паузу - антидребезг типа
        case 3: menu = 0; pause = 0;                                                       break; // перебор меню
      }
    }
    if (Key_P_0) {
      menu = 2; pause = 1; grOffset = 0;
    }
    // === Ведём рассчеты === //
    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;
        }
      }
      // === Считаем частоту сигнала === //
      { // === Меряем частоту сигнала программно === //
        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 = 100000000 / ((y - grOffset)  * 325) / 8;  break; // делитель 32
              case 2: count = 100000000 / ((y - grOffset)  * 325) / 16; break; // делитель 64
              case 1: count = 100000000 / ((y - grOffset)  * 325) / 32; break; // делитель 128
              case 0: count = 1000000 / ((y - grOffset)  * 510);       break; // делитель 128 тоже
            }
            if (count > 1000000) count = 1000000;
            break;
          }
        }
      }
    } // закончили вести рассчеты
    Clear_LCD__(); // чистим экран...

    // == Отрисовка графика == //drawColumn (byte x, byte y, byte z)
    for (int x = 0; x < 96; x++)  {
      byte y1 = adcBuf[x + grOffset] / 4;
      byte y2 = adcBuf[x + grOffset + 1] / 4;
      Line(x , 67 - y1 , 67 - y2);
    }
    // === Отрисовка меню осцилла ===
    if (vRef) printFloat(0, 0, 50); else  printFloat(0, 0, 11);
    u = !u;
    if (menu == 0 & u) print(0, 0, "   ");
    print(24, 0, razv);
    if (menu == 1 & u) print(24, 0, " ");
    printFloat(82, 1, vMax * (vRef ? 50 : 11) / 255);
    printFloat(82, 4, vMax * (vRef ? 50 : 11) / 255 - vMin * (vRef ? 50 : 11) / 255);
    printFloat(82, 7, vMin * (vRef ? 50 : 11) / 255);
    if (!pause) {
      print(45, 0, "F");
      print (54, 0, count ); // вывод частоты
    }
    else {
      print(45, 0, "Pause");
      print(78, 0, grOffset);
      // рисуем прокрутку в режиме паузы
      //Line (95, grOffset / 4, grOffset / 4 + 2);
      delay(100);
    }
#if (NALADKA == 1)
    Serial.println("******************");
#endif
  }
}


//===========================Инициализация дисплея=======================
void Inicialize() {
  pinMode(CS,    OUTPUT);
  pinMode(Data,  OUTPUT);
  pinMode(Clock, OUTPUT);
  Clock0; // 
  Data0; // 
  CS0; // 
  delay(20);
  CS1; // 
  delay(1);
  SendByte(0, 0x2F); // Power control set(charge pump on/off)
  SendByte(0, 0xA4); // Normal Display Mode
  //SendByte(0, 0xA7); //
  SendByte(0, 0xAF); // AF экран вкл / AE выкл
  SendByte(0, 0x40);
  // http://we.easyelectronics.ru/OlegG/ispolzovanie-usart-stm32-dlya-upravleniya-lcd-nokia-1202.html
  /*SendByte(0, 0xE2);  // Soft reset
  SendByte(0, 0x3D);  // Charge pump
  SendByte(0, 0x01);  // Charge pump = 4 (default 5 is too hight for 3.0 volt)
  SendByte(0, 0xE1);  // Additional VOP for contrast increase
  SendByte(0, www);  // from -127 to +127
  // SendByte(0, 0xC8);  // C8...CF - зеркально по вертикали
  SendByte(0, 0x2F); // Power control set(charge pump on/off)
  SendByte(0, 0xA4);  // Power save OFF
  SendByte(0, 0x2F);  // Booster ON Voltage regulator ON Voltage follover ON
  SendByte(0, 0xAF);  // LCD on*/
}

//===========================Отправка 9 байт=============================
void SendByte(byte mode, byte c) {
  CS0; //
  (mode) ? Data1 : Data0; // 
  Clock1; // 
  for (byte i = 0; i < 8; i++) {
    Clock0; // 
    (c & 0x80) ? Data1 : Data0; // 
    Clock1; // 
    c <<= 1;
  }
  Clock0; // 
}

//===========================Очистка дисплея=============================
void Clear_LCD__() {
  for (byte y = 0; y < 9; y++) {
    SendByte(0, 0xB0 | y);
    SendByte(0, 0x00);
    SendByte(0, 0x10);
    for (byte col = 0; col < 96; col++) {
      SendByte(1, 0);
    }
    SendByte(0, 0x40);
  }
}


//========================================================Вывод строки
void print(byte x, byte y, char *str) {
  unsigned char type = *str;
  if (type >= 128) x = x - 3;
  while (*str) {
    drawChar(x, y, *str++);
    unsigned char type = *str;
    (type >= 128) ? x = x + 3 : x = x + 6;
  }
}
//========================================================Вывод числовых значений
void print(byte x, byte y, unsigned long num) {
  char c[20];
  print(x, y, ultoa(num, c, 10));
}
void printFloat(byte x, byte y, int num) {
  print(x, y, num / 10);
  print(x + 5, y, ".");
  print(x + 9, y, num % 10);//остаток от деления
}
//===========================Нарисовать букву============================
void drawChar(byte x, byte y, unsigned char c) {
  if ((x >= 128) || (y >= 64) || ((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;
  SendByte(0, 0xB0 | y);
  if (x > 91) return;
  byte q = x >> 4; // q = x/16;
  SendByte(0, q + 16); // +32
  SendByte(0, x - (q * 16)); // +2
  for (byte i = 0; i < 5; i++) {
    SendByte(1, pgm_read_byte(font + (c * 5) + i));
  }
  SendByte(1, 0);
}

//===========================Нарисовать колонку==========================
void drawColumn (byte x, byte y, byte z) {
#if (NALADKA == 1)
  Serial.print(x);
  Serial.print('-');
  Serial.print(y);
  Serial.print('-');
  Serial.println(z);
#endif
  SendByte(0, 0xB0 | y);
  if (x > 95) return;
  byte q = x >> 4; // q = x/16;
  SendByte(0, q + 16); // +32
  SendByte(0, x - (q * 16)); // +2
  SendByte(1, z);
}

void Line (int x, int y1, int y2) {
  if (y1 > 67)y1 = 67;
  if (y2 > 67)y2 = 67;
  if (y1 < 0)y1 = 0;
  if (y2 < 0)y2 = 0;
  if (y1 > y2)swap(y1, y2);
  if (y1 == y2)drawColumn(x, y1 / 8, (1 << (y1 & 0x7)));//y1 & 0x7-остаток от деления на 8 (111 - 3 бита)
  else {
    int y1_byte = y1 / 8;//33/8=4
    int y1_plus = (y1 & 0x7);//33-32=1//y1 & 0x7-остаток от деления на 8 (111 - 3 бита)
    int y2_byte = y2 / 8;//55/8=6  //34/8=4
    int y2_plus = (y2 & 0x7);//55-48=7  //34-32=2
#if (NALADKA == 1)
    Serial.print(y1);
    Serial.print("-");
    Serial.print(y2);
    Serial.print("-");
    Serial.print(y1_byte);
    Serial.print(",");
    Serial.print(y1_plus);
    Serial.print(",");
    Serial.print(y2_byte);
    Serial.print(",");
    Serial.print(y2_plus);
    Serial.print("\t");
#endif
    if (y1_byte == y2_byte) {
      byte column = 0;
      for (byte j = 0; j < 8; j++) {
        if ((j >= y1_plus) & (j <= y2_plus))bitSet(column, j);
      }
      drawColumn(x, y1_byte, column);
    }
    else {
      byte column = 0;
      for (byte j = 0; j < 8; j++) {
        if (j >= y1_plus)bitSet(column, j);
      }
      drawColumn(x, y1_byte, column);//x,4,254
      for (byte k = y1_byte + 1; k < y2_byte; k++) {
        drawColumn(x, k, 255);//x,5,255
      }
      column = 0;
      for (byte j = 0; j < 8; j++) {
        if (j <= y2_plus)bitSet(column, j);
      }
      drawColumn(x, y2_byte, column);//x,6,127
    }
  }
}

Hy6yk, попробуйте, если сможете исправить под свою распиновку.

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

Hy6yk пишет:

... При объявлении массива  (char buffer[xx];) мы задаём ему размер, и в комментариях указано, что размер массива должен быть достаточно велик для того, чтобы вместить даже самую большую строку. Сейчас я остановился на размере 26, когда всё вроде работает. И как я понимаю, даже если указать массив большей размерности, то ничего плохого не должно случиться, кроме того что прошивка займёт больше места в памяти. Но стоит его изменить (даже в большую сторону), то происходят глюки. То в ШИМ генераторе не работает кнопка ОК, то в осциллографе отображается не то что должно - ну например, не отображается горизонтальный пунктир, или совсем ничего не выводится - белый экран, или мусор какой-то выводится... С разными значениями размера разные глюки....
 

Тут вроде победил. В функции вывода пикселя была закомментирована строчка:

  if ((x < 0) || (x >= 96) || (y < 0) || (y >= 68)) return; 

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

Ну и я там выше писал, что размер массива 26 был хорош и всё работало, так вот это ошибка, с 26 тоже глюки были, уже не помню что именно - по-моему в режим осцила не входил, но вот с размером 27 работало почти всё - единственная проблема - не работала смена авторазвёртки на ручную. Вот для меня это чистое колдунство - не могу себе хоть как-то объяснить этот эффект.

seri0shka пишет:

Hy6yk, попробуйте, если сможете исправить под свою распиновку.

Спасибо за скетч, обязательно попробую, но сейчас я похоже повредил, то ли вход А3, то ли АЦП, какие-то показания странные - заниженные и периодически плавают. Например, если при питании от USB тыкнуть щупом в пин VIN самой ардуинки, то он показывает 1.7 вольт и плавно растёт. Потом вырастает до 3,5 и так и показывает. Но не всегда - иногда сразу 3,5 показывает. А там точно больше 4 вольт - китайский мультиметр не может врать!)) Да и раньше он показывал там что-то около 4,3. Тыкал видать пультоскопом куда ни попадя. Перекину вход сигнала на другой пин - посмотрю изменится ли что-нибудь.

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

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

seri0shka пишет:

Вот код для Атмега8 и дисплея Нокиа1202, только осцил без всего прочего, экранный буфер не используется, поэтому нужно намного меньше флеша. SPI программный. Дефайны все под мою платку, чтоб поменять- нужно слегка понимать как. Вроде должно работать и с ардуинами (Атмега168, 328). Работает без библиотек, и вроде в любой версии ИДЕ. Я компилирую по привычке в ИДЕ топикстартера (1.6.5).


Hy6yk, попробуйте, если сможете исправить под свою распиновку.

Проверил на версии 1.8.13 нормально скомпилилось.Дома дисп такой,попробую.Спасибо 

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

Да, всё компилится, заливается и работает. Я только для себя закоментил в скетче отдельную кнопу пауза, ибо у меня только три кнопки разведено, а также, в скетче пауза включается третьим нажатием кнопки ОК. Так что все функции там работают. Но нет авторазвертки и автопредела как в более поздних вариантах пультоскопа. Возможно он не такой быстрый, как ускоренный progrik-ом, я если честно не проверял на этот факт. 

Возвращаясь к своим баранам с плавающими показаниями - я тут оказывается накосячил - питал дисплей от пина VIN, вернее питал стабилизатор на 3,3 вольта от него, почему-то думал что там должно быть то питание, которое идёт от USB. Перепутал с пином 5V который и на "вход и на выход" работает. Ан нет, Vin оказывается только вход питания. В связи с этим хочется сказать что не так давно я выкладывал схему - так вот там как раз неправильно указано - питание от Vin. И ведь сижу сейчас и вспоминаю, что что-то читал про это когда-то давно. Вечерком перепаяю проводок и погляжу как это скажется на показаниях.

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

Hy6yk пишет:
...В функции вывода пикселя была закомментирована строчка:

  if ((x < 0) || (x >= 96) || (y < 0) || (y >= 68)) return; 

Я так понимаю это проверка на то, рисуем ли мы пиксель за пределами экрана.

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

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

progrik пишет:

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

Да, у меня "накодино" как раз с вылезанием за границы  - это типа анимация сдвига картинки вправо/влево/вниз при переключении пунктов "главного меню". Просто по другому я не умею)). Раскомментировав проверку может что и замедлилось, но на глаз не заметно. После ускорения вывода, даже с проверкой границ, вывод картинки стал таким быстрым, что мне пришлось переделывать - иначе картинка просто пролетала незаметно и пункты меню переключались уж очень быстро)) 

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

Да, информации много и много ошибок - в силу того, что часто этим всем занимаются не всегда компетентные товарищи - только я не хочу никого обидеть - в первую очередь я себя к таковым некомпетентным товарищам отношу. Ведь я сам вон что-то там наделал, да ещё и выкладывал схему с явной ошибкой. Но ошибки они на то и нужны чтобы их исправлять)) Ну так вот - исправил я у себя питание - подал 5 вольт не через USB а сразу на пин 5V для того чтобы питание дисплея убрать с пина Vin и посадить на те же 5 вольт (конечно же через стабилизатор на 3,3). Теперь всё вроде работает как положено. Будем ковырять зверушку дальше - надо только на досуге разобраться, что же это за магические знаки такие - (1<<(8-razv)) и с чем их едят)). А компетентным товарищам огромное спасибо за то, что не бросаете нас некомпетентных и помогаете дельными советами! 

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

Hy6yk пишет:
После ускорения вывода, даже с проверкой границ, вывод картинки стал таким быстрым, что мне пришлось переделывать - иначе картинка просто пролетала незаметно и пункты меню переключались уж очень быстро))
это очередная проблема - я раньше писал, что ЭТО работает только потому, что ОНО еле работает))
а теперь пора прикрутить к кнопкам антидребезг, и все станет норм. см. в моем коде, там запоминается время нажатия кнопок. в какой-то версии реализовано длинное нажатие (если надо - где-то в топике после мессаги с видосами, что я указал выше...)
Hy6yk пишет:
что же это за магические знаки такие - (1<<(8-razv)) и с чем их едят))
это сдвигает единицу 1 (00000001) на (8-razv) бит влево (<< - это сдвиг бит влево). по сути, в данном случае это возводит двойку в степень 1<<0 = 1; 1<<1 = 2 (00000010); 1<<2 = 4 (00000100); 1<<3 = 8 (0001000) и т.д. razv это номер развертки, если я правильно помню...
ну, наводок накидал) если что не получается - в окно к чертям всё это))

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

progrik пишет:

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

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

Со сдвигами битов надо ещё разбираться)) Вернее я конечно понял как она сдвигается, но тут ведь главное понять зачем её сдвигать?)) и как все эти сдвиги потом прикрутить к формуле.)) Ну, вода камень точит, не будем торопить события.

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

UPD: Вот кстати и ссылка на видео https://disk.yandex.ru/i/N47CORvayX6IKg

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

Hy6yk пишет:
...по поводу антидребезга - необходимость прикручивать дополнительно отсутствует...
ну, просто было сказано, что по меню пролетает - так вроде после того, что я сделал, никто никуда летать не должен)) или я чего не так помню, или не так понял - не важно)
Hy6yk пишет:
Со сдвигами битов надо ещё разбираться)) Вернее я конечно понял как она сдвигается, но тут ведь  Ну, вода камень точит, не будем торопить события.
ну, в месте расчета частоты (в девяти ее строках, включая switch) в каждой (почти) строке есть /2 /4 /8 /16... вот это всё бред сивой кобылы. эти степени двойки и делаются путем вычислений, а не росписью на 100500 строк...
смотрим: 

        switch (razv) { // считем частоту периода
          case 6: count = 1000000 / ((x - grOffset - 1) * 3.25);    break; // делитель 4
          case 5: count = 1000000 / ((x - grOffset)  * 3.25) / 2;  break; // делитель 8
          case 4: count = 1000000 / ((x - grOffset)  * 3.25) / 4;  break; // делитель 16
          case 3: count = 1000000 / ((x - grOffset)  * 3.25) / 8;  break; // делитель 32
          case 2: count = 1000000 / ((x - grOffset)  * 3.25) / 16; break; // делитель 64
          case 1: count = 1000000 / ((x - grOffset)  * 3.25) / 32; break; // делитель 128
          case 0: count = 1000000 / ((x - grOffset)  * 510);     break; // делитель 128 тоже
        }

что за 3.25, что за 510 (может стоять другое) - одному автору известно. подбирал, видимо, долго...

заменяем _всю_ эту хЕромантию на одну строку:

count = 16000000.0 / (13.0 * (x - grOffset) * (1<<(8-razv)));

где 16М - частота МК, 13 - столько тактов занимает преобразование АЦП, 1<<(8-razv) - делитель АЦП. так же все понятно) мне - точно)
если я не ошибся, то уже заработает) ну или в 2 млм в 4 раза будет мимо, надо проверять))  8-razv,  7-razv,  9-razv...)))

 

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

progrik пишет:

count = 16000000.0 / (13.0 * (x - grOffset) * (1<<(8-razv)));

Попробовал, не, не то пальто.

Во-первых, авторазвёртка перестаёт работать, вернее она мечется и не может определиться - я так понимаю постоянно переключается между нулевой и шестой. Хотя вполне возможно и перебирает все возможные.  Во-вторых если переключить на ручную развёртку, то каждая последующая развёртка увеличивает выводимую частоту приблизительно вдвое. Т.е. если на нулевой развёртке показывает 30 Гц (колеблется вокруг этой цифры), то на первой 60 Гц, на второй около 128Гц, затем что-то вроде 263 Гц и т.д. До корректировки кода этот сигнал показывал частоту 1,97 кГц

Если подставить (7-razv), то авторазвертка уже не мечется, а встаёт на нулевую развёртку и выводит увеличенную вдвое по сравнению с (8-razv) частоту - т.е. в районе 61-62... В ручном режиме, так же, при переключении развёртки выводимая частота увеличивается в два раза. Сигнал тот же.

Остальные функции работают штатно.

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

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

Hy6yk пишет:
если вручную посчитать, то по старым подсчетам, и по новой формуле - все один в один...
у меня на ослике эта-же формула - всё работает. вручную проверил - тоже сходится.
что-то пошло не так))

 

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

Нубук, выложите ваш код (рабочий) с авторазвёрткой, я авторазвёртку ещё не пробовал, а искать в 5000 сообщений форума замучаешься.

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

seri0shka пишет:

Нубук, выложите ваш код (рабочий) с авторазвёрткой, я авторазвёртку ещё не пробовал, а искать в 5000 сообщений форума замучаешься.

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

/* Hy6yk - скетч взял тут  http://arduino.ru/forum/proekty/pultoskop-na-arduino-27mgts?page=88#comm...
  Вариант пультоскопа для макетки и LCD Nokia1202
  
  План меропрриятий по модернизации:
  - ==Сделано== Удалить DDS-генератор
  - ==Сделано== Удалить температуру
  - ==Сделано== Удалить Медленный осцилл
  - ==Сделано== Добавить измерение до 50 вольт
  - ==Сделано== Попробовать ускорить посредством cyberlib.
  - ==Сделано== Вывод частоты в Гц или кГц
  - ==Сделано== Удалить аппаратный замер чатоты
  - ==Сделано== Вставить анимированное меню
  - ==Сделано== Перевести на LCD Nokia1202 на основе варианта от Seri0shka
  - ==Сделано== Вывести маштаб временной шкалы
  - ==Сделано== Ускорить на основе кода от progrik
  - По возможности причесать всё 
  - Переделать расчёт частоты по советам progrik

*/


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

//#include <FreqCount.h>
#include <EEPROM.h>
#include <math.h>
#include <PWM.h>
#include "CyberLib.h"
#include <avr/pgmspace.h>
/*
  ####### Описание работы некоторых функций библиотеки <CyberLib.h> #######

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

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

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

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


// ***** Пины LCD1202 ***** //
#define RES 9
#define CS 8
#define Data 7
#define Clock 6
// ***** Пины LCD1202 ***** //
#define swap(a, b) { int t = a; a = b; b = t; }

//progrik: определяем макросы для действий с управляющими пинами
#define CLOCK_HIGH  	bitWrite(PORTD,6,1) // pin6=PORTD,6  pin7=PORTD,7   pin8=PORTB,0   pin9=PORTB,1  и так далее
#define CLOCK_LOW   	bitWrite(PORTD,6,0)
#define DATA_HIGH   	bitWrite(PORTD,7,1) // pin7
#define DATA_LOW    	bitWrite(PORTD,7,0)
#define RESET_HIGH  	bitWrite(PORTB,1,1) // pin9
#define RESET_LOW    	bitWrite(PORTB,1,0)
#define CS_HIGH     	bitWrite(PORTB,0,1) // pin8
#define CS_LOW       	bitWrite(PORTB,0,0)


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

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

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

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

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


//***************************************************************************************************************************
//***************************************************************************************************************************
float VCC; // = 5.0;      // напряжение питания (меряем мультиметром - СТАЛО НЕ НАДО)
//byte contrast; // контрастность дисплея
//byte Set = 0; // Настройка экрана
bool BL; // Подсветка
byte mode = 0; // пункт главного меню
byte menu = 0; // пункт меню
byte adcBuf[BUFSIZE_LONG];
byte vSync = 30;   // уровень синхронизации
bool vRef = 1; // флаг опорного напряжения
bool pause = 0; // флаг режима паузы
byte razv = 4;
int grOffset = 0; // смещение графика в рабочем режиме
byte vMax, vMin;// максимальное и минимальное напряжение сигнала
int kdel = 5;         //bulat  автопредел 1,1/0,2 вольта
bool avtorazv = 1;    // Автоматический выбор развертки
bool flag = 0;
unsigned long ok_last_time; //была ok_press_time
unsigned long ok_start_time;
bool ok_short_press = false;
int temp = 0;
bool TextColor = 1;

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

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

byte LCD_RAM[96 * 9]; // 96 * 9


const uint8_t PROGMEM logoOSC[] = { //80х64
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0xc0, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xc0, 0x80,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x3e, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfe, 0x7e, 0x3e, 0x3e, 0x1e, 0x0f, 0x0f, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x07,
  0x07, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x1e, 0x3e, 0x3e, 0x7e, 0xfe, 0xff, 0xff, 0xff, 0xff,
  0xff, 0x3e, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0,
  0xf0, 0xf8, 0xff, 0xff, 0x3f, 0x07, 0x03, 0xc0, 0x70, 0x18, 0x08, 0x0c, 0x04, 0x04, 0x0c,
  0x08, 0x18, 0x70, 0xc0, 0x00, 0x00, 0x10, 0xf8, 0x14, 0x00, 0xa0, 0xa0, 0xa0, 0x00, 0x00,
  0x00, 0x03, 0x07, 0xbf, 0xff, 0xff, 0xf8, 0xf0, 0xe0, 0xc0, 0xc0, 0xc0, 0x80, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x1f, 0x3f, 0x3f, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x3c, 0x0f, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x3c, 0xe0, 0x81, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x81, 0xe0, 0x39, 0x0e, 0xc7, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x3f,
  0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xff, 0xff, 0xff,
  0xff, 0xfc, 0xf0, 0xe0, 0xc0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x01, 0x01, 0x03, 0x02, 0x82, 0xc3, 0xe1, 0xf1, 0xf8, 0xfc, 0xff, 0xff, 0xff,
  0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x03, 0x07, 0x0f, 0x1f, 0x1f, 0x0f, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0f, 0x3f,
  0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x3f, 0x0f, 0x0f, 0x07, 0x07, 0x07, 0x07,
  0x07, 0x0f, 0x1f, 0x1f, 0x1f, 0x0f, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0xe0, 0xf0, 0x10, 0x10, 0x10, 0xf0, 0xe0, 0x00, 0x80, 0xc0, 0x40, 0x40, 0x40, 0x00,
  0xc0, 0xc0, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0xc0, 0x00, 0x80, 0xc0, 0xc0, 0x00, 0x00,
  0xc0, 0xc0, 0x40, 0x40, 0xc0, 0xc3, 0x03, 0x03, 0xc3, 0xc3, 0x43, 0x43, 0xc1, 0xc0, 0x00,
  0x80, 0xc0, 0x40, 0x40, 0xc0, 0x80, 0x00, 0xc0, 0xc0, 0x40, 0x40, 0x00, 0xc0, 0xc0, 0x40,
  0x40, 0xc0, 0x80, 0x00, 0x00, 0x40, 0x40, 0x40, 0xc0, 0x80, 0x00, 0x80, 0xc0, 0x40, 0xf8,
  0xf8, 0x40, 0xc0, 0x80, 0x00, 0x00, 0x03, 0x07, 0x04, 0x04, 0x04, 0x07, 0x03, 0x00, 0x03,
  0x07, 0x04, 0x04, 0x04, 0x00, 0x07, 0x07, 0x04, 0x04, 0x07, 0x0f, 0x0c, 0x00, 0x07, 0x03,
  0x01, 0x00, 0x07, 0x00, 0x04, 0x07, 0x03, 0x00, 0x00, 0x07, 0x07, 0x00, 0x04, 0x07, 0x03,
  0x00, 0x00, 0x07, 0x07, 0x00, 0x03, 0x07, 0x04, 0x04, 0x07, 0x03, 0x00, 0x07, 0x07, 0x00,
  0x00, 0x00, 0x1f, 0x1f, 0x04, 0x04, 0x07, 0x03, 0x00, 0x02, 0x07, 0x05, 0x05, 0x07, 0x07,
  0x00, 0x03, 0x07, 0x04, 0x1f, 0x1f, 0x04, 0x07, 0x03, 0x00
};

const uint8_t PROGMEM logoPWM[] = { //80х64
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0xc0, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xc0, 0x80,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x3e, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfe, 0x7e, 0x3e, 0x3e, 0x1e, 0x0f, 0x0f, 0x0f, 0x07, 0x67, 0x67, 0x87, 0x47,
  0x27, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x1e, 0x3e, 0x3e, 0x7e, 0xfe, 0xff, 0xff, 0xff, 0xff,
  0xff, 0x3e, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0,
  0xf0, 0xf8, 0xff, 0xff, 0x3f, 0x07, 0x03, 0x00, 0xe0, 0xe0, 0x60, 0x60, 0x60, 0x60, 0xe0,
  0xe0, 0x02, 0x01, 0x00, 0x03, 0xe3, 0xe0, 0x60, 0x60, 0x60, 0x60, 0xe0, 0xe0, 0x00, 0x00,
  0x00, 0x03, 0x07, 0x3f, 0xff, 0xff, 0xf8, 0xf0, 0xe0, 0xc0, 0xc0, 0xc0, 0x80, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x1f, 0x3f, 0x3f, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x80, 0x80, 0x80, 0xff, 0xff,
  0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, 0xff, 0xff, 0x00, 0x00, 0x00,
  0x00, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x3f,
  0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xff, 0xff, 0xff,
  0xff, 0xfd, 0xf1, 0xe1, 0xc1, 0xc0, 0x80, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x81, 0xc1, 0xe1, 0xf1, 0xf9, 0xfd, 0xff, 0xff, 0xff,
  0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x03, 0x07, 0x0f, 0x1f, 0x1f, 0x0f, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0f, 0x3f,
  0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x3f, 0x0f, 0x0f, 0x07, 0x07, 0x07, 0x07,
  0x07, 0x0f, 0x1f, 0x1f, 0x1f, 0x0f, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xe0, 0xe0,
  0x00, 0x00, 0xe0, 0xe0, 0x00, 0x03, 0xe3, 0x03, 0x03, 0x03, 0x83, 0xc3, 0xe1, 0x00, 0x00,
  0xe0, 0xe0, 0xc0, 0x80, 0x00, 0x80, 0xc0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
  0x1f, 0x10, 0x10, 0x1f, 0x1f, 0x10, 0x10, 0x1f, 0x1f, 0x00, 0x00, 0x1f, 0x0c, 0x06, 0x03,
  0x01, 0x00, 0x1f, 0x00, 0x00, 0x1f, 0x00, 0x01, 0x03, 0x01, 0x00, 0x1f, 0x1f, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

const uint8_t PROGMEM logoSET[] = { //80х64
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0xc0, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xc0, 0x80,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x3e, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xfe, 0x7e, 0x3e, 0x3e, 0x1e, 0x0f, 0x0f, 0x0f, 0x07, 0x07, 0x07, 0x07, 0xe7,
  0x07, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x1e, 0x3e, 0x3e, 0x7e, 0xfe, 0xff, 0xff, 0xff, 0xff,
  0xff, 0x3e, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0,
  0xf0, 0xf8, 0xff, 0xff, 0x3f, 0x07, 0x03, 0x00, 0x00, 0x00, 0x02, 0x04, 0x08, 0x60, 0x30,
  0x10, 0x00, 0x08, 0x08, 0xf9, 0xf8, 0xf0, 0xf0, 0xe0, 0xc0, 0x08, 0x04, 0x02, 0x00, 0x00,
  0x00, 0x03, 0x07, 0x3f, 0xff, 0xff, 0xf8, 0xf0, 0xe0, 0xc0, 0xc0, 0xc0, 0x80, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x1f, 0x3f, 0x3f, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x04, 0x04, 0x04, 0x04,
  0x00, 0x00, 0x0f, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x3f,
  0x0f, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x3f,
  0x3f, 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xff, 0xff, 0xff,
  0xfe, 0xfc, 0xf0, 0xe0, 0xc0, 0xc4, 0x82, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x79,
  0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x82, 0xc4, 0xe8, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xff,
  0xff, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x03, 0x07, 0x0f, 0x1f, 0x1f, 0x0f, 0x0f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0f, 0x3f,
  0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x3f, 0x0f, 0x0f, 0x07, 0x07, 0x07, 0x07,
  0x07, 0x0f, 0x1f, 0x1f, 0x1f, 0x0f, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0x80, 0x80, 0x80, 0xf0, 0xf0, 0x00,
  0x00, 0x00, 0x40, 0x40, 0x40, 0xc0, 0x80, 0x00, 0x00, 0x80, 0xc0, 0x40, 0x40, 0x40, 0x00,
  0x40, 0x40, 0xc0, 0xc0, 0x40, 0x43, 0x03, 0xc3, 0xc3, 0x43, 0x43, 0xc3, 0x81, 0x00, 0x00,
  0x80, 0xc0, 0x40, 0x40, 0xc0, 0x80, 0x00, 0x00, 0xc8, 0x18, 0x10, 0x98, 0xc8, 0x00, 0x00,
  0xc0, 0xc0, 0x00, 0x80, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0xc0, 0x80, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00,
  0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x06, 0x0f, 0x09, 0x09, 0x0f, 0x0f, 0x00, 0x00, 0x07,
  0x0f, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x08,
  0x08, 0x0f, 0x07, 0x00, 0x00, 0x07, 0x0f, 0x08, 0x08, 0x0f, 0x07, 0x00, 0x00, 0x0f, 0x06,
  0x03, 0x01, 0x0f, 0x00, 0x00, 0x0f, 0x0f, 0x02, 0x07, 0x0c, 0x08, 0x00, 0x00, 0x06, 0x0f,
  0x09, 0x09, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};


const uint8_t PROGMEM logoLED[] = { // 64x8
  0x00, 0x00, 0xff, 0xff, 0x01, 0x01, 0x01, 0xff, 0x00, 0x30, 0x78, 0x84, 0x84, 0x84, 0x78, 0x30,
  0x80, 0xc0, 0xbc, 0x84, 0xfc, 0xfc, 0x80, 0x00, 0x78, 0xfc, 0x84, 0x84, 0x84, 0x48, 0x00, 0xfc,
  0xfc, 0x94, 0x94, 0x68, 0x00, 0x00, 0x78, 0xfc, 0x94, 0x94, 0x58, 0x00, 0x0c, 0x0c, 0xfc, 0x0c,
  0x0c, 0x00, 0xfc, 0xfc, 0x38, 0x6c, 0xc4, 0x00, 0x00, 0x60, 0xf4, 0x94, 0xfc, 0xf8, 0x00, 0x00
};


const uint8_t PROGMEM logoLED_ON[] = { // 40x32
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x80, 0xc0, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x60, 0x30, 0x98, 0x48,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x01, 0x03, 0xe2, 0x18, 0x0c, 0x04, 0x02,
  0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x0c, 0x18, 0xe3, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00,
  0x00, 0x01, 0x03, 0x06, 0x0c, 0x19, 0x32, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
  0x01, 0x00, 0x80, 0xc7, 0x18, 0x30, 0x20, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x20, 0x30, 0x18,
  0x47, 0xc0, 0x80, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x1e, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00
};

const uint8_t PROGMEM logoLED_OFF[] = { // 40x32
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x01, 0x03, 0xe2,
  0xf8, 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xfc, 0xf8, 0xe3, 0x01, 0x00, 0x80,
  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x98, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x80, 0xc7, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
  0x7f, 0x3f, 0x3f, 0x1f, 0x47, 0xc0, 0x80, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x24, 0x32, 0x19, 0x0c, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

const char string_0[] PROGMEM = "ШИМ-Генератор"; // "String 0" и т.д. - это содержимое строк; если необходимо меняйте его
const char string_1[] PROGMEM = " ШИМ=";
const char string_2[] PROGMEM = " | "; // Пауза - в шрифте символ перерисовал 
const char string_3[] PROGMEM = "МГц";
const char string_4[] PROGMEM = "Гц";
const char string_5[] PROGMEM = "кГц";
const char string_6[] PROGMEM = "% ";
const char string_7[] PROGMEM = "мс";
const char string_8[] PROGMEM = "руч";
const char string_9[] PROGMEM = "авт";
const char string_10[] 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};

char buffer[26];    // массив должен быть достаточно велик, чтобы вместить даже самую большую строку


//***************************************************************************************************************************
void ShowMode(char x, char y) { // выводим режим работы. x, y - где рисовать
  switch (mode) {
    case 0: {
        Clear_LCD();
        drawBitmap(x, y, logoOSC, 80, 64);
      } break;
    case 1: {
        Clear_LCD();
        drawBitmap(x, y, logoPWM, 80, 64);
      } break;
    case 2: {
        Clear_LCD();
        drawBitmap(x, y, logoSET, 80, 64);
      } break;
  }
}

void ShowT(char x, char y, byte razv) { //вывод масштаба веременной шкалы
  switch (razv) {
    case 0: {
		print(x, y, TextColor, 4);
		strcpy_P(buffer, (char*)pgm_read_word(&(string_table[7]))); //string_table[7] - мс
		print(x + 7, y, TextColor, (buffer));
	} break;
    case 1: {
		print(x, y, TextColor, 2);
		strcpy_P(buffer, (char*)pgm_read_word(&(string_table[7]))); //string_table[7] - мс
		print(x + 7, y, TextColor, (buffer));
	} break;
	case 2: {
		print(x, y, TextColor, 1);
		strcpy_P(buffer, (char*)pgm_read_word(&(string_table[7]))); //string_table[7] - мс
		print(x + 7, y, TextColor, (buffer));
	} break;
	case 3: {
		float_print(x, y, TextColor, 0.5, 1);
		strcpy_P(buffer, (char*)pgm_read_word(&(string_table[7]))); //string_table[7] - мс
		print(x + 19, y, TextColor, (buffer));
	} break;
	case 4: {
		float_print(x, y, TextColor, 0.25, 2);
		strcpy_P(buffer, (char*)pgm_read_word(&(string_table[7]))); //string_table[7] - мс
		print(x + 26, y, TextColor, (buffer));
	} break;
	case 5: {
		print(x, y, TextColor, 125);
		strcpy_P(buffer, (char*)pgm_read_word(&(string_table[10]))); //string_table[10] - мкс
		print(x + 19, y, TextColor, (buffer));
	} break;
	case 6: {
      print(x, y, TextColor, 63);
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[10]))); //string_table[10] - мкс
    print(x + 13, y, TextColor, (buffer));
	} break;
  }
}

//***************************************************************************************************************************
//******************************** Взамен библиотеки для LCD1202 Начало********************************
//***************************************************************************************************************************

// =========================== Инициализация дисплея ===========================
void Inicialize() {
  pinMode(RES,   OUTPUT); // можно воткнуть ресет на питание дисплея и удалить отсюда
  pinMode(CS,    OUTPUT);
  pinMode(Data,  OUTPUT);
  pinMode(Clock, OUTPUT);
  // Инициализация дисплея

  RESET_HIGH;
  CLOCK_LOW;
  DATA_LOW;
  delay(20);
  CS_HIGH;
  SendByte(0, 0x2F);           // Power control set(charge pump on/off)
  SendByte(0, 0xA4);
  SendByte(0, 0xAF);           // экран вкл/выкл
  // <a href="http://we.easyelectronics.ru/OlegG/ispolzovanie-usart-stm32-dlya-upravleniya-lcd-nokia-1202.html" rel="nofollow">http://we.easyelectronics.ru/OlegG/ispolzovanie-usart-stm32-dlya-upravleniya-lcd-nokia-1202.html</a>
  /*SendByte(0, 0xE2);  // Soft reset
    SendByte(0, 0x3D);  // Charge pump
    SendByte(0, 0x01);  // Charge pump = 4 (default 5 is too hight for 3.0 volt)
    SendByte(0, 0xE1);  // Additional VOP for contrast increase
    SendByte(0, www);  // from -127 to +127
    // SendByte(0, 0xC8);  // C8...CF - зеркально по вертикали
    SendByte(0, 0x2F); // Power control set(charge pump on/off)
    SendByte(0, 0xA4);  // Power save OFF
    SendByte(0, 0x2F);  // Booster ON Voltage regulator ON Voltage follover ON
    SendByte(0, 0xAF);  // LCD on*/

}
// =================================================================================================

// =========================== Шрифт ===========================
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   |
  0x7E, 0x7E, 0x00, 0x7E, 0x7E,   // 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, 0x7C, 0xC0 ,  // 0xB6   ц
  //  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   я
};
// =================================================================================================



// =========================== функция вывода 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));
}
// =================================================================================================

/* Не используется в Пультоскопе, но оставил для справки.
  // =========================== Печать цифры размером 24х48 пикселя  ===========================
  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 dWrite(byte pin, byte val) {
  byte bit = digitalPinToBitMask(pin);
  volatile byte *out;
  out = portOutputRegister(digitalPinToPort(pin));
  (val) ? *out |= bit : *out &= ~bit;
}
// =================================================================================================

// =========================== Отправка 9 байт ===========================

//progrik: добалено определение inline. функция встраивается в код и не расходуется время на ее вызов.
//progrik: вместо многократных вызовов функций дергаем ногами при помощи написанных вверху кода макросов
inline __attribute__((always_inline)) void SendByte(byte mode, byte c) {
  //dWrite(CS, 0); //progrik: чип селект нужно включить один раз в конце инициализации дисплея, и больше не трогать. перенес в инициализацию
  CS_LOW; //progrik: вернул для тестов
  //(mode) ? dWrite(Data, 1) : dWrite(Data, 0);
  (mode) ? DATA_HIGH : DATA_LOW;
  //dWrite(Clock, 1);
  CLOCK_HIGH;
  for (byte i = 0; i < 8; i++)
  {
    //dWrite(Clock, 0);
    CLOCK_LOW;
    //(c & 0x80) ? dWrite(Data, 1) : dWrite(Data, 0);
    (c & 0x80) ? DATA_HIGH : DATA_LOW;
    //dWrite(Clock, 1);
    CLOCK_HIGH;
    c <<= 1;
  }
  //dWrite(Clock, 0);
  CLOCK_LOW;
}
// =================================================================================================

// =========================== Очистка дисплея ===========================
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]);
    }
  }
}
// =================================================================================================

// =========================== Нарисовать пиксель ===========================
inline __attribute__((always_inline)) void drawPixel (byte x, byte y, boolean color) {
  if ((x < 0) || (x >= 96) || (y < 0) || (y >= 68)) return; //  NAN херня
  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);
      if (line & 0x1)
      {
        drawPixel(x + i, y + j, color);
      }
      else
      {
        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++) {
    if (steep)
    {
      drawPixel(y0, x0, color);
    }
    else
    {
      drawPixel(x0, y0, color);
    }
    err -= dy;
    if (err < 0) {
      y0 += ystep;
      err += dx;
    }
  }
}
// =================================================================================================

/////////////////добавь где-то, например, под функцией DrawLine такую функцию:////////////////////////////
void drawVLineUltraFast(byte x, byte y0, byte y1, boolean color) {
  if (y0 > y1)
  {
    swap(y0, y1);
  }
  do
  {
    drawPixel(x, y0, color);
  }
  while (++y0 <= y1);
}
// =================================================================================================

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

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


// =========================== Рисование прямоугольника ===========================
void drawRect(byte x, byte y, byte w, byte h, boolean color) {
  drawFastHLine(x, y, w, color);
  drawFastHLine(x, y + h - 1, w, color);
  drawFastVLine(x, y, h, color);
  drawFastVLine(x + w - 1, y, h, 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 drawBitmap(byte x, byte y, const uint8_t *bitmap, byte w, byte h) {

  for (int16_t j = 0; j < h; j++) {
    for (int16_t i = 0; i < w; i++ ) {
      if (pgm_read_byte(bitmap + i + (j / 8)*w) & _BV(j % 8)) {
        drawPixel(x + i, y + j, TextColor);
      }
    }
  }
}
// =================================================================================================

//***************************************************************************************************************************
//******************************** Взамен библиотеки для LCD1202 Конец ********************************
//***************************************************************************************************************************


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

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

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

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

  mode = 0;

  while (D_Read(KEY_OK) != KEY_PRESSED) { // цикл, пока не нажали кнопку ОК
    // опрос кнопок
    if (D_Read(KEY_R) == KEY_PRESSED) {
      for (char b = 8; b > -80; b -= 3) {
        Clear_LCD();
        ShowMode(b, 5);
        Update();
      };
      mode++; if (mode == 3  ) mode = 0;

      for (char b = 80; b > 8; b -= 3) {
        Clear_LCD();
        ShowMode(b, 5);
        Update();
      };

    }

    if (D_Read(KEY_L) == KEY_PRESSED) {
      for (char b = 8; b < 80; b += 3) {
        Clear_LCD();
        ShowMode(b, 5);
        Update();
      };
      mode--; if (mode == 255) mode = 2;
      for (char b = -80; b < 8; b += 3) {
        Clear_LCD();
        ShowMode(b, 5);
        Update();
      };

    }

    Clear_LCD();  // чистим буфер экранчика
    ShowMode(8, 5);
    Update();

  }

  if (mode == 1) {
    InitTimersSafe();
    bool success = SetPinFrequencySafe(GEN_PIN, freq);
    pwmWrite(GEN_PIN, PWM * 2.55);

  }

  // антидребезг кнопки ОК
  for (char a = 5; a < 90; a += 3) {
    Clear_LCD();  // - это вместо delay(200);
    ShowMode(8, a);
    Update();
  }
  ok_last_time = millis(); //progrik: запоминаем время последнего нажатия

  delay(200);

} // End Setup()

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

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

  }
  else {                          // развертка с задержками
    ADCSRA = 0b11100111;            // делитель на /128
    for (uint16_t i = 0; i < len; i++) { // цикл для чтения
      while (!(ADCSRA & 0x10));     // ждем готовность АЦП
      ADCSRA |= 0x10;               // запускаем следующее преобразование
      while (!(ADCSRA & 0x10));     // ждем готовность АЦП, для того чтобы убрать дэлэй
      ADCSRA |= 0x10;    // запускаем следующее преобразование
      adcBuf[i] = ADCH;             // записываем данные в массив
    }
  }

}
//***************************************************************************************************************************
//progrik: для расчета напряжений ---------------
void calc_val()
{
  vMax = 0; vMin = 0xFF;
  uint16_t l = (pause) ? BUFSIZE_LONG : BUFSIZE_SHORT;
  for (uint16_t x = 0; x < l; x++) {
    if (vMax < adcBuf[x]) vMax = adcBuf[x];  // пока 255, но надо экспериментировать
    if (vMin > adcBuf[x]) vMin = adcBuf[x];
  }

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

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

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

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


  if (menu == 0) TextColor = 1;

  if (!avtorazv) {
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[8]))); //string_table[8] - руч
    print(19, 0, TextColor, (buffer)); //28
  }

  else {
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[9]))); //string_table[9] - авт
    print(19, 0, TextColor, (buffer));
  }


  if (menu == 1)
    if (!pause)  TextColor = 1;
    else {   // рисуем прокрутку в режиме паузы
      strcpy_P(buffer, (char*)pgm_read_word(&(string_table[2]))); //string_table[2] - Пауза
      print(19, 0, !TextColor, (buffer));


      temp = grOffset / 4.7;  // место остановки чёрточки при прокрутке в паузе в конце экрана
      drawFastHLine(temp, 10, 7, 1);  drawFastHLine(temp, 9, 7, 1);  //чёрточка прокрутки в паузе
    }  // шкала прокрутки

  countX = count;
  if (countX < 1000) {
    print(42, 0, TextColor, countX);
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[4]))); //string_table[4] - Гц
    print(84, 0, TextColor, (buffer)); // Вывод частоты в герцах
  }
  else  {
    float countXK = countX / 1000.0; float_print(41, 0, TextColor, countXK, 2);
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[5]))); //string_table[5] - кГц
    print(78, 0, TextColor, (buffer)); // Вывод частоты в килогерцах
  }


  if (vMax == 0xFF) for (uint8_t x = 0; x < 5; x++) drawLine(x, 9, x, 67, 1); // указатель привышения напряжения на входе осцила


  // == Отрисовка сетки == //
  for (byte i = 67; i > 9; i = i - 7) {
    drawFastHLine( 0, i, 2, 1);  // черточки слева
  }
  for (byte i = 67; i > 9; i = i - 3) {
    drawPixel(19, i, 1);  // вертикальный пунктир
    drawPixel(38, i, 1);
    drawPixel(57, i, 1);
    drawPixel(76, i, 1);
    drawPixel(95, i, 1);
  }
  for (byte i = 3; i < 96; i = i + 3) {
    drawPixel(i, 11, 1); //горизонтальный пунктир
    drawPixel(i, 39, 1);
    drawPixel(i, 67, 1);
  }
  ShowT(5, 11, razv);

  ///////////////авто razv//////////////
  if (avtorazv)
#define PER 1.3
    if (count > 4323.3 * PER) razv = 6;
    else if (count > 2434.5 * PER) razv = 5;
    else if (count > 0969.3 * PER) razv = 4;
    else if (count > 0486.8 * PER) razv = 3;
    else if (count > 0245.8 * PER) razv = 2;
    else if (count > 0120.1 * PER) razv = 1;
    else razv = 0;
  //bulat если зашкаливает включаем предел 5 в
  if (vMax == NAPR) {
    if (vRef == 0)
    {
      vRef = 1;
      ADMUX = 0b01100011;// выбор внутреннего опорного 5.0 В
      goto   label_ReadAdc;
    }
  }
  //bulat если  5 в  и уровень менее 1,1 в то вкл предел 1,1 в
  if (vMax <= 55) {
    if (vRef == 1)
    {
      vRef = 0;
      ADMUX = 0b11100011;// выбор внутреннего опорного 1,1В
      goto   label_ReadAdc;
    }
  }
  //bulat здесь автопредел 1,1/0,22 в,программный
  kdel = 5;
  if (vMax <= 55) {
    if (vRef == 0)
    {
      kdel = 1;
    }
  }

  // == Отрисовка графика == //
  for (uint8_t x = 0; x < 92; x++)
    drawVLineUltraFast(x + 4, 67 - adcBuf[x + grOffset] / kdel / 0.9, 67 - adcBuf[x + grOffset + 1] / kdel / 0.9, 1); //progrik: drawVLineUltraFast вместо медленной drawLine
  Update();
}
////////////////////////////////////////////////////////////////////////////////////////////

//***************************************************************************************************************************
// РЕЖИМ ГЕНЕРАТОРА
void Generator() {
  // обработка кнопок и отрисовка одновременно
  Clear_LCD();
  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[0]))); // string_table[0]- ШИМ-генератор
  print(10, 3, TextColor, (buffer));

  if (D_Read(KEY_OK) == KEY_PRESSED) {
    if (menu++ == 7) menu = 0;  // переходим по разрядам / меняем ШИМ
    delay(KEY_DELAY);

  }
  if (menu == 7) { // меняем ШИМ
    if (D_Read(KEY_L) == KEY_PRESSED) {
      PWM--;
      if (PWM < 0)   PWM = 100;
      delay(KEY_DELAY/2);
    }
    if (D_Read(KEY_R) == KEY_PRESSED) {
      PWM++;
      if (PWM > 100) PWM = 0;
      delay(KEY_DELAY/2);
    }
    pwmWrite(GEN_PIN, PWM * 2.55); // задали ШИМ
    TextColor = 0; // если меняем шим, то рисуем его инверсным
    drawLine(15, 54, 74, 54, !TextColor); // сверху полоска для большей инверсности
  } else { // меняем частоту
    if (D_Read(KEY_L) == KEY_PRESSED) {
      if (freq > stepFreq)  freq -= stepFreq;          // не даем выйти за допустимый диаппазон
      SetPinFrequencySafe(GEN_PIN, freq / (OVERCLOCK / 16.0)); // задали частоту
      delay(KEY_DELAY); // задержка для кнопок
    }
    if (D_Read(KEY_R) == KEY_PRESSED) {
      if ((freq + stepFreq) < 10000000) freq += stepFreq; // не даем выйти за допустимый диаппазон
      SetPinFrequencySafe(GEN_PIN, freq / (OVERCLOCK / 16.0)); // задали частоту
      delay(KEY_DELAY); // задержка для кнопок
    }
    TextColor = 1; // если ШИМ не меняем, то выбираем обычный текст
#define XFREQ 20 // ======== // и, выделяем декаду частоты полосочками
    stepFreq = pow(10, (byte)menu); if (menu > 1) stepFreq++; // устраняем глючность pow, почему 10 в степени 2 = 99?
    byte menu_t = menu; if (menu > 5) menu_t++; // делаем табуляцию частоты
    menu_t = 56 - menu_t * 6; // считаем положение полосочек
    drawLine(menu_t, XFREQ - 2, menu_t + 4, XFREQ - 2, 1); // рисуем полоски
    drawLine(menu_t, XFREQ - 3, menu_t + 4, XFREQ - 3, 1);
    drawLine(menu_t, XFREQ + 8, menu_t + 4, XFREQ + 8, 1);
    drawLine(menu_t, XFREQ + 9, menu_t + 4, XFREQ + 9, 1);

  }

  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[1]))); // string_table[1]- ШИМ=
  print(15, 55, TextColor, (buffer));
  if (100 != PWM > 9) {
    drawChar(45, 55, TextColor, 32);
    print(51, 55, TextColor, PWM);
  }
  if (PWM == 100) print(44, 55, TextColor, PWM);

  if (PWM < 10) {
    drawChar(45, 55, TextColor, 32);
    print(51, 55, TextColor, PWM);
    drawChar(57, 55, TextColor, 32);
  }

  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[6]))); //string_table[6]- %
  print(63, 55, TextColor, (buffer));
  TextColor = 1; // убираем инверсию при выводе частоты


  float_print(14, XFREQ, TextColor, freq / 1000000.0, 6);


  strcpy_P(buffer, (char*)pgm_read_word(&(string_table[3]))); // string_table[3] - МГц
  print(65, XFREQ, 1,  (buffer));

  // отрисовка графика PWM
  for (char x = 20; x < 70; ) {
    if (PWM != 0)             drawLine(x, 34, x + PWM / 4, 34, 1); x += PWM / 4; // верх
    if (PWM != 0 && PWM != 100) {
      drawLine(x, 34, x, 48, 1);  // спад
      drawFastVLine(20, 34, 15, 1);
      drawFastVLine(70, 34, 14, 1);
    }
    if (PWM != 100)           drawLine(x, 48, x + 25 - PWM / 4, 48, 1); x += 25 - PWM / 4; // низ
    if (PWM != 0 && PWM != 100 && x < 46) drawLine( x, 48, x, 34, 1);        // подъем

  }

  Update(); // вываливаем буфер на дисплей
}

//***************************************************************************************************************************
//////////////////////////////Экран/////////////////////////////////
void Menu_ekrana() {
  for (char a = -4; a < 10; a += 8) {
    Clear_LCD();
    drawBitmap(16, a, logoLED, 64, 8);
    Update();
  }
  while (D_Read(KEY_OK) != KEY_PRESSED) {
    Clear_LCD();

    drawBitmap(16, 10, logoLED, 64, 8);

    if (BL == 1) {
      drawBitmap(20, 23, logoLED_ON, 40, 32);
      digitalWrite(Ekran, BL);
    } else
    { drawBitmap(32, 23, logoLED_OFF, 40, 32);
      digitalWrite(Ekran, BL);
    }
    if (D_Read(KEY_R) == KEY_PRESSED)  BL = 1;
    if (D_Read(KEY_L) == KEY_PRESSED)  BL = 0;

    Update();
  }
  //delay(KEY_DELAY);
  for (char a = 10; a < 90; a += 2) {
    Clear_LCD();
    drawBitmap(16, a, logoLED, 64, 8);
    Update();
  }

  Clear_LCD();  // чистим буфер экранчика
  // EEPROM.write(0, contrast);
  EEPROM.write(1, BL);
  void (* reboot)(void) = 0;
  reboot();


}

В посте по ссылке ниже есть комментарии для первоначальной версии на LCD 5110, в целом информация актуальна и для этой версии скетча, за исключением того, что тут дисплей 1202. Там и схема есть, но она не корректна - т.к. питание дисплея показано с пина Vin. Я думаю, что Вы и так разберётесь со скетчем, но для справочки всё же ссылку на тот пост оставлю. 

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

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

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

Что я имею в виду: При увеличении частоты меняется и скважность сигнала (хотя отображается установленная), и в какой-то момент сигнал пропадает. И только если протыкать курсор (кнопкой ОК) по всем разрядам до изменения скважности - всё становится нормально (даже если саму скважность не менять) сигнал установленной частоты появляется, и скважность соответствует установленной. А если опять менять частоту, то всё по новой.

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

штук 5 кондёров по 0.1мкф по питанию напаяй, один на питание ног микросхемы и электролитов пару 100,0х10в

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

со строки 1063 по строку по строку 1072 - нафик!
что это такое:

1073       break;
1074       // count = 16000000.0 / (13.0*(x - grOffset)*(1<<(8-razv)));

я так понял, порядок остался? что за чёрт? брейк до вычисления? ПОМЕНЯТЬ МЕСТАМИ!
сначала count = 16000000.0 / (13.0*(x - grOffset)*(1<<(8-razv))); а потом уже break;
break 
прерывает цикл, то, что после него - до лампочки.

ох уж...
или я ошибся?)) 
знаю, что нет... ну заменить же, заменить - откуда брейк вылез вперед вычислений?...
и последнее: если я таки гоню, то еще вариант вмест
о (1<<(8-razv)) попробовать pow(2, 8-razv), ибо возможны глюки из за типа данных... но я склоняюсь к первой ошибке - надо считать, потом брейкать..)

 

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

progrik пишет:

со строки 1063 по строку по строку 1072 - нафик!
что это такое:

1073       break;
1074       // count = 16000000.0 / (13.0*(x - grOffset)*(1<<(8-razv)));

я так понял, порядок остался? что за чёрт? брейк до вычисления? ПОМЕНЯТЬ МЕСТАМИ!

Да, Вы правы, в выложенном скетче некорректная запись, что-то наверное при копировании туда сюда накосячил. "Бряк" там действительно лишний.))) 

Что же касается вычисления частоты - то я пробовал именно так, как вы говорите - весь switch к чертям и оставляем только ту строку. Ну в общем так - 

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

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

 код count = 16000000.0 / (13.0*(x - grOffset)*pow(2, 8-razv)); даёт такой же результат... ..

Что же касается ШИМ-генератора, вернее его работы с "особенностями" о которой писал в предыдущем своём посте, то пока пофиксил эту "особенность" копированием строки

pwmWrite(GEN_PIN, PWM * 2.55); // задали ШИМ  из секции изменения скважности в секцию изменения частоты.

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

еще раз: сначала count = 16000000.0 / (13.0*(x - grOffset)*(1<<(8-razv))); а потом уже break;
БРЕЙК нужен, но ПОСЛЕ подсчета....
сейчас бухну - держитесь! разнесу тут все и всех к чертям!)))

вот, как надо:

count = 16000000.0 / (13.0*(x - grOffset)*(1<<(8-razv)));
break;

ну я же ни слова про брейк не говорил...
надо было заменить только 9 строк switch...(( на одну. брейк на месте....

когда это заработает, ждите еще порцию отборного мата)))

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

И действительно, работает! Это я конкретно затупил)) 

progrik пишет:

когда это заработает, ждите еще порцию отборного мата)))

Да, давайте! Всегда рад услышать конструктивный мат)))

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

uldin@mail.ru пишет:

штук 5 кондёров по 0.1мкф по питанию напаяй, один на питание ног микросхемы и электролитов пару 100,0х10в

Если Вы это к тому, что я писал про неправильное питание от пина Vin, то считаю лучше переделать, а не пытаться бороться с последствиями явно не корректного исполнения. Тем более, что ошибка была выявлена. Просто ещё раз поясню - я по глупости считал, что на пине Vin будет напряжение которым запитана ардуинка, а это не так. Этот пин предназначен только для входа питания. Причём напряжением от 7 до 12 вольт. 

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

Дубль. DEL... 

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

Hy6yk пишет:
И действительно, работает! Это я конкретно затупил))
три раза) работает - ну и фиг с ним...

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

....

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

Объясните мне, как это работает (пост 4674, строка 1207)? Где скобки? Или я не знаю чего-то?

///////////////авто razv//////////////
 if (avtorazv)
#define PER 1.3
if (count > 4323.3 * PER) razv = 6;
else if (count > 2434.5 * PER) razv = 5;
else if (count > 0969.3 * PER) razv = 4;
else if (count > 0486.8 * PER) razv = 3;
else if (count > 0245.8 * PER) razv = 2;
else if (count > 0120.1 * PER) razv = 1;
else razv = 0;

 

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

ардуино ide иногда позволяет такое, иногда нет. зависит то-ли от степени вложенности, то ли еще от чего. тут все норм, должно работать. иногда) как свитч. иф авторазв, за ним куча єлс-иф - все отлично. сам иногда в шоке, почему такое не пролазит. а иногда пролазит. когда все очень сложно - тогда видимо ну очень надо скобки рисовать...

рискну предположить, что и эту всю дичь можно записать в одну строку... кодеры-шмакодеры...

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

вобще 0 здравого смысла, алго, понимания - НОЛЬ...

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

Значит можно (и нужно) поставить фигурные скобки, и всё будет ОК?

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

а что не ок? ты же кодер, что сам не поставил? или я упускаю тонкий троллинг?

///////////////авто razv//////////////
#define PER 1.3
 if(avtorazv)
{
  if (count > 4323.3 * PER) { razv = 6; }
  else if (count > 2434.5 * PER) { razv = 5; }
  else if (count > 0969.3 * PER) { razv = 4; }
  else if (count > 0486.8 * PER) { razv = 3; }
  else if (count > 0245.8 * PER) { razv = 2; }
  else if (count > 0120.1 * PER) { razv = 1; }
  else { razv = 0; }
}

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

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

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

sadman41
Offline
Зарегистрирован: 19.10.2016

Капец ты ускоряльщик. Причём тут вложенные циклы?

После условия выполняется выражение. Если требуется выполнить несколько выражений , то они оформляются блоком, который обрамляется {}. В противном случае будет выполнено только первое выражение. Это стандарт языка.

progrik
Offline
Зарегистрирован: 30.12.2018
sadman41 пишет:
Капец ты ускоряльщик. Причём тут вложенные циклы? После условия выполняется выражение. Если требуется выполнить несколько выражений , то они оформляются блоком, который обрамляется {}. В противном случае будет выполнено только первое выражение. Это стандарт языка.
глубокие циклы - имеются ввиду участки кода с глубокой степенью вложенности, если вдруг я криво выразился. мне бухому так было понятно) и казалось, что все видят перед собой тот участок кода, где мне пришлось единственное действие после else заключить в скобки, ибо не компилилось... ардуино иде иногда и не такое выдает...
а этот кусок кода и без скобок рабочий... на этом и порешим...
Hy6yk
Offline
Зарегистрирован: 14.06.2020

Уважаемые, сеньоры! Давайте будем более уважительно относиться друг к другу... Позвольте мне продолжить...

Глюк заметил у себя - Пин D11 согласно распиновке ардуины нано имеет ШИМ, но когда я задаю его в качестве выхода генератора, то никакого сигнала на нём нет. Вернее даже так - сигнала нет если скважность меньше/равно 50%, если установить скважность больше 51 % то на выходе просто появляется потенциал (в районе 5 вольт) и всё, ни  каким сигналом определённой частоты там и не пахнет. Если переназначить выход на пин D3 например, или D10 - то как и полагается есть сигнал заданной частоты и скважности. Проверил на двух разных ардуинках - идентичная ситуация. Что это? Наши китайские партнёры подвели? Но ладно бы на одной ардуинке, а тут на двух купленных в разное время и у разных продавцов. Или это с чем-то другим связанно?

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

del

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

del

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

Думаю, надо "копать" в сторону используемых библиотек. Так как, в большинстве из них, "При работе с 8-битными таймерами доступен только один канал (например на ATmega328 останутся D3, D5, D9 и D10)". Ваш "Пин D11" - явно не входит в этот перечень.
https://alexgyver.ru/lessons/pwm-overclock/

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

Alex-Bee пишет:

Думаю, надо "копать" в сторону используемых библиотек. Так как, в большинстве из них, "При работе с 8-битными таймерами доступен только один канал (например на ATmega328 останутся D3, D5, D9 и D10)". Ваш "Пин D11" - явно не входит в этот перечень.
https://alexgyver.ru/lessons/pwm-overclock/

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

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

sadman41 пишет:
к вопросу о глюках.. моих или все-же иде: скажи, в твоих толстых книгах есть ответ, почему код ниже не компилится?

register byte b asm("r10");

void setup() {
  b = 2;
}

void loop() {
}

но тем не менее у меня в коде глобальные регистровые переменные используются и все работает. шесть штук, с r10 по r15... (больше в коде asm не используется, весь код на Си+-)
я уже когда _рабочий_ код написал, потом узнал, что глобальные регистровые переменные у людей не работают))
теперь не знаю, как это заработало... и есть проблемы с модификацией кода - иногда абсолютно в левом месте поменяешь 2 на 3 и вылазит та-же ошибка... вот такое оно, иде... или мне просто везет. или я просто тупой)) я-то уже собирал 4 флеш-рояля)))

sadman41
Offline
Зарегистрирован: 19.10.2016

Сначала херами обкладывал весь день, потом проспался, бред свой потёр, а теперь как ни в чем не бывало совета просишь? Ну-ну. 

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

sadman41 пишет:
Сначала херами обкладывал весь день, потом проспался, бред свой потёр, а теперь как ни в чем не бывало совета просишь? Ну-ну.
да, проспался, осознал, что ты начал буксовать по другому поводу. был невнимателен, и решил, что ты имеешь ввиду, что эта хрень не будет работать из-за отсутствия скобок... признаю, поспешил обматерить. я сказал, что данный код будет работать и без скобок. видимо seri0shka дефайн напугал и он подумал, что это работать не будет. но дефайн это не строка кода а указание препроцессору, поэтому будет работать (а вот это я не уверен знал ли ты).. и пихать в меня стандарт не надо, я знаю... именно из-за этого у меня и подгорело... я писал за глюк. может бухим непонятно выразился, или ты трезвым читал...

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

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

мне жаль, что ты успел почитать мой гневный бухой пизд*жь, сорри)) надо было совсем немножко) эксперимент с бухлом окончен, не понравилось))
ЗЫ: мне конечно алкотестер на клавиатуру не помешал-бы...

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

скажите мне, дорогие,
почему до сих пор никто не сделал подсчет частоты по всем периодам?
по одному - это бред. что делать, когда 10 периодов на 23 точки?

...передумал сыпать идеями...

я все давно сделал. в коде нереальное кол-во говна. когда в последний раз я помогал перепиливать "это" , я перепиливал и библиотеки. вы не понимаете, как глючит терминал, когда в него приходит перенос строки...
ВСЁ в этом коде сделано, чтобы хоть как-то работало. но не "как надо!".

и никто блин не пытается сделать, чтобы "хорошо" сделать ОХ*ЕННО!!...

всё таки сделаю топик с цветным осликом... там только кодящим будет помощь....

да уже и пусть будет, тереть устал)
Мона Лиза     в конце...
а так - собираю желающих совладеть с ТФТ))

застолблю за собой место первого, кто на ардуинке нарисовал спектром Мону Лизу, XY-осциллограф, сделал ФПС более любого вменяемого - эти две одинокие цифры, что обычто за 30-40...
и это _не_ _полная_ _скорость_. оставил место бездарям - ассеммблерщикам. потом еще раз их унижу.
(претензии принимаются только _датированными_ видео... жаль, что я это 4 года тому не снял))

sadman41 , есть еще место в книге, что ты мне хочешь процитировать? ну серьезно. опустите меня, обнаглевшего. все вместе. напишите ослик быстрее)))