VirtOs - Самый простой двухлучевой осциллограф осциллограф на Arduino

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015
    Пример того, как иногда бывает полезно не слушать мнение других. 
Все началось с того, что я решил попробовать программировать Ардуинки. Начал с GSM модуля и выяснил, что у меня нет такой важной вещи в быту, как осциллограф. Первым делом пошерстил по сети и нашел «Мини осциллограф Arduino на LCD 5110». Экрана у меня не было и решил создать свой проект «Выжимаем максимум. USB осциллограф на Arduino». Вроде все получилось, но апетиты росли. - Надо внешний АЦП.
    Тут стал вопрос. Городить свой колхоз, или спаять уже готовую схему из сети и не парится. Принято решение делать что то самому, но при этом начать с нуля, никого не слушать и не подсматривать как делают другие. Вот у меня родилась схема входного тракта с плавным масштабированием диапазона и автоматической подстройкой нуля. Схему развел на макетке, вроде все работает, но удовлетворение не приходит.
    По своему незнанию, что так делать нельзя и никто так не делает, я решил испробовать входной тракт с виртуальной землей. 
    Задумка такова:
    Зачем делать смещение сигнала и потом ловить ноль, если можно сместить щупов  землю на необходимое напряжение. То есть земля щупа подключается не к общей земле прибора, а к виртуальной земле, которая поддерживается ОУ.
    Что мне это дало:
    Плюсы:
1. Из входного тракта пропал один ОУ, который отвечает за смещение сигнала.
2. Опорное напряжение теперь можно плавно изменять в диапазоне 100%-300%, у меня пока только 100%-200%
3. Можно сделать второй луч абсолютно симметричным первому. Смещение будет общим.
4. Общее опорное напряжение для обоих АЦП (внешнего и внутреннего).
5. Смещение можно плавно регулировать. Землю можно притянуть к низу шкалы, таким образом смотреть только положительный сигнал, или к верху, тогда можно смотреть только отрицательное плече. Также его можно плавно смещать на необходимое значение и смотреть не симметричный сигнал на всю шкалу.
6. Отсутствует генератор отрицательно напряжения.
7. Из за отсутствия отрицательного напряжения, нет возможности спалить АЦП при выходе за диапазон.
8. Ну конечно, как вы догадались, два луча.
    Минусы:
1. Нет общей земли с прибором, потому работа только от аккумулятора.
2. Максимальная чувствительность прибора 0,016В на пиксель, при шкале 0В-4В.
Вот упрощенная схема входного тракта:
    Необходимый уровень смещения земли поддерживается ОУ U1. Опорное запитано с внешнего АЦП. Тут вроде все работает, но аппетиты росли и хотелось чего то большего. Решил изменять опорное 2В переменником, а также изменять смещения земмли.
    Тут меня ждал нежданчик. Мощности опорного напряжения, после прохода через переменник 10к явно не хватало. Начинались проседания и взаимопроникновения каналов. Долго бился над проблемой. Добавлять еще один ОУ не хотелось.
    В один вечер, при повторном  изучении АЦП AD9280, меня осенило. Ведь в АЦП есть свой ОУ, обратная связь которого выведена наружу. Пошаманив несколько часов, получил работающий пример.
    Тут надо немного объяснить. Как я понял, обратная связь тут не обычная. До какого то момента все идет по плану, но на грани притягивания REF SENSE к земле, срабатывает тригер в самом АЦП, вход обратной связи REF SENSE отключается и начинает работать как логический вход. Добавил резистор R2 и все стало на свои места. Уменьшая R2, можно добится опорного вплоть до напряжения питания.
    Программная и аппаратная часть.
    Долго думал какой дисплей выбирать. Решил испробовать черно-белый жидкокристаллический  дисплей. Библиотеку похерал как Бог черепаху. Переделал под SPI, убрал чего не нужно, прибрал пару багов по переполнению переменных. Вроде заработало.
    Дисплейчик примечателен тем, что он жутко инерционный, и потому отрисовка луча подобно как на ЕЛТ. На высоких частотах до 1мГц, можно даже увидеть сам сигнал. - Мне понравилось. Благо, на дисплее есть свой стабилизатор питания на 3,3В.
    Управление энкодером. Тут нечего добавить.
    Питание от китайских готовых преобразователей типа DC-DC Step UP.
    Скетч. Тут все просто. АЦП тактируется от таймера Т1 частотой 8 000 000 Гц. Максимальный захват за четыре такта 4 000 000 выб/с. Немного повозился с синхронизацией. Второй канал захватывается на высоких частотах линейной функцией, на низких через таймер Т2. На высоких частотах отключаю все прерывания. От использования переменных типа float отказался сразу – нечего там пробразовывать. Подписывать пункты меню не стал. Их всего пять и можно запомнить.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Внимание!!!!

На схеме ошибка.

Должно быть так:

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

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

Кварц 0,2$
Резисторы 0,2$
Конденсаторы 0,6$
DC-DC 0,5$
Зарядка 0,5$
Потенциометр 10К 2шт 0,5$
BNC разъем 0,6$
Плата печатная 0,7$
Энкодер 0,8$
Корпус 0,9$
ATMEGA328P-PU 1,3$
ОУ AD823AN 2,3$
АЦП ad9280 2,3$
Аккумулятор 2,3$
12864G-086-P 5,3$
Всего 19$
Xumuk
Xumuk аватар
Offline
Зарегистрирован: 03.03.2016

Okmor пишет:

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

Кварц 0,2$
Резисторы 0,2$
Конденсаторы 0,6$
DC-DC 0,5$
Зарядка 0,5$
Потенциометр 10К 2шт 0,5$
BNC разъем 0,6$
Плата печатная 0,7$
Энкодер 0,8$
Корпус 0,9$
ATMEGA328P-PU 1,3$
ОУ AD823AN 2,3$
АЦП ad9280 2,3$
Аккумулятор 2,3$
12864G-086-P 5,3$
Всего 19$

=))по стоимости равен китайскому дешевому ослику

bodriy2014
bodriy2014 аватар
Offline
Зарегистрирован: 12.05.2015

Xumuk пишет:

Okmor пишет:

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

Кварц 0,2$
Резисторы 0,2$
Конденсаторы 0,6$
DC-DC 0,5$
Зарядка 0,5$
Потенциометр 10К 2шт 0,5$
BNC разъем 0,6$
Плата печатная 0,7$
Энкодер 0,8$
Корпус 0,9$
ATMEGA328P-PU 1,3$
ОУ AD823AN 2,3$
АЦП ad9280 2,3$
Аккумулятор 2,3$
12864G-086-P 5,3$
Всего 19$

=))по стоимости равен китайскому дешевому ослику

DSO138

На первый взгляд стоит так-же, НО

--в нем нет DC-UP нужно докупить

--в нем нет AKB нужно докупить

--в нем нет зарядки нужно докупить

и он в 4 раза медленней и на один луч.

 

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Вот добавил, как обещал, новые видео и фото.

ВИДЕО

Внешний вид и разборка.

Сигнал 100 кГц,  400 кГц , 666  кГц

Сигнал 1мГц, 2мГц.

Сигнал 100кГц и увеличение 1х1.

Низкие частоты и двухканальный режим.

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

Okmor пишет:

Вот добавил, как обещал, новые видео и фото.

