#1 Re: Апаратні питання » Отучаем кота пакостить. » 2016-12-13 01:28:24

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

Наверно, чтобы не мучать кота, можно попробовать просто на ИК фотодатчике сделать на пути к стене излучатель и приемник, и при срабатывании ардуино громко пищало бы. Я на работе под большим офисным принтером поставил, было дело, ардуино с ультразвуковым датчиком препятствий(http://myshop.biz.ua/index.php?route=in … news_id=15) , когда человек подходил, из-под принтера раздавалась сирена, в общем на людей неплохо работало, чем коты хуже?

#2 Re: Програмування Arduino » Почему комп не видит порт????? » 2016-12-13 01:12:54

Порт появляется в системе, когда Windows обнаружило устройство, подключенное к USB порту, (в данном случае - Arduino), считало идентификатор этого устройства и нашло драйверы, соответствующие этому идентификатору. Поэтому нужно лезть в Диспетчер устройств из "управления компьютером" и смотреть, что там изменяется при подключении Ардуино. Если Ардуина не сгоревшая, если целый кабель, но нет драйверов, соответствующих идентификатору Arduino Mega, то приподключении должно появляться в списке устройств "Неизвестное устройство", если ничего не появляется, скорее всего, плохой контакт/USB кабель/Ардуино. Если драйверы есть, то при подключении Ардуино в Диспетчере устройств будет появляться новый порт, можно раскрыть секцию Com Порты и вставлять/вынимать кабель Ардуино, чтобы видеть - меняется ли что в диспетчере.
Возможно порт и появляется, но чтобы успешно загрузить скетч, в Arduino IDE важно правильно выбрать номер порта, который появлялся пи подключении Ардуино, и обязательно там же нужно выбрать вид платы - Arduino Mega, если там стоит Arduino Nano, то загрузки скорее всего не получится.

Чтобы много не гадать для начало надо объяснить, что происходит в диспетчере задач...

#3 Проекты » Осциллограф из Ардуино ("Пультоскоп") » 2016-12-04 18:23:40

Saddamko
відповідей: 2

Собрал себе из Ардуино и LCD экрана от телефона Nokia 3310 простенький осциллограф, который оказался очень удобным и простым в эксплуатации. При помощи его можно измерять частоту, изучать форму сигналов, мерять напряжение до 5В (например, проверять батарейки). Есть встроенный генератор сигналов разной формы, терминальный дисплей. Нашел описание этого устройства в интернете, и решил сам его собрать. Тем более, мой старый советский осциллограф сказал "Бам, бубух", и перестал работать (взорвались конденсаторы повышения напряжения). Автор называет устройство "Пультоскоп", поскольку собрал его в пульте дистанционного управления. В конце статьи будут ссылки на автора.

Умеет устройство также работать в качестве монитора последовательного порта - на разъем выведен сигнал Rx Arduino, при переводе в режим "Терминал" устройство "слушает" входной сигнал на частоте 9600 бод. Удобно проверять, если вторая плата ардуино выводит отладочные сообщения в последовательный порт, подключить к выходу этот осциллограф и на экране смотреть выводимые отладочные сообщения.

При минимуме электронных компонентов - польза от устройства неоценимая.

Для сборки потребовалось:


Схема устройства:

shem_pultoskop_v2.jpg
Вот как выглядит получившееся устройство:

oscill4.jpg

oscill3.jpg

Поскольку я взял оригинальный экран от телефона NOKIA, а не готовый дисплейный модуль, пришлось городить колхоз по его подключению:

oscill2.jpg

На картинке ниже подписал основные компоненты:

oscill1.jpg

Видео работы - для демонстрации я на второй платке Arduino запустил программу Fade, которая на 9-м пине занимается ШИМ (широтно-импульсной модуляцией), на видео можно таки рассмотреть, как ШИМ выглядит.:

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


Текст программы, который использовал я:

//Страница проэкта  http://srukami.inf.ua/pultoscop_v25110.html
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <FreqCount.h> 
#include <SPI.h>
#include <PWM.h>
#include <CyberLib.h>
#define led  6   //пин для генератора сигналов (не менять)
#define dds  7   //пин для генератора dds (не менять)

//#################№№№№№№####пользовательские настройки
#define power 8 //пин который опрашивает кнопку включения
#define OFF 14//пин который управляет ключем питания
#define  timepowerON 50 //время удержания кнопки выключения
#define levo 2  //кнопка ЛЕВО(можно любой пин)
#define ok 3    //кнопка ОК(можно любой пин)
#define pravo 4 //кнопка ПРАВО(можно любой пин)
#define akb A6 //любой своюодный аналоговый пин для измерения напряжения АКБ 
#define overclock 16  //Частота на которой работает Ардуино 

Adafruit_PCD8544 display = Adafruit_PCD8544(14, 13, 12, 11, 10);//пины к которым у вас подключен дисплей         
byte cont=52;//контрастность дисплея

byte SinU=30;   //уровень синхронизации 0 до 255 
int PWM = 128;//стартовое значение ШИМ от 0 до 255        
int32_t frequency = 500; //стартовое значение частоты в Гц
float VCC=5.0;  //напряжение питания, меряем мультиметром
//###########################################################
int d=0;
byte menuDDS=0; 
byte sinM[32]={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};
byte pilaM[32]={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};
byte RpilaM[32]={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};
byte trianglM[32]={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};
int powerON=0;//состояние кнопки питания
byte hag=0;
int mnog=0;
boolean flag=0;
byte mass[701];
byte x=0; 
byte menu=0;//переменная выбора меню 
bool opornoe=1; //флаг опорного напряжения
bool paus=0; //флаг режима паузы
byte pultoskop=0; //флаг выбора генератора или осциллографа
byte razv=6;  
unsigned long count =0;
byte sinX=30; 
byte meaX=83;
int Vmax=0;// максимальное напряжение 
byte sinhMASS=0;
long countX=0;
long speedTTL=9600; //скорость терминала 
int prokr=0;

void setup(){
pinMode(A3,INPUT);
digitalWrite(OFF,HIGH);//включем питание 
//Serial.begin(9600);
display.begin();
display.setContrast(cont);  
while(digitalRead(ok)==LOW){  
/////////////////////////////////////////удержание кнопки отключения
if(digitalRead(power)==HIGH){powerON++;delay(10);}  
if(powerON>=timepowerON){digitalWrite(OFF,LOW);}///отключаем питание
/////////////////////////////////////////удержание кнопки отключения 
  if(pultoskop==0){
    display.clearDisplay();
    display.setCursor(10,0);
    display.setTextColor(WHITE, BLACK); // 'inverted' text
    display.println("Pultoscop");
    display.setCursor(10,10);
    display.setTextColor(BLACK); 
    display.println("Generator");
    display.setCursor(10,20);
    display.println("DDSgenerator");
    display.setCursor(10,30);
    display.println("Terminal");
    display.setCursor(0,40);
    display.print("Battery=");
    display.print(analogRead(akb)*5.0/1024);
    display.print("V");    
  }
    if(pultoskop==1){
    display.clearDisplay();
    display.setCursor(10,0);
    display.setTextColor(BLACK); // 'inverted' text
    display.println("Pultoscop");
    display.setCursor(10,10);
    display.setTextColor(WHITE, BLACK); // 'inverted' text
    display.println("Generator");
     display.setTextColor(BLACK); // 'inverted' text;
    display.setCursor(10,20);
    display.println("DDSgenerator");
    display.setCursor(10,30);
    display.println("Terminal");
    display.setCursor(0,40);
    display.setTextColor(BLACK); 
    display.print("Battery=");
    display.print(analogRead(akb)*5.0/1024);
    display.print("V");   
  } 
    if(pultoskop==2){
    display.clearDisplay();
    display.setCursor(10,00);
    display.setTextColor(BLACK); // 'inverted' text
    display.println("Pultoscop");
    display.setCursor(10,10);
    display.println("Generator");
    display.setTextColor(WHITE, BLACK); // 'inverted' text;
    display.setCursor(10,20);
    display.println("DDSgenerator");
    display.setTextColor(BLACK);
    display.setCursor(10,30);
    display.println("Terminal");
    display.setCursor(0,40);
    display.setTextColor(BLACK); 
    display.print("Battery=");
    display.print(analogRead(akb)*5.0/1024);
    display.print("V");   
    }
        if(pultoskop==3){
    display.clearDisplay();
    display.setCursor(10,00);
    display.setTextColor(BLACK); // 'inverted' text
    display.println("Pultoscop");
    display.setCursor(10,10);
    display.println("Generator");
    display.setTextColor(BLACK);
    display.setCursor(10,20);
    display.println("DDSgenerator");
    display.setTextColor(WHITE, BLACK);
    display.setCursor(10,30);
    display.println("Terminal");
    display.setCursor(0,40);
    display.setTextColor(BLACK); 
    display.print("Battery=");
    display.print(analogRead(akb)*5.0/1024);
    display.print("V");   
    }
if(digitalRead(levo)==HIGH){delay(300);pultoskop=pultoskop+1;}
if(digitalRead(pravo)==HIGH){delay(300);pultoskop=pultoskop+1;}
if(pultoskop>3){pultoskop=0;}
delay(50);  
display.display(); }
if(pultoskop==2){InitTimersSafe(); bool success = SetPinFrequencySafe(led,200000);}
if(pultoskop==0){FreqCount.begin(1000);}
if(pultoskop==1){InitTimersSafe(); bool success = SetPinFrequencySafe(led, frequency);}
display.setTextColor(BLACK);
delay(500); }   
void Zamer(){
  if (razv>=6){ADCSRA = 0b11100010;}//delitel 4
  if (razv==5){ADCSRA = 0b11100011;}//delitel 8
  if (razv==4){ADCSRA = 0b11100100;}//delitel 16
  if (razv==3){ADCSRA = 0b11100101;}//delitel 32
  if (razv==2){ADCSRA = 0b11100110;}//delitel 64
  if (razv<2){ADCSRA = 0b11100111;}//delitel 128
  if (razv==0){
      for(int i=0;i<700;i++){ 
          while ((ADCSRA & 0x10)==0);
          ADCSRA|=0x10;
          delayMicroseconds(500);
          mass[i]=ADCH;
      }
  }
  if (razv>0){
      for(int i=0;i<700;i++){ 
          while ((ADCSRA & 0x10)==0);
          ADCSRA|=0x10;
          mass[i]=ADCH;
      }
  }
  
}
void loop() {
/////////////////////////////////////////удержание кнопки отключения
if(digitalRead(power)==HIGH){powerON++;delay(10);}  
if(powerON>=timepowerON){digitalWrite(OFF,LOW);}///отключаем питание
/////////////////////////////////////////удержание кнопки отключения    
if(pultoskop==0){  
if(opornoe==0){ADMUX = 0b11100011;}//выбор внутреннего опорного 1,1В
if(opornoe==1){ADMUX = 0b01100011;}//Выбор внешнего опорного
delay(5);
if(paus==0){Zamer();}
//#######################################определение точки синхронизации
bool flagSINHRO=0;
bool flagSINHRnull=0;
for(int y=1;y<255;y++){
  if(flagSINHRO==0){if(mass[y]<SinU){flagSINHRnull=1;}}
  if(flagSINHRO==0){if(flagSINHRnull==1){if(mass[y]>SinU){flagSINHRO=1;sinhMASS=y;}}}}
//#######################################определение точки синхронизации
//максимальное значение сигнала##########################
Vmax=0; 
for(int y=1;y<255;y++){if(Vmax<mass[y]){Vmax=mass[y];} }
//максимальное значение сигнала##########################
//#######################################определение точки синхронизации
//#######################################отрисовка графика 
if(paus==0){
display.clearDisplay();
display.fillCircle(80,47-SinU/7, 2, BLACK);//рисуем уровень синхронизации    
x=3;
for(int y=sinhMASS;y<sinhMASS+80;y++){
      if(razv<7){x++;}
      if(razv==7){x=x+2;}
      if(razv==8){x=x+3;} 
      display.drawLine(x, 47-mass[y]/7, x+1, 47-mass[y+1]/7, BLACK);
      display.drawLine(x+1, 47-mass[y]/7+1, x+2, 47-mass[y+1]/7+1, BLACK);        
}
sinhMASS=0;}
if(paus==1){
display.clearDisplay();
display.drawLine(prokr/8,8,prokr/8+6,8, BLACK);//шкала прокрутки
display.drawLine(prokr/8,9,prokr/8+6,9, BLACK);//шкала прокрутки
          x=3;
          for(int y=prokr;y<prokr+80;y++){
                if(razv<7){x++;}
                if(razv==7){x=x+2;}
                if(razv==8){x=x+3;} 
                display.drawLine(x, 47-mass[y]/7, x+1, 47-mass[y+1]/7, BLACK);
                display.drawLine(x+1, 47-mass[y]/7+1, x+2, 47-mass[y+1]/7+1, BLACK); 
          }}
//#######################################отрисовка графика
for(byte i=47;i>5;i=i-7){display.drawPixel(0,i, BLACK);display.drawPixel(1,i, BLACK);display.drawPixel(2,i, BLACK);}//разметка экрана  вертикальная
//////////////////////////////////////////////////сетка
for(byte i=47;i>5;i=i-3){display.drawPixel(21,i, BLACK);display.drawPixel(42,i, BLACK);display.drawPixel(63,i, BLACK);}
for(byte i=3;i<84;i=i+3){display.drawPixel(i,33, BLACK);display.drawPixel(i,19, BLACK);}
//////////////////////////////////////////////////сетка
//#######################################отрисовка menu
if(menu==0){
    display.setCursor(0,0);
    display.setTextColor(WHITE,BLACK);
    if(opornoe==0){display.print("1.1");}
    if(opornoe==1){display.print(VCC,1);}
    display.setTextColor(BLACK); 
    display.print(" ");
    display.print(razv);
    display.print(" P");
    if(digitalRead(levo)==HIGH){opornoe=!opornoe;}
    if(digitalRead(pravo)==HIGH){opornoe=!opornoe;}    
}
if(menu==1){
    display.setCursor(0,0);
    display.setTextColor( BLACK);
    if(opornoe==0){display.print("1.1");}
    if(opornoe==1){display.print(VCC,1);}
    display.setTextColor(WHITE, BLACK); // 'inverted' text 
    display.print(" ");
    display.print(razv);
    display.setTextColor( BLACK); // 'inverted' text
    display.print(" P");
    if(digitalRead(levo)==HIGH){razv=razv-1;if(razv==255){razv=0;}}
    if(digitalRead(pravo)==HIGH){razv=razv+1;if(razv==9){razv=8;}}
}
if(menu==2){
    display.setCursor(0,0);
    display.setTextColor( BLACK);
    if(opornoe==0){display.print("1.1");}
    if(opornoe==1){display.print(VCC,1);}
    display.print(" ");
    display.print(razv);
    display.setTextColor(WHITE, BLACK); // 'inverted' text 
    display.print(" P");
    paus=1;
    if(digitalRead(levo)==HIGH){prokr=prokr-10;if(prokr<0){prokr=0;}}
    if(digitalRead(pravo)==HIGH){prokr=prokr+10;if(prokr>620){prokr=620;}}    
}
if(menu==3){
    prokr=0;
    paus=0;
    display.setCursor(0,0);
    display.setTextColor( BLACK);
    if(opornoe==0){display.print("1.1");}
    if(opornoe==1){display.print(VCC,1);}
    display.print(" ");
    display.print(razv);
    display.setTextColor(BLACK);
    display.print(" P");
    if(digitalRead(levo)==HIGH){SinU=SinU-20;if(SinU<20){SinU=20;}}
    if(digitalRead(pravo)==HIGH){SinU=SinU+20;if(SinU>230){SinU=230;}}   
    display.fillCircle(80,47-SinU/7, 5, BLACK);
    display.fillCircle(80,47-SinU/7, 2, WHITE); 
}
if(digitalRead(ok)==HIGH){menu++;if(menu==4){menu=0;paus=0;}}//перебор меню
if (FreqCount.available()) { count = FreqCount.read();}//вывод частоты по готовности счетчика
//#######################################частоты сигнала
byte Frec1=0;
long Frec=0;
bool flagFrec1=0;
bool flagFrec2=0;
bool flagFrec3=0;
for(int y=1;y<255;y++){
  if(flagFrec1==0){if(mass[y]<SinU){flagFrec2=1;}}
  if(flagFrec1==0){if(flagFrec2==1){if(mass[y]>SinU){flagFrec1=1;Frec1=y;}}}
  if(flagFrec1==1){if(mass[y]<SinU){flagFrec3=1;}}
  if(flagFrec3==1){if(mass[y]>SinU){
  if (razv>=6){Frec=1000000/((y-Frec1-1)*3.27);}//delitel 4
  if (razv==5){Frec=1000000/((y-Frec1)*3.27)/2;}//delitel 8
  if (razv==4){Frec=1000000/((y-Frec1)*3.27)/4;}//delitel 16
  if (razv==3){Frec=1000000/((y-Frec1)*3.27)/8;}//delitel 32
  if (razv==2){Frec=1000000/((y-Frec1)*3.27)/16;}//delitel 64
  if (razv==2){Frec=1000000/((y-Frec1)*3.27)/32;}//delitel 128
  if (razv==1){Frec=1000000/((y-Frec1)*3.27)/32;}//delitel 128
  if (razv==0){Frec=1000000/((y-Frec1)*500);}//delitel 128
  flagFrec1=0;flagFrec3=0;}}}
//#######################################частоты сигнала
display.setTextColor( BLACK);
if(opornoe==1){
if((Vmax*VCC/255)>2.5){countX=count*(overclock/16.0);}
if((Vmax*VCC/255)<2.5){countX=Frec*(overclock/16.0);}}
if(opornoe==0){countX=Frec*(overclock/16.0);}
if(countX<1000){display.print(" ");display.print(countX);display.print("Hz");}
if(countX>1000){float countXK=countX/1000.0;display.print(countXK,1);display.print("KHz");}
if(opornoe==1){display.setCursor(0,40);display.setTextColor(BLACK);
display.print(Vmax*VCC/255,1);}
if(opornoe==0){display.setCursor(0,40);display.setTextColor(BLACK);
display.print(Vmax*1.1/255,1);}
display.print("V");
//#######################################отрисовка menu
delay(200);  
display.display();
}
if(pultoskop==1){Generator();}
if(pultoskop==2){DDSGenerator();}
if(pultoskop==3){TTL();}
}
//#######################################режим ренератора
void Generator(){
display.clearDisplay();  
if (flag==0){//флаг выборов режима настройки ШИМ или Частоты
            if(digitalRead(levo)==HIGH){
              frequency=frequency-mnog;
              if(frequency<0){frequency=0;}
              bool success = SetPinFrequencySafe(led, frequency);
              delay(3);//защита от дребезга 
            }
            if(digitalRead(pravo)==HIGH){
              frequency=frequency+mnog;
              bool success = SetPinFrequencySafe(led, frequency);
              delay(3);//защита от дребезга 
            }  
}
if (flag==1){//флаг выборов режима настройки ШИМ или Частоты
            if(digitalRead(levo)==HIGH){
              PWM=PWM-1;
              if(PWM<0){PWM=255;} 
              delay(3);//защита от дребезга
            
            }
            if(digitalRead(pravo)==HIGH){
              PWM=PWM+1;
              if(PWM>255){PWM=0;} 
              delay(3);//защита от дребезга 
            }  
}      
if(digitalRead(ok)==HIGH){//переключение разряда выбора частоты 
  delay(3);//защита от дребезга
  hag++;
  if(hag>=5){hag=0;}
} 
////////////
display.setTextSize(1);
display.setCursor(0,5);
display.print("PWM=");
display.print(PWM*100.0/255);
display.print(" %");
display.drawLine(0,0,83*PWM/255.0,0, BLACK);
display.drawLine(0,1,83*PWM/255.0,1, BLACK);
display.drawLine(0,2,83*PWM/255.0,2, BLACK);
display.drawLine(0,15,83*PWM/255.0,15, BLACK);
display.drawLine(0,16,83*PWM/255.0,16, BLACK);
display.drawLine(0,17,83*PWM/255.0,17, BLACK);
///////////    
display.setCursor(5,20);
 display.setTextSize(2);
long frequencyX=frequency*(overclock/16.0);
if(frequencyX<1000){display.print(frequencyX);display.setTextSize(1);display.println("Hz");}
if(frequencyX>1000){if(frequencyX<10000){display.print((frequencyX/1000.0),2);display.setTextSize(1);display.println("KHz");}}
if(frequencyX>=10000){if(frequencyX<100000){display.print((frequencyX/1000.0),1);display.setTextSize(1);display.println("KHz");}}
if(frequencyX>=100000){display.print((frequencyX/1000.0),0);display.setTextSize(1);display.println("KHz");}
display.setCursor(0,40);
display.setTextSize(1);
display.print(">>X ");    
      if(hag==0){//выбор множителя частоты
        
          display.print(1*(overclock/16.0),1); 
          mnog=1;
          flag=0;
      }
      if(hag==1){//выбор множителя частоты
          display.print(10*(overclock/16.0),0); 
          mnog=10;
      }
      if(hag==2){//выбор множителя частоты
          display.print(100*(overclock/16.0),0); 
          mnog=100;
      }
      if(hag==3){//выбор множителя частоты
          display.print(1000*(overclock/16.0),0); 
          mnog=1000;
      } 
      if(hag==4){//выбор  PWM
          display.print("PWM ");
          display.print(PWM*100.0/255);
          display.print("%"); 
          flag=1;
      } 
display.print("<<");        
pwmWrite(led, PWM);
delay(300);  
display.display();
}
/////////////////////DDS
void DDSGenerator(){
int fr=10;
if(menuDDS==0){
    display.clearDisplay(); 
    display.setTextColor(WHITE, BLACK); // 'inverted' text
    display.setCursor(10,0);
    display.println("Sinus");
    display.setTextColor(BLACK);
    display.setCursor(10,10); 
    display.println("Triangle");
    display.setCursor(10,20);
    display.println("Saw");
    display.setCursor(10,30);
    display.println("Back Saw");
    display.setTextColor(BLACK);
    display.setCursor(0,40);
    //display.print("Частота=");
    //display.print(57);
    //display.print("Гц"); 
    delay(100);  
    display.display();
    while(D11_Read==LOW){
      PWM=sinM[d];
      pwmWrite(dds,PWM);
      //delayMicroseconds(fr);
      d++;
      if(d==32){d=0;}}
    menuDDS++;
    delay(200);}
if(menuDDS==1){
    display.clearDisplay(); 
    display.setTextColor(BLACK); // 'inverted' text
    display.setCursor(10,0);
    display.println("Sinus");
    display.setTextColor(WHITE, BLACK);
    display.setCursor(10,10); 
    display.println("Triangle");
    display.setTextColor(BLACK);
    display.setCursor(10,20);
    display.println("Saw");
    display.setCursor(10,30);
    display.println("Back Saw");
    display.setTextColor(BLACK);
    //display.setCursor(0,40);
    //display.print("Частота=");
   // display.print(57);
    //display.print("Гц");
    delay(100);  
    display.display();
    while(D11_Read==LOW){
      PWM=trianglM[d];
      pwmWrite(dds,PWM);
      //delayMicroseconds(fr);
      d++;
      if(d==32){d=0;}}
    menuDDS++;
    delay(200);}
if(menuDDS==2){
    display.clearDisplay(); 
    display.setTextColor(BLACK); // 'inverted' text
    display.setCursor(10,0);
    display.println("Sinus");
    display.setTextColor(BLACK);
    display.setCursor(10,10); 
    display.println("Triangle");
    display.setTextColor(WHITE, BLACK);
    display.setCursor(10,20);
    display.println("Saw");
    display.setTextColor(BLACK);
    display.setCursor(10,30);
    display.println("Back Saw");
    display.setTextColor(BLACK);
    //display.setCursor(0,40);
    //display.print("Частота=");
   // display.print(57);
    //display.print("Гц");
    delay(100);  
    display.display();
    while(D11_Read==LOW){
      PWM=pilaM[d];
      pwmWrite(dds,PWM);
     // delayMicroseconds(fr);
      d++;
      if(d==32){d=0;}}
      menuDDS++;
    delay(200);}
if(menuDDS==3){
    display.clearDisplay(); 
    display.setTextColor(BLACK); // 'inverted' text
    display.setCursor(10,0);
    display.println("Sinus");
    display.setTextColor(BLACK);
    display.setCursor(10,10); 
    display.println("Triangle");
    display.setTextColor(BLACK);
    display.setCursor(10,20);
    display.println("Saw");
    display.setTextColor(WHITE, BLACK);
    display.setCursor(10,30);
    display.println("Back Saw");
    display.setTextColor(BLACK);
    //display.setCursor(0,40);
    //display.print("Частота=");
   // display.print(57);
   // display.print("Гц");
    delay(100);  
    display.display();
    while(D11_Read==LOW){
      PWM=RpilaM[d];
      pwmWrite(dds,PWM);
      //delayMicroseconds(fr);
      d++;
      if(d==32){d=0;}}
      menuDDS++;
    delay(200);}
if(menuDDS==4){menuDDS=0;}

}
/////////////////////DDS
/////////////////////TTL
void TTL(){
display.clearDisplay(); 
display.setTextColor(BLACK); 
display.setCursor(10,0);
display.println("Terminal");
display.setCursor(10,10);
display.println("Speed");
display.setCursor(10,20);
display.print("-");
display.print(speedTTL);
display.println("+");
display.setCursor(0,30);
display.println("Press OK-start");
if(digitalRead(pravo)==HIGH){speedTTL=speedTTL+100;}
if(digitalRead(levo)==HIGH){speedTTL=speedTTL-100;}
if(speedTTL<0){speedTTL=250000;}
if(speedTTL>250000){speedTTL=0;}
if(digitalRead(ok)==HIGH){Serial.begin(speedTTL*(16/overclock));
      display.clearDisplay(); 
      delay(100);  
      display.display();
      int x=0;
      int y=0; 
      while(1){ 
            char incomingBytes;  
            if (Serial.available() > 0) { // Если в буфере есть данные
                incomingBytes=Serial.read(); // Считывание байта в переменную incomeByte
                display.setCursor(x,y);
                display.print(incomingBytes); // Печать строки в буффер дисплея
                display.display(); x=x+6;
                if(x==84){x=0;y=y+8;}
                if(y==48){x=0;y=0;
                  display.clearDisplay(); 
                  delay(100);  
                  display.display();}}         
      }} 
delay(100);  
display.display();  
}
/////////////////////TTL

Страница разработчика "Пультоскопа": http://srukami.inf.ua/pultoscop_v25110.html

04.12.2016 Дубликат этой страницы

#4 Проекты » Ардуино, часы, управление реле (ЖЕСТЬ! СМОТРЕТЬ ДО КОНЦА! :) » 2016-11-27 11:47:23

Saddamko
відповідей: 6

Устройство разработано для обеспечения возможности автоматического включения подсветки аквариума по расписанию, но может использоваться для других целей. Собрано в небольшой коробочке, содержит Arduino Mini Pro 5V 328, модуль реле, и модуль часов реального времени на чипе DS1307. Вместо этого модуля часов, можно без переделки использовать более современный ds3231.

Может включать и выключать нагрузку по заданному в программе расписанию. Реле рассчитано на подключение достаточно мощной нагрузки (250 вольт 10 Ампер), но утюг к нему подключать не следует, поскольку кроме реле, еще нужно учитывать тонкие дорожки на плате. Но, тем не менее, управлять лампами небольшой мощности можно достаточно уверенно. Тем более, что на плате модуля реле предусмотрена оптронная развязка по питанию, т.е Ардуино отделено от высоковольтной части реле.


aqua(3).jpg


Миниатюрность Ардуино имеет минус - на такой плате не поместился преобразователь USB в TTL и его приходится подключать к плате снаружи, в корпусе я изготовил пропил, куда вывел разъем гребенку, припаяв его к плате Arduino Mini Pro. На снимке в правом верхнем углу виден припаяный к Ардуино небольшой голубой конденсатор - он используется для организации автоматического ресета при запуске программирования (не нужно нажимать кнопку Reset на Arduino Mini Pro, чтобы инициировать режим программирования). Модуль преобразователя USB 2 UART на чипе cp2102 имеет отдельный вывод DTR, выведенный на разъем, который и обеспечивает сигнал Reset.

usb2uart2.jpg

Чтобы сделать автоматический Reset для arduino-mini надо прицепить конденсатор 0.1мкф от DTR на вывод reset ардуины (см. даташит на arduino-pro-mini).



Номинал конденсатора не сильно критичен (я ставил 0.68мкф), надо только чтобы RC-цепочка давала импульс не более 1 сек.

Картинка ниже не моя, но отражает ситуацию,  резистор подтягивающий RST к VCC я не ставил - и так рабоотает.



arduinoresetdtr.png

aqua(2).jpg

Ардуино Mini Pro была выбрана, как самая миниатюрная из имеющихся плат Ардуино, на снимке ниже видно, насколько больше бы потребовалось место для формата Arduino Uno.

aqua(4).jpg

Поскольку предполагается запитывать устройство от 12 вольт, в корпусе нашлось место под микросхему стабилизатора на 5 вольт 7805 (Крен 5), которую я прикрепил к радиатору, на всякий случай. Поскольку потребляемый устройством ток небольшой, 7805 и не греется, даже при питании 12 В, когда на ней падает около 7 вольт. На снимке ниже 7805 с радиатором в верхнем левом углу, к ней идут провода питания от модуля часов, реле и Ардуино.
aqua(6).jpg

Высокохудожественная схема подключения:

aqua(7).jpg

Контакт на плате часов SDA подключаем к контакту A5 платы Ардуино, контакт часов SCL подключаем к выводу A4 Ардуино. На модуле реле два контакта питания (5V И GND), подключаем их на 5 в стабилизатора 7805. Вход управления реле IN подключаем к D10 Arduino.

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

Управляется модуль часов по шине I2C, которая стандартно реализована в Ардуино на контактах A4, A5.

Подключение модуля RTC выполняется к аппаратным выводам SDA, и SCL.


RTC модуль часов на базе чипа DS1307    Arduino Mini Pro
GND    GND
Vcc    +5V
SDA (Serial DAta)    A4
SCL (Serial CLock)    A5



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

relay_module_arduino.jpg

То есть, контакты реле включаются в разрыв цепи нагрузки, как простой переключатель.


#include <Wire.h>
#include "DS1307.h"

DS1307 clock;    //define a object of DS1307 class

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);
  pinMode(10, OUTPUT);
  Serial.begin(9600);
  
  clock.begin();

// Этот закоментированый кусок кода раскоментируем, когда хотим установить время в часах:

//  clock.fillByYMD(2016,11,26);//Jan 19,2013
//  clock.fillByHMS(19,48,30);//15:28 30"
//  clock.fillDayOfWeek(TUE);//Saturday
//  Serial.print("setTime");

  printTime();
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);              // wait for a second
  digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);              // wait for a second
  
  clock.getTime();

// Для примера - включаем реле в 7 часов, выключаем в 10

  if (clock.hour==7)
  {
    digitalWrite(10, HIGH);
    Serial.print("On"); Serial.println(clock.minute);
  };
  
  if ( clock.hour==10)
  {
    digitalWrite(10, LOW);
    
    Serial.println("Off");
  };
  
    if (clock.hour==19)
  {
    digitalWrite(10, HIGH);
    Serial.print("On"); Serial.println(clock.minute);
  };
  
  if ( clock.hour==21)
  {
    digitalWrite(10, LOW);
    
    Serial.println("Off");
  };
  
  
}

void printTime()
{
    clock.getTime();
    Serial.print(clock.hour, DEC);
    Serial.print(":");
    Serial.print(clock.minute, DEC);
    Serial.print(":");
    Serial.print(clock.second, DEC);
    Serial.print("    ");
    Serial.print(clock.month, DEC);
    Serial.print("/");
    Serial.print(clock.dayOfMonth, DEC);
    Serial.print("/");
    Serial.print(clock.year+2000, DEC);
    Serial.print(" ");
    Serial.print(clock.dayOfMonth);
    Serial.print("*");
    switch (clock.dayOfWeek)// Friendly printout the weekday
    {
        case MON:
          Serial.print("MON");
          break;
        case TUE:
          Serial.print("TUE");
          break;
        case WED:
          Serial.print("WED");
          break;
        case THU:
          Serial.print("THU");
          break;
        case FRI:
          Serial.print("FRI");
          break;
        case SAT:
          Serial.print("SAT");
          break;
        case SUN:
          Serial.print("SUN");
          break;
    }
    Serial.println(" ");
}

