O clasă părinte pentru dispozitive spi, sau un c distractiv și convenabil pentru avr

Mereu mi-a plăcut ideea de programare orientată pe obiect. Acest lucru este foarte convenabil și ușor, mai ales când programul este umflat la dimensiuni mari sau există mai multe elemente foarte asemănătoare, dar cu setări diferite. Și am fost mereu interesat de soluții neobișnuite, interesante și tendințe lingvistice - modele, funcțiile lambda, operatorii ternare ... Din păcate, nu am putut ajunge la ei - că nu a existat nici un moment, creierul nu a fost gata. Știam în general ce era, dar eu nu am încercat-o niciodată. Dar dintr-o dată, într-unul din programele AVR, am văzut o utilizare interesantă a șablonului, ceea ce a facilitat foarte mult lucrarea. M-am interesat - și sa găsit timp și dorință ... Și acum sa născut ideea acestui articol. Rezultatul este o clasă părinte pentru a lucra ușor cu dispozitive bazate pe SPI (registre de deplasare, transmițătoare, Ethernet etc.), în implementări hardware și software. Interesant - te rog, sub pisica.







tl; dr - la sfârșitul tuturor legăturilor din articol, inclusiv codul finit și exemple.

generație
Atunci când se ocupă cu un număr mare de periferice, începeți să urâți în liniște defensiunile cu porturi și pini. Sunt atât de multe dintre ele pe care nu le puteți trece. Vom pune SlaveSelect într-un port cu Hardware SPI. Oh, acolo e greu să ții o cale, o vom schimba cu alta. Și cu asta, bineînțeles, vom face apărarea pentru DDRx și PINx - vrem ca totul să fie inițializat. Și pentru toată lumea ... Și dacă blocați fierul, cu orice schimbare a designului, trebuie să bateți tot codul.

Am avut o idee - de ce să nu faceți totul o clasă? Specificați toate porturile prin argumentele constructorului. Un spațiu convenabil, frumos, puțin. Dar. PORTx nu este o funcție, nu este un tip, este o macrocomandă distrugătoare la care poți scrie. În pofida acestui fapt, am abandonat ideea de OOP pentru a lucra cu porturile AVR.

Problema cu porturile este rezolvată, acum puteți trece la cele mai interesante. Am scris câteva clase folosind această funcție, m-am gândit: ar fi minunat să faci o clasă părinte, de la care interfața va fi moștenită. Se hotărăște - vom scrie un astfel de lucru pentru SPI.

Implementarea hardware-ului SPI
Am biblioteca libSPI (Fundația a luat Tinkerer) în trei versiuni - Hardware (fier utilizează SPI), USI-based (ruleaza pe USI - de exemplu, pentru ATtiny24) și software (versiunea software completă). Aruncând înapoi al doilea (USI este acum destul de rar), am început cu cea mai ușoară - Hardware. Am folosit acest schelet al clasei părinte:

Pentru cei care nu sunt familiarizați cu template-uri, descrie pe scurt esența lucru (cei care știu. - vă rugăm să nu lovi cu piciorul în atât de scurt și versiunea nu destul de corect). Un șablon vă permite să înlocuiți diferite tipuri în aceeași construcție. În acest caz, SPI_Base_Hardware obiect de inițializare I punctul de clasa de port IO (același cu cel care creează un MAKE_PORT macro) și un număr PIN SlaveSelect (denumit în continuare SS), care poate funcționa apoi în clasă, cu ajutorul cuvintelor PORT și PIN_SS respectiv. Aici este destul de bine descris ce fel de animal este și ce este mâncat prin exemple.








Un astfel de design încă nu mi-a plăcut și, după un timp, a fost găsită o versiune destul de simplă. Din inklyudy primar (în cazul nostru - spi_base_hardware.h) Descriere clasa pentru a scoate spi_base_hardware.hpp, toate implementare - în spi_base_hardware.cpp. În acest caz, fișierul spi_base_hardware.h devine astfel:


Asta e tot. Descrieți separat, implementarea este separată, sunt fericit :)

