Chirurgia spinală minim invazivă
Chirurgia spinală minim invazivă oferă pacienților oportunitatea unui tratament eficient, permițându-le o recuperare ultra rapidă și nu în ultimul rând minimizând leziunile induse chirurgical. Echipa noastră utilizează un spectru larg de tehnici minim invazive, din care enumerăm câteva: endoscopia cu variantele ei (transnazală, transtoracică, transmusculară, etc), microscopul operator, abordurile trans tubulare și nu în ultimul rând infiltrațiile la toate nivelurile coloanei vertebrale. www.neurohope.ro |
Arduino - automatizare DIY
Last Updated: Oct 27 2022 08:53, Started by
Costi_68
, Feb 10 2015 02:14
·
0
#1495
Posted 06 May 2019 - 11:23
gmartau, on 06 mai 2019 - 10:03, said: Procesorul nu se blocheaza niciodata, el executa instructiuni din program chiar daca aparent pare sa fie blocat, de exemplu, executa o bucla infinita. Daca sunt paraziti in sursa de alimentare procesorul ori ramane neafectat ori se reseteaza. |
#1496
Posted 06 May 2019 - 16:22
Iocan, on 06 mai 2019 - 11:23, said:
Dacã e așa cum spui tu, de ce majoritatea cipurilor Atmel au implementat mecanismul de hardware watchdog wdt_enable()? Mecanismul watchdog se poate folosi intr-un mod mai inteligent decat simpla resetare a microcontrolerului. In tutorialul de mai jos, cu ajutorul unei biblioteci care foloseste mecanismul watchdog, dupa fiecare blocaj se salveaza in memoria eeprom locatia unde se executa codul in momentul respectiv. Te ajuta sa descoperi exact unde e problema. Pot confirma ca libraria este foarte utila, am descoperit un bug altfel aproape imposibil de descoperit prin alte metode. https://www.megunoli...duino-watchdog/ |
#1497
Posted 06 May 2019 - 17:28
Iocan, on 06 mai 2019 - 11:23, said:
Dacã e așa cum spui tu, de ce majoritatea cipurilor Atmel au implementat mecanismul de hardware watchdog wdt_enable()? |
#1498
Posted 06 May 2019 - 20:04
gmartau, on 06 mai 2019 - 16:22, said: In primul rand trebuie sa ai o sursa de alimentare stabila. dexterash, on 06 mai 2019 - 17:28, said: Știi la ce se referă si cum se foloseste, in general, un watchdog? Așteaptă o "comanda"(registru schimbat) de la software. Așa că... tot la erori de software ajungem. Bun, acum văd că vrem doar să arătăm că sîntem mai competenți ca ălălalt. Mersi, nu mă interesează acest concurs. Edited by Iocan, 06 May 2019 - 20:04. |
#1499
Posted 16 May 2019 - 19:19
Salutare,
Sunt novice in ale Arduino, am achizitionat un kit de aprox 150lei cu destul de multe componente si am incercat sa fac cate ceva.. Primul lucru ce l am facut a fost sa testez cateva din componente cu un programel simplu de "Hello World" pe un lcd display. A functionat. Mai jos schema dupa care m am luat, de pe net, si poza cu standul: 11.png 208.75K 29 downloads 1.jpeg 253.78K 39 downloads Am vrut sa merg mai departe si sa incerc un senzor de culoare TCS3200 (cumparat separat, nu a venit in kit) Aici intampin probleme, un motiv e ca schema gasita pe internet nu e chiar asa de usor de citit ca prima (nu mai e mura-n gura) si desi consider ca am citit o corect nu merge 100%. Displayul este foarte slab, deabia porneste, si nici din potentiometru nu poti da decat oprit de tot sau foarte foarte slab...de nici nu se poate citi. Eu am considerat ca acolo este tot potentiometru in schema(unde am pus sageata rosie pe schema, dar nu sunt sigur daca am inteles bine schema). Aveti vreo idee de ce nu primeste displayul suficienta energie si cum as putea remedia? 22.jpg 192.35K 41 downloads 2.jpeg 219.98K 35 downloads Multumesc mult si scuze daca e banala postarea, nu am gasit ceva mai potrivit ptr incepatori. |
#1500
Posted 17 May 2019 - 08:28
Din poza se pare ca ai conectat Vss (minus/gnd) de la ecran la linia rosie (5V) si Vdd(plus) la linia albastra. Daca e asa, corect e invers. Pune firul negru la linia albastra si cel rosu la linia rosie.
Edit: Acum vad ca ai alimentat si breadboardul gresit de aia ti-a mers. Deci refa conexiunile si la placa si respecta si indicatiile de pe breadboard ca altfel te incurci. Observ ca deja folosesti firele cu culori cat de cat in mod intuitiv. Revii cu o poza de sus, nu lateral. Edited by gmartau, 17 May 2019 - 08:40. |
#1501
Posted 17 May 2019 - 10:23
10nutz_413x, on 16 mai 2019 - 19:19, said:
... Asta inseamna sa poti citi scheciul si sa identifici partile din cod si care e scopul lor. Stiu ca varianta replicarii schemei si a incarcarii scheciului facut de altcineva (tutorial, instructables) e cea mai simpla si e buna pentru inceput. Trebuie insa sa intelegi cum functioneaza si cum poti dezvolta schema si codul acela. Eu am inceput progresiv cu display pe "paralel" ca si tine. Ei bine, am inceput cu blink. Am citit, am experimentat diferite exemple si mi-am dat seama cum se citeste un port analogic si cum se poate afisa pe ecran la cordonatele dorite valoarea. Mi-am dat seama ca ecranul pe paralel imi tinea pinii digitali ocupati si dupa cautari si incercari am mutat afisajul pe comunicatie i2c astfel ca am pastrat bucata de cod si schema pentru afisare pe display cu i2c. Apoi am vrut sa citesc temperatura pe un senzor digital (onewire) si sa o pun pe ecran. Am vrut sa stiu cum se citeste un pin digital (buton) si cum se modifica iesirea unui pin digital (releu, led). Apoi am adaugat mai multi senzori de temperatura (10), inca 3 relee. Important este sa intelegi bazele (pentru ce e folosita o comanda/variabila, cum se foloseste). Mai tarziu vine si optimizarea codului. (Se poate obtine acelasi rezultat sau mai bun/rapid cu mai putine linii de cod si comenzi). Apoi doar imaginatia te mai opreste sa faci ceea ce ti-ai propus. Inca un sfat. Cand cumperi senzori, te uiti mai intai daca a facut cineva un tutorial pentru el, exista "librarii" pentru senzor, sunt destule persoane care au confirmat ca functioneaza. Edited by radurus, 17 May 2019 - 10:29. |
#1502
Posted 18 May 2019 - 17:01
Salut, am revenit cu ceva poze.
Am modificat firele, inteleg la ce te ai referit gmartau. radurus asa este, poate ai dreptate, poate m am aruncat cu capul inainte e adevarat..oricum voi incerca si alte lucruri mai simple si mai ales sa incerc eu sa programez, fara sa iau copy-paste, dar tentatia e mare cu atata material pe internet Am umblat la potentiometru si am reusit sa fac sa se vada, din anumite unghiuri, foarte foarte slab, si ce este pe ecran. Trebuie umblat la cod, asta e clar, ca da rateuri la corelarea valorilor RGB cu culorile proprizise (cum se vede din poze, dar aia e ok, e modificabil) Am auzit o varianta ca poate nu e destul de la usb ce vine si ar trebui sa incerc cu o baterie de 9V sa alimentez circuitul. (nu am incercat inca) Deasemenea am inteles ca poate e din cod setata luminozitatea la un maxim, nu am reusit sa descifrez asa ceva din cod. (totusi nu cred varianta asta) Am pus si poza de sus, poate e mai clar asa. Mersi de pareri si sfaturi 333.jpeg 238.73K 19 downloads 111.jpeg 212.42K 21 downloads 222.jpeg 238.26K 25 downloads Later Edit: Am rezolvat problema. Chiar dupa ce am scris postul initial m am gandit ca nu are rost sa nu mearga, ceva lipseste, era ca si cum nu era alimentat displayul corespunzator. Am analizat schita precenta, de la Hello World, ce avea in plus fata de cea de fata si am adaugat ultimele 2 fire, de la Ground la pinul K si cu un rezistor de la 5V la pinul A al displayului (schema din poza mai jos, zona incercuita cu rosu) si functioneaza perfect. Imi mai ramane problema depistarii corecte a culorii, problema de software. 555.png 202.18K 39 downloads 444.jpeg 172.26K 42 downloads Edited by 10nutz_413x, 18 May 2019 - 17:30. |
#1503
Posted 10 October 2019 - 14:58
Offtopic.
Am aruncat o privire pe discutiile de pe thread. ...era candva vorba despre automatizari centrale termice cu arduino. Cand am ajuns pe ramura asta (2015), pentru partea asta am ajuns. Mi-am facut automatizarea si am tot perfectionat la ea si am invatat multe. Anul acesta am montat si o CT in condensatie. In versiunea actuala a trebuit sa integrez sistemele (lemne si gaz). Nu sunt inca dispus sa renunt de tot la incalzirea cu lemne. Deoarece experienta/confortul e mai bun la utilizarea cu boiler ACM versus ACM instant, am gandit o solutie prin care sa fac ACM cu CT dar sa o folosesc din boiler. Asa ca automatizarea s-a extins de la 4 relee (4 pompe) la 6 relee (o pompa si un circuit de trimitere contact TA catre noua centrala. Pompa adaugata trage din baza boilerului si impinge in CT pe apa rece, apoi apa la 60 ajunge sus in boiler (adica am facut un boiler cu acumulare fara a folosi serpentina) Am adaugat contoare de timp pentru astea 2 optiuni, astfel ca pot vedea cat timp a functionat CT pe incalzire si pe ACM. Am inplementat o optiune mod vacanta dente ACM a.i. sa pot dezactiva functia de incarcare a boilerului. |
#1504
Posted 10 October 2019 - 16:21
Poti dezvolta un pic partea cu contoarele de timp ? Ce contor, de unde iei semnalul, etc...
|
|
#1505
Posted 10 October 2019 - 18:34
Sorry ca incep mai din spate...
Codul e structurat pe "module". In loop sunt timere cu millis pentru rutine care ruleaza la 25, 100, 1000, 4000, 30000 etc. milisecunde. (citire temperaturi, diferite calcule,...) Pentru fiecare releu am cate o variabila uint8t care ia valori 0 sau 1. (Stiu ca se poate face la nivel de bit si cu bitmasking si e f. utila varianta cand trimiti pe i2c spre un expander i/o, dar asa cum facut e mai usor de urmarit variabila in cod decat sa urmaresti un bit dintr-un byte) Pentru a atribui valori la variabilele astea, am facut o clasa decisionsPumpState() La fiecare 100ms e apelata clasa asta. In ea sunt o groaza de if-uri facute dupa scheme logice. La terminarea rularii clasei, toate valiabilele in legatura cu releele plus altele (histerezisuri, limite de temperatura, etc.) au valori care sunt folosite in urmatoarea clasa setOutputRelays() apelata. Atata timp cat un releu e activ, se incrementeaza o variabila cu diferenta de timp de la rularea anterioara. Cand releul e inactiv, variabila millis anterioara e doar actualizata cu millis. In alta clasa contoareDeTimp(), variabila asta care se tot incrementeaza, cand trece de 60000, se scad 60000 si se incrementeaza o variabila 8bit care reprezinta minutele... etc. la fel pentru variabila orelor 16bit. La fiecare incrementare a orelor/ minutelor este scrisa variabila in Eeprom. La pornirea automatizarii, se citesc variabilele din Eeprom. Fractiunile de minut se pierd dar minutele si orele se incarca si se reia contorul de umde a ramas O sa pun un fragment de cod mai incolo ca e mai usor de inteles. Edited by radurus, 10 October 2019 - 18:45. |
#1506
Posted 11 October 2019 - 08:46
Revin cu fragmentul de cod promis.
Am sters ce nu e relevant si am inlocuit cu [....] si comemtarii. Codul ar trebui sa fie functional (binenteles cu bibliotecile corespunzatoare). Stripped_code.ino /*-----( Import needed libraries )-----*/ #include <EEPROM.h> #include <OneWire.h> // Get 1-wire Library here: http://www.pjrc.com/teensy/td_libs_OneWire.html #include <DallasTemperature.h> //Get DallasTemperature Library here: http://milesburton.com/Main_Page?title=Dallas_Temperature_Control_Library #include <Wire.h> // Wire (I2C) Library #include <LCD.h> // LCD Library #include <LiquidCrystal_I2C.h> // F Malpartida's NewLiquidCrystal library //Download: https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads char timp01_hmm[12]; // #define ONE_WIRE_BUS 4 // onewire data e conectat la pin 4 #define I2C_ADDR 0x27 // adresa modulului I2CtoLCD PCF8574T este 0x27. //asignare pini/semnale pentru PCF8574T #define BACKLIGHT_PIN 3 #define En_pin 2 #define Rw_pin 1 #define Rs_pin 0 #define D4_pin 4 #define D5_pin 5 #define D6_pin 6 #define D7_pin 7 #define LED_OFF 0 #define LED_ON 1 // initializare pini iesire/intrare [....] const int termostat_ambianta = 3; // initializare pin 3 intrare termostat ambianta const int pompa_CT_boiler = 7; // pinul 7 va comanda pompa de recirculare boiler-CT condensatie pentru reumplere cu ACM, Releu_2.2 (Rel5 in schema fritzing) [....] uint8_t staretermostatambianta = 0; uint8_t mod_ACM_vacanta = 0; // variabila folosita pentru dezactiva pompa de recirculare ACM prin CT in condensatie modificabila in 0/1 intr-um meniu cu ajutorul butoanelor // declarare variabile pentru contoare de timp [....] unsigned long start_counter00 = 0; // contorul 00 e folosit pentru bucla de citire temperaturi, inputuri 100ms ciclu unsigned long stop_counter00; unsigned long start_counter04 = 0; // contorul 04 e folosit la actualizarea informatiilor dinamice pe LCD o data la 1000ms, nivel pufer, energie, procent, autonomie... unsigned long stop_counter04; //initializare variabile temperaturi [....] float temp_bacm = 0; float temp_bacmjos = 0; // adaugate pentru comanda pompei de recirculare boiler-CT // initializare limite temperaturi pentru bucla de decizii [....] uint8_t temp_startpompaboilerCT = 42; // adaugat pentru rutina pompei de incarce boiler de la CT, senzor mijloc uint8_t temp_stopompaboilerCT = 52; // adaugat pentru rutina pompei de incarce boiler de la CT, senzor jos // initializare variabile contoare pompe [....] //---------------------------- pompa de recirculare boiler prin CT unsigned int contor_pompa_boilerCT; unsigned long millis_p_boCT_acum = 0; // contorul dintre pornire si oprire unsigned long millis_p_boCT_anterior = 0; // contorul dintre pornire si oprire unsigned int tmp_contor_pompa_boilerCT = 0; // contor de 60000ms uint8_t minute_p_boilerCT = 0; unsigned int adresa_eepprom_start = 512; // adresa de inceput pentru parametri/contoare de unde incepe maparea /*-----( Declare objects )-----*/ OneWire oneWire(ONE_WIRE_BUS); // Pass address of our oneWire instance to Dallas Temperature. DallasTemperature sensors(&oneWire); // Start the LCD display library LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin); // initializare adrese senzori DS18B20 // pentru citire adrese si afisare pe serial, vezi exemplul DS18x20_Temperature.pde [....] DeviceAddress T_acm = { 0x28, 0x38, 0x47, 0xD4, 0x07, 0x00, 0x00, 0x9F }; // senzor 13 DeviceAddress T_acmsus = { 0x28, 0x38, 0x47, 0xD4, 0x07, 0x00, 0x00, 0x90 }; // senzor ? adrese fictive DeviceAddress T_acmjos = { 0x28, 0x38, 0x47, 0xD4, 0x07, 0x00, 0x00, 0x91 }; // senzor ? adrese fictive int a = 0; // ADC value for button void setup() { Wire.begin(); //------- Initialize the Temperature measurement library-------------- sensors.begin(); // set the resolution to 9 bit -->0.5grad 10bit --> 0.25 grad (Can be 9 to 12 bits .. lower is faster) [....] // alti senzori sensors.setResolution(T_acm, 10); sensors.setResolution(T_acmjos, 10);// neinstalat inca //---------------- Initializare lcd ------------------ lcd.begin (20, 4); // 20 caractere, 4 linii // pornire iluminare lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE); lcd.setBacklight(LED_ON); lcd.clear(); // initializare pin 14,15,16,17,6,7 ca OUTPUT si activare ca HIGH) // pentru releele cu trigger pe LOW // !!! in cazul releelor care ce activeaza cu HIGH toate starile trebuie inversate !!! [.....] pinMode(pompa_CT_boiler, OUTPUT); /// test iesiri relee [.....] digitalWrite(pompa_CT_boiler, LOW); pinMode(termostat_ambianta, INPUT_PULLUP); //termostatul va conecta pinul respectiv la GND prin intermediul unui releu sau optocuplor pinMode(A7, INPUT); //butoanele sunt conectate la A7 /// citire/actualizare valori contoare ore EEPROM/ram EEPROM.get((adresa_eepprom_start + 17), contor_pompa_boilerCT); //contor ore p_boCT EEPROM.get((adresa_eepprom_start + 19), minute_p_boilerCT); } void loop() /****** LOOP: ruleaza continuu ******/ { /// citeste intrarea A7 la fiecare 25ms si evalueaza ce buton e apasat /// citeste intrarea D /// alte operatii nerelevante pentru bucata de cod prezentata /// bucla pentru operatii repetitive la 100ms (citire temperaturi, calculare temperaturi medii puffer, citire inputuri, citire ora) stop_counter00 = millis(); if ((stop_counter00 - start_counter00) >= 100) { start_counter00 = stop_counter00; // resetare contor [....] /// alte operatii si instructiuni sensors.requestTemperatures(); // trimitere comanda pentru achizitie temperarturi staretermostatambianta = digitalRead(termostat_ambianta); // citire stare termostat ambianta temp_bacm = sensors.getTempC(T_acm); temp_bacmjos = sensors.getTempC(T_acmjos); [....] } /// sfarsit operatii la 100ms [....] // o multime de linii de cod :) [timer configurabil 100-250ms similar cu cel de 100ms, pentru actualizarea informatiilor de pe ecran, deoarece nu are rost sa aglomeram comunicatia i2c inutil] [mai multe meniuri de afisat pe LCD, unele meniuri se actualizeaza doar la 1000ms, ca infoscreen03, dar altele au elemente care se actualizeaza dupa acest timer] infoscreen03 (); // timpi functionare CT /// sfarsit timer if (start_counter00 == stop_counter00) // adica o data la 100ms { decisionsPumpState(); /// --- rutina decizii stari pompe in functie de temperaturi --- /// setOutputrelays(); // functie de setare iesiri pentru relee in LOW/HIGH, pentru pinii 4-7 contoarepompe(); // contorizarea timpilor de functionare ai pompelor } delay(5); // o mica pauza inainte de a relua void loop } void decisionsPumpState() { [....] if (mod_ACM_vacanta == 0) // ocolire logica de start daca e setat ACM mod vacanta { if ((temp_bacm < temp_startpompaboilerCT) && (temp_bacm > 0) && (starepompaboilerCT == 0)) // conditii de start...momentan 42 + conditie de ocolire a startului daca senzorul da rateuri sau daca e deja pornita { starepompaboilerCT = 1; } if (starepompaboilerCT == 1) // conditie de ocolire a rutinei daca pomopa e deja oprita { if ((temp_bacmjos > 0) && (temp_bacmjos < 120)) // conditie de folosire a sensorului daca semnalul e valid, varianta 2 senzori prezenti { if (temp_bacmjos >= temp_stopompaboilerCT) // conditie de stop cu senzor boiler jos... momentan 52 { starepompaboilerCT = 0; } } else { if ((temp_bacm >= temp_stopompaboilerCT) || (temp_bacm <= 0)) // conditii de stop cu senzor boiler mijloc daca semnalul senzor jos nu e valid sau daca da rateuri temp_bacm , varianta un senzor prezent { starepompaboilerCT = 0; } } if ((staretermostatambianta == LOW) && (temp_teu_tur_puffer < temp_startpomparadiatoare) && (temp_puffersus < temp_startpomparadiatoare) && (temp_bacm >= ((temp_stopompaboilerCT+temp_startpompaboilerCT)/2))) // conditie de scurtare a timpului de recirculare a ACM daca este activat TA (CT comuta de pe ACM e incalzire) { starepompaboilerCT = 0; } } } else { starepompaboilerCT = 0; } [....] } void setOutputrelays() { [.....] if (starepompaboilerCT == 1) { digitalWrite(pompa_CT_boiler, LOW); // activeaza releu 6 millis_p_boCT_acum = millis(); tmp_contor_pompa_boilerCT = tmp_contor_pompa_boilerCT + (millis_p_boCT_acum - millis_p_boCT_anterior); millis_p_boCT_anterior = millis_p_boCT_acum; } else { digitalWrite(pompa_CT_boiler, HIGH); // dezactiveaza releu 6 millis_p_boCT_anterior = millis(); } [.....] } void contoarepompe() // contoare incrementale pentru pompe [ore si minute] { [....] if (tmp_contor_pompa_boilerCT >= 60000) // pompa de recirculare boiler prin CT { tmp_contor_pompa_boilerCT -= 60000; // scadere un minut din milisecunde minute_p_boilerCT ++; // incrementare contor minute if (minute_p_boilerCT > 59) { minute_p_boilerCT = 0; contor_pompa_boilerCT ++; // incrementare contor de ore EEPROM.put((adresa_eepprom_start + 17), contor_pompa_boilerCT); //contor ore p_boCT } EEPROM.put((adresa_eepprom_start + 19), minute_p_boilerCT); } [....] } void infoscreen03 () // afisare timpi functionare CT condensatie (ACM + incalzire) { stop_counter04 = millis(); if ((stop_counter04 - start_counter04) >= 1000) { // urmeaza comenzi care sunt executate la fiecare 1000ms, informatii pe ecran start_counter04 += 1000; // actualizare contor lcd.clear(); [....] sprintf(timp01_hmm, "%4u:%02u:%02u", contor_pompa_boilerCT, minute_p_boilerCT, (tmp_contor_pompa_boilerCT / 1000)); // timp01_hmm e o variabila string de minim 11 caractere (10 necesare + 1 non printable), sprintf construieste un string de din variabilele din argumente %4u - 4 digiti, unsigned, no leading zero pentru ore; %02u - 2 digiti, leading zero pentru minute; la fel pentru secunde lcd.setCursor(0, 2); lcd.print(F("Apa calda ")); lcd.print(timp01_hmm); } } void readButtonsDoAction () // citire ADC butoane, decizii actiuni in functie de buton activ, meniu activ, selectie, etc. { /// nenecesar deoarece in fragmentul acesta nu folosim navigarea prim meniuri fiid doar unul (infoscreen03) } |
#1507
Posted 17 October 2019 - 18:55
A facut careva pe aici un meniu cu scroll?
Pe langa ce am vreau sa mai introduc o pagina cu un meniu unde sa vad diferiti parametri (as avea vreo 15, m-as putea la 5-7, dar ap putea sa mai adaug peste 15), valorile lor, sa defilez cu up/down. Cu ok sa pot intra un nivel mai jos pe parametru (nume, valoare actuala, valoare setabila up/down/ok) Cu left (back) sar inapoi un nivel mai sus pe lista de unde am plecat. Idei? |
#1508
Posted 21 October 2019 - 07:58
Am facut meniul (primul nivel).
Am definit un "char array" cu 21 parametri Afisez pe ecran 3 dintre ei. Il am setat pe cel curent, cel anterior si urmatorul sunt calculati cu +/- 1 sau conditii daca trebuie sarit la capatul opus al listei. Cu up/down defilez prin lista schimband parametrul curent. Ceilalti doi (deasupra/dedesubt) de afiseaza automat. La capete, lista face rollover. Eu consideram numerotarea si "call"-ul din array incepand cu 1 dar se incepe cu 0. Urmeaza sa fac nivelul urmator. |
#1509
Posted 22 October 2019 - 08:35
...deci
Nivelul urmator e facut. Pe baza unui switch/case aduc valoarea parametrului curent (selectat) impreuna cu limitele upper/lower in noul "ecran" (unde am si numele parametrului curent) Aici pot face + sau - la valoare dar am in dreapta si valoarea nemodificata (sunt de fapt 2 variabile distincte temporare) La actiunea "ok" valoarea din dreapta este actualizata cu noua valoare. Butonul "back" (stanga) ma aduce inaloi in lista parametrilor. Am renuntat la ideea de a afisa si valorile parametrilor anterior/urmator. Necesita mai mult cod. Ramane sa vad cum salvez inapoi valoarea modificata in parametrul original... Am incercat sa pun valorile parametrilor intr-un "array" de uint8_t dar nu a mers. Poate n-am facut eu ceva bine si trebuia sa declar int. Daca functioneaza asa pot plasa parametrii si limitele in 3 constructii "array", ii citesc de acolo unde pot sa si actualizez. Ar fi mai simplu sa actualizez punctual valorile din "array". Se pare ca in testele mele mi-am "busit" Nano-ul cu care faceam testele. Merge dar nu mai pot incarca pe usb nimic. |
|
#1510
Posted 24 October 2019 - 09:29
Mi-am meniul cu parametri pe care il doream.
Este loc de extins numarul de parametri/ optiuni si de optimizat. Nano-ul nu e bushit, am reusit sa incarc soft in el dar necesita mai multe incercari si ledul 13 se aprinde ciudat. O sa fac un filmulet scurt ca e mai usor de inteles dar cine este interesat poate citi mai jos logica de functionare: - am declarat 5 arrays (vectori?) Un "char*" si 4 ca uint8_t pentru consum mai redus de resurse (numele parametrilor , variabilele parametrilor, valorile "default", valorile upperlimit, valorile lowerlimit) - de asemenea a trebuit sa declar si variabilele parametrilor - principiul de lucru este cel prezentat anterior, meniu se afla intr-un void separat (eu le spun "screen" sau pagina) - pe LCD linia 0 am titlul meniului - la linia 2 este afisat parametrul curent si valoarea lui (extrase din vectorii respectivi) - pe linia 1 si 3 sunt numele parametrilor n-1 si n+1 fara valori (extrase din vectorul nu numele lor) - defilarea de face cu up/down cu -- sau ++ la indicele obiectului din vector si rollover la primul/ultimul parametru - activarea butonului ok conduce in al screen (e o alta rutina void) in care sunt preluate 4 valori din 4 vectori (nume parametru curent, valoare parametru curent, limita sus, limita jos) si o variabila temporara egala cu valoarea parametrului curent pentru incrementare/decrementare cu ++ (up) sau -- (down) - limitele opresc incrementarea/ decrementarea la valorile max/min - activarea butonului "ok" in ecranul acesta conduce la copierea valorii temporare in vector la indicele parametrului curent, si scrierea in epprom la o adresa (am adresa de start + indicele parametrului curent din vector). - butonul "stanga" e considerat "back" si face saritura la inapoi la lista parametrilor la pozitia ramasa. - butonul "dreapta" nu l-am implementat dar ar putea reseta parametrul curent la valoarea "default". - actiunile butoanelor sunt verificate in subrutina paginii respective. In lista parametrilor am pus si o optiune "reset parametri la valori initiale". Asta ia doar valori 0/1. Daca o fac 1 si dau ok, programul sare (in fundal, nu se vede pe display) intr-o alta subrutina (void) unde este un "for" in care pe rand se citeste fiecare parametru din vectorul cu valori default, se copiaza in vectorul cu valori curente si se scrie in eeprom la adresa curenta (ca in pagina cu salvare in eeprom), apoi intorcandu-se cu executia in pagina unde este optiunea "initializare parametri". |
#1511
Posted 25 October 2019 - 08:25
Iata si videclipul promis.
[ https://www.youtube-nocookie.com/embed/WnlLuo0EXBU?feature=oembed - Pentru incarcare in pagina (embed) Click aici ] |
#1512
Posted 25 October 2019 - 21:28
Salut.
Unul dintre colegii de pe aici mi-a sugerat sa postez codul pentru meniul pe care l-am facut. Nu este un meniu universal dar cred ca poate fi folosit/adaptat usor daca e cineva care ar dori sa isi implementeze ceva similar. Imi pare rau pentru explicatiile din preambulul lung dar cine stie poate sari direct la cod. Trebuie explicat deoarece meniul acesta mai are si tentacule prin restul codului automatizarii, iar cele 2 rutine ar fi incomplete fara inca altele. Codul adaugat pentru meniul acesta impreuna cu alte optimizari facute ocupa suplimentar de ceea ce aveam ~900byte in flash si ~430byte in SRAM. Variabila uint8_t [buton] este actualizata la fiecare 20ms (desi cred ca e mai mult in realitate) pe baza citirii unui port analogic. 0 - niciun buton 1 - sus 2 - dreapta 3 - jos 4 - stanga 5 - ok Altcineva ar putea implementa butoane pe port digital si ar putea face conexiunea usor cu meniul acesta. In meniul acesta se afla doar comenzile pentru butoanele sus/ok/jos. Comenzile pentru stanga/dreapta se afla altundeva in rutina de evaluare a ADC-ului (void readButtonsDoActions() care nu apare in codul de mai jos) deoarece ele incrementeaza/decrementeaza variabila uint8_t [meniu] (0....6) adica maxim 7 pagini sau cate vrei si fac rollover la capete.(daca puneam comenzile stanga/dreapta in fiecare pagina de meniu, se repetau inutil ocupand spatiu de memorie). Eu am incercat sa optimizez folosirea variabilelor ca sa ocupe cat mai putina memorie, e valabil si pentru EEPROM: - uint8_t - pentru orice numar care e doar pozitiv pana la 255 (1 byte), de mai foloseste si "byte". Am folosit si pentru variabila true/false 1/0 tot uint8_t ca nu se poate mai mic de 8 biti. - unsigned int - pentru orice numar pozitiv pana la 65535 (2 byte) (de exemplu 60000ms este 1 minut, pentru contor de minut nu are rost sa folosesc o variabila de tip mai "mare", sau in EEPROM pentru contoare de ore de functionare deoarece 255 era prea mic) Adresa de pornire pentru operatii EEPROM este 562 deoarece de la 512 am alte chestii rezervate si mi s-a parut mie interesant sa nu incep de la 0. Coordonatele pentru lcd.setcursor(x-coloana,y-rand) sunt aranjate pentru display 20(x) x 4 (y) caractere, incepand cu 0,0 din stanga-sus. Sper sa va fie de ajutor. Va doresc "Happy programing"! Lozinca de programatori: "we brake keyboards not hearts" // declarare variabile, constante // lista parametrilor, array, pentru meniul de setari, alegerea dimensiunii textului trebuie facuta a.i. la inceput sa aiba loc indicele parametrului (daca vrei) iar 3 caractere la final pentru valoarea parametrului const byte parametriFolositi = 25; // numarul maxim de parametri din lista, e pus intr-o "variabila" ca sa poata fi extinsa mai usor lista. Atentie ca pointerul dintr-un vector ia valori de la 0 la 24 (in cazul meu) const char * const listaParametriMeniu[] PROGMEM = { "TTurStartPPu", "TTurStartHist", "TMinRetur", "TMinReturHist", "TTurStartPBo", "TTurDifBoiler", "TBoilerStopPBo", "TBoilerStopHist", "TBoilerStrtReCT", "TBoilerStopReCT", "TPufMinIncalz.", "TPufMinHist", "En%MaxStartPRa", "ModDetectFoc", "TempStartFoc", "TempStopFoc", "ACMVacanta", "AutoscrollTime",// counter05// contorul 05 e folosit la defilare automata intre ecrane la 3s configurabil 1-6 dintr- "DoarPufer", "DoarBoiler", "InitParametri", "ResetTimpPBy", "ResetTimpPuf", "ResetTimpPBo", "ResetTimpPRad", }; uint8_t j_param = 0; // variabila folosita pentru indicele array din lista parametri char* si nu numai uint8_t j_param_prev, j_param_next;// variabile folosita pentru indicele array anterior/urmator din lista parametri char* uint8_t tmp_param_value, i; // tmp_param_value e "volatila", i e folosit in 2 constructii de tip "for" // declarare tip variabile din vectorul urmator uint8_t temp_min_start_pompapuffer, histerezis_temp_start_pompapuffer, temp_min_retur, histerezis_retur, temp_min_start_pompaboiler, temp_diff_start_boiler, temp_max_boiler, histerezis_temp_stop_boiler, temp_startpompaboilerCT, temp_stopompaboilerCT, temp_min_start_radiatoare, histerezis_temp_start_radiatoare, energy_percent_max_avarie, mod_detectie_foc_activ, temp_startfoc, temp_stopfoc, mod_ACM_vacanta, counter05, mod_doar_puffer, mod_vara; // declarare vector uint8_t parameterValues[parametriFolositi] // valoarea actuala parametriFolositi= 25, variabilele trebuie sa corespunda la ordine cu numele prametrilor din lista { temp_min_start_pompapuffer, // acestia sunt parametrii mei histerezis_temp_start_pompapuffer, temp_min_retur, histerezis_retur, temp_min_start_pompaboiler, temp_diff_start_boiler, temp_max_boiler, histerezis_temp_stop_boiler, temp_startpompaboilerCT, // aceasta este o alta pompa, nu cea de la cazan pentru serpentina temp_stopompaboilerCT, // temp_min_start_radiatoare, histerezis_temp_start_radiatoare, energy_percent_max_avarie, // daca puferul trece de o limita (%) atunci porneste pompa radiatoarelor mod_detectie_foc_activ, // 0/1 pot detecta focul cu termostat de cos sau cu temperatura cazanului temp_startfoc, temp_stopfoc, mod_ACM_vacanta, /// counter05, // contorul 05 e folosit la defilare automata intre ecrane la 3s configurabil 1-6 dintr-un meniu mod_doar_puffer, // dezactivare pompa boiler mod_vara, /// doar boiler, dezactivare pompa pufer 0, // acestia sunt "parametri" folositi pentru a face reset la diferite chestii 0, 0, 0, 0 }; // valori "default" pentru parametri modificabili din optiuni const uint8_t default_parameters[20] PROGMEM ={81,1,65,10,70,6,80,2,42,52,43,2,110,1,70,65,0,3,0,0}; // limitele de modificare ale parametrilor de mai sus - ultimii 5 sunt doar comenzi de reset. const uint8_t parameters_upperlimit[parametriFolositi] PROGMEM ={85,5,70,12,75,8,80,3,50,55,50,4,115,1,75,65,1,6,1,1,1,1,1,1,1}; const uint8_t parameters_lowerlimit[parametriFolositi] PROGMEM ={75,1,50,6,65,4,65,1,35,40,40,1,100,0,60,50,0,1,0,0,0,0,0,0,0}; void setup() {... for (i=0 ;i <20; i++) // 20 numarul parametrilor, array este [25] dar ultimii 5 sunt doar comenzi de reset. { EEPROM.get((562 + i), parameterValues[i]); // citire din EEPROM a parametrilor de la adresele corespunzatoare si actualizarea valorilor in vector pe rand la fiecare rulare cate unul copy_arrayParamToFunctionalVariable(); // a trebuit sa construiesc rutina asta pentru a actualiza valorile realtime din RAM cu valorile din vector } ..... } // urmeaza void loop() {..o groaza de cod.. unde e si switch/case pentru afisat paginile pe ecran in functoe de [meniu] etc.} // iata si rutina de actualizare a valorilor parametrilor, nu mi-a venit alta idee, cred e buna ca sa o pot refolosi void copy_arrayParamToFunctionalVariable() { switch (i) { case 0: temp_min_start_pompapuffer = parameterValues[i]; break; case 1: histerezis_temp_start_pompapuffer = parameterValues[i]; break; case 2: temp_min_retur = parameterValues[i]; break; case 3: histerezis_retur = parameterValues[i]; break; case 4: temp_min_start_pompaboiler = parameterValues[i]; break; case 5: temp_diff_start_boiler = parameterValues[i]; break; case 6: temp_max_boiler = parameterValues[i]; break; case 7: histerezis_temp_stop_boiler = parameterValues[i]; break; case 8: temp_startpompaboilerCT = parameterValues[i]; break; case 9: temp_stopompaboilerCT = parameterValues[i]; break; case 10: temp_min_start_radiatoare = parameterValues[i]; break; case 11: histerezis_temp_start_radiatoare = parameterValues[i]; break; case 12: energy_percent_max_avarie = parameterValues[i]; break; case 13: mod_detectie_foc_activ = parameterValues[i]; break; case 14: temp_startfoc = parameterValues[i]; break; case 15: temp_stopfoc = parameterValues[i]; break; case 16: mod_ACM_vacanta = parameterValues[i]; break; case 17: counter05 = parameterValues[i]; break; case 18: mod_doar_puffer = parameterValues[i]; break; case 19: mod_vara = parameterValues[i]; break; } } // meniu vizualizare parametri - meniu functional scroll up/down/rollover // la mine lista asta e accesata cand meniu=4 void meniuParameterList() { // actiuni butoane if (buton == 1) // buton sus { // conditiile aste se pot scrie prescurat , am incerca dar nu stiu de ce nu mi-a mers if (j_param == 0) { j_param = parametriFolositi-1; } else { j_param -= 1; } } if (buton == 3) // buton jos { if (j_param == parametriFolositi-1) // conditii pentru rollover in jos { j_param = 0; } else { j_param += 1; // incrementare } // j_param = (j_param == 1) ? parametriFolositi : (j_param+1); } j_param_prev = (j_param == 0) ? (parametriFolositi-1) : (j_param-1);// calculam aici pointerele anterior si urmator si punem conditii ca sa faca rollover si sa nu incurce treaba pe aici j_param_next = (j_param == (parametriFolositi-1)) ? 0 : (j_param+1);// daca j_param=24, atunci j_param_next=0, daca nu, ia valoare +1. if (buton == 5) // buton ok { // sari in ecran singleParamDisplay unde se preia numele si valoarea din vector cu pointer j_param de doua ori (una fixa si una modificabila) tmp_param_value = parameterValues [j_param]; meniu_anterior = meniu; // ca sa ma pot intoarce de une am plecat meniu = 49; // sare la singleParamDisplay(); // paginile intregii interfete sunt accesate pe baza valorii variabilei meniu intr-o constructie switch/case } // sfarsit actiuni butoane // urmeaza afisarea pe ecran lcd.clear(); lcd.setCursor(0, 0); lcd.print(F("Parametri")); lcd.setCursor(16, 0); lcd.print((char)13); lcd.print(F("OK")); lcd.print((char)14); // char 13 si 14 sunt definite/declarate inainte de setup ca uparrow si downarrow lcd.setCursor(0, 1); lcd.print (j_param_prev); // acesta e pointerul pentru randul de deasupra sa fie afisat la inceputul randului lcd.print(listaParametriMeniu[j_param_prev]); // acesta e numele parametrului de la pointerul anterior lcd.setCursor(0, 2); lcd.print (j_param); lcd.print(listaParametriMeniu[j_param]); lcd.setCursor(17, 2); sprintf(timp01_hmm, "%3u", parameterValues [j_param]); lcd.print(timp01_hmm);// aliniere la dreapta cu sprinf 3 caractere fara 0 in fata a valorii parametrului actual, pentru cei nepretentiosi se poate printa direct variabila asa cum e // timp01_hmm e o variabila char de cel putin 3+1 caractere (in cazul asta) dar in codul meu ea este de 11 deoarece o refolosesc pentru diferite contoare de timp de tipul hhhh:mm:ss lcd.setCursor(0, 3); lcd.print (j_param_next); lcd.print(listaParametriMeniu[j_param_next]); // n-am mai pus si valorile parametrilor anterior si urmator ca imi ocupa memorie } // cam asta e lista parametrilor, treaba importanta e in declararea vectorilor // rutina urmatoare este pentru afisarea unui singur parametru cu scopul de a-l modifica // am sarit aici cand am zis meniu=49 dar poate fi alt numar insa trebuie sa fie acelasi cu cel din switch/casevoid // meniu= 49 este trecut ca exceptie la actiunile comune pentru butoanele 4 si 2 (stanga/dreapta) situate altundeva in cod cum am explicat undeva mai sus // tmp_param_value are deja valoarea parametrului curent cu pointerul [j_param] singleParamDisplay() { // actiuni butoane , limitele sunt incarcare din array //sus tmp_param_value ++ if (buton == 1) { tmp_param_value ++; // incrementam valoarea if (tmp_param_value > parameters_upperlimit[j_param]) { tmp_param_value = parameters_upperlimit[j_param]; // dar o limitam la valoarea limita superioara // tmp_param_value = parameters_lowerlimit[j_param];// sau daca preferam rollover activam linia asta si o comentam pe anterioara } } //jos tmp_param_value -- if (buton == 3) { tmp_param_value --; // decrementam valoarea if (tmp_param_value < parameters_lowerlimit[j_param]) { tmp_param_value = parameters_lowerlimit[j_param];// dar nu mai jos decat ne permite limita inferioara definita in vectorul respectiv // tmp_param_value = parameters_upperlimit[j_param]; //pentru rollover } } // buton ok confirmare, aici treaba se complica putin if (buton == 5) { parameterValues[j_param] = tmp_param_value; // atribuim valoarea temporara variabilei din vector la pointerul curent [j_param] care are aceeasi valoare in toata rutina asta if (j_param < 20) // daca e vorba de parametri, scriem in eeprom altfel ignoram ca de la 21 la 25 sunt niste comenzi de reset. { EEPROM.put((562+ j_param), parameterValues[j_param]); //scriem in EEPROM noua valoare pe care am actualizat-o anterior in vector i = j_param; // ii dam lui [i] valioarea lui [j_param] deoarece trebuie folosit in rutina urmatoare pentru switch/case la actualizare variabila reala din RAM copy_arrayParamToFunctionalVariable(); // sarim acolo, facem greaba si ne introarcem inapoi sa continuam } if ((j_param == 20) && (tmp_param_value==1)) // parametrul 20 este pentru a initializa toti parametri la valorile din "fabrica". Valorile lor sunt luate din vectorul default_parameters[20] { resetParamToDefault(); // vezi mai jos codul tmp_param_value = 0; parameterValues[j_param] = 0;// actualizeaza valorile pe ecran dupa ce ai s-a terminat citirea din eeprom } } // stanga sari inapoi in meniu if (buton == 4) { meniu = meniu_anterior;// adica va fi parcursa rutina meniuParameterList(); } if (buton == 2) // buton dreapta { // adaugi aici comenzile pentru butonul [dreapta] } // sfarsit actiuni butoane // ce apare pe ecran? lcd.clear(); lcd.setCursor(0, 0); lcd.print(listaParametriMeniu[j_param]); // numele parametrului ca titlu // afisam pe ecran si indicii despre ce butoane/functii sunt disponibile aici lcd.setCursor(1, 1); lcd.print((char)13); //up arrow lcd.setCursor(13, 1); lcd.print((char)127); // left arrow lcd.print(F(" back")); lcd.setCursor(0, 2); lcd.print(F("OK [ ]")); lcd.setCursor(4, 2); lcd.print(tmp_param_value); lcd.setCursor(15, 2); // lcd.print(current_param_value); lcd.print (parameterValues [j_param]); lcd.setCursor(1, 3); lcd.print((char)14); // down arrow lcd.setCursor(13, 3); lcd.print(F("reset ")); lcd.print((char)126);// right arrow... dar butonul 2 (dreapta) nu are nicio comanda implementata } void resetParamToDefault() { for (i=0 ; i <20; i++) { uint8_t tempval = default_parameters[i]; // folosim o variabila intermediara volatila careia ii atribuim pe rand valorile parametrilor, nu a mers direct vector cu vector parameterValues[i] = tempval; // actualizam in vector valoarea parametrului EEPROM.put((562 + i), tempval); // citire din array a parametrilor si actualizarea valorilor in EEPROM copy_arrayParamToFunctionalVariable(); // il avem pe [i], refolosim rutina de actualizare (switch/case) a variabilelor din RAM } } |
Anunturi
▶ 0 user(s) are reading this topic
0 members, 0 guests, 0 anonymous users