#5 Re: Апаратні питання » Не могу подключить Arduino UNO R3 к компьютеру. » 2016-11-15 23:59:16

Yадо попробовать еще так:
1) Нажать в списке устройств в диспетчере на "Unknown device" которое и является Arduino.
2) Перейти на вкладку этого устройства "Свойства" "Hardware" и выбрать кнопку "Обновить" ("Update Driver").
3) Выбрать вариант "Установка из указанного места" - "Не выполнять поиск" "Я сам укажу, где искать драйвер"..
4) В появившемся списке устройств найты "Порты" ("Ports").
5) Выбрать изготовителя "Arduino LLC" и потом "Arduino UNO". Если в списке производителей нет "Arduino LLC" тогда делаем следующее:
  a) Нажать  "Установить с диска" "Have Disk" кнопку в том же окне.
  b) Указать на папку с установленной средой ардуино (если она еще не установлена, значит нужно установить),  в этой папке найти "drivers" подпапку, потом выбрать в ней файл с .inf расширением для нужного устройства (В данном случае Arduino UNO.inf).
6) Установить драйвер. Игнорировать предупреждение при установке.
7) Должен появится  COM порт вместо unknown device. Ардуино IDE выбрать Tools > Serial Port и выбрать  COM с нужным номером.

Скорее всего, так должно получиться. Если нет  - надо смотреть в свойствах неизвестного устройства вкладку "Сведения", там выбрать в списке "Коды оборудования" им по этим кодам гуглить нужные драйверы, если в китайской ардуине стоит новый преобразователь USB 2 COM

#6 Re: Програмування Arduino » Помогите новичку » 2016-11-15 23:34:40

Опечатка в посте или в программе?
includeВ - надо include, наверное буква B случайно нажалась на клавиатуре.

#7 Re: Програмування Arduino » Ошибка при компиляции библиотеки RTC1307 » 2016-11-14 17:31:09

Поскольку библиотек к часам много, 
- во-первых: они все рабочие,
- во-вторых: их много и они могут конфликтовать между собой,
я предложил бы два варианта:

Первый вариант: Указать "жесткие" пути к библиотекам часов в #include (вместо #include <DS1307RTC.h> написать #include "C:\Arduino\libraries\DS1307RTC/DS1307RTC.h"), поскольку

Форма в кавычках    Препроцессор ищет включаемые файлы в следующем порядке:

1. В том же каталоге, где находится файл с оператором #include.
2. В каталогах открытых в данный момент включаемых файлов (в порядке, обратном тому, в котором они открывались). Поиск начинается в каталоге родительского включаемого файла, а затем выполняется в каталогах всех включаемых файлов-прародителей.
3. По путям, заданным всеми параметрами компилятора /I.
4. По путям, заданным в переменной среды INCLUDE.

Форма с угловыми скобками    Препроцессор ищет включаемые файлы в следующем порядке:

1. По путям, заданным всеми параметрами компилятора /I.
2. Если компиляция выполняется из командной строки — по путям, которые заданы в переменной среды INCLUDE.

Ну в второй вариант, по принципу первого, переложить файлы h, cpp от библиотеки часов в каталог с ino, и изменить кавычки с угловых на двойные, вот так: #include "DS1307RTC.h". При открытии ino файла откроются в Arduino IDE дополнительные закладки с .h файлами, игнорим.

Третий вариант - хреновый, сделать поиск по компьютеру одноименных файлов библиотек часов, и ну и переименовывать лишние в DS1307RTC.h.old, например, оставив один какой-то DS1307RTC.h, предварительно проверив в нем наличие определений  tmElements_t и пробовать.

#8 Re: Проекты » Радиоприемник с цифровой настройкой на базе модуля FM Stereo » 2016-11-08 01:41:47

NoName пише:

Saddamko, продайте мелкий принтер )

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

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

Так что и жалеть не надо.
Да и размеры - 38х38х38 мм. Я доработал это довольно известный принтер eWaste, так что он по вертикали 38 мм печатает, а в оригинале там шаговик от флопика - наверно мм 15 в высоту... Жабок только печатать:

http://www.instructables.com/id/eWaste-60-3DPrinter/
http://www.instructables.com/id/Curiosi … 3D-Printer

#9 Re: Різне » error: 'flow_cmd_*************' undeclared here (not in a function ) » 2016-11-08 01:29:09

Непонял, что такое

TFunctionStatus  flow_cmd_hello


А все остальное работает:

typedef int TE_TYPE_CONFIG_CMD ;

typedef struct {
   char *CMD;
   TE_TYPE_CONFIG_CMD COMMAND;
   float TFunctionStatus;
   //    TFunctionStatus (*flow_)(unsigned long ID);
}TD_TEXT_CMD;

float flow_command_hello1,flow_command_hello2,flow_command_hello3,flow_command_hello4,flow_command_hello5,flow_command_hello6;

int COMMAND_HELLO1=1;
int COMMAND_HELLO2=2;
int COMMAND_HELLO3=3;
int COMMAND_HELLO4=4;
int COMMAND_HELLO5=5;
int COMMAND_HELLO6=6;


const TD_TEXT_CMD TEXT_CMD[]  =
{
{"HELLO1"                ,COMMAND_HELLO1,                     flow_command_hello1 },
{"HELLO2"                ,COMMAND_HELLO2,                     flow_command_hello2 },
{"HELLO3"                ,COMMAND_HELLO3,                     flow_command_hello3 },
{"HELLO4"                ,COMMAND_HELLO4,                     flow_command_hello4 },
{"HELLO5"                ,COMMAND_HELLO5,                     flow_command_hello5 },
{"HELLO6"                ,COMMAND_HELLO6,                     flow_command_hello6 }
};


void setup() {
  // put your setup code here, to run once:
  int i;
  Serial.begin(9600);

  for (i=0; i<6; i++)
  {
  Serial.print(TEXT_CMD[i].CMD);Serial.print("=");Serial.println(TEXT_CMD[i].COMMAND);
  }
  
}

void loop() {
  // put your main code here, to run repeatedly:

}

#10 Re: Програмування Arduino » Функция sprintf » 2016-11-05 22:29:37

Пишут, что в Aрдуино не реализован sprintf с %f, вроде по соображениям быстродействия - чтобы обойти эту проблему, предлагаю попробовать другой способ вывода float:

#include <stdio.h>

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
}

// the loop routine runs over and over again forever:

void loop()
{
char buffer[12];
float value = 12.987;

char str_temp[6];

/* 4 is mininum width, 2 is precision; float value is copied onto str_temp*/
dtostrf(value, 5, 3, str_temp);
sprintf(buffer,"%s F", str_temp);

Serial.println(buffer);
}

#11 Проекты » Ультразвуковой измеритель расстояния и температуры на Ардуино ds18B20, » 2016-11-04 13:00:39

Saddamko
відповідей: 0

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

Работает очень точно. Расстояние, которое можно измерить не очень большое - уверенно меряет до 4-х метров.

Использованный в устройстве датчик HC-SR04 содержит ультразвуковой излучатель и приемник, по времени отклика от предмета перед датчик определяется расстояние с достаточно высокой точностью.

Дальность измерения - примерно до 5 метров.  Подключив к Arduino
данный датчик и,  цифровой индикатор LCD 1602 (HD44780) по шине i2c,  а самое главное, засунув все это в коробочку, а не оставив в виде макета, получил удобное и надежное устройство. Поскольку измерять приходится редко, чтобы уж не перевести устройство в разряд бесполезно валяющихся, добавил в него измеритель температуры на ds18B20.

После запуска поочередно выводит показания температуры и расстояния, что видно на двух картинках ниже:

us1.jpg
us5.jpg




Так устройство выглядит спереди - кнопка включения, приемная и передающая часть датчика, дырочка под лазерный диод и кнопка его включения, которые просто попутно поместились в коробочке. Прилепил я этот лазер, чтобы удобней было целиться в препятствие, к которому измеряем расстояние:

us2.jpg

"Кишочки" - все обильно сдобрено пластиковым клеем из термопистолета. Видно, что  LCD 1602 (HD44780) я использовал с припаяным к нему переходником, позволяющим управлять индикатором по i2c и уменьшить число проводов к индикатору.
Схема подключения индикатора к Ардуино по I2C:
1602i2c_2.jpg

Почитать подробней можно на https://lesson.iarduino.ru/page/urok-4- … k-arduino/
us3.jpg
Желтый цилиндрик слева - это упомянутый лазерный диод, запитано все от батарейки "Крона" 9в, поскольку потребляемый ток устройством минимальный,  штатных стабилизаторов питания на Ардуино вполне достаточно для понижения питания. Я вот смотрю на черную кляксу пластика в левом нижнем углу на снимке ниже, к которой идут провода, и кажется, я все-таки там поставил стабилизатор напряжения на 7805

us4.jpg



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

#include <LiquidCrystal.h>
#include <OneWire.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <Ultrasonic.h>

/*
 * HCSR04Ultrasonic/examples/UltrasonicDemo/UltrasonicDemo.pde
 *
 * SVN Keywords
 * ----------------------------------
 * $Author: cnobile $
 * $Date: 2011-09-17 02:43:12 -0400 (Sat, 17 Sep 2011) $
 * $Revision: 29 $
 * ----------------------------------
 */


#define TRIGGER_PIN  10
#define ECHO_PIN     9

