Aparitia Erorilor In Sistemele Senzoriale
CUPRINS:
Rezumat în limba engleză
Planificarea activității
Stadiul actual
Fundamentare teoretică
Sisteme Embedded
Microcontrollere
Comunicarea serială pe RS-485 și RS-232
Relee electromagnetice
Modul USB pentru salvarea datelor pe memory stick
Implementarea soluției adoptate
Creearea cablajului
Circuitul de alimentare
Ecranul LCD
Comenzile și instrucțiunile LCD-ului
Interfață LCD – conexiune pe 4 biți
Microcontrollerul ATmega8
Dispunerea porturilor și pinilor
Convertor analog – numeric
Generarea întreruperilor
Implementarea butoanelor și decodificarea acestora
Releele electromagnetice
Testarea liniei și verificarea automată a polarității
Implementarea comuncației seriale pe RS-485
Inițializarea USART-ului și configurarea regiștrilor
Transmisia datelor
Rezultate experimentale
Simularea unor părți din circuit
Crearea cablajului
Programarea microcontrollerului
Testarea circuitului integrat RS485
Dispozitivul slave
Pornirea aparatului
Rularea testelor
Concluzii
Bibliografie
Anexe
CV
Rezumat în limba engleză.
The main subject of the diploma thesis is the diagnosis of the sensory systems. A sensory system is a complex network full of information containing exterior or interior events. To understand better, an example of a sensory system should be given. Assuming there is a need to implement a sensory system within a house as an alarm system, a sensory system will be created. The system will be composed of sensors, wires, communication protocols, indicators for signaling occurrences of events, and other electronic components for processing the information. All this information about exterior world represents a sensory system. The diagnosis of a sensory system is the identification of the nature of a problem that has a bad impact over the system. In other words, finding the errors. An error represents the deviation from the systems normal functioning, and different methods of diagnosis are implemented : finding the type of the error, the gravity of an error and the localization of the error.
More details you have about the fault that occurred, the easier the fault can be corrected.
Manual diagnosis exist since the first tehnical systems were built, but automated daignosis appeared for the first time when computers were invented. The First applications that received this type of diagnosis were the aerospace applications and subsequently it was introduced in chimical plants.
Automatic close surveillance of sensory systems could lead to the detection of unexpected behaviors that shouldn’t normally exist, and along with this, a measure must be taken to correct the issues.
There are many types of diagnosis, including classical diagnosis and automated protection diagnosis. The Classical diagnosis ( or monitoring diagnosis) checks if the system variables are inside optimal parameters, based on the addmited tolerance, and if the normal values exceeded that tolerance, an alarm will be generated to alert the user. The automatic protection diagnosis is that type of diagnosis that determined when issues appear, and automatically initialises a measure to counteract its negative action over the system.
Another covered subject is automatic testing. Given the fact that many of nowadays electronic systems are too complicated to be manually tested, or it would take too much time to be tested, automatic tests should be performed instead. Automaticl tests make use of microcontrollers that are programmed to run specific tests. The time for automatic tests will take less time than it would take to manually test the same network or device.
The purpose of this thesis is to diagnose a sensorial system using serial communication. The importance of this work is very high because the resulted full working device can be used to automatically diagnose a real sensorial system that is stretched on one square kilometer. In case the system needs to be tested, the device will be connected to the line verifying all the other slave devices. In this case, the job will be completed in no time, easing everyone’s work. If manual testing will be used instead, the time that w ould take to move from one slave device to another will be very high and it would require more than one man. This means that the costs will be higher too.
First of all, the requirements of the final device should be analysed in orde to find the best solution to be physically implemented.
The requirements of the project say that the communication needs to be done at distances of severals meters (hundreds of meters) across a dam. This means that the master device should be able to be connected to the communication line and diagnose the entire network.
To transfer data RS232 interface can be used. This old interface is no doubt the best known interface because it was implemented on almost all computers. Today, this was replaced with faster methods like USB. The problem with RS232 is that it is inappropriate in this case, since one of the big problmes with t RS232 is that it does not have noise immunity on the signal lines. Noise is easily induced into wires and limits maximum distance of transmision and communication speed. More than that, the speed at 1 km drops under 1 kb/s.
On the other hand, RS485 interface have full noise immunity because of its differential mode of transmision and its speed can reach up to 100 kb/s at distances over 1km and up to 35 MB/s at 12 meters. So, the communication part will use RS485 bus.
The most important part of the RS485 interface is the way it works. By default, all the senders on the RS485 bus are in tri-state with high impedance. The developed device, that is the master, will be connected to the line and then ,the user will use the buttons to activate a test. This test will basicaly be a data frame wich contains the address of the slave device that needs to be read, the command which determines what the slave device should do, traductor address and control sum. When the RS485 that contains the address specified in the data frame sees the message, it will respond with the requested data.
The communication protocol shall be written in a microcontroller. The most suited microcontroller is the AVR ATmega8a, a microcontroller with high performance and low power, running at a frequency of 16 MHz. The transmition routine will be implemented as a function while the receiving will be implemented as an interrupt service routine.
The microcontroller it’s the heart of the device. It is the one that does all the calculations implemented in each of the tests. There will be two tests implemented, each one having more tests within, but wich are not shown to the user because of their complexity.
Test one represents more test cases:
Verifing that the line has the proper voltage (the voltage at wich RS485 can send and receive). If the voltage is good it means that the polarity of the signal is good and with this test, basicaly two tests are executed. So, with good polarity and voltage states, the next tests can continue.
Verifing that there are conditions for receiving serial data. This test checks that lines A and B are both at their normal voltage potential. The sum of A and B voltages devided by two has to be more than 1.5 V or equal to it. If the conditions are met, then it means that all the reception is active.
Test two consists again, in more test cases:
Sending a serial frame to the specified slave RS485 device. The address is specified in the data frame .
After the sending is completed, if one slave devices it has the address mentioned by the master, it should respond right away.
Checking the control sum: if the sum is null, then we have good reception of data, otherwise the reception wasn’t completed, or invalid data was sent.
Also, besides communication and tests, the device should have an LCD display to ease the interface with the user. Some buttons were implemented, more precisely the buttons that control what testst are executed.
The implementation was pysically implemented as follows:
The final product must act like an embedded system. An embedded system is a device used to control, monitor or assist the operation of equipment, machinery or plant. An embedded is a small computer, created to serve a specific purpose, unlike personal computers that are designed to be flexible and to meet a wide range of the users needs.
Embedded systems control many of the todays common devices. Embedded systems are found in consumer, cooking, industrial, automotive, medichal, commercial and military applications.
For example, a microwave is an embedded system, build with the purpose to heat the food. The microwave has buttons to control the time and the desired power at wich the food should be heated at. So basicaly, the microwave is a system that has only one major purpose – to heat the food.
Modern embedded systems are very often based on microcontrollers. Similar, in this manner, the diagnosis of the sensory system device is built.
The microcontroller was introduced in 1970 as a programmable replacement for logic-based circuits and hasmore advatages over the logic-based circuits:
Can be easily upgraded
Can be easily maintained
Less fragile (instead of hundreds of logical circuits – only one microcontroller)
The Integrity of property (it is very difficult to copy the software burnt in the microcontroller)
After the selection process of the componets has been completed, a first schematic was built to analyse the components as a whole. After that, parts of the schematic were simulated in oder to check if it worked as it should. The next step was creating the PCB layout in OrCad Layout and afterwards the PCB was physically created.
The main components were put on the PCB board and the first real tests began. Checking the voltage potential in different points of the board, checking if there are no discontinuities in the routes of the circuit.
First part of the code was written for the 4×20 display to test if this part of the circuit works as planned.
The next move was to set the buttons for each action. Because after, the ports and the pins of the microncontroller were assigned to each electronic components, there was only one pin of microcontroller left and that one was an ADC pin.
Due to the fact that there were still three buttons to connect to the microcontroller and only one pin available, a solution had to be developed. The ADC (analog to digital converter) is an electronic device that is integrated as a pheripheral into the microcontroller and its scope is to convert continous quantity (analog values – usually voltage) into a digital number. Basicaly the conversion represents the quantization of the input meaning that some error it will be introduced. The AVR ATmega8 ADC has an input values interval between 0 and 5 volts meaning that its 10 bit convertor will output numbers from this interval between 0 – 1023. The output values are a sequence of digital values that have been converted from continous-time and continous-amplitude analog signals to discrete-time and discrete-amplitude digital signal.
With the use of ADC, the solution to implement three buttons on a single pin is quite simple. A different voltage must be generated for each of the pressed buttons so a voltage divider was implemented. The resistors had values of 50 Ω , 2.2 kΩ and 6.6 kΩ providing voltages of 0.024 V, 0.897 V, 1.987 V.
All this voltages will be converted by the converter into the following digital numbers: 5, 184 and 407.
In the source code three macros for each buttons were created and when an button is pressed a condition was put to see what button was pressed (using those macros – which are the numbers given by ADC), and another condition to set what each button does. Two of the butons represent up and down and the third one represent the OK button.
The code was written in a more professional way so output numbers from this interval between 0 – 1023. The output values are a sequence of digital values that have been converted from continous-time and continous-amplitude analog signals to discrete-time and discrete-amplitude digital signal.
With the use of ADC, the solution to implement three buttons on a single pin is quite simple. A different voltage must be generated for each of the pressed buttons so a voltage divider was implemented. The resistors had values of 50 Ω , 2.2 kΩ and 6.6 kΩ providing voltages of 0.024 V, 0.897 V, 1.987 V.
All this voltages will be converted by the converter into the following digital numbers: 5, 184 and 407.
In the source code three macros for each buttons were created and when an button is pressed a condition was put to see what button was pressed (using those macros – which are the numbers given by ADC), and another condition to set what each button does. Two of the butons represent up and down and the third one represent the OK button.
The code was written in a more professional way so that if a new reader wants to add another features, to be able to do that without losing to much time to understand the code. There are functions for almost every action and the almost all the code is commented (not the simple code, but the more complex one).
In the end, resulted a fully functional device, capable of testing RS485 communication and voltages on the communication line as specified in the requirements of the project.
Planificarea activității
Stadiul actual
Lucrarea de diplomă abordează problema apariției erorilor în sistemele senzoriale. Un sistem senzorial este un sistem tehnic care prezintă un comportament bine definit. O eroare reprezintă abaterea de la funcționarea sa în regim normal. Metodele de diagnosticare a erorilor constau în determinarea tipului de defect, gravitatea și localizarea defectului. Cu cat există mai multe detalii despre defectul apărut, cu atât soluționarea erorilor se realizează mai ușor.
Diagnozele manuale există de când s-au produs primele sisteme tehnice, însă diagnozele automate au apărut pentru prima dată atunci când s-au inventat calculatoarele. Primele domenii care au beneficiat de aceste diagnoze au fost aplicațiile aerospațiale, iar ulterior s-au introdus în uzinele chimice. Cercetarile s-au accentuat între anii '80 și anii '90 iar în ziua de azi, aceasta este încă o zonă extinsă de cercetare.
Fie că vorbim de o diagnoză medicală, fie despre una tehnică, dintr-o perspectivă generală putem să o explicăm pe aceasta în următorul fel: pentru un proces, există diferite variabile sau comportamente, iar pentru fiecare dintre acestea există o cunoaștere a ceea ce trebuie să se întâmple, a ceea ce trebuie să fie normal. Scopul diagnozei este de a analiza aceste comportamente și de a verifica dacă există sau nu o abatere de la comportamentul normal.
Prezenta lucrare se concentrează pe diagnoza unei rețele de circuite dintr-un baraj și principalul obiectiv este identificarea erorilor pe linie, atunci când acestea apar. Erorile pot proveni de la anumiți senzori, actuatori, etc.
Pentru a putea determina dacă sistemul funcționează sau nu corect, avem nevoie de anumite semnale primite de la senzori externi. Diagnoza se evaluează observând inconsecvențele dintre variabilele rezultat și cele considerate a fi normale.
Diagnoza sistemelor senzoriale se poate realiza fie în timp ce sistemul funcționează, fie în timp ce acesta este oprit. De obicei, atunci când diagnoza se realizează în timp ce sistemul funcționează, aceasta se realizează automat, fără implicarea unei ființe umane.
Tema aleasă are o importanță extrem de ridicată deoarece aceste diagnoze se pot folosi în aproape toate domeniile. Cele mai importante dintre ele sunt cele din cadrul industriei automobilelor, a industriei aeronautice și poate cel mai important, în medicină. Pentru evitarea situațiilor în care se riscă viața oamenilor, o sumedenie de teste trebuie făcute atunci când inițializăm diferite aparate.
Ca și exemplu ce întărește ipotezele prezentate, un elicopter are extrem de multă tehnologie iar un defect la nivel de senzori, actuatoare, sau sisteme de control ar fi catastrofic. Dacă defectul nu este depistat la timp, acesta poate să se prăbușească.
Supravegherea automată a sistemelor tehnice poate duce la detectarea comportamentamentelor care nu ar trebui să existe și la aplicarea unor măsuri pentru corectarea acestora și prevenirea accidentelor.
Există mai multe tipuri de sisteme de diagnoză. Clasică (sau de monitorizare). Această diagnoză verifică dacă variabilele sistemului sunt în parametri optimi, în funcție de toleranța admisă, iar dacă se depășesc valorile normale, o alarmă se va declanșa pentru a înștiința operatorul. O alta diagnoză este cea cu protecție automată, în care atunci când se sesizează anumite defecțiuni, se inițializează automat o măsura de contracarare a erorii.
Această lucrare își propune testarea unui sistem senzorial bazat pe o comunicație RS485.
Pentru acest lucru, s-a creeat un dispozitiv electronic al cărui utilizare este ușoară, tocmai pentru a putea fi folosit de către orice persoană neavizată. Interacțiunea dintre aparat și utilizator se realizează prin intermediul unor butoane și al unui display. Se dorește să se poate selecta un anumit test din meniul cu teste și să se afișeze rezultatul pe un display LCD.
Fundamentare teoretică
2.1 Sisteme Embedded
Un sistem embedded reprezintă un sistem computerizat (automat) care îndeplinește o funcție bine definită și care face parte dintr-un sistem mecanic sau electric mai mare. Aplicațiile moderne încorporate, sau sistemele încorporate au la bază utilizarea unui microcontroler și a perifericelor subsidiare lui.
În funcție de complexitatea sistemelor se folosesc diferite microcontrolere cu diferite specificații tehnice, de la microcontrolere de uz general la integrate specifice, unele create chiar special pentru aplicația în cauză. Acestea din urmă se numesc ASIC (Application Specific Integrated-Circuit) și pentru sisteme complicate sunt soluția optimă deoarece ele sunt creeate să facă exact ceea ce este nevoie. Chipurile ASIC au un singur scop pe toată durata funcționării (existenței) lor și acesta este bine definit la început. Complexitatea acestora a crescut enorm în ultimii ani iar dimensiunile au scăzut . Pentru schițarea unei idei , la început, aceste chipuri aveau aproximativ 5000 de porți logice, iar acum s-a trecut de 100 de milioane pentru același chip. Chipurile ASIC moderne au mai multe microprocesoare, conțin memorie ROM, EEPROM, RAM și memorie de tip FLASH.
În loc de microcontrolere se mai folosesc și FPGA-uri (field programmable gate arrays) – blocuri logice programabile deoarece sunt capabile să efectueze mai multe operații paralele. FPGA-urile au apărut în anii 80, fiind niște dispozitive bazate pe semiconductoare,formate din elemente logice interconectate și blocuri de intrări/ieșiri. Avantajele FPGA-urilor față de alte dispozitive sunt viteza de procesare mare și consumul de putere redus, iar un FPGA de tip ASIC va consuma și mai puțin deoarece este optimizat pentru aplicație.
Sistemele embedded sunt răspândite foarte mult în ziua de astăzi, aproape orice dispozitiv realizează un sistem de acest tip: roboți de bucătărie, industria automobilelor, medicină, în telecomunicații, aplicații militare, etc.
Aplicația dezvoltată în prezenta lucrare va funcționa ca un sistem embedded. Va avea nevoie de un micropocesor care va face calculele, un display de tip LCD și componente auxiliare.
Cea mai bună alegere pentru sistemul dorit este folosirea unui microcontroler deoarece acesta poate fi considerat el însuși un sistem independent cu microprocesor, periferice și memorie și poate fi folosit cu ușurință în aplicații embedded. Un sistem embedded reprezintă un sistem computerizat (automat) care îndeplinește o funcție bine definită și care face parte dintr-un sistem mecanic sau electric mai mare. Aplicațiile moderne încorporate, sau sistemele încorporate, au la bază utilizarea unui microcontroler și a perifericelor subsidiare lui.
În funcție de complexitatea sistemelor, se folosesc diferite microcontrolere cu diferite specificații tehnice, de la microcontrolere de uz general la integrate specifice, unele create chiar special pentru aplicația în cauză. Acestea din urmă se numesc ASIC (Application Specific Integrated-Circuit) și pentru sisteme complicate sunt soluția optimă, deoarece ele sunt create să facă exact ceea ce este nevoie. Chipurile ASIC au un singur scop pe toată durata funcționării (existenței) lor și acesta este bine definit la început. Complexitatea acestora a crescut enorm în ultimii ani iar dimensiunile au scăzut . Pentru schițarea unei idei , la început, aceste chipuri aveau aproximativ 5000 de porți logice, iar acum s-a trecut de 100 de milioane pentru același chip. Chipurile ASIC moderne au mai multe microprocesoare, conțin memorie ROM, EEPROM, RAM și memorie de tip FLASH.
În loc de microcontrolere se mai folosesc și FPGA-uri (field programmable gate arrays) – blocuri logice programabile deoarece sunt capabile să efectueze mai multe operații paralele. FPGA-urile au apărut în anii 80, fiind niște dispozitive bazate pe semiconductoare,formate din elemente logice interconectate și blocuri de intrări/ieșiri. Avantajele FPGA-urilor față de alte dispozitive sunt viteza de procesare mare și consumul de putere redus, iar un FPGA de tip ASIC va consuma și mai puțin deoarece este optimizat pentru aplicație.
Sistemele embedded sunt răspândite foarte mult în ziua de astăzi, aproape orice dispozitiv realizează un sistem de acest tip: roboți de bucătărie, industria automobilelor, medicină, în telecomunicații, aplicații militare, etc.
Aplicația dezvoltată în prezenta lucrare va funcționa ca un sistem embedded. Va avea nevoie de un micropocesor care va face calculele, un display de tip LCD și componente auxiliare.
Cea mai bună alegere pentru sistemul dorit, este folosirea unui microcontroler. deoarece acesta poate fi considerat el însuși un sistem independent cu microprocesor, periferice și memorie și poate fi folosit cu ușurință în aplicații embedded.
2.1.1 Microcontrolere
Apariția microcontrolerelor și a microprocesoarelor a determinat crearea unor noi posibilități de verificare a sistemelor tehnice. În ultimii cincisprezece ani comunitatea științifică a pus mare accent pe dezvoltarea tehnologiilor în ceea ce privește diagnoza sistemelor tehnice. În ceea ce privește lucrarea de față, aceasta va face uz de folosirea unui microcontroler.
Un microcontroler este un mini calculator într-un circuit integrat și el conține un
procesor, memorie și alte dispozitive periferice care se pot programa. Memoria unui microcontroler este în general de tip EEPROM iar acesta mai poate dispune și de memorie RAM.
Primul microprocesor (cu un sigur chip) a fost realizat în anul 1971 de către doi ingineri de la Texas Instruments, Gary Boone și Michael Cochran și se chema TMS 1000. Acesta avea un procesor pe 4 biți și a fost testat mai mulți ani pentru a vedea dacă se poate integra în aplicații embedded pre-programate . Mai târziu, în 1974, acest model de microprocesor a fost lansat pentru a putea fi folosit de către oricine.
Majoritatea microcontrolerelor din perioada aceasta erau de două tipuri. Un model avea memorie EPROM care se putea șterge printr-o fereastră transparentă. Expunerea acestei ferestre la lumină ultravioletă determina ștergerea chipului. Celălat tip de microcontroler avea memorie PROM (Programable Read-Only Memory), adică putea fi programat doar o singură dată. Memoria PROM folosită era de același tip ca și cea EPROM, însă datorită faptului că nu putea fi expusă unei luminii ultraviolete, nu putea fi ștearsă.
În 1993 a apărut memoria EEPROM (Electrically Erasable Programmable Read-Only Memory) și odată cu ea a apărut microcontrolerul PIC16C84, microcontroler care a devenit foarte popular printre cei care aveau ca hobby dezvoltarea de aplicații cu aceste chipuri. Faptul că memoria era acum EEPROM a schimbat total lucrurile, deoarece pentru ștergerea acesteia nu era nevoie de dispozitive speciale ca pentru EPROM. Astfel, oricine avea cunoștințe în domeniu, putea să-și creeze o mică aplicație embedded. Această memorie care putea fi ștearsă electronic a apărut mai devreme de 1993 însă era mult mai scumpă și mult mai puțin durabilă, ceea ce o făcea improprie pentru microcontrolerele de tip low-cost produse în masă.
În același an, Atmel a fabricat primul microcontroler care folosea memorie FLASH, o memorie de tip EEPROM mai specială. Această memorie este o memorie electronică non-volatilă, în care datele rămân stocate și dacă ea nu este alimentată cu energie electrică. Acest tip de memorie a fost inventată în anii 80 de către Toshiba, iar numele de memorie „flash” provine de la faptul că cipul se poate șterge printr-o singură operație.
Memoria FLASH este împărțită în două categorii, memorie bazată pe porți logice SAU-NU și memorie bazată pe porți logice ȘI-NU. Datorită faptului că cele două tipuri de memorii diferă ca și construcție, și proprietățile lor sunt oarecum diferite. Cu chipurile ȘI-NU se pot realiza stocări de date mult mai mari decât cu cealaltă tehnologie, acestea fiind gândite și pentru un ciclu de scriere-stergere mai mare. Chipurile SAU-NU sunt au capacități de stocare mai mici și sunt mai scumpe, însă compensează prin viteza de accesare a datelor.
Cu toate că sunt probabil cele mai răspândite tipuri de memorii, au și niște dezavantaje destul de consistente. Dacă nu se folosesc vreme îndelungată, datele se pot pierde, iar faptul că au un număr limitat de scrieri-ștergeri este din nou o limitare care merită să fie luată în considerare atunci când trebuie să folosești o memorie.
Marea majoritate a microcontrolerelor din ziua de astăzi se folosesc în industira sistemelor embedded, o industrie care a crescut foarte mult în ultimul deceniu. Telefoane mobile, aparate electrocasnice, diferite dispozitive electronice sau automobile toate împart ceva comun. Faptul că folosesc cel puțin un microcontroler.
Microcontrolerele trebuie să ofere un răspuns în timp real a evenimentelor ce se întâmplă într-un sistem integrat pe care îl controlează. Astfel, când în sistem apare un eveniment, un semnal de întrerupere trebuie trimis către procesor, semnal care îi spune acestuia să suspende instrucțiunea curentă și să trateze evenimentul care a generat întreruperea printr-o rutină de tratare a întreruperii (ISR). După ce procesorul tratează întreruperea, revine la instrucțiunea pe care o executa inițial.
Întreruperile sunt dependente de microcontroler și de multe ori acestea includ întreruperi de genul internal timer overflow, întreruperi generate de schimbarea nivelului logic a unui pin (când se folosesc butoane de exemplu), sau întreruperi generate de primirea unor date. Multe sisteme embedded au nevoie de informații de la mediul înconjurător, semnale provenite de la diferiți senzori. Pentru a putea citi acești senzori, microcontrolerele au nevoie de convertoare. Convertoarele analog-numerice sau ADC-urile (analog to digital converters) sunt folosite de către microcontrolere deoarece acestea nu pot interpreta informația analogică. Astfel, informația analogică se convertește cu ajutorul acestor convertoare. Unele controlere oferă convertor numeric-analogic sau DAC (digital to analog converter) pentru a scoate un nivel de tensiune, sau un semnal analogic.
Programele scrise cu ajutorul limbajelor de programare de tip high-end, trebuie convertite în cod mașină și doar apoi scrise în memoria microcontrolerelor. Convertirea propriu-zisă se realizează cu ajutorul compilatoarelor și al asambloarelor.
În alegerea microcontrolerului trebuie să se țină cont de mai multe aspecte: perifericele de care este nevoie, arhitectura necesară, memoria de care dispune acesta și costurile.
Microcontrollerele AVR (megaAVR) fabricate de Atmel sunt realizate pe 8 biți și au o structură internă asemănătoare cu cea a celorlalte familii de microcontrollere RISC (Reduced Instruction Set Computing). Acestea sunt ușor de folosit, au un consum mic și complementează microcontrollerele ARM (tot de la AVR) oferind o combinație unică de performanță și flexibilitate.
Cele mai importante componente ale structurii interne sunt: oscilatorul, numărătorul de program (program counter), registrul de instrucțiuni, memoria de program, regiștrii de uz gemera, decodorul de instrucțiuni, memoria EEPROM si RAM, unitatea aritmetică și logică (ALU), regiștrii de intrare și de ieșire, sistemul de întreruperi, watchdog-ul (ceas de gardă), diferite interfețe de comunicație (SPI, UART,TWI, USB, CAN, LIN, etc) și convertoare analog-numerice (ADC).
Microcontrollerele AVR RISC au o arhitectură Harvard, având bus separat pentru memoria de date și memoria de program, iar frecvențele de ceas diferă de la microcontroller la microcontroller. De exemplu, unele microcontrollerele tinyAVR au frecvență minimă de 4 MHz (ATtiny 4/ATtiny 5) iar altele au frecvență maximă de 20 MHz (ATtiny 25/ ATtiny 45/ ATtiny 85). Unele microcontrollere ATmega au frecvențe de până la 32 MHz însă majoritatea au o frecvență de 8 – 16 MHz pentru a nu crește consumul.
Frecvența la care funcționează un microcotroller influențează curentul de alimentare, iar pentru ca acest curent consumat să fie cât mai mic ( sisteme care sunt alimentate de la baterii/acumulatori), acestea au trei moduri de funcționare – Activ Mode, Idle Mode și Power Down Mode. Curenții de alimentare pentru aceste trei moduri de funcționare sunt prezentate în tabelul 1 luând în considerare frecvențe de 1 MHz respectiv 4 MHz.
Tabelul 1. Curentul de alimentare pentru anumite tipuri de microcontrollere AVR
Una dintre cele mai folosite proprietăți ale microcontrollerelor AVR este cea de întrerupere. Există o structură bine definită cu mai multe surse de întreruperi sau de reset. Vectorul de reset este plasat la adresa 0x0000. Începând cu 0x0001 există ceilalți vectori de întrerupere implementați în microcontroller. Pentru fiecare vector de întrerupere există rezervat în memoria de program un singur cuvânt. În aceste locații se vor plasa instrucțiuni de salt la subrutinele de tratare a întreruperilor.
Întreruperile implementate în microcontrollerele AVR pot fi activate prin setarea bitului 7 (bitul I) din registrul SREG (tabelul 2).
Tabelul 2. Registrul SREG
Bitul 7 activează întreruperile globale (Global Interrupt Enable) iar apoi întreruperile individuale sunt activate în regiștrii de control diferiți. Când o întrerupere apare, bitul I este șters de către hardware și orice altă întrerupere care apare nu este validată până când acest bit nu este setat din nou. Setarea se face prin soft sau la revenirea din întrerupere (prin instrucțiunea RETI). Bitul mai poate fi setat și șters de către aplicație folosind instrucțiunile SEI și CLI.
Întreruperile externe sunt generate de semnale aplicate pe anumite intrări ale microcontrollerului. ATmega 8 are două intrări pentru generarea întreruperilor externe, iar validarea acestor întreruperi se face prin setarea biților de validare a întreruperilor externe în registrul GICR( General Interrupt Control Register). Generarea întreruperilor externe se poate face pe nivel de logic „0”/„1” sau pe fronturi pozitive/negative.
Întreruperile generate prin numărare sunt întreruperi ce pot fi mascate ca și întreruperile externe. Mascarea lor se face în registrul TIMSK (Timer/Counter Interrupt Mask Register). Timerele/Contoarele interne pot avea o viteză de ceas setată de utilizator (prin prescalator) sau prin legarea unui clock extern la pinul T0.
Timerul 0 este un contor pe 8 biți care numără înainte, iar pentru anumite microcontrollere care au implementată o funcție de generare de semnal PWM pentru acest numărător, acesta numără înainte și înapoi.
Figura 1. Timer pe 8 biți din ATmega8
2.1.2 Comunicarea serială pe RS-485 și RS-232
Comunicarea serială oferă o singură cale de acces a informației din punctul A în punctul B, și chiar dacă nu oferă viteze foarte mari, este folosită în detrimentul comunicării paralele atunci când este nevoie de comunicații la distanțe mai mari de cațiva metri.
Interfețele seriale pot fi folosite pentru a genera nivele logice standardizate de la transmițător la receptor. Unul dintre cele mai vechi standarde de comunicație este RS-232. Acest standard a apărut în jurul anilor 1962, ca și soluție pentru interconectarea echipamentelor de comunicație. În timp a ajuns să fie folosită în calculatoare, modemuri, terminale video, etc. Primul calculator personal care avea port serial RS-232, era folosit pentru conectarea acestuia cu o imprimantă sau cu un alt dispozitiv.
Standardul definește un nivel logic de „1” pentru o tensiune între -3V și -25V și un „0” logic pentru o tensiune între +3V și 25 V (fig.2).
Tensiunile cuprinse între -3V – 3V sunt interzise , aceste tensiuni fiind considerate nivele de zgomot. În aplicațiile practice, nivelele de „0” logic sunt cuprinse între +5V și +15V, iar nivelele de „1” logic sunt cuprinse între -5V și -15 V.
Standardul specifică patru tipuri de linii: 4 linii de date, 11 linii de control, 3 linii de sincronizare și 2 linii de masă .
Lungimea cablurilor determină viteza maximă de transmisie și aceasta,în general, nu ar trebui să fie mai mare de 15 metri. Dacă nu este nevoie de viteză mare de transmisie, iar distanțele sunt mici, se pot folosi cabluri obișnuite, neecranate. Ecranul se folosește în momentul în care dorim să reducem interferențele datorate celorlalte echipamente electronice folosite, acesta legându-se la masa de protecție (la conectorul cu 25 de pini) sau la masa circuitului (pentru conectorul cu 9 pini). Un lucru ce influențează viteza de transmisie este capacitatea cablului.Orice capacitate mai mare de 2500 de picofarazi limitând rata de transmisie la maxim 20 kbiți / secundă.
Figura 2. Nivelele logice standardizate pentru interfața seriala RS-232.
Standardul RS-232 oferă mai multe tipuri de interfațări: cu 4,9 sau 25 de pini (fig.3). În aplicațiile practice,de obicei, nu se folosesc toate cele 25 de fire, ci cel mult 10, iar unul dintre conectoarele populare din ziua de astăzi este cel cu 9 pini, DB-9.
Figura 3. Conector RS-232 cu 9 pini (DB-9).
Rolul fiecărui pin este explicat în tabelul de mai jos.
Tabelul 3. Rolul pinilor pentru conectorul cu 9 pini.
Unul dintre marele dezavantaje ale transmiterii datelor pe RS-232 este lipsa imunității la zgomot. Transmițătorul și receptorul, compară valorile tensiunilor de pe linia de date și aplică handshake-ul la referința comună, linia de masă. După cum se observă în figura 2, nivelul de trigger este setat destul de sus, între V. Zgomotul este ușor recepționat iar astfel distanța va fi limitată și viteza de transmisie va scădea de asemenea.
RS-485 este unul dintre cele mai versatile standare de comunicație. Acesta este o interfață serială ce oferă viteze de transmisie a datelor de aproximativ 35 Mbiți/secundă până la 10 metri și 100 Kbiți pana la 1200 de metri. Standardul de comunicație folosește o transmisie semi duplex diferențială cu nivele logice asemănătoare celor de la RS-232 și astfel : nivel logic de „0” între +2 și +6 V și nivelul de „1” logic între -2 și -6 V (fig 2). Comunicarea half duplex înseamnă că informația poate circlula într-un singur sens la un moment dat, iar orice dispozitiv poate fi fie transmițător fie receptor într-o rețea.
Contrar comunicării RS-232, RS-485 are fire torsodate (răsucite) pentru a anula interferența electromagnetică a surselor de perturbare externă. Această metodă de a răsuci firele se numește transmisie diferențială. Zgomotul este generat de către câmpurile magnetice din mediul exterior (fig. 4). În firele paralele, tot zgomotul (curentul) indus „curge” în aceeași direcție, practic generând o buclă de curent exact ca într-un transformator obișnit. Când cablurile sunt răsucite, se observă faptul că în anumite părți ale liniilor de semnal, direcția curentului este în direcție opusă față de curentul din alte părți alea cablului. Din această cauză, curentul zgomot rezultat este redus foarte mult față de zgomotul din liniile paralele.
Această metodă de prevenire a zgomotului se poate oarecum compara cu ecranarea firelor în sistemele de comunicație cu RS-232. Ecranul încearcă să protejeze firele de câmpurile electromagnetice prin încercarea de a le bloca trecerea. La RS-485, câmpul electromagnetic este lăsat să treacă prin fire însă acesta nu va afecta funcționarea sistemului.
Dacă o mare protecție la zgmot este necesară, se pot folosi ambele soluții, cabluri torsodate ecranate, sau cabluri torsodate ecranate cu folie sau cu tresă.
Figura 4. Inducerea zgomotului exterior în firele de transmisie
pentru un sistem transmițător-receptor bazat pe RS-485.
Topologia rețelei pentru un sistem cu RS-485 este, poate ,faptul principal pentru care sunt atât de populare în ziua de astăzi. Aceasta constă în faptul că putem avea mai multe transmițătoare și receptoare în aceeași rețea. Atunci când se folosesc receptoare RS-485 standard, cu o rezistență de intrare de 12 kΩ, este posibil să se interconecteze până la 32 de dispozitive în aceeași rețea. Mai nou există dispozitive RS-485 cu o rezistență mai mare de intrare, mărind numărul de maxim de dispozitive admise în aceeași rețea până la 256, iar pentru un număr și mai mare de ansamble, se pot folosi repetoare RS-485, ducând numarul maxim la câteva mii de dispozitive, făcând posibilă comunicația pe mai mulți kilometrii.
Cel mai important aspect este funcționalitatea. Implicit, toate transmițătoarele RS-485 de pe magistrală sunt în înaltă impedanță. În unele protocoale, configurațiile acestea pot să difere în sensul că unul dintre noduri este definit ca find master și va trimite diverse interogări sau comenzi pe magistrală RS-485. Celelalte noduri (dispozitive RS-485) aflate pe linie, primesc aceste date de la dispozitivul master. În functie de informația recepționată de dispozitivele slave, fie niciun nod nu răspunde masterului, fie unul sau mai multe noduri îi răspund acestuia. În acest caz, lățimea de bandă poate fi folosită în totalitate. Mai există alt tip de rețea RS-485 în care fiecare nod poate să înceapă o sesiune de transmitere a datelor. Funcționarea acestui tip de rețea se aseamănă foarte mult cu funcționarea rețelelor ethernet. Datorită faptului că există șanse destul de mari să existe coliziuni între date (în momentul când două sau mai multe dispozitive încep transmisia în același timp), teoria spune că timpul canalului se divide în intervale egale de dimensiune fixă. Astfel, utilizarea canalului este de aproximativ 37% din valoarea maximă a acestuia. O rețea de RS-485 construită după tiparul rețelei ethernet va trebui să aibă implementat un sistem de detectare a erorilor în protocol, care să detecteze dacă datele sunt sau nu corupte, iar dacă acestea sunt corupte, să trimită informația din nou peste un anumit interval de timp.
După ce transmisia de date a fost încheiată cu succes, dispozitivele RS-485 se întorc automat în starea de impedanță înaltă după câteva microsecunde. Mai mult de atât, nu este necesar să avem timpi de întârziere între pachetele de date trimise pe magistrală.
Fiecare comandă trebuie trimisă în ASCI și are următoarea structură: bit de start – adresă transmițător – adresă receptor – comandă – date (D1…Dn) – sumă de verificare – bit de stop.
Biții de start și cel de stop sunt folosiți pentru a înștiința receptorul că o comandă a fost trimisă sau terminată. Adresa transmițătorului este situată între 0 și FF la fel și cea a receptorului. Comanda îi spune dispozitivului ce anume să facă, datele depind de comanda care a fost trimisă, iar suma de control este folosită pentru a detecta erorile de transmisie la recepția unei comenzi.
2.1.3 Relee electromagnetice
Acest dispozitiv electronic a fost inventat în anul 1835 și funcția sa nu s-a schimbat mult de atunci. Releele electromagnetice sunt proiectate pentru diferite aplicații. Un releu electromagnetic simplu este construit dintr-un electromagnet, armătură, contacte, izolator și un resort.Acesta mai are o bobina cu miez din fier, iar când aeasta este supusă unei tensiuni electrice, miezul electromagnetului se magnetizează. Atunci când fluxul magnetic depășește un anumit prag (când curentul prin bobină depășește pragul de atragere) armătura de fier mobilă este atrasă spre cea fixă. Contactele se închid și astfel funcționalitatea sistemului se modifică.
Figura 5. Schemă internă a unui releu electromagnetic simplu.
Când nu îi mai furnizăm bobinei tensiunea necesară și magnetizarea miezului se pierde, armătura mobilă împreună cu contactul său se retrage la poziția inițială. Această demagnetizare poate produce un salt de tensiune de-a lungul bobinei și astfel armătura releului se poate distruge în timp. Pentru a evita această problemă, de obicei se pune o diodă în paralel cu bobina, cu catodul conectat spre plusul bobinei.
Contactele releelor electromagnetice pot avea mai multe stări: contact normal deschis – conectează circuitul când releul este activat, și, deconectează sistemul când releul se dezactivează (ca un întrerupător de lumină), contact normal închis – deconectează circuitul când miezul este magnetizat și conectează circuitul când releul este activat.
Releele electromagnetice sunt foarte populare datorită faptului că sunt capabile să controleze o putere mare chiar dacă ele sunt comandate cu un curent mic. Astfel se separă circuite ale căror potențiale diferă foarte mult și, cu un curent relativ mic, putem activa un releu, care la rândul său activează un alt circuit, care are nevoie de mult mai multă energie ca să funcționeze.
Dacă avem nevoie să comutăm rapid anumite semnale, soluția releului nu este cea mai bună, fiindcă din cauza părților mecanice ale acestuia, care se mișcă, timpii de comutare închis/deschis sunt mari în comparație cu timpii de comutare a unor circuite pur electronice. Timpii de comutare uzuali a unui releu electromecanic sunt în jurul a 5 – 100 ms. Totodată, din cauza părților mecanice, releul este producător de vibrații mecanice și poate fi afectat de anumite vibrații mecanice din mediu.
Caracteristicile releelor luate în calcul de obicei următoarele: tensiunea nominală a bobinei, curentul și rezistența acesteia, timpii de comutare, curentul maxim suportat de contacte, tensiunea maximă comutată, temperatura la care operează în limitele normale.
2.1.4 Modul USB pentru salvarea datelor pe memory stick
Această parte a lucrării se va implementa ulterior, in funcție de necesitatățile utilizatorului.
Pentru ca utilizatorul să beneficieze de aceste date și după ce s-a încheiat testarea propriu-zisă, este necesară folosirea unui modul de salvare a datelor pe memory stick. În funcție de montarea/nemontarea acestui dispozitiv, prețul final al aparatului diferă. Modulul de folosit se numește VDIP1 și este un MCU (multipoint control unit – microcontroller). Un MCU are integrat un microcontroler multipunct (MC) și opțional procesoare multipunct (MPs).
Componenta vine într-o configurație cu 24 de pini și se potrivește într-o capsulă DIP Socket cu 24 de pini. Modulul VDIP1 pune la dispoziție interfață UART, FIFO paralel și SPI prin intermediul pinilor AD și AC. Datorită designului și mărimii sale se potrivește în majoritatea proiectelor.
Figura 6. VDIP1
Modulul VDIP1 are integrat un microcontroler (VNC1L) și practic este un system embedded complet. Acest microcontroler controlează, handel-uiește interfața USB și transferul de date dintre microcontrollerul folosit în aplicație (ATmega8) și memoria flash. Atunci când dispozitivul este interfațat unor dispozitive de stocare în masa așa cum sunt flash drive-urile pe USB, Vinculum controlează structura FAT a acestora și comunică cu ele prin UART,SPI sau FIFO paralel, folosind un set de comenzi implementate.
Dintre metodele de comunicație, cea care folosește cei mai puțini pini, este cea pe SPI (Serial Pheripheral Interface). Această interfață oferă o bună comunicație cu dispozitive periferice lente ca și EEPROM-uri sau RTC -uri (Real Time-Clock). Dispozitivele care folosesc SPI-ul și au o relație de master/slave și în care masterful inițiează frame -ul de date. Ținând cont de faptul că această transmisie este una full duplex, atunci când materul generează clock-ul și selectează un dispozitiv slave, datele pot fi transferate simultan în orice directive. De fapt, datele sunt transmise în amândouă direcțiile tot timpul însă este de datoria masterului/slaveului să verifice dacă biții recepționați sunt într-adevăr importanți (necesari) sau nu.
Standardul SPI specifică patru semnale: semnalul de ceas (SCLK), semnal master de date de ieșire – semnal slave de date de intrare (MOSI), semnal master de intrare – semnal slave de ieșire (MISO) și semnal de selectare slave (CSS). SCLK este în majoritatea cazurilor generat de către master și se transmite mai departe către slave-urile din rețea. MOSI – poartă datele de la master către slave iar MISO poartă datele de la slave înapoi către master. Un dispozitiv slave este selectat când materul trimite un semnal de CSS. Dacă există mai multe dispositive slave, atunci masterul generează un semnal diferit pentru fiecare.
Tabelul 4. Descrierea semnalelor interfeței SPI pentru VDIP1.
Dacă se dorește să se scrie prin intermediul SPI, pinul CS trebuie din start să fie ținut în high pe tot ciclul de scriere și trebuie trecut în low pentru cel puțin o perioadă de clock după ce scrierea s-a finalizat. Primul bit pe pinul de SPI Data In este cel de de R/W – dacă este „0” , permite ca datele să fie scrise în chip. Următorul bit este bitul de adresă, ADD, care este folosit pentru a indica dacă se scrie fie în registrul de date („0”), fie în statusul registrului („1”) . În timpul ciclului de scriere, un octet de date poate fi intrare pentru pinul SPI Data In . După ce datele se scriu în chip, se verifică pinul SPI Data Out pentru a verifica dacă citirea datelor a fost acceptată. Un nivel logic de „0” pe pinul SPI Data Out înseamnă că scrierea datelor a fost acceptată, iar un „1” logic indică faptul că bufferul intern este plin și scrierea trebuie să fie repetată.
CS trebuie ținut în „0” pentru cel puțin o perioadă de clock înainte de a fi trecut în starea high din nou, pentru a putea continua cu următorul ciclu de scriere sau citire.
Operația de scriere se realizează conform figurii 7.
Figura 7. Ciclul de scriere de date în slave folosind SPI.
3. Implementarea soluției adoptate
3.1 Creearea cablajului
După creearea schemei electrice în OrCad se creează layout-ul în Layout Plus. Cablajul PCB va fi imprimat pe un singur strat și va avea o dimensiune de 90×200 mm. Etapa imediat următoare este lipirea componentelor pe cablaj și testarea unor eventuale scurturi între trasee. După ce toate traseele sunt verificate se poate trece la lipirea componentelor.
3.2 Circuitul de alimentare
Alimentarea se va realiza de la o baterie de 9 V, prin intermediul unui circuit auxiliar prezentat în figura 8. Principala componentă a circuitului este stabilizatorul de tensiune LM7805, care stabilizează tensiunea de ieșire la 5 V.
Figura 8. Schema circuitului de alimentare a întreg circuitului.
Condensatorul C6 și C7 filtrează oscilațiile de înaltă frecvență, C8 îmbunătățește filtrarea semnalului de ieșire pentru frecvențe joase (se alege în funcție de aplicație) iar C9 filtrează frecvențele înalte (se alege conform datasheetului). Ledul D10 este folosit pentru a semnaliza funcționarea circuitului de alimentare. În folosirea acestor stabilizatoare trebuie să se țină cont de faptul că ele nu sunt foarte eficiente deoarece transformă o anumită putere în căldură după următoarea formulă:
(1)
unde:
P = puterea disipată sub formă de căldură,
= tensiunea de intrare,
= tensiunea de ieșire,
= curentul ce trece prin stabilizator la momentul t.
3.3 Ecranul LCD
Afișajele LCD sunt de mai multe dimensiuni, cel mai des denumite după numarul de rânduri și coloane (lungimea în caractere a unui rand). Spre exemplu, un display de tip 16×1 are un rând cu 16 caractere, iar un LCD 20×4 are 4 randuri a câte 20 de caractere fiecare.
LCD-urile pot avea iluminare din spate (backlight) sau pot fi de tipul reflectiv (făra iluminare). Modul în care se comandă display-ul cu backlight nu diferă de cel fără backlight . LCD-urile cu backlight au 2 pini în plus pentru alimentarea grupului de LED-uri de backlight și de obicei, aceștia sunt notați cu A (anod) și K (catod).
Dispozitivul folosit va fi un display de 20×4 (fig.9), cu backlight, pe care se va afișa meniul și testele care se pot executa. Citind pinii LCD-ului din figura 9, de la dreapta la stânga, se poate observa: 1-VSS (GND), 2-VDD (Alimentare +5V), 3-VO/VEE (contrastul), 4-RS (1=caractere, 0=comenzi), 5-R/W (1=citire, 0=scriere), 6-E (impuls 1 pentru a valida caracterele sau comenzile), 7-10 (DB0 – DB3 – bus date bidirecțional între microcontroller și LCD, nu se folosește în modul de transfer pe 4 biți), 11-14 (DB4 – DB7 – bus date bidirecțional între microcontroller și LCD, se folosește în modul de transfer pe 4 biți), 15-A (Led -), 16-K (Led+).
Figura 9. Display LCD alfanumeric 20×4.
3.3.1 Comenzile și instrucțiunile LCD-ului
Doar registrul LCD-ului de instrucțiuni (IR) și registrul de date (DR) pot fi controlate de către microcontroller. Înainte de operarea propriu-zisă a LCD-ului, informația de control este stocată temporar în acești regiștrii, astfel putându-se interfața cu diferite microcontrollere care funcționează la viteze diferite sau care au periferice diferite. Funcționarea internă a LCD-ului este determinată în totalitate de semnalele trimise de către microcontroller. Aceste semnale, care includ selectarea regiștrilor RS, RW și magistrala de date (DB0 – DB7) se numesc tabelul de instrucțiuni al LCD-ului.
1.Ștergere Display
2. Setare funcții
DL = 1 – Interfață 8 biți
DL = 0 – Interfață 4 biți
N = 0; 1 linie pe display
F = setare font caractere
3. Control display ON/OFF
D = 0; Display oprit
C = 0; Cursor oprit
B = 0; Pâlpâire cursor oprit
4. Setarea modului de scriere (definește modul de scriere sau citire a datelor)
I/D = 1; Increment cu 1
S = 0; Cursor fără shiftare
3.3.2 Interfață LCD –conexiune pe 4 biți
În majoritatea aplicațiilor se preferă interfața pe 4 biți, deoarece sunt multe motive pentru această decizie. Unul dintre motivele clasice a acestui lucru este faptul că pentru această interfață este nevoie de mai puțini pini.
În modul pe 4 biți, datele sunt împărțite în parte high și parte low (nibbles). În primă instanță se trimite partea high, apoi partea low. Pentru a activa modul pe 4 biți al LCD-ului trebuie urmată o secvență de inițializare specială care îi spune microcontrollerului LCD-ului faptul că utilizatorul dorește să selectează această caracteristică. Această secvență este următoarea:
Așteptare 20 mS
Trimiterea primei valoari de inițializare (0x30)
Așteptare 10 mS
Trimiterea celei de-a doua valori de inițializare (0x30)
Așteptare 1 mS
Trimiterea celei de-a treia valori de inițializare (0x30)
Așteptare 1 mS
Selectare lățime bus ( 0x30 – pentru 8 biți, 0x20 – pentru 4 biți)
Conectarea LCD-ului la microcontroller se realizează prin intermediul portului B.
3.4 Microcontrollerul ATmega 8A
3.4.1 Dispunerea porturilor și pinilor
Pentru aplicația practică prezentată în această lucrare se va folosi un microcontroler Atmel AVR ATmega8, un microcontroler pe 8 biți. Numărul de biți reprezintă lățimea registrelor folosite pentru operațiile procesorului. Astfel, un procesor pe 64 de biți, poate face operații cu 64 de biți într-o singură instrucțiune. Pentru aceleși număr de operații, un procesor pe 32 de biți ar avea nevoie de 2 instrucțiuni.
Microcontrolerul ATmega8 are 28 de pini, 32 de regiștrii de uz general, frecvență de 16 MHz, 8 Kbiți de memorie FLASH, 1 Kbit de memorie SRAM, 512 biți EEPROM, două timere de 8 biți, un timer de 16 biți, 6 canale de ADC și multe alte proprietăți.
Pentru a putea folosi acest dispozitiv trebuie să se cunoască rolul fiecărui pin și cum anume aceștia funcționează(fig.10). Mai târziu se va selecta utilitatea pinilor necesari dezvoltării aplicației.
Figura 10. Capsulă PDIP Atmega8
VCC – Alimentarea digitală
GND – Masa
PORTB (Pin 0-7) – Port pe 8 biți bidirecțional de intrare/ieșire cu rezistențe de pull-up interne (selectabile pentru fiecare bit). Pinii 6 și 7 pot fi folosiți ca intrare pentru un oscilator cu cuarț.
PORTC (Pin 0-5) – Port pe 7 biți bidirecțional de intrare/ieșire cu rezistențe de pull-up interne (selectabile pentru fiecare bit).
PORTC (Pin 6-Reset) – Dacă programăm bitul de fuse RSTDISBL, pinul 6 este folosit ca și orice alt pin. Dacă fuse-ul de RSTDISBL este neprogramat, atunci funcția sa este de reset.
PortD (Pin 0-7) – Port pe 8 biți bidirecțional de intrare/ieșire cu rezistențe de pull-up interne (selectabile pentru fiecare bit). Portul D mai are și alte funcții speciale.
AVCC – este pinul prin care se alimentează cele 5 convertoare analog-numerice (PC 0-5)
AREF – pin prin care se poate atribui o referință analogică convertoarelor.
Microcontrolerul are asociat fiecărui port câte 3 regiștrii: DDR – care setează direcția pinilor (intrare/ieșire), PORT – care setează datele la nivel de pin și PIN – facilitează accesul la nivel de PIN.
Figura 11. Controlul statusului biților unui port al microcontrolerului.
3.4.2 Convertor Analog – Numeric
Pentru aplicația practică este nevoie de convertoare analog-numerice. Acestea funcționează după următorul principiu. La intrare se aplică o mărime analogică (de obicei tensiune), iar la ieșire convertorul va transforma aceaste valori analogice în numere digitale. Conversia implică cuantizarea marimii de intrare. Astfel întreg domeniul de variațe este împărțit în cuante de mărime determinată de rezoluția sistemului. Această cuantă face ca, orice diferență dintre două valori consecutive să nu poată fi mai mică decât ea. Astfel, va exista o eroare, eroare de cuantificare.
Cu toate că există erori de conversie, aceste erori sunt destul de mici și nu influențează sistemul, datele numerice fiind preferate atunci când este nevoie de prelucrarea acestora sub formă de anumite operații matematice. Operațiile consecutive făcute pe forma numerică a unei valori vor duce la erori nesemnificative (sau chiar zero erori) pe când, operațiile consecutive directe cu valorile analogice pot genera erori destul mari. Ca și un alt avantaj, datele numerice se pot păstra foarte ușor în memorii non-volatile.
Microcontrolerul Atmega8 are un convertor pe 10 biți cu aproximări succesive .Acesta este conectat la un multiplexor cu ajutorul căruia putem selecta o anumită intrare de ADC .Valoarea minimă digitală este 0 (GND), iar valoarea maximă este tensiunea de pe pinul AREF minus 1 LSB. Rezoluția convertorului este de 10 biți, iar precizia de 2 LSB. Conversia se realizează între 13 și 260 µs, iar tensiunea de referință se poate alege fie ca o tensiune de referință exterioară, fie cea internă de 2.56 V a microcontrolerului.
Convertorul mai dispune de două moduri de funcționare și anume modul liber, în care se fac conversii neîntrerupt, și modul conversie singulară, în care se face o conversie iar apoi un flag de terminare trebuie setat. Pentru ca zgomotul să nu afecteze conversia convertorului, uzual, se folosește un condesator de decuplare la pinul AREF.
Formula de conversie este următoarea:
(2)
ADC – valoarea digitală;
VIN – valoarea analogică;
1024 – rezoluția convertorului: ;
VREF – tensiunea de referință.
Ținând cont de faptul că nu avem nevoie de o precizie foarte mare de măsurare a tensiunilor, măsurarea (conversia) se va realiza cu două zecimale. Dintr-un calcul se poate deduce rezoluția convertorului în funcție de tensiune:
(3)
Având în vedere că, după cum s-a specificat, precizia convertorului este de 2 LSB se poate face o aproximare pentru o eroare generală de maxim 10 mV. Acest lucru nu necesistă nicio corectare deoarece, după cum se va vedea ulterior, tensiunile măsurate nu vor avea impact asupra sistemului atunci când valoarea lor se va modifica cu valori de ordinul milivolților .
În aplicație se folosesc două convertoare analog – numerice, fiecare din ele citind două tensiuni diferite. Datorită faptului că microcontrollerul nu poate face operații cu două convertoare în același timp, trebuie selectat unul, trebuie inițializat, iar apoi să se execute operațiunea de conversie cu salvarea rezultatului într-o variabilă, pentru ca apoi să se reia același proces pentru un alt convertor.
Funcțile creeate pentru convertoare sunt următoarele:
void initializare_ADC (unsigned char canal) // funcție de inițializare a ADC-urilor
{ // cu selectare canal (convertor)
if (canal==0) // initializare ADC la nivel de pin
{
cbi(DDRC,0);
cbi(PORTC,0);
}
if (canal==1) //adc1
{
cbi(DDRC,1);
cbi(PORTC,1);
}
… … … …
if (canal==5) //if adc5
{
cbi(DDRC,5);
cbi(PORTC,5);
}
else
{
//nothing
}
ADMUX = 0x40|canal;
ADCSRA = 0b10100110; //free run / "clok/64"/
}
Funcția de inițializare este o funcție cu parametru, care inițializează fiecare convertor în parte. CBI sau SBI sunt macrouri pentru setarea sau ștergerea unui pin din port pentru o manipulare mai ușoară a pinilor.
#define sbi(a, b) (a) |= (1 << (b))
#define cbi(a, b) (a) &= ~(1 << (b))
Funcția de conversie a convertorului este următoarea:
uint16_t read_adc_value(uint8_t channel_ADC)
{
static unsigned char local=0;
ADMUX |= channel_ADC; // start conversie,cu selectare canal ADC
local=ADCSRA & 0x10;
while (local != ADCSRA & 0x10) // asteptare conversie gata
{
local =ADCSRA & 0x10; //gata!
}
valoare_ADC=ADCW;
ADCSRA |= 0x10; //stergere flag intrerupere
return valoare_ADC; //returnez valoarea conversiei
}
Se face un „sau” logic între registrul ADMUX și canalul ADC ( variabila channel_ADC trecută ca parametru) pentru a selecta convertorul din care se citește. Se dă drumul la conversie iar, se așteaptă să fie gata conversia, iar apoi se citește valoarea conversiei din ADCW. Funcția returnează rezultatul conversiei.
3.4.3 Generarea întreruperilor
Timerul 0 este un numărător pe 8 biți și numără înainte. Pentru funcția de PWM el poate număra și înainte și înapoi. Citirea și scrierea acestui timer se face cu ajutorul registrului TCN0, el fiind sincronizat cu ceasul intern al microcontrollerului, însă cu posibilitatea de a-i modifica frecvența cu ajutorul biților CS00,CS01,CS02 și anume:
Tabelul 4. Selectarea semnalului de clock pentru timerul 0
Timerul 0 este folosit pentru a genera întreruperi de depășire (overflow). Atunci când acesta ajunge la valoarea maximă de numărare se resetează și biții TOVO (registrul TIFR) și TOIE0 (registrul TIMSK) sunt setați. Timerul 0 începe numărătoarea de la 0x00 și merge până la valoarea 0xFF.
Timerul 0 se inițializează prin următoarea funcție:
void initializare_time0 (void)
{
TCCR0 = 0x04; //65 us
TCNT0 = 0x01;
TIMSK |=0x01; //intreruperea overflow
}
Încărcarea valorii 0x05 în registrul TCCR0 înseamnă trecerea biților CS02 și CS00 în 1, ceea ce implică o divizare a frecvenței de clock cu 256. Ținând cont de aceast lucru se poate calcula intervalul de timp la care întreruperea de timper overflow va aparea:
(3)
Din (2) => imediat
(4)
Timerul 0 este folosit pentru detetarea întreruperii, iar în caz afirmativ, va intra în rutina de tratare a întreruperii:
ISR(TIMER0_OVF_vect)
{
Global_8 = Decodificare_buton(2) & 0xff;
if( Global_8 != 0)
{
y=0;
… //alte instrucțiuni
}
}
În întreruperea de timer se va implementa cea mai mare parte a codului. Această parte conține decodificarea butoanelor (după cum se va vedea în următorul capitol), intrarea în meniul principal al programului, selectarea testelor dorite și execuția acestora.
3.5 Implementarea butoanelor și decodificarea acestora
Figura 12. Schema butoanelor.
În figura 12 se poate observa conexiunea butoanelor. Atunci când niciun buton nu va fi apăsat tensiunea Vcc ( 5V ) va trece prin condensatorul C10 și prin eticheta btns va ajunge la pinul PC2 (convertorul ADC2) al microcontrollerului. Datorită faptului că toți pinii de ADC au alte utilități, cuplarea și decuplarea celor trei relee din circuit respectiv, aflarea celor două potențiale V1’ și V2’ pentru stabilirea polarității semnalelor, a rămas doar acest pin de ADC pentru folosirea butoanelor. În acest caz s-a căutat o soluție pentru implementarea acestei funcționalități.
Ținându-se cont de faptul că convertorul preia o tensiune, trebuie ca pentru fiecare buton să se genereze o tensiune diferită. Aceste tensiuni trebuie ca întotdeauna să fie aceleași (luând în calcul și eroarea convertorului). Cea mai simplă și eficientă soluție este creearea unui divizor rezistiv. Tensiunea rezultată din divizor va fi introdusă în convertor și în funcție de numărul generat se va cunoaște care buton a fost apăsat.
(5)
(6)
(7)
Știind că convertoarele analog numerice sunt pe 10 biți vom avea valori pentru tensiunea cuprinsă între 0 și 5 V, adică 1024 de valori distincte. Astfel se poate deduce foarte ușor valorile numerice ale convertorului pentru fiecare dintre cele trei butoane:
(8)
(9)
(10)
La apăsarea a două butoane, în orice combinație, se generează o rezistență echivalentă, paralelă, care poate produce o tensiune aproape egală cu cea a unei singure rezistențe, fapt care ar însemna că aparatul va citi apăsarea unui buton când defapt s-au apăsat două. Astfel, pentru combinația BTN1 + BTN2, va rezulta o rezistență echivalentă paralelă foarte apropiată de valoarea cea mai mică a rezistențelor (R18):
După cum se observă tensiunea la apăsarea butonelor 1 și 2 în același timp sunt identice, însă, datorită faptului că nu este o situație critică în care apăsarea unuia dintre butoane poate însemna ceva foarte important, nu necesită o soluție de remediere. Mai mult decât atât, poziționarea butoanelor nu este una extrem de apropiată în care să se poată apăsa fără voință mai multe butoane, ci doar dacă utilizatorul dorește implicit acest lucru.
Ca soluție pentru corectarea acestui „defect” se poate modifica rezistența R18 (50 Ω), ea fiind cea care influențează cel mai mult divizorul rezistiv datorită valorii sale foarte mici. La apăsarea butonului 1 și a butonului 3 va exista o rezistență echivalentă paralelă și mai apropiată de valoarea rezistenței R18:
V
Presupunând că se schimbă valoarea rezistenței R18 de la 50 Ω la 1.8 kΩ vor rezulta următoarele rezistențe echivalente: R18||R19 = 990 Ω, R18||R20 = 1414 Ω, R19||R20 = 1650 Ω, iar R18||R19||R20 = 860 Ω, suficiente încât să nu afecteze dispozitivul la apăsarea mai multor butoane.
Cu toate că pentru aplicația aceasta nu este necesară o implementare a acestei funcționalități, trebuie să se ia în considerare valorile generate de convertor pentru aceste tensiuni generate de către fiecare buton. Pentru implementarea acestei caracteristici într-o manieră cât mai elegantă se vor folosi macrouri pentru fiecare număr generat de ADC și anume:
#define Buton1 5
#define Buton2 184
#define Buton3 407
Folosirea macrourilor pentru fiecare din cele trei butoane va face ca o citire ulterioară a codului sursă să fie mult mai bine înțeleasă. Acest lucru este valabil și pentru implementarea unor noi funcționalități.
În continuare se va prezenta decodificarea butoanelor.
S-a implementat codul de mai jos pentru deocodificarea butoanelor. Aceasta se face după organigrama prezentată la figura 13.
unsigned char Decodificare_buton(unsigned char canal)
{
unsigned int Var_ADC = 0,ADC_medie = 0;
unsigned char REG_loc = 0;
static unsigned int oldVar_ADC = 0;
ADMUX = 0x40|canal; //1 în RFS0, adică selectăm referința externă cu condensator la
// pinul AREF. Se face un sau logic pentru selectarea //convertorului
for (Var_ADC = 0; Var_ADC < Nr_esantion; Var_ADC++) //nr eșantion = 32
// se folosește pentru a avea o //măsurătoare cât mai precisă
{
REG_loc = ADCSRA & 0x10;
while(REG_loc != 0x10) //așteptăm flagul de întrerupere (ADIF)
{
REG_loc = ADCSRA & 0x10; //conversie gata
}
ADC_medie += ADCW; //adunăm valorile
ADCSRA |= 0x10; //ștergere flag întrerupere
}
ADC_medie = ADC_medie >> Nr_esantion_shift; //calculare medie a valorilor ADC
if( ADC_medie < oldVar_ADC)
{
Var_ADC = oldVar_ADC-ADC_medie;
//banda buton e folosită pentru a avea o marjă de eroare la apăsare, deoarece //valoarea ADC-ului poate să nu fie 100% exactă. Banda butoane = 10.
//Buton1, Buton2, Buton 3 sunt valorile (7), (8) și (9).
if ((Var_ADC >= (Buton1 -BandaButon)) && (Var_ADC <= (Buton1 + BandaButon)))
{
REG_loc = 1;
oldVar_ADC = ADC_medie;
}
if ((Var_ADC >= (Buton2 -BandaButon)) && (Var_ADC <= (Buton2 + BandaButon)))
{
REG_loc = 2;
oldVar_ADC = ADC_medie;
}
if ((Var_ADC >= (Buton3 -BandaButon)) && (Var_ADC <= (Buton3 + BandaButon)))
{
REG_loc = 3;
oldVar_ADC = ADC_medie;
}
}
//în funcție de ce buton este apăsat , se va returna valoarea 1,2 sau 3.
else
{
REG_loc = 0; //nu este apăsat niciun buton
oldVar_ADC = ADC_medie;
}
return REG_loc;
}
Figura 13. Organigrama codului de decodificare a butoanelor.
3.6 Releele electromagnetice
Releele electromagnetice folosite în aplicație sunt niște relee de tip reed, produse de Meder, cu codul Dip05-1c90-51l .
Figura 14. Schema internă a releului Dip05-1c90-51l
Din figura 14 se observă faptul că releul este unul de tip deschis. La conectarea bobinei între pinii 2 și 6, contactul se va închide la pinul 14, astfel orice semnal aflat la pinul 14 va trece automat spre pinii 8 respectiv 7.
3.7 Testarea liniei și verificarea automată a polarității
Fie că este vorba despre o linie de comunicație, fie că e linie normală de tensiune, în ambele cazuri apariția defectelor poate surveni oricând. Aceste defecte trebuie detectate și remediate. Defectele pe linia de comunicație pot apărea în momentul în care se defectează fizic un cablu, comunicația fiind afectată.
Funcționalitatea produsului finit se învârte în jurul unor teste implementate în microcontroller, astfel se dorește ca un prim test să fie cel de verificare a polarității rețelei seriale de comunicație. În caz că în aparat se introduce invers mufa de conectare la rețeaua de transmisie este necesar să se detecteze acest lucru. O măsurătoare cu o polaritate greșită va duce la rezultate eronate. În caz că polaritatea este greșită, toate testele implementate nu se vor mai executa.
Astfel, ca acest test să poată fi făcut, trebuie să se măsoare efectiv tensiunea între punctele Vcc și GND de pe linia de comunicație. În figura 16, tensiunea Vcc este simbolizată cu valoarea 12Vi.
Fig. 15 Linia de transmisie RS485.
Există mai multe metode de măsurare a unei tensiuni:
Se pot folosi amplificatoare operaționale deoarece acestea au un domeniu larg răspândit în mai multe aplicații. Măsurări de instrumentație, calcule analogice (adunări, scăderi, multiplicări, derivări, integrări, etc), control și reglare a sistemelor.
Folosirea unui amplificator operațional inversor poate fi o soluție pentru verificarea polarității. Astfel, folosind amplificatorul din figura 17 se poate deduce că:
Dacă se respectă polaritatea, atunci tensiunea Vcc de pe linie ( 5V ) va ajunge la intrarea V+ a amplificatorului, iar GND va fi conectat la intrarea V- a amplificatorului. Tensiunea de ieșire a amplificatorului trebuie să fie o valoare oarecare până în maxim 5 V, deoarece convertorul nu poate primi tensiuni mai mari de 5V. Astfel se alege tensiunea 5 V pentru a fi în concordanță cu tensiunea Vcc.
Figura 16. Folosirea unui amplificator operațional pentru detecția polarității
Se poate calcula tensiunea de ieșire atunci când polaritatea este corectă (adică V+ = 5V și V- = 0 V):
( 11)
Iar când polaritatea este greșită (adică cei 5 V vor ajunge pe intrarea minus a amplificatorului și la intrarea V+ vor fi 0V):
( 12)
O soluție și mai simplă ar fi folosirea unui repetor. Se construiește un repetor ca în figurile următoare:
Figura 17. Schema inversor.
Dacă tensiunea are polaritatea corectă, la ieșire vor fi 0 V, iar dacă polaritatea va fi greșită la ieșire vor fi 5 V. Chiar dacă este o logică inversată, se poate modifica acest lucru în codul sursă (prin folosirea unui macrou) pentru ca să fie mult mai ușor înțeles de către o persoană care citește pentru prima dată codul.
Aceste două soluții sunt destul de simple, însă atunci când vrem să comparăm între două tensiuni de pe linie A și B, se va complica schema de implementare, fapt care se dorește a fi evitat.
Astfel, pentru soluția cea mai simplă a fost nevoie atât de parte hardware cât și de parte software. Pentru partea de hardware se folosește un amplificator de tensiune și mai multe divizoare rezistive (fig. 18). Amplificatorul LT1013 se folosește în configurație neinversoare, cu raport de amplificare zero, deci practic un repetor. LT1013 nu este alimentat diferențial, iar la intrare lui neinversoare se face un divizor rezistiv pentru a împărții tensiunea de alimentare la jumătate. Fiind un repetor, tensiunea de intrare se va regăsi la ieșire, conform formulei divizorului rezistiv aplicat la intrare:
(13)
Figura 18. Schemă electrică pentru aflarea polarității semnalului de pe linia de comunicație.
Tensiunea de la ieșirea amplificatorului se va folosi ca masă virtuală pentru celelalte două divizoare rezistive. Semnalul V2 va fi comutat la fiecare test efectuat care implică tensiuniile de pe linia de comunicație. Spre exemplu, pentru primul test, cel de verificare a polarității, se va comuta tensiunea Vcc de pe linie cu ajutorul releelor electromagnetice.Tensiunea Vcc considerată în limite normale este cea între 4,75 V și 5,20 V. Formulele de calcul pentru potențialele V2’ respectiv V1’ sunt următoarele:
(14)
(15)
Din formulele (14) respectiv (15) se observă că pentru o tensiune V2 cuprinsă între 0 și 5 V, variația potențialului V2’ va fi cuprinsă între 1,25 V și 3,75 V, iar pontențialul V1’ nu va avea nicio variație, ci va rămâne constant la 1,25 V. Dacă mufa nu are polaritatea potrivită (conform figurii 18) V2 își schimbă poziția în locul masei, iar masa trece în locul tensiunii V2) atunci V1’ va avea variația între 1,25 V și 3,75 V pentru un V2 cuprins între 0 și 5 V, iar V2’ nu va avea nicio variație, va rămâne constant la 1,25 V.
Semnalele 12Vi, A și respectiv B sunt comutate pe rând spre punctul V2 al circuitului cu ajutorul celor trei relee electromagnetice și a celor trei tranzistoare de tip NPN. Tranzistoarele sunt comandate de către microcontrollerul ATmega8 prin pinii ADC3, ADC4, ADC5 adică portul C, pinii 3,4 și 5. După comutarea tensiunii 12Vi (tensiunea Vcc de pe linia de comunicație) la V2, la selectarea din meniu a opțiunii „Test Linie” se verifică dacă aceasta are polaritatea corectă. Acest test se face astfel: se verifică apăsarea butonului de „Test Linie”, dacă este apăsat intrăm în meniul de testare și cuplăm releul 12Vi_Relay (pentru citirea tensiunii 12Vi). Cu ajutorul funcției de citire a ADC-ului (read_adc_value) vom afla valoarea numerică a tensiunii. Se va face apoi o conversie și se va transforma în tensiune. Formula de calcul a tensiunii V2 este următoarea:
(16)
în acest caz, 2.5 V fiind tensiunea considerată masă virtuală în circuitul de aflare a polarității (fig. 18). La fel se procedează și cu celelalte tensiuni, respectiv teste.
3.8 Implementarea comunicației seriale pe RS485
3.8.1 Initializarea USART-ului și configurarea regiștrilor
USART-ul trebuie să fie ințializat pentru ca orice comuncație să poată fi realizată. Acest proces de inițializare constă în setarea baud rate-ului, setarea formatului mesajului (frame-ului) trimis pe serial și activarea transmițătorului sau receptorului în funcție de folosire. USART-ul se folosește folosind întreruperile, astfel flagul de întreruperi globale trebuie șters (și întreruperile globale oprite) atunci când se face inițializarea.
Pentru a verifica faptul că transmisiile s-au realizat cu succes se poate verifica flagul TXC din registrul UCSRA, iar pentru a verifica că nu exista date necitite din bufferul de recepție, se verifică flagul RXC din același registru. Pentru fiecare transmisie trebuie să se țină cont de faptul că bitul TXC trebuie șters (înainte ca UDR să fie scris).
Calcul baud rate: pentru un baud rate de 2400 bps la frecvența oscilatorului intern de 4 MHz, din datasheet rezultă UBRR = 207. Viteza de baud se configurează în registrul UBRRL și UBRRH.
Pe lângă stabilirea baud rate-ului trebuie să configurăm regiștrii UCSRA,UCSRB,UCRSC. Acești regiștrii sunt folosiți pentru controlul interfeței USART.
Viteza de baud se poate calcula cu formula:
(17)
În cazul de față registrul UBRRH s-a încărcat cu valoarea 0x00, iar registrul UBRRL cu valoare 0xCF (207).
Registrul UCSRA este un registru de control și stare (Usart Control and Status Registers A). Acesta poate fi citit și scris și indică starea în care se află interfața USART. Transferul datelor pe USART se face în funcție de biții din acest registru.
La inițializare registrul UCSRA va fi 0x00. Registrul UCSRB (USART Control and Status Registers B) controlează modul de transfer al datelor și poate fi scris și citit, iar registrul UCSRC (USART Control and Status Register C) poate fi citit și scris și stabilește modul de lucru al interfeței seriale, numărul de biți de date, polaritatea și paritatea. La aceeași adresă se află și registrul superior pentru stabilirea vitezei baud de comuncație (UBRRH). Selecția acestor regiștrii se face cu valoarea din bitul cel mai seminificativ al registrului UCSRC (URSEL).
Initializarea USART-ului se va face astfel:
void Initializare_serial (void)
{
//transmisie/receptie 2400 biti pe secunda
UCSRA=0x00;
UCSRB=0x98; //UCSRB = 0b10011000 – (1<<RXCIE, 1<<RXEN, 1<<TXEN)
UCSRC=0x86; //UCSRC = 0b10000110 – (1<<URSEL, 1<<UCSZ1, 1<<UCSZ0)
UBRRH=0x00;
UBRRL=0xCF;
}
3.8.2 Transmisia datelor
Transmisia pe USART este activată setând bitul TXEN (Transmit Enable) din registrul UCSRB. Baud rate-ul, modul de operare și dimensiunea frame-ului (mesajului) trebuiesc setate o dată, înainte de a face orice transisie. Dacă se folosește modul sincron de transmisie, clock-ul de la pinul XCK va fi folosit ca si clock de transmisie.
Registrul de date UDR este realizat (fizic) din doi regiștrii diferiți care folosesc aceeași adresă. Citind acest registru se poate copia conținutul său. Bufferul pentru transmisie poate fi scris doar când bitul UDRE din registrul UCSRA este setat. Informația scrisă în UDR atunci când acest bit nu este setat, va fi ignorată de transmițătorul USART. Când informația este scrisă în bufferul de transmisie și transmițătorul este setat, acesta va prelua datele și le va introduce în TSR (Transmit Shift Register) atunci când acesta este gol. Datele vor fi apoi transmise serial câtre pinul TxD.
Funcționarea transmisiei se bazează pe următorul principiu: se configurează regiștrii și se selectează viteza dorită. Atunci când se primește o comandă (de exemplu: apăsarea butonului pentru testarea conexiunii) se va genera efectiv transmisiunea serială. Se va transmite un frame de la master (M) către slave (S) ca în exemplul din următorul tabel:
Tabel 5. Exemplu de transmisie de la master către slave.
În funcție de adresa trimisă (adresă µC) un singur dispozitiv va prelua mesajul trimis de master și va răspunde ca în exemplul din tabelul 6.
Tabelul 6. Exemplu de recepție de la slave către master.
Rezultate Experimentale
4.1 Simularea unor părți din circuit
Figura 19. Simularea butoanelor.
După ce s-au calculat tensiunile generate pentru fiecare buton, s-a simulat schema pentru a verifica calculele. Punctul dintre rezistența R1 și cele trei rezistențe va fi practic potențialul dat convertorului analog-numeric.
4.2 Crearea cablajului
Cablajul s-a realizat în Layout Plus, iar firele neconectate pe bottom vor fi conectate pe top cu ajutorul firelor.
După realizarea cablajului s-a trecut la montarea componentelor electronice. Se observă în figura 20 care sunt componentele și poziția acestora. În partea stângă (la mijloc) este conectorul care face legătura dintre placa master (aceasta) și linia externă pe care sunt conectate dispozitivele slave. Se mai observă releele care comută semnalele, diodele de supresare și cei trei tranzistori aferenți celor trei relee care controlează bobinele acestora. Sub microcontroller este plasat circuitul integrat de comunicație serială pe RS485. Butoanele ajută la interacțiunea dintre utilizator și circuit.
Figura 20. Plasarea componentelor.
4.3 Programarea microcontrollerului
Codul a fost scris în programul Atmel Studio 6.2. După ce programul este compilat trebuie ca programul generat de acesta (cod mașină) să fie scris în microcontroller. Cu ajutorul programului eXtreme Burner codul mașină este scris în microcontroller.
Figura 21. Scrierea programului în microcontroller.
Testarea circuitului integrat RS485
Figura 22. Testarea circuitului RS485
Experimental (fig. 22), și din datasheetul acestei componente (SN75LBC176) s-au dedus pragurile tensiunilor în regimul de funcționare normal (transmisie / recepție):
Pentru recepție, Vcc trebuie să fie între 4,75 V și 5,25 V, tensiunea A să fie mai mare ca tensiunea B, iar raportul sumei dintre cele două tensiuni trebuie să fie mai mare decât 1,5V.
4.5 Dispozitivul Slave
Dispozitivul slave (fig. 23) se conectează la linie prin mufa ce se observă în partea stângă.Pe linie pot exista alte dispozitive slave și un dispozitiv master. În partea dreaptă este o mufă de alimentare pentru circuitul plăcuței slave
Figura 23. Dispozitiv slave.
4.6 Pornirea aparatului
Atunci când aparatul este pornit se afișează un mesaj de întâmpinare, iar atunci când utilizatorul apasă un buton se va intra în meniul principal. Ledul verde semnalizează faptul că aparatul are tensiune de alimentare. Pentru afișarea meniului principal se așteaptă apăsarea unui buton.
Figura 24. Pornirea aparatului.
4.7 Rularea testelor
După intrarea în meniul principal, utilizatorul are posibilitatea să aleagă între mai multe teste. Primul test (Testare Linie) este testul care trebuie rulat prima oară pentru a vedea dacă există tensiune de alimentare pe linia de comunicație și dacă tensiunile A și B primite sunt în parametrii normali. Microcontrollerul va calcula toate aceste date, iar apoi le va afișa pe LCD.
Dacă tensiunile sunt în limitele normale, aparatul va afișa tensiunile A și B, apoi diferența lor, apoi va afisa „Recepție” pentru a semnaliza faptul că toate condițiile pentru ca dispozitivul să fie în starea de recepție au fost îndeplinite. Dacă tensiunile nu sunt în parametrii normali, dispozitivul nu va avea nicio recepție.
Figura 25. Testarea liniei.
Cel de-al doilea test presupune transmiterea unui frame pe serial către dispozitiviul slave (fig. 26) și așteptarea răspunsului. Dacă mesajul este corect, atunci se va afișa recepția. (fig. 27)
Figura 26. Transmiterea mesajului pe serial.
Figura 27. Recepție normală pe serial.
Concluzii
În această lucrare s-a prezentat proiectarea unui sistem de testare automat, util în aplicațiile care necesită verificarea sistemelor senzoriale. Datorită folosirii comunicației 485 dispozitivul funcționează pe o rază de 1 km, fapt care îl face să fie foarte util.
De exemplu, dacă există dispozitive slave de la care sunt necesare anumite informații și acestea sunt împrăștiate pe o rază foarte mare, utilizatorul trebuie să meargă la fiecare în parte și să extragă informația dorită. Cu acest dispozitiv se renunță la deplasarea fizică și se recurge la comunicația serială ca și alternativă.
Avantajele testelor automate:
Testele se rulează efectiv și foarte rapid (chiar dacă testele se implementează la început destul de greu, odată ce acestea există nu mai trebuie nimic făcut);
Sunt mai ieftine pe termen lung ( pe termen scurt pot fi scumpe);
Detectează erorile mult mai rapid decât un om ar putea să o facă (ceea ce înseamnă că se poate interveni mult mai rapid, salvând bani și timp);
Dezavantajele testelor automate:
Aparatura poate fi scumpă;
Timpul de fabricare al dispozitivului și al testelor este unul considerabil;
Aparatele au limitările lor (chiar dacă un dispozitiv va găsi aproape toate bug-urile dintr-un sistem, nu poate ”gândi” în anumite cazuri – așadar nu toate testele pot fi făcute automat);
Avantajele testării manuale:
Pe termen scurt costul este mai mic decât la testarea automată (cumpărarea/dezvoltarea softurilor de testare sunt scumpe);
Mult mai mult probabil să se găsească defecte care nu sunt neapărat defecte, ci poate fi un mod mai ciudat de funcționare care afectează utilizatorii;
Testarea manuală este flexibilă și poate fi aplicată într-un timp mult mai rapid.
Dezavantajele testării manuale:
Anumite teste sunt dificil de făcut manual;
Testele manuale pot fi repetitive și plictisitoare;
Nu pot fi refolosite (spre exemplu, dacă un cod sursă trebuie este verificat manual, iar apoi se introduc noi bucăți de cod, se va pierde din nou foarte mult timp cu verificarea manuală a codului).
Bibliografie:
Ioan Ciascai, Microcontrolere AVR, Presa Universitară Clujeană,ISBN: 978-973-595-620-2, 2013.
Ovidiu Aurel Pop,Proiectare asistată de calculator, Editura Mediamira, Cluj-Napoca, 2007.
Ligia-Domnica Chiorean, Iulian Benta, Mircea-Florin Vaida, Petre Gavril Pop, Cosmin Striletchi, Elemente practice de bază pentru programarea în limbajul C/C++ -(editia a doua revizuita si adaugita), Editura Casa Cărții de Știință, Cluj-Napoca, ISBN : 978-606-17-0397-2, 2013
Atmel website, http://www.atmel.com/
[5] Base36 website, http://www.base36.com/2013/03/automated-vs-manual-testing-the-pros-and- cons-of-each/
[6]“SN75LBC176”, AUGUST 1990 − REVISED DECEMBER 2010
[7] Meder website, http://www.soselectronic.ro/a_info/resource/h/meder/Meder_Product_Overview.pdf
[8] Maxiintegrated, http://www.maximintegrated.com/en/app-notes/index.mvp/id/763
Anexe
Schema circuitului
Layout-ul:
Organigrama codului sursă:
Codul sursă principal:
/*
* Program Diploma.c
* DIAGNOZA SISTEMELOR SENZORIALE
*
* Created: 3/31/2014 12:30:34 AM
* Author: Frentoni Klaus
*/
//////////////////////////////////////////////
#define F_CPU 4000000UL // 4 MHz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include "initializare_periferice.h"
#include "variabile.h"
#include "LCDwrite.h"
#include "lcd_lib.h"
#include "functii.h"
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <stdbool.h>
///////////////////////////////////////////////
volatile unsigned char *Pointer_data_8 = 0;
volatile unsigned char Global_data_8 = 0;
volatile unsigned const char a=4;
volatile unsigned int global_16=0;
// variabile folosite pentru calculul tensiunilor
volatile float f16_ADC_value_V1=0; // tensiune V1
volatile float f16_ADC_value_V2=0; // tensiune V2
volatile float f16_ADC_value_V1_prim=0; // tensiune V1'
volatile float f16_ADC_value_V2_prim=0; // tensiune V2'
volatile float f16_A_signal=0; // potential A
volatile float f16_B_signal=0; // potential B
volatile char A_sign_Value[10]; // potential A -> caracter
volatile char *str1 = A_sign_Value; // pointer buffer sir caracter A
volatile char B_sign_Value[10]; // potential B -> caracter
volatile char *str2 = B_sign_Value; // pointer buffer sir caracter B
volatile char receptionp[32];
// variabile char pentru mesaje
volatile char VCC_OK[] = "Tensiune Vcc Normala"; // mesaj tensiune in parametrii normali
volatile char VCC_NOK[] = "Tensiune Vcc Absenta"; // mesaj lipsa tensiune (tensiune in parametrii anormali)
// variabile bool
volatile bool alimentare; // variabila de alimentare (daca == true -> exista o tensiune Vcc normala)
volatile bool receptie; // variabila de receptie (daca == true -> exista receptie)
volatile bool polaritate = true; // variabila de polaritate (daca == true -> avem polaritatea corecta la linia de comunicatie)
volatile bool serial;
//serial varia
volatile unsigned char Index_Receptie_PC = 0;
volatile unsigned char Variabila_Timp = 0;
//////////////////////////////////////////////
ISR(TIMER0_OVF_vect)
{
unsigned char local_8 = 0;
Global_8 = Decodificare_buton(2) & 0xff;
if( Global_8 != 0)
{
/* /////////////// PRINCIPAL MENU //////////////////////// */
y=0;
if (Global_8 ==1)
{
x–;
}
if (Global_8 ==2)
{
x++;
}
///////////////////////////////////////////////////////////////////
/* ////////////// MENIU SECUNDAR = CONEXIUNE /////////////// */
if ((x==0) && (Global_8==3)) // intru in meniul de conexiune
{
y=0;
LCDclr();
while (y==0)
{
sbi(DDRC,3); // setez pinul 3 in high (activez releul 12Vi)
sbi(PORTC,3); // setez pinul 3 in high (activez releul 12Vi)
_delay_ms(200);
Global_8 = Decodificare_buton(2) & 0xff; //citesc valoarea variabilei Global_8
initializare_ADC(0); // initializez adc0
_delay_ms(1);
f16_ADC_value_V1= read_adc_value(0); //salvez valoarea adc0 intr-o variabila
_delay_ms(1);
initializare_ADC(1); // initializez adc1
_delay_ms(1);
f16_ADC_value_V2=read_adc_value(1); //salvez valoarea adc1 intr-o variabila
LCDGotoXY(1,0);
writeLCD_meniu(3,0);
f16_ADC_value_V1_prim = (Vref*f16_ADC_value_V1)/1024; // potentialul V1' din conversie din nr-> volti
f16_ADC_value_V2_prim = (Vref*f16_ADC_value_V2)/1024; // potentialul V2' din conversie din nr-> volti
///// testare VCC linie/////
if (f16_ADC_value_V2_prim >= 3.5) // daca V2' > 3.6 V inseamna ca VCC >= 4.75 V => VCC ok.
{
alimentare = true;
LCDGotoXY(0,1);
LCDstring(VCC_OK,strlen(VCC_OK)); // scriu tensiune vcc normala
// daca V2' e mai mare sau egal decat 3.6 V inseamna
} //clar ca polaritatea este buna -> polaritate =1;s
else
{
if (f16_ADC_value_V2_prim < 3.5 ) // daca V2' < 3.6 V avem 2 posibilitati
{
if (f16_ADC_value_V2_prim +0.1 < f16_ADC_value_V1_prim) // daca V2' < V1'
{
polaritate = false; // polaritatea e gresita
receptie=false;
LCDGotoXY(0,1);
writeLCD_meniu(10,0);
}
else // altfel, oricum, tensiunea Vcc nu e suficienta/buna
{
LCDGotoXY(0,1);
LCDstring(VCC_NOK,strlen(VCC_NOK)); // tensiune Vcc insuficienta
alimentare = false;
receptie = false;
}
}
else
{
//nimic
}
}
_delay_ms(1500);
if (alimentare == true) // doar daca
{
_delay_ms(200);
cbi(DDRC,3); //inchid releul 12Vi
cbi(PORTC,3); //inchid releul 12Vi
_delay_ms(200);
sbi(DDRC,4); //deschid releul A
sbi(PORTC,4); //deschid releul A
_delay_ms(200);
initializare_ADC(0); // initializez adc0
_delay_ms(1);
f16_ADC_value_V1 = read_adc_value(0); //salvez valoarea adc0 intr-o variabila
_delay_ms(1);
initializare_ADC(1); // initializez adc1
_delay_ms(1);
f16_ADC_value_V2=read_adc_value(1);
f16_ADC_value_V1_prim =(Vref*f16_ADC_value_V1)/1024; // potentialul V1' din conversie din nr-> volti
f16_ADC_value_V2_prim = (Vref*f16_ADC_value_V2)/1024; // potentialul lui V2'
f16_A_signal = (f16_ADC_value_V2_prim * 2) – VirtualGround; // calcul valoare tensiune A (FLOAT)
_delay_ms(200);
cbi(DDRC,4); // inchid releul A
cbi(PORTC,4); // inchid releul A
_delay_ms(200);
sbi(DDRC,5); // deschid releul B
sbi(PORTC,5); // deschid releul B
_delay_ms(200);
initializare_ADC(0); // initializez adc0
_delay_ms(1);
f16_ADC_value_V1 = read_adc_value(0); //salvez valoarea adc0 intr-o variabila
_delay_ms(1);
initializare_ADC(1); // initializez adc1
_delay_ms(1);
f16_ADC_value_V2=read_adc_value(1);
f16_ADC_value_V1_prim =(Vref*f16_ADC_value_V1)/1024; // potentialul V1' din conversie din nr-> volti
f16_ADC_value_V2_prim = (Vref*f16_ADC_value_V2)/1024; // potentialul lui V2'
f16_B_signal = (f16_ADC_value_V2_prim * 2) – VirtualGround; // calcul valoare tensiune B (FLOAT)
if ( (f16_A_signal >= f16_B_signal+marja_noSig) // verific daca tensiunea A mai mare ca tensiunea B
&& (f16_A_signal + f16_B_signal) / 2 > VMC ) // si daca VMC > 1.5 V (Va+Vb)/2 > 1.5
{
receptie = true;
dtostrf(f16_A_signal,10,2,A_sign_Value); // convertesc tensiunea A in caractere
LCDGotoXY(1,2);
LCDsendChar('A');
LCDsendChar('=');
LCDstring(A_sign_Value,strlen(A_sign_Value)); // afisez tensiunea A
LCDsendChar(' ');
LCDsendChar('V');
_delay_ms(1200);
dtostrf(f16_B_signal,10,2,B_sign_Value); // convertesc tensiunea B in caractere
LCDGotoXY(1,2);
LCDsendChar('B');
LCDsendChar('=');
LCDstring(B_sign_Value,strlen(B_sign_Value)); // afisez tensiunea B
LCDsendChar(' ');
LCDsendChar('V');
_delay_ms(1200);
writeLCD_meniu(7,0); // rand gol
f16_A_signal = f16_A_signal – f16_B_signal; // calcul tensiune A – tensiune B
dtostrf(f16_A_signal,10,2,A_sign_Value); // convertesc tensiunea diferenta in caracter
LCDGotoXY(1,2);
LCDsendChar('A');
LCDsendChar('-');
LCDsendChar('B');
LCDsendChar(' ');
LCDsendChar('=');
LCDstring(A_sign_Value,strlen(A_sign_Value)); // afisez tensiunea diferenta
LCDsendChar(' ');
LCDsendChar('V');
_delay_ms(1200);
}
else // altfel nu avem receptie
{
receptie = false;
_delay_ms(1);
writeLCD_meniu(7,0); // sterg randurile 3 si 4 de pe display, adica A si B
}
}
if (receptie == true )
{
writeLCD_meniu(7,0); // sterg randurile 3 si 4 de pe display, adica A si B
_delay_ms(1);
writeLCD_meniu(8,0); // Scriu Receptie
serial = true;
}
if (receptie == false)
{
writeLCD_meniu(7,0); // sterg randurile 3 si 4 de pe display, adica A si B
_delay_ms(1);
writeLCD_meniu(9,0); // Scriu Nicio receptie
serial = false;
}
_delay_ms(1300);
cbi(DDRC,5); // inchid releul B
cbi(PORTC,5); // inchid releul B
_delay_ms(100);
y=4; // iesire while
}
} // test linie gata
/* ///////////////////////// BREAK; ////////////////////////// */
///////////////////////////////////////////////////////////////////
/* //////////// MENIU SECUNDAR = Conexiune= ////////////// */
if ((x==1) && (Global_8==3))
{
y=1;
LCDclr();
while (y==1)
{
z=3;
Global_8 = Decodificare_buton(2) & 0xff;
LCDGotoXY(1,0);
writeLCD_meniu(4,0);
f16_ADC_value_V2_prim = (Vref*f16_ADC_value_V2)/1024; // i convert adc1 to volts
dtostrf(f16_ADC_value_V2_prim,10,2,str2); // float to string
LCDGotoXY(1,1); // goto 1,1
LCDstring(str2,strlen(str2)); // write on dispaly
LCDsendChar(' ');
LCDsendChar('V');
if (Global_8 ==3)
{
y=4;
}
LCDGotoXY(0,z);
LCDsendChar('>');
}
}
/* ///////////////////////// BREAK; ////////////////////////// */
///////////////////////////////////////////////////////////////////
/* ///////// MENIU SECUNDAR = TEST COMUNICATIE = //////////// */
if ((x==2) && (Global_8==3))
{
_delay_ms(200);
y=2;
LCDclr();
//Functie_transmisie(0x01);
while (y==2)
{
z=3;
Global_8 = Decodificare_buton(2) & 0xff;
local_8 = UCSRB & 0x80;
if(local_8 != 0)
{
if (serial == true)
{
writeLCD_meniu(13,0);
}
else
{
writeLCD_meniu(14,0);
writeLCD_meniu(15,0);
LCDGotoXY(0,z);
LCDsendChar('>');
//_delay_ms(145);
}
LCDGotoXY(0,z);
LCDsendChar('>');
}
if (Global_8 ==3)
{
y=4;
}
}
}
/* ///////////////////////// BREAK; ////////////////////////// */
///////////////////////////////////////////////////////////////////
/* ///////// MENIU SECUNDAR = COMUNICATIE RS485 = ////////// */
if ((x==3) && (Global_8==3))
{
y=3;
LCDclr();
while (y==3)
{
z=3;
Global_8 = Decodificare_buton(2) & 0xff;
LCDGotoXY(1,0);
writeLCD_meniu(5,0);
LCDGotoXY(1,1);
LCDsendChar('D');
LCDGotoXY(1,2);
LCDsendChar('E');
if (Global_8 ==3)
{
y=4;
}
LCDGotoXY(0,z);
LCDsendChar('>');
}
}
/* //////////////////////// BREAK; ///////////////////////////// */
///////////////////////////////////////////////////////////////////
/* /////////////// MENIU PRINCIPAL //////////////////////// */
if (x<0)
{
x=3;
}
if (x>3)
{
x=0;
}
writeLCD_meniu(0,0);
LCDGotoXY(1,x);
_delay_ms(1);
LCDsendChar('>');
}
if ((x==2) && (Global_8==3))
{
LEDOcupat_off;
Functie_transmisie(0x01);
Index_Receptie_PC = 0;
}
Global_8 = 0;
}
// End Interrupt
int main(void)
{
initializare_time0();
Initializare_porturi();
initializare_ADC(2); // initializare ADC2 – aici sunt conectate butoanele
LCDinit(); // initializare LCD
_delay_ms(5);
LCDclr(); // clear LCD
_delay_ms(5);
LCDcursorOFF();
_delay_ms(100);
writeLCD_meniu(2,0); // meniu de inceputul programului
ADCSRA |=0x40;
Global_8 = 0;
x = 0;
Initializare_serial();
//pregatire buffer de transmis
Struct_T.Antet_Trans = Antet_Transmisie_uC_To_DL; //nu se schimba nici o data
Struct_T.Adr_uC = 0x10; //reeprezinta adresa fiecarui datalogger testat
Struct_T.Reg_Cmd_PC = 0x01; //comanda transmisa [Reset…CMD_R2]
Struct_T.Reg_Adr_Trad = 0x00; //adresa traductorului
//transmit bufferul
Variabila_Timp = 0;
Index_Receptie_PC = 0;
//enable receptie de la datalogger
LEDOcupat_on;
_delay_ms(500);
LEDOcupat_off;
_delay_ms(500);
LEDOcupat_on;
_delay_ms(500);
LEDOcupat_off;
sei(); //global interrupts
while(1)
{
}
}
ISR(USART_RXC_vect)
{
// buffer || /0x21/uC/CMD/Adr_Ap/Val_H/Val_L/Oer/Sc
// 1 2 3 4 5 6 7 8
unsigned char Data_RX = 0,Stare = 0;
Stare = UCSRA;
if((Stare & (DATA_OVERRUN |Frame_Error |Parity_Error )) == 0) //am receptie un caracter
{
global_16 = 1;
Data_RX = UDR;
Index_Receptie_PC++;
LEDOcupat_on;
if((Data_RX != Antet_Receptie_uC) && (Index_Receptie_PC == 1))
{
Index_Receptie_PC = 9;
}
if((Index_Receptie_PC > 1) && (Index_Receptie_PC <= 8))
{
if((Index_Receptie_PC == 2)&& (Data_RX != Struct_T.Adr_uC))
{
Index_Receptie_PC = 9;
}
if((Index_Receptie_PC == 3)&& (Data_RX != Struct_T.Reg_Cmd_PC))
{
Index_Receptie_PC = 9;
}
if((Index_Receptie_PC == 4)&& (Data_RX != Struct_T.Reg_Adr_Trad))
{
Index_Receptie_PC = 9;
}
if(Index_Receptie_PC == 5)
{
Struct_R.Reg_Val_H = Data_RX;
}
if(Index_Receptie_PC == 6)
{
Struct_R.Reg_Val_L = Data_RX;
}
if(Index_Receptie_PC == 7)
{
Struct_R.Reg_OE = Data_RX;
}
if(Index_Receptie_PC == 8)
{
Data_RX +=Antet_Receptie_uC;
Data_RX +=Struct_T.Adr_uC ;
Data_RX +=Struct_T.Reg_Cmd_PC ;
Data_RX +=Struct_T.Reg_Adr_Trad ;
Data_RX +=Struct_R.Reg_Val_H ;
Data_RX +=Struct_R.Reg_Val_L ;
Data_RX +=Struct_R.Reg_OE ;
if (Data_RX != 0)
{
}
else
{
LEDOcupat_off;
}
LCDGotoXY(0,0);
LCDsendChar(Struct_T.Antet_Trans);
_delay_ms(2000);
}
}
}
else
{
global_16 = 3;
Data_RX = UDR;
Index_Receptie_PC = 0;
}
}
//END INTR
////////////////////////////////////////////////////////////////////////
Bibliografie:
Ioan Ciascai, Microcontrolere AVR, Presa Universitară Clujeană,ISBN: 978-973-595-620-2, 2013.
Ovidiu Aurel Pop,Proiectare asistată de calculator, Editura Mediamira, Cluj-Napoca, 2007.
Ligia-Domnica Chiorean, Iulian Benta, Mircea-Florin Vaida, Petre Gavril Pop, Cosmin Striletchi, Elemente practice de bază pentru programarea în limbajul C/C++ -(editia a doua revizuita si adaugita), Editura Casa Cărții de Știință, Cluj-Napoca, ISBN : 978-606-17-0397-2, 2013
Atmel website, http://www.atmel.com/
[5] Base36 website, http://www.base36.com/2013/03/automated-vs-manual-testing-the-pros-and- cons-of-each/
[6]“SN75LBC176”, AUGUST 1990 − REVISED DECEMBER 2010
[7] Meder website, http://www.soselectronic.ro/a_info/resource/h/meder/Meder_Product_Overview.pdf
[8] Maxiintegrated, http://www.maximintegrated.com/en/app-notes/index.mvp/id/763
Anexe
Schema circuitului
Layout-ul:
Organigrama codului sursă:
Codul sursă principal:
/*
* Program Diploma.c
* DIAGNOZA SISTEMELOR SENZORIALE
*
* Created: 3/31/2014 12:30:34 AM
* Author: Frentoni Klaus
*/
//////////////////////////////////////////////
#define F_CPU 4000000UL // 4 MHz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include "initializare_periferice.h"
#include "variabile.h"
#include "LCDwrite.h"
#include "lcd_lib.h"
#include "functii.h"
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <stdbool.h>
///////////////////////////////////////////////
volatile unsigned char *Pointer_data_8 = 0;
volatile unsigned char Global_data_8 = 0;
volatile unsigned const char a=4;
volatile unsigned int global_16=0;
// variabile folosite pentru calculul tensiunilor
volatile float f16_ADC_value_V1=0; // tensiune V1
volatile float f16_ADC_value_V2=0; // tensiune V2
volatile float f16_ADC_value_V1_prim=0; // tensiune V1'
volatile float f16_ADC_value_V2_prim=0; // tensiune V2'
volatile float f16_A_signal=0; // potential A
volatile float f16_B_signal=0; // potential B
volatile char A_sign_Value[10]; // potential A -> caracter
volatile char *str1 = A_sign_Value; // pointer buffer sir caracter A
volatile char B_sign_Value[10]; // potential B -> caracter
volatile char *str2 = B_sign_Value; // pointer buffer sir caracter B
volatile char receptionp[32];
// variabile char pentru mesaje
volatile char VCC_OK[] = "Tensiune Vcc Normala"; // mesaj tensiune in parametrii normali
volatile char VCC_NOK[] = "Tensiune Vcc Absenta"; // mesaj lipsa tensiune (tensiune in parametrii anormali)
// variabile bool
volatile bool alimentare; // variabila de alimentare (daca == true -> exista o tensiune Vcc normala)
volatile bool receptie; // variabila de receptie (daca == true -> exista receptie)
volatile bool polaritate = true; // variabila de polaritate (daca == true -> avem polaritatea corecta la linia de comunicatie)
volatile bool serial;
//serial varia
volatile unsigned char Index_Receptie_PC = 0;
volatile unsigned char Variabila_Timp = 0;
//////////////////////////////////////////////
ISR(TIMER0_OVF_vect)
{
unsigned char local_8 = 0;
Global_8 = Decodificare_buton(2) & 0xff;
if( Global_8 != 0)
{
/* /////////////// PRINCIPAL MENU //////////////////////// */
y=0;
if (Global_8 ==1)
{
x–;
}
if (Global_8 ==2)
{
x++;
}
///////////////////////////////////////////////////////////////////
/* ////////////// MENIU SECUNDAR = CONEXIUNE /////////////// */
if ((x==0) && (Global_8==3)) // intru in meniul de conexiune
{
y=0;
LCDclr();
while (y==0)
{
sbi(DDRC,3); // setez pinul 3 in high (activez releul 12Vi)
sbi(PORTC,3); // setez pinul 3 in high (activez releul 12Vi)
_delay_ms(200);
Global_8 = Decodificare_buton(2) & 0xff; //citesc valoarea variabilei Global_8
initializare_ADC(0); // initializez adc0
_delay_ms(1);
f16_ADC_value_V1= read_adc_value(0); //salvez valoarea adc0 intr-o variabila
_delay_ms(1);
initializare_ADC(1); // initializez adc1
_delay_ms(1);
f16_ADC_value_V2=read_adc_value(1); //salvez valoarea adc1 intr-o variabila
LCDGotoXY(1,0);
writeLCD_meniu(3,0);
f16_ADC_value_V1_prim = (Vref*f16_ADC_value_V1)/1024; // potentialul V1' din conversie din nr-> volti
f16_ADC_value_V2_prim = (Vref*f16_ADC_value_V2)/1024; // potentialul V2' din conversie din nr-> volti
///// testare VCC linie/////
if (f16_ADC_value_V2_prim >= 3.5) // daca V2' > 3.6 V inseamna ca VCC >= 4.75 V => VCC ok.
{
alimentare = true;
LCDGotoXY(0,1);
LCDstring(VCC_OK,strlen(VCC_OK)); // scriu tensiune vcc normala
// daca V2' e mai mare sau egal decat 3.6 V inseamna
} //clar ca polaritatea este buna -> polaritate =1;s
else
{
if (f16_ADC_value_V2_prim < 3.5 ) // daca V2' < 3.6 V avem 2 posibilitati
{
if (f16_ADC_value_V2_prim +0.1 < f16_ADC_value_V1_prim) // daca V2' < V1'
{
polaritate = false; // polaritatea e gresita
receptie=false;
LCDGotoXY(0,1);
writeLCD_meniu(10,0);
}
else // altfel, oricum, tensiunea Vcc nu e suficienta/buna
{
LCDGotoXY(0,1);
LCDstring(VCC_NOK,strlen(VCC_NOK)); // tensiune Vcc insuficienta
alimentare = false;
receptie = false;
}
}
else
{
//nimic
}
}
_delay_ms(1500);
if (alimentare == true) // doar daca
{
_delay_ms(200);
cbi(DDRC,3); //inchid releul 12Vi
cbi(PORTC,3); //inchid releul 12Vi
_delay_ms(200);
sbi(DDRC,4); //deschid releul A
sbi(PORTC,4); //deschid releul A
_delay_ms(200);
initializare_ADC(0); // initializez adc0
_delay_ms(1);
f16_ADC_value_V1 = read_adc_value(0); //salvez valoarea adc0 intr-o variabila
_delay_ms(1);
initializare_ADC(1); // initializez adc1
_delay_ms(1);
f16_ADC_value_V2=read_adc_value(1);
f16_ADC_value_V1_prim =(Vref*f16_ADC_value_V1)/1024; // potentialul V1' din conversie din nr-> volti
f16_ADC_value_V2_prim = (Vref*f16_ADC_value_V2)/1024; // potentialul lui V2'
f16_A_signal = (f16_ADC_value_V2_prim * 2) – VirtualGround; // calcul valoare tensiune A (FLOAT)
_delay_ms(200);
cbi(DDRC,4); // inchid releul A
cbi(PORTC,4); // inchid releul A
_delay_ms(200);
sbi(DDRC,5); // deschid releul B
sbi(PORTC,5); // deschid releul B
_delay_ms(200);
initializare_ADC(0); // initializez adc0
_delay_ms(1);
f16_ADC_value_V1 = read_adc_value(0); //salvez valoarea adc0 intr-o variabila
_delay_ms(1);
initializare_ADC(1); // initializez adc1
_delay_ms(1);
f16_ADC_value_V2=read_adc_value(1);
f16_ADC_value_V1_prim =(Vref*f16_ADC_value_V1)/1024; // potentialul V1' din conversie din nr-> volti
f16_ADC_value_V2_prim = (Vref*f16_ADC_value_V2)/1024; // potentialul lui V2'
f16_B_signal = (f16_ADC_value_V2_prim * 2) – VirtualGround; // calcul valoare tensiune B (FLOAT)
if ( (f16_A_signal >= f16_B_signal+marja_noSig) // verific daca tensiunea A mai mare ca tensiunea B
&& (f16_A_signal + f16_B_signal) / 2 > VMC ) // si daca VMC > 1.5 V (Va+Vb)/2 > 1.5
{
receptie = true;
dtostrf(f16_A_signal,10,2,A_sign_Value); // convertesc tensiunea A in caractere
LCDGotoXY(1,2);
LCDsendChar('A');
LCDsendChar('=');
LCDstring(A_sign_Value,strlen(A_sign_Value)); // afisez tensiunea A
LCDsendChar(' ');
LCDsendChar('V');
_delay_ms(1200);
dtostrf(f16_B_signal,10,2,B_sign_Value); // convertesc tensiunea B in caractere
LCDGotoXY(1,2);
LCDsendChar('B');
LCDsendChar('=');
LCDstring(B_sign_Value,strlen(B_sign_Value)); // afisez tensiunea B
LCDsendChar(' ');
LCDsendChar('V');
_delay_ms(1200);
writeLCD_meniu(7,0); // rand gol
f16_A_signal = f16_A_signal – f16_B_signal; // calcul tensiune A – tensiune B
dtostrf(f16_A_signal,10,2,A_sign_Value); // convertesc tensiunea diferenta in caracter
LCDGotoXY(1,2);
LCDsendChar('A');
LCDsendChar('-');
LCDsendChar('B');
LCDsendChar(' ');
LCDsendChar('=');
LCDstring(A_sign_Value,strlen(A_sign_Value)); // afisez tensiunea diferenta
LCDsendChar(' ');
LCDsendChar('V');
_delay_ms(1200);
}
else // altfel nu avem receptie
{
receptie = false;
_delay_ms(1);
writeLCD_meniu(7,0); // sterg randurile 3 si 4 de pe display, adica A si B
}
}
if (receptie == true )
{
writeLCD_meniu(7,0); // sterg randurile 3 si 4 de pe display, adica A si B
_delay_ms(1);
writeLCD_meniu(8,0); // Scriu Receptie
serial = true;
}
if (receptie == false)
{
writeLCD_meniu(7,0); // sterg randurile 3 si 4 de pe display, adica A si B
_delay_ms(1);
writeLCD_meniu(9,0); // Scriu Nicio receptie
serial = false;
}
_delay_ms(1300);
cbi(DDRC,5); // inchid releul B
cbi(PORTC,5); // inchid releul B
_delay_ms(100);
y=4; // iesire while
}
} // test linie gata
/* ///////////////////////// BREAK; ////////////////////////// */
///////////////////////////////////////////////////////////////////
/* //////////// MENIU SECUNDAR = Conexiune= ////////////// */
if ((x==1) && (Global_8==3))
{
y=1;
LCDclr();
while (y==1)
{
z=3;
Global_8 = Decodificare_buton(2) & 0xff;
LCDGotoXY(1,0);
writeLCD_meniu(4,0);
f16_ADC_value_V2_prim = (Vref*f16_ADC_value_V2)/1024; // i convert adc1 to volts
dtostrf(f16_ADC_value_V2_prim,10,2,str2); // float to string
LCDGotoXY(1,1); // goto 1,1
LCDstring(str2,strlen(str2)); // write on dispaly
LCDsendChar(' ');
LCDsendChar('V');
if (Global_8 ==3)
{
y=4;
}
LCDGotoXY(0,z);
LCDsendChar('>');
}
}
/* ///////////////////////// BREAK; ////////////////////////// */
///////////////////////////////////////////////////////////////////
/* ///////// MENIU SECUNDAR = TEST COMUNICATIE = //////////// */
if ((x==2) && (Global_8==3))
{
_delay_ms(200);
y=2;
LCDclr();
//Functie_transmisie(0x01);
while (y==2)
{
z=3;
Global_8 = Decodificare_buton(2) & 0xff;
local_8 = UCSRB & 0x80;
if(local_8 != 0)
{
if (serial == true)
{
writeLCD_meniu(13,0);
}
else
{
writeLCD_meniu(14,0);
writeLCD_meniu(15,0);
LCDGotoXY(0,z);
LCDsendChar('>');
//_delay_ms(145);
}
LCDGotoXY(0,z);
LCDsendChar('>');
}
if (Global_8 ==3)
{
y=4;
}
}
}
/* ///////////////////////// BREAK; ////////////////////////// */
///////////////////////////////////////////////////////////////////
/* ///////// MENIU SECUNDAR = COMUNICATIE RS485 = ////////// */
if ((x==3) && (Global_8==3))
{
y=3;
LCDclr();
while (y==3)
{
z=3;
Global_8 = Decodificare_buton(2) & 0xff;
LCDGotoXY(1,0);
writeLCD_meniu(5,0);
LCDGotoXY(1,1);
LCDsendChar('D');
LCDGotoXY(1,2);
LCDsendChar('E');
if (Global_8 ==3)
{
y=4;
}
LCDGotoXY(0,z);
LCDsendChar('>');
}
}
/* //////////////////////// BREAK; ///////////////////////////// */
///////////////////////////////////////////////////////////////////
/* /////////////// MENIU PRINCIPAL //////////////////////// */
if (x<0)
{
x=3;
}
if (x>3)
{
x=0;
}
writeLCD_meniu(0,0);
LCDGotoXY(1,x);
_delay_ms(1);
LCDsendChar('>');
}
if ((x==2) && (Global_8==3))
{
LEDOcupat_off;
Functie_transmisie(0x01);
Index_Receptie_PC = 0;
}
Global_8 = 0;
}
// End Interrupt
int main(void)
{
initializare_time0();
Initializare_porturi();
initializare_ADC(2); // initializare ADC2 – aici sunt conectate butoanele
LCDinit(); // initializare LCD
_delay_ms(5);
LCDclr(); // clear LCD
_delay_ms(5);
LCDcursorOFF();
_delay_ms(100);
writeLCD_meniu(2,0); // meniu de inceputul programului
ADCSRA |=0x40;
Global_8 = 0;
x = 0;
Initializare_serial();
//pregatire buffer de transmis
Struct_T.Antet_Trans = Antet_Transmisie_uC_To_DL; //nu se schimba nici o data
Struct_T.Adr_uC = 0x10; //reeprezinta adresa fiecarui datalogger testat
Struct_T.Reg_Cmd_PC = 0x01; //comanda transmisa [Reset…CMD_R2]
Struct_T.Reg_Adr_Trad = 0x00; //adresa traductorului
//transmit bufferul
Variabila_Timp = 0;
Index_Receptie_PC = 0;
//enable receptie de la datalogger
LEDOcupat_on;
_delay_ms(500);
LEDOcupat_off;
_delay_ms(500);
LEDOcupat_on;
_delay_ms(500);
LEDOcupat_off;
sei(); //global interrupts
while(1)
{
}
}
ISR(USART_RXC_vect)
{
// buffer || /0x21/uC/CMD/Adr_Ap/Val_H/Val_L/Oer/Sc
// 1 2 3 4 5 6 7 8
unsigned char Data_RX = 0,Stare = 0;
Stare = UCSRA;
if((Stare & (DATA_OVERRUN |Frame_Error |Parity_Error )) == 0) //am receptie un caracter
{
global_16 = 1;
Data_RX = UDR;
Index_Receptie_PC++;
LEDOcupat_on;
if((Data_RX != Antet_Receptie_uC) && (Index_Receptie_PC == 1))
{
Index_Receptie_PC = 9;
}
if((Index_Receptie_PC > 1) && (Index_Receptie_PC <= 8))
{
if((Index_Receptie_PC == 2)&& (Data_RX != Struct_T.Adr_uC))
{
Index_Receptie_PC = 9;
}
if((Index_Receptie_PC == 3)&& (Data_RX != Struct_T.Reg_Cmd_PC))
{
Index_Receptie_PC = 9;
}
if((Index_Receptie_PC == 4)&& (Data_RX != Struct_T.Reg_Adr_Trad))
{
Index_Receptie_PC = 9;
}
if(Index_Receptie_PC == 5)
{
Struct_R.Reg_Val_H = Data_RX;
}
if(Index_Receptie_PC == 6)
{
Struct_R.Reg_Val_L = Data_RX;
}
if(Index_Receptie_PC == 7)
{
Struct_R.Reg_OE = Data_RX;
}
if(Index_Receptie_PC == 8)
{
Data_RX +=Antet_Receptie_uC;
Data_RX +=Struct_T.Adr_uC ;
Data_RX +=Struct_T.Reg_Cmd_PC ;
Data_RX +=Struct_T.Reg_Adr_Trad ;
Data_RX +=Struct_R.Reg_Val_H ;
Data_RX +=Struct_R.Reg_Val_L ;
Data_RX +=Struct_R.Reg_OE ;
if (Data_RX != 0)
{
}
else
{
LEDOcupat_off;
}
LCDGotoXY(0,0);
LCDsendChar(Struct_T.Antet_Trans);
_delay_ms(2000);
}
}
}
else
{
global_16 = 3;
Data_RX = UDR;
Index_Receptie_PC = 0;
}
}
//END INTR
////////////////////////////////////////////////////////////////////////
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Aparitia Erorilor In Sistemele Senzoriale (ID: 161888)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
