Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

В Esimene osa Püüdsin Arduino pükstest välja kasvanud hobielektroonikainseneridele rääkida, kuidas ja miks nad peaksid lugema mikrokontrollerite andmelehti ja muud dokumentatsiooni. Tekst osutus suureks, nii et lubasin praktilisi näiteid näidata eraldi artiklis. Noh, ta nimetas end laaduriks ...

Täna näitan teile, kuidas andmelehtede abil lahendada STM32 (Blue Pill) ja STM8 kontrolleritel paljude projektide jaoks üsna lihtsaid, kuid vajalikke ülesandeid. Kõik demoprojektid on pühendatud minu lemmikutele LED-idele, valgustame neid suures koguses, selleks tuleb kasutada igasuguseid huvitavaid välisseadmeid.

Tekst osutus taas tohutuks, nii et mugavuse huvides koostan sisu:

STM32 Blue Pill: 16 LED-i DM634 draiveriga
STM8: kuue PWM-viigu seadistamine
STM8: 8 RGB LED-i kolmel kontaktil, katkestused

Vastutusest loobumine: ma ei ole insener, ma ei pretendeeri oma sügavate teadmistega elektroonikasse, artikkel on mõeldud minusugustele amatööridele. Tegelikult pidasin end sihtrühmaks kaks aastat tagasi. Kui keegi oleks mulle tookord öelnud, et tundmatu kiibi andmelehti pole hirmus lugeda, poleks ma palju aega kulutanud internetist koodijuppide otsimisele ning kääride ja kleepkrohviga karkude leiutamisele.

Selle artikli keskmes on andmelehed, mitte projektid, nii et kood ei pruugi olla liiga lihvitud ja sageli kark. Projektid ise on väga lihtsad, kuigi sobivad esmatutvuseks uue kiibiga.

Loodan, et minu artikkel aitab kedagi, kes on hobisse sukeldumise sarnases etapis.

STM32

16 LED-i DM634 ja SPI-ga

Väike projekt Blue Pilli (STM32F103C8T6) ja DM634 LED-draiverit kasutades. Andmelehtede abil tegeleme draiveri, STM IO portide ja SPI konfigureerimisega.

DM634

Taiwani kiip 16 x 16-bitise PWM väljundiga, saab aheldada. Noorem 12-bitine mudel on tuntud kodumaisest projektist kerge pakk. Kunagi, valides DM63x ja tuntud TLC5940 vahel, leppisin DM-iga mitmel põhjusel: 1) Aliexpressi TLC on kindlasti võlts, kuid see pole seda; 2) DM-l on autonoomne PWM oma sagedusgeneraatoriga; 3) seda saab Moskvas odavalt osta ja mitte oodata Ali pakki. Ja muidugi oli huvitav õppida, kuidas kiipi ise juhtida, mitte kasutada valmis teeki. Kiibid on nüüd peamiselt SSOP24 pakendis, neid on lihtne adapteril jootma.

Kuna tootja on Taiwani päritolu, andmeleht to chip on kirjutatud hiina inglise keeles, mis tähendab, et see saab olema lõbus. Kõigepealt vaadake pinoutiPin ühendus), et mõista, milline jalg mida ühendada, ja tihvtide kirjeldus (PIN-koodi kirjeldus). 16 tihvti:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Valamu alalisvoolu allikad (avatud äravool)

valamu / Avatud äravooluga väljund - laos; sissetuleva voolu allikas; maandusega ühendatud väljund aktiivses olekus - LED-id ühendatakse draiveriga katoodide abil. Elektriliselt pole see muidugi "avatud äravool" (avatud äravool), kuid andmelehtedel leidub sageli sellist tähistust tühjendusrežiimis olevate väljundite jaoks.

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Välised takistid REXT ja GND vahel väljundvoolu väärtuse määramiseks

REXT tihvti ja maanduse vahele on paigaldatud võrdlustakisti, mis juhib väljundite sisetakistust, vt graafikut andmelehe lk 9. DM634 puhul saab seda takistust juhtida ka tarkvara abil, seadistades üldise heleduse (globaalne heledus); Ma ei lasku selles artiklis üksikasjadesse, panen siia lihtsalt 2.2–3 kOhm takisti.

Kiibi juhtimise mõistmiseks vaatame seadme liidese kirjeldust:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

Jah, siin see on, hiina inglise keel kogu oma hiilguses. Selle tõlkimine on problemaatiline, saate sellest aru saada, kui soovite, kuid on ka teine ​​võimalus - vaadata, kuidas kirjeldatakse andmelehel ühendust funktsionaalselt lähedase TLC5940-ga:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
… Andmete seadmesse sisestamiseks on vaja ainult kolme tihvti. SCLK signaali tõusev serv nihutab andmed SIN-viigust siseregistrisse. Pärast kõigi andmete laadimist lukustab lühike kõrge XLAT-signaal seeriaviisiliselt edastatud andmed sisemistes registrites. Sisemised registrid on väravad, mille käivitab XLAT signaali tase. Kõik andmed edastatakse kõigepealt MSB kaudu.

Riiv - riiv / riiv / riiv.
Tõusev serv on impulsi esiserv
MSB kõigepealt – kõige olulisem (vasakpoolseim) bitt ettepoole.
kella andmeid – edastada andmeid järjestikku (bitihaaval).

Sõna riiv sageli leitakse kiipide dokumentatsioonist ja seda tõlgitakse mitmel viisil, nii et mõistmiseks luban endale

väike haridusprogrammLED-draiver on sisuliselt nihkeregister. "Shift" (suunata) nimes - andmete bitthaaval liikumine seadme sees: iga uus sisse lükatud bitt lükkab kogu keti enda ees ette. Kuna keegi ei taha jälgida LED-ide kaootilist vilkumist vahetuse ajal, siis toimub protsess puhverregistrites, mis on töötajatest katikuga eraldatud (riiv) on omamoodi riietusruum, kus bitid reastuvad soovitud järjekorras. Kui kõik on valmis, avaneb katik ja bitid lähevad tööle, asendades eelmise partii. Sõna riiv mikroskeemide dokumentatsioonis tähendab peaaegu alati sellist summutit, olenemata sellest, millistes kombinatsioonides seda kasutatakse.

Niisiis, andmete edastamine DM634-le toimub järgmiselt: seadke DAI sisend kaugema LED-i kõrge biti väärtusele, tõmmake DCK üles ja alla; seadke DAI sisendiks järgmise biti väärtus, tõmmake DCK; ja nii edasi, kuni kõik bitid on edastatud (sisse kellatanud), mille järel tõmbame LAT. Seda saab teha käsitsinatuke pauk), kuid selleks on parem kasutada spetsiaalselt teritatud SPI-liidest, kuna see on meie STM32-s kahes eksemplaris.