OneWire ow  (2); // on pin 10
Ultrasonic ultrasonic(TRIGGER_PIN, ECHO_PIN);
// initialize the library with the numbers of the interface pins
LiquidCrystal_I2C lcd(0x27,16,2);   /* Задаем размерность дисплея. 
При использовании LCD I2C модуля с дисплеем 16х4 ничего в коде изменять не требуется, cледует только заменить цифру отвечающую за количество сторок */

int pos = 0;    // variable to store the servo position 

void setup()
  {
  Serial.begin(9600);

  
  lcd.init();                       // Инициализация lcd             
  lcd.backlight();                  // Включаем подсветку
  // Курсор находится в начале 1 строки
  lcd.print("Temperature and");       // Выводим текст
  lcd.setCursor(0, 1);              // Устанавливаем курсор в начало 2 строки
  lcd.print("Ultrasonic mtr.   ");     // Выводим текст
  delay (1000); 
  lookUpSensors();
  delay (1000);
  }

void loop()
  {
  int led = 13;
  float cmMsec, inMsec;
  long microsec = ultrasonic.timing(); 

  cmMsec = ultrasonic.convert(microsec, Ultrasonic::CM);
  inMsec = ultrasonic.convert(microsec, Ultrasonic::IN);
 //inMsec= int(inMsec);
  myLCDclear();
  lcd.setCursor(0, 0);
  lcd.print("Ultrasonic      "); 
  lcd.setCursor(0, 1);
  lcd.print("dist.(cm:)");
  lcd.print (cmMsec);
  delay (2000);
  Temp ();
  delay (2000);
 }
  
  
 void Temp ()
 {
 byte i;
 byte present = 0;
 byte type_s;
 byte data[12];
 byte addr[8];
 float celsius, fahrenheit;
 
 if  (! ow.search  (addr)) {
 ow.reset_search  ();
 delay  (250);
 return;
 }
 
 
 ow.reset  ();
 ow.select  (addr);
 ow.write  (0x44,1); // start conversion, with parasite power on at the end
 
 delay  (1000); // maybe 750ms is enough, maybe not
 // we might do a ow.depower  () here, but the reset will take care of it.
 
 present = ow.reset  ();
 ow.select  (addr); 
 ow.write  (0xBE); // Read Scratchpad

 
 for  (i = 0; i < 9; i++) { // we need 9 bytes
 data[i] = ow.read  ();
 }
 

 // convert the data to actual temperature

 unsigned int raw =  (data[1] << 8) | data[0];
 if  (type_s) {
 raw = raw << 3; // 9 bit resolution default
 if  (data[7] == 0x10) {
 // count remain gives full 12 bit resolution
// raw =  (raw & 0xFFF0) + 12 — data[6];
 }
 } else {
 byte cfg =  (data[4] & 0x60);
 if  (cfg == 0x00) raw = raw << 3; // 9 bit resolution, 93.75 ms
 else if  (cfg == 0x20) raw = raw << 2; // 10 bit res, 187.5 ms
 else if  (cfg == 0x40) raw = raw << 1; // 11 bit res, 375 ms
 // default is 12 bit resolution, 750 ms conversion time
 }
 celsius =  (float)raw / 16.0;
 fahrenheit = celsius * 1.8 + 32.0;
 myLCDclear();
 lcd.setCursor(0, 0);
 lcd.print  ("Temperature =");
 lcd.setCursor(0, 1);
 lcd.print  (celsius);
 lcd.print  (" C, ");
 lcd.print  (fahrenheit);
 lcd.println  (" F   ");
} 


 
 void lookUpSensors(){
  byte address[8];
  int i=0;
  byte ok = 0, tmp = 0;
  //start the search
  lcd.setCursor(0, 0);
  while (ow.search(address)){
    tmp = 0;
    //0x10 = DS18S20
    if (address[0] == 0x10){
      lcd.print("This is a DS18S20: ");
      tmp = 1;
    } else {
      //0x28 = DS18B20
      if (address[0] == 0x28){
        lcd.print("This is a DS18B20: ");
        tmp = 1;
      }
    }
    lcd.setCursor(0, 1);
    //display the address, if tmp is ok
    if (tmp == 1){
      if (OneWire::crc8(address, 7) != address[7]){
        lcd.println("but it doesn't have a valid CRC!");
      } else {
        //all is ok, display it
        for (i=0;i<8;i++){
          if (address[i] < 9){
            lcd.print("0");
          }
          lcd.print(address[i],HEX);
          if (i<7){
            lcd.print("");
          }
        }
        lcd.println("");
        ok = 1;
      }
    }//end if tmp
  }//end while
  if (ok == 0){
    lcd.println("No devices were found");
  }
}

void myLCDclear()
{
  lcd.setCursor(0, 0);
  lcd.print  ("                           ");
  lcd.setCursor(0, 1);
  lcd.print  ("                           ");  
}

#12 Re: Програмування Arduino » Arduino и шифрование » 2016-11-03 01:33:01

Похоже, это все-таки проблема. Если говорить о шифровании, как о кодировке передаваемых данных - так действительно, сниффером неважно какие данные снимать - снял поток, и повторно отправил. А если по аналогии с SSL шифрованием - то просто нет ресурсов в ардуине реализовать даже упрошенный вариант. Обмен сертификатами, с проверкой достоверности, как минимум, серверного, обмен доступными протоколами шифрования - это и  не нужно. И после удачных этих этапов идет шифрованный поток на рандомном ключе, которым обмениваются точки в момент "снюхивания". Ну сертификат, допустим, можно отбросить, метод шифрования, понятно один выбрать. Тогда реализация шифрования  может быть такая - в момент установления каждой сессии между двумя Ардуинами генерировать рандом, обмениваться им, и затем гнать трафик шифрованый этим рандомом. Если сниффер повторно пошлет поток, но на приемной стороне уже другой рандомный ключ, и взлома не будет.
Ну это теоретически, как это увяжется в код я не знаю, я стратег wink

#13 Проекты » Создание GPS трекера на Ардуино с записью треков в EEPROM » 2016-10-30 17:30:52

Saddamko
відповідей: 0

Захотелось сделать устройство записи треков GPS по причине того, что использовать телефон для таких целей не очень удобно, поскольку Android телефон и так не очень хорошо держит зарядку. Пользоваться на нем навигатором иногда очень удобно, но на длительное время его включать - значит рисковать остаться без связи в нужный момент. Альтернативой у меня есть внешний Bluetooth GPS приемник, который можно использовать вместе с ноутбуком, но по аналогичным проблемам с электропитанием, его использование тоже не устраивает. Хотелось иметь небольшое устройство, которое можно включить, и забыть про него. Не контролировать заряд аккумулятора. Чтобы оно записывало информацию, и не теряло.

Поэтому был куплен модуль GPS приемника, с выходами уровня TTL (Rx, Tx), Ардуино и модуль EEPROM памяти на чипе AT24C256.  Также понадобился контроллер заряда аккумулятора, сам аккумулятор, корпус и миниатюрный включатель питания.

Все это было собрано в кучку, соединено проводами и уже работает.

Что умеет:

1. Записывать GPS трек в течение нескольких часов, больше 6 часов точно, еще не замерял максимальное время работы.

2. Выгружать записанные треки по последовательному интерфейсу в форматах GPX и KML.

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

Как им пользоваться:
После включения устройство ожидает команды по последовательному интерфейсу, если нет подключения к компьютеру и нет команд, через 3 минуты автоматически  переходит в режим записи. После получения уверенного сигнала со спутников начинается запись в первую из 2048 записей трека. Каждую минуту добавляется новая запись.

При подключении к компьютеру устройство переходит в режим приема команд.
Обмен происходит через последовательный интерфейс, как при обычном подключении Ардуино к компьютеру. Можно для обмена информацией использовать любую другую терминальную программу, работающую с COM портами, например Putty.

Команды следующие:

K - Отправить на компьютер текст в формате KML файла (Send to PC in KML format)
D - Вывести шестнадцатеричный дамп EEPROM памяти для контроля заполнения (HEX dump of EEPROM memory)
E - Заполнить содержимое EEPROM памяти нулями (стереть)(Erase EEPROM data)
R - Запустить процесс сохранения в памяти координат (запись трека) (Start recording of GPS data)
G - Отправить на компьютер текст в формате GPX файла (Send to PC in GPX format)


Результаты вывода в консоль руками копируем и сохраняет в текстовые файлы, которые потом можно загрузить в Google Maps, например.

Вот пример загруженного на Google Maps GPX файла из устройства:
megagym1.png

Выглядит устройство внутри так:
gps1.jpg

В правой части корпуса - аккумулятор LiIon, контроллер его заряда и включатель питания:
gps2.jpg


В левой части корпуса - GPS приемник, и под ним, под пластмассовой перегородкой из синей пластмассы - Arduino Nano. НА Ардуино имеется преобразователь USB2COM, поэтому для подключения к компьютеру достаточно обычного MiniUSB кабеля. Разъем Ардуино MiniUSB доступен снаружи через отверстие в корпусе и может использоваться для программирования, а также для получения данных в компьютер.
gps3.jpg


Для подключения к Ардуино GPS приемника используются контакт Ардуино D2 (software serial), точнее, выход Tx GPS приемника подключен к D2 Ардуино.

Для EEPROM памяти используются контакты A4 A5 Ардуино (стандартное подключение по I2C протоколу).

Модуль памяти EEPROM размером 32 килобайта (256 Килобит) позволяет записать 2048 точек в треке, поскольку под одну точку в треке используется 16 байт (помимо координат, записывается дата и время замера, скорость, высота и др. информация из GPS NMEA потока - подробности в программе можно увидеть).


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


#include <SoftwareSerial.h>
#include <Wire.h> //I2C library
#include <TinyGPS++.h>

/*
The TinyGPS++ Object Model

The main TinyGPS++ object contains several core sub-objects:

    location – the latest position fix
    date – the latest date fix (UT)
    time – the latest time fix (UT)
    speed – current ground speed
    course – current ground course
    altitude – latest altitude fix
    satellites – the number of visible, participating satellites
    hdop – horizontal diminution of precision
*/

/*
 
    charsProcessed() – the total number of characters received by the object
    sentencesWithFix() – the number of $GPRMC or $GPGGA sentences that had a fix
    failedChecksum() – the number of sentences of all types that failed the checksum test
    passedChecksum() – the number of sentences of all types that passed the checksum test

*/


/* This sample code demonstrates the normal use of a TinyGPSPlus object.
   It requires the use of SoftwareSerial, and assumes that you have a
   9600-baud serial GPS device hooked up on pins 2(rx) and 3(tx).
Summary:
This software displays information from an EM 406A GPS sensor on Phi-1 shield's LCD screen. It also logs the GPS information to the onboard EEPROM of the Phi-1 shield. 

Sample GPS data:
Lat/Long(10^-5 deg): 45xxxxx, -94xxxxx
Date(ddmmyy): 281210 Time(hhmmsscc): 134000
Alt(cm): 31750 Speed(mph): 1.81

List of functions:
* Menu gives you several choices:
* Send to PC: sends recorded GPS information to PC via the USB connection.
Two modes are available:
Verbose mode generates information as shown above.
Non-verbose mode sends only the column labels followed by tab-separated data, ideal for spreasheet programs to import. You may copy and paste.
* Erase EEPROM: erases the EEPROM
* Record: records GPS information, lattitude, longitude, altitude, date, time, speed to EEPROM
* Display: displays the GPS coordinates without recording
* Parameters: allows the user to adjust parameters such as period between two consecutive recordings,, PC data format, to start recording at which data entry and end at which entry.
* Up and down cycle through the menu options.
* Left, right, B act as confirm or enter.
* A escapes and only will preserve the latest value.
*/

#define EEPROM_size 32768UL // This is the maximal bytes on your eeprom, depending on the chip you use. I'm using 24LC256, with 256KiloBits so 32KiloBytes=32768 bytes.
#define n_menu_items 5
#define menu_PC 0     //'Pp'
#define menu_erase 1  //'Ee'
#define menu_record 2 //'Rr'
#define menu_dump 3   //'Dd'
#define menu_para 4
#define menu_KML 5    //'Kk'
#define menu_GPX 6    //'Gg'
#define menu_none 7
#define GPS_Tx 3
#define GPS_Rx 2

// Global Variables
int command = menu_none;       // This is the command char, in ascii form, sent from the serial port
boolean GotCommand=false;
boolean recording=false; // This indicates whether the program is recording the GPS info. If it is recording, a symbol "a chip" appears on the bottom right corner of the LCD.
boolean verbose=false; // This indicates the output to PC format. Verbose is for a human to read with "Lat/long:" and such. While not in verbose mode, it transfers faster and is more compatible with a spreadsheet program.
unsigned long period=5; // This is the period in seconds between two consecutive GPS recordings.
unsigned long pointer=0; // This pointer points to the next empty EEPROM byte for storing or next unread EEPROM byte for reading.
unsigned long lower_limit=0; // This is the lower limit to the pointer value. Save mode startssaving from this EEPROM address. If you use less than 4MBit EEPROM, there is no problem. If not, the limits can go beyond the limit of the signed integer taken by the input function.
unsigned long upper_limit=EEPROM_size; // This is the upper limit to the pointer value. Once the pointer is equal to this value, save mode will stop saving and quits to menu.
unsigned long start;

TinyGPSPlus gps;
SoftwareSerial ss(GPS_Rx, GPS_Tx);


void setup()
{
  
 Wire.begin(); // initialize wire
 Serial.begin(9600);
 ss.begin(9600);

 Serial.println("");
 Serial.print("Library version: ");
 Serial.println(TinyGPSPlus::libraryVersion());
// Serial.println("K - Send to PC in KML format");
// Serial.println("D - HEX dump of EEPROM memory");
// Serial.println("E - Erase EEPROM data");
// Serial.println("R - Start recording of GPS data");
// Serial.println("G - Send to PC in GPX format");
}

void loop()
{
  do_menu();
  
  if ((millis()> 180000)and (GotCommand==false))
  {
//    Serial.println ("No commands is received, start recording!");
    _record();
  };
}

void GPS_to_EEPROM(unsigned long *pointer)
/*
The function assumes that the TinyGPSPlus object gps is already initialized and ready to send data.
It also assumes that the caller feeds the GPS and checks the pointer so the pointed address will not exceed the address space of the EEPROM, or cross page boundaries while writing.
*/
{
  
  double spdf;
  unsigned long spd;
  float lat, lon;
  long alt;
  unsigned long age, dat, tim;
  float buf[4];

  lat=gps.location.lat();
  lon=gps.location.lng();

  
  age=gps.location.age();
  alt=gps.altitude.meters();
  spdf=gps.speed.kmph();
  dat=gps.date.value();
  tim=gps.time.value();

  spd=spdf*100;
  buf[0]=lat;
  buf[1]=lon;
  buf[2]=((alt/10)<<16)|((dat/10000)<<11)|(((dat%10000)/100)<<7)|(dat%100); // Altitude only takes 16 bit. It is in the unit of 0.1m instead of 1cm, which is not necessary in accuracy. date(when expressed in binary 5bit date-4bit month-7bit year, takes no more than 16 bit. Combine them together.
  buf[3]=(spd<<17)|((tim/1000000)*3600+((tim%1000000)/10000)*60+(tim%10000)/100); // Speed, expressed in 1/100 mph, takes less than 15 bits. Compact hhmmsscc into seconds since 00:00 and lose the 1/100 seconds. This is 17 bit long.
  i2c_eeprom_write_page(0x50, (unsigned int) (*pointer), (byte*) buf, 16); // Store 16 bytes of data at location of the pointer.
  (*pointer)=(*pointer)+16; // Increment pointer.
  delay(5); // Make sure the data is written to the EEPROM.
}

boolean EEPROM_to_GPS(float *lat, float *lon, long *alt, unsigned long *tim, unsigned long *dat, double *spdf, unsigned long *pointer)
/*
This function reads one EEPROM entry, if it's non zero, parse it into long integer forms (double precision for speed), and returns true.
If the EEPROM entry is empty, return false.
To stay isolated from the main program, this function doesn't check if the pointer will be beyond the EEPROM size, which is left to the caller to do.
*/
{
  float buf[4];
  i2c_eeprom_read_buffer (0x50, (unsigned int) (*pointer), (byte*) buf, 16);
  if ((buf[0]==0)&&(buf[1]==0)&&(buf[2]==0)&&(buf[3]==0)) return false;
  *lat=(float)buf[0];
  *lon=(float)buf[1];
  *dat=(long)buf[2]&0xFFFF;
  *dat=(*dat>>11)*10000+((*dat>>7)&15)*100+(*dat&127); //Process data to turn into 12/27/10 form
  *alt=10*((long)buf[2]>>16);
  *tim=((long)buf[3]&0x1FFFF);
  *tim=(*tim/3600)*1000000+((*tim%3600)/60)*10000+(*tim%60)*100; //Process time to turn into 12:59:0000 form
  *spdf=((double)(((long)buf[3])>>17))/100.0;
  (*pointer)=(*pointer)+16; // Increment pointer by 16 bytes.
  return true;
}

void do_menu()
{

  int temp1=AskMode ();

  switch (temp1)
  {
    case menu_dump:
    _print_EEPROM_dump();
    break;

    case menu_erase:
    _erase();
    break;

    case menu_record:
    _record();
    break;

    case menu_para:
    _parameters();
    break;

    case menu_PC:
    _send_to_PC();
    break;
    
    case menu_KML:
    _send_to_PC_KML();
    break; 
    
    case menu_GPX:
    _send_to_PC_GPX();
    break; 
    }
  
    if (temp1 != menu_none) {
    Serial.print("Command is completed");
    command = menu_none;
  }
}

 int AskMode ()
 {
    if (Serial.available()) {      // Look for char in serial que and process if found
      command = Serial.read();

      if (command == (byte)'P' || command == (byte)'p') {           //If command = "Pp" Send GPS to PC
        command = menu_PC;
        GotCommand=true;
      }
      else if (command == (byte)'E' || command == (byte)'e') {      //If command = "Ee" Erase EEPROM
        command = menu_erase;
        GotCommand=true;
      }
      else if (command == (byte)'D' || command == (byte)'d') {      //If command = "Dd" Dump EEPROM
        command = menu_dump;
        GotCommand=true;
      }
      else if (command == (byte)'R' || command == (byte)'r') {      //If command = "Rr"  Record GPS
        command = menu_record;
        GotCommand=true;
      } 
       else if (command == (byte)'G' || command == (byte)'g') {      //If command = "Gg" send GPX
        command = menu_GPX;
        GotCommand=true;
      }      
      else if (command == (byte)'K' || command == (byte)'k') {      //If command = "Kk"  send KML
        command = menu_KML;
        GotCommand=true;
      }
      else {
      command = menu_none;                 // none command 
      };
      if (command != menu_none){
           Serial.print("Command: ");      Serial.println(command);     // Echo command CHAR in ascii that was sent
        }
      }
      delay(100);
      return command;
}

void _send_to_PC()
{
  double spdf;
  unsigned long spd;
  float lat, lon;
  long alt;
  unsigned long age, dat, tim;
  unsigned long buf[4];
  pointer=0;

  
  while (EEPROM_to_GPS(&lat, &lon, &alt, &tim, &dat, &spdf, &pointer)&&(pointer<=EEPROM_size-16))
  {
      Serial.print("Lat/Long(10^-5 deg): "); Serial.print(lat,6); Serial.print(", "); Serial.print(lon,6); Serial.println("");
      Serial.print("Date(ddmmyy): "); Serial.print(dat); Serial.print(" Time(hhmmsscc): "); Serial.print(tim); Serial.println("");
      Serial.print("Alt(cm): "); Serial.print(alt); Serial.print(" Speed(mph): ");  Serial.print(spdf,2); Serial.println(""); Serial.println("");
  }
  pointer=0;
}

void _send_to_PC_GPX()
{
  double spdf;
  unsigned long spd;
  float lat, lon;
  long alt;
  unsigned long age, dat, tim;
  unsigned long buf[4];
  pointer=0;     

  Serial.println ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
  Serial.println ("<gpx xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" version=\"1.0\"");
  Serial.println ("xmlns=\"http://www.topografix.com/GPX/1/0\" creator=\"Polar WebSync 2.3 - www.polar.fi\"");
  Serial.println ("xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">");
  
  Serial.println ("<time>2011-09-22T18:56:51Z</time>");
  Serial.println ("<trk>");
  Serial.println ("<name>exercise</name>");
  Serial.println ("<trkseg>");
  
  while (EEPROM_to_GPS(&lat, &lon, &alt, &tim, &dat, &spdf, &pointer)&&(pointer<=EEPROM_size-16))
  {
     Serial.print ("<trkpt lat=\""); Serial.print(lat, 6); Serial.print("\" lon=\""); Serial.print(lon,6); Serial.print ("\">");
     Serial.print ("<time>"); Serial.print(gps.date.year());  Serial.print ("-"); Serial.print(gps.date.month()); Serial.print ("-"); Serial.print(gps.date.day()); Serial.print ("T"); Serial.print(gps.time.hour()); Serial.print (":");  Serial.print(gps.time.minute());  Serial.print (":"); Serial.print(gps.time.second()); Serial.print ("Z</time>");
     Serial.println ("</trkpt>");    
  }
 
  Serial.println ("</trkseg>");
  Serial.println ("</trk>");
  Serial.println ("</gpx>");
  pointer=0;
}


void _send_to_PC_KML()
{
  double spdf;
  unsigned long spd;
  float lat, lon;
  long alt;
  unsigned long age, dat, tim;
  unsigned long buf[4];
  pointer=0;
  
  Serial.println ("<?xml version=\"1.0\" standalone=\"yes\"?>");
  Serial.println ("<kml xmlns=\"http://earth.google.com/kml/2.1\">");
  Serial.println ("<Placemark>");
  Serial.println ("<name>Kiev</name>");
  Serial.println ("<description>Data from Arduino GPS DIY Logger</description>");
  
  while (EEPROM_to_GPS(&lat, &lon, &alt, &tim, &dat, &spdf, &pointer)&&(pointer<=EEPROM_size-16))
  {
     Serial.println ("<Point>");
     Serial.print ("<coordinates>"); Serial.print(lon, 6); Serial.print(","); Serial.print(lat,6); Serial.print ("</coordinates>");
     Serial.println ("</Point>");     
  }
  Serial.println ("</Placemark>");
  Serial.println ("</kml>");
  pointer=0;
}

void _erase()
{
  int temp1, temp2;
  unsigned long buf[4]={0,0,0,0};
  temp1=1;
  Serial.println ("EEPROM Erasing...");
  if (temp1)
    {
    for (unsigned long addr=0;addr<EEPROM_size;addr+=16)
    {
      i2c_eeprom_write_page( 0x50, addr, (byte*) buf, 16);
      delay(5);
    }
  }
  Serial.println ("Erased!");
}

void _print_EEPROM_dump ()
{
  int addr, i, j=0;
  byte b = i2c_eeprom_read_byte(0x50, addr);
  
//  Serial.println("Start dump:");
  for (i=0;i<10; i++)
  {
    for (j=0;j<16; j++)
    {
      Serial.print(b, HEX); Serial.print(" ");
      addr++;
      b = i2c_eeprom_read_byte(0x50, addr);
    }
    Serial.println("#");
  }
}

void _record()
{
  double spdf;
  unsigned long spd;
  float lat, lon, alt;
  unsigned long age, dat, tim;
  unsigned long buf[4];
  char msg[17];

  bool newdata = false;
  unsigned long start = millis();
  
  Serial.println ("Record GPS data is started now!");
  
  // Every few seconds we print an update
  pointer=lower_limit; // Load the lower limit.
  recording = true;
  while(pointer <upper_limit)
  {
    while (ss.available() > 0)
    gps.encode(ss.read());
    start=millis();
  if (gps.location.isUpdated() || gps.altitude.isUpdated())
  {

    GPS_Test ();
      
      if (recording)
      {
        if (pointer<upper_limit)
        {
          GPS_to_EEPROM(&pointer);
          delay (60000);
        }
        
        else
        {
          Serial.print("Limit reached");
          return;
        }
      }
    }
  }
}

void _parameters()
{
}

void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data )
{
  int rdata = data;
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8)); // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(rdata);
  Wire.endTransmission();
}

// WARNING: address is a page address, 6-bit end will wrap around
// also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes
void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length )
{
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddresspage >> 8)); // MSB
  Wire.write((int)(eeaddresspage & 0xFF)); // LSB
  byte c;
  for ( c = 0; c < length; c++)
    Wire.write(data[c]);
  Wire.endTransmission();
}

byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress )
{
  byte rdata = 0xFF;
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8)); // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress,1);
  if (Wire.available()) rdata = Wire.read();
  return rdata;
}

// maybe let's not read more than 30 or 32 bytes at a time!
void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length )
{
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8)); // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress,length);
  int c = 0;
  for ( c = 0; c < length; c++ )
    if (Wire.available()) buffer[c] = Wire.read();
}

void GPS_Test ()
{
Serial.println(gps.location.lat(), 6); // Latitude in degrees (double)
Serial.println(gps.location.lng(), 6); // Longitude in degrees (double)
Serial.print(gps.location.rawLat().negative ? "-" : "+");
Serial.println(gps.location.rawLat().deg); // Raw latitude in whole degrees
Serial.println(gps.location.rawLat().billionths);// ... and billionths (u16/u32)
Serial.print(gps.location.rawLng().negative ? "-" : "+");
Serial.println(gps.location.rawLng().deg); // Raw longitude in whole degrees
Serial.println(gps.location.rawLng().billionths);// ... and billionths (u16/u32)
Serial.println(gps.date.value()); // Raw date in DDMMYY format (u32)
Serial.println(gps.date.year()); // Year (2000+) (u16)
Serial.println(gps.date.month()); // Month (1-12) (u8)
Serial.println(gps.date.day()); // Day (1-31) (u8)
Serial.println(gps.time.value()); // Raw time in HHMMSSCC format (u32)
Serial.println(gps.time.hour()); // Hour (0-23) (u8)
Serial.println(gps.time.minute()); // Minute (0-59) (u8)
Serial.println(gps.time.second()); // Second (0-59) (u8)
Serial.println(gps.time.centisecond()); // 100ths of a second (0-99) (u8)
Serial.println(gps.speed.value()); // Raw speed in 100ths of a knot (i32)
Serial.println(gps.speed.knots()); // Speed in knots (double)
Serial.println(gps.speed.mph()); // Speed in miles per hour (double)
Serial.println(gps.speed.mps()); // Speed in meters per second (double)
Serial.println(gps.speed.kmph()); // Speed in kilometers per hour (double)
Serial.println(gps.course.value()); // Raw course in 100ths of a degree (i32)
Serial.println(gps.course.deg()); // Course in degrees (double)
Serial.println(gps.altitude.value()); // Raw altitude in centimeters (i32)
Serial.println(gps.altitude.meters()); // Altitude in meters (double)
Serial.println(gps.altitude.miles()); // Altitude in miles (double)
Serial.println(gps.altitude.kilometers()); // Altitude in kilometers (double)
Serial.println(gps.altitude.feet()); // Altitude in feet (double)
Serial.println(gps.satellites.value()); // Number of satellites in use (u32)
Serial.println(gps.hdop.value()); // Horizontal Dim. of Precision (100ths-i32)
}


Сеанс работы с модулем выглядит так:


Library version: 0.92
Command: 3
8F C3 49 42 7E 0 F5 41 0 51 4F 49 0 7B 3F 47 #
35 C3 49 42 C5 FF F4 41 0 51 4F 49 B8 FD C5 49 #
41 C3 49 42 F8 FF F4 41 0 51 5F 49 A0 FF C5 49 #
3F C3 49 42 C1 FF F4 41 0 51 6F 49 88 1 C6 49 #
15 C3 49 42 B3 FF F4 41 0 51 6F 49 1B B0 41 4C #
3E C3 49 42 B4 FF F4 41 0 51 7F 49 2A B0 41 4C #
E9 C2 49 42 68 FF F4 41 0 51 7F 49 3A 30 14 4C #
CD C2 49 42 2A FF F4 41 80 A8 8F 49 49 30 14 4C #
AF C2 49 42 F FF F4 41 80 A8 97 49 58 30 14 4C #
8F C2 49 42 BC FE F4 41 80 A8 97 49 67 30 2E 4C #
Command is completed
Command: 6

<?xml version="1.0" encoding="UTF-8"?>
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0"
xmlns="http://www.topografix.com/GPX/1/0" creator="Polar WebSync 2.3 - www.polar.fi"
xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd">
<time>2016-10-31T12:00:00Z</time>
<trk>
<name>exercise</name>
<trkseg>
<trkpt lat="50.440994" lon="30.628486"><time>2016-11-1T6:40:0Z</time></trkpt>
<trkpt lat="50.438034" lon="30.629999"><time>2016-11-1T6:41:0Z</time></trkpt>
<trkpt lat="50.436225" lon="30.631147"><time>2016-11-1T6:32:0Z</time></trkpt>
<trkpt lat="50.433849" lon="30.632692"><time>2016-11-1T6:36:0Z</time></trkpt>
<trkpt lat="50.431716" lon="30.633689"><time>2016-11-1T6:40:0Z</time></trkpt>
<trkpt lat="50.429172" lon="30.635606"><time>2016-11-1T6:44:0Z</time></trkpt>
<trkpt lat="50.427814" lon="30.636674"><time>2016-11-1T7:48:0Z</time></trkpt>
<trkpt lat="50.427806" lon="30.637451"><time>2016-11-1T7:52:0Z</time></trkpt>
<trkpt lat="50.428657" lon="30.640392"><time>2016-11-1T7:56:0Z</time></trkpt>
<trkpt lat="50.429931" lon="30.644645"><time>2016-11-1T7:0:0Z</time></trkpt>
<trkpt lat="50.430488" lon="30.644224"><time>2016-11-1T7:4:0Z</time></trkpt>
<trkpt lat="50.430534" lon="30.643608"><time>2016-11-1T7:36:0Z</time></trkpt>
<trkpt lat="50.430465" lon="30.643112"><time>2016-11-1T7:40:0Z</time></trkpt>
<trkpt lat="50.430507" lon="30.643178"><time>2016-11-1T7:44:0Z</time></trkpt>
<trkpt lat="50.430389" lon="30.643089"><time>2016-11-1T7:48:0Z</time></trkpt>
<trkpt lat="50.430519" lon="30.643329"><time>2016-11-1T7:52:0Z</time></trkpt>
<trkpt lat="50.430461" lon="30.643135"><time>2016-11-1T7:56:0Z</time></trkpt>
<trkpt lat="50.430538" lon="30.643316"><time>2016-11-1T7:0:0Z</time></trkpt>
<trkpt lat="50.430427" lon="30.642770"><time>2016-11-1T7:4:0Z</time></trkpt>
<trkpt lat="50.430683" lon="30.643207"><time>2016-11-1T7:8:0Z</time></trkpt>
<trkpt lat="50.430622" lon="30.643318"><time>2016-11-1T7:12:0Z</time></trkpt>
<trkpt lat="50.430511" lon="30.643299"><time>2016-11-1T7:16:0Z</time></trkpt>
<trkpt lat="50.430458" lon="30.643127"><time>2016-11-1T7:48:0Z</time></trkpt>
<trkpt lat="50.430419" lon="30.643144"><time>2016-11-1T7:52:0Z</time></trkpt>
<trkpt lat="50.430500" lon="30.643247"><time>2016-11-1T7:56:0Z</time></trkpt>
<trkpt lat="50.430492" lon="30.643100"><time>2016-11-1T7:0:0Z</time></trkpt>
<trkpt lat="50.430541" lon="30.643268"><time>2016-11-1T7:4:0Z</time></trkpt>
<trkpt lat="50.430492" lon="30.643062"><time>2016-11-1T7:8:0Z</time></trkpt>
<trkpt lat="50.430683" lon="30.643390"><time>2016-11-1T7:12:0Z</time></trkpt>
<trkpt lat="50.430511" lon="30.643236"><time>2016-11-1T7:16:0Z</time></trkpt>
<trkpt lat="50.430553" lon="30.643251"><time>2016-11-1T7:20:0Z</time></trkpt>
<trkpt lat="50.430622" lon="30.643255"><time>2016-11-1T7:24:0Z</time></trkpt>
<trkpt lat="50.430755" lon="30.643877"><time>2016-11-1T7:28:0Z</time></trkpt>
<trkpt lat="50.430438" lon="30.643171"><time>2016-11-1T7:32:0Z</time></trkpt>
<trkpt lat="50.430538" lon="30.643449"><time>2016-11-1T7:36:0Z</time></trkpt>
<trkpt lat="50.430694" lon="30.643373"><time>2016-11-1T7:8:0Z</time></trkpt>
<trkpt lat="50.430473" lon="30.643560"><time>2016-11-1T7:12:0Z</time></trkpt>
<trkpt lat="50.430500" lon="30.643421"><time>2016-11-1T7:16:0Z</time></trkpt>
<trkpt lat="50.430461" lon="30.643058"><time>2016-11-1T7:20:0Z</time></trkpt>
<trkpt lat="50.429500" lon="30.638359"><time>2016-11-1T7:24:0Z</time></trkpt>
<trkpt lat="50.427513" lon="30.630750"><time>2016-11-1T7:28:0Z</time></trkpt>
<trkpt lat="50.425941" lon="30.623737"><time>2016-11-1T7:32:0Z</time></trkpt>
<trkpt lat="50.431198" lon="30.616735"><time>2016-11-1T7:36:0Z</time></trkpt>
<trkpt lat="50.436553" lon="30.613574"><time>2016-11-1T7:40:0Z</time></trkpt>
<trkpt lat="50.444984" lon="30.608430"><time>2016-11-1T7:44:0Z</time></trkpt>
<trkpt lat="50.451854" lon="30.604282"><time>2016-11-1T7:48:0Z</time></trkpt>
<trkpt lat="50.452846" lon="30.603673"><time>2016-11-1T7:20:0Z</time></trkpt>
<trkpt lat="50.459339" lon="30.598125"><time>2016-11-1T7:24:0Z</time></trkpt>
<trkpt lat="50.466320" lon="30.592060"><time>2016-11-1T7:28:0Z</time></trkpt>
<trkpt lat="50.472824" lon="30.586578"><time>2016-11-1T7:32:0Z</time></trkpt>
<trkpt lat="50.478488" lon="30.581762"><time>2016-11-1T7:36:0Z</time></trkpt>
<trkpt lat="50.479003" lon="30.581178"><time>2016-11-1T7:40:0Z</time></trkpt>
<trkpt lat="50.482902" lon="30.574560"><time>2016-11-1T7:44:0Z</time></trkpt>
<trkpt lat="50.483150" lon="30.573579"><time>2016-11-1T7:48:0Z</time></trkpt>
<trkpt lat="50.483917" lon="30.570413"><time>2016-11-1T7:52:0Z</time></trkpt>
<trkpt lat="50.484176" lon="30.557836"><time>2016-11-1T7:56:0Z</time></trkpt>
<trkpt lat="50.484161" lon="30.547096"><time>2016-11-1T7:28:0Z</time></trkpt>
<trkpt lat="50.484249" lon="30.538497"><time>2016-11-1T7:32:0Z</time></trkpt>
<trkpt lat="50.484031" lon="30.532958"><time>2016-11-1T7:36:0Z</time></trkpt>
<trkpt lat="50.484157" lon="30.524370"><time>2016-11-1T7:40:0Z</time></trkpt>
<trkpt lat="50.484184" lon="30.515460"><time>2016-11-1T7:44:0Z</time></trkpt>
<trkpt lat="50.484466" lon="30.506853"><time>2016-11-1T7:48:0Z</time></trkpt>
<trkpt lat="50.485046" lon="30.498723"><time>2016-11-1T7:52:0Z</time></trkpt>
<trkpt lat="50.485145" lon="30.497272"><time>2016-11-1T7:56:0Z</time></trkpt>
<trkpt lat="50.485839" lon="30.492294"><time>2016-11-1T8:0:0Z</time></trkpt>
<trkpt lat="50.489120" lon="30.483161"><time>2016-11-1T8:4:0Z</time></trkpt>
<trkpt lat="50.489238" lon="30.483140"><time>2016-11-1T8:52:0Z</time></trkpt>
<trkpt lat="50.488643" lon="30.484096"><time>2016-11-1T8:56:0Z</time></trkpt>
<trkpt lat="50.488353" lon="30.483186"><time>2016-11-1T8:0:0Z</time></trkpt>
<trkpt lat="50.488304" lon="30.481788"><time>2016-11-1T8:56:0Z</time></trkpt>
<trkpt lat="50.488121" lon="30.480539"><time>2016-11-1T8:0:0Z</time></trkpt>
<trkpt lat="50.488391" lon="30.479782"><time>2016-11-1T8:56:0Z</time></trkpt>
<trkpt lat="50.488334" lon="30.478380"><time>2016-11-1T8:0:0Z</time></trkpt>
<trkpt lat="50.488246" lon="30.477094"><time>2016-11-1T8:0:0Z</time></trkpt>
<trkpt lat="50.488967" lon="30.476121"><time>2016-11-1T8:0:0Z</time></trkpt>
<trkpt lat="50.489303" lon="30.475259"><time>2016-11-1T8:4:0Z</time></trkpt>
<trkpt lat="50.491306" lon="30.475305"><time>2016-11-1T8:4:0Z</time></trkpt>
</trkseg>
</trk>
</gpx>

Command is completed
Command: 5

<?xml version="1.0" standalone="yes"?>
<kml xmlns="http://earth.google.com/kml/2.1">
<Placemark>
<name>Kiev</name>
<description>Data from Arduino GPS DIY Logger</description>
<Point>
<coordinates>30.625240,50.440975</coordinates></Point>
<Point>
<coordinates>30.624887,50.440631</coordinates></Point>
<Point>
<coordinates>30.624984,50.440677</coordinates></Point>
<Point>
<coordinates>30.624879,50.440670</coordinates></Point>
<Point>
<coordinates>30.624853,50.440509</coordinates></Point>
<Point>
<coordinates>30.624855,50.440666</coordinates></Point>
<Point>
<coordinates>30.624710,50.440341</coordinates></Point>
<Point>
<coordinates>30.624591,50.440235</coordinates></Point>
<Point>
<coordinates>30.624540,50.440120</coordinates></Point>
<Point>
<coordinates>30.624382,50.439998</coordinates></Point>
<Point>
<coordinates>30.624336,50.439952</coordinates></Point>
<Point>
<coordinates>30.624345,50.440029</coordinates></Point>
<Point>
<coordinates>30.624279,50.439929</coordinates></Point>
<Point>
<coordinates>30.624334,50.440013</coordinates></Point>
<Point>
<coordinates>30.624294,50.440078</coordinates></Point>
<Point>
<coordinates>30.624567,50.440319</coordinates></Point>
<Point>
<coordinates>30.624744,50.440414</coordinates></Point>
<Point>
<coordinates>30.625295,50.441028</coordinates></Point>
<Point>
<coordinates>30.625415,50.441131</coordinates></Point>
<Point>
<coordinates>30.625429,50.441154</coordinates></Point>
<Point>
<coordinates>30.625413,50.441139</coordinates></Point>
<Point>
<coordinates>30.625398,50.441131</coordinates></Point>
<Point>
<coordinates>30.625398,50.441131</coordinates></Point>
<Point>
<coordinates>30.625381,50.441116</coordinates></Point>
<Point>
<coordinates>30.625383,50.441116</coordinates></Point>
<Point>
<coordinates>30.625322,50.441089</coordinates></Point>
<Point>
<coordinates>30.625339,50.441085</coordinates></Point>
<Point>
<coordinates>30.625350,50.441085</coordinates></Point>
<Point>
<coordinates>30.625417,50.441101</coordinates></Point>
<Point>
<coordinates>30.625402,50.441089</coordinates></Point>
<Point>
<coordinates>30.625429,50.441104</coordinates></Point>
<Point>
<coordinates>30.625429,50.441108</coordinates></Point>
<Point>
<coordinates>30.625429,50.441104</coordinates></Point>
<Point>
<coordinates>30.625415,50.441074</coordinates></Point>
<Point>
<coordinates>30.625419,50.441104</coordinates></Point>
<Point>
<coordinates>30.625370,50.441085</coordinates></Point>
<Point>
<coordinates>30.625314,50.441051</coordinates></Point>
<Point>
<coordinates>30.625335,50.441066</coordinates></Point>
<Point>
<coordinates>30.625667,50.441024</coordinates></Point>
<Point>
<coordinates>30.625587,50.441005</coordinates></Point>
<Point>
<coordinates>30.625207,50.440696</coordinates></Point>
<Point>
<coordinates>30.625137,50.440738</coordinates></Point>
<Point>
<coordinates>30.625299,50.440345</coordinates></Point>
<Point>
<coordinates>30.625938,50.440605</coordinates></Point>
</Placemark>
</kml>
Command is completed

#14 Re: Проекты » Подойдет ли Ардуино для автоматизации умным домом? » 2016-10-27 18:14:53

ballun пише:

Я вам помогу выходите на связь. big_smile

Недавно на форуме журнала доктора Добба прочитал в свежих комментариях к тексту программы - "Ребята, успокойтесь, статья была написана 16 лет назад"

#15 Re: Апаратні питання » Все на arduino... » 2016-10-25 16:57:59

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

#16 Re: Апаратні питання » Необходимы рекомендации для старта » 2016-10-25 16:18:39

Для домашней метеостанции я бы порекомендовал сразу посмотреть в сторону wifi модуля ESP8266 - его удобно использовать и с Ардуино и без него (у него аналогичный встроенный микроконтроллер) - он сам коннектится на домашний роутер (в интернет) - и появляется возможность транслировать данные погоды в мир ( я использовал narodmon.ru - глянь прямо там, есть ссылки на железки), можно наоборот из инета читать погоду с погодных сайтов через Json и выводить на экран, опять через сеть удобно данные о погоде со своих датчиков обрабатывать на чем-то - можно просто на компьютере. Автономно на Ардуино скучновато - ну есть текущие показания, ну и что. Греет не долго. Сайтов много по поиску, вот, например, для затравки.

Вот из скучных вариантов на Ардуино - что я делал - http://forum.arduino.ua/viewtopic.php?id=818

#17 Re: Проекты » Радиоприемник с цифровой настройкой на базе модуля FM Stereo » 2016-10-21 14:21:47

NoName пише:

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

принято )
я еще лодку не закончил )   принтер подождет...

Лодка, кстати, супер! Мне очень нравится. Плохо, что скоро совсем похолодает hmm  Придется с ванной выгонять всех резиновый уточек и зимой там тестировать wink

#18 Re: Проекты » Радиоприемник с цифровой настройкой на базе модуля FM Stereo » 2016-10-21 13:41:00

NoName пише:

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

печатаете на заказ?   мне б корпус для девасины что б крепился на планку пикатинни, (
еще не рисовал )

Маленький обошелся, наверно, до 50 долларов, а то и меньше.

Но просто он собирался - из того, что уже было -
блок питания от компьютера - очень дорого, но брал свой.
А так - порезка акрила - не помню точно, с материалом кажется 250 грн была,
по принтеру - электроника (Ардуино Мега + Шилд Polulu - долларов 20),
Ну экструдер баксов 5 и шаговик один - со старого винчестера советского.
На разборку на разиобазаре купил старые DVD приводы - где по 10 грн брал, где по 50 грн.
В общем, не очень затратно - я на его основе просто хотел понять, как работает, как настраивается.
Идея себя не очень оправдала - потому что оси, построенные на шаговиках от DVD не очень хорошо под нагрузкой себя ведут - довольно часто проскакивает, сдвигается. Все время возня, что-то подправить, что-то подстроить...
А потом собрал Graber - это уже по накатанной, как конструктор .

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

Кажется, я какие-то крепления для планки видел на
http://thingiverse.com/ - можно там посмотреть, по поиску Picatinny rail

#19 Re: Проекты » Радиоприемник с цифровой настройкой на базе модуля FM Stereo » 2016-10-21 13:06:24

NoName пише:

привет
http://myshop.biz.ua/index.php?route=pr … duct_id=55
печатаете? или только в планах?

Привет! Печатаю. Любительски. Любительски - потому что не хватает терпения отстроить все, чтобы более качественная печать была - видно по картинкам, что не высокохудожественные работы получаются, но как механические объекты очень прочные.

Сделал два принтера - сначала маленький, потом Graber i3
small3dprinter.jpg
print3d(2).jpg
print3d(4).jpg

Ну и раз начал хвастаться хозяйством - еще сделал лазерный гравер, в корпусе, аналогичном маленькому 3D принтеру, и ЧПУ станок, который уже несколько лет в состоянии - что-то можно делать, но показывать стыдно:
printer_graver.jpg

#20 Проекты » Радиоприемник с цифровой настройкой на базе модуля FM Stereo » 2016-10-21 11:41:11

Saddamko
відповідей: 9

Продающийся копеешный радиомодуль em5807m с цифровым управлением по шине i2c я сначала выпаял из поломанного радиоприемника, а подом подкупил еще в Китае. Для управления модулем использовал Ардуино, чтобы выводить частоту настройки использовал дисплейный модуль с 4-я цифрами, тоже программирующийся по шине.

Приемник был смонтирован в корпусе поломанного аналогового приемника с часами (или наоборот).http://forum.arduino.ua/ В корпусе пригодились кнопки - две я задействовал на управление - выбор радиостанции из списка предустановленных в программе.

Картинки радиоприемника (извиняюсь за качество - использован модуль усилителя звука, Arduino Mini Pro, модуль дисплея  tm1637, FM модуль RDA5807M).

radio(2).jpg

radio(6).jpg

Распиновка модуля следующая:

radioem5807m.jpg

Шина I2C это пины 6 и 7 радиомодуля, они подключены к A4 A5 Ардуино, 2 и 3 контакт радиомодуля - выходы звуковые, один из них подключается к модулю усилителя звука.

Для подключения к ардуино используется следующая коммутация (только дисплейный модуль я использовал другой):

radioem5807m42.jpg

Пример кода для создания приемника на основе чипа 5807 и LED модуля tm1637 для индикации частоты приема.

Код рабочий,  частоты настроены для Киева:

// Programm: fm_radio_module_em5807m_rev100.ino
// Language: Arduinio C++
// Hardware: Arduino Nano 3.0 + EM5807M module with RDA5807M Chip.
// Version:  1.00
// Autor:    www.5v.ru
// Link:     www.5v.ru/start/em5807m-arduino-nano-30.htm
/*
92.4	Ретро FM	Oldies
92.8	Europa Plus Украина	CHR
93.8	Бизнес Радио	AC
94.2	Радио Ренессанс	Contemporary Jazz
95.2	Радио Дача	AC
95.6	Джем FM	Rock
96.0	Эра FM	News/Talk
96.4	Хит FM	Hot AC/AC
96.8	DJFM	Dance
98.0	Радіо Київ	News/Talk, AC
98.5	Русское Радио Украина	Russian Top 40
99.0	Radio Nostalgie	Gold Hits/Oldies
99.4	Радио Next	
100.0	Гала Радио	Hot AC
100.5	Народное Радио	-
101.1	Super Radio	Hot AC
101.5	MusicРадио	Easy Listening
101.9	Радио Шансон	Шансон
102.5	Просто Ради.О	AAA/Hot AC
103.1	Люкс FM	Hot AC
103.6	Radio ROKS	Rock
104.0	Радио Шарманка	CHR/Top 40
104.6	Радио 24	AC
105.0	1-й канал НРУ
Радио «Промінь»	News/Talk
105.5	Стильное радио Перец FM	Top 40
106.0	Голос Столицы	News, Gold Hits
106.5	Kiss FM	Dance
107.0	Европа Плюс Киев	AC
107.4	Авторадио Украина	AC
107.9	Наше Радио	AC
*/
#include "TM1637.h"
#include <Wire.h>               // I2C-Library
#define CLK 13//pins definitions for TM1637 and can be changed to other ports       
#define DIO 12
const int buttonPinMax = 9;     // the number of the pushbutton pin
const int buttonPinMin = 8;     // the number of the pushbutton pin
double f_ini=103.6;             // Стартовая частота настройки приемника. (Изменяем на нужную).
// variables will change:
int buttonStateMax = 0;         // variable for reading the pushbutton status
int buttonStateMin = 0;         // variable for reading the pushbutton status
int Station=21;

TM1637 tm1637(CLK,DIO);

void setup()                    // Инициализация.
{
  
    // initialize the pushbutton pin as an input:
    pinMode(buttonPinMax, INPUT);
    pinMode(buttonPinMin, INPUT);
    
    tm1637.init();
    tm1637.set(BRIGHT_TYPICAL);//BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;
  
    Wire.begin();                 // Инициализация двухпроводной шины I2C.
    setFrequency(f_ini);          // Вызываем фукнкцию загрузки частоты настройки в модуль EM5807M.
    DisplayStation (f_ini);
 
}

void loop()                     // Основной цикл программы
{
  // Здесь можем написать нашу самую лучшую программу, которая будет работать так как нам нужно.
  buttonStateMax = digitalRead(buttonPinMax);
  if (buttonStateMax == HIGH) 
  {     
      // turn LED on:    
    Station = Station + 1;
    if (Station >=31) {Station = 1;};
    ChangeStation ( Station);
    DisplayStation (f_ini);
    delay (1000);
  }
   buttonStateMin = digitalRead(buttonPinMin);
  if (buttonStateMin == HIGH) 
  {     
      // turn LED on:    
    Station = Station - 1;
    if (Station <1) {Station = 30;};
    ChangeStation ( Station);
    DisplayStation (f_ini);
    delay (1000);
  }  
}
  
 void ChangeStation (int Station)
 {
  switch (Station) {
    case 1:
      //do something when var equals 1
      f_ini=92.4;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);      
      break;
    case 2:
      //do something when var equals 2
      f_ini=92.8;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;
    case 3:
      //do something when var equals 2
      f_ini=93.8;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;
    case 4:
      //do something when var equals 2
      f_ini=94.2;
      setFrequency(f_ini);          // Вызываем фукнкцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;
    case 5:
      //do something when var equals 2
      f_ini=95.2;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;
    case 6:
      //do something when var equals 2
      f_ini=95.6;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;
    case 7:
      //do something when var equals 2
      f_ini=96.0;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;
    case 8:
      //do something when var equals 2
      f_ini=96.4;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;
    case 9:
      //do something when var equals 2
      f_ini=96.8;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;
    case 10:
      //do something when var equals 2
      f_ini=98.0;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;
    case 11:
      //do something when var equals 2
      f_ini=98.5;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;
    case 12:
      //do something when var equals 2
      f_ini=99.0;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;
    case 13:
      //do something when var equals 2
      f_ini=99.4;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;     
    case 14:
      //do something when var equals 2
      f_ini=100.0;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;  
    case 15:
      //do something when var equals 2
      f_ini=100.5;
      setFrequency(f_ini);          // Вызываем фукнкцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;  
    case 16:
      //do something when var equals 2
      f_ini=101.1;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;  
    case 17:
      //do something when var equals 2
      f_ini=101.5;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;  
    case 18:
      //do something when var equals 2
      f_ini=101.9;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;  
    case 19:
      //do something when var equals 2
      f_ini=102.5;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;  
    case 20:
      //do something when var equals 2
      f_ini=103.1;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;  
    case 21:
      //do something when var equals 2
      f_ini=103.6;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;  
    case 22:
      //do something when var equals 2
      f_ini=104.0;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;  
    case 23:
      //do something when var equals 2
      f_ini=104.6;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;  
    case 24:
      //do something when var equals 2
      f_ini=105.0;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;  
    case 25:
      //do something when var equals 2
      f_ini=105.5;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;  
    case 26:
      //do something when var equals 2
      f_ini=106.0;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break;  
    case 27:
      //do something when var equals 2
      f_ini=106.5;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break; 
    case 28:
      //do something when var equals 2
      f_ini=107.0;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break; 
    case 29:
      //do something when var equals 2
      f_ini=107.4;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break; 
    case 30:
      //do something when var equals 2
      f_ini=107.9;
      setFrequency(f_ini);          // Вызываем функцию загрузки частоты настройки в модуль EM5807M.
      DisplayStation (f_ini);            
      break; 
    default: 
      // if nothing else matches, do the default
      // default is optional
      break;
  }
 }
  
 void DisplayStation (double Freq)
 {
    int8_t ListDisp[4];
    ListDisp[0] = ((int)Freq/100) % 10;
    ListDisp[1] = ((int)Freq/10) % 10;
    ListDisp[2] = ((int)Freq/1) % 10;
    ListDisp[3] = ((int)(Freq*10)) % 10;
    tm1637.display(0,ListDisp[0]);
    tm1637.display(1,ListDisp[1]); 
    tm1637.display(2,ListDisp[2]);
    tm1637.display(3,ListDisp[3]);
 }
 

void setFrequency(double fmhz)  // Функция загрузки частоты настройки в модуль EM5807M.
{
  int  frequencyB = 4 * (fmhz * 1000000 + 225000) / 32768;
  char frequencyH = frequencyB >> 8;     // Старший байт.
  char frequencyL = frequencyB & 0XFF;   // Накладываем маску 0xFF на младший байт.
  Wire.beginTransmission(0x60);          // Адрес чипа RDA5807M
  Wire.write(frequencyH);                // Старший байт.
  Wire.write(frequencyL);                // Младший байт.
  Wire.write(0xB8);                      // 1011 1000     =Стерео
  Wire.write(0x10);                      // 0001 0000
  Wire.write((byte)0x00);                // 
  Wire.endTransmission();                // формируем I2C-Stop.
}

#21 Проекты » Домашняя метеостанция, датчик BMP180 и TFT дисплей ST7735 на Arduino » 2016-10-20 13:13:34

Saddamko
відповідей: 9

BMP180 ST7735 Arduino
Для создания небольшой домашней метеостанции был использован датчик давления и температуры BMP180, для вывода информации использовался дисплей TFT  ST7735 и Arduino Mini Pro. Само устройство было помещено в коробочку для визиток из оргстекла.

station1s.jpg
station2s.jpg

В примере кода, который идет ниже по тексту, использовались следующие коммутации:

Дисплей подключен к пинам Ардуино так (cs к пину 10, dc к пину 9, rst к 8, gnd и power (3В!!!)  дисплея к сответствующим выводам питания).

/**********************************************************
 Bosch Pressure Sensor BMP085 / BMP180 readout routine
 for the Arduino platform.
  
 Compiled by Leo Nutz
 [url=http://www.ALTDuino.de]www.ALTDuino.de[/url]              
**********************************************************/
// 0.0075006375541921
#include <Wire.h>
#include "Barometer.h"
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>

float temperature;
float pressure;
float atm;
float altitude;
Barometer myBarometer;

#define cs   10
#define dc   9
#define rst  8  // you can also connect this to the Arduino reset

 
Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst);


void setup()
{
 Wire.begin();                             // Activate I2C
 
 Serial.begin(9600);                       // Set up serial port

 myBarometer.init();                          // Initialize baro sensor variables
 delay(100);
   tft.initR(INITR_BLACKTAB);   // initialize a ST7735S chip, black tab
   tft.fillScreen(ST7735_BLACK);
   tft.setRotation(3);
}

void loop()
{
ShowInfo ();
 
}


void ShowInfo ()
{
   temperature = myBarometer.bmp085GetTemperature(myBarometer.bmp085ReadUT()); //Get the temperature, bmp085ReadUT MUST be called first
   pressure = myBarometer.bmp085GetPressure(myBarometer.bmp085ReadUP())*0.0075006375541921;//Get the pressure
   altitude = myBarometer.calcAltitude(pressure); //Uncompensated caculation - in Meters 
   atm = pressure / 101325; 
  
  Serial.print("Temperature: ");
  Serial.print(temperature, 2); //display 2 decimal places
  Serial.println("deg C");

  Serial.print("Pressure: ");
  Serial.print(pressure, 0); //whole number only.
  Serial.println(" mmHg");

  Serial.print("Ralated Atmosphere: ");
  Serial.println(atm, 4); //display 4 decimal places

  Serial.print("Altitude: ");
  Serial.print(altitude, 2); //display 2 decimal places
  Serial.println(" m");

  Serial.println();

  delay(1000); //wait a second and get values again.
  
    
    tft.fillRect (0,0, 160, 128,ST7735_BLACK);
    
    tft.setTextWrap(true);
    tft.setTextColor(ST7735_RED);
    tft.setTextSize(3);
    tft.setCursor(0, 0);
    tft.println("Hello!");

 tft.setTextColor(ST7735_BLUE);
 tft.setTextSize(2);


 tft.println("Temperature:");
 tft.setTextSize(2);
 tft.setTextColor(ST7735_YELLOW);
 tft.print(temperature, 2);
 tft.println(" C");


 tft.setTextColor(ST7735_GREEN);
 tft.setTextSize(2);
 tft.println("Pressure: ");
 tft.setTextColor(ST7735_CYAN);
 tft.setTextSize(2);
 tft.print(pressure, 2);
 tft.println(" mmHg");

 delay(5000);  
 // Delay between each readout
 
  tft.setTextColor(ST7735_GREEN);
  tft.setCursor(0, 20);
  tft.setTextSize(12);
  tft.fillRect (0,0, 160, 128,ST7735_BLACK);
  tft.println(temperature, 0);
  delay(2000);  
  tft.setTextColor(ST7735_WHITE);
  tft.setTextSize(8);
  tft.setCursor(0, 40);
  tft.fillRect (0,0, 160, 128,ST7735_BLACK);
  tft.println(pressure, 0);
  delay(2000);  
  
  testfillcircles(5, ST7735_BLUE);
  testdrawcircles(5, ST7735_WHITE);  
   delay(1000);
}


void testfillcircles(uint8_t radius, uint16_t color) {
  for (int16_t x=radius; x < tft.width(); x+=radius*2) {
    for (int16_t y=radius; y < tft.height(); y+=radius*2) {
      tft.fillCircle(x, y, radius, color);
    }
  }
}

void testdrawcircles(uint8_t radius, uint16_t color) {
  for (int16_t x=0; x < tft.width()+radius; x+=radius*2) {
    for (int16_t y=0; y < tft.height()+radius; y+=radius*2) {
      tft.drawCircle(x, y, radius, color);
    }
  }
}

#22 Проекты » Создание фоторамок на Ардуино и TFT дисплеях (Arduino Nano и QVGA TFT) » 2016-10-20 13:04:41

Saddamko
відповідей: 0

Поскольку дисплейные модули изначально продаются, в большинстве случаев, с SD или microSD картоприемником, первым их применением у меня стало создание фоторамок.
(На самом деле, это у меня было из подсознания - подаренная девушкой покупная рамка успешно взорвалась после моей попытки установить внутрь аккумулятор с плохим контроллером заряда).

 Вот несколько для примера:

На основе модуля QVGA TFT display 320x240 ili9340 собрана такая фоторамка

Я использовал часы реального времени, Arduino Mini Pro, батарейный модуль, кнопку питания и сам дисплейный модуль
ramka3s.jpg


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

Ниже приведен код:

/*
* Commands:
 * T(00-59)(00-59)(00-23)(1-7)(01-31)(01-12)(00-99) - T(sec)(min)(hour)(dayOfWeek)(dayOfMonth)(month)(year) -
 * T - Sets the date of the RTC DS1307 Chip.
 *T0007002210115
* T004519 
 * Example to set the time for 25-Jan-2012 @ 19:57:11 for the 4 day of the week, use this command - T1157194250112
 * Q(1-2) - (Q1) Memory initialization  (Q2) RTC - Memory Dump  
 * R - Read/display the time, day and date
 */

#include <Adafruit_GFX.h>    // Core graphics library
#include "Adafruit_ILI9340.h" // Hardware-specific library

#include <SD.h>
#include <Wire.h>
#include "RTClib.h"
#include <SPI.h>

//#if defined(__SAM3X8E__)
//    #undef __FlashStringHelper::F(string_literal)
//    #define F(string_literal) string_literal
//#endif

// TFT display and SD card will share the hardware SPI interface..
#define TFT_RST 8
#define TFT_DC 9
#define TFT_CS 10
#define SD_CS 6
#define DS1307_I2C_ADDRESS 0x68  // This is the I2C address

// Arduino version compatibility Pre-Compiler Directives
#if defined(ARDUINO) && ARDUINO >= 100   // Arduino v1.0 and newer
  #define I2C_WRITE Wire.write 
  #define I2C_READ Wire.read
#else                                   // Arduino Prior to v1.0 
  #define I2C_WRITE Wire.send 
  #define I2C_READ Wire.receive
#endif

// Global Variables
byte zero;
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
byte test;
int command = 0;       // This is the command char, in ascii form, sent from the serial port     
int i;
long previousMillis = 0;        // will store last time Temp was updated
RTC_DS1307 rtc;
Adafruit_ILI9340 tft = Adafruit_ILI9340(TFT_CS, TFT_DC, TFT_RST);
File dir;

void setup(void) {
  Serial.begin(9600);
  Wire.begin();
  tft.begin();
  rtc.begin();
  
  if (! rtc.isrunning()) {
    Serial.println(F("RTC is NOT running!"));
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(__DATE__, __TIME__));
  }
//  
  Serial.print(F("Initializing SD card..."));
  if (!SD.begin(SD_CS)) {
    Serial.println(F("failed!"));
    return;
  }
  Serial.println(F("OK!"));
  printtime ();
  delay (1000);
  freeMem();
//  CheckCmd();
}

void loop() {

  File dir=SD.open("/");
  dir.rewindDirectory();
    while (true) {  

    File entry =  dir.openNextFile();
     if (! entry) {
       // no more files
       Serial.println(F("**nomorefiles**"));
//      break;
       dir.rewindDirectory();
     }
     // Print the 8.3 name
     Serial.print(entry.name());
     // Recurse for directories, otherwise print the file size
     if (entry.isDirectory()) {
       Serial.println(F("/"));
     } 
	 else{
       // files have sizes, directories do not
       Serial.print(F("\t\t"));
       Serial.println(entry.size(), DEC);
       bmpDraw(entry.name(),0,0);

       delay(3000);
     }
         entry.close();
        printtime ();  
    }  
    dir.rewindDirectory();
   
}

uint16_t freeMem() {
  char top;
  extern char *__brkval;
  extern char __bss_end;
  Serial.println( __brkval ? &top - __brkval : &top - &__bss_end);
}

#define BUFFPIXEL 20

void bmpDraw(char *filename, uint8_t x, uint8_t y) {

  File     bmpFile;
  int      bmpWidth, bmpHeight;   // W+H in pixels
  uint8_t  bmpDepth;              // Bit depth (currently must be 24)
  uint32_t bmpImageoffset;        // Start of image data in file
  uint32_t rowSize;               // Not always = bmpWidth; may have padding
  uint8_t  sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel)
  uint8_t  buffidx = sizeof(sdbuffer); // Current position in sdbuffer
  boolean  goodBmp = false;       // Set to true on valid header parse
  boolean  flip    = true;        // BMP is stored bottom-to-top
  int      w, h, row, col;
  uint8_t  r, g, b;
  uint32_t pos = 0, startTime = millis();

  if((x >= tft.width()) || (y >= tft.height())) return;

  Serial.println();
  Serial.print(F("Loading image '"));
  Serial.print(filename);
  Serial.println('\'');

  // Open requested file on SD card
  if ((bmpFile = SD.open(filename)) == NULL) {
    Serial.print(F("File not found"));
    return;
  }

  // Parse BMP header
  if(read16(bmpFile) == 0x4D42) { // BMP signature
    Serial.print(F("File size: ")); Serial.println(read32(bmpFile));
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile); // Start of image data
    Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
    // Read DIB header
    Serial.print(F("Header size: ")); Serial.println(read32(bmpFile));
    bmpWidth  = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if(read16(bmpFile) == 1) { // # planes -- must be '1'
      bmpDepth = read16(bmpFile); // bits per pixel
      Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
      if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed

        goodBmp = true; // Supported BMP format -- proceed!
        Serial.print(F("Image size: "));
        Serial.print(bmpWidth);
        Serial.print(F("x"));
        Serial.println(bmpHeight);

        // BMP rows are padded (if needed) to 4-byte boundary
        rowSize = (bmpWidth * 3 + 3) & ~3;

        // If bmpHeight is negative, image is in top-down order.
        // This is not canon but has been observed in the wild.
        if(bmpHeight < 0) {
          bmpHeight = -bmpHeight;
          flip      = false;
        }

        // Crop area to be loaded
        w = bmpWidth;
        h = bmpHeight;
        if((x+w-1) >= tft.width())  w = tft.width()  - x;
        if((y+h-1) >= tft.height()) h = tft.height() - y;

        // Set TFT address window to clipped image bounds
        tft.setAddrWindow(x, y, x+w-1, y+h-1);

        for (row=0; row<h; row++) { // For each scanline...

          // Seek to start of scan line.  It might seem labor-
          // intensive to be doing this on every line, but this
          // method covers a lot of gritty details like cropping
          // and scanline padding.  Also, the seek only takes
          // place if the file position actually needs to change
          // (avoids a lot of cluster math in SD library).
          if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
            pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
          else     // Bitmap is stored top-to-bottom
            pos = bmpImageoffset + row * rowSize;
          if(bmpFile.position() != pos) { // Need seek?
            bmpFile.seek(pos);
            buffidx = sizeof(sdbuffer); // Force buffer reload
          }

          for (col=0; col<w; col++) { // For each pixel...
            // Time to read more pixel data?
            if (buffidx >= sizeof(sdbuffer)) { // Indeed
              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0; // Set index to beginning
            }

            // Convert pixel from BMP to TFT format, push to display
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            tft.pushColor(tft.Color565(r,g,b));
          } // end pixel
        } // end scanline
        Serial.print(F("Loaded in "));
        Serial.print(millis() - startTime);
        Serial.println(F(" ms"));
      } // end goodBmp
    }
  }

  bmpFile.close();
  if(!goodBmp) Serial.println(F("BMP format not recognized."));
}

// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.

uint16_t read16(File f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

uint32_t read32(File f) {
  uint32_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read();
  ((uint8_t *)&result)[2] = f.read();
  ((uint8_t *)&result)[3] = f.read(); // MSB
  return result;
}

void printtime () {
    DateTime now = rtc.now();
    
 //   tft.fillScreen(ILI9340_BLACK);
    tft.setTextColor (ILI9340_RED,ILI9340_BLACK);
    tft.setTextSize (4);
    tft.setCursor(0,00);
    tft.print(now.year(), DEC);
    tft.print(F("/"));
    
    if (now.month() < 10)
      tft.print("0");  
    tft.print(now.month(), DEC);
    tft.print(F("/"));
    
    if (now.day() < 10)
      tft.print(F("0"));     
    tft.print(now.day(), DEC); 
    tft.println(F(""));
    
    tft.setCursor(0,280);
    tft.setTextColor (ILI9340_GREEN,ILI9340_BLUE);
    tft.setTextSize (5);
    
    if (now.hour() < 10)
      tft.print(F("0"));
    tft.print(now.hour(), DEC); 
    tft.print(F(":"));
   
    if (now.minute() < 10)
      tft.print(F("0"));
    tft.print(now.minute(), DEC);
    tft.print(F(":"));
    
    if (now.second() < 10)
      tft.print(F("0"));    
    tft.print(now.second(), DEC);
    tft.println();

    delay(5000);
}

void CheckCmd() {
     if (Serial.available()) {      // Look for char in serial que and process if found
      command = Serial.read();

      if (command == 84 || command == 116) {      //If command = "Tt" Set Date
       setDateDs1307();
      }
      Serial.println(command);     // Echo command CHAR in ascii that was sent
      }
      command = 0;                 // reset command 
      delay(100);
}

    void setDateDs1307()                
{
 
   second = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48)); // Use of (byte) type casting and ascii math to achieve result.  
   minute = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   hour  = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   dayOfWeek = (byte) (Serial.read() - 48);
   dayOfMonth = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   month = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   year= (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
   Wire.beginTransmission(DS1307_I2C_ADDRESS);
   I2C_WRITE(zero);
   I2C_WRITE(decToBcd(second) & 0x7f);    // 0 to bit 7 starts the clock
   I2C_WRITE(decToBcd(minute));
   I2C_WRITE(decToBcd(hour));      // If you want 12 hour am/pm you need to set
                                   // bit 6 (also need to change readDateDs1307)
   I2C_WRITE(decToBcd(dayOfWeek));
   I2C_WRITE(decToBcd(dayOfMonth));
   I2C_WRITE(decToBcd(month));
   I2C_WRITE(decToBcd(year));
   Wire.endTransmission();
}
 
// Gets the date and time from the ds1307 and prints result
void getDateDs1307()
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  I2C_WRITE(zero);
  Wire.endTransmission();
 
  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
 
  // A few of these need masks because certain bits are control bits
  second     = bcdToDec(I2C_READ() & 0x7f);
  minute     = bcdToDec(I2C_READ());
  hour       = bcdToDec(I2C_READ() & 0x3f);  // Need to change this if 12 hour am/pm
  dayOfWeek  = bcdToDec(I2C_READ());
  dayOfMonth = bcdToDec(I2C_READ());
  month      = bcdToDec(I2C_READ());
  year       = bcdToDec(I2C_READ());
}
 
 
 // Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}
 
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}

Підвал форуму