хороший результат!!!! походу нужно заказывать еще один дисплей)))

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Спасибо, Xumuk. 

Прибор и прошивка довольно сырые, но усложнять не хотелось. Кому надо, тот еще чего то добавит.

Для начинающего любителя больше и не надо. Потыкать и посмотреть сигнал - самое то. Прибор можно собрать на коленке и не сложен в наладке.

Yarik.Yar
Offline
Зарегистрирован: 07.09.2014

Поправил. Если надо ещё что-то редактировать, обращайтесь.

VetalST
Offline
Зарегистрирован: 29.12.2015

Классно получилось молодец!!!!!

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

 

 

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

VetalST пишет:

Классно получилось молодец!!!!!

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

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

VetalST
Offline
Зарегистрирован: 29.12.2015

И еще вопросик. Я хочу попробовать подключить другой дисплей. Мне нужно освободить A0 перенести на A6 где искать в скетче.

Или как вообще убрать 2 канал покаместь. Что бы место в ардуине освободить. Вы уже знаете где что, а то я не хочу что не буть нужное удалить.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

VetalST пишет:

И еще вопросик. Я хочу попробовать подключить другой дисплей. Мне нужно освободить A0 перенести на A6 где искать в скетче.

Или как вообще убрать 2 канал покаместь. Что бы место в ардуине освободить. Вы уже знаете где что, а то я не хочу что не буть нужное удалить.

void setADCSRA () {
        TCCR1A=0b00000000;   
        FlagSyncOk=false;      N=0;
        ADCSRA = (1 << ADEN) | (1 << ADSC) | (0 << ADATE) | (0 << ADIF) | (0 << ADIE) | (0 << ADPS2) | (1 << ADPS1) | (0 << ADPS0);
        ADMUX =  (0 << REFS1) | (0 << REFS0) | (1 << ADLAR)  | (0 << MUX3) | (0 << MUX2)  | (0 << MUX1)  | (0 << MUX0) ; 
  }
                                         //ADCSRA
                                          //0 ADEN: Разрешение работы ADC 
                                          //1 ADSC: Запуск преобразования ADC
                                          //0 ADATE: Включение режима автоматического запуска ADC
                                          //0 ADIF: Флаг прерывания ADC
                                          //0 ADIE: Разрешение прерывания ADC 
                                          //000 ADPS2:0: Биты управления предделителем ADC 
                                          //000 - CLK/2
                                          //001 - CLK/2
                                          //010 - CLK/4
                                          //011 - CLK/8
                                          //100 - CLK/16
                                          //101 - CLK/32
                                          //110 - CLK/64
                                          //111 - CLK/128            
                               
                                          //ADMUX
                                          //REFS1  REFS0  устанавливают какой источник опорного напряжения будет выбран:
                                          //00 - опорное напряжение на входе AREF (21 ножка)
                                          //01 - Vпитания (вход AREF должен быть отключен. или к нему можно подключить фильтрующий конденсатор)
                                          //10 - резерв
                                          //11 - внутренний ИОН 1.1 В (к входу AREF можно подключить фильтрующий конденсатор)
                                          //ADLAR (5) регистра ADMUX позволяет выравнивать результат преобразования по левому краю при записи в него 1.                                          
                                          //MUX3 - MUX0 (3 - 0) - управляют мультиплексором:
                                          
                                          //0000 - вход ADC0 (23 ножка)
                                          //0001 - вход ADC1 (24 ножка)
                                          //0010 - вход ADC2 (25 ножка)
                                          //0011 - вход ADC3 (26 ножка)
                                          //0100 - вход ADC4 (27 ножка)
                                          //0101 - вход ADC5 (28 ножка)
                                          //0111 - резерв
                                          //1000 - датчик температуры
                                          //1001 - 1101 - резерв
                                          //1110 - 1.1 В
                                          //1111 - 0 В (земля)

 

VetalST
Offline
Зарегистрирован: 29.12.2015

Если я правельно понял void setADCSRA () это второй канал.

А Биты 3:0 – MUX3:MUX0 – Биты выбора аналогового канала.

0000 ADC0
0001 ADC1
0010 ADC2
0011 ADC3
0100 ADC4
0101 ADC5
0110 ADC6
0111 ADC7

Мне прописать А6  ADMUX =  (0 << REFS1) | (0 << REFS0) | (1 << ADLAR)  | (0 << MUX3) | (1 << MUX2)  | (1 << MUX1)  | (0 << MUX0) ;
Я правильно понял ???? 
Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Да. setADCSRA () подготавливает АЦП к захвату. Измененя эту функцию, можно переназначить вход АЦП.

VetalST пишет:
Мне нужно освободить A0 перенести на A6 где искать в скетче.

Зачем? Используйте А6 для дисплея.

VetalST
Offline
Зарегистрирован: 29.12.2015

Okmor пишет:

Зачем? Используйте А6 для дисплея.

А6 и А7 это только аналоговый вход АЦП. Так разработчикам AVR захтелось добавить в TQFP и MLF корпус 2 ноги АЦП.

А0-----А5 можно настроить как аналоговые или цифровые порты ввода/вывода.

 

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

VetalST пишет:
А6 и А7 это только аналоговый вход АЦП. Так разработчикам AVR захтелось добавить в TQFP и MLF корпус 2 ноги АЦПА0-----А5 можно настроить как аналоговые или цифровые порты ввода/вывода

Кстати. Посмотрите как сделано у меня. Я ногу CS от дисплея тупо посадил на землю. Дисплей один и пусть всегда работает. Ногу RST подтянул к питанию через RC задержку. Не знаю почему, но сбрасывать надо с задержкой.

Итого, экономия двух ног.

VetalST
Offline
Зарегистрирован: 29.12.2015

Okmor Пологите пожалуйста у меня уже кипят мозги. Уберите с скетча все что касается второго канала и что лишнее на схеме. Выложите или скиньтена почту  vetalst777(собака)gmail.com.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

VetalST пишет:
 Okmor Пологите пожалуйста у меня уже кипят мозги. Уберите с скетча все что касается второго канала и что лишнее на схеме. Выложите или скиньтена почту  vetalst777(собака)gmail.com.

Залил сюда. Я не пробовал, но должно работать.

Там есть две функции с задержками. Задержки надо подобрать єкспериментально для точного отображения периода сигнала.

void delay32 ()
{ 
  
   //ADCSRA = ADCSRA | 1<<ADSC;
   asm("nop");asm("nop"); asm("nop"); 
   asm("nop");asm("nop"); asm("nop"); 
   PORTB  = PORTB  | 1<<1;
   asm("nop");asm("nop"); // х 8
   PORTB = PORTB & ~(1<<1);
   asm("nop");
}

void delay64 ()
{ 
  asm("nop");asm("nop"); 
   asm("nop");asm("nop"); asm("nop"); 
   asm("nop");asm("nop"); asm("nop"); 
   PORTB  = PORTB  | 1<<1;
   asm("nop"); // х 8
   PORTB = PORTB & ~(1<<1);
   asm("nop");
   delay16 ();delay16 ();delay16 ();
}

 

VetalST
Offline
Зарегистрирован: 29.12.2015

Спасибо.

gun-58
Offline
Зарегистрирован: 10.02.2016

Okmor не могли бы вы подсказать в какой версии программы компилировали свой скетч, а то у меня в Arduino 1.6.11 при компиляции выскакивает ошибка 'freeRam' was not declared in this scope. В чем может быть причина?

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