Sinine tahvelarvuti STM32F103

Sissejuhatus: STM32 kontrollerid on palju keerulisemad kui Atmega328, kui nad võivad olla hirmutavad. Samal ajal lülitatakse energiasäästu huvides alguses peaaegu kõik välisseadmed välja ja taktsagedus on 8 MHz sisemisest allikast. Õnneks kirjutasid STM-i programmeerijad koodi, mis toob kiibi "arvutatud" 72 MHz-le ja kõigi mulle teadaolevate IDE-de autorid lülitasid selle initsialiseerimisprotseduuri, nii et meil pole vaja kella (aga sa saad, kui sa tõesti tahad). Kuid peate välisseadmed sisse lülitama.

Dokumentatsioon: Blue Pillile on installitud populaarne STM32F103C8T6 kiip, selle jaoks on kaks kasulikku dokumenti:

  • Andmeleht mikrokontrolleritele STM32F103x8 ja STM32F103xB;
  • Teatmik kogu STM32F103 liini ja muu jaoks.

Andmelehel võib meid huvitada:

  • Pinouts - chip pinouts - juhuks, kui otsustame ise lauad teha;
  • Mälukaart – konkreetse kiibi mälukaart. Teatmejuhendis on kaart kogu rea kohta, seal on mainitud registreid, mida meie omas ei ole.
  • Pin Definitions tabel – peamiste ja alternatiivsete tihvtide funktsioonide loetelu; Internetist “sinise pilli” jaoks leiab mugavamaid pilte koos tihvtide ja nende funktsioonidega. Seetõttu guugeldame kohe Blue Pill pinouti ja hoiame seda pilti käepärast:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
NB: pildil oli internetist tulnud viga, märgati kommentaarides, mille eest aitäh. Pilt on asendatud, kuid see on õppetund - parem on kontrollida teavet mitte andmelehtedelt.

Eemaldame andmelehe, avame Reference Manuali, edaspidi kasutame ainult seda.
Protseduur: tegelege standardse sisendi/väljundiga, konfigureerige SPI, lülitage sisse vajalikud välisseadmed.

Sisend väljund

Atmega328-l on I/O äärmiselt lihtne, mistõttu võib STM32 valikute rohkus segadusse ajada. Nüüd vajame ainult järeldusi, kuid isegi on neli võimalust:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Avatud äravoolu väljund, push-pull väljund, push-pull alternatiivne, avatud äravoolu alternatiivne

"Tõmba lükka" (tõukejõud) - Arduino tavaline väljund, tihvti väärtus võib olla kas HIGH või LOW. Kuid "avatud äravooluga" tekivad raskusi, kuigi tegelikult on siin kõik lihtne:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Väljundi konfiguratsioon / kui port on väljundile määratud: / väljundpuhver lubatud: / – avatud tühjendusrežiim: "0" väljundregistris lubab N-MOS-i, "1" väljundregistris jätab pordi Hi-Z režiimi (P -MOS ei ole aktiveeritud ) / - push-pull mode: "0" väljundregistris aktiveerib N-MOS, "1" väljundregistris aktiveerib P-MOS.

Kõik avatud äravoolu erinevus (avatud äravool) sõnast "push-pull" (tõukejõud) seisneb selles, et esimeses viigus ei saa see võtta HIGH olekut: kui üksus kirjutatakse väljundregistrisse, läheb see suure takistuse režiimi (kõrge takistus, Tere-Z). Nulli kirjutades käitub tihvt mõlemas režiimis ühtmoodi, nii loogiliselt kui ka elektriliselt.

Tavalises väljundrežiimis tõlgib pin lihtsalt väljundregistri sisu. "Alternatiivis" juhib seda vastav välisseade (vt 9.1.4):

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Kui pordibitt on konfigureeritud alternatiivse funktsiooni väljundina, on väljundregister keelatud ja kontakt on ühendatud välisseadme väljundsignaaliga.

Iga tihvti alternatiivset funktsionaalsust kirjeldatakse artiklis PIN-ide definitsioonid Andmeleht on allalaaditud pildil. Küsimusele, mida teha, kui tihvtil on mitu alternatiivset funktsiooni, annab vastuse andmelehel joonealune märkus:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Kui mitu välisseadet kasutavad sama tihvti, tuleks alternatiivsete funktsioonide vahelise konflikti vältimiseks kasutada korraga ainult ühte välisseadet, mille ümberlülitamiseks kasutatakse bitti Peripheral Clock Enable (vastavas RCC registris).

Lõpuks on väljundrežiimis kontaktidel ka taktsagedus. See on veel üks energiasäästu funktsioon, meie puhul paneme selle lihtsalt maksimumile ja unustame ära.

Niisiis: me kasutame SPI-d, mis tähendab, et kaks kontakti (andmete ja kellasignaaliga) peaksid olema "alternatiivne push-pull funktsioon" ja veel üks (LAT) peaks olema "tavaline push-pull". Kuid enne nende määramist tegeleme SPI-ga.

SPI

Veel üks väike häkkimine

SPI ehk Serial Peripheral Interface (serial peripheral interface) on lihtne ja väga tõhus liides MK-ga suhtlemiseks teiste MK-dega ja välismaailmaga üldiselt. Selle tööpõhimõtet on juba eespool kirjeldatud, kus räägitakse Hiina LED-draiverist (vt juhendi jaotist 25). SPI võib töötada ülem- ("master") ja alam ("alluv") režiimides. SPI-l on neli põhikanalit, millest kõik ei pruugi olla seotud:

  • MOSI, põhiväljund / alluv sisend: see kontakt saadab andmeid ülemrežiimis ja võtab andmeid vastu alamrežiimis;
  • MISO, Master Input / Slave Output: vastupidi, ülemseadmes see võtab vastu, alamseadmes annab;
  • SCK, Serial Clock: määrab andmeedastuse sageduse ülemseadmes või võtab vastu alamseadmes kellasignaali. Sisuliselt lööb lööki;
  • SS, Slave Select: selle kanali puhul teab ori, et nad tahavad temalt midagi. STM32 peal nimetatakse seda NSS-iks, kus N = negatiivne, st. kontroller muutub alluvaks, kui sellel kanalil on maandus. See sobib hästi Open Drain Output režiimiga, kuid see on teine ​​lugu.

