Систематизированного описания нигде не найти, т.к. каждый переписывает/адаптирует свою версию под себя, свои нужды. Схема - я думаю, не сильно отличается от оригинальной схемы автора, но были варианты, кто делал под прибор плату, со своими доработками - вот там схема может отличаться от оригинальной. В своих версиях я не уходил от схемы автора, и старался все изменения писать в начале файла в комментарии.
Понял, спасибо. В программировании к сожалению я не силен, во всяком случае пока...) Приходится довольствоваться тем что есть)) Можете вкратце описать функционал доступных в теме версий прибора? Какую порекомендуете?
Дак функционал то от версии к версии остается в общем и целом одним и тем же. Добавляют ребята себе фишки в виде управлением подсветки дисплея, меню настроек, ну кароче по большому счету функционал чтобы так глобально - никто не переделывает. Некоторые зачем то удалают часть функций, ссылаясь на то, что памяти не хватает им. Памяти предостаточно! - надо уметь рационально её использовать.
Порекомендую, кАнечно же свой варинат, на данный момент времени это PULTOSCOPE_LCD5110_EL83_18_OK. Эта версия - вторая моя переделка с нуля кода автора, код оптимизирован, добавлены некторые фишки, например в виде графического меню, ну кароче ни одну ночь я провел за компьютером. Есть и более свежие версии, но выкладывать их не стал, т.к. что то там было не так. Стараюсь выкладывать всегда более менее проверенные мной версии, но без каких то багов редко обходится (в авторской версии тоже есть косяки).
Вот Скетч для 5510 подсветка к пину 8 + регулировка контрасности.
//Страница проэкта <a href="<a href="http://srukami.inf.ua/pultoscop_v25110.html" rel="nofollow">http://srukami.inf.ua/pultoscop_v25110.html</a>" rel="nofollow"><a href="http://srukami.inf.ua/pultoscop_v25110.html" rel="nofollow">http://srukami.inf.ua/pultoscop_v25110.html</a></a>
// ---------------------------------------------------------------
// От Electronik83 (mailto: <a href="mailto:gsmkillersevsk@mail.ru">gsmkillersevsk@mail.ru</a>): ver 17032017
// 1. В режиме генератора PWM в процентах в целых числах (без дробей), нарисовал график сигнала PWM
// 2. В генераторе пофиксил/оптимизировал вывод частоты (1000 герц не показывало)
// 3. Автоматическое определение схемы подключения кнопок (при включении лучше ничего не нажимать:) :
// a). Как у автора - кнопки к питанию и резюки на массу
// b). Как я хочу - кнопки к земле и без всяких резюков
// 4. Отправил вэйвы для DDS генератора во флэш - оперативы больше стало свободной
// 5. Реализовал перезапуск при зажатии кнопок "+" и "-" (из осцилла не работает (не знаю, как исправить!))
// 6. Убрал развертки 7 и 8 (программное растягивание)
// 7. На DDS - генераторе видно форму выводимого сигнала, оптимизировал, сделал свои формы - ваще клевый стал...
// 8. Переделал меню генератора - вроде удобней стало.
// 9. В терминале можно выбирать стандартные скорости
// 10. Координально переделал некоторые куски кода, например - вывод меню....
// От smokok, //
// 11. Заменил терминал на меню контрастности и вкл. откл. подсветки с сохранением в EEPROM
// 12. Сломал перезагрузку кнопками + и - из за добавления EEPROM, но прошива очень шустрая однако!!!
// 13. Подсветка экрана на пине №8
// 14. Автоматическая развёртка включается с "Р" на "А"
// 15. Автоматическая синхронизация
// 15. Автоматическое автопределение делителя "5.0" "1.1"
// 16. В планах добавить ещё звуковое предупреждение при превышении 5v на щупе //
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <FreqCount.h>
#include <PWM.h>
#include <EEPROM.h>
//#include <CyberLib.h>
// ---- UserSpace ---- //
// Подключение дисплея
// (clk(scl, sck), din(sda, mosi), dc, ce (cs), rst)
#define Ekran 8 //Экран/////////////////////////////////Подсвет
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 4, 3, 2); // пины к которым подключен дисплей
// #define contrast 52 // контрастность дисплея////////////////////////////////////////
#define key_down 11 // кнопка минус (можно любой пин)
#define key_ok 12 // кнопка ОК (можно любой пин)
#define key_up 13 // кнопка плюс (можно любой пин)
#define akb A5 // любой свободный аналоговый пин для измерения напряжения АКБ
#define overclock 16 // частота на которой работает Ардуино
float VCC=5.0; // напряжение питания, меряем мультиметром
// ---- UserSpace_End ---- //
// A3 !! // пин подключиния входа осцилла (для отображения формы сигнала)
// D5 !! // пин подключиния входа осцилла (для аппаратного измерения частоты через таймер (в FreqCount.h))
#define led 9 // пин для генератора сигналов (не менять)
#define dds 10 // пин для генератора dds (не менять)
// ---- Глобальные переменные ---- //
byte contrast;
byte Set=0; ///////////////////////Экран/////////////////////////////////
bool BL; /////////////////////////Экран///////////////////////////////
bool avtorazv=0; // Автоматический выбор развертки
bool flag_key; // нужно для разных подключений кнопок
byte mode=0; // режим работы прибора
byte menu=0; // подменю
const char* const modeStr[] PROGMEM= { " Осциллоскоп ", "PWM-генератор", "DDS-генератор", "* * Экран * *"};
// ---- Переменые для осциллоскопа ---- //
#define BUFSIZE 700
byte adcBuf[BUFSIZE+1]; // буфер проебразований АЦП
int kdel=5; //bulat автопредел 1,1/5,0 вольта
byte syncLevel=0; // уровень синхронизации 0 до 255
byte razv=4; // развертка
bool pause=0; // флаг режима паузы
bool opornoe=1; // флаг опорного напряжения
int pauseOffset=0; // смещение графика в режиме паузы (прокрутка)
long count=0; // для подсчета частоты сигнала
// bool magnify=0; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// ---- Переменные для генератора ---- //
unsigned long stepFreq=0;
int PWM = 50; // стартовое значение ШИМ от 0 до 100 для генератора
unsigned long freq = 500; // стартовое значение частоты в Гц для генератора
void ShowMode(char m, char y) {
display.setCursor(3, y);
switch (m) {
case 0: display.print(modeStr[0]); break;
case 1: display.print(modeStr[1]); break;
case 2: display.print(modeStr[2]); break;
case 3: display.print(modeStr[3]); break;
}
}
void ShowModeInv(char y) {
display.setTextColor(WHITE, BLACK);
display.setCursor(0, y); display.println(" "); display.setCursor(77, y); display.println(" "); // для красоты только
ShowMode(mode, y);
display.setTextColor(BLACK);
}
// ==== Инициализация всего :) ==== //
void setup() {
delay(500); // ждем, пока питание устаканится (меньше глюков чтоб потом ловить)
////////////////////////////Экран//////////////////////////////
// Примечание. Экран становится темным, решение проблемы.///////////////////////////////////////
// EEPROM.write(0, 50); // Записать закрытую строку, Обновить и начать использовать.
contrast = EEPROM.read(0);
BL = EEPROM.read(1);
pinMode(Ekran, OUTPUT);
digitalWrite(Ekran, BL);
byte key_test=0;
digitalWrite(key_up, HIGH); digitalWrite(key_down, HIGH); digitalWrite(key_ok, HIGH);
if (digitalRead(key_up)) key_test++;
if (digitalRead(key_down)) key_test++;
if (digitalRead(key_ok)) key_test++;
if (key_test>1) {
flag_key=0;
}
else {
digitalWrite(key_up, LOW); digitalWrite(key_down, LOW); digitalWrite(key_ok, LOW);
flag_key=1;
}
display.begin();
display.setContrast(contrast);
while(flag_key-digitalRead(key_ok)) {
display.clearDisplay();
//////////////////////////////////////////////////////
// автодетект кнопок
byte key_test=0;
//pinMode(key_up, INPUT); pinMode(key_down, INPUT); pinMode(key_ok, INPUT);
// подтянули кнопки к питанию
digitalWrite(key_up, HIGH); digitalWrite(key_down, HIGH); digitalWrite(key_ok, HIGH);
// автодетект подключения кнопок при включении..
if (digitalRead(key_up)) key_test++; // если подтяжка к питанию осталась (не стоят резюки на массу) - плюсуем
if (digitalRead(key_down)) key_test++; // если подтяжка к питанию осталась (не стоят резюки на массу) - плюсуем
if (digitalRead(key_ok)) key_test++; // если подтяжка к питанию осталась (не стоят резюки на массу) - плюсуем
if (key_test>1) { // определили подключение кнопок на массу
flag_key=0;
}
else { // определили подключение кнопок на питание + резюки на массу
digitalWrite(key_up, LOW); digitalWrite(key_down, LOW); digitalWrite(key_ok, LOW); // убрали подтяжку
flag_key=1;
}
// если автодетект работает неверно (менюха скачет постоянно), то нужно расскомментировать одну из следующих строчек:
// flag_key = 0; // кнопки просто подключены к земле, резюков нету.
// flag_key = 1; // кнопки подключены к питанию и резюки на землю
while(flag_key-digitalRead(key_ok)) { // выводим меню, пока не выбран режим работы прибора
display.clearDisplay(); // чистим дисплей
// выводим главное меню
for (char i=0; i<4; i++) {
if (i==mode) ShowModeInv(i*10); else ShowMode(i, i*10);
}
// delay(50);
display.setTextColor(WHITE, BLACK);
display.setCursor(12,40); display.print(" Бат="); // выводим напряжение батареи
display.print(analogRead(akb)*VCC/1024);
display.print("v");
display.setTextColor(BLACK);
// перемещаемся по меню
if (flag_key-!digitalRead(key_up) ) { mode++; if (mode>3) mode=0; delay(100); }
if (flag_key-!digitalRead(key_down)) { mode--; if (mode == 0xFF) mode=3; delay(100); }
display.display(); // выводим все на экран
}
// выбран режим работы...
if (mode==0) FreqCount.begin(1000);
if (mode==1) { InitTimersSafe(); SetPinFrequencySafe(led, freq); }
if (mode==2) { InitTimersSafe(); SetPinFrequencySafe(led, 200000); }
delay(150);
}
}
// безконечный цикл - по сути прыгаем в подпрограммы
void loop() {
if (mode==0) Oscill(); // "выпадаем" в осцилл
if (mode==1) Generator(); // "выпадаем" в генератор
if (mode==2) DdsGenerator(); // "выпадаем" в DDS генератор
if (mode==3) Menu_ekrana(); // "выпадаем" в Menu Экрана
}
// читаем с АЦП данные и помещаем их в буфер...
void ReadAdc() {
if (razv) { // (razv>0) // если развертка без задержек всяких
ADCSRA = 0b11100000 | (8-razv); // установили делитель (/2 - не работает, так что начинаем с /4)
for(int i=0; i<BUFSIZE; i++) { // цикл для чтения
while ((ADCSRA & 0x10)==0); // ждем готовность АЦП
ADCSRA|=0x10; // запускаем следующее преобразование
adcBuf[i]=ADCH; // записываем данные в массив
}
} else { // развертка с задержками (delay)
ADCSRA = 0b11100111; // делитель на /128
for(int i=0; i<BUFSIZE; i++) { // цикл для чтения
while ((ADCSRA & 0x10)==0); // ждем готовность АЦП
ADCSRA|=0x10; // запускаем следующее преобразование
delayMicroseconds(500); // делаем задержку
adcBuf[i]=ADCH; // записываем данные в массив
}
}
}
//////////////////////////////// РЕЖИМ ОСЦИЛЛОСКОПА//////////////////////////////
void Oscill() {
if(opornoe) ADMUX = 0b01100011; // выбор внешнего опорного
else ADMUX = 0b11100011; // выбор внутреннего опорного 1,1В
label_ReadAdc:
delay(100);
if(!pause) ReadAdc(); // если паузы нет, то считываем сигнал в буфер
// определение точки синхронизации
bool flagSync=0; // флаг, когда сигнал ниже уровня синхронизации
int syncOffset=0; // смещение для вывода с синхронизацией
// считаем смещение графика по уровню синхронизации
for(int y=0; y<BUFSIZE-80; y++) {
if(adcBuf[y]<syncLevel) flagSync=1;
if(flagSync && adcBuf[y]>syncLevel) { syncOffset = y; break; }
}
// считаем максимальное и минимальное значение сигнала (для вывода на экран)
byte Vmax=0, Vmin=255; // тут будем хранить максимальное и минимальное напряжение
for(int y=0; y<BUFSIZE; y++) { if(Vmin>adcBuf[y]) Vmin=adcBuf[y]; if(Vmax<adcBuf[y]) Vmax=adcBuf[y]; }
syncLevel = (Vmax-Vmin) / 2 + Vmin; // /////////////// Авто синхронизация
//bulat если зашкаливает включаем предел 5 в
if (Vmax==255){
if (opornoe==0)
{
opornoe=1;
ADMUX = 0b01100011;// выбор внутреннего опорного 5.0 В
goto label_ReadAdc;
}
}
//bulat если 5 в и уровень менее 1,1 в то вкл предел 1,1 в
if (Vmax<=55){
if (opornoe==1)
{
opornoe=0;
ADMUX = 0b11100011;// выбор внутреннего опорного 1,1В
goto label_ReadAdc;
}
}
//bulat здесь автопредел 1,1/0,22 в,программный
/* kdel=5;
if (Vmax<=55){
if (opornoe==0)
{
kdel=1;
}
}*/
// отрисовка графика
display.clearDisplay(); // чистим дисплей
byte x=2; // задаем смещение графика немного вправо
if(pause) { // если в режиме паузы, то рисуем с прокруткой...
display.drawLine(pauseOffset/0,8,84,8, BLACK); //линия прокрутки
display.drawLine(pauseOffset/8,9,pauseOffset/8+6,9, BLACK); //шкала прокрутки
display.drawLine(pauseOffset/8,10,pauseOffset/8+6,10, BLACK); //шкала прокрутки
for(int y=pauseOffset; y<pauseOffset+80; y++) { // рисуем форму сигнала
display.drawLine(++x, 47-adcBuf[y]/7, x, 47-adcBuf[y+1]/7, BLACK); //линия сигнала/////////
//display.drawLine(x+1, 47-adcBuf[y]/7+1, x+2, 47-adcBuf[y+1]/7+1, BLACK); //раскоментить то будет толще линия сигнала/////////
}
}
else {// если паузы нет, то рисуем немного по другому))..
for(int y=syncOffset; y<syncOffset+80; y++) { // рисуем форму сигнала
display.drawLine(++x, 47-adcBuf[y]/7, x, 47-adcBuf[y+1]/7, BLACK); //линия сигнала/////////
//display.drawLine(x+1, 47-adcBuf[y]/7+2, x+1, 47-adcBuf[y+1]/7+1, BLACK); //раскоментить то будет толще линия сигнала/////////
}
syncOffset=0;
}
// отрисовка сетки
for(byte i=47;i>5;i-=7) { display.drawPixel(0, i, BLACK); display.drawPixel(1, i, BLACK); display.drawPixel(2, i, BLACK); display.drawPixel(3, i, BLACK); }
// сетка
for(byte i=46;i>5;i-=3) { display.drawPixel(24,i, BLACK); display.drawPixel(42,i, BLACK); display.drawPixel(60,i, BLACK); }
for(byte i=3;i<84;i+=3) { display.drawPixel(i,34, BLACK); display.drawPixel(i,19, BLACK); }
///////////////авто razv
if (avtorazv)
#define PER 1.3
if (count > 3823.3*PER) razv = 6; else
if (count > 1934.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;
////////////////
// отрисовка menu
display.setCursor(0,0);
if (menu==0) {
if(opornoe)
{
display.print(VCC,1);
}
else
{
if(kdel==5)display.print("1.1");//else display.print("0.2");
}
if(flag_key-!digitalRead(key_down)) { razv--; if(razv==255) razv=6; }
if(flag_key-!digitalRead(key_up) ) { razv++; if(razv==7) razv=0; }
else display.setTextColor(WHITE, BLACK);
display.print(" "); display.print(razv);
display.setTextColor(BLACK);
if(flag_key-!digitalRead(key_down) || flag_key-!digitalRead(key_up));
}
if (menu==1) {
if(opornoe)
{
display.print(VCC,1);
}
else
{
if(kdel==5)display.print("1.1");//else display.print("0.2");
}
if(flag_key-!digitalRead(key_down) || flag_key-!digitalRead(key_up)) avtorazv = !avtorazv;
else display.setTextColor(WHITE, BLACK);
display.print(" "); display.print(avtorazv?'A':'P');
display.setTextColor(BLACK);
}
if (menu==2) {
pause=1;
if(flag_key-!digitalRead(key_down)) { pauseOffset-=27; if(pauseOffset<0) pauseOffset=0; }
if(flag_key-!digitalRead(key_up) ) { pauseOffset+=27; if(pauseOffset>(BUFSIZE-84)) pauseOffset=BUFSIZE-84; }
else display.setTextColor(WHITE, BLACK);
display.print(" П~");
display.setTextColor(BLACK);
}
if (flag_key-!digitalRead(key_ok)) { menu++; if(menu==3) { menu=0; pause=0; }}
// забираем частоту сигнала, полученную аппаратно (через таймер)
if (FreqCount.available()) count = FreqCount.read(); // забираем по готовности счетчика
// считаем программно частоту сигнала
byte Freq1=0;
long Freq=0;
bool flagFreq1=0, flagFreq2=0, flagFreq3=0;
for(int y=1; y<255; y++) {
if(!flagFreq1 && adcBuf[y]<syncLevel) flagFreq2=1; // тут можно че то оптимизировать, тока не могу понять, что [El83]
if(!flagFreq1 && flagFreq2 && adcBuf[y]>syncLevel) { flagFreq1=1; Freq1=y; }
if( flagFreq1 && adcBuf[y]<syncLevel) flagFreq3=1;
if( flagFreq3 && adcBuf[y]>syncLevel) {
switch (razv) { // тут позже оптимизирую! ////////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11
case 6: Freq=1000000/((y-Freq1-1)*3.27); break; // делитель 4
case 5: Freq=1000000/((y-Freq1)*3.27)/2; break; // делитель 8
case 4: Freq=1000000/((y-Freq1)*3.27)/4; break; // делитель 16
case 3: Freq=1000000/((y-Freq1)*3.27)/8; break; // делитель 32
case 2: Freq=1000000/((y-Freq1)*3.27)/16; break; // делитель 64
case 1: Freq=1000000/((y-Freq1)*3.27)/32; break; // делитель 128
case 0: Freq=1000000/((y-Freq1)*500); break; // делитель 128
}
flagFreq1=0; flagFreq3=0;
}
}
// отрисовка частоты сигнала
if (opornoe && ((Vmax*VCC/255)>2.5)) count=count*(overclock/16.0);
else count=Freq *(overclock/16.0);
if (Vmax*VCC/255<0.29) count = 0;
if (count<1000) { display.print(" "); display.print(count); display.print("Hz"); }
else { display.print(" "); display.print(count/1000.0,3); display.print("Kz"); }
display.setTextColor(WHITE, BLACK);
if(opornoe && ((Vmax*VCC/255)>2.5)) display.print('*'); // если меряем частоту аппаратно, рисуем звездочку
display.setTextColor(BLACK);
// отрисовка максимального напряжения сигнала
display.setCursor(0,40);
if (opornoe) display.print(Vmax*VCC/255,2); else display.print(Vmax*1.1/255,2);
// display.print("v");
// delay(150);
display.display(); // вываливаем все на экран
}
//////////////////////////////// РЕЖИМ ГЕНЕРАТОРА//////////////////////////////
void Generator() {
// обработка кнопок и отрисовка одновременно
display.clearDisplay();
ShowModeInv(0);
if(flag_key-!digitalRead(key_ok)) { if(menu++==7) menu=0; delay(200); } // переходим по разрядам / меняем ШИМ
if (menu==7) { // меняем ШИМ
if(flag_key-!digitalRead(key_down)) { PWM--; if(PWM<0) PWM=100; delay(200); }
if(flag_key-!digitalRead(key_up)) { PWM++; if(PWM>100) PWM=0; delay(200); }
pwmWrite(led, PWM*2.55); // задали ШИМ
display.setTextColor(WHITE, BLACK); // если меняем шим, то рисуем его инверсным
display.drawLine(15, 39, 68+(PWM==100?6:0)+(PWM<10?-6:0), 39, BLACK); // сверху полоска для большей инверсности
} else { // меняем частоту
if(flag_key-!digitalRead(key_down)) {
if (freq>stepFreq) freq-=stepFreq; // не даем выйти за допустимый диаппазон
SetPinFrequencySafe(led, freq/(overclock/16.0)); // задали частоту
delay(150); // задержка для кнопок
}
if(flag_key-!digitalRead(key_up)) {
if ((freq+stepFreq)<10000000) freq+=stepFreq; // не даем выйти за допустимый диаппазон
SetPinFrequencySafe(led, freq/(overclock/16.0)); // задали частоту
delay(150); // задержка для кнопок
}
display.setTextColor(BLACK); // если ШИМ не меняем, то выбираем обычный текст
#define XFREQ 12 // ======== // и, выделяем декаду частоты полосочками
stepFreq=pow(10, (byte)menu); if (menu>1) stepFreq++; // устраняем глючность pow, почему 10 в степени 2 = 99?
byte menu_t = menu; if (menu>2) menu_t++; if (menu==6) menu_t++; // делаем табуляцию частоты
menu_t = 54 - menu_t * 6; // считаем положение полосочек
display.drawLine(menu_t, XFREQ-2, menu_t+4, XFREQ-2, BLACK); // рисуем полоски
display.drawLine(menu_t, XFREQ-3, menu_t+4, XFREQ-3, BLACK);
display.drawLine(menu_t, XFREQ+8, menu_t+4, XFREQ+8, BLACK);
display.drawLine(menu_t, XFREQ+9, menu_t+4, XFREQ+9, BLACK);
}
// рисуем уровень ШИМ (инверсия текста задана ранее)
display.setCursor(15, 40); // ставим курсор))
display.print(" PWM="); display.print(PWM); display.print("% "); // выводим уровень ШИМ
display.setTextColor(BLACK); // убираем инверсию при выводе частоты
// рисуем частоту с табуляцией
display.setCursor(6, XFREQ);
for (unsigned long freq_t = 1000000; freq_t>0; freq_t/=10) {
if (freq>=freq_t) {
display.print((freq/freq_t)%10); if (freq_t==1000000 || freq_t==1000) display.print("'"); } else {
display.print("_"); if (freq_t==1000000 || freq_t==1000) display.print(" "); }
}
display.print(" Hz");
// отрисовка графика PWM
for (char x=17; x<67; ) {
if (PWM!=0) display.drawLine(x, 25, x+PWM/4, 25, BLACK); x+=PWM/4; // верх
if (PWM!=0 && PWM!=100) display.drawLine(x, 25, x, 36, BLACK); // спад
if (PWM!=100) display.drawLine(x, 36, x+25-PWM/4, 36, BLACK); x+=25-PWM/4; // низ
if (PWM!=0 && PWM!=100 && x<43) display.drawLine( x, 36, x, 25, BLACK); // подъем
}
display.display(); // вываливаем буфер на дисплей
}
//////////////////////////////// DDS генератор//////////////////////////////
void DdsGenerator() {
static const byte ddsWave[][32] PROGMEM = {
1,6,15,29,48,69,92,117,143,168,191,212,229,243,251,255,254,248,237,222,203,181,156,131,106,81,59,39,22,10,3,1, // El83_sinNew
1,18,35,52,69,86,103,120,137,154,171,188,205,222,239,255,239,223,207,191,175,159,143,127,111,95,79,63,47,31,15,1, // El83_treugNew
1,9,17,25,33,41,49,57,65,73,81,89,97,105,113,121,129,137,145,153,161,169,177,185,193,201,209,217,225,235,245,255, // El83_pilaNew
250,246,238,230,222,214,206,198,190,182,174,166,158,150,142,134,126,118,110,102,94,86,78,70,62,54,41,33,25,17,9,1 }; // El83_pilaObrNew
const char* const ddsStr[] PROGMEM = { " Синус", " Треугольник", " Пила", "Обратная пила"};
byte ddsCount=0;
// Рисуем DDS-генератор
display.clearDisplay();
ShowModeInv(0);
for (byte i=0; i<84;) display.drawLine(i, 37-pgm_read_byte(&ddsWave[menu][i%32])/9, i, 37-pgm_read_byte(&ddsWave[menu][(i++)%32])/9, BLACK);
display.setCursor(3, 40); display.print(ddsStr[menu]); display.display(); // отрисовали все
// выводим выбранный сигнал, пока не нажали кнопку
while(flag_key-digitalRead(key_up) && flag_key-digitalRead(key_down) && flag_key-digitalRead(key_ok)) {
pwmWrite(dds, pgm_read_byte(&ddsWave[menu][(ddsCount++)&0x1F]));
}
if (++menu==4) menu = 0; // нажали кнопку - переключаем режим
delay(150); // чтоб кнопки нормально нажимались
}
//////////////////////////////Экран/////////////////////////////////
void Menu_ekrana() {
Set=0;delay(200);
while (flag_key-digitalRead(key_ok)){
display.clearDisplay();
if (Set == 0) display.setTextColor(WHITE, BLACK); else display.setTextColor(BLACK);
display.setCursor(0 , 0); display.println("Контраст:"); display.setTextColor(BLACK);
display.setCursor(60 , 0); display.println(contrast);
display.setCursor(0 , 10); display.println("Подсветк:"); display.setTextColor(BLACK);
if (BL == 1) { display.setCursor(60 , 10); display.println("Вкл");} else
{ display.setCursor(60 , 10); display.println("Отк");} display.display();
if (flag_key-!digitalRead(key_up)) contrast++;
if (flag_key-!digitalRead(key_down)) contrast--;
if (contrast<30) contrast=30;
if (contrast>70) contrast=70;
display.setContrast(contrast);
delay(150);
}
Set=1; delay(200);
while (flag_key-digitalRead(key_ok)){
display.clearDisplay();
display.setCursor(0 , 0); display.println("Контраст:");
display.setCursor(60 , 0); display.println(contrast);
if (Set == 1) display.setTextColor(WHITE, BLACK); else display.setTextColor(BLACK);
display.setCursor(0 , 10); display.println("Подсветк:"); display.setTextColor(BLACK);
if (BL == 1) { display.setCursor(60 , 10); display.println("Вкл"); digitalWrite(Ekran, BL); } else
{ display.setCursor(60 , 10); display.println("Отк"); digitalWrite(Ekran, BL); }
if (flag_key-!digitalRead(key_up)) BL=1;
if (flag_key-!digitalRead(key_down)) BL=0;
display.display();
delay(150);
}
display.display();
display.clearDisplay();
EEPROM.write(0, contrast);
EEPROM.write(1, BL);
setup();
}
Включение и регулировка через пункт в меню. Говорят что этот скетч не огого, но меня вполне устраивает. Я чтото менял в нём для себя, уже не помню что.
А в этом скетче Автоматическое автопределение делителя "5.0" "1.1" "0.22"
//Страница проэкта <a href="<a href="http://srukami.inf.ua/pultoscop_v25110.html" rel="nofollow">http://srukami.inf.ua/pultoscop_v25110.html</a>" rel="nofollow"><a href="http://srukami.inf.ua/pultoscop_v25110.html" rel="nofollow">http://srukami.inf.ua/pultoscop_v25110.html</a></a>
// ---------------------------------------------------------------
// От Electronik83 (mailto: <a href="mailto:gsmkillersevsk@mail.ru">gsmkillersevsk@mail.ru</a>): ver 17032017
// 1. В режиме генератора PWM в процентах в целых числах (без дробей), нарисовал график сигнала PWM
// 2. В генераторе пофиксил/оптимизировал вывод частоты (1000 герц не показывало)
// 3. Автоматическое определение схемы подключения кнопок (при включении лучше ничего не нажимать:) :
// a). Как у автора - кнопки к питанию и резюки на массу
// b). Как я хочу - кнопки к земле и без всяких резюков
// 4. Отправил вэйвы для DDS генератора во флэш - оперативы больше стало свободной
// 5. Реализовал перезапуск при зажатии кнопок "+" и "-" (из осцилла не работает (не знаю, как исправить!))
// 6. Убрал развертки 7 и 8 (программное растягивание)
// 7. На DDS - генераторе видно форму выводимого сигнала, оптимизировал, сделал свои формы - ваще клевый стал...
// 8. Переделал меню генератора - вроде удобней стало.
// 9. В терминале можно выбирать стандартные скорости
// 10. Координально переделал некоторые куски кода, например - вывод меню....
// От smokok, //
// 11. Заменил терминал на меню контрастности и вкл. откл. подсветки с сохранением в EEPROM
// 12. Сломал перезагрузку кнопками + и - из за добавления EEPROM, но прошива очень шустрая однако!!!
// 13. Подсветка экрана на пине №8
// 14. Автоматическая развёртка включается с "Р" на "А"
// 15. Автоматическая синхронизация
// 15. Автоматическое автопределение делителя "5.0" "1.1" "0.22"
// 16. В планах добавить ещё звуковое предупреждение при превышении 5v на щупе //
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <FreqCount.h>
#include <PWM.h>
#include <EEPROM.h>
//#include <CyberLib.h>
// ---- UserSpace ---- //
// Подключение дисплея
// (clk(scl, sck), din(sda, mosi), dc, ce (cs), rst)
#define Ekran 8 //Экран/////////////////////////////////Подсвет
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 4, 3, 2); // пины к которым подключен дисплей
// #define contrast 52 // контрастность дисплея////////////////////////////////////////
#define key_down 11 // кнопка минус (можно любой пин)
#define key_ok 12 // кнопка ОК (можно любой пин)
#define key_up 13 // кнопка плюс (можно любой пин)
#define akb A5 // любой свободный аналоговый пин для измерения напряжения АКБ
#define overclock 16 // частота на которой работает Ардуино
float VCC=5.0; // напряжение питания, меряем мультиметром
// ---- UserSpace_End ---- //
// A3 !! // пин подключиния входа осцилла (для отображения формы сигнала)
// D5 !! // пин подключиния входа осцилла (для аппаратного измерения частоты через таймер (в FreqCount.h))
#define led 9 // пин для генератора сигналов (не менять)
#define dds 10 // пин для генератора dds (не менять)
// ---- Глобальные переменные ---- //
byte contrast;
byte Set=0; ///////////////////////Экран/////////////////////////////////
bool BL; /////////////////////////Экран///////////////////////////////
bool avtorazv=0; // Автоматический выбор развертки
bool flag_key; // нужно для разных подключений кнопок
byte mode=0; // режим работы прибора
byte menu=0; // подменю
const char* const modeStr[] PROGMEM= { " Осциллоскоп ", "PWM-генератор", "DDS-генератор", "* * Экран * *"};
// ---- Переменые для осциллоскопа ---- //
#define BUFSIZE 700
byte adcBuf[BUFSIZE+1]; // буфер проебразований АЦП
int kdel=5; //bulat автопредел 1,1/0,2 вольта
byte syncLevel=0; // уровень синхронизации 0 до 255
byte razv=4; // развертка
bool pause=0; // флаг режима паузы
bool opornoe=1; // флаг опорного напряжения
int pauseOffset=0; // смещение графика в режиме паузы (прокрутка)
long count=0; // для подсчета частоты сигнала
// bool magnify=0; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// ---- Переменные для генератора ---- //
unsigned long stepFreq=0;
int PWM = 50; // стартовое значение ШИМ от 0 до 100 для генератора
unsigned long freq = 500; // стартовое значение частоты в Гц для генератора
void ShowMode(char m, char y) {
display.setCursor(3, y);
switch (m) {
case 0: display.print(modeStr[0]); break;
case 1: display.print(modeStr[1]); break;
case 2: display.print(modeStr[2]); break;
case 3: display.print(modeStr[3]); break;
}
}
void ShowModeInv(char y) {
display.setTextColor(WHITE, BLACK);
display.setCursor(0, y); display.println(" "); display.setCursor(77, y); display.println(" "); // для красоты только
ShowMode(mode, y);
display.setTextColor(BLACK);
}
// ==== Инициализация всего :) ==== //
void setup() {
delay(500); // ждем, пока питание устаканится (меньше глюков чтоб потом ловить)
////////////////////////////Экран//////////////////////////////
// Примечание. Экран становится темным, решение проблемы.///////////////////////////////////////
// EEPROM.write(0, 50); // Записать закрытую строку, Обновить и начать использовать.
contrast = EEPROM.read(0);
BL = EEPROM.read(1);
pinMode(Ekran, OUTPUT);
digitalWrite(Ekran, BL);
byte key_test=0;
digitalWrite(key_up, HIGH); digitalWrite(key_down, HIGH); digitalWrite(key_ok, HIGH);
if (digitalRead(key_up)) key_test++;
if (digitalRead(key_down)) key_test++;
if (digitalRead(key_ok)) key_test++;
if (key_test>1) {
flag_key=0;
}
else {
digitalWrite(key_up, LOW); digitalWrite(key_down, LOW); digitalWrite(key_ok, LOW);
flag_key=1;
}
display.begin();
display.setContrast(contrast);
while(flag_key-digitalRead(key_ok)) {
display.clearDisplay();
//////////////////////////////////////////////////////
// автодетект кнопок
byte key_test=0;
//pinMode(key_up, INPUT); pinMode(key_down, INPUT); pinMode(key_ok, INPUT);
// подтянули кнопки к питанию
digitalWrite(key_up, HIGH); digitalWrite(key_down, HIGH); digitalWrite(key_ok, HIGH);
// автодетект подключения кнопок при включении..
if (digitalRead(key_up)) key_test++; // если подтяжка к питанию осталась (не стоят резюки на массу) - плюсуем
if (digitalRead(key_down)) key_test++; // если подтяжка к питанию осталась (не стоят резюки на массу) - плюсуем
if (digitalRead(key_ok)) key_test++; // если подтяжка к питанию осталась (не стоят резюки на массу) - плюсуем
if (key_test>1) { // определили подключение кнопок на массу
flag_key=0;
}
else { // определили подключение кнопок на питание + резюки на массу
digitalWrite(key_up, LOW); digitalWrite(key_down, LOW); digitalWrite(key_ok, LOW); // убрали подтяжку
flag_key=1;
}
// если автодетект работает неверно (менюха скачет постоянно), то нужно расскомментировать одну из следующих строчек:
// flag_key = 0; // кнопки просто подключены к земле, резюков нету.
// flag_key = 1; // кнопки подключены к питанию и резюки на землю
while(flag_key-digitalRead(key_ok)) { // выводим меню, пока не выбран режим работы прибора
display.clearDisplay(); // чистим дисплей
// выводим главное меню
for (char i=0; i<4; i++) {
if (i==mode) ShowModeInv(i*10); else ShowMode(i, i*10);
}
// delay(50);
display.setTextColor(WHITE, BLACK);
display.setCursor(12,40); display.print(" Бат="); // выводим напряжение батареи
display.print(analogRead(akb)*VCC/1024);
display.print("v");
display.setTextColor(BLACK);
// перемещаемся по меню
if (flag_key-!digitalRead(key_up) ) { mode++; if (mode>3) mode=0; delay(100); }
if (flag_key-!digitalRead(key_down)) { mode--; if (mode == 0xFF) mode=3; delay(100); }
display.display(); // выводим все на экран
}
// выбран режим работы...
if (mode==0) FreqCount.begin(1000);
if (mode==1) { InitTimersSafe(); SetPinFrequencySafe(led, freq); }
if (mode==2) { InitTimersSafe(); SetPinFrequencySafe(led, 200000); }
delay(150);
}
}
// безконечный цикл - по сути прыгаем в подпрограммы
void loop() {
if (mode==0) Oscill(); // "выпадаем" в осцилл
if (mode==1) Generator(); // "выпадаем" в генератор
if (mode==2) DdsGenerator(); // "выпадаем" в DDS генератор
if (mode==3) Menu_ekrana(); // "выпадаем" в Menu Экрана
}
// читаем с АЦП данные и помещаем их в буфер...
void ReadAdc() {
if (razv) { // (razv>0) // если развертка без задержек всяких
ADCSRA = 0b11100000 | (8-razv); // установили делитель (/2 - не работает, так что начинаем с /4)
for(int i=0; i<BUFSIZE; i++) { // цикл для чтения
while ((ADCSRA & 0x10)==0); // ждем готовность АЦП
ADCSRA|=0x10; // запускаем следующее преобразование
adcBuf[i]=ADCH; // записываем данные в массив
}
} else { // развертка с задержками (delay)
ADCSRA = 0b11100111; // делитель на /128
for(int i=0; i<BUFSIZE; i++) { // цикл для чтения
while ((ADCSRA & 0x10)==0); // ждем готовность АЦП
ADCSRA|=0x10; // запускаем следующее преобразование
delayMicroseconds(500); // делаем задержку
adcBuf[i]=ADCH; // записываем данные в массив
}
}
}
//////////////////////////////// РЕЖИМ ОСЦИЛЛОСКОПА//////////////////////////////
void Oscill() {
if(opornoe) ADMUX = 0b01100011; // выбор внешнего опорного
else ADMUX = 0b11100011; // выбор внутреннего опорного 1,1В
label_ReadAdc:
delay(100);
if(!pause) ReadAdc(); // если паузы нет, то считываем сигнал в буфер
// определение точки синхронизации
bool flagSync=0; // флаг, когда сигнал ниже уровня синхронизации
int syncOffset=0; // смещение для вывода с синхронизацией
// считаем смещение графика по уровню синхронизации
for(int y=0; y<BUFSIZE-80; y++) {
if(adcBuf[y]<syncLevel) flagSync=1;
if(flagSync && adcBuf[y]>syncLevel) { syncOffset = y; break; }
}
// считаем максимальное и минимальное значение сигнала (для вывода на экран)
byte Vmax=0, Vmin=255; // тут будем хранить максимальное и минимальное напряжение
for(int y=0; y<BUFSIZE; y++) { if(Vmin>adcBuf[y]) Vmin=adcBuf[y]; if(Vmax<adcBuf[y]) Vmax=adcBuf[y]; }
syncLevel = (Vmax-Vmin) / 2 + Vmin; // /////////////// Авто синхронизация
//bulat если зашкаливает включаем предел 5 в
if (Vmax==255){
if (opornoe==0)
{
opornoe=1;
ADMUX = 0b01100011;// выбор внутреннего опорного 5.0 В
goto label_ReadAdc;
}
}
//bulat если 5 в и уровень менее 1,1 в то вкл предел 1,1 в
if (Vmax<=55){
if (opornoe==1)
{
opornoe=0;
ADMUX = 0b11100011;// выбор внутреннего опорного 1,1В
goto label_ReadAdc;
}
}
//bulat здесь автопредел 1,1/0,22 в,программный
kdel=5;
if (Vmax<=55){
if (opornoe==0)
{
kdel=1;
}
}
// отрисовка графика
display.clearDisplay(); // чистим дисплей
byte x=2; // задаем смещение графика немного вправо
if(pause) { // если в режиме паузы, то рисуем с прокруткой...
display.drawLine(pauseOffset/0,8,84,8, BLACK); //линия прокрутки
display.drawLine(pauseOffset/8,9,pauseOffset/8+6,9, BLACK); //шкала прокрутки
display.drawLine(pauseOffset/8,10,pauseOffset/8+6,10, BLACK); //шкала прокрутки
for(int y=pauseOffset; y<pauseOffset+80; y++) { // рисуем форму сигнала
display.drawLine(++x, 47-adcBuf[y]/kdel, x, 47-adcBuf[y+1]/kdel, BLACK); //линия сигнала/////////
//display.drawLine(x+1, 47-adcBuf[y]/7+1, x+2, 47-adcBuf[y+1]/7+1, BLACK); //раскоментить то будет толще линия сигнала/////////
}
}
else {// если паузы нет, то рисуем немного по другому))..
for(int y=syncOffset; y<syncOffset+80; y++) { // рисуем форму сигнала
display.drawLine(++x, 47-adcBuf[y]/kdel, x, 47-adcBuf[y+1]/kdel, BLACK); //линия сигнала/////////
//display.drawLine(x+1, 47-adcBuf[y]/7+2, x+1, 47-adcBuf[y+1]/7+1, BLACK); //раскоментить то будет толще линия сигнала/////////
}
syncOffset=0;
}
// отрисовка сетки
for(byte i=47;i>5;i-=7) { display.drawPixel(0, i, BLACK); display.drawPixel(1, i, BLACK); display.drawPixel(2, i, BLACK); display.drawPixel(3, i, BLACK); }
// сетка
for(byte i=46;i>5;i-=3) { display.drawPixel(24,i, BLACK); display.drawPixel(42,i, BLACK); display.drawPixel(60,i, BLACK); }
for(byte i=3;i<84;i+=3) { display.drawPixel(i,34, BLACK); display.drawPixel(i,19, BLACK); }
///////////////авто razv
if (avtorazv)
#define PER 1.3
if (count > 3823.3*PER) razv = 6; else
if (count > 1934.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;
////////////////
// отрисовка menu
display.setCursor(0,0);
if (menu==0) {
if(opornoe)
{
display.print(VCC,1);
}
else
{
if(kdel==5)display.print("1.1"); else display.print("0.2");
}
if(flag_key-!digitalRead(key_down)) { razv--; if(razv==255) razv=6; }
if(flag_key-!digitalRead(key_up) ) { razv++; if(razv==7) razv=0; }
else display.setTextColor(WHITE, BLACK);
display.print(" "); display.print(razv);
display.setTextColor(BLACK);
if(flag_key-!digitalRead(key_down) || flag_key-!digitalRead(key_up));
}
if (menu==1) {
if(opornoe)
{
display.print(VCC,1);
}
else
{
if(kdel==5)display.print("1.1"); else display.print("0.2");
}
if(flag_key-!digitalRead(key_down) || flag_key-!digitalRead(key_up)) avtorazv = !avtorazv;
else display.setTextColor(WHITE, BLACK);
display.print(" "); display.print(avtorazv?'A':'P');
display.setTextColor(BLACK);
}
if (menu==2) {
pause=1;
if(flag_key-!digitalRead(key_down)) { pauseOffset-=27; if(pauseOffset<0) pauseOffset=0; }
if(flag_key-!digitalRead(key_up) ) { pauseOffset+=27; if(pauseOffset>(BUFSIZE-84)) pauseOffset=BUFSIZE-84; }
else display.setTextColor(WHITE, BLACK);
display.print(" П~");
display.setTextColor(BLACK);
}
if (flag_key-!digitalRead(key_ok)) { menu++; if(menu==3) { menu=0; pause=0; }}
// забираем частоту сигнала, полученную аппаратно (через таймер)
if (FreqCount.available()) count = FreqCount.read(); // забираем по готовности счетчика
// считаем программно частоту сигнала
byte Freq1=0;
long Freq=0;
bool flagFreq1=0, flagFreq2=0, flagFreq3=0;
for(int y=1; y<255; y++) {
if(!flagFreq1 && adcBuf[y]<syncLevel) flagFreq2=1; // тут можно че то оптимизировать, тока не могу понять, что [El83]
if(!flagFreq1 && flagFreq2 && adcBuf[y]>syncLevel) { flagFreq1=1; Freq1=y; }
if( flagFreq1 && adcBuf[y]<syncLevel) flagFreq3=1;
if( flagFreq3 && adcBuf[y]>syncLevel) {
switch (razv) { // тут позже оптимизирую! ////////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11
case 6: Freq=1000000/((y-Freq1-1)*3.27); break; // делитель 4
case 5: Freq=1000000/((y-Freq1)*3.27)/2; break; // делитель 8
case 4: Freq=1000000/((y-Freq1)*3.27)/4; break; // делитель 16
case 3: Freq=1000000/((y-Freq1)*3.27)/8; break; // делитель 32
case 2: Freq=1000000/((y-Freq1)*3.27)/16; break; // делитель 64
case 1: Freq=1000000/((y-Freq1)*3.27)/32; break; // делитель 128
case 0: Freq=1000000/((y-Freq1)*500); break; // делитель 128
}
flagFreq1=0; flagFreq3=0;
}
}
// отрисовка частоты сигнала
if (opornoe && ((Vmax*VCC/255)>2.5)) count=count*(overclock/16.0);
else count=Freq *(overclock/16.0);
if (Vmax*VCC/255<0.29) count = 0;
if (count<1000) { display.print(" "); display.print(count); display.print("Hz"); }
else { display.print(" "); display.print(count/1000.0,3); display.print("Kz"); }
display.setTextColor(WHITE, BLACK);
if(opornoe && ((Vmax*VCC/255)>2.5)) display.print('*'); // если меряем частоту аппаратно, рисуем звездочку
display.setTextColor(BLACK);
// отрисовка максимального напряжения сигнала
display.setCursor(0,40);
if (opornoe) display.print(Vmax*VCC/255,2); else display.print(Vmax*1.1/255,2);
// display.print("v");
// delay(150);
display.display(); // вываливаем все на экран
}
//////////////////////////////// РЕЖИМ ГЕНЕРАТОРА//////////////////////////////
void Generator() {
// обработка кнопок и отрисовка одновременно
display.clearDisplay();
ShowModeInv(0);
if(flag_key-!digitalRead(key_ok)) { if(menu++==7) menu=0; delay(200); } // переходим по разрядам / меняем ШИМ
if (menu==7) { // меняем ШИМ
if(flag_key-!digitalRead(key_down)) { PWM--; if(PWM<0) PWM=100; delay(200); }
if(flag_key-!digitalRead(key_up)) { PWM++; if(PWM>100) PWM=0; delay(200); }
pwmWrite(led, PWM*2.55); // задали ШИМ
display.setTextColor(WHITE, BLACK); // если меняем шим, то рисуем его инверсным
display.drawLine(15, 39, 68+(PWM==100?6:0)+(PWM<10?-6:0), 39, BLACK); // сверху полоска для большей инверсности
} else { // меняем частоту
if(flag_key-!digitalRead(key_down)) {
if (freq>stepFreq) freq-=stepFreq; // не даем выйти за допустимый диаппазон
SetPinFrequencySafe(led, freq/(overclock/16.0)); // задали частоту
delay(150); // задержка для кнопок
}
if(flag_key-!digitalRead(key_up)) {
if ((freq+stepFreq)<10000000) freq+=stepFreq; // не даем выйти за допустимый диаппазон
SetPinFrequencySafe(led, freq/(overclock/16.0)); // задали частоту
delay(150); // задержка для кнопок
}
display.setTextColor(BLACK); // если ШИМ не меняем, то выбираем обычный текст
#define XFREQ 12 // ======== // и, выделяем декаду частоты полосочками
stepFreq=pow(10, (byte)menu); if (menu>1) stepFreq++; // устраняем глючность pow, почему 10 в степени 2 = 99?
byte menu_t = menu; if (menu>2) menu_t++; if (menu==6) menu_t++; // делаем табуляцию частоты
menu_t = 54 - menu_t * 6; // считаем положение полосочек
display.drawLine(menu_t, XFREQ-2, menu_t+4, XFREQ-2, BLACK); // рисуем полоски
display.drawLine(menu_t, XFREQ-3, menu_t+4, XFREQ-3, BLACK);
display.drawLine(menu_t, XFREQ+8, menu_t+4, XFREQ+8, BLACK);
display.drawLine(menu_t, XFREQ+9, menu_t+4, XFREQ+9, BLACK);
}
// рисуем уровень ШИМ (инверсия текста задана ранее)
display.setCursor(15, 40); // ставим курсор))
display.print(" PWM="); display.print(PWM); display.print("% "); // выводим уровень ШИМ
display.setTextColor(BLACK); // убираем инверсию при выводе частоты
// рисуем частоту с табуляцией
display.setCursor(6, XFREQ);
for (unsigned long freq_t = 1000000; freq_t>0; freq_t/=10) {
if (freq>=freq_t) {
display.print((freq/freq_t)%10); if (freq_t==1000000 || freq_t==1000) display.print("'"); } else {
display.print("_"); if (freq_t==1000000 || freq_t==1000) display.print(" "); }
}
display.print(" Hz");
// отрисовка графика PWM
for (char x=17; x<67; ) {
if (PWM!=0) display.drawLine(x, 25, x+PWM/4, 25, BLACK); x+=PWM/4; // верх
if (PWM!=0 && PWM!=100) display.drawLine(x, 25, x, 36, BLACK); // спад
if (PWM!=100) display.drawLine(x, 36, x+25-PWM/4, 36, BLACK); x+=25-PWM/4; // низ
if (PWM!=0 && PWM!=100 && x<43) display.drawLine( x, 36, x, 25, BLACK); // подъем
}
display.display(); // вываливаем буфер на дисплей
}
//////////////////////////////// DDS генератор//////////////////////////////
void DdsGenerator() {
static const byte ddsWave[][32] PROGMEM = {
1,6,15,29,48,69,92,117,143,168,191,212,229,243,251,255,254,248,237,222,203,181,156,131,106,81,59,39,22,10,3,1, // El83_sinNew
1,18,35,52,69,86,103,120,137,154,171,188,205,222,239,255,239,223,207,191,175,159,143,127,111,95,79,63,47,31,15,1, // El83_treugNew
1,9,17,25,33,41,49,57,65,73,81,89,97,105,113,121,129,137,145,153,161,169,177,185,193,201,209,217,225,235,245,255, // El83_pilaNew
250,246,238,230,222,214,206,198,190,182,174,166,158,150,142,134,126,118,110,102,94,86,78,70,62,54,41,33,25,17,9,1 }; // El83_pilaObrNew
const char* const ddsStr[] PROGMEM = { " Синус", " Треугольник", " Пила", "Обратная пила"};
byte ddsCount=0;
// Рисуем DDS-генератор
display.clearDisplay();
ShowModeInv(0);
for (byte i=0; i<84;) display.drawLine(i, 37-pgm_read_byte(&ddsWave[menu][i%32])/9, i, 37-pgm_read_byte(&ddsWave[menu][(i++)%32])/9, BLACK);
display.setCursor(3, 40); display.print(ddsStr[menu]); display.display(); // отрисовали все
// выводим выбранный сигнал, пока не нажали кнопку
while(flag_key-digitalRead(key_up) && flag_key-digitalRead(key_down) && flag_key-digitalRead(key_ok)) {
pwmWrite(dds, pgm_read_byte(&ddsWave[menu][(ddsCount++)&0x1F]));
}
if (++menu==4) menu = 0; // нажали кнопку - переключаем режим
delay(150); // чтоб кнопки нормально нажимались
}
//////////////////////////////Экран/////////////////////////////////
void Menu_ekrana() {
Set=0;delay(200);
while (flag_key-digitalRead(key_ok)){
display.clearDisplay();
if (Set == 0) display.setTextColor(WHITE, BLACK); else display.setTextColor(BLACK);
display.setCursor(0 , 0); display.println("Контраст:"); display.setTextColor(BLACK);
display.setCursor(60 , 0); display.println(contrast);
display.setCursor(0 , 10); display.println("Подсветк:"); display.setTextColor(BLACK);
if (BL == 1) { display.setCursor(60 , 10); display.println("Вкл");} else
{ display.setCursor(60 , 10); display.println("Отк");} display.display();
if (flag_key-!digitalRead(key_up)) contrast++;
if (flag_key-!digitalRead(key_down)) contrast--;
if (contrast<30) contrast=30;
if (contrast>70) contrast=70;
display.setContrast(contrast);
delay(150);
}
Set=1; delay(200);
while (flag_key-digitalRead(key_ok)){
display.clearDisplay();
display.setCursor(0 , 0); display.println("Контраст:");
display.setCursor(60 , 0); display.println(contrast);
if (Set == 1) display.setTextColor(WHITE, BLACK); else display.setTextColor(BLACK);
display.setCursor(0 , 10); display.println("Подсветк:"); display.setTextColor(BLACK);
if (BL == 1) { display.setCursor(60 , 10); display.println("Вкл"); digitalWrite(Ekran, BL); } else
{ display.setCursor(60 , 10); display.println("Отк"); digitalWrite(Ekran, BL); }
if (flag_key-!digitalRead(key_up)) BL=1;
if (flag_key-!digitalRead(key_down)) BL=0;
display.display();
delay(150);
}
display.display();
display.clearDisplay();
EEPROM.write(0, contrast);
EEPROM.write(1, BL);
setup();
}
Перезалил, подправил скетч, Причина; график вылазил в поднебесную)))
В планах добавить ещё звуковое предупреждение при превышении 5v на входе. Помогите плиз, а.
Вместо текста - только нечитаемые символы,пробовал разные -ARDUINO 1.6.5-r5,ARDUINO 1.8.6,и Adafruit_Library. Скиньте Ваши Adafruit Library.Пожалуйста .
Вместо текста - только нечитаемые символы,пробовал разные -ARDUINO 1.6.5-r5,ARDUINO 1.8.6,и Adafruit_Library. Скиньте Ваши Adafruit Library.Пожалуйста .
Скетч использовал старый , 2017го года. На осциллографе менял сетку, оставил только X.Y по центру. Поставил опирационник на входе, подал на него смещщение чтобы график проходил через ноль. Делитель до 500 вольт. Получился полноценный аппарат для работы с тиристорными преобразователями. Проблемма в отсутствие входа внешней синхронизации. Невозможно правильно отследить коммутацию тиристоров. Сам я не смогу сделать этот вход. После этого прибор демонтировал на другие игрушки. С радостью соберу его заново, если появится внешняя синхронизация. (Синхронизация от сети.)
Уточните, к какой версии относится данный вопрос про кнопки. Но в старых версиях у меня был автодетект кнопок, но что то он никому не понравился...
Сегодня думал позаниматься пультоскопом этим. Отдахать иногда от него - хорошо.
Отловил глюк. Вставил ардуинку - прошил 18-ой версией, и ардуинко перезагружалась каждые ~30 секунд. Провел много опытов - оказалось, что ноут питался от акб и не хватало питания на USB (там есть какой то фьюз, отвечающий за питание). Как только подключаю зарядку к ноуту - все работает как раньше и без перезагрузок :)
И вообще - надоело мне выбор опорного этого - надо делать автодетект и вот эта строчка меня тоже напрягать стала:
И синхронизацию надо автоматом - по середине сигнала, зачем её заранее выставлять то?
Делать 19-ую версию??
... и кнопки ужасно нажимаются - не знаю пока как с этим бороться - найти бы свободное прерывание от всяких измерений частоты и прочих библиотек.... и повесить кнопки на них. И как я раньше тыкал??
Да, Конечно Да! Добавь пожалуйста побольше автоматики. Я так пивык и так очень удобно.
Спасибо! :-)
Вот я ранее спрашивал, почему показание частоты 1306 немного отличаются от 5110? Всё очень просто, нужно на кварц 16 ардуинки с экраном 1306 нужно было добавить два кандёра по 22пф., так как на 5110 я их уже добавил ранее он и показывал правильно.
Пока не смог ещё понять, почему при кварце на 20 или 27 частота занижается во много раз? Все правки в скетче перед заливкой естоственно производил. Например кварц на 20 при частоте 10000 показывает 6000. Может умножитель какой править надо?
Привет, старый друг)))) Никто не пробовал вроде как... для прозвонки надо держать на щупах напряжние. А это уже получается отдельный режим городить надо. Так то не сложно забацать...
Он закоментирован. Он просто не влез. Чтобы он влез нужно порезать картинки меню и.тд. Или можно залить в про мини загрузчик от ардуино уно - ОПТИБУТ. он в раза 3-4 меньше, в результате 1-1.5 к.б. памяти освободится.
empirevv пишет:
После софтового выхода из Осциллоскопа, до перезагрузки в него уже нельзя войти.
Починил. Забыл обнулять key_ok_press=0 при выходе из осцила.
Сам мучаюсь этим вопросом) пины общие. проверить работу пока нет 2 приборчика - нечем. думаю что pwm ген будет работать. а вот dds хз там типа фильтр из резюка и кондея надо. Как это скажется на ардутестере хз. Возможно можно както эти резюк и кондей на какото свободный порт зацепить чтоб во время ддс генератора подключать их а потом отключать. Может бородатые дядьки подскажу, я только "вчера" паяльник в руки взял ;-)
Понял, спасибо. В программировании к сожалению я не силен, во всяком случае пока...) Приходится довольствоваться тем что есть)) Можете вкратце описать функционал доступных в теме версий прибора? Какую порекомендуете?
Дак функционал то от версии к версии остается в общем и целом одним и тем же. Добавляют ребята себе фишки в виде управлением подсветки дисплея, меню настроек, ну кароче по большому счету функционал чтобы так глобально - никто не переделывает. Некоторые зачем то удалают часть функций, ссылаясь на то, что памяти не хватает им. Памяти предостаточно! - надо уметь рационально её использовать.
Порекомендую, кАнечно же свой варинат, на данный момент времени это PULTOSCOPE_LCD5110_EL83_18_OK. Эта версия - вторая моя переделка с нуля кода автора, код оптимизирован, добавлены некторые фишки, например в виде графического меню, ну кароче ни одну ночь я провел за компьютером. Есть и более свежие версии, но выкладывать их не стал, т.к. что то там было не так. Стараюсь выкладывать всегда более менее проверенные мной версии, но без каких то багов редко обходится (в авторской версии тоже есть косяки).
Порекомендую, кАнечно же свой варинат
Где можно качнуть?))
Тут. Искать долго - знаю. Страницы назад.
Тут. Искать долго - знаю. Страницы назад.
Будем искать... Спасибо.
Я нашел - https://yadi.sk/d/OWt4M28A3ULLcf #El83Ver18
Или как тут хэштеги делать?
И как я понял - лучшая проверки именно для осциллографа - это тыкать в ZX-Spectrum)
Я тут как то чинил - сразу много багов отловил:))
Я нашел - https://yadi.sk/d/OWt4M28A3ULLcf #El83Ver18
Или как тут хэштеги делать?
Круто! Спасибо!
На счет хэштегов хз, эт к модерам)))
Порекомендую, кАнечно же свой варинат,
Мне понравился ваш вариант с кодом автоматического управления, очень удобно. Не забрасываите это дело))).
Да, Ваш вариант просто шикарен.
Осталось не понятно одно.
Вош же код полностью подходит к схеме с главной страницы?
К какому пину подключать подсветку и как ее включать.
Иногда без подсветки совсем плохо :(
Я может не первый. Научите пожалуйста терминалом пользоваться.
Код подходит к схеме главной страницы. Подсветка не предусмотрена. У меня она к питанию напрямую...
Я тоже хочу такие часики.
К какому пину подключать подсветку и как ее включать.
Иногда без подсветки совсем плохо :(
Вот Скетч для 5510 подсветка к пину 8 + регулировка контрасности.
Включение и регулировка через пункт в меню. Говорят что этот скетч не огого, но меня вполне устраивает. Я чтото менял в нём для себя, уже не помню что.
А в этом скетче Автоматическое автопределение делителя "5.0" "1.1" "0.22"
Перезалил, подправил скетч, Причина; график вылазил в поднебесную)))
Вместо текста - только нечитаемые символы,пробовал разные -ARDUINO 1.6.5-r5,ARDUINO 1.8.6,и Adafruit_Library. Скиньте Ваши Adafruit Library.Пожалуйста .
Вместо текста - только нечитаемые символы,пробовал разные -ARDUINO 1.6.5-r5,ARDUINO 1.8.6,и Adafruit_Library. Скиньте Ваши Adafruit Library.Пожалуйста .
Все,разобрался,спасибо. !
Всем здравствуйте. Я поставил кварц на 24Мгц от старой видюхи и PWM генератор заработал правильно.
Установка частоты показывает правильно.
Всё, теперь графикой доволен. Скетч прилогаю.
Всем здравствуйте. Я поставил кварц на 24Мгц от старой видюхи и PWM генератор заработал правильно.
Немного поиграл с графикой и вот что получилось
Скетч использовал старый , 2017го года. На осциллографе менял сетку, оставил только X.Y по центру. Поставил опирационник на входе, подал на него смещщение чтобы график проходил через ноль. Делитель до 500 вольт. Получился полноценный аппарат для работы с тиристорными преобразователями. Проблемма в отсутствие входа внешней синхронизации. Невозможно правильно отследить коммутацию тиристоров. Сам я не смогу сделать этот вход. После этого прибор демонтировал на другие игрушки. С радостью соберу его заново, если появится внешняя синхронизация. (Синхронизация от сети.)
007
// a). Как у автора - кнопки к питанию и резюки на массу
008
// b). Как я хочу - кнопки к земле и без всяких резюков
Уточните, к какой версии относится данный вопрос про кнопки. Но в старых версиях у меня был автодетект кнопок, но что то он никому не понравился...
Сегодня думал позаниматься пультоскопом этим. Отдахать иногда от него - хорошо.
Отловил глюк. Вставил ардуинку - прошил 18-ой версией, и ардуинко перезагружалась каждые ~30 секунд. Провел много опытов - оказалось, что ноут питался от акб и не хватало питания на USB (там есть какой то фьюз, отвечающий за питание). Как только подключаю зарядку к ноуту - все работает как раньше и без перезагрузок :)
И вообще - надоело мне выбор опорного этого - надо делать автодетект и вот эта строчка меня тоже напрягать стала:
float VCC=5.0; // напряжение питания, меряем мультиметром
Конечно делать! Мы все ждем затаив дыхание!
Ну и вопрос сразу. А самая свежая версия под 1306 та что на первой странице? Какая то она слишком простая в сравнение с версией для 5110.
Спасибо! :-)
Вот я ранее спрашивал, почему показание частоты 1306 немного отличаются от 5110? Всё очень просто, нужно на кварц 16 ардуинки с экраном 1306 нужно было добавить два кандёра по 22пф., так как на 5110 я их уже добавил ранее он и показывал правильно.
Пока не смог ещё понять, почему при кварце на 20 или 27 частота занижается во много раз? Все правки в скетче перед заливкой естоственно производил. Например кварц на 20 при частоте 10000 показывает 6000. Может умножитель какой править надо?
всем привет.Давно тут не появлялся=))) не подскажете, кто-нибудь пробовал уже прикрутить прозвонку к ослику?
Привет, старый друг)))) Никто не пробовал вроде как... для прозвонки надо держать на щупах напряжние. А это уже получается отдельный режим городить надо. Так то не сложно забацать...
кто-нибудь пробовал уже прикрутить прозвонку к ослику?
Я пробовал. Включаешь режим генератора и выводишь сигнал через динамик. Даже высоту звука можно регулировать. :-)
Всем здрасти. Я может нудный, как на счёт отдельного входа внешней синхронизации. Очень нужно. Вообще прибор класснй получается.
моя версия пультоскопа(v18_20 Electronica)+ардутестера(1.08.004) = АЛЬФА версия
кнопки все на А3 через резисторный делитель
в осциле - 3 частотомера(меню выбора):
у-софтовый по уровню
с-софтовый по средней
т-тактирование таймера на 5 пине (возможен баг переполнения счетчика ибо пока переполнение не отлавливаю)
выход - долгое нажатие средней кнопки
выход из ттестера - долгое нажатие тест кнопки
вход осцила на А4
дисплей на 4-ех пинах
Блин - достойно. Изучу, спасибо!
Ну все - теперь я не самый крутой в программировании пультоскопа:))
А схема где с шестью резисторами?
Круто...
А на какие контакты подключать тестер? Подсветку куда?
схему МИКСА в студию !!!
Схема стандартная :)
Тестер подключен как тут:
http://arduino.ru/forum/proekty/transistor-tester-arduino#comment-195453
Подсветка у меня на переключателе. просто замкнул на землю - есть светло.
можно на пин 2 повесить - без дела болтаеся.
дисплей на 4-ех пинах
кнопки в посте выше
кому лень можно заюзать типа такого модуля (AD Keyboard) и повесить на A3
тогда в функцие Check_keys() нужно свои значения поставить
я использовал китайскую pro mini
c платы выпаял резистор и светодиод с 13-ой ноги
и выпаял конденсатор с ноги AREF
вобщем все как тут:
http://arduino.ru/forum/proekty/transistor-tester-arduino#comment-195453
В нано3 не влазит,
Скетч использует 30824 байт (100%) памяти устройства. Всего доступно 30720 байт.
Разобрался.
я думаю это из-за разных версий библиотек.
я использую теже что и автор оригинального путьтоскопа.
можно также порезать строки выводимые на экран и логотипы.
_починил отображение высоких частот по тактированию таймера с 5 пина(обрабатываю переполнения счетчика)
1 мегагерц покрайней мере определяет и показывает
_починил символы компонентов- диодов, резисторов, конденсаторов
_переименовал библиотеку Adafruit_GFX в Adafr_GFX чтоб со стандартной не конфликтовала
бета версия
https://cloud.mail.ru/public/4Psf/Lm3xXavea
Микс All in One - очень интересен.
Но у меня он работает с глюками.
УАРТ-терминал - не запускается. После софтового выхода из Осциллоскопа, до перезагрузки в него уже нельзя войти.
Это только у меня так?
Железо: про мини и 5110
УАРТ-терминал - не запускается.
Он закоментирован. Он просто не влез. Чтобы он влез нужно порезать картинки меню и.тд. Или можно залить в про мини загрузчик от ардуино уно - ОПТИБУТ. он в раза 3-4 меньше, в результате 1-1.5 к.б. памяти освободится.
После софтового выхода из Осциллоскопа, до перезагрузки в него уже нельзя войти.
Починил. Забыл обнулять key_ok_press=0 при выходе из осцила.
Большое спасибо за указаные опшипки!
А как тогда убрать терминал из меню?
И еще пару вопросов. )
Если нет резисторов 680 Ом, критична их замена на 220 Ом+470 Ом?
Какие планируются настройки в меню настройки? )
Убрать то можно, но я оставил - может что на его место найду приспособить. Просто чтоб потом код не переворачивать.
//----------------------------------------------------------
С ттестером мало знаком, но думаю что такая замена вполне приемлема - там в скетче есть:
//----------------------------------------------------------
в настройках как минимум когдато будет Контрастность и Вкл.Вкл подсветки - вон пин 2 и прочие аналоговые без дела болтаются
так же для ттестера можно в настройки добавить опять же номиналы резисторов 680 и 470.000 и прочие калибровочные
вобщем пихай - нихочу только память надо както освобождать ибо скетч 99% жрет со стандартным бутлоадером
Спасибо за ответ.
Еще вопрос всплыл. А на каких пинах теперь выходы генератора? В стандартной схеме это 9 и 10. Но здесь они заняты тестером
Сам мучаюсь этим вопросом) пины общие. проверить работу пока нет 2 приборчика - нечем. думаю что pwm ген будет работать. а вот dds хз там типа фильтр из резюка и кондея надо. Как это скажется на ардутестере хз. Возможно можно както эти резюк и кондей на какото свободный порт зацепить чтоб во время ддс генератора подключать их а потом отключать. Может бородатые дядьки подскажу, я только "вчера" паяльник в руки взял ;-)
как сделать тестер первым в меню ? ,сам тестер получилось поставить первым в меню - но картинки меню неполучается изменить .
Генератор проверил. Пины те же. DDS работает хорошо. А пины основной функции пультоскопа если соединить - нормально все будет?
как сделать тестер первым в меню ? ,сам тестер получилось поставить первым в меню - но картинки меню неполучается изменить .
самый простой способ
найти в функцие setup()
строки
А к каким пинам подключать щуп осциллоскопа?
А к каким пинам подключать щуп осциллоскопа?
A4
Печалька. :( Генераторы работают, тестер деталей работает, а основкая штука (осциллоскоп)- не работает :(
Так. Он же на отдельном пине А4. Все должно работать. (Хотя если на A0-A2 завести тоже должео работать.)
По конкретнее что не работает?
Подал сигнал на А4. Синусоду 1кГц. Во всех трех режимах нет синусоиды ии не показывает частоту
В оригинальном пультоскопе соединены пины 5 и А3, в микс версии все на одном пине А4? Можно переназначить пин? Где?