gun-58 пишет:
Okmor не могли бы вы подсказать в какой версии программы компилировали свой скетч, а то у меня в Arduino 1.6.11 при компиляции выскакивает ошибка 'freeRam' was not declared in this scope. В чем может быть причина?

У меня 1.6.5.

Относительно freeRam.

Не знаю почему у вас эта функция не поддерживается, но ее можно без ущерба выбросить из скетча, а также все ее упоминания в нем. Функция используется для отладки, что бы видеть оставшуюся оперативную память.

Выбросить вот это и все, где ругается на ее использование.

int freeRam(void)
{
  extern int  __bss_end;
  extern int  *__brkval;
  int free_memory;
  if ((int)__brkval == 0) {
    free_memory = ((int)&free_memory) - ((int)&__bss_end);
  }
  else {
    free_memory = ((int)&free_memory) - ((int)__brkval);
  }
  return free_memory;
}

 

gun-58
Offline
Зарегистрирован: 10.02.2016

Вот что происходит при компиляции скетча даже в 1.6.5. Выбрасывание этого куска не помогло. Компилирую в ардуино нано АТМега 328. Что еще может быть?

gun-58
Offline
Зарегистрирован: 10.02.2016

UpgaradeLibSPI.ino: In function 'void setup()':
UpgaradeLibSPI:70: error: 'freeRam' was not declared in this scope
'freeRam' was not declared in this scope

 Почему-то скрин экрана загрузился, но не передался. Программа останавливается в

void setup()  {

   SPI.begin() ;

   gicd.begin(12) ;

   glcd.display(); delay(500); glcd.clear();

   glcd.drawstringS(0, 0, "MEMORY= " + String(freeRam())) ;

На этой строке встает и пишет 'freeRam' was not declared in this scope

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Уберите строку 

glcd.drawstringS(0, 0, "MEMORY= " + String(freeRam())) ;

 

gun-58
Offline
Зарегистрирован: 10.02.2016

После того, как убрал эту строку появились следующие ошибки:

UpgaradeLibSPI.ino: In function 'void __vector_4()':
UpgaradeLibSPI.ino:181:18: warning: suggest parentheses around '&&' within '||' [-Wparentheses]
UpgaradeLibSPI.ino:184:19: warning: suggest parentheses around '&&' within '||' [-Wparentheses]
UpgaradeLibSPI.ino: In function 'void DravValue()':
UpgaradeLibSPI.ino:288:18: warning: unused variable 'kU' [-Wunused-variable]
D:\Моя папка\Arduino\Версии программы Ардуино\arduino-1.6.5-r5\libraries\ST7565\ST7565.cpp:29:77: fatal error: c:\Program Files\Arduino\hardware\arduino\avr\libraries\SPI\SPI.h: No such file or directory
 #include <c:\Program Files\Arduino\hardware\arduino\avr\libraries\SPI\SPI.h>
                                                                             ^
compilation terminated.
Ошибка компиляции.
 

gun-58
Offline
Зарегистрирован: 10.02.2016

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

VetalST
Offline
Зарегистрирован: 29.12.2015

gun-58 

В библиотеке ST7565 откройте файл ST7565.CPP программой блокнот Notepad++. найдите строчку #include <c:\Program Files\Arduino\hardware\arduino\avr\libraries\SPI\SPI.h> это путь к файлу SPI.h в библиотеке SPI. Вам нужно прописать #include < D:\Моя папка\Arduino\Версии программы Ардуино\arduino-1.6.5-r5\hardware\arduino\avr\libraries\SPI\SPI.h> и сохранить файл. 

gun-58 пишет:
После того, как убрал эту строку появились следующие ошибки:

UpgaradeLibSPI.ino: In function 'void __vector_4()':
UpgaradeLibSPI.ino:181:18: warning: suggest parentheses around '&&' within '||' [-Wparentheses]
UpgaradeLibSPI.ino:184:19: warning: suggest parentheses around '&&' within '||' [-Wparentheses]
UpgaradeLibSPI.ino: In function 'void DravValue()':
UpgaradeLibSPI.ino:288:18: warning: unused variable 'kU' [-Wunused-variable]
D:\Моя папка\Arduino\Версии программы Ардуино\arduino-1.6.5-r5\libraries\ST7565\ST7565.cpp:29:77: fatal error: c:\Program Files\Arduino\hardware\arduino\avr\libraries\SPI\SPI.h: No such file or directory
 #include <c:\Program Files\Arduino\hardware\arduino\avr\libraries\SPI\SPI.h>

                                                                             ^
compilation terminated.
Ошибка компиляции.

У вас arduino-1.6.5 лежит на диске D  D:\Моя папка\Arduino\Версии программы Ардуино\arduino-1.6.5-r5 и в самой Arduino 1.6.5 есть библиотека SPI находиться в папках hardware\arduino\avr\libraries\SPI\SPI.h .Некоторые версии Arduino ID могут глючить из за названий папок на русском по пути к программе Arduino ID.

Arduino 1.6.11 у меня без проблем все компелирует. НО ЕЙ НЕ НРАВИТЬСЯ  ДЛИННЫЙ ПУТЬ К СКЕТЧУ (папка в папке и так далие) когда есть папки с названиями написаных на русском языке, только цифры или англ. Я просто кидаю скетч в папке на рабочий стол и нет больше ни каких ошибок.  А сначала тоже было куча ошибок, и я подумал что глючьная какая то новоя весия, и холел удалить ее нафиг. 

gun-58 пишет:
Okmor не могли бы вы подсказать в какой версии программы компилировали свой скетч, а то у меня в Arduino 1.6.11 при компиляции выскакивает ошибка 'freeRam' was not declared in this scope. В чем может быть причина?
Перевод строки (FreeRAM не был объявлен в этой области)

Arduino 1.6.11 хочет чтобы Структура программы была написана по порядку. Сначала наши какие то функции ( int freeRam(void) ) и  т.д, Потом void setup() и в конце скетча void loop(). Хотя у меня сейчас глотает все скетчи написанны как угодно, и процентов на 5 -7 уменьшает код по сравнению с 1.6.5 и 1.6.7.

gun-58
Offline
Зарегистрирован: 10.02.2016

VetalST спасибо за разъяснение. Нашел ошибку в библиотеке SPI. Сейчас компиляция проходит, только пишет, что недостаточно памяти и программа может работать не стабильно.

denbox
Offline
Зарегистрирован: 18.09.2016

Okmor приветствую! Пытаюсь заказать детали для повторения вашего устройства. Подскажите пожалуйста, а зачем в перечне деталей нужен кварц?

VetalST
Offline
Зарегистрирован: 29.12.2015

И у меня к вам тоже вопрос. По мимо кварца ????? Собрал пытаюсь переделать на другой дисплей показывает но. Какие два из перемннных резистров 1 смещение земли, 2 Диапазон 1-2в, 3 подстройка измерителя опорного,  вынесены на корпус прибора ???? И не большие проблемы с энкодором. У вас я так понял энкодер 24 такта на оборот, а у меня 20 такта на оборот. Поэтому показания перепрыгивают через один, и попадаю в нужное меню струдом. Как это исправить программно не пойму, перепробывал почьти все. Так что в списке деталей уточните какой энкодер. 

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

denbox пишет:
Okmor приветствую! Пытаюсь заказать детали для повторения вашего устройства. Подскажите пожалуйста, а зачем в перечне деталей нужен кварц?

Это список для сборки без ардуинки на голом камне. Иначе кварца не надо.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

VetalST пишет:
Какие два из перемннных резистров 1 смещение земли, 2 Диапазон 1-2в, 3 подстройка измерителя опорного,  вынесены на корпус прибора ????

Подстройка измерителя опорного спрятана внутри. 

Смещение земли и диапазон наружу.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

VetalST пишет:
И не большие проблемы с энкодором. У вас я так понял энкодер 24 такта на оборот, а у меня 20 такта на оборот. Поэтому показания перепрыгивают через один, и попадаю в нужное меню струдом.

Увас энкодер с двойным щелчком. Должно лечится:

static boolean n=0;  if (n=!n){return;} // снять ремарку для энкодеров с двойным щелчком

ISR (PCINT1_vect) {
  //static boolean n=0;  if (n=!n){return;} // снять ремарку для энкодеров с двойным щелчком
  TimeClickB = millis();
  static byte old_n = PINC & B00011000; // маска B00011000 что б читать только нужные 2 бита
  byte new_n = PINC & B00011000;
  if (old_n == 8 && new_n == 24 || old_n == 16 && new_n == 0) {
    if ((PINC&(1<<5))==0){NumberMenu = constrain(NumberMenu-1,0,4) ;} else {--EncoderGo /*-= 1*/;}
  }
  if (old_n == 16 && new_n == 24 || old_n == 8 && new_n == 0) {
    if ((PINC&(1<<5))==0){NumberMenu = constrain(NumberMenu+1,0,4) ;} else {++EncoderGo /*+= 1*/;}
  }
  old_n = new_n;
}

 

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

gun-58 пишет:
VetalST спасибо за разъяснение. Нашел ошибку в библиотеке SPI. Сейчас компиляция проходит, только пишет, что недостаточно памяти и программа может работать не стабильно.

Это не ошибка, а предупреждение, что может нехватить оперативной памяти. Для этого и включил функцию freeRam(void). Я ею проверял всюду ли хватает памяти.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

VetalST пишет:
Собрал пытаюсь переделать на другой дисплей.

Можно поинтересоватся под какой дисплей вы переделываете.

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

Okmor пишет:

VetalST пишет:
Собрал пытаюсь переделать на другой дисплей.

Можно поинтересоватся под какой дисплей вы переделываете.

могу предположить что под ls020

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Xumuk пишет:
могу предположить что под ls020

Я тоже присматривался к этим дисплеям, но им по схеме нужно питание 9В на подсветку. - Забросил. Лежат три штуки без дела.

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

Okmor пишет:

Xumuk пишет:
могу предположить что под ls020

Я тоже присматривался к этим дисплеям, но им по схеме нужно питание 9В на подсветку. - Забросил. Лежат три штуки без дела.

думаю step-up в корпус пихнуть не проблема, я щас плату делаю под корпус для этого дисплея и ардуино ослика, с прошивкой от VetalST

VetalST
Offline
Зарегистрирован: 29.12.2015

Энкодер почьти поборол но на большых частотах все равно успевает иногда впоймать второй щелчк. Нужно ставить номальный как у вас.

ISR (PCINT1_vect) {
  //static boolean n=0;  if (n=!n){return;} // снять ремарку для энкодеров с двойным щелчком
  TimeClickB = millis();
  static byte old_n = PINC & B00011000; // маска B00011000 что б читать только нужные 2 бита
  byte new_n = PINC & B00011000;
  static boolean n=0;  //if (n=!n){return;} // снять ремарку для энкодеров с двойным щелчком
  
  if (old_n == 8 && new_n == 24 || old_n == 16 && new_n == 0) {
    if (n=!n){return;}
    if ((PINC&(1<<5))==0){NumberMenu = constrain(NumberMenu-1,0,5) ;} else {--EncoderGo /*-= 1*/;}
  }
  if (old_n == 16 && new_n == 24 || old_n == 8 && new_n == 0) {
    if (n=!n){return;}
    if ((PINC&(1<<5))==0){NumberMenu = constrain(NumberMenu+1,0,5) ;} else {++EncoderGo /*+= 1*/;}
  }
  old_n = new_n;
}

Экран да ls020. Но никак не могу побороть полностью мерцание, оно то и не мешает но неприятно. Спаял на плате разводил как умею я не спец. Микросхема МРС 6022 была под рукой, думал паять "хамелеон". Сегодня проверил в качестве генератора шим как в пультоскопе и в самодельном "Тестер полупроводников". Шим сигнал 100 кгц, 250 кгц идеольно 500 кгц надо подстроить переменным кондером на (5 рФ) нет под рукой впаял на 3 рФ. Хотя можно и микросхему поменять на AD823 может будет еще лутше.

Теперь о проблемах. 

Не определяет частоту после 30 кгц где копать ????

Не могу разобратся полностью с сеткой и нормально с шкалалой. Библиотека под ls020 получается что начало координат Y 0 и X 0 снизу в левом углу, в верх Y 131 и в право X 175. Поэтому все через задницу. Как обычно 0 X 0 Y в верху с лева, X длинна  а Y ширина высота экрана. Вот здесь я и запутался. Сегодня поишу как инвертировать экран, или изменю в библиотеке викину все лишнее и оставлю только пиксель линию и печать текста.  Okmor может у вас есть нормалная библиотека под ls020. И не могли бы вы прокоментировать в скетче где что для екрана и желательно все остальное.

 

VetalST
Offline
Зарегистрирован: 29.12.2015

VetalST пишет:
Теперь о проблемах. 

Не определяет частоту после 30 кгц где копать ????

Все заработало. Позаимствовал с вашей библиотеки функцию drawstringS и скрестил с своей библиотекой.

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

Okmor пишет:

Xumuk пишет:
могу предположить что под ls020

Я тоже присматривался к этим дисплеям, но им по схеме нужно питание 9В на подсветку. - Забросил. Лежат три штуки без дела.

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

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

VetalST пишет:
Теперь нужно разобратся с экраном. Нужно придумать как не закрашивать экран полностью, а затирать только сам график.

Надо копировать буфер захвата, если память позволит.

VetalST
Offline
Зарегистрирован: 29.12.2015

Затирать график получилось. Теперь нужно разобратся с сеткой и немного помелочам. Попозже освобожусь еще помучаю контроллеры. А то я уже умудрился, залочить две самодельные ардуины, програмировал через usb бар все в зборе. Пришлось доктором мк востанавливать.

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

VetalST пишет:

Затирать график получилось. Теперь нужно разобратся с сеткой и немного помелочам. Попозже освобожусь еще помучаю контроллеры. А то я уже умудрился, залочить две самодельные ардуины, програмировал через usb бар все в зборе. Пришлось доктором мк востанавливать.

Если свободно готовый скетч выложите . я попробую под ST7735 переделать.

VetalST
Offline
Зарегистрирован: 29.12.2015
/////////////////////////////////////
//D9 ADC clock
//D8  lcd RS
//D10 lcd CS
//D11 lcd DATA 
//D12 lcd ////
//D13 lcd CLK 
//A0  lcd RST
/////////////////////////////////////
//A1 Измерение опорнгого напряжения
//A2   Free
//A3 encoder
//A4 encoder
//A5 encoder button
//A6  ADC второй канал
//A7 Измерение смещения земли
////////////////////////////////////
uint8_t MyBuff_ADC[256];
uint8_t MyBuff_AI0[256];
uint8_t AI; 
byte old_ADCSRA;
byte old_ADMUX;

uint8_t MyBuff_ADCpov[256];
int StartPointpov = 0;

#include <stdio.h>
//#include <SPI.h> 
#include "S65_LCD.h"
#include "ADCRead.h"

int EncoderGo = 0;                //Меню. Номер активного меню
int StartPoint = 0;            //Синхронізаія Зсув, як результат синхронізації
int LastPoint = 0;            //Остання точка
byte CountPoint = 0;            //Кылькысть точок
int SyncVal = 127+20;           //Синхронізаія Значення синхронызацыъ
int Tinc = 20;
long  Fr=0;

#define Epin_A  A4              //Енкодер
#define Epin_B  A3              //Енкодер
#define Epin_SW A5              //Енкодер Кнопка
     
byte NumberMenu ;               //Меню. Поточне меню
int MeasureDelay = 3;           //Меню. Частота вибырки
byte Scale = 2 ;                //Меню. Масштаб /  0, 2, 4
int  BiasY = 0 ;                 //Меню. Змыщення по осі У
int BiasX = 0;
int BiasAI0 = 0;
int NullPoint = 175;            //Меню. Нульова точка ///128; 
int Uref     ;                   //опорна напруга
int UrefD;
int GroundValue    ;             //Зміщення землі

byte FlagSyncOk = true;         //АЦП закінчило зчитування
byte ADCGoes = true;            //АЦП в процесі зчитування
byte N =0;
unsigned long TimeClickB;  // Коли клыкнули кнопкою

///////////////////////////////////////////////////////////
/*
void testdrawchar(void) {
  for (int i=0; i < 168; i++) {
   // glcd.drawchar((i % 21) * 6, i/21, i+127);
 
    
  }    
}
*/
void stretchChart(byte M)
{
             for (int k = 0; k <= M; k++)
             {
                    for (int i = 254; i >= 1; i-=2)
                     {
                      MyBuff_ADC[i]= MyBuff_ADC[i/2];
                    
                     }  
                    for (int i = 253; i >= 1; i-=2)
                     {
                      MyBuff_ADC[i]= (MyBuff_ADC[i-1]+MyBuff_ADC[i+1])/2;
                    
                     } 
             } 
                                         
}

void setADCSRA () {   // ВТОРОЙ КАНАЛ НА А6
        TCCR1A=0b00000000;   
        FlagSyncOk=false;      N=0;
        ADCSRA = (1 << ADEN) | (1 << ADSC) | (0 << ADATE) | (0 << ADIF) | (0 << ADIE) | (0 << ADPS2) | (1 << ADPS1) | (0 << ADPS0);
        ADMUX =  (0 << REFS1) | (0 << REFS0) | (1 << ADLAR)  | (0 << MUX3) | (1 << MUX2)  | (1 << MUX1)  | (0 << MUX0) ; 
                                                             //(0 << MUX3) | (0 << MUX2)  | (0 << MUX1)  | (0 << MUX0) ; А0 
                                                             //(0 << MUX3) | (1 << MUX2)  | (1 << MUX1)  | (0 << MUX0) ; А6  
//        PORTB  = PORTB  | 1<<1;  PORTB = PORTB & ~(1<<1);  
//        PORTB  = PORTB  | 1<<1;  PORTB = PORTB & ~(1<<1);
//        PORTB  = PORTB  | 1<<1;  PORTB = PORTB & ~(1<<1);
//        PORTB  = PORTB  | 1<<1;  PORTB = PORTB & ~(1<<1); 
  }


void scanframe ()
{

 switch (MeasureDelay) {
          case 0: { TCCR1A=0b01000000;  noInterrupts(); LoadPin4();  interrupts();  stretchChart(2);  FlagSyncOk=true; break; }  
          case 1: { TCCR1A=0b01000000;  noInterrupts(); LoadPin4();  interrupts();  stretchChart(1);  FlagSyncOk=true;  break;}  
          case 2: { TCCR1A=0b01000000;  noInterrupts(); LoadPin4();  interrupts();  stretchChart(0);  FlagSyncOk=true;   break;}
          case 3: { TCCR1A=0b01000000;  noInterrupts(); LoadPin4();  interrupts();  FlagSyncOk=true;  break;}
          case 4: { TCCR1A=0b01000000;  noInterrupts(); LoadPin8();  interrupts();  FlagSyncOk=true;  break;}
          case 5: { TCCR1A=0b01000000;  noInterrupts(); LoadPin16(); interrupts();  FlagSyncOk=true;  break;}
          case 6: { noInterrupts(); setADCSRA (); LoadPin32();  interrupts();  FlagSyncOk=true;  break;}
          case 7: { noInterrupts(); setADCSRA ();  LoadPin64();  interrupts();  FlagSyncOk=true;  break;}                                        
          case 8: {  setADCSRA ();  TCCR2A=0;  TCCR2B=(0<<CS22)|(0<<CS21)|(1<<CS20);  OCR2A=100;   TIMSK2=(1<<OCIE2A);    break;}
          case 9: {  setADCSRA ();  TCCR2A=0;  TCCR2B=(0<<CS22)|(0<<CS21)|(1<<CS20);  OCR2A=227;  TIMSK2=(1<<OCIE2A);  break;}   
          case 10: { setADCSRA ();  TCCR2A=0;  TCCR2B=(0<<CS22)|(1<<CS21)|(0<<CS20);  OCR2A=61;  TIMSK2=(1<<OCIE2A); break;}   
          case 11: { setADCSRA ();  TCCR2A=0;  TCCR2B=(0<<CS22)|(1<<CS21)|(0<<CS20);   OCR2A=127; TIMSK2=(1<<OCIE2A);    break;}                               
          case 12: { setADCSRA ();  TCCR2A=0;  TCCR2B=(0<<CS22)|(1<<CS21)|(0<<CS20);  OCR2A=255;  TIMSK2=(1<<OCIE2A); break;}    
          case 13: { setADCSRA ();  TCCR2A=0;  TCCR2B=(0<<CS22)|(1<<CS21)|(1<<CS20);  OCR2A=128;  TIMSK2=(1<<OCIE2A);     break;}  
          case 14: { setADCSRA ();  TCCR2A=0;  TCCR2B=(0<<CS22)|(1<<CS21)|(1<<CS20);  OCR2A=255;  TIMSK2=(1<<OCIE2A);    break;}                                                             
          default: { ; break;}
        }
}


ISR(TIMER2_COMPA_vect) {
   TCNT2 = 0; // Работает, если вручную обнулять
   PORTB  = PORTB  | 1<<1;  PORTB = PORTB & ~(1<<1);
   ADCSRA |= (1<<ADSC);
   MyBuff_ADC[N] = PIND ;
   MyBuff_AI0[N+2] = ADCH; 
   N++;
   if (N>= 250) {TIMSK2=0b00000000; FlagSyncOk = true; ; };
 }
  
ISR (PCINT1_vect) {
  //static boolean n=0;  if (n=!n){return;} // снять ремарку для энкодеров с двойным щелчком
  TimeClickB = millis();
  static byte old_n = PINC & B00011000; // маска B00011000 что б читать только нужные 2 бита
  byte new_n = PINC & B00011000;
  static boolean n=0;  //if (n=!n){return;} // снять ремарку для энкодеров с двойным щелчком
  
  if (old_n == 8 && new_n == 24 || old_n == 16 && new_n == 0) {
    if (n=!n){return;}
    --EncoderGo /*-= 1*/;
  }
  if (old_n == 16 && new_n == 24 || old_n == 8 && new_n == 0) {
    if (n=!n){return;}
    ++EncoderGo /*+= 1*/;
  }
  old_n = new_n;
}


void ExecEncoder()
{
/////////////// свое /////////////////////////////////////////////////////  
  if ((PINC&(1<<5))==0){
    delay (30);
   while((PINC&(1<<5))==0);
    delay (30);
    if(NumberMenu < 6){
      NumberMenu++;
    }
    if(NumberMenu >= 6){
      NumberMenu=0;
    }
    clear(BLACK);  //закрашиваем дисплей, 
  }
//////////////////////////////////////////////////////////////////////////
  if (EncoderGo != 0) {
    
    switch (NumberMenu) {
      case 0: {//час розгортки
          if ((PINC&(1<<2))==0) {MeasureDelay = MeasureDelay + (EncoderGo);   //*0*/byte MUX = 2;  // Частота вибырки
                                MeasureDelay = constrain(MeasureDelay, 0, 14);}
               else {
                        BiasX = BiasX - EncoderGo;
                         BiasX = constrain(BiasX, 0-StartPoint, 175-StartPoint);
                    };
                  clear(BLACK);  //закрашиваем дисплей, 
          break;
        }
      case 1: { // точка синхронізації
          SyncVal += EncoderGo<<Scale; //  constrain(EncoderGo,-10,10)/*<<Scale*/;
          clear(BLACK);  //закрашиваем дисплей,
          break;
      }
      case 2: {// масштаб по вертикалі
          Scale = constrain(Scale + EncoderGo, 0, 2);  //*2*/byte Scale = 0 ;//Масштаб /  0, 2, 4
          clear(BLACK);  //закрашиваем дисплей,
          break;
        }// constrain(Scale+K,0,2); break;}
      case 3: {
          BiasY = BiasY + EncoderGo  ;   //*3*/int  Bias ; //Змыщення по осі У
          clear(BLACK);  //закрашиваем дисплей,
          break;
        }
      case 4: {
          BiasAI0 = BiasAI0 + EncoderGo  ;   //*3*/int  Bias ; //Змыщення по осі У
          clear(BLACK);  //закрашиваем дисплей,
          break;
        }        
        case 5: {
           //ls020_put_string8(60,120,"OFF LCD ",CL8_RED,CL8_BLACK,1,2,1); // пишем
           
          break;
        } 

    };

   EncoderGo = 0; 
  }
}

void synchronization()
{
  StartPoint = 6;
  LastPoint = 0;           
  CountPoint = 0;     
  for (int i = 6; i <= 253 ; i++) // тут 
  {
    if( ((MyBuff_ADC[(i-3 )]*2+MyBuff_ADC[(i-2 )]*4+MyBuff_ADC[(i-1 )]*8)<=SyncVal*14)&&
       ((MyBuff_ADC[(i+3 )]*2+MyBuff_ADC[(i+2 )]*4+MyBuff_ADC[(i+1 )]*8)>=SyncVal*14) 
       )
            {// Тут знайшли точку.
             if (StartPoint==6) {StartPoint = (i) ; i= i+8;  }
               else {
                     if ((i-StartPoint)>125 ) {  break;}
                     else {
                     CountPoint++; 
                     LastPoint = i;
                     i= i+8; }
                    }
            };
  }; 

}

void ReadRefValue ()
{
   NullPoint =  (NullPoint*3+analogread_map(7,0,1023,0,255))/4   ; 
   UrefD =  (UrefD*3+analogread256(1))/4  ;       ///13*3.6 Калыбровка дыапазону
   Uref = UrefD*13/11;
   
}

void DravValue() {
  
//  glcd.drawstringS(0, 4, "BiasX= " + String(BiasX)) ;
//  glcd.drawstringS(0, 5, "StartPoint= " + String(StartPoint)) ;
  
 // glcd.drawstringS(0,2, "Cnt= " + String(CountPoint)) ;
//  glcd.drawstringS(0, 2, "MDelay= " + String(MeasureDelay)) ;
//  glcd.drawstringS(0, 0, "Fr= " + String((32000000>>MeasureDelay)/((LastPoint-StartPoint)/CountPoint))) ;
  
//  glcd.drawstringS(0, 1, "Memory= " + String(freeRam())) ;
//  glcd.drawstringS(0, 3, "Pin2= " + String(((PINC&(1<<2))==0))) ;

  unsigned long  kU = 65535;
  byte show = !((millis()-TimeClickB)>2000) ;
  String period = String(MeasureDelay);
  switch (MeasureDelay) {
  case 0:  {Tinc = 16 ; period = "0.5"; period[3]=230; break ;}  // 0.625мс  32000000
  case 1:  {Tinc = 16 ; period = "1" ; period[1]=230; break ;}   // 1.25мс 16000000 
  case 2:  {Tinc = 20 ; period = "2.5"  ; period[3]=230; break ;}    // 2.5µs  8000000
  case 3:  {Tinc = 20 ; period = "5"    ; period[1]=230; break ;}     // 5мс*******400000**************
  case 4:  {Tinc = 20 ; period = "10"   ; period[2]=230; break ;}     // 5мс
  case 5:  {Tinc = 20 ; period = "20"   ; period[2]=230; break ;}
  case 6:  {Tinc = 25 ; period = "50"   ; period[2]=230; break ;}
  case 7:  {Tinc = 25 ; period = "100"  ; period[3]=230; break ;}
  case 8:  {Tinc = 25 ; period = "200"  ; period[3]=230; break ;}
  case 9:  {Tinc = 25 ; period = "400"  ; period[3]=230; break ;}
  case 10: {Tinc = 25 ; period = "800"  ; period[3]=230; break ;}
  case 11: {Tinc = 25 ; period = "1.6"  ;  break ;}
  case 12: {Tinc = 25 ; period = "3.2"  ;  break ;}
  case 13: {Tinc = 25 ; period = "6.4"  ;  break ;}
  case 14: {Tinc = 25 ; period = "12.8"  ;  break ;}
  };

   
  if ((show)|(NumberMenu==0)) {
                      
                      ls020_drawstringS(155-10*period.length(), 2, period + "ms", 1, RED, BLACK) ;///
                      
                      if (CountPoint!=0){ 
                        Fr = ((32000000*CountPoint/(LastPoint-StartPoint)>>MeasureDelay));
                       // glcd.drawstringS(0, 0, "Fr= " + String(Fr) ) ;
                      ls020_drawstringS(0, 2, "Fr= " + String(Fr) + " Hz     ", 1, RED, BLACK) ;/////  
                         } 
                      else {
                        //glcd.drawstringS(0, 0,"Fr= ----");
                        ls020_drawstringS(0, 2, "Fr= ----", 1, RED, BLACK) ;/////
                        }
                      } ; // 0 Частота вибырки
  //if ((show)|(NumberMenu==1)) {glcd.drawstringS(127-6*String(SyncVal).length(), 1, String(SyncVal) ) ;} ;
  if ((show)|(NumberMenu==1)) {ls020_drawstringS(171-10*String(SyncVal).length(), 12, String(SyncVal), 1,RED, BLACK) ;} ;
 
 // if ((show)|(NumberMenu==2)) {glcd.drawstringS(127-6*String(Scale).length(), 2 , String(Scale) )  ;} ; //1 Масштаб /  0, 2, 4
 if ((show)|(NumberMenu==2)) {ls020_drawstringS(171-10*String(Scale).length(), 22, String(Scale), 1, RED, BLACK) ;} ;
    
//  if ((show)|(NumberMenu==3)) {glcd.drawstringS(127-6*String(BiasY).length(), 3 , String(BiasY) )  ;} ;
   if ((show)|(NumberMenu==3)) {ls020_drawstringS(171-10*String(BiasY).length(), 32, String(BiasY), 1, RED, BLACK) ;} ;
    
//  if ((show)|(NumberMenu==4)) {glcd.drawstringS(127-6*String(BiasAI0).length(), 4 , String(BiasAI0) )  ;} ;
if ((show)|(NumberMenu==4)) {ls020_drawstringS(171-10*String(BiasAI0).length(), 42, String(BiasAI0), 1, RED, BLACK) ;} ;
    
 if (show){  // указатель меню
  //glcd.drawline(127, 0+NumberMenu*8, 127, 7+NumberMenu*8, BLACK);
  //glcd.drawline(126, 0+NumberMenu*8, 126, 7+NumberMenu*8, BLACK);
  drawLine(175, 0+NumberMenu*10, 175, 10+NumberMenu*10, YELLOW); // линия
  drawLine(174, 0+NumberMenu*10, 174, 10+NumberMenu*10, YELLOW); // линия
  drawLine(173, 0+NumberMenu*10, 173, 10+NumberMenu*10, YELLOW); // линия
  };
}

void drawL (int y) {
  if (y <= 255) {
                   for (int i = 0; i <= 175; i = i + 4) // горизонтальная сетка
                  {
                    setpixel(i,y,WHITE);
                    //lcd_setPixel8(i,y,CL8_BLUE);
                  }
  }
}

void DrawGrid() {
  int y = 0;
  drawL (NullPoint+Uref/2);
  drawL (NullPoint+Uref/2-Uref/16);
  drawL (NullPoint+Uref/4);
  drawL (NullPoint+Uref/8);
  drawL (NullPoint+Uref/16);      
  drawL (NullPoint+Uref/2-Uref/8);
  drawL (NullPoint+Uref/4+Uref/16);
  drawL (NullPoint+Uref/4-Uref/16);
    
  drawL (NullPoint-(Uref/2));
  drawL (NullPoint-(Uref/2-Uref/16));    
  drawL (NullPoint-(Uref/4));
  drawL (NullPoint-(Uref/8));
  drawL (NullPoint-(Uref/16));        
  drawL (NullPoint-(Uref/2-Uref/8));  
  drawL (NullPoint-(Uref/4+Uref/16));
  drawL (NullPoint-(Uref/4-Uref/16));

  for (int i = 0; i <= 175; i = i + 4) // 0 сетки центр графика
  {
    setpixel(i,NullPoint,BLUE);
          //lcd_setPixel8(i,NullPoint,CL8_BLUE);    
   // setpixel(i+1,NullPoint,CL8_WHITE);
         //lcd_setPixel8(i+1,NullPoint,CL8_BLUE);
    setpixel(i+2,NullPoint,BLUE);/////
   // setpixel(i+3,NullPoint,CL8_WHITE);/////
  };
   
  for (int x = Tinc; x <= 175; x = x + Tinc) // вертикальная разметка
  {
    for ( y = 0; y <= 256; y = y + (4<<Scale))  {
        setpixel(x, y, WHITE); 
       // lcd_setPixel8(x, y, CL8_BLUE);
      }
  };
  

   drawLine(0-BiasX, ScalePint(SyncVal), 5-BiasX, ScalePint(SyncVal),WHITE);
      
   drawLine(LastPoint-StartPoint, 126,LastPoint-StartPoint, 131,WHITE); 
    
   drawLine(0-BiasX, 126,0-BiasX, 131,WHITE);
   
}

void DrawChart()   // uint8_t MyBuff_ADCpov[256]  int StartPointpov = 0;
{
  int aY1 ;
  int aY2;
  int bY1 ;
  int bY2;

 StartPoint = StartPoint+BiasX;
    
    for (int i = StartPointpov; i <= 175+StartPointpov; i++)
  {
    
    bY1= ScalePint(MyBuff_ADCpov[i]);
    bY2= ScalePint(MyBuff_ADCpov[i+1]);

    //LCD_line(i-StartPointpov, bY1, i+1-StartPointpov, bY2, CL8_BLACK); // линия 
    drawLine(i-StartPointpov, bY1, i+1-StartPointpov, bY2, BLACK);//график
  }; 
  //////////////////////////////////////////////////////////////////////////////
  for (int i = StartPoint; i <= 175+StartPoint; i++)
  {
    
    aY1= ScalePint(MyBuff_ADC[i]);
    aY2= ScalePint(MyBuff_ADC[i+1]);

   // LCD_line(i-StartPoint, aY1, i+1-StartPoint, aY2, CL8_GREEN); 
    drawLine(i-StartPoint, aY1, i+1-StartPoint, aY2, GREEN);//график// линия
  }; 
  
  StartPointpov = StartPoint;
  
  for(int i = 0; i < 256; i++){  // копируем с одного в другой массив
        MyBuff_ADCpov[i] = MyBuff_ADC[i]; // убираем все лишнее
        }

};
////////////////////////////////////////////////////////////////////////////////
int ScalePint( int Y)
{ 
  
  return constrain((((255 - Y)>>Scale)- BiasY-((127 >> Scale) - 95)) , 0 , 255) ; 
                //((((255 - Y)>>Scale)- BiasY-((127 >> Scale) - 100)), 0 , 255) ;
  
}

void setpixel(int X , int Y, char color )
{
  Y = ScalePint( Y);
  if ((Y>0)&&(Y<132)) {drawPixel(X, Y, color);}
};


int freeRam(void)
{
  extern int  __bss_end;
  extern int  *__brkval;
  int free_memory;
  if ((int)__brkval == 0) {
    free_memory = ((int)&free_memory) - ((int)&__bss_end);
  }
  else {
    free_memory = ((int)&free_memory) - ((int)__brkval);
  }
  return free_memory;
}

/////////////////////////////////////////////////////////////////
void setup()   {
  
  SPI_init(); //Start HW SPI ; do nothing in SW SPI
  LCD_init(); //init Ports and LCD //закрашиваем дисплей,
  ls020_8bit_mode(0); //Установите 8-битный режим LCD
  //ls020_8_color_mode();
  clear(BLACK);  //закрашиваем дисплей,
  delay(500);
  
  PORTC|=(1<<PC2)|(1<<PC3)|(1<<PC4)|(1<<PC5)|(1<<PC6); //подтяжка кнопок на A3, A4 , A5
  DDRB |= (1<<PB1); // Настройка D9  на вихід  9-8=1
//  ADMUX =  (0 << REFS1) | (0 << REFS0) ; // Зовнішня опорна напруга
  
  ADCSRA = (1 << ADEN) | (1 << ADSC) | (0 << ADATE) | (0 << ADIF) | (0 << ADIE) | (0 << ADPS2) | (1 << ADPS1) | (0 << ADPS0);
  ADMUX =  (0 << REFS1) | (0 << REFS0) | (1 << ADLAR)  | (0 << MUX3) | (0 << MUX2)  | (0 << MUX1)  | (0 << MUX0) ; 

//Енкодер включити переривання
  PCICR = 1 << PCIE1; //разрешить пренрывание
  PCMSK1 = B00111000 ; //(1<<PCINT12)|(1<<PCINT11); //выбрать входы
  //PCMSK1=(1<<PCINT9)|(1<<PCINT10)|(1<<PCINT11); //выбор пинов прерывания (9-A1, 10-A2, 11-A3)
  //    B00000000
  //     76543210
  //PCINT14   PCINT13   PCINT12   PCINT11   PCINT10   PCINT9    PCINT8
  

//Таймер ногодриг для АЦП
  TCCR1A=0b01000000; //подключить выход OC1A первого таймера
  TCCR1B=0b00001001;//

}

void loop()
{   
    if (FlagSyncOk){
      ExecEncoder();       
       // glcd.clear();
        synchronization(); 
        DrawChart();
        if ((PINC&(1<<2))==0) {
          ReadRefValue ();
          scanframe ();
          };
       DrawGrid();
       DravValue();
       //glcd.display();
      
    if(NumberMenu==5){ //  отключение дисплея 
        drawText(20, 50,"OFF LCD", 2, RED, BLACK);// пишем     
       if (PINC & (1 << PINC2)) {
          lcd_poweroff (); //выключить дисплей
           }
       }
      };
    
};
/////////////////////////////////////////////////////////////

Okmor Как расчитать сетку что бы была на весь экран ?????? Библиотека стандартная  X0, Y0 в верху слева.

 return constrain((((255 - Y)>>Scale)- BiasY-((127 >> Scale) - 95)) , 0 , 255) ;  методом тыка опустил вниз и все. Сетка на пол экрана и дальше у меня уже мозги кипят.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

VetalST пишет:
 Okmor Как расчитать сетку что бы была на весь экран ?????? Библиотека стандартная  X0, Y0 в верху слева.

 return constrain((((255 - Y)>>Scale)- BiasY-((127 >> Scale) - 95)) , 0 , 255) ;  методом тыка опустил вниз и все. Сетка на пол экрана и дальше у меня уже мозги кипят.

int ScalePint( int Y)
{ return constrain(    (((255 - Y)>>Scale)- BiasY-((127 >> Scale) - 31)) , 0 , 255) ;}

 

Функция ScalePint масштабирует изображение и зеркалирует ось Y.

Scale - делитель масштаба. при Scale = (0, 1, 2) масштаб делится на (/1, /2, /4) соответственно.

(255 - Y)>>Scale  - переворачивает изображение и масштабирует его

BiasY - это возможность сдвигать график вверх/вниз при большом масштабе.

(127 >> Scale) - 31) - это поправка для того, чо бы график всегда был по центру, а не масштабировался от нулевой точки. Для вас будет (127 >> Scale) - 62

