Visual Studio
Table of Contents
1 Mediu Dezvoltare
1.1 Visual Studio
1.1.1 Introducere în
1.1.2 Componente Visual Studio
1.2 Limbajul C#
1.2.1 Introducere
1.2.2 Tipuri de date in C#
1.2.3 Clase
1.2.4 Constructori si destructori
1.2.5 Proprietăți
1.2.6 Moștenire
1.2.7 Tratarea Excepțiilor
1.2.8 Proiect Nou in Microsoft Visual Studio
1.2.9 Crearea unui program C#
1.3 MPLAB IDE
1.3.1 Introducere
1.3.2 Componente
1.3.3 Compilatorul
1.4 Limbajul ANSI C
1.4.1 Scurta Prezentare
1.4.2 Proiect nou in MPLAB IDE
1.4.3 Crearea unui program C
2 PREZENTAREA APLICATIEI
2.1 Comunicația între Tool și ECU
2.2 Interfata Grafica
2.3 Firul principal al algoritmului ( exemple pe codul aplicatiei)
2.3.1 Initializarea comunicatiei
2.3.2 Comanda ECU-ului
2.4 Aplicatia Integrata pe ECU
2.4.1 Macrouri define
2.4.2 Module Microcontroler
2.5 Firul principal al algoritmului ( exemple pe codul aplicatiei)
Mediu Dezvoltare
Visual Studio
Introducere în Visual Studio
Microsoft Visual Studio este un mediu de dezvoltare integrat ( integrated development environment – IDE) de la Microsoft. Acesta poate fi utilizat pentru a dezvoltă aplicații consola și aplicații cu interfață grafică pentru toate platformele suportate de Microsoft Windows (ex. .NET Framework etc).
Microsoft Visual Studio pune la dispoziție editor, compilator/debugger și mediu de proiectare (designer) pentru mai multe limbaje de programare suportate. Limbaje de programare: Microsoft Visual C++, Microsoft Visual C#, Microsoft Visual Basic, Microsoft Visual Web Developer.
.NET Framework este o platforma de dezvoltare software unitara, inzestrata cu un set mare de clase, structuri, enumerari etc., organizate intr-un set de spatii de nume bazate pe un limbaj comun.
Componente Visual Studio
Editor
Microsoft Visual Studio include un editor de cod, care suportă IntelliSense. Este o denumire populară de la Microsoft pentru Sens Inteligent. Este o trăsătură a mediului de dezvoltare care anticipează oarecum ce cod vrem să scriem, și ne sugerează de exemplu printr-o fereastră pop-up ce anume ar tebui să tastăm, astfel procesul de scriere de cod devine mai rapid, reducând cantitatea de cod tastat sau posibile greșeli de sciere.
Lucrează folosind o baza de date generată automat a claselor, numelor de variabile sau a altor construcții. IntelliSense lucrează prin detectarea caracterelor depinzând de limbaj. Când utilizatorul tastează cod, IntelliSense face o sugestie într-o fereastră pop-up. Acesta poate să accepte sugestia sau poate să continuie să tasteze.
Depanator
Microsoft Visual Studio ne pune la dispoziție un depanator care lucrează și pentru nivel-sursă și pentru nivel mașină. Lucrează și cu cod-sursă și cu cod-mașină și este folosit pentru aplicații scrise în orice limbaj de programare suportat de Visual Studio. Dacă este disponibil codul sursă al unui proces care rulează, acesta va fi afișat așa cum este rulat, iar dacă nu este disponibil va fi afișat codul asamblare. Depanatorul pus la dispoziție de Microsoft Visual Studio poate crea sau rezerva anumite zone de memorie pe care le va folosi ulterior pentru depanare. De asemenea suportă programele care operează pe mai multe fire de execuție (Mulți-threading) și poate fi configurat să fie lansat în execuție atunci când o aplicație „crapă“.
Ne permite să setăm anumite puncte de întrerupere a programului (breakpoint) sau monitorizează anumite valori ale variabilelor. Cu ajutorul Depanatorului codul poate fi rulat pas cu pas, linie cu linie, se poate face debug în interiorul unei funcții sau se poate sări direct după execuția acesteia.
Proiectant
Microsoft Visual Studio oferă o serie de modele vizuale menite să ajute la dezvoltarea de aplicații:
Windows Form Designer
Ne oferă posibilitatea de a crea aplicații de tip GUI ( Interfață Grafică cu Utilizatorul). Într-o fereastră principala putem plasa anumite controale ( butoane, cursoare, ferestre-text) și se crează automat codul sursă pentru fiecare, cod legat în principal de modelul vizual a acestora.
Windows Presentation Foundation
Este folosit pentru a crea formulare de introducere a datelor generând cod XAML care poate fi stocat în sistem sau în baza de date pentru a fi refolosit. Se pot plasa controale din fereastră de instrumente prin intermediul unei ferestre de proprietăți. Setează legături de date pentru fiecare tip de control prin intermediul unei ferestre de proprietăți.
Dezvoltare WEB
Suportă limbajele HTML, CSS, JavaScript pentru crearea și administrarea aplicațiilor WEB.
Proiectant Clase
Este folosit pentru a edita clase (inclusiv membrii) folosind modelul UML. Proiectantul de clasa poate genera cod pentru clase și metode. Poate deasemena genera diagrame de clase din clase scrise manual.
Limbajul C#
Introducere
Limbajul C# a fost dezvoltat de o echipa de ingineri de la Microsoft și este un limbaj simplu, circa 80 de cuvinte cheie și 12 tipuri de date predefinite. Permite programarea structurată și orientate obiectual, conform conceptelor programării profesioniste. Principiile de baza ale programării obiectuale(încapsulare, moștenire, polimorfism) sunt elemente fundamentale ale programării C#. La baza acestuia stă limbajul C sar sunt preluate și principiile de programare din C++. Sintaxa este apropiată și limbajului Java.
Au fost adăugate o serie de tipuri noi de date sau funcțiuni diferite ale datelor din C++, iar în spiritual realizării unor secvențe de cod sigure (safe) , unele funcțiuni au fost adăugate(interfețe), diversificate (tipul string) sau chiar eliminate(moștenirea multiplă și pointerii către funcții). Unele funcțiuni (cum ar fi accesul direct la memorie folosind pointeri) au fost păstrate, dar secvențele de cod corespunzătoare se consideră nesigure.
În momentul în care s-a decis să se dezvolte C# s-a hotărât că acesta să aibă o legătură deosebită cu mediul sau de rulare, arhitectură .NET. Pe de o parte, C# a fost dezvoltat pentru crearea codului pentru arhitectură .NET, iar pe de altă parte bibliotecile utilizate de C# sunt cele ale arhitecturii .NET.
Tipuri de date in C#
Limbajul C# include două categorii de tipuri de date: tipuri valorice și tipuri referință. Tipurile valoare se clasifică astfel:
Tipuri numerice
Intregi
În C# sunt definite 9 tipuri de întregi: char, byte, sbyte, short, ushort, int, uint, long, ulong. Cu excepția lui char, toate sunt folosite la calcule numerice.
Variabilele de tip int se utilizează în controlul buclelor, indexarea tablourilor, aritmetică normală cu numere întregi. Se recomandă că atunci când e nevoie de o valoare ( fără semn ) care depășește domeniul lui int, să se folosească uint. În cazul valorilor mari este recomandat long, iar la cele fără semn, ulong.
În virgulă mobilă
Tipurile în virgulă mobilă, se utilizează pentru reprezentarea numerelor care au parte fractionara. Există două tipuri: float și double.
Decimal
Tipul decimal este folosit în calcule. El are avantajul că elimina erorile de rotunjire atunci când se lucrează cu valori fracționare, pentru că poate reprezenta în mod precis până la 28 de poziții zecimale.
Tipul Bool
Acest tip reține valorile de adevăr ( true ) și ( fals ). Orice expresie de tipul bool va lua una din aceste valori.
Clase
O clasa este o structura care contine date constante si variabile, functii ( metode, proprietati, evenimente, operatori supraincarcati, operatori de indexare, constructori, destructori ) si tipuri imbricate.
Clasele de declara asemanator cu cele din C++, cu unele mici deosebiri de sintaxa (declaratiile de clase nu se termina cu „;“, modificatorii de acces public si privat se aplica pentru fiecare element in parte). Cuvantul cheie this este prezent in continuare, dar este folosit ca o referinta ( nu mai are sintaxa de pointer ).
Modificatorii de acces in C# sunt:
public: accesibil din interiorul și din exteriorul clasei
protected: accesibil numai din interiorul clasei și a claselor derivate
internal: accesibil din interiorul din exteriorul clasei dar numai în cadrul
assembly-ului (proiectului in VS)
protected internal: accesibil numai din interiorul clasei și a claselor derivate în
cadrul assembly-ului (proiectului in VS)
private: accesibil numai din interiorul clasei
Constructori si destructori
Constructorul este o metodă care are același nume cu clasa de care aparțin și se cheamă ori de câte ori este nevoie pentru a crea o instanța a clasei. Aceștia au o sintaxa asemănătoare cu cea din C++ ( au același nume cu clasa de care aparțin și nu au tip returnat ). Diferența apare la lista de initializare: în C# în lista de initializare nu pot apărea decât cuvintele cheie this ( care permite apelarea unui alt constructor din aceeași clasa).
Destructorii sunt metode care au același nume cu clasa din care fac parte, precedat de semnul ~. Nu au tipuri de acces, nu au argumente și nu permit niciun fel de specificatori ( static, virtual etc). Nu pot fi invocați explicit, ci numai de librăriile .NET specializate pe recuperarea memoriei. Ordinea și momentul în care sunt apelați sunt nedefinite, că și firul de execuție în care sunt executați. Este bine că în aceste metode să se dealoce numai obiectele care nu pot fi dealocate automat de .NET și să nu se facă niciun alt fel de alte operații.
Proprietăți
Proprietățile sunt membrii în clasa care facilitează accesul la diferite caracteristici ale clasei. Deși sunt utilzate la fel că atributele, proprietățile sunt de fapt metode și nu reprezintă locații de memorie.
Declararea proprietăților se face sub formă:
tip NumeProprietate
{
get { … }
set { …}
}
După cum se poate observă, o proprietate este alcătuită de fapt din două funcții; din declarația de mai sus compilatorul va genera automat două funcții: tip get_NumeProprietate() și void set_NumeProprietate(tip value). Metodele de tip set primesc un parametru implicit denumit value care conține valoarea atribuită proprietății.
Moștenire
Moștenirea ( numită și derivare ) permite crearea unei clase derivate care conține implicit toți membrii clasei de baza ( cu excepția constructorilor și destructorilor ) unei alte clase numite de baza. În C# o clasa poate avea numai o clasa de baza, nu există moștenire multiplă. În cazul în care nu se specifică nicio clasa de baza, compilatorul consideră că este derivată implicit din clasa System.Object. Sintaxa este asemănătoare cu cea din C++ cu excepția faptului că există un singur tip de moștenire echivalent derivării publice din C++.
Moștenirea este tranzitivă, în sensul că dacă A este derivată din B și B este derivată din C, implicit A va conține și membrii lui C, evident și pe ai lui B. Prin moștenire, o clasa derivată extinde clasa de baza. Clasa derivată poate adaugă noi membrii, dar nu îi poate elimina pe cei existenți.
Deși clasa derivată conține implicit toți membrii clasei de baza, asta nu înseamnă că îi și poate accesa. Membrii privați ai clasei de baza există și în clasa derivată, dar nu pot fi accesați. În acest fel, clasa de baza își poate schimbă la nevoie implementarea internă fără a distruge funcționalitatea claselor derivate existente.
Tratarea Excepțiilor
Tratarea excepțiilor permite interceptarea și tratarea erorilor care astfel ar conduce la terminarea programului și oferă un mecanism pentru semnalarea condițiilor excepționale care pot apărea în timpul execuției programului.
Excepțiile sunt de fapt obiecte derivate din System.Exception care conțin informații despre tipul erorii și locul unde au apărut. Se pot folosi excepțiile predefinite, dar se pot crea și excepții noi prin definirea unei clase derivate din System.Exception. Lansarea unei excepții se face folosind instructiunea throw. Această are că efect oprirea execuției funcției și transferul controlului către apelant.
Tratarea excepțiilor se face utilizând instrucțiunile try și catch și finally în forma:
try
{
// instrucțn acest fel, clasa de baza își poate schimbă la nevoie implementarea internă fără a distruge funcționalitatea claselor derivate existente.
Tratarea Excepțiilor
Tratarea excepțiilor permite interceptarea și tratarea erorilor care astfel ar conduce la terminarea programului și oferă un mecanism pentru semnalarea condițiilor excepționale care pot apărea în timpul execuției programului.
Excepțiile sunt de fapt obiecte derivate din System.Exception care conțin informații despre tipul erorii și locul unde au apărut. Se pot folosi excepțiile predefinite, dar se pot crea și excepții noi prin definirea unei clase derivate din System.Exception. Lansarea unei excepții se face folosind instructiunea throw. Această are că efect oprirea execuției funcției și transferul controlului către apelant.
Tratarea excepțiilor se face utilizând instrucțiunile try și catch și finally în forma:
try
{
// instrucțiuni
}
catch (Exceptie1 e1)
{
// tratare exceptie 1
}
catch (Exceptie1 e2)
{
// tratare exceptie 1
}
finally
{
// instructiuni
}
Succesiunea execuției este următoarea:
Se execută instrucțiunile din blocul try până la apariția unei excepții; în căzul în care nu se declanșează nicio excepție se execută întregul bloc;
Dacă a apărut o excepție se compară tipul exceptiei cu tipurile din lista de catch și se execută blocul de instrucțiuni corespunzător pentru tratarea excepției;
Comparația se face în ordinea în care apar blocurile catch;
După execuția unui bloc catch nu se continuă căutarea în celelalte blocuri catch, deci excepțiile mai generale trebuie puse după excepțiile particulare;
Se execută instrucțiunile din blocul finally, indiferent dacă a apărut sau nu o excepție și indiferent dacă această a fost tratată sau nu
Dacă nu a apărut nicio excepție sau dacă excepția a fost tratată printr-un bloc catch execuția continuă cu instrucțiunile de după blocul finally, altfel excepția este programată în apelator.
Blocurile catch si finally nu sunt obligatorii ( unul dintre ele poate lipsi ).
Proiect Nou in Microsoft Visual Studio
Pentru crearea unui proiect nou este necesar să urmăm câțiva pași:
Pentru a crea un proiect nou se selectează File New Project
Apare o nouă fereastră în care trebuie să selectăm Windows Forms Application
Crearea unui program C#
Microsoft Visual Studio și limbajul de programare C# ne oferă posibilitatea de a crea aplicații, de exemplu construirea unei aplicații de tip interfață, prin intermediul căreia să putem comunica cu un anumit dispozitiv.
Ca un exemplu pentru crearea unui astfel de program vom utiliza un buton care să verifice dacă portul serial este pregătit pentru transmisia de date, cu alte cuvinte dacă este initializata comunicația, și care să trimită un caracter pe portul serial.
După urmarea pașilor specificați anterior, vom avea disponibilă o fereastă de proiectant ( designer ). În partea stânga este disponibilă o fereastră de instrumente de unde vom selecta un buton și îl vom plasa în fereastră de proiectare.
Următorul pas este să dăm dublu-clic pe buton și va apărea codul generat automat așa cum am amintit anterior. Este realizată o legătură între controlul adăugat, în cazul de față un buton, și codul generat automat pentru acesta. Acest cod generat automat are legătură în mare parte cu modelul de vizualizare al acestuia.
Tot ce a mai rămas de făcut este să tastăm codul C# necesar pentru a realiza cele menționate anterior.
Am ales ca exemplu implementarea unui sistem cu tratare a excepțiilor. În cazul de față, dacă la apelul port.Write() aplicația ar fi eșuat și trasmiterea pe portul serial nu ar mai fi fost posibilă, s-ar executa codul din catch și ne va apărea un mesaj de informare. Alfel, în caz contrat, aplicația ar fi “crăpat”.
În acest moment putem spune că avem un mic program realizat în Microsoft Visual Studio cu ajutorul limbajului de programare C# în care se încearcă testarea portului serial și trimiterea de date înspre acesta.
MPLAB IDE
Introducere
MPLAB este un program software al sistemului de operare Windows care rulează pe un PC, cu ajutorul căruia putem dezvolta aplicații pentru microcontolerele de la Microchip. Este denumit Mediu de Dezvoltare Integrat ( IDE ) deoarece oferă un singur mediu de dezvoltare pentru a dezvolta cod pentru microcontrolerele integrate.
Componente
Managerul de Proiect
Managerul de Proiect oferă integrarea și comunicarea între mediul de dezvoltare și instrumentele de limbaj.
Editorul
Editorul este un editor de cod programare echipat complet și care servește de asemenea ca și o fereastră în cadrul depanatorului.
Asamblorul / Fișierul de Legătură
Asamblorul poate fi folosit pentru a asambla un singur fișier, sau poate fi folosit împreună cu Fișierul de Legătură pentru a construi un proiect compus din mai multe fișiere sursă, librării sau obiecte recompilate. Fișierul de Legătură este responsabil cu poziționarea codului compilat într-o zonă de memorie a microcontrolerului folosit.
Depanatorul
Depanatorul de la Microchip ne dă voie să poziționăm puncte de întrerupere a programului, rularea pas cu pas a programului, ferestre de monitorizare, unde putem monitoriza valorile anumitor variabile, diferiți regiștrii etc. Lucrează în strânsă legătură cu Editorul. Depanatorul folosit oferit din cadrul mediului de dezvoltare MPLAB este ICD 2.
Compilatorul
Compilatorul folosit este oferit de Microchip, Microchip C30 Compiler, și se instalează separat de mediul de dezvoltare MPLAB.
Limbajul ANSI C
Scurta Prezentare
Este un limbaj de programare standardizat, compilat, de nivel mediu. Este implementat pe majoritatea platformelor de calcul existente azi, și este cel mai popular limbaj de programare pentru scrierea de software de sistem. Este în strânsă legătură cu hardware-ul, fiind cel mai apropiat de limbajul de asamblare față de majoritatea celorlalte limbaje de programare.
Acest limbaj de programare a fost creat având ca scop important de a face ca programele mari să poată fi scrise mai ușor și cu mai puține erori. Are următoarele caracteristici importante:
Este un limbaj de bază simplu, cu importante funcționalități, cum ar fi funcțiile matematice
Utilizează un set simplu de tipuri de date ce împiedică multe operații neintenționate
Folosește un limbaj preprocesor, preprocesorul C, pentru sarcini cum ar fi definirea de macrouri și includerea mai multor fișiere sursă
Permite accesarea la nivel jos a memoriei calculatorului prin intermediul pointerilor
Permite folosirea parametrilor, care sunt comunicați funcțiilor prin valoare și nu prin referință.
Alegerea acestui limbaj de programare pentru dezvoltarea aplicațiilor integrate pe microcontrolere este una destul de simplă.
Limbaj de programare foarte eficient
Limbaj de programare foarte popular și foarte bine înțeles
Limbaj de programare de nivel mediu, cu caracteristicile unui limbaj de nivel înalt ( suport pentru funcții și module), dar și cu caracteristici de limbaj de nivel jos, oferă acces către hardware prin intermediul pointerilor.
Este foarte ușor de înțeles chiar și pentru programatorii care folosesc limbajele de programare Java, C#, C++
Se găsesc foarte ușor cărți de specialitate, cursuri sau exemple de cod.
Proiect nou in MPLAB IDE
Pentru crearea unui proiect nou este necesar să urmăm câțiva pași.
Din bara de meniu trebuie să selectăm Project Project Wizard
Următorul pas este să apăsăm Next și să selectăm tipul de microcontroler folosit pentru dezvoltarea aplicației, în cazul de față dsPIC30F2020.
În acest pas trebuie să selectăm tipul de compilator dorit, pentru compilarea codului, în funcție de codul scris, putem să selectăm un compilator pentru cod C sau un compilator pentru cod asamblare, în cazul de față se selectează compilatorul Microchip C30 Compiler.
Tot ce ne mai rămâne de făcut este să selectăm locația la care să se salveze proiectul nou creat. Aici avem opțiunea să creăm un proiect nou sau putem să reconfigurăm unul deja existent.
Crearea unui program C
Mediul de dezvoltare MPLAB împreună cu limbajul de programare C ne oferă posibilitatea de a crea programe care pot fi integrate pe un microcontroler, împreună formând un sistem dedicat. Ca și exemplu pentru un astfel de program, am putea alege ceva simplu, cum ar fi aprinderea și stingerea unui LED.
În cele menționate anterior, am văzut cum se poate crea un proiect nou în mediul de dezvoltare MPLAB, tot ce ne mai rămâne de făcut este să creăm programul în sine.
După cum se poate observa, am stabilit că portul trebuie să fie setat ca ieșire, prin intermediul registrului PORTB, am inițializat registrul de direcție TRISB. După aceea în bucla infinită while (1) aprindem led-ul punând valoarea maximă 0xFF în registrul PORTB, o întârziere, după care led-ul este stins, 0x00 în registrul PORTB. Avem nevoie de acea întârziere deoarece altfel nu am sesiza aprinderea și stingerea, acest proces se desfășoară foarte rapid.
În cele din urmă trebuie să vedem dacă programul nostru conține erori, de sintaxă, de logică etc, cu alte cuvinte dacă se construiește.
În acest moment putem spune că am realizat un program C cu ajutorul mediului de dezvoltare MPLAB care să facă ce ne-am propus.
PREZENTAREA APLICATIEI
Folosind notiunile teoretice prezentate in capitolele anterioare am realizat un tool care permite comunicatia cu dispozitivul ( ECU-ul ) in mediul de dezvoltare Microsoft Visual Studio si deasemenea o aplicatie care comanda dispozitivul ( ECU-ul ) in mediul de dezvoltare MPLAB IDE.
Tool-ul realizat ofera o interfata prietenoasa cu utilizatorul, nefiind necesare cunostinte avansate de operare a calculatorului pentru a-l putea utiliza.
Meniul permite deplasarea usoara intre comenzi, elementele de meniu avand denumiri explicite, astfel utilizatorul nu intalneste niciun fel de dificultati in utilizarea acestuia.
Tool-ul comunica cu dispozitivul si ii trimite comenzi. Reactia la aceste comenzi este programata in cadrul dispozitivului, prin intermediul aplicatiei integrate. Comenzile sunt trimise serial si sunt executate.
Functiile de baza pe care acest tool le poate face sunt acelea de a comanda dispozitivul electronic, dar si de a primi un raspuns in urma acestor comenzi, ca rezultat al executiei lor, functii de monitorizare a partii hardware. Cu ajutorul acestor functii se poate testa si valida proiectul.
Pe cealalta parte s-a realizat un sistem dedicat, menit sa simuleze actionarea motorului DC, componenta a pompei hidraulice din cadrul sistemului de franare al unui automobil.
Pompa hidraulica este alcatuita dintr-un motor DC si doua sau mai multe pistoane. Daca softul de control cere activarea pompei, atunci motorul incepe sa se roteasca si lichidul de frana va incepe sa curga. Pompa hidraulica are doua mari sarcini:
Impingerea lichidului de frana in sistem
Pedala de frana este apasata, supapa de admisie este inchisa, supapa de evacuare este deschisa. In tot acest timp motorul se roteste actionand pistoanele pentru a face posibil procesul.
Mentinerea presiunii fara ca pedala sa fie actionata
Motorul se roteste actionand pistoanele astfel incat presiunea necesara sa fie mentinuta.
Aplicatia realizata cu ajutorul mediului de dezvoltare MPLAB si a limbajului de programare C actioneaza motorul in ambele sensuri, bazat pe un sistem de intreruperi, la diferite viteze, simuland astfel necesitatea de a impinge lichidul de frana in sistem si de a mentine presiunea acestuia in diferite conditii. Aplicatia realizata pune la dispozitie un sistem de monitorizare pentru anumiti parametri cum ar fi numarul de rotatii ale motorului intr-o unitate de timp, sau stocarea valorii unui consum mare de curent in caz ca intervine o problema mecanica a pistoanelor si totodata cu asta blocarea motorului, valori care ulterior pot fi vizualizate in tool-ul pus la dispozitie, sau pe un LCD pus la dispozitie in cadrul dispozitivului.
Pentru a putea fi controlat cu usurinta si in timpul development-ului dispozitivului electronic i-au fost atasate controale hardware, doua butoane pentru sensul de rotatie si un potentiometru pentru marirea sau micsorarea numarului de rotatii, bazat pe un sistem cu PWM.
Comunicația între Tool și ECU
Comunicatia intre Tool-ul realizat si ECU se face serial prin intermediul unui driver FTDI incorporat pe dispozitiv. S-a realizat o comunicatie prin intermediul unui astfel de driver pentru a facilita comunicatia intre dispozitiv si mai multe potentiale PC-uri care nu dispun de un conector RS232.
In prima faza se trimite un mesaj din interfata grafica catre dispozitiv, din acel moment controlul asupra ECU-ului fiind numai din interfata grafica.
Apelarea unei operatii duce la schimburi de date. Schimbul de date consta in trimiterea unui mesaj care contine o comanda dupa care urmeaza executia acesteia de catre ECU, sau primirea unui raspuns continand date in urma executarii unor comenzi. In cazul in care initializarea nu s-a desfasurat cu succes, vom avea un mesaj de eroare.
Interfata Grafica
Aplicatia este formata din doua panouri:
Panoul de Initializare Comunicatie in care:
Se poate initializa comunicatia ( se deschide portul COM, se seteaza Baudrate, bitii de date, bitii de stop si se trimite comanda de conectare catre ECU )
Se poate deinitializa comunicatia ( se trimite comanda de deconectare catre ECU si se inchide portul COM)
O fereastra de tip text in care ne va apararea un mesaj daca inititializarea a fost sau nu cu succes
Panoul de control in care:
Se poate comanda rotirea motorului in ambele sensuri
Se poate opri rotirea motorului
Se poate comanda numarul de rotatii ale motorului printr-un sistem PWM
Se poate vizualiza consumul de curent al motorului
Se poate vizualiza numarul de rotatii ale motorului in unitatea de timp
Se poate vizualiza un consum de curent peste limita daca este cazul
Firul principal al algoritmului ( exemple pe codul aplicatiei)
Initializarea comunicatiei
Este declansata prin apasarea butonului „Connect“ din cadrul panoului de initializare a comunicatiei.
private void btnConnect_Click(object sender, EventArgs e)
{
if (port.IsOpen)
MessageBox.Show("Communication is already initialized!");
else
{
try
{
port.Open();
port.Write("c");
btnInit.BackColor = Color.GreenYellow;
txtCommunication.Text = "COM6 Opened BaudRate 9600 Initialization OK…";
}
catch (Exception ex)
{
MessageBox.Show("Nu se poate conecta la portul 6");
btnInit.BackColor = Color.Red;
txtCommunication.Text = "COM6 Access denied…";
}
}
}
Explicatie:
Prima data se verifica starea portului COM, daca acesta este deja deschis, inseamna ca avem deja comunicatia initializata si ne va aparea un mesaj de informare.
Daca portul nu este deschis, se apeleaza metoda port.Open() care deschide portul COM.
Dupa ce portul este deschis se apeleaza metoda port.Write(”c”) si se trimite catre ECU caracterul „c”, care reprezinta comanda de conectare cu ECU-ul.
Pentru interactiunea prietenoasa dintre interfata si utilizator butonul de „Connect” o sa isi schimbe culoarea in verde, iar in fereastra de tip text vom avea mesajul de informare despre initializarea cu succes a comunicatiei.
Daca intervine o problema in procesul de initializare a comunicatiei, vom avea un mesaj de informare, culoarea butonului „Connect” va deveni rosu, iar in fereastra de tip text vom avea un mesaj de eroare.
Pentru ca accesul la portul COM sa fie posibil acesta trebuie mai intai configurat.
SerialPort port = new SerialPort("COM4", 9600, Parity.None, 8, StopBits.One);
Se face acces la COM4, se seteaza baudrate-ul la 9600, niciun bit de paritate, 8 biti de date si un bit de stop.
Comanda ECU-ului
Dupa ce faza de initializare este terminata cu succes, se pot trimite alte comenzi, cum ar fi comenzile de comanda a ECU-ului.
Actionare Motor spre stanga
Daca testul presupune in prima faza rotirea motorului inspre stanga, atunci aceasta comanda este declansata de apasarea butonului „Move Left“ din cadrul panoului de comanda.
private void btnLeft_Click(object sender, EventArgs e)
{
if (!port.IsOpen)
{
MessageBox.Show("Communication is not initialized!", "Message", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
try
{
port.Write("l");
bool btnLeft_Clicked = true;
}
catch (Exception ex)
{
MessageBox.Show("Rotate to the left is not possible", "Message", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
Explicatie:
In prima faza se verifica starea portului COM, cu alte cuvinte daca avem comunicatia initializata.
Daca acest proces nu a fost cu succes, s-au nici macar nu s-a incercat initializarea comunicatiei, atunci aceasta comanda nu va putea fi executata si vom avea un mesaj de alerta.
Daca procesul de initializare a comunicatiei a fost realizat cu succes, atunci se apeleaza metoda port.Write(“l“), metoda prin intermediul careia se trimite comanda catre ECU de actionare a motorului inspre stanga, trimitand caracterul „l“ pe serial.
Dupa ce comanda a fost trimisa se seteaza o variabila de tip bool cum ca butonul de trimitere a comenzii de rotire a motorului inspre stanga a fost apasat.
Daca aceasta comanda nu a fost trimisa cu succes, atunci vom avea un mesaj de alerta.
Actionare Motor spre Dreapta
Daca testul presupune rotirea motorului inspre dreapta, atunci aceasta comanda este declansata prin apasarea butonului „Move Right“ din cadrul panoului de comanda.
private void btnRight_Click(object sender, EventArgs e)
{
if (!port.IsOpen)
{
MessageBox.Show("Communication is not initialized!", "Message", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
try
{
port.Write("r");
}
catch
{
MessageBox.Show("Message was not sent");
}
bool btnRight_Clicked = true;
}
}
Explicatie:
In prima faza se verifica starea portului COM, cu alte cuvinte daca avem comunicatia initializata.
Daca acest proces nu a fost cu succes, sau nici macar nu s-a incercat initializarea comunicatiei, atunci aceasta comanda nu va putea fi executata si vom avea un mesaj de alerta.
Daca procesul de initializare a comunicatiei a fost realizat cu succes, atunci se apeleaza metoda port.Write(“r“), metoda prin intermediul careia se trimite comanda catre ECU de actionare a motorului inspre dreapta, trimitand caracterul „r“ pe serial.
Dupa ce comanda a fost trimisa se seteaza o variabila de tip bool cum ca butonul de trimitere a comenzii de rotire a motorului inspre dreapta a fost apasat.
Daca aceasta comanda nu a fost trimisa cu succes, atunci vom avea un mesaj de alerta.
Comanda Numar Rotatii Motor
Daca testul presupune urmarirea comportamentului ECU-ului, sau mai exact a motorului la diferite rotatii ale acestuia, sau numarul rotatiilor mai exact, in unitatea de timp, indiferent de sensul de rotatie, atunci avem la dispozitie un cursor, care trimite comanda de marire sau micsorare a numarului rotatiilor in unitatea de timp. Cursorul trimite pe serial catre ECU valori de la 0 la 1023, valori ce sunt interpretate in cadrul ECU-ului, mai exact de blocul de PWM.
private void trackBar1_Scroll(object sender, EventArgs e)
{
if (port.IsOpen)
{
PWM();
}
else
{
trackBar1.Value = 0;
MessageBox.Show("Communication is not initialized!", "Message", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
Explicatie:
In prima faza se verifica daca este initializata comunicatia, daca este portul COM deschis
Daca avem comunicatia initializata se apeleaza functia PWM()
Daca procesul de initializare nu este efectuat cu succes, atunci vom avea un mesaj de alerta
Explicatie functie PWM():
private void PWM()
{
int stochez, temporary;
string a;
stochez = trackBar1.Value;
port.Write("p");
if (stochez < 1000)
port.Write("0");
if (stochez < 100)
port.Write("0");
temporary = stochez;
a = temporary.ToString();
port.Write(a);
}
Se declara doua variabile locale de tip intreg, stochez si temporary, si o variabila locala de tip sir de caractere.
In variabila de tip intreg stochez stocam valorile date de cursor, in momentul comandarii acestuia, valori de la 0 la 1023, asa cum am mentionat si anterior. Aceste valori trebuiesc trimise pe serial catre ECU pentru a putea fi interpretate de catre modulul de PWM.
Mediul de dezvoltare Microsoft Visual Studio prin intermediul metodei port.Write() ne permite sa stocam caractere in buffer-ul de serial, caractere ce ulterior vor fi trimise pe serial. Valorile care trebuiesc puse pe serial, date de cursor, sunt de tipul intreg. Acestea trebuiesc convertite la tipul caracter pentru a putea fi trimise pe serial. Trebuiesc trimise 4 caractere care, ulterior, interpretate si convertite in cadrul ECU-ului vor forma un intreg.
Se trimite pe serial caracterul „p“ care interpretat de catre ECU va face diferenta intre 2 mesaje succesive. In momentul in care va primi caracterul „p“ va sti ca a sosit urmatoarea valoare.
Se testeaza daca valoarea data la un moment dat de catre cursor este mai mica decat 1000 sau decat 100. Acest test se realizeaza pentru a ne ajuta la formarea mesajului de 4 caractere, daca valoarea este mai mica decat 1000 atunci primul caracter trimis va fi „0“. Daca valoarea este mai mica si decat 100, atunci se mai trimite inca un caracter „0“.
In ultima faza, valoarea data de catre cursor se converteste de la tipul intreg la tipul caracter si se trimite pe serial. Mesajul va fi interpretat ulterior de catre ECU si valoarea va fi trimisa catre modulul de PWM.
Comanda Citire Curent Consumat
Daca testul presupune monitorizarea consumului de curent al motorului, indiferent de sensul de rotatie sau numarul de rotatii ale acestuia in unitatea de timp, atunci aceasta comanda este declansata de apasarea butonului „View Curent“.
private void btnViewCurent_Click(object sender, EventArgs e)
{
if (!port.IsOpen)
{
MessageBox.Show("Communication is not initialized!", "Message", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
try
{
port.Write("w");
txtRead.Text = port.ReadExisting();
}
catch
{
MessageBox.Show("Message was not sent");
}
}
}
Explicatie:
In prima faza se verifica starea portului COM, daca portul este deschis sau inchis, cu alte cuvinte, daca a fost initializata comunicatia cu succes. Daca initializarea comunicatiei nu a fost cu succs, atunci vom avea un mesaj de alerta
Daca avem o comunicatie initializata cu succes, atunci prin intermediul metodei port.Write(“w“) se trimite pe serial caracterul „w“, care interpretat de catre ECU reprezinta comanda de citire a curentului consumat de motor.
In cadrul ECU-ul se interpreteaza comanda si se calculeaza valoarea curentului consumat de motor, vom vedea intr-un capitol urmator cum este posibil acest lucru, si se trimite catre interfata pentru a fi afisata.
Urmatorul pas este sa se ia valoarea trimisa de catre ECU, din buffer-ul de serial, prin intermediul metodei port.readExisting() si se va afisa in fereastra de tip text.
Comanda Citire Numar Rotatii Motor
Urmatorul lucru care trebuie monitorizat este numarul rotatiilor motorului in anumite conditii, in functie de cativa parametri cum ar fi sensul de rotatie, PWM sau daca ceva este in neregula cu motorul sau pistoanele actionate de acesta.
private void btnViewSpeed_Click(object sender, EventArgs e)
{
if (!port.IsOpen)
{
MessageBox.Show("Communication is not initialized!", "Message", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
try
{
port.Write("z");
txtSpeed.Text = port.ReadExisting();
}
catch
{
MessageBox.Show("Message was not sent");
}
}
}
Explicatie:
In prima faza se verifica starea portului COM, daca portul este deschis sau inchis, cu alte cuvinte, daca a fost initializata comunicatia cu succes. Daca initializarea comunicatiei nu a fost cu succs, atunci vom avea un mesaj de alerta
Daca avem o comunicatie initializata cu succes, atunci prin intermediul metodei port.Write(“z“) se trimite pe serial caracterul „z“, care interpretat de catre ECU reprezinta comanda de citire a numarului rotatiilor motorului pe secunda.
In cadrul ECU-ul se interpreteaza comanda si se calculeaza numarul rotatiilor motorului, vom vedea intr-un capitol urmator cum este posibil acest lucru, si se trimite catre interfata pentru a fi afisata.
Urmatorul pas este sa se ia valoarea trimisa de catre ECU, din buffer-ul de serial, prin intermediul metodei port.readExisting() si se va afisa in fereastra de tip text.
Comanda citire Valori Curent peste limita
Sa presupunem ca o problema mecanica a intervenit si unul dintre pistoane s-a blocat. Atunci motorul o sa incerce sa se roteasca in continuare, numai ca o sa fie un consum foarte mare de curent. Aceste valori trebuiesc stocate si afisate.
private void btnView_Consumptions_Click(object sender, EventArgs e)
{
if (!port.IsOpen)
{
MessageBox.Show("Communication is not initialized!", "Message", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
try
{
port.Write("a");
txtConsumptions.Text = port.ReadExisting();
if (txtConsumptions.Text == "000")
MessageBox.Show("Curent Consumption OK!");
}
catch
{
MessageBox.Show("Message was not sent");
}
}
}
Explicatie:
In prima faza se verifica starea portului COM, daca portul este deschis sau inchis, cu alte cuvinte, daca a fost initializata comunicatia cu succes. Daca initializarea comunicatiei nu a fost cu succs, atunci vom avea un mesaj de alerta
Daca avem o comunicatie initializata cu succes, atunci prin intermediul metodei port.Write(“a“) se trimite pe serial caracterul „a“, care interpretat de catre ECU reprezinta comanda de citire a valorii curentului peste limita.
In cadrul ECU-ul se interpreteaza comanda si se calculeaza valoarea curentului peste limita, vom vedea intr-un capitol urmator cum este posibil acest lucru, si se trimite catre interfata pentru a fi afisata.
Urmatorul pas este sa se ia valoarea trimisa de catre ECU, din buffer-ul de serial, prin intermediul metodei port.readExisting() si se va afisa in fereastra de tip text.
In ultima faza se verifica valoarea trimisa de catre ECU, daca aceasta este 0, atunci se trimite un mesaj de informare cum ca nu am avut niciun consum exagerat de curent.
Aplicatia Integrata pe ECU
Macrouri define
Pentru manipularea registrilor si a variabilelor s-au folosit cateva macrouri, care au fost declarate in cadrul fisierului main.h.
#define PWMH_Output IOCON2bits.PENH
#define PWML_Output IOCON2bits.PENL
#define TMR2_ON_Control_Bit T2CONbits.TON
#define TMR2_Interrupt_Flag_Status _T2IF
#define ADC_Conversion_Complete_Int_Flag_Status IFS0bits.ADIF
#define ADC_CHANNEL_4 ADCBUF4
#define ADC_CHANNEL_5 ADCBUF5
#define UART_Receive_Reg U1RXREG
#define UART_Transmit_Reg U1TXREG
#define PWM_Duty_Cycle_Reg PDC2
#define Curent_THRESHOLD 100
#define UART1_TX_Interrupt_Status_Flag IFS0bits.U1TXIF
#define UART1_RX_Interrupt_Status_Flag IFS0bits.U1RXIF
#define INTERRUPT_ENABLE_CONTROL IEC1
#define PWM_Control_Immediate_Update PWMCON2bits.IUE
#define U1_Baud_Rate_Generator U1BRG
#define UART_Module_Enable U1MODEbits.UARTEN
#define LoopBack_Disable U1MODEbits.LPBACK
#define High_Baudrate_Disabled U1MODEbits.BRGH
#define UART_Transmit_Enable U1STAbits.UTXEN
#define LED_Left _LATE5 /* Led Stanga */
#define LED_Right _LATE4 /* Led Dreapta */
#define INT0 IFS0bits.INT0IF
#define INT1 IFS1bits.INT1IF
#define INT2 IFS1bits.INT2IF
Module Microcontroler
Pentru realizarea aplicatiei a fost nevoie de configurarea catorva module ale microcontrolerului dsPIC30f2020.
Modul Comunicatie ( UART.c ):
Void UART_init ( void )
{
IPC2bits.U1RXIP = 7; /* prioritatea intreruperii, maxim */
IFS0bits.U1RXIF = 0; /* flag intrerupere U1RX */
IEC0bits.U1RXIE = 1; /* activeaza intreruperea de primire */
U1_Baud_Rate_Generator = 194; /* seteaza baudrate la 9600, U1BRG=((FCY/Desired Baud Rate)/16) – 1 where FCY=30 000 000 */
UART_Module_Enable = 1; /* Activeaza modulul UART */
U1MODEbits.ALTIO = 1; /* Foloseste U1RX si U1TX alternat */
High_Baudrate_Disabled = 0; /* Dezactiveaza baudrate maxim */
U1MODEbits.PDSEL = 0; /* 8 biti de date, fara paritate */
U1MODEbits.STSEL = 0; /* 1 bit de stop */
UART_Transmit_Enable = 1; /* Activeaza modulul UART de Transmitere */
}
Modul PWM ( pwm.c):
void InitMCPWM(void)
{
/*~~~~~~~~~~~~~~~~~~~~~~~ PWM2 Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* PWM2 I/O Control Register register */
PWMH_Output = 0; /* PWM2H este controlat de modulul GPIO */
PWML_Output = 0; /* PWM2L este controlat de modulul GPIO */
PWM_Duty_Cycle_Reg = 0; /* Incarca registrul PDC2 cu valoarea initiala a Duty Cycle-ului */
/* PWM Module Common settings */
PTPER = 65000; /* PWM Period 2.15 usec @ 30 MIPS
PWM Period = PTPER*1.05nsec = 2.15 usec */
PWM_Control_Immediate_Update = 1; /* activeaza actualizarea imediata a PWM-ului */
PTCON = 0x8000; /* Activeaza modulul PWM */
}
Modul ADC ( adc.c ):
void ADC_init (void)
{
/* Set up the ADC Module */
ADCONbits.ADSIDL = 0; /* Opereaza in modul Idle*/
ADCONbits.FORM = 0; /* Rezultat in format intreg */
ADCONbits.SEQSAMP = 1; /* Activeaza prelevarea secventiala de date */
ADCONbits.ADCS = 5; /* Clock Divider setat pentru Fadc/14 */
ADPCFG = 0b1111111111001111; /* AN4 and AN5 sunt intrari analogice*/
ADSTAT = 0; /* Initializeaza registrul ADSTAT cu 0 (ADC status register) */
ADCPC1bits.TRGSRC2 = 0xC; /* Trigger conversion on TMR1 Prd Match */
ADCPC1bits.IRQEN2 = 1; /* Activeaza intreruperea */
/* Set up Timer1 */
T1CON = 0; /* Timer with 0 prescale */
TMR1 = 0; /* Clear the Timer counter */
PR1 = TIMER_PERIOD; /* Load the period register */
/* Set up the Interrupts */
IFS0bits.ADIF = 0; /* Clear AD Interrupt Flag */
IFS0bits.T1IF = 0; /* Clear Timer1 Interrupt Flag */
IEC0bits.T1IE = 0; /* Timer Interrupt is not needed */
IPC2bits.ADIP = 4; /* Set ADC Interrupt Priority */
IEC0bits.ADIE = 1; /* Enable the ADC Interrupt */
/* Enable ADC and Timer */
ADCONbits.ADON = 1; /* Start the ADC module */
T1CONbits.TON = 1; /* Start the Timer */
}
Blocul de Intreruperi ( interrupts.c ):
void Interrupt_init(void)
{
INTCON1 = 0x0000; /* Control intrerupere 1 */
INTCON2 = 0x0000; /* Control intrerupere 2 */
IFS0 = 0x0000; /* Flagul de status al intreruperii */
IFS1 = 0x0000; /* Flagul de status al intreruperii */
IEC0 = 0x0001; /* Se initilizeaza controlerul de activare a intreruperii */
IEC1 = 0x0003;
}
Modulul de Timer ( timer.c ):
void timer_init (void)
{
T2CON = 0x0030; /* Timer2 Input Clock Prescale Select bits */
PR2 = 0xFFFF; /* Timer2 Period Register */
TMR2_Interrupt_Flag_Status = 0; /* Timer2 Interrupt Status Flag */
_T2IE = 1; /* Timer2 Interrupt Enable */
TMR2_ON_Control_Bit = 0; /* Timer2 ON Control Bit */
}
Definire functie Delay ( delay_C30.c ):
void DelayNmSec(unsigned int N)
{
unsigned int j;
N=N*4;
while(N–)
for(j=0;j < MILLISEC;j++);
}
Prin aceasta functie se urmareste intarzierea softului in anumite locuri, in functie de necesitati.
Firul principal al algoritmului ( exemple pe codul aplicatiei)
In momentul in care ECU-ul este alimentat se va afisa pe LCD, Bigiu Gabriel pe prima linie si 2014, pe a doua linie.
Lcd_Out (1,0," BIGIU GABRIEL");
Lcd_Out (2,0," 2014 ");
DelayNmSec(500);
Dupa o mica intarziere, pe LCD se vor afisa, curentul cosumat si numarul rotatiilor pe secunda ale motorului.
while( CONNECTED_TO_THE_INTERFACE == 0 )
{
lcd_clear();
Lcd_Out (1,1,"SPEED= rps");
Lcd_Out (2,1,"CURRENT= mA");
while( CONNECTED_TO_THE_INTERFACE == 0 )
{
Curent_to_LCD = ADC_Channel_4_Result;
Lcd_Chr( 2, 12, 0x30 + Curent_to_LCD % 10 );
Curent_to_LCD = Curent_to_LCD / 10;
Lcd_Chr( 2, 11, 0x30 + Curent_to_LCD % 10 );
Curent_to_LCD = Curent_to_LCD / 10;
Lcd_Chr( 2, 10, 0x30 + Curent_to_LCD % 10 );
Curent_to_LCD = Curent_to_LCD / 10;
Lcd_Chr( 2, 9, 0x30 + Curent_to_LCD % 10 );
Rotations_to_LCD = Rotations_per_Second;
Lcd_Chr( 1, 10, 0x30 + Rotations_to_LCD % 10 );
Rotations_to_LCD = Rotations_to_LCD / 10;
Lcd_Chr( 1, 9, 0x30 + Rotations_to_LCD % 10 );
Rotations_to_LCD = Rotations_to_LCD / 10;
Lcd_Chr( 1, 8, 0x30 + Rotations_to_LCD % 10 );
Rotations_to_LCD = Rotations_to_LCD / 10;
Lcd_Chr( 1, 7, 0x30 + Rotations_to_LCD % 10 );
DelayNmSec(100);
}
}
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: Visual Studio (ID: 124813)
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.