Nagu kõik muu, on STM32 SPI-l palju funktsioone, mis muudab selle mõistmise mõnevõrra keeruliseks. Näiteks võib see töötada mitte ainult SPI-ga, vaid ka I2S-liidesega ja nende kirjeldused on dokumentatsioonis segatud, peate ülejäägid õigeaegselt ära lõikama. Meie ülesanne on äärmiselt lihtne: peate lihtsalt andma andmed ainult MOSI ja SCK abil. Läheme jaotisse 25.3.4 (pooldupleksside, pooldupleksside), kust leiame 1 kell ja 1 ühesuunaline andmejuhe (1 kell ja 1 ühesuunaline andmevoog):

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Selles režiimis kasutab rakendus SPI-d kas ainult edastus- või ainult vastuvõturežiimis. / Ainult edastusrežiim sarnaneb dupleksrežiimiga: andmed edastatakse edastusviiul (MOSI ülemrežiimis või MISO alamrežiimis), samas kui vastuvõtuviiku (vastavalt MISO või MOSI) saab kasutada tavalise I/O-na. pin. Sel juhul piisab, kui rakendus ignoreerib Rx puhvrit (kui see loetakse, siis andmeid ei edastata).

Suurepärane, MISO pin on vaba, ühendame sellega LAT signaali. Tegeleme Slave Selectiga, mida saab STM32 pealt programmiliselt juhtida, mis on ülimugav. Samanimelist lõiku loeme jaotises 25.3.1 SPI üldkirjeldus:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
NSS-i tarkvara juhtimine (SSM = 1) / Slave valiku teave sisaldub SPI_CR1 registri SSI-bitis. Väline NSS-i tihvt jäetakse vabaks muude rakenduste vajaduste jaoks.

On aeg registritesse kirjutada. Otsustasin kasutada SPI2, otsime selle baasaadressi andmelehelt - jaotisest 3.3 Mälukaart (mälukaart):

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

Noh, alustame:

#define _SPI2_(mem_offset) (*(volatile uint32_t *)(0x40003800 + (mem_offset)))

Avame jaotise 25.3.3 kõneka pealkirjaga "SPI konfigureerimine põhirežiimis":

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

1. Seadke jadaliidese kell SPI_CR2 registri BR[0:1] bittidega.

Registrid on kogutud samanimelisse teatmejuhendi jaotisesse. Aadressi nihe (aadressi nihe) CR1-l on 0x00, vaikimisi kustutatakse kõik bitid (Lähtesta väärtus 0x0000):

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

BR-bitid määravad kontrolleri kellajaguri, määrates nii sageduse, millega SPI töötab. STM32 sagedus on 72 MHz, LED-draiver töötab selle andmelehe järgi sagedusel kuni 25 MHz, seega peame jagama neljaga (BR[2:0] = 001).

#define _SPI_CR1 0x00

#define BR_0        0x0008
#define BR_1        0x0010
#define BR_2        0x0020

_SPI2_ (_SPI_CR1) |= BR_0;// pclk/4

2. Seadistage CPOL- ja CPHA-bitid, et määrata seos andmeedastuse ja jadaliidese kella vahel (vt diagrammi lk 240).

Kuna me loeme siin andmelehte, mitte ei vaata skeeme, siis vaatame lähemalt CPOL- ja CPHA-bittide tekstilist kirjeldust leheküljel 704 (SPI üldkirjeldus):

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Kella faas ja polaarsus
Kasutades SPI_CR1 registri CPOL- ja CPHA-bitte, saate programmiliselt valida neli ajastussuhte valikut. CPOL (Clock Polarity) bitt juhib kella signaali olekut, kui andmeid ei edastata. See bitt juhib ülem- ja alamrežiime. Kui CPOL lähtestatakse, on SCK viik puhkeolekus madal. Kui CPOL-bitt on seatud, on SCK-viik jõudeoleku ajal kõrgel.
Kui CPHA (Clock Phase) bitt on seatud, on MSB trap strobo SCK signaali teine ​​serv (langeb, kui CPOL on kustutatud, või tõusev serv, kui CPOL on seatud). Andmed lukustatakse teisel kellavahetusel. Kui CPHA-bitt on kustutatud, toimib SCK-signaali tõusev serv (langev serv, kui CPOL on seatud, või tõusev serv, kui CPOL on tühi) kõrge bitilõksu strobina. Andmed lukustatakse esimesel kellavahetusel.

Olles seda teadmist maitsnud, jõuame järeldusele, et mõlemad bitid peavad jääma nulliks, sest tahame, et SCK-signaal jääks madalaks, kui seda ei kasutata, ja andmeid edastataks impulsi tõusval serval (vt joonis XNUMX). Tõusev serv andmelehel DM634).

Muide, siin kohtasime esmakordselt ST-andmete lehtede sõnavara omadust: neis on kirjutatud fraas "reset the bit to zero". natukene lähtestadaJa mitte natuke puhastada, nagu näiteks Atmega.

3. 8-bitise või 16-bitise andmeploki vormingu määramiseks määrake DFF-bitt

Võtsin konkreetselt 16-bitise DM634, et mitte vaeva näha 12-bitiste PWM-andmete edastamisega, nagu DM633. DFF-i on mõttekas ühendada:

#define DFF         0x0800

_SPI2_ (_SPI_CR1) |= DFF; // 16-bit mode

4. Konfigureerige LSBFIRST bitt SPI_CR1 registris, et määrata ploki vorming

LSBFIRST, nagu nimigi viitab, seadistab edastuse esmalt kõige vähem olulise bitiga. Kuid DM634 soovib esmalt saada andmeid MSB-st. Seetõttu jätame selle lähtestama.

5. Riistvararežiimis, kui on vaja sisendit NSS-i viigust, juhtige NSS-i viik kõrgele kogu baidiedastusjada jooksul. NSS-programmirežiimis määrake SSM- ja SSI-bitid SPI_CR1-registris. Kui NSS-i viik tuleb väljastada, tuleb määrata ainult SSOE-bitt.

Installige SSM ja SSI, et unustada NSS-i riistvararežiim:

#define SSI         0x0100
#define SSM         0x0200

_SPI2_ (_SPI_CR1) |= SSM | SSI; //enable software control of SS, SS high

6. MSTR ja SPE bitid tuleb seadistada (need jäävad seadistatuks ainult siis, kui NSS on kõrge)

Tegelikult määrame nende bittide abil oma SPI-d ülemseadmeks ja lülitame selle sisse:

#define MSTR        0x0004
#define SPE         0x0040

_SPI2_ (_SPI_CR1) |= MSTR; //SPI master
//когда все готово, включаем SPI
_SPI2_ (_SPI_CR1) |= SPE;

SPI on seadistatud, kirjutame kohe funktsioonid, mis saadavad draiverile baite. Loe edasi 25.3.3 "SPI konfigureerimine põhirežiimis":

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Andmeedastusprotseduur
Edastamine algab siis, kui bait kirjutatakse Tx-puhvrisse.
Andmebait laaditakse nihkeregistrisse kell paralleelselt režiimis (sisemisest siinist) esimese biti edastamise ajal, misjärel see edastatakse järjekindel MOSI viigu režiim, esimene või viimane bitt edasi, sõltuvalt LSBFIRST biti seadistusest registris CPI_CR1. TXE lipp määratakse pärast andmeedastust Tx puhvrist nihkeregistrisse, ja katkestus genereeritakse, kui TXEIE bitt CPI_CR1 registris on seatud.

Tõlkes tõstsin esile paar sõna, et juhtida tähelepanu ühele SPI-i juurutamise tunnusele STM-kontrollerites. Atmegal on TXE lipp (Tx tühi, Tx on tühi ja valmis andmete vastuvõtmiseks) määratakse alles pärast kogu baidi saatmist väljapoole. Ja siin pannakse see lipp pärast seda, kui bait on sisestatud sisemisse nihkeregistrisse. Kuna see lükatakse sinna kõigi bittidega korraga (paralleelselt) ja seejärel edastatakse andmed järjestikku, siis seadistatakse TXE enne, kui bait on täielikult saadetud. See on oluline, sest meie LED-draiveri puhul peame pärast saatmist tõmbama LAT-tihvti Kõik andmed, s.t. ainult TXE lipust meile ei piisa.

Mis tähendab, et vajame teist lippu. Vaatame 25.3.7 - "Oleklipud":

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
<…>
Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
HÄIVATUD lipp
BSY lipu määrab ja kustutab riistvara (sellele kirjutamine ei mõjuta). BSY lipp näitab SPI sidekihi olekut.
See lähtestab:
kui ülekanne on lõppenud (välja arvatud põhirežiimis, kui ülekanne on pidev)
kui SPI on keelatud
kui ilmneb põhirežiimi tõrge (MODF=1)
Kui edastamine ei ole pidev, kustutatakse BSY lipp iga andmeedastuse vahel.

Olgu, see tuleb kasuks. Uurige, kus asub Tx-puhver. Selleks lugege "SPI andmeregistrit":

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Bitid 15:0 DR[15:0] Andmeregister
Vastuvõetud või edastatavad andmed.
Andmeregister on jagatud kaheks puhvriks, millest üks on kirjutamiseks (edastuspuhver) ja teine ​​lugemiseks (vastuvõtupuhver). Andmeregistrisse kirjutamine kirjutab Tx puhvrisse ja andmeregistrist lugemine tagastab Rx puhvris sisalduva väärtuse.

Noh, olekuregister, kus on TXE ja BSY lipud:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

Me kirjutame:

#define _SPI_DR  0x0C
#define _SPI_SR  0x08

#define BSY         0x0080
#define TXE         0x0002

void dm_shift16(uint16_t value)
{
    _SPI2_(_SPI_DR) = value; //send 2 bytes
    while (!(_SPI2_(_SPI_SR) & TXE)); //wait until they're sent
}

Noh, kuna peame vastavalt LED-draiveri väljundite arvule üle kandma 16 korda kaks baiti, siis midagi sellist:

void sendLEDdata()
{
    LAT_low();
    uint8_t k = 16;
    do
    {   k--;
        dm_shift16(leds[k]);
    } while (k);

    while (_SPI2_(_SPI_SR) & BSY); // finish transmission

    LAT_pulse();
}

Kuid me ei tea veel, kuidas LAT-i tihvti tõmmata, nii et läheme tagasi I/O juurde.

Määrake tihvtid

STM32F1-s on kontaktide oleku eest vastutavad registrid üsna ebatavalised. Selge on see, et neid on rohkem kui Atmega, kuid need erinevad ka teistest STM kiipidest. Jaotis 9.1 GPIO Üldkirjeldus:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Kõik üldotstarbelised I/O-pordid (GPIO) sellel on kaks 32-bitist konfiguratsiooniregistrit (GPIOx_CRL ja GPIOx_CRH), kaks 32-bitist andmeregistrit (GPIOx_IDR ja GPIOx_ODR), 32-bitine seadistus-/lähtestusregister (GPIOx_BSRR), 16-bitine lähtestusregister (GPIOx_BRR) ja 32-bitine seadistusregister (GPIOx_BSRR). bitiblokeerimisregister (GPIOx_LCKR).

Ebatavalised ja ka üsna ebamugavad on siin kaks esimest registrit, sest pordi 16 viiku on nende vahel laiali “neli bitti venna kohta” formaadis. Need. tihvtid XNUMX kuni XNUMX on CRL-is ja ülejäänud on CRH-s. Samal ajal sobivad ülejäänud registrid edukalt kõigi pordi viigude bittidega - sageli jäävad need pooleks "reserveeritud".

Lihtsuse huvides alustame loendi lõpust.

Me ei vaja blokeerimisregistrit.

Seadistamise ja lähtestamise registrid on üsna naljakad selle poolest, et nad dubleerivad üksteist osaliselt: kõike saab kirjutada ainult BSRR-is, kus ülemised 16 bitti lähtestavad viigu nulli ja alumised seatakse 1-le või saate ka kasutage BRR-i, mille alumised 16 bitti lähtestavad ainult viigu . Mulle meeldib teine ​​variant. Need registrid on olulised, kuna need pakuvad tihvtidele aatomi juurdepääsu:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Aatomi installimine või lähtestamine
GPIOx_ODR-i bititasemel programmeerimisel ei pea te katkestusi keelama: saate muuta üht või mitut bitti ühe APB2 aatomikirjutusoperatsiooniga. See saavutatakse, kirjutades "1" muudetava biti seadistus-/lähtestamisregistrisse (GPIOx_BSRR või ainult lähtestamise korral GPIOx_BRR). Muud bitid jäävad muutumatuks.

Andmeregistritel on üsna kõnekad nimed – IDR = Sisend Suunaregister, sisestusregister; ODR= Väljund Suunaregister, väljundregister. Praeguses projektis me neid ei vaja.

Ja lõpuks, kontrollregistrid. Kuna meid huvitavad teise SPI kontaktid, nimelt PB13, PB14 ja PB15, vaatame kohe CRH-i:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

Ja me näeme, et 20.-31. kuupäevast tuleb midagi bitti kirjutada.

Saime juba ülaltoodud kontaktidest aru, mida tahame, nii et siin teen ilma ekraanipildita, ütlen lihtsalt, et MODE määrab suuna (sisend, kui mõlemad bitid on seatud 0-le) ja viigu kiiruse (me vajame 50MHz, st. mõlemad tihvtid väärtusele "1") ja CNF seab režiimi: tavaline "push-push" - 00, "alternative" - ​​10. Vaikimisi, nagu näeme ülalt, on kõigil kontaktidel kolmas bitt altpoolt ( CNF0), see seab need režiimi ujuv sisend.

Kuna plaanin selle kiibiga midagi muud teha, siis lihtsuse mõttes defineerisin üldiselt kõik võimalikud MODE ja CNF väärtused nii alumise kui ka ülemise juhtregistri jaoks.

Kuidagi nii

#define CNF0_0 0x00000004
#define CNF0_1 0x00000008
#define CNF1_0 0x00000040
#define CNF1_1 0x00000080
#define CNF2_0 0x00000400
#define CNF2_1 0x00000800
#define CNF3_0 0x00004000
#define CNF3_1 0x00008000
#define CNF4_0 0x00040000
#define CNF4_1 0x00080000
#define CNF5_0 0x00400000
#define CNF5_1 0x00800000
#define CNF6_0 0x04000000
#define CNF6_1 0x08000000
#define CNF7_0 0x40000000
#define CNF7_1 0x80000000
#define CNF8_0 0x00000004
#define CNF8_1 0x00000008
#define CNF9_0 0x00000040
#define CNF9_1 0x00000080
#define CNF10_0 0x00000400
#define CNF10_1 0x00000800
#define CNF11_0 0x00004000
#define CNF11_1 0x00008000
#define CNF12_0 0x00040000
#define CNF12_1 0x00080000
#define CNF13_0 0x00400000
#define CNF13_1 0x00800000
#define CNF14_0 0x04000000
#define CNF14_1 0x08000000
#define CNF15_0 0x40000000
#define CNF15_1 0x80000000

#define MODE0_0 0x00000001
#define MODE0_1 0x00000002
#define MODE1_0 0x00000010
#define MODE1_1 0x00000020
#define MODE2_0 0x00000100
#define MODE2_1 0x00000200
#define MODE3_0 0x00001000
#define MODE3_1 0x00002000
#define MODE4_0 0x00010000
#define MODE4_1 0x00020000
#define MODE5_0 0x00100000
#define MODE5_1 0x00200000
#define MODE6_0 0x01000000
#define MODE6_1 0x02000000
#define MODE7_0 0x10000000
#define MODE7_1 0x20000000
#define MODE8_0 0x00000001
#define MODE8_1 0x00000002
#define MODE9_0 0x00000010
#define MODE9_1 0x00000020
#define MODE10_0 0x00000100
#define MODE10_1 0x00000200
#define MODE11_0 0x00001000
#define MODE11_1 0x00002000
#define MODE12_0 0x00010000
#define MODE12_1 0x00020000
#define MODE13_0 0x00100000
#define MODE13_1 0x00200000
#define MODE14_0 0x01000000
#define MODE14_1 0x02000000
#define MODE15_0 0x10000000
#define MODE15_1 0x20000000

Meie kontaktid on pordis B (baasaadress - 0x40010C00), kood:

#define _PORTB_(mem_offset) (*(volatile uint32_t *)(0x40010C00 + (mem_offset)))

#define _BRR  0x14
#define _BSRR 0x10
#define _CRL  0x00
#define _CRH  0x04

//используем стандартный SPI2: MOSI на B15, CLK на B13
//LAT пусть будет на неиспользуемом MISO – B14

//очищаем дефолтный бит, он нам точно не нужен
_PORTB_ (_CRH) &= ~(CNF15_0 | CNF14_0 | CNF13_0 | CNF12_0);

//альтернативные функции для MOSI и SCK
_PORTB_ (_CRH) |= CNF15_1 | CNF13_1;

//50 МГц, MODE = 11
_PORTB_ (_CRH) |= MODE15_1 | MODE15_0 | MODE14_1 | MODE14_0 | MODE13_1 | MODE13_0;

Ja vastavalt saate kirjutada LAT-i jaoks määratlusi, mis tõmblevad BRR- ja BSRR-registreid:

/*** LAT pulse – high, then low */
#define LAT_pulse() _PORTB_(_BSRR) = (1<<14); _PORTB_(_BRR) = (1<<14)

#define LAT_low() _PORTB_(_BRR) = (1<<14)

(LAT_madal lihtsalt inertsist, kuidagi alati oli, las see jääb endale)

Nüüd on kõik suurepärane, kuid see ei tööta. Kuna see on STM32, säästavad nad siin elektrit, mis tähendab, et peate sisse lülitama vajalike välisseadmete kella.

Lülitage kellaaeg sisse

Kell vastutab kellaajamise eest, nemad on ka Kell. Ja juba võisime märgata lühendit RCC. Otsime seda dokumentatsioonist: see on Reset ja Clock Control (lähtestamise ja kellaaja haldamine).

Nagu eelpool mainitud, siis õnneks tegid STM-i inimesed meie jaoks kõige raskema osa kellatamise teemast, mille eest suur tänu neile (panen taaskord lingi Di Halti veebisaitet oleks selge, kui segane see on). Vajame ainult registreid, mis vastutavad välisseadmete kellastamise lubamise eest (Peripheral Clock Enable Registers). Esiteks leiame RCC baasaadressi, see asub "Mälukaardi" alguses:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

#define _RCC_(mem_offset) (*(volatile uint32_t *)(0x40021000 + (mem_offset)))

Ja seejärel klõpsake lingil, kust tabelist midagi otsida, või, palju parem, vaadake üle hõlmavate registrite kirjeldused jaotistest lubada registrid. Kust leiame RCC_APB1ENR ja RCC_APB2ENR:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

Ja nendes vastavalt bitid, mis sisaldavad SPI2, IOPB (I / O-port B) ja alternatiivsete funktsioonide (AFIO) takti.

#define _APB2ENR 0x18
#define _APB1ENR 0x1C

#define IOPBEN 0x0008
#define SPI2EN 0x4000
#define AFIOEN 0x0001

//включаем тактирование порта B и альт. функций
_RCC_(_APB2ENR) |= IOPBEN | AFIOEN;

//включаем  тактирование SPI2
_RCC_(_APB1ENR) |= SPI2EN;

Lõpliku koodi leiate siin.

Kui on võimalus ja soov testida, siis ühendame DM634 nii: DAI PB15 külge, DCK PB13 külge, LAT PB14 külge. Toidame juhti 5 voltist, ärge unustage maandusi kombineerida.

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

STM8 PWM

PWM STM8-l

Kui ma just seda artiklit kavandasin, otsustasin näiteks proovida mõne harjumatu kiibi funktsionaalsust meisterdada vaid andmelehe abil, et kingsepp ilma saabasteta välja ei tuleks. STM8 sobis sellesse rolli suurepäraselt: esiteks oli mul paar hiina tahvlit STM8S103-ga, teiseks pole see eriti populaarne ning seetõttu toetub kiusatus internetist lugeda ja lahendus leida just nende samade lahenduste puudumisel.

Kiibil on ka andmeleht и kasutusjuhend RM0016, esimeses pinout ja registri aadressid, teises - kõik muu. STM8 programmeerimine C-s inetus IDE-s ST Visual Develop.

Kell ja I/O

Vaikimisi töötab STM8 sagedusel 2 MHz, see tuleb kohe parandada.

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
HSI kell (kõrge sisemine)
HSI kell on tuletatud sisemisest 16 MHz RC-ostsillaatorist, millel on programmeeritav jagur (1 kuni 8). See on määratud kellajaguri registris (CLK_CKDIVR).
Märkus: HSI RC ostsillaator jaguriga 8 valitakse käivitamisel peamise kella allikaks.

Leiame andmelehelt registri aadressi, refmanis kirjelduse ja näeme, et register vajab tühjendamist:

#define CLK_CKDIVR *(volatile uint8_t *)0x0050C6

CLK_CKDIVR &= ~(0x18);

Kuna kavatseme käivitada PWM-i ja ühendada LED-id, vaatame pinouti:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

Kiip on väike, paljud funktsioonid on riputatud samadele tihvtidele. See, mis on nurksulgudes, on "alternatiivne funktsionaalsus", seda vahetavad "valikubaitid" (valikubaidid) – midagi Atmega kaitsmete sarnast. Saate nende väärtusi programmiliselt muuta, kuid see pole vajalik, sest. Uus funktsioon aktiveeritakse alles pärast taaskäivitamist. Lihtsam on kasutada ST Visual Programmerit (allalaaditud koos Visual Developiga), mis saab neid baite muuta. Pinout näitab, et esimese taimeri väljundid CH1 ja CH2 on peidetud nurksulgudesse; STVP-s on vaja seadistada AFR1 ja AFR0 bitid ning teine ​​kannab ka teise taimeri väljundi CH1 PD4-lt PC5-le.

Seega juhivad LED-e 6 kontakti: PC6, PC7 ja PC3 esimese taimeri jaoks, PC5, PD3 ja PA3 teise jaoks.

STM8 sisend- ja väljundviikude endi seadistamine on lihtsam ja loogilisem kui STM32 puhul:

  • Atmega tuttav andmete suunaregister DDR (Andmete suuna register): 1 = väljund;
  • esimene juhtregister CR1 seab väljastamisel push-pull režiimi (1) või avatud äravoolu (0); kuna ühendan LED-id kiibiga katoodidega, siis jätan siia nullid;
  • teine ​​juhtregister CR2 määrab väljastamisel taktsageduse: 1 = 10 MHz

#define PA_DDR     *(volatile uint8_t *)0x005002
#define PA_CR2     *(volatile uint8_t *)0x005004
#define PD_DDR     *(volatile uint8_t *)0x005011
#define PD_CR2     *(volatile uint8_t *)0x005013
#define PC_DDR     *(volatile uint8_t *)0x00500C
#define PC_CR2     *(volatile uint8_t *)0x00500E

PA_DDR = (1<<3); //output
PA_CR2 |= (1<<3); //fast
PD_DDR = (1<<3); //output
PD_CR2 |= (1<<3); //fast
PC_DDR = ((1<<3) | (1<<5) | (1<<6) | (1<<7)); //output
PC_CR2 |= ((1<<3) | (1<<5) | (1<<6) | (1<<7)); //fast

PWM-i seadistus

Esiteks määratleme terminid:

  • PWM sagedus – taimeri tiksumise sagedus;
  • Automaatne uuesti laadimine, AR – automaatselt laaditud väärtus, milleni taimer loeb (impulsiperiood);
  • Värskenda sündmust, UEV – sündmus, mis leiab aset siis, kui taimer on AR-le lugenud;
  • PWM töötsükkel - PWM-i töötsükkel, mida sageli nimetatakse "töötsükliks";
  • Jäädvusta/võrdle väärtust – jäädvustamise/võrdlemise väärtus, milleni loendatakse taimer teeb midagi (PWM-i puhul inverteerib väljundsignaali);
  • eellaadimise väärtus – eelsalvestatud väärtus. väärtust võrrelda ei saa muuta, kui taimer tiksub, vastasel juhul katkeb PWM-tsükkel. Seetõttu asetatakse uued edastatud väärtused puhvrisse ja tõmmatakse välja, kui taimer jõuab loenduse lõpuni ja lähtestatakse;
  • Servad joondatud и Keskjoondatud režiimid – joondus piiril ja keskel, sama mis atmelovskie Kiire PWM и Faasikorrektne PWM.
  • OCiREF, väljundi võrdlussignaal - võrdlusväljundsignaal, tegelikult see, mis kuvatakse PWM-režiimis vastaval viigul.

Nagu pinoutist juba selgub, on kahel taimeril PWM-võimalused - esimesel ja teisel. Mõlemad on 16-bitised, esimesel on palju lisafunktsioone (eelkõige võib see lugeda nii üles kui ka alla). Meil on vaja mõlemat ühtemoodi töötada, seega otsustasin alustada ilmselgelt kehvemast teisest, et mitte kogemata kasutada midagi, mida selles pole. Mõningane probleem on selles, et kõigi taimerite PWM-i funktsionaalsuse kirjeldus viitejuhendis on esimest taimerit käsitlevas peatükis (17.5.7 PWM-režiim), seega peate kogu aeg dokumendis edasi-tagasi hüppama.

STM8 PWM-il on Atmega PWM-i ees oluline eelis:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
PWM servade joondamisega
Konto seadistamine alt üles
Ülesloendamine on aktiivne, kui DIR-bitt TIM_CR1 registris on selge
Näide
Näites kasutatakse esimest PWM-režiimi. PWM-i tugisignaali OCiREF hoitakse kõrgel seni, kuni TIM1_CNT < TIM1_CCRI. Vastasel juhul võtab see madala taseme. Kui võrreldav väärtus TIM1_CCRI registris on suurem kui automaatse laadimise väärtus (TIM1_ARR register), hoitakse OCiREF signaali väärtusel 1. Kui võrdlusväärtus on 0, hoitakse OCiREF nullis....

STM8 taimer ajal värskenda sündmust kontrollib kõigepealt väärtust võrreldaja alles siis toodab võrdlussignaali. Atmegas ajab taimer esmalt värisema ja seejärel võrdleb, mille tulemusena millal compare value == 0 väljundiks on nõel, millega peab kuidagi hakkama saama (näiteks programmiliselt loogikat ümber pöörates).

Mida me teha tahame: 8-bitine PWM (AR == 255), lugedes alt üles, joondus piki piiri. Kuna pirnid on kiibiga ühendatud katoodidega, peaks PWM väljastama 0 (LED põleb), kuni väärtust võrrelda ja 1 pärast.

Mõne kohta oleme juba lugenud PWM-režiim, nii et leiame teise taimeri soovitud registri, otsides teatmejuhendist seda fraasi (18.6.8 - TIMx_CCMR1):

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
110: Esimene PWM-režiim – alt üles loendamisel on esimene kanal aktiivne seni, kuni TIMx_CNT < TIMx_CCR1. Vastasel juhul on esimene kanal passiivne. [dokumendis edasi, ekslik kopeeri-kleebi taimer 1] 111: Teine PWM-režiim – alt üles loendamisel on esimene kanal passiivne kuni TIMx_CNT < TIMx_CCR1. Vastasel juhul on esimene kanal aktiivne.

Kuna LED-id on MK-ga ühendatud katoodidega, siis teine ​​režiim sobib meile (esimene ka, aga seda me veel ei tea).

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Bitt 3 OC1PE: lubage 1. väljundi eellaadimine
0: TIMx_CCR1 eellaadimisregister on keelatud. Saate igal ajal kirjutada aadressile TIMx_CCR1. Uus väärtus töötab kohe.
1: TIMx_CCR1 eellaadimisregister on lubatud. Lugemis-/kirjutustoimingud pääsevad juurde eellaadimisregistrisse. TIMx_CCR1 eellaaditud väärtus laaditakse iga värskendussündmuse ajal variregistrisse.
*Märkus. PWM-režiimi nõuetekohaseks toimimiseks peavad eellaadimisregistrid olema lubatud. See on ühe signaali režiimis valikuline (OPM-bitt on seatud registris TIMx_CR1).

Olgu, lülitage sisse kõik, mida vajate teise taimeri kolme kanali jaoks:

#define TIM2_CCMR1 *(volatile uint8_t *)0x005307
#define TIM2_CCMR2 *(volatile uint8_t *)0x005308
#define TIM2_CCMR3 *(volatile uint8_t *)0x005309

#define PWM_MODE2   0x70 //PWM mode 2, 0b01110000
#define OCxPE       0x08 //preload enable

TIM2_CCMR1 = (PWM_MODE2 | OCxPE);
TIM2_CCMR2 = (PWM_MODE2 | OCxPE);
TIM2_CCMR3 = (PWM_MODE2 | OCxPE);

AR koosneb kahest kaheksabitisest registrist, siin on kõik lihtne:

#define TIM2_ARRH  *(volatile uint8_t *)0x00530F
#define TIM2_ARRL  *(volatile uint8_t *)0x005310

TIM2_ARRH = 0;
TIM2_ARRL = 255;

Teine taimer saab lugeda ainult alt üles, joondus piiril, midagi muuta ei pea. Seadke sagedusjagur näiteks 256-le. Teise taimeri jaoks määratakse jagur registris TIM2_PSCR ja see on kahe astmega:

#define TIM2_PSCR  *(volatile uint8_t *)0x00530E

TIM2_PSCR = 8;

Jääb järeldused ja teine ​​taimer ise sisse lülitada. Esimene ülesanne on lahendatud registrite abil Jäädvusta/võrdle Võimaldama: neid on kaks, nende peale on asümmeetriliselt hajutatud kolm kanalit. Siit saame ka teada, et on võimalik muuta signaali polaarsust, s.t. põhimõtteliselt võiks kasutada ka PWM režiimi 1. Kirjutame:

#define TIM2_CCER1 *(volatile uint8_t *)0x00530A
#define TIM2_CCER2 *(volatile uint8_t *)0x00530B

#define CC1E  (1<<0) // CCER1
#define CC2E  (1<<4) // CCER1
#define CC3E  (1<<0) // CCER2

TIM2_CCER1 = (CC1E | CC2E);
TIM2_CCER2 = CC3E;

Ja lõpuks käivitame taimeri registris TIMx_CR1:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

#define TIM2_CR1   *(volatile uint8_t *)0x005300

TIM2_CR1 |= 1;

Kirjutame AnalogWrite'i () lihtsa analoogi, mis edastab tegelikud väärtused võrdluseks taimerile. Registrid on ettearvatavalt nimelised Registrite hõivamine/võrdlemine, on neid iga kanali jaoks kaks: madalad 8 bitti TIM2_CCRxL-s ja kõrged bitid TIM2_CCRxH-s. Kuna alustasime 8-bitise PWM-iga, piisab ainult madalate bittide kirjutamisest:

#define TIM2_CCR1L *(volatile uint8_t *)0x005312
#define TIM2_CCR2L *(volatile uint8_t *)0x005314
#define TIM2_CCR3L *(volatile uint8_t *)0x005316

void setRGBled(uint8_t r, uint8_t g, uint8_t b)
{
    TIM2_CCR1L = r;
    TIM2_CCR2L = g;
    TIM2_CCR3L = b;
}

Tähelepanelik lugeja märkab, et meil on pisut defektne PWM, mis ei suuda 100% täitmist välja anda (maksimaalse väärtuse 255 korral pööratakse signaal ühe taimeritsükli võrra ümber). LED-ide puhul see rolli ei mängi ja tähelepanelik lugeja aimab juba ära, kuidas seda parandada.

Teise taimeriga PWM töötab, minge esimese juurde.

Esimesel taimeris on täpselt samad bitid samades registrites (lihtsalt neid bitte, mis teises taimeris "reserveeritud" jäid, kasutatakse esimeses aktiivselt igasuguste edasijõudnute jaoks). Seetõttu piisab, kui leida andmelehel samade registrite aadressid ja kopeerida kood. Noh, muuda sagedusjaguri väärtust, sest. esimene taimer tahab saada kahes registris mitte kahe astme, vaid täpse 16-bitise väärtuse Eelskaala kõrge и Madal. Teeme kõike ja ... esimene taimer ei tööta. Mis viga?

Ainus viis probleemi lahendamiseks on vaadata kogu jaotist taimeri 1 juhtimisregistrite kohta, kus otsime sellist, mida teisel taimeril pole. tuleb 17.7.30 Rikete register (TIM1_BKR), kus on natuke selline:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Luba põhiväljund

#define TIM1_BKR   *(volatile uint8_t *)0x00526D

TIM1_BKR = (1<<7);

See on praegu kõik, kood seal.

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

STM8 multipleks

Multipleksimine STM8-l

Kolmas miniprojekt on ühendada kaheksa RGB LED-i teise taimeriga PWM-režiimis ja panna need näitama erinevaid värve. See põhineb LED-multipleksimise kontseptsioonil, mis seisneb selles, et kui lülitate LED-id väga-väga kiiresti sisse ja välja, tundub meile, et need põlevad pidevalt (nägemise püsivus, visuaalse taju inerts). Kunagi tegin midagi sellist arduino peal.

Töö algoritm näeb välja selline:

  • ühendas esimese RGB LED-i anood;
  • valgustage see, andes katoodidele vajalikke signaale;
  • ootas PWM-tsükli lõppu;
  • ühendatud teise RGB LED-i anood;
  • süütas selle...

No jne. Muidugi on ilusa töö jaoks vajalik, et anoodiühendus ja LED-i "süütamine" toimuksid samaaegselt. Noh, peaaegu. Igal juhul peame kirjutama koodi, mis väljastab väärtused teise taimeri kolmes kanalis, muutma neid, kui UEV on saavutatud, ja samal ajal muutma hetkel aktiivset RGB LED-i.

Kuna LED-i lülitus on automaatne, peate looma "videomälu", kust katkestuse töötleja andmeid saab. See on lihtne massiiv:

uint8_t colors[8][3];

Konkreetse LED-i värvi muutmiseks piisab, kui kirjutada sellesse massiivi vajalikud väärtused. Ja muutuja vastutab aktiivse LED-i arvu eest

uint8_t cnt;

Demux

Korralikuks multipleksimiseks vajame kummalisel kombel CD74HC238 demultiplekserit. Demultiplekser - kiip, mis rakendab operaatori riistvaras <<. Kolme sisendviigu (bitid 0, 1 ja 2) kaudu anname talle ette kolmebitise numbri X ja vastuseks aktiveerib ta väljundnumbri (1<<X). Ülejäänud kiibi sisendeid kasutatakse kogu disaini skaleerimiseks. Seda kiipi vajame mitte ainult mikrokontrolleri hõivatud tihvtide arvu vähendamiseks, vaid ka ohutuse tagamiseks - et mitte kogemata sisse lülitada rohkem LED-e kui võimalik ja mitte põletada MK-d. Kiip maksab senti, seda tuleks alati kodus esmaabikomplektis hoida.

CD74HC238 vastutab soovitud LED-i anoodi pinge andmise eest. Täisväärtuslikus multipleksis annaks see P-MOSFET-i kaudu kolonni pinget, kuid selles demos saate seda teha otse, sest. see tõmbab vastavalt 20mA absoluutsed maksimumhinnangud andmelehel. Alates andmeleht CD74HC238 vajame pinouti ja seda petulehte:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
H = kõrge pinge tase, L = madalpinge tase, X - ei huvita

Ühendame E2 ja E1 maandusega, E3, A0, A1 ja A3 STM5 kontaktidega PD3, PC4, PC5 ja PC8. Kuna ülaltoodud tabel sisaldab nii madalaid kui ka kõrgeid tasemeid, seadistasime need tihvtid push-pull tihvtidena.

PWM

Teise taimeriga PWM on konfigureeritud samamoodi nagu eelmises loos, kahe erinevusega:

Esiteks peame lubama katkestuse Värskenda sündmust (UEV), mis kutsub välja funktsiooni aktiivse LED-i ümberlülitamiseks. Seda tehakse biti muutmisega Värskenda katkestuse lubamine kõneleva nimega registris

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
Katkestuse lubamise register

#define TIM2_IER   *(volatile uint8_t *)0x005303

//enable interrupt
TIM2_IER = 1;

Teine erinevus on seotud sellise multipleksimise nähtusega nagu ghosting - dioodide parasiitne sära. Meie puhul võib see ilmneda sellest, et UEV-s katkestuse tekitanud taimer tiksub edasi ja katkestuste töötlejal pole aega LED-i enne vahetada, kui taimer hakkab midagi väljunditesse kirjutama. Selle vastu võitlemiseks peate loogika ümber pöörama (0 = maksimaalne heledus, 255 = midagi pole sisse lülitatud) ja mitte lubama äärmuslikke töötsükli väärtusi. Need. tagage, et pärast UEV-d on LED-id täielikult kustunud üheks PWM-tsükliks.

Polaarsuse muutmine:

//set polarity 
    TIM2_CCER1 |= (CC1P | CC2P);
    TIM2_CCER2 |= CC3P;

Vältige väärtuste r, g ja b seadmist väärtusele 255 ning ärge unustage neid kasutamise ajal ümber pöörata.

Katkestab

Katkestuse olemus seisneb selles, et teatud asjaoludel lõpetab kiip põhiprogrammi täitmise ja kutsub välja mõne välise funktsiooni. Katkestused tekivad väliste või sisemiste mõjude, sealhulgas taimeri mõju tõttu.

Kui me esimest korda ST Visual Developi projekti lõime, välja arvatud main.c saime akna salapärase failiga stm8_interrupt_vector.cautomaatselt projekti kaasatud. Selles failis on igale katkestusele lisatud funktsioon NonHandledInterrupt. Peame oma funktsiooni siduma soovitud katkestusega.

Andmelehel on katkestusvektorite tabel, kust leiame need, mida vajame:

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s
13 TIM2 värskendus/ületäitmine
14 TIM2 jäädvustamine/võrdlemine

Peame UEV-s LED-i vahetama, seega on vaja katkestust nr 13.

Seega esiteks toimikus stm8_interrupt_vector.c muutke katkestuse numbri 13 (IRQ13) eest vastutava funktsiooni nimi vaikimisi meie omaks:

{0x82, TIM2_Overflow}, /* irq13 */

Teiseks peame looma faili main.h sisu selline:

#ifndef __MAIN_H
#define __MAIN_H

@far @interrupt void TIM2_Overflow (void);
#endif

Ja lõpuks kirjutage see funktsioon oma sisse main.c:

@far @interrupt void TIM2_Overflow (void)
{
    PD_ODR &= ~(1<<5); // вырубаем демультиплексор
    PC_ODR = (cnt<<3); // записываем в демультиплексор новое значение
    PD_ODR |= (1<<5); // включаем демультиплексор

    TIM2_SR1 = 0; // сбрасываем флаг Update Interrupt Pending

    cnt++; 
    cnt &= 7; // двигаем счетчик LED

    TIM2_CCR1L = ~colors[cnt][0]; // передаем в буфер инвертированные значения
    TIM2_CCR2L = ~colors[cnt][1]; // для следующего цикла ШИМ
    TIM2_CCR3L = ~colors[cnt][2]; // 

    return;
}

Järele jääb katkestuste lubamine. Seda tehakse käsuga assembler. rim - peate selle sealt otsima Programmeerimisjuhend:

//enable interrupts
_asm("rim");

Veel üks monteerija juhend - sim - Lülitab katkestused välja. Uute väärtuste "videomällu" kirjutamise ajal tuleb need keelata, et kahetsusväärsel hetkel tekkinud katkestus massiivi ei rikuks.

Kogu kood - Githubis.

Lugege andmelehti 2: SPI STM32-l; PWM, taimerid ja katkestused STM8-s

Kui vähemalt kellelegi on see artikkel kasulik, siis ma ei kirjutanud seda asjata. Mul on hea meel kommentaaride ja märkuste vastu, proovin vastata kõigile.

Allikas: www.habr.com

Lisa kommentaar