При высоте дисплея 132 точки, у вас будет только две градации маштаба Scale = (0, 1)

поправте здесь: 

case 2: {// масштаб по вертикалі
 Scale = constrain(Scale + EncoderGo, 0, 1);  //*2*/byte Scale = 0 ;//Масштаб /  0, 2
Также надо снять ограничение на высоту дисплея, поменяв 64 на 127.
void setpixel(int X , int Y, byte color )
{
  Y = ScalePint( Y);
  if ((Y>0)&&(Y<127)) {glcd.setpixel(X, Y, color);}
};

Я могу ошибатся, тотому, что сам чуть голову не сломал избегая делений и типа float.

 
 
VetalST
Offline
Зарегистрирован: 29.12.2015

Вот убогое видео https://youtu.be/DLu7stRZ8K8 того что получилось

Это видео https://www.youtube.com/watch?v=5UyFiLwjZNM проблеммы с разверткой и синхронезацией. Как это можно исправить. И как она вообще работает и как ее перещитать.

Вот видео https://youtu.be/gyQD55e4lJU Без синхронезации чистый график на всеж режимах развертки.

////////////////////////////// ИЗМЕНЯЛ ///////////////////////////////////////////////////
void synchronization()
{
  StartPoint = 4;// = 6 ИЗМЕНЯЛ на 4
  LastPoint = 0;           
  CountPoint = 0;     
  for (int i = 4; i <= 253 ; i++) // тут //// i = 6 ИЗМЕНЯЛ на 4
  {
    if(((MyBuff_ADC[(i-3 )]*2+MyBuff_ADC[(i-2 )]*4+MyBuff_ADC[(i-1 )]*8)<=SyncVal*14)&&
       ((MyBuff_ADC[(i+3 )]*2+MyBuff_ADC[(i+2 )]*4+MyBuff_ADC[(i+1 )]*8)>=SyncVal*14))
            {// Тут знайшли точку.
             if (StartPoint==4) {StartPoint = (i) ; i= i+8;  } //StartPoint==6 ИЗМЕНЯЛ на 4
               else {
                     if ((i-StartPoint)>110 ) {  break;}// 125 ИЗМЕНЯЛ на 110
                     else {
                     CountPoint++; 
                     LastPoint = i;
                     i= i+8; }
                    }
            };
  }; 

}
///////////////////////////////////////////////////////////////////////////////////////////

Меняя в //" for (int i = 4; i <= 253 ; i++) // тут //// i = 6 ИЗМЕНЯЛ на 4"// меньше 4 появляются шумы в начале графика когда нет сигнала.

StartPoint = 4;// = 6 ИЗМЕНЯЛ на 4 и  if ((i-StartPoint)>110 ) {  break;}// 125 ИЗМЕНЯЛ на 110

Уменишились шумы. На меньшей развертке шумов нет вообще.

А развернуть еще шире шумы появляются до пол экрана

КАК ЭТО МОЖНО ИСПРАВИТЬ ???????

enjoyneering
enjoyneering аватар
Offline
Зарегистрирован: 05.09.2016

" Зачем делать смещение сигнала и потом ловить ноль, если можно сместить щупов  землю на необходимое напряжение."

а у вас при этом между землей осцилографа и землей измеряемого сигнала разности напряжения не получится? ток не потечет?

VetalST
Offline
Зарегистрирован: 29.12.2015

 В посте выше добавил видео без синхронезации чистый график на всеж режимах развертки.

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

enjoyneering пишет:
а у вас при этом между землей осцилографа и землей измеряемого сигнала разности напряжения не получится? ток не потечет?

Ток не потечет, если осциллограф питается от аккумулятора. Это цена которую придется платить за простоту.

VetalST пишет:
меньше 4 появляются шумы в начале графика когда нет сигнала.

Читайте мануал. Я до конца не понял, но преобразование происходит за четыре такта. Тоесть конвеером. Потому первые четыре измерения надо отбрасывать.

VetalST пишет:
 А развернуть еще шире шумы появляются до пол экрана 

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

Okmor
Okmor аватар
Offline
Зарегистрирован: 16.10.2015

Осторожно подделка!!!

Заказал для пробы два ОУ AD823

На картинке усиление синуса коэфициент 1:1. Графики раздвинул для наглядности.