Continuăm să scriem
După ce am scris implementarea fiecărei funcții, am decis să merg mai departe. În versiunea Hardware, porturile și pinii de interfață SPI nu pot fi modificați cu ușurință (este hardware, de pildă). Asa ca sa le luam pe ele, vei spune. Da, să răspund, dar în același timp voi adăuga - numai tu nu le vei vedea. Să se adauge ei înșiși, pentru piatra dorită - definițiile necesare. Deschidem fișierul include \ io.h și începem sortarea prin toate MC-urile - google pinout. Apoi, în stilul aceluiași io.h, vom crea un fișier care va verifica versiunea selectată a MK și va crea definiția cerută. Asta am primit spi_hardware_defs.h. Pe toate MC-ul nu am avut destul, lista de suport (toate versiunile) - la începutul acelui fișier. Dacă cel puțin cineva va beneficia de această piesă, cu siguranță o voi aduce până la capăt.

Și ce sa întâmplat?
spi_hardware.h


exemple
O clasă poate fi utilizată în mai multe moduri - ca un driver pentru interfața SPI, ca un părinte la o altă clasă ca părinte pentru un alt șablon de clasă și conducătorul auto este conținută într-un șablon de clasă. Voi arăta tot felul.
Exemplul 1. Hardware SPI, utilizați ca driver


Exemplul 2. Hardware SPI, crearea unui succesor de clasă


Și, în sfârșit, cele mai interesante ...
Exemplul 3. Hardware SPI, creând un șablon pentru succesorul clasei

Aici trebuie să faceți o rezervare. Probabil ați observat că în metoda init, am folosit acest lucru-> spi ... Dacă nu, compilatorul va striga cu voce tare că nu poate găsi aceste metode. Acest lucru se aplică tuturor metodelor din clasa SPI_Base_Hardware.

Toate exemplele anterioare au un dezavantaj - numele metodelor fast_shift etc sunt ocupate, ceea ce nu este critic, dar într-un fel nu este bun ... Prin urmare, consider opțiunea cea mai optimă ...

Exemplul 4. Hardware SPI, creând un șablon de clasă care conține driverul interior
Șoferul este încapsulat, acum totul este cool :)

Și ce urmează?
După ce am jucat cu Hardware SPI, am decis să rezolv versiunea software. Există deja orizonturi mari deschise: atârnă mai multe dispozitive pe porturi diferite, fără a acorda atenție controlorului de tip pinout - unde este ușor de condus, acolo și petrecut. Frumusețe!

Scheletul va fi același, cu excepția numelui și a modelului clasei:
Acum nu numai portul și pinul SS sunt transmise, dar și pinii MISO, MOSI și SCK. Dar dacă nu avem picioare libere într-un port? Corect, ne împrăștie pe diferite - avem aceeași implementare software, facem ceea ce ne dorim. Șablonul se modifică la acest formular:

El a crescut și sa transformat într-o linie uriașă. În implementare este necesar să se scrie:

Bitch ... Dar dacă faci două macrocomenzi, atunci totul arată foarte armonios: nu-i mai bine? Voi folosi în mod activ aceste macrocomenzi în viitor.

Noi scriem în continuare: implementarea Software-ului SPI
Am lăsat două opțiuni - Software SPI și Software separat SPI. Primul se blochează pe un port și acceptă clasa de port și 4 pini în șablon - MOSI, MISO, SCK și SS. Cel de-al doilea ia portul pentru fiecare pin, arată astfel:
Pentru a nu face două clase identice, am făcut SPI_Base_Software un moștenitor de la SPI_Base_Software_Separate. Aici:

Și ce sa întâmplat?
spi_software.h


exemple
Moduri de utilizare - la fel ca în versiunea hardwar.
Exemplul 5. Software SPI, șofer.

Exemplul 6. Crearea unei clase de moștenire

Exemplul 7. Crearea unui șablon pentru succesorul clasei

Exemplul 8. Crearea unui șablon de clasă care să conțină driverul interior







Articole similare

Trimiteți-le prietenilor: