Suvartojamos energijos matuoklis

Šiame straipsnyje aprašysiu atskirą darbą, kuriame su RPI ir Arduino bei operaciniu stiprintuvu atliekamas kintamos formos srovės ir įtampos matavimas, įvertinamas statistinis duomenų išbarstymas ir rezultatai patiekiami WEB puslapyje.

Turinys. Darbo atskiros dalys:
1. Trumpas aprašymas.
2. Davikliai
3. Struktūrinė, principinė schemos bei ploštės konstruktyvas.
4. Arduino programos diagrama ir listingas, duomenų struktūra
5. RPI C programos listingas ir paleidimo aprašymas
6. PHP, JS listingai duomenų priėmimui ir atvaizdavimui.
7. Išvados.

1. Trumpas aprašymas.

2. Davikliai
3. Struktūrinė, principinė schemos bei ploštės konstruktyvas.
4. Arduino programos diagrama ir listingas.
Duomenų struktūra
Greitaveika
Reikia atsakyti į klausimą: Kaip greit galima fiksuoti duomenis? Vienas iš išeities argumentų yra Arduino perdavimo greitis. Šiuo atveju naudojame USB to Serial chipą Arduino plokštėje CH341. Pagal Arduino manualą didžiausias perduodamas greitis yra 115200 bit/sek.. Duomenų paketas sudaro 8 reišmes atskirtas SPACE 20H simboliu ir milis() funkcijos grąžinama reikšme (integer) milisekundes. Kol kas realizuota viena iš aštuonių duomenų yra FLOAT, kitos Integer. Taigi maksimalus eilutės ilgis: 7×4(INT 0…1024) + 4(FLOAT) + 7 (20H) + milis()+ 2(ODH, OAH – eilutės pabaiga):
xxxx x.xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx OAH ODH
Dar vienas išeities argumentas yra analoginio keitiklio greitaveika. Žr. teorinius parametrus: TODO.

Sunaudojama vieta kaupiklyje, duomenų bazės įrašų kiekis

5. RPI C programos listingas ir paleidimo aprašymas

Prie RPI jungiames WiFi, putty, IP adresas: 192.168.3.95 (pi/vejojegaines), hostname sratavimas – kadangi IP adresas nėra fiksuotas, bandau su putty jungtis naudodamas hostaname vietoj IP adreso. Neveikia. TODO kodėl?. Trūksta proftpd. Instaliuojam: apt-get install proftpd. Pasiūlo atnaujinti: apt-get update. bandau dar. Padarė. Nenurodžius katalogo, sujungia šakniniame kataloge. Taisau: nuimu kompentarą DefaultRoot ~ eilutei. /etc/proftpd/proftpd.conf faile. Perstartuoju proftpd: /etc/init.d/proftpd restart

sukuriame išeities failą. pasinaudosime ankstesniu darbu ir nukopijuosime kodą iš:

http://vejas.defas.lt/wp-content/uploads/2018/02/ziogas.c

ziogas.c pervardiname failu sratavimas.c

Pakeičiam prisijungimo prie mysql duomenis:
const char *user=”sratavimas”;
const char *password=”sratavimas”;
const char *database=”sratavimas”;

kompiliavimo eilutė:

gcc -o sratavimas.o -I /usr/include/ `mysql_config --cflags --libs` sratavimas.c

Gaunu klaidą:

sratavimas.c:10:10: fatal error: mysql/mysql.h: Toks failas ar aplankas neegzistuoja
#include <mysql/mysql.h> //used by mysql

sukompiliuojam:

apt-get install mariadb-server

po šio instaliavimo konfigūruojam mysql serverį komanda:

root@sratavimas:/home/pi# mysql_secure_installation

Čia sukuriame root slaptažodį (sratavimas) ir pašaliname anonymous vartotoją, leidžiam prisijungti nuotoliniu, taisome failą: /etc/mysql/mariadb.conf.d/50-serv.cnf

#bind-address = 127.0.0.1

papildomai instaliuojame:

apt-get install libmariadb-dev
apt-get install libmariadb-dev-compat

dabar failą mysql.h randa:
/usr/include/mariadb/mysql.h
/usr/include/mariadb/server/mysql.h
Pataisome kodą sratavimas.c vietoj mysql įrašydami mariadb/mysql.h

Sukuriame duomenų bazę sratavimas, sukuriame vartotoją sratavimas, jam suteikiame teisę prie DB sratavimas:

MariaDB [(none)]> grant all on sratavimas.* to sratavimas identified by 'sratavimas';

Joje sukuriame dvi lenteles: Duomenys ir Forma. Jų struktūra:

CREATE TABLE `sratavimas`.`Duomenys` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`A0` int(10) unsigned NOT NULL COMMENT 'Srove',
`A1` int(10) unsigned NOT NULL COMMENT 'Itampa',
`TS` int(10) unsigned NOT NULL COMMENT 'Timestamp from Arduino',
`Laikas` datetime NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2282 DEFAULT CHARSET=utf8mb4;
CREATE TABLE `sratavimas`.`Forma` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`KreivesTaskai` varchar(6144) NOT NULL,
`TS` int(10) unsigned NOT NULL,
`Laikas` datetime NOT NULL DEFAULT current_timestamp(),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4;

 

Dabar kompiliavimas vyksta be klaidų. pataisysiu kodą formuodamas dvi mysql insert komandas: viena kas sekundę praneša srovės ir įtampos reikšmes ir yra trumpa, kita ilga ir kas minutę perduoda įtampos ir srovės kreivių formą. Maksimalus eilutės ilgis= (4(vieno matavimo reikšmė 0…1023)+2(‘, ‘))* MAsize (const unsigned int MAsize=96; – arduino kodas)=1024*6=6144 baitų. sratavimas.c faile užknisa skaičiuoti, kiek yra raidžių eilutėje. Tam yra online priemonė: https://www.lettercount.com/

Trumpos eilutės formatas:

insert into sratavimas.Duomenys (A0, A1, TS) values (128, 0, 1006907 );

Ilgos eilutės formatas:

insert into sratavimas.Forma (KreivesTaskai, TS) values ('528, 528, 528, 529, 528, 529, 529, 529, 529, 528, 529, 529, 529, 528, 528, 528, 528, 528, 528, 527, 528, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 528, 527, 527, 528, 528, 528, 528, 528, 528, 528, 528, 528, 528, 529, 528, 529, 528, 528, 529, 529, 529, 529, 529, 528, 528, 528, 528, 528, 528, 528, 527, 528, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 527, 528, 528, 528, 528, 528, 528, 528, 528, 529, 528, 528, 529, 529, 528, 529, 529, 528, 529, ', 1005867);

taigi:

 

6. PHP, JS listingai duomenų priėmimui ir atvaizdavimui.

Konfigūruojame proftps, kad pasiektume katalogą /var/www/html/ kuriame leidžiamas apache2. Taisome failą /etc/proftpd/proftpd.conf:

 

Pagal nutylėjimą nėra suinstaliuota PHP: Instaliuojam:

 

apt install libapache2-mod-php
apt-get install php7.3-mysql

taisome /etc/php/7.3/apache2/php.ini:

short_open_tag=on

 

Atsarginę SD kortelės kopiją darau su win32diskimager programa. Matomai ji kopijuoja sektoriais, ne failais, iš 16GB kortelės gavosi 15GB atvaizdo failas. Bet kompresuojasi gerai. Archyvas sudaro 4GB failą.

 

7. Bandymai ir išvados.

 

 

Maksimalios galios taško nustatymas

Angliškai skambėtų PPT – Power Point Tracking (dėkui Rimui V. už termino „atradimą”).

Tai turėtų būti šio darbo esmė.
Kadangi didžiausia dabartinė problema suprojektuoti galingą (10kW) reguliatorių siejantį generatorių kaip energijos šaltinį ir fiksuotą apkrovą kaip generatoriaus terminatorių. Problema slypi nestabiliame schemos darbe, kai įvyksta reguliavimo elemento grandinės perdegimas. Tai beveik visada įvyksta generuojant didesnius galingumus. Kokia tai riba – nenustatyta, nes ir matavimo reikšmės nėra kalibruotos. Vienas iš laboratorinių bandymų parodė, kad net ~1,5kW generatorius sukamas 500W variklio „sugeba sudeginti” 1200V 60A reguliatoriaus IGBT tranzistorių. Tik LC filtras įmontuotas tarp generatoriaus ir reguliatoriaus pašalino šią problemą. Tai parodo, kaip sudėtinga įvertinti patį generatorių su savo „triukšmais”.
Taigi todėl noriu pradėti nuo pradžios, siekiant teisingai suprojektuoti reguliatoriaus schemą. Vienas iš trūkumų yra apsaugų nuo neatsargus trumpinimo ar srovės perkrovos nebuvimas. Kita vertus dingtelėjusi mintis, kad atsisakius filtruojančio kondensatoriaus reguliatoriaus išėjimo grandinėje ir galimai turima ši bėda verčia sugrįžti prie šios grandinės perprojektavimo. Taigi pradėkim naujai. Paanalizuokime, ką yra nuveikęs šiuo klausimu likęs pasaulis. Žemiau keletas nuorodų.
Pirmas pasitaikęs VGTU magistrinis darbas kurio antrame skyriuje nagrinėjama MAKSIMALIOS GALIOS TAŠKO SEKIMO (MGTS) METODO ANALIZĖ. Patiko idėja valdyti tranzistorius dalinis sinuso bangos signalu. Imam domėn MGT reguliavimo metodus P&O (angl. Perturb-and-observe), IncCond (angl. Incremental Conductance).

Duomenų replikavimas

Tikslas kaupti duomenis atsarginiame serveryje su tikslu pasiekti juos net ir tada, kai jėgainės duomenys nepasiekiami. Jėgainės MySQL master serveris kaupia duomenis replikavimui. Juos pasiima centrinis slave serveris. Slave serveris bus defas.lt MySQL serveris. Patikrinkime abejų serverių id. Jie turi būti skirtingi. Aprašomas my.cnf faile MySQL serverio atveju.

[mysqld]
server-id=2

ir MariaDB MySQL serverio versijos atveju server-id užduodamas serverio paleidimo komandinėje eilutėje:

/usr/local/mysql/bin/mysqld_safe --datadir=/home/mysql/ --server-id=2 --pid-file=/var/run/mysql/mysql.pid &

server-id sužinoti galima komanda:

SELECT @@server_id

defas.lt serveris grąžina reikšmę 2, jėgainės serveris reikšmę 1.

MySQL aprašyme reikalauja, kad keli naudojami slave serveriai privalo turėti skirtingus server-id. Galbūt master ir slave gali turėti tuos pačius? Reikėtų pabandyti.

Slave serveryje nurodome, master konfigūraciją komanda:

CHANGE MASTER TO 
MASTER_HOST='90.140.218.158', 
MASTER_USER='replika', 
MASTER_PASSWORD='replika', 
MASTER_LOG_FILE='recorded_log_file_name', 
MASTER_LOG_POS=recorded_log_position;

Pastaba: pasikeitus IP adresui, šią komandą turėsime pastoviai perleidinėti. Tai atliks ActivateFactory() funkcija:

Function ActivateFactory() {
 if (isset($_REQUEST['AJIP'])) {
  $_SESSION['AJIP']=$_REQUEST['AJIP'];
  $this->server2=$_REQUEST['AJIP'];
  $this->query_to_res("stop slave");
  $this->query_to_res("CHANGE MASTER TO   MASTER_HOST='".$_REQUEST['AJIP']."',MASTER_USER='replika',MASTER_PASSWORD='replika',MASTER_LOG_FILE='recorded_log_file_name',MASTER_LOG_POS=recorded_log_position;");
  $this->query_to_res("start slave");
 }
}

Padarome DB vejojegaines duomenų kopiją slave serveryje: konfigūraciją komanda:
mysqldump -u vejojegaines -p vejojegaines>20181209.sql

FPT perduodame gautą failą į defas.lt serverį. Po to sukuriame defas.lt serveryje DB Duomenys ir komandine eilute sukeliame duomenis iš sql failo.

mysql -u arturas -p vejojegaines<20181209.sql

Taigi: jėgainės serveryje redaguojame /etc/mysql/mycnf failą:

server-id               = 1
log_bin                 = /var/log/mysql/mysql-bin.log
expire_logs_days        = 10
max_binlog_size         = 100M
binlog_do_db            = vejojegaines

Naujai paleidžiame serverį: sudo service mysql restart

Paleidus slave serverį gaunamas klaidos pranešimas: Master command COM_REGISTER_SLAVE failed: Access denied for user ‘replika’@’%’ (using password: YES) (Errno: 1045). Taisome problemą resetindami slave serverį mysql’inėmis komandomis: reset slave; stop slave; start slave;

Taip pat suteikiame replikavimo teises replika vartotojui master serveryje. Tą padaryti galima su root/root mysql vartotoju:

GRANT REPLICATION SLAVE ON *.* TO replika identified by 'replika';
flush privileges;

Vidutinių reikšmių matavimas ir perdavimas į DB

Nerandant metodo, kaip momentines analogines reikšmes versti į apibendrintas (Užduotis: tris sinusoidės absoliučius taškus su X ir Y koordinatėmis transformuoti į sinusoidės amplitudę ir kampinį greitį), supaprastiname užduoties sprendimą ieškodami minimalios ir maksimalios sinusoidės taškų laike ir čia išskaičiuojame jos amplitudę. Matavimo laikas preliminariai imamas lygus vienai sekundei. Ši prielaida siejama su visos sistemos inertiškumu. Nesant jo įvertinimo, laikoma, kad vienos sekundės intervale esminių pokyčių nevyksta. taigi matavimo principas:

Avid ir yra norima žinoti reikšmė. Tai nėra efektyvioji srovės ar įtampos reikšmė, o tik signalo amplitudė. Efektyvioji reikšmė turėtų būti išskaičiuojama pagal formulę:

Aef=Avid/SQRT2

Tai tas pats kaip apskritimo ir tos pačios kraštinės kvadrato plotų santykis. Efektyvioji reikšmė bus perskaičiuojama toliai, neužkraunant Arduino procesoriui matematinių veiksmų su kableliu. Taigi į Arduino kodą įterpiame:

const int MatSkaicius=20;
...
unsigned int A0mom, A1mom, A2mom, A3mom, A4mom, A5mom;
unsigned int A0min, A1min, A2min, A3min, A4min, A5min;
unsigned int A0max, A1max, A2max, A3max, A4max, A5max;
unsigned int A0vid, A1vid, A2vid, A3vid, A4vid, A5vid;
.....
A0max=0; A1max=1; A2max=0, A3max=0; A4max=0, A5max=0;
A0min=1023; A1min=1023; A2min=1023, A3min=1023; A4min=1023, A5min=1023;
for (i=0; i<MatSkaicius; i++) {
  A0mom=analogRead(A0);if (A0mon>A0max) {A0max=A0mom;}; if (A0mon<A0min) {A0min=A0mom;};
  A1mom=analogRead(A1);if (A1mon>A1max) {A1max=A1mom;}; if (A1mon<A1min) {A1min=A1mom;};
  A2mom=analogRead(A2);if (A2mon>A2max) {A2max=A2mom;}; if (A2mon<A2min) {A2min=A2mom;};
  A3mom=analogRead(A3);if (A3mon>A3max) {A3max=A3mom;}; if (A3mon<A3min) {A3min=A3mom;};
  A4mom=analogRead(A4);if (A4mon>A4max) {A4max=A4mom;}; if (A4mon<A4min) {A4min=A4mom;};
  A5mom=analogRead(A5);if (A5mon>A5max) {A5max=A5mom;}; if (A5mon<A5min) {A5min=A5mom;};
}
A0vid=(A0max-A0min)/2;
A1vid=(A1max-A1min)/2;
A2vid=(A2max-A2min)/2;
A3vid=(A3max-A3min)/2;
A4vid=(A4max-A4min)/2;
A5vid=(A5max-A5min)/2;

dat[3]=lowByte(A0vid); dat[4]=highByte(A0vid);
dat[5]=lowByte(A1vid); dat[6]=highByte(A1vid);
dat[7]=lowByte(A2vid); dat[8]=highByte(A2vid);
dat[9]=lowByte(A3vid); dat[10]=highByte(A3vid);
dat[11]=lowByte(A4vid); dat[12]=highByte(A4vid);
dat[13]=lowByte(A5vid); dat[14]=highByte(A5vid);

Taip pat vidurkinami vėjo greičio ir generatoriaus apsisukimo greičio parametrai:

...
unsigned int A0vid, A1vid, A2vid, A3vid, A4vid, A5vid;
unsigned long VGRus, GDAus, VGRusvid, GDAusvid;
...
VGRusvid=0; GDAusvid=0;
...
for (i=0; i<MatSkaicius; i++) {
...
VGRus=VejoGreitis_us/MatSkaicius; VGRusvid=VGRusvid+VGRus;
GDAus=GenDaznis_us/MatSkaicius; GDAusvid=GDAusvid+GDAus;
...
}
...
CH=VGRusvid>>16; CL=VGRusvid;
...
GH=GDAusvid>>16; GL=GDAusvid;
...

Koreguotas visas failas saugomas pavadinimu VejasPociunai.ino
Jį galima rasti ir čia.

Žiogas

Vėjo jėgainės valdiklio atskira realizacija, koreguojanti vėjo kryptį nuo generatoriaus apsisukimų.

Schema: Ziogas_schema, plokštė
Ziogas_plokste.
Rpi suinstaliuotas OS, panašiai, kaip ir VJV (vėjo jėgainės valdiklio. user’is pi/vejojegaines, root be slaptažodžio). Šis Rpi turi WLAN, nenaudosime GSM ryšio. Tačiau paimsime duomenis iš Arduino, kaip ir VJV atveju. Taigi,
ruošiame kompiliavimui tokį pat failą, kaip ir VJV Rpi. Perkopijuojame iš VJV failą test2.c ir naudojame komandinę eilutę:

gcc -o test2.o -L/usr/lib/test1 -lmysqlclient -I/usr/local/include -L/usr/local/lib -lwiringPi test2.c

Po kurio laiko test2.c failas stipriai modifikuotas buvo pervadintas į failą ziogas.c ir kompiliuojamas jau jis, gaunant vykdomąjį failą ziogas.o. Gaunu pranešimą mysql.h – no such file. Instaliuojame mysql:

apt-get install mysql-server mysql-client

Pridedam ir:

 apt-get install libmysqlclient-dev

Nepanikuojam, jei gaunam pranešimą libmysqlclient-dev is missing or absolete. Pasirodo paketo vardas pasikeitė. Dabar reikia naudoti:

apt-get install default-libmysqlclient-dev

Paruošiame darbui su SSH. Pagal nutylėjmą neveikia. Raspi-config čia tinkama. Kažkas buvo susimaišęs su sertifikatų failais – nepavykdavo prisijungti. Pagalba iš googles:

pi@raspberrypi ~ $ sudo rm -f /etc/ssh/ssh_host*
pi@raspberrypi ~ $ sudo dpkg-reconfigure openssh-server

Neveikia:
spi: nebuvo kontakto plokštėje MOSI signalas nenukeliaudavo iji Rpi. Dabar nėra CLK signalo, arba nepamatuojamas oscilu. proftpd: suinstaliuojame komanda

apt-get install pro-ftpd

Pajungus išorinį +12V maitinimą impulsai D12 pin’e sumažėja iki 1V. Nuo USB maitinimo – normalūs

Arduino Nano modulio, naudojamo čia išvadai:
nano
Nano vaizdas iš viršaus:

ir iš apačios

Panašu SPI neveikia su Arduino. Pagooglinau ir radau tokį atsakymą:Arduino Nano is based on the ATmega168/328 chip, which does support SPI in hardware. Ką darom? bandom paimti duomenis per USB. Pajungus USB laidą Rpi-Arduino su komanda lsusb randame įrenginį

Bus 001 Device 004: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter

. Usman rašo: I was wondering if I can find any helpful materials or tutorials on how to read data and transfer data from one device to another Raspberry PI device using USB ports. In short it would be reading data through USB. – keista, pasirodo nėra sunku.

Pabandysime perduoti duomenis iš Arduino per USB nuoseklų portą realizuotą USB adapterio būdu. Pasitikrinam, kaip atrodo Arduino prijungtas prie Rpi per USB sąsają. Pažiūriu užkrovimo informacinį failą užklausdamas:

dmesg |grep tty

ir gaunu atsakymą:

[ 5.785336] usb 1-1.2: ch341-uart converter now attached to ttyUSB0

Sukursime DB lentelę, į kurią periodiškai įrašinėsime duomenis iš nuoseklaus porto. DB pavadinimas ziogas, lentelės pavadinimas Duomenys ir slaptažodis – ziogas. Lentelės laukai:
id – identifikatorius
VK – vejo kryptis AD keitiklio reikšmė. integer 0…1023. A7 Arduino įvadas
GD1 – generatoriaus dažnis realizuotas per optroną. integer – 4 baitai. D2 Arduino įvadas
GD2 – generatoriaus dažnis realiz. per komparatorių. integer – 4 baitai. D3 Arduino įvadas
KP – korekcija potenciometru – kiek nusukti vėjo krypties daviklio reikšmę. A0 Arduino įvadas
K0 – vėjo krypties daviklio kalibravimas. integer 0…1023. A1 Arduino įvadas
GD2 – generatoriaus analoginė reikšmė realiz. per operacinį stiprinuvą. integer – 4 baitai. A5 Arduino įvadas
TS – milis() funkcija iš Arduino, rodanti paketo laiką. Integer tipas.
Data – duomenų fiksavimo data ir laikas. Duomenų tipas timestamp su CURRENT_TIMESTAMP numatytąja reikšme

Sukuriamas mysql root slaptažodis ‘ziogas’.

/usr/bin/mysqladmin -u root password 'ziogas'

Sukuriama duomenų bazė ir suteikiama useriui ziogas priejimas prie jos:

MariaDB [(none)]> create database ziogas;
Query OK, 1 row affected (0.00 sec)
MariaDB [(none)]> grant all on ziogas.* to ziogas identified by 'ziogas';

Ir vėl pasikeitimai: failas /etc/mysql/my.cnf dabar linkintas o leisti išorinį prisijungimą galima užkomentuojant eilutę faile /etc/mysql/mariadb.conf.d: #bind-address=127.0.0.1

Tolimesnės užduotys:

DB struktūra:

DROP TABLE IF EXISTS `ziogas`.`Duomenys`;
CREATE TABLE  `ziogas`.`Duomenys` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'identifikatorius',
  `VK` int(10) unsigned NOT NULL COMMENT 'vejo kryptis AD keitiklio reikšmė. integer 0...1023. A7 Arduino įvadas',
  `GD1` int(10) unsigned NOT NULL COMMENT 'generatoriaus dažnis realizuotas per optroną.',
  `GD2` int(10) unsigned NOT NULL COMMENT 'generatoriaus dažnis realiz. per komparatorių.',
  `KP` int(10) unsigned NOT NULL COMMENT 'korekcija potenciometru - kiek nusukti vėjo krypties daviklio reikšm',
  `K0` int(10) unsigned NOT NULL COMMENT 'vėjo krypties daviklio kalibravimas',
  `GV` int(10) unsigned NOT NULL COMMENT 'Analogine generatoriaus itampa',
  `TS` int(10) unsigned NOT NULL COMMENT 'data ir laikas, duomenų fiksavime',
  `Date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Data ir laikas mysql irase',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=77096 DEFAULT CHARSET=utf8mb4;

C+ failas ziogas.c. Padaryti vykdomuoju.
Pasiaiškinti, kodėl programa lūžta atjungus USB sąsają.
Arduino kodas ziogas projekte:
Pavyko perduoti duomenis per USB sąsają. Perdavimo greitis: 2ms/paketas.
Kaista transformatorius. Kodėl?
Kaista 7805 stabilizatorius. Kiek srovės naudoja visa sistema?
Patikrinti, ar veikia Apache. Ne. Suinstaliuojam pagal nuorodą: http://vejas.defas.lt/?p=39.
Perkelti duomenų nuskaitymo php failą. vgreitis.php.index.php


Problema: kaista maitinimo stabilizatorius IC U1 L7805, maitinanti Rpi. Pakeista iškirptu NB plokštės fragmentu, žr. foto nuotrauką.

.

Mėlynas laidas +12V, Geltonas GND, oranžinis +5V. Valdymo IC TPS51020. Enable  – 20kOm varža sujungta EN (9pin TPS51029) ir VIN (24pin TPS51020).

 

Išjungti RPI mygtuko paspaudimu. Radau nuorodą: shutdown-restart. Instaliavimas:

sudo apt install python3-gpiozero
sudo mkdir -p /usr/local/bin
chmod +x shutdown_button.py
sudo cp shutdown_button.py /usr/local/bin
sudo cp shutdown_button.service /etc/systemd/system
sudo systemctl enable shutdown_button.service
sudo systemctl start shutdown_button.service

jei reikia atsisiųsti kodą: nuoroda: scruss/shutdown_button.

Mygtukas jungiamas tarp GPIO 27 ir GND kontaktų. Jeigu Rpi turi 40 kontaktų GPIO kontaktų grupę, naudojama septinta skaičiuojant nuo kairės kontaktų pora, kaip parodyta paveikslėlyje.

Naudojimas:

Rpi perkraunamas, jei mygtukas laikomas paspaustas daugiau, nei dvi sekundės, bet mažiau nei penkios sekundės. Rpi išjungiamas palaikius nuspaustą mygtuką ilgiau, nei penkios sekundės. Laikų nustatymai, kaip ir mygtuko kontakto numerio parinkimas gali būti pakeisti python shutdown_python.py faile.

Perkelti registracijos failą. Failas /etc/host2mysql. Jį pakoreguoju, išmesdamas eilutes susijusias su 3G modemo inicializacija, palieku tik paskutinę eilutę ir HOST vardą keičiu į ziogas. Jo turinys atrodo taip:

echo "--------------------------"
sudo ifconfig wlan0 |grep "inet " |awk -F ":" '{print $1}'| awk '{print "insert into hostai (host,IP) values(\x27ziogas\x27,\x27" $2 "\x27)" }' |mysql -hdefas.lt -uvejas -p******** VJserver

dar įrašau į crontab’ą eilutę, kad kas penkiolika minučių sistema padarytų įrašą defas.lt serveryje komanda crontab -e:

0,5,10,15,20,25,30,35,40,45,50,55 * * * * /etc/host2mysql >>/var/log/crontab.log

Aplikacijos ziogas.o automatinis paleidimas.

Įrašomos dvi paleidimo eilutės /etc.rc.local faile. sleep komandą rašau pagal pirmą VJV projektą – nespėdavo pasileisti mySQL’as. Ten būdavo sleep 100. Čia užteko reikšmės 30, kas reiškia 30 sekundžių uždelsimą, prieš programos startą, po OS sistemos užsikrovimo.

sleep 30
sudo /home/pi/ziogas.o &

Rpi programos kodas:ziogas.c
Parašyti finalinį koregavimo algoritmą.
Pradžiai pavaizduosiu vėjo krypties priklausomybę nuo vėjo greičio esant koregavimui. Koregavimas realizuotas Arduino programos algoritmu:

int VKKoregavimas(int VK, int VG) {
  signed int KOR;
  unsigned long x, A;
  unsigned int a;
  float y,z, P, R, PX,KPOT, XA,XC, XV, Y, B;
  if (VGUS<VGUSmin) {
    KOR=VGUS*(VKmax-VKmin)/4/VGUSmin/(1+((512-POT)/512));
    P=VGUS; R=VGUSmin-VGUS;
    KORmax=(VKmax-VKmin)/4;
    KPOT=VGUSmin;  
    PX=512-POT;  
    PX=PX/512;  
    KPOT=KPOT*PX;
    B=VGUSmin-VGUS+KPOT;
    if (B<0) {B=0;} Y=VGUSmin+KPOT; XA=B; XC=Y; y=B/Y; KOR=y*KORmax; if (VK>Puse) return VK-KOR; else return VK+KOR;
  } else return VK;
}

Ši funkcija turi du argumentus: vėjo kryptį VK ir generatoriaus greitį VG, o grąžina koreguotą vėjo kryptį VKO. Arduino programoje algoritmas realizuotas paprastais aritmetiniais veiksmais, nes surašius į ilgą formulę, rezultatas būna nenuspėjamas. Galbūt reikėtų visus argumentus paversti į FLOAT tipo, pabandysiu vėliau.
Algoritmo principas parodytas paveiksle:

Algoritmas:

Procedūra:

int VKKoregavimas(int VK, int GG) {
  int KOR;
  float y, PX,KPOT, XV, Y, B;
  if (GGUS<GGUSmin) {
    //KOR=GGUS*(VKmax-VKmin)/4/GGUSmin/(1+((512-POT)/512));
    KORmax=(VKmax-VKmin)/4;
    KPOT=GGUSmin;  
    PX=512-POT;  
    PX=PX/512;  
    KPOT=KPOT*PX;
    B=GGUSmin-GGUS+KPOT;
    if (B<0) {B=0;} Y=GGUSmin+KPOT; y=B/Y; KOR=y*KORmax; if (VK>Puse) return VK-KOR; else return VK+KOR;
  } else return VK;
}

Nulinti GGUS skaitliuką, jei nėra pertraukimo (timeout funkcija) Arduino modulyje.
Įvedu tikrinimą pagrindinėje programoje: jei generatoriaus periodo laikas didesnis nei trigubas, tarkime, kad generatorius stovi ir GGUS kintamąjam priskirkim maksimaliai didelę reikšmę.

if ((micros()-GGUS_prev)>2*GGUS) {GGUS=-1;}

TODO:

Atskirti valdymo svetainėje (php) atskiras jėgaines pagal HOST vardą.
Padaryti atsarginę Rpi OS kopiją.
Įdėti funkciją truncate Duomenys ir duomenų perkopijavimą.
Apvali vejo krypties diagrama. Dalinai atlikta. chart.js tipas doughnut.
Pakeisti DB, kad rodytų išduodamą koreguotą vėjo kryptį
Pataisyti vėjo krypties daviklį: yra ‘mirtina’ zona, kur nesikeičia įtampa, keičiant kryptį.
Dėžė – konstrukcija, sugalvoti. Nepamiršti išvesti matavimo taškų

JS grafike po ‘DB klaida’ pranešimo stabdyti arba automatiškai paleisti duomenų perdavimą, gerai būtų mirksintis rutuliukas, skirtingų salvų – dirba ar nedirba
Jei lūžta programa, ją reikia iš naujo pakelti. Gal čia Goga padės?
Resetinti MySQL duomenis, kas kiek laiko.
Pasiruošimas deryboms. Argumentai: GSM ryšys – mėnesinis mokestis, aptarnavimas – naujos savybės, aprašymas (laikmena, ar popierius)

Pirmasis bandymas lauke pareikalavo prisijungimo prie kito WLAN. Pašarinau savo mob. tel. su SSID AndriodAP_art, psw: aaaaaaaaaa. WLAN tinklai konfigūruojami /etc/wpa_supplicant/wpa_supplicant.conf faile. Daugiau info: https://www.raspberrypi.org/documentation/configuration/wireless/wireless-cli.md

paleisti naujai wlan0: ifconfig wlan0 down ir atitinkamai up.

perkonfigūruoti komanda:  wpa_cli -i wlan0 reconfigure

Tarp kitko eth0 interfeiso adresas 192.168.2.177 (192.168.2.57 – wlan0 ir tai darbe). Bet jėgainė į uzsakymų programą neprisiduoda. Užkomentinam dhcpd.conf faile wlan fiksuotus adresus. ir pašalinam eth0 kaip gataway: route del default eth0.

Dar pastebėjimas – bloga data – nesuinstaliuotas ntpdate paketas. Kalam: apt-get install ntpdate. Jei gavom klaidą: 404 Not Found [IP: 93.93.128.193 80], paleidžiam apt-get update komandą.

Duomenų srautas

Netikėtai nutrūko mobilaus interneto paslauga. Iškilo klausimas, kokį srautą generuoja duomenų grafiko perpiešimas. Suinstaliuotas iptraf paketas į Rpi.
parodytas srautas su iptraf paslauga ir grafiko atvaizdavimas viename įrenginyje generavo 38kbit/sek. srautą. Pridėjus dar vieną įrenginį su grafiko srauto vaizdavimu gavosi 52 kbit/sek. Atjungus įrenginius srautas sumažėjo iki 28kbit/sek. nedidelės matematinės manipuliacijos rodo

(52-27)/2=12,5kbit/sek duomenų srautas vieno grafiko dinaminiam atvaizdavimui

.

TODO: Gerai būtų automatiškai stabdyti duomenų perdavimą – reikia mygtuko grafiko vaizdavimo puslapyje.

Ką daryti, jei neveikia?

Prijungti USB kabelį – įsitikinti ar detektuoja Arduino Procesorių – įrenginių tvarkytuvėje turi atsirasti COM prievadas.
Pajungti LAN kabelį – Rpi turi atsakyti į ping paketą ir jungtis 192.168.2.177 fiksuotu LAN adresu su SSH protokolu (naudoju Putty programą).
Patikrinti megabaitų likutį http://mano.tele2.lt svetainėje. 2018.01.15 nustojo veikti valdiklio registracija MySQL į centrinį serverį. Per 15 dienų išnaudota 3GB duomenų.

Rpi programos kodas

Kompiliavimo eilutė

gcc -o test3.o -lmysqlclient -I/usr/local/include -L/usr/local/lib -lwiringPi test2.c

Programos kodas:

/*****Configures an Raspberry Pi as an SPI master and demonstrates bidirectional communication with an***/
#include <mysql/mysql.h>        //used by mysql
#include              //used by mysql
#include 
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include 
#include 
#include              //used by string
//#include 
/*******Declare Global Variables*****************************/
unsigned short int spiTxRx(char txDat);
int fd;
unsigned char AR_command[]={0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
//AR_command antras baitas nurodo siunciamos komandos ilgi be pirmo ir antro baitu jis uzpildomas siunciant seka
unsigned char AR_Komanda[512];
unsigned int AR_Komanda_Size;
unsigned char AR_command1[] = {0x20, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12};
unsigned char spi_bitsPerWord;
unsigned char spi_mode;
struct connection_details{char *server;char *user;char *password;char *database;};
MYSQL* mysql_connection_setup(struct connection_details mysql_details){// first of all create a mysql instance and initialize the variables within
        MYSQL *connection = mysql_init(NULL); // connect to the database with the details attached.
        if (!mysql_real_connect(connection,mysql_details.server, mysql_details.user, mysql_details.password, mysql_details.database, 0, NULL, 0)) {
                printf("Conection error : %s\n", mysql_error(connection));exit(1);
        }
        return connection;
}
MYSQL_RES* mysql_perform_query(MYSQL *connection, char *sql_query){
        if (mysql_query(connection, sql_query)) {// send the query to the database
                printf("MySQL query error : %s\n", mysql_error(connection));
                exit(1);
        }
        return mysql_use_result(connection);
}
struct connection_details mysqlD;
MYSQL *conn;                            // the connection
MYSQL_RES *res;                         // the results
MYSQL_ROW row;                          // the results row (line by line)
/**********************************************************
Main
    Setup SPI
    Open file spidev0.0 (chip enable 0) for read/write access with the file descriptor "fd"
    Configure transfer speed(1MHz)
***********************************************************/
unsigned short int resu[512];
int main (void){
    mysqlD.server = "localhost";                // where the mysql database is
    mysqlD.user = "vejojegaines";               // the root user of mysql
    mysqlD.password = "vejojegaines";           // the password of the root user in mysql
    mysqlD.database = "vejojegaines";           // the databse to pick
    conn = mysql_connection_setup(mysqlD);      // connect to the mysql database
    unsigned char result[20];
    unsigned char buffH[1];
    unsigned char buffL[1];
    fd = open("/dev/spidev0.0", O_RDWR);
    unsigned int speed =100000;
    ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    unsigned short int i;
    unsigned short int j=0;
    unsigned short int jmax=30;
    unsigned short int TS=100;
    unsigned short int TS_Prev=100;
    unsigned short int *TSa2Point;
    unsigned char qu[255];
    char *lai;
    unsigned int retx;
    unsigned int iii;
    unsigned int iiii;
    unsigned short int DisableWork=0;
    unsigned short int DisableWorkPrevious=0;
    unsigned char Komanda;
    void KomandosVykdymas();
    void LokalusDarbas();
    unsigned int id;
    char *pChar;
    while (1) {
        res = mysql_perform_query(conn, "select id, Komanda, Atlikta from komandos where Atlikta=0 order by ModData asc limit 1");
        while ((row = mysql_fetch_row(res))!=NULL) {
            for (iiii=0; iiii<strlen(row[1]); iiii=iiii+2) {
                AR_Komanda[iiii/2]=hex_char_to_bin(row[1][iiii])*16+hex_char_to_bin(row[1][iiii+1]);
            }
            AR_Komanda_Size=strlen(row[1])/2;
            if (atoi(row[2])==0) {DisableWork=1;} else {DisableWork=0;}
            if (DisableWork!=DisableWorkPrevious) {
                //printf("Darbo rezimas: %d\n", DisableWork);
                DisableWorkPrevious=DisableWork;
            }
            id=atoi(row[0]);
        }
        mysql_free_result(res);
        if (DisableWork==1) {
            KomandosVykdymas();
            sprintf(qu, "update komandos set Atlikta=1 where id=%d", id);
            res = mysql_perform_query(conn, qu);
            mysql_free_result(res);
            DisableWork=0;
          } else {
            //LokalusDarbas();
        }
        LokalusDarbas();        //testavimui
        usleep(1000000);//sekundes uzdelsimas tarp duomenu uzklausu
    }
    exit(1);
}
void KomandosVykdymas() {
    unsigned int i, pakartojimas;
    printf("(ilgis=%d) vykdymas\n", AR_Komanda_Size);
    SR_packet(AR_Komanda, AR_Komanda_Size);
    while (SR_packet(AR_Komanda, AR_Komanda_Size)==0){
        for (i=0; i<AR_Komanda_Size; i++) {printf("%02X ", AR_Komanda[i]);} printf("Kartojimas Komandos (%d baitu ilgis) vykdymas (%u kartas)\n", AR_Komanda_Size, pakartojimas); if (pakartojimas++>100) {
            printf("Pasiektas limitas kartojimui: %d. Vykdymas nesekmingas\n");
            break;
        }
    }
}
void LokalusDarbas() {
    unsigned int A0, A1, A2, A3, A4, A5, TS1, TS2, VGRA, VGRB, GenHzA, GenHzB;
    unsigned int i, pakartojimas;
    unsigned char qu[255];
    while (SR_packet(AR_command, sizeof(AR_command))==0){
        for (i=0; i<sizeof(AR_command); i++) {printf("%02X ", AR_command[i]);} SR_packet(AR_command, sizeof(AR_command)); printf("Kartojimas Komandos (%d baitu ilgis) vykdymas (%u kartas)\n", sizeof(AR_command), pakartojimas); if (pakartojimas++>100) {
            printf("Pasiektas limitas kartojimui (LokalusDarbas): %d. Vykdymas nesekmingas\n");
            return ;
            break;
        }
    }
    printf("Uzklausa(lokali):");
    for (i=0; i<sizeof(AR_command); i++) {printf("%02X ", AR_command[i]);}
    printf("Rezultatas:");
    for (i=0; i<sizeof(AR_command); i++) {printf("%02X ", resu[i]);}
    printf("\n ");
        A0=resu[3] + resu[4]*256;
        A1=resu[5] + resu[6]*256;
        A2=resu[7] + resu[8]*256;
        A3=resu[9] + resu[10]*256;
        A4=resu[11] + resu[12]*256;
        A5=resu[13] + resu[14]*256;
        VGRA=resu[15] + resu[16]*256;
        VGRB=resu[17] + resu[18]*256;
        GenHzA=resu[19] + resu[20]*256;
        GenHzB=resu[21] + resu[22]*256;
        TS1=resu[23] + resu[24]*256;
        TS2=resu[25] + resu[26]*256;
        //TSa2Point=&TSa2[0];
        //TS=AtmestiKrastinesReikmes(TSa2Point, jmax);
        //int A0min=0xFFFF;int A0max=0;for (j=0; j<jmax; j++) {if (A0a[j]>A0max) A0max=A0a[j];if (A0a[j]<A0min) A0min=A0a[j];}
        //int A1min=0xFFFF;int A1max=0;for (j=0; j<jmax; j++) {if (A1a[j]>A1max) A1max=A1a[j];if (A1a[j]<A1min) A1min=A1a[j];}
        //int A2min=0xFFFF;int A2max=0;for (j=0; j<jmax; j++) {if (A2a[j]>A2max) A2max=A2a[j];if (A2a[j]<A2min) A2min=A2a[j];}
        //int A3min=0xFFFF;int A3max=0;for (j=0; j<jmax; j++) {if (A3a[j]>A3max) A3max=A3a[j];if (A3a[j]<A3min) A3min=A3a[j];}
        //int A4min=0xFFFF;int A4max=0;for (j=0; j<jmax; j++) {if (A4a[j]>A4max) A4max=A4a[j];if (A4a[j]<A4min) A4min=A4a[j];}
        //int A5min=0xFFFF;int A5max=0;for (j=0; j<jmax; j++) {if (A5a[j]>A5max) A5max=A5a[j];if (A5a[j]<A5min) A5min=A5a[j];}
        sprintf(qu, "insert into vejojegaines.spi values (\"\",%i,%i,%i,%i,%i,%i,%i,%i,%i,null)",A0,A1,A2,A3,A4,A5, VGRA+VGRB*256*256, GenHzA+GenHzB*256*256, TS1+TS2*256*256);
        //printf("qu=%s\n", qu);
        res=mysql_perform_query(conn, qu);      // assign the results return to the MYSQL_RES pointer
        mysql_free_result(res);                 //clean up the database result set
}
int SR_packet(char AR[], int KKiek) {
    unsigned short int cs, css, i;
    cs=spiTxRx(0x81);//pradinis sekos baitas
    cs=0;//pirmas baitas dummy - jis neapskaitomas issiunciamojoje kontrolineje sumoje
    css=0x81;   //pirmas baitas ir pradeda kontrolin▒ siun▒iamos bait▒ sekos sum▒
    for (i=0; i<KKiek; i++) { if (i==1) {AR[i]=KKiek-2;}//siunciamu baitu kiekis irasomas i seka, kad priimantis irenginys zinotu ilgi resu[i] = spiTxRx(AR[i]); cs+=resu[i];if(cs>255) {cs=cs-256;}
        css+=AR[i];if(css>255) {css=css-256;}
    }
    resu[i]=spiTxRx(255-css);//kontrolin▒ siunciam▒ bait▒ sekos suma
    cs+=resu[i++];if(cs>255) {cs=cs-256;}
    resu[i]=spiTxRx(0x00);//finalinis baitas 'dymmy' skirtas nuskaityti paskutin▒ gaunam▒ bait▒
    cs+=resu[i];if(cs>255) {cs=cs-256;}
    if (cs!=0xff){
        printf("Bloga kontroline suma (checksum send) sc=%x\n", cs);return 0;
        } else {
        return 1;
    }
}
/**********************************************************
spiTxRx
    Transmits one byte via the SPI device, and returns one byte as the result.
    Establishes a data structure, spi_ioc_transfer as defined by spidev.h and loads the various members to pass the data
    and configuration parameters to the SPI device via IOCTL
    Local variables txDat and rxDat are defined and passed by reference.
***********************************************************/
unsigned short int spiTxRx(char txDat){
    unsigned char rxDat;
    struct spi_ioc_transfer spi;
    memset (&spi, 0, sizeof (spi));
    spi.tx_buf        = (unsigned long)&txDat;
    spi.rx_buf        = (unsigned long)&rxDat;
    spi.len           = 1;
    ioctl (fd, SPI_IOC_MESSAGE(1), &spi);
    return rxDat;
}
void ToMySQL(char qu[]) {
        res=mysql_perform_query(conn, qu);      // assign the results return to the MYSQL_RES pointer
        mysql_free_result(res);                 //clean up the database result set
}
int AtmestiKrastinesReikmes(unsigned short int *ar_ptr, int jmax) {
    unsigned short int i;
    unsigned short int max=0;
    unsigned short int min=1024;
    unsigned int res=0;
    unsigned long int res1=55555555;
    unsigned short int ct=0;
    for (i=0;i<jmax; i++) { if (*(ar_ptr+i)>max) max=*(ar_ptr+i);
        if (*(ar_ptr+i)<min) min=*(ar_ptr+i);
        //printf("%hu,", *(ar_ptr+i));
    }
    for (i=0;i<jmax; i++) {
        if (*(ar_ptr+i)!=max && *(ar_ptr+i)!=min) {
            res+=*(ar_ptr+i);
            ct++;
        }
    }
    if (ct==0) {
        //printf(".max:%hu, min: %hu, ct: %hu, res1: %li,--------\n", max, min, ct, max);
        return max;
      } else {
        res1=(double)res/(double)ct;
        res=res1;
        //printf(".max:%hu, min: %hu, ct: %hu, res1: %li,--------\n", max, min, ct, res);
        return res;
    }
}
int hex_char_to_bin(unsigned char *c){// TODO handle default / error
    switch(toupper(c)) {
        case '0': return 0;
        case '1': return 1;
        case '2': return 2;
        case '3': return 3;
        case '4': return 4;
        case '5': return 5;
        case '6': return 6;
        case '7': return 7;
        case '8': return 8;
        case '9': return 9;
        case 'A': return 10;
        case 'B': return 11;
        case 'C': return 12;
        case 'D': return 13;
        case 'E': return 14;
        case 'F': return 15;
    }
}

Arduino programos kodas

#include <SPI.h>
const int markeris=8;
const int klaida=4;
const int VejoPin=3;
const int Power1=5;
const int Power2=6;
const int VGROUT=2;//sukeiciau 2 ir 7 vietomis, kad tur42iau pertraukima, kurie galimi 2 ir 3 pin'uose UNO versijai
const int TempCL=7;
byte buf[256];
byte BETZ[256]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x06,0x07,0x07,0x07,0x08,0x08,0x08,0x08,0x09,0x09,0x09,0x0A,0x0A,0x0A,0x0A,0x0B,0x0B,0x0B,0x0C,0x0C,0x0C,0x0D,0x0D,0x0D,0x0E,0x0E,0x0E,0x0F,0x10,0x11,0x11,0x12,0x12,0x13,0x14,0x14,0x15,0x15,0x16,0x17,0x17,0x18,0x18,0x19,0x1A,0x1A,0x1B,0x1B,0x1C,0x1C,0x1D,0x1E,0x1F,0x1F,0x20,0x20,0x21,0x22,0x23,0x24,0x25,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x48,0x49,0x4B,0x4D,0x4E,0x4F,0x52,0x53,0x55,0x57,0x58,0x5A,0x5C,0x5D,0x5F,0x60,0x62,0x64,0x65,0x66,0x67,0x69,0x6A,0x6C,0x6E,0x6F,0x71,0x72,0x73,0x74,0x76,0x78,0x7B,0x7D,0x80,0x83,0x85,0x88,0x8A,0x8D,0x8F,0x92,0x94,0x97,0x9A,0x9C,0x9D,0x9F,0xA1,0xA4,0xA6,0xA9,0xAC,0xAE,0xB1,0xB4,0xB6,0xB9,0xBB,0xBF,0xC1,0xC2,0xC3,0xC5,0xC6,0xC8,0xCA,0xCC,0xCE,0xD0,0xD2,0xD4,0xD6,0xD8,0xDA,0xDC,0xDE,0xE0,0xE1,0xE3,0xE5,0xE7,0xE9,0xEB,0xED,0xEF,0xF1,0xF3,0xF4,0xF7,0xF9,0xFB,0xFD,0xFF};
byte dat[256];//={0x82,0xA9,0x0f,0x12,0x55,0x66,0x77,0x88,0x99,0x0A,0x19,0x28,0x37,0x46,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
byte checksumreal,komanda,clr;
int komilgis;
boolean beginas=false;
boolean process_error=false;
byte checksumsend=0;
int ctklaida=0;
volatile boolean doprint=false;
volatile byte pos;
signed long GenDaznis_us, prev_time_GenD, VejoGreitis_us, prev_time_us;
volatile boolean process_it;
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))    //Speedup the analogRead() function
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))      //Speedup the analogRead() function
void setup (void){
  Serial.begin (115200);         // debugging
  pinMode(markeris, OUTPUT);
  pinMode(klaida, OUTPUT);
  pinMode(VGROUT, INPUT);
  pinMode(Power1, OUTPUT);
  pinMode(Power2, OUTPUT);
  pinMode(MISO, OUTPUT);         // have to send on master in, *slave out*
  SPCR |= _BV(SPE);              // turn on SPI in slave mode, get ready for an interrupt 
  clr=SPSR;
  clr=SPDR;
  delay(10);
  ctklaida=0;
  pos = 0;                       // buffer empty
  checksumsend=0;
  process_it = false;
  SPI.attachInterrupt();         // now turn on interrupts
  sbi(ADCSRA, ADPS2);    //Speedup the analogRead() functionSS
  cbi(ADCSRA, ADPS1);
  cbi(ADCSRA, ADPS0);
  digitalWrite(klaida, LOW);
  attachInterrupt(digitalPinToInterrupt(VejoPin), rising, RISING);
  attachInterrupt(digitalPinToInterrupt(VGROUT), rising1, RISING);
  //pinMode(TempCL, OUTPUT);
  //setPwmFrequency(TempCL,1);
  //analogWrite(TempCL, 127);
} 
ISR (SPI_STC_vect){              // SPI interrupt routine
  digitalWrite(markeris, HIGH);
  byte c = SPDR;                 // grab byte from SPI Data Register
  byte z = 0;
  if (c==0x81 and beginas==false) {//0X81 hex'E - PAKETO PIRMAS BAITAS
    beginas=true;checksumreal=0;komilgis=0;pos=0;checksumsend=0; 
  }  
  if (beginas==true) {
    buf[pos]=c;
    checksumreal+=c; 
    switch (pos) {
      case 0:     z=dat[pos];
                  checksumsend+=dat[pos]; 
                  break;
      case 1:     z=dat[pos];
                  checksumsend+=dat[pos]; 
                  komanda=c;
                  break;
      case 2:     z=dat[pos];
                  checksumsend+=dat[pos]; 
                  komilgis=c; 
                  break;
      default: 
                if ((komanda & 0xF8)==0x30) {
                  if (pos<(komilgis+3)) {
                    BETZ[(komanda & 0x07)* 32 + pos-3]=c;    //Komandos A8-AF apraso, kuris is astuoniu paketas bus irasytas i BETZ masyva. Viename pakete 32 baitai. A8: 0-32 masyvo baitai AF - 224-256 baitai
                  }
                } else if ((komanda & 0xF8)==0x40) {
                   z=BETZ[(komanda & 0x07)* 32 + pos-3];
                } else {
                  //Serial.println("Komanda kita ");
                   z=dat[pos];
                } 
                if (pos==(komilgis+3)) {
                   dat[pos]=255-checksumsend;
                   z=dat[pos];
                  } else if (pos==(komilgis+4)) {
                   z=0x55;
                   process_it=true;
                   checksumsend=0;
                   pos=0;
                   beginas=false;
                   if (checksumreal==0xFF) {
                       process_error=false;
                      } else {
                       process_error=true;
                      digitalWrite(klaida, HIGH);
                   }
                } else {
                   checksumsend+=z; 
                }  
    }
    SPDR=z;  
    if (pos < sizeof(buf)) pos++; else { pos=0;beginas=false; } } digitalWrite(markeris, LOW); } void loop (void){ byte apkr; unsigned long TPM; unsigned int VGRmpers, x, CL, CH, GL, GH, TPL, TPH;//unsigned int - 0...256, signed int, -127...+127 reiksmes if (process_it) {process_it = false;} x=analogRead(A0); dat[3]=lowByte(x); dat[4]=highByte(x); x=analogRead(A1); dat[5]=lowByte(x); dat[6]=highByte(x); x=analogRead(A2); dat[7]=lowByte(x); dat[8]=highByte(x); x=analogRead(A3); dat[9]=lowByte(x); dat[10]=highByte(x); x=analogRead(A4); dat[11]=lowByte(x); dat[12]=highByte(x); x=analogRead(A5); dat[13]=lowByte(x); dat[14]=highByte(x); CH=VejoGreitis_us>>16; CL=VejoGreitis_us;
  dat[15]=lowByte(CL); dat[16]=highByte(CL); dat[17]=lowByte(CH); dat[18]=highByte(CH);//vejo greicio perdavimas 4 baitai
  GH=GenDaznis_us>>16; GL=GenDaznis_us;
  dat[19]=lowByte(GL); dat[20]=highByte(GL); dat[21]=lowByte(GH); dat[22]=highByte(GH);//generatoriaus daznio perdavimas 4 baitai
  TPM=millis(); TPH=TPM>>16; TPL=TPM;
  dat[23]=lowByte(TPL); dat[24]=highByte(TPL); dat[25]=lowByte(TPH); dat[26]=highByte(TPH);//TPL //TPH
  //paruosiame apkrovai vejo greitį padaugintą iš 16 (užpildysime 0-16m/s kiekvieną iš 16 vėjo greicio 16 tarpinių reiksmiu - viso 256 reiksmes)
  VGRmpers=1000000*16/12/VejoGreitis_us;//VGRmpers reiškia vėjo greitį padaugintą is 16, 12 - vėjo daviklio charakteristika tiek mimpulsų per sekundę esant 1m/sek vėjo greičiui
  analogWrite(Power1, BETZ[VGRmpers]);
  analogWrite(Power2, BETZ[VGRmpers]);
}
void SePrHe(int x) {
if (x<16) {
    Serial.print("0");
    Serial.print(x, HEX);
  } else {
    Serial.print(x, HEX);
  }
  Serial.print(" ");
  return;
}
void rising() {
  attachInterrupt(digitalPinToInterrupt(VejoPin), falling, FALLING);
  GenDaznis_us=micros()-prev_time_GenD;
  prev_time_GenD = micros();
}
void falling() {
  attachInterrupt(digitalPinToInterrupt(VejoPin), rising, RISING);
}
void rising1() {
  attachInterrupt(digitalPinToInterrupt(VGROUT), falling1, FALLING);
  VejoGreitis_us=micros()-prev_time_us;
  prev_time_us = micros();
}
void falling1() {
  attachInterrupt(digitalPinToInterrupt(VGROUT), rising1, RISING);
}
void setPwmFrequency(int pin, int divisor) {
  byte mode;
  if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 64: mode = 0x03; break;
      case 256: mode = 0x04; break;
      case 1024: mode = 0x05; break;
      default: return;
    }
    if(pin == 5 || pin == 6) {
      TCCR0B = TCCR0B & 0b11111000 | mode;
    } else {
      TCCR1B = TCCR1B & 0b11111000 | mode;
    }
  } else if(pin == 3 || pin == 11) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 32: mode = 0x03; break;
      case 64: mode = 0x04; break;
      case 128: mode = 0x05; break;
      case 256: mode = 0x06; break;
      case 1024: mode = 0x07; break;
      default: return;
  }
  TCCR2B = TCCR2B & 0b11111000 | mode;
}
}