ProHoster > Blog > internet nuus > Lees datablaaie 2: SPI op STM32; PWM, timers en onderbrekings op STM8
Lees datablaaie 2: SPI op STM32; PWM, timers en onderbrekings op STM8
В die eerste deel Ek het probeer om stokperdjie-elektronika-ingenieurs wat uit Arduino-broeke gegroei het, te vertel hoe en hoekom hulle datablaaie en ander dokumentasie vir mikrobeheerders moet lees. Die teks blyk groot te wees, so ek het belowe om praktiese voorbeelde in 'n aparte artikel te wys. Wel, hy het homself 'n laaier genoem ...
Vandag sal ek jou wys hoe om datablaaie te gebruik om redelik eenvoudige, maar noodsaaklike take vir baie projekte op STM32 (Blue Pill) en STM8-beheerders op te los. Alle demonstrasieprojekte is opgedra aan my gunsteling LED's, ons sal hulle in groot hoeveelhede verlig, waarvoor ons allerhande interessante randapparatuur sal moet gebruik.
Die teks het weer groot geblyk te wees, so gerieflikheidshalwe maak ek die inhoud:
Vrywaring: Ek is nie 'n ingenieur nie, ek gee nie voor dat ek diep kennis in elektronika het nie, die artikel is bedoel vir amateurs soos ek. Trouens, ek het myself twee jaar gelede as die teikengehoor beskou. As iemand toe vir my gesê het dat dit nie skrikwekkend is om datablaaie vir 'n onbekende skyfie te lees nie, sou ek nie baie tyd spandeer het om 'n paar stukkies kode op die internet te soek en krukke met 'n skêr en kleefpleister uit te vind nie.
Die fokus van hierdie artikel is datablaaie, nie konsepte nie, so die kode is dalk nie te gepoleer nie en dikwels 'n kruk. Die projekte self is baie eenvoudig, hoewel hulle geskik is vir die eerste kennismaking met 'n nuwe skyfie.
Ek hoop dat my artikel iemand in 'n soortgelyke stadium van 'n stokperdjie sal help.
STM32
16 LED's met DM634 en SPI
Klein projek met Blue Pill (STM32F103C8T6) en DM634 LED-bestuurder. Met behulp van datablaaie sal ons die bestuurder, STM IO-poorte hanteer en SPI konfigureer.
DM634
Taiwanese skyfie met 16 x 16-bis PWM-uitsette, kan vasgeketting word. Die jonger 12-bis-model is bekend van 'n huishoudelike projek ligte pak. Op 'n tyd, deur te kies tussen DM63x en die bekende TLC5940, het ek om verskeie redes op DM besluit: 1) TLC op Aliexpress is beslis vals, maar hierdie een is nie; 2) DM het 'n outonome PWM met sy eie frekwensiegenerator; 3) dit kan goedkoop in Moskou gekoop word, en nie wag vir 'n pakkie van Ali nie. En natuurlik was dit interessant om te leer hoe om die skyfie self te beheer, en nie 'n klaargemaakte biblioteek te gebruik nie. Skyfies word nou hoofsaaklik in die SSOP24-pakket aangebied, dit is maklik om op die adapter te soldeer.
Aangesien die vervaardiger Taiwanees is, datablad na die skyfie is in Chinees Engels geskryf, wat beteken dit sal pret wees. Kyk eers na die pinoutPenverbinding) om te verstaan watter been om wat te verbind, en 'n beskrywing van die penne (Speldbeskrywing). 16 penne:
Sink DC bronne (oop drein)
Wasbak / Oopdrein-uitset - voorraad; bron van inkomende stroom; 'n uitset gekoppel aan grond in 'n aktiewe toestand - LED's word deur katodes aan die drywer gekoppel. Elektries is dit natuurlik geen "oop drein" (oop drein), maar in datablaaie word so 'n benaming vir uitsette in dreineermodus dikwels gevind.
Eksterne weerstande tussen REXT en GND om die uitsetstroomwaarde in te stel
'n Verwysingsweerstand word tussen die REXT-pen en grond geïnstalleer, wat die interne weerstand van die uitsette beheer, sien die grafiek op bladsy 9 van die datablad. In die DM634 kan hierdie weerstand ook deur sagteware beheer word deur die algehele helderheid (globale helderheid); Ek gaan nie in hierdie artikel in op besonderhede nie, ek sal net 'n 2.2 - 3 kOhm-weerstand hier plaas.
Om te verstaan hoe om die skyfie te beheer, kom ons kyk na die beskrywing van die toestelkoppelvlak:
Ja, hier is dit, Chinese Engels in al sy glorie. Dit is problematies om dit te vertaal, jy kan dit verstaan as jy wil, maar daar is 'n ander manier - om te kyk hoe die verbinding in die datablad na die funksioneel naby TLC5940 beskryf word:
… Slegs drie penne word benodig om data in die toestel in te voer. Die stygende rand van die SCLK-sein skuif die data van die SIN-pen na die interne register. Nadat alle data gelaai is, grendel 'n kort hoë XLAT-sein die serie-oorgedra data in interne registers. Interne registers is hekke wat deur die XLAT seinvlak geaktiveer word. Alle data word MSB eerste versend.
Grendel - grendel / grendel / grendel. Stygende rand is die voorpunt van die pols MSB eerste – die mees betekenisvolle (mees links) bietjie vorentoe. om data te klok – versend data opeenvolgend (bietjie vir bietjie).
Woord grendel word dikwels in die dokumentasie vir skyfies gevind en word op 'n verskeidenheid maniere vertaal, so vir begrip sal ek myself toelaat
klein opvoedkundige programDie LED-bestuurder is in wese 'n skuifregister. "Shift" (skuif) in die naam - bietjie-vir-bietjie beweging van data binne die toestel: elke nuwe bietjie wat binne gedruk word, stoot die hele ketting vorentoe voor dit. Aangesien niemand die chaotiese flikkering van LED's tydens die skof wil waarneem nie, vind die proses plaas in bufferregisters wat van die werkers geskei is deur 'n sluiter (grendel) is 'n soort kleedkamer waar die stukkies in die verlangde volgorde in lyn is. Wanneer alles gereed is, gaan die sluiter oop en die stukkies gaan aan die werk en vervang die vorige bondel. Woord grendel in die dokumentasie vir mikrobane impliseer byna altyd so 'n demper, in watter kombinasies dit ook al gebruik word.
Dus, data-oordrag na DM634 word soos volg uitgevoer: stel die DAI-invoer in op die waarde van die hoë bietjie van die verre LED, trek DCK op en af; stel die DAI-invoer na die waarde van die volgende bietjie, trek DCK; en so aan totdat alle stukkies oorgedra is (ingeklok het), waarna ons LAT trek. Dit kan met die hand gedoen wordbietjie bang), maar dit is beter om die spesiaal skerpgemaakte SPI-koppelvlak hiervoor te gebruik, aangesien dit in twee kopieë op ons STM32 aangebied word.
Blou Tablet STM32F103
Inleidend: STM32-beheerders is baie meer ingewikkeld as Atmega328 as wat hulle skrikwekkend kan wees. Terselfdertyd, vir redes van energiebesparing, is byna alle randapparatuur aan die begin gedeaktiveer, en die klokfrekwensie is 8 MHz vanaf 'n interne bron. Gelukkig het die STM-programmeerders 'n kode geskryf wat die skyfie na die "berekende" 72 MHz bring, en die skrywers van al die IDE's wat ek ken het dit by die inisialiseringsprosedure ingesluit, so ons hoef nie te klok nie (maar jy kan as jy regtig wil). Maar jy moet die randapparatuur aanskakel.
Dokumentasie: Die gewilde STM32F103C8T6-skyfie is op Blue Pill geïnstalleer, daar is twee nuttige dokumente daarvoor:
Data Sheet vir mikrobeheerders STM32F103x8 en STM32F103xB;
Pinouts - chip pinouts - ingeval ons besluit om self borde te maak;
Memory Map - 'n geheue kaart vir 'n spesifieke chip. Die naslaanhandleiding het 'n kaart vir die hele lyn, dit noem registers wat nie op ons s'n is nie.
Pendefinisiestabel - 'n lys van die hoof- en alternatiewe penfunksies; vir die "blou pil" op die internet kan jy geriefliker prente vind met 'n lys penne en hul funksies. Daarom google ons dadelik Blue Pill pinout en hou hierdie prentjie byderhand:
NB: daar was 'n fout in die prentjie vanaf die internet, opgemerk in die kommentaar, waarvoor dankie. Die prentjie is vervang, maar dit is 'n les - dit is beter om inligting na te gaan, nie uit datablaaie nie.
Ons verwyder die datablad, maak die Verwysingshandleiding oop, van nou af gebruik ons net dit.
Prosedure: hanteer standaard insette / uitvoer, stel SPI in, skakel die nodige randapparatuur aan.
Invoer Uitset
Op die Atmega328 is I/O uiters eenvoudig, en daarom kan die oorvloed STM32-opsies verwarrend wees. Nou het ons net gevolgtrekkings nodig, maar selfs daar is vier opsies:
"Trek druk" (stoot trek) - die gewone uitset van die Arduino, die pen kan óf HOOG óf LAAG wees. Maar met die "oop drein" ontstaan probleme, hoewel alles hier eintlik eenvoudig is:
Uitsetkonfigurasie / wanneer poort aan uitset toegewys is: / uitsetbuffer geaktiveer: / – oop dreinmodus: "0" in die uitsetregister aktiveer N-MOS, "1" in die uitsetregister verlaat die poort in Hi-Z-modus (P -MOS is nie geaktiveer nie ) / - druk-trek-modus: "0" in die uitsetregister aktiveer N-MOS, "1" in die uitsetregister aktiveer P-MOS.
Alle oop drein verskil (oop drein) van "druk-trek" (stoot trek) is dat dit in die eerste pen nie die HOOG-toestand kan neem nie: wanneer 'n eenheid na die uitsetregister geskryf word, gaan dit in hoë weerstandmodus (hoë impedansie, Hi-Z). Wanneer nul geskryf word, gedra die pen in beide modusse dieselfde, beide logies en elektries.
In normale uitsetmodus vertaal die pen eenvoudig die inhoud van die uitsetregister. In "alternatief" word dit beheer deur die ooreenstemmende randapparaat (sien 9.1.4):
As die poortbis gekonfigureer is as 'n alternatiewe funksie-uitset, word die uitsetregister gedeaktiveer en die pen is gekoppel aan die uitsetsein van die randapparaat.
Die alternatiewe funksionaliteit van elke pen word beskryf in Spelddefinisies Die datablad is op die afgelaaide prent. Op die vraag wat om te doen as die pen verskeie alternatiewe funksies het, word die antwoord gegee deur 'n voetnoot in die datablad:
As veelvuldige randapparatuur dieselfde pen gebruik, om konflik tussen alternatiewe funksies te vermy, moet slegs een randapparaat op 'n slag gebruik word, met behulp van die Periferal Clock Enable-bis (in die ooreenstemmende RCC-register).
Laastens het penne in uitsetmodus ook 'n klokspoed. Dit is nog 'n energiebesparende kenmerk, in ons geval stel ons dit net op die maksimum en vergeet dit.
Dus: ons gebruik SPI, wat beteken dat twee penne (met data en met 'n kloksein) "alternatiewe druk-trek-funksie" moet wees, en nog een (LAT) moet "normale druk-trek" wees. Maar voordat ons hulle toewys, kom ons gaan met SPI.
SPI
Nog 'n klein hack
SPI of Serial Peripheral Interface (seriële perifere koppelvlak) is 'n eenvoudige en baie effektiewe koppelvlak om MK met ander MK's en die buitewêreld in die algemeen te kommunikeer. Die beginsel van sy werking is reeds hierbo beskryf, waar oor die Chinese LED-bestuurder (sien afdeling 25 in die verwysingshandleiding). SPI kan in meester ("meester") en slaaf ("slaaf") modus werk. SPI het vier basiese kanale, waarvan nie almal betrokke mag wees nie:
MOSI, Meester Uitset / Slaaf Invoer: hierdie pen stuur data in Meester af, en ontvang data in slaaf af;
MISO, Meester Invoer / Slawe Uitset: inteendeel, in die meester wat dit ontvang, in die slaaf wat dit gee;
SCK, Serial Clock: stel die frekwensie van data-oordrag in die meester of ontvang 'n kloksein in die slaaf. In wese, klop die slae;
SS, Slave Select: met hierdie kanaal weet die slaaf dat hulle iets van hom wil hê. Op STM32 word dit NSS genoem, waar N = negatief, d.w.s. die beheerder word 'n slaaf as hierdie kanaal 'n grond het. Dit kombineer goed met die Open Drain Output-modus, maar dit is 'n ander storie.
Soos alles anders, is SPI op STM32 ryk aan funksionaliteit, wat dit ietwat moeilik maak om te verstaan. Byvoorbeeld, dit kan nie net met SPI werk nie, maar ook met 'n I2S-koppelvlak, en hul beskrywings word in die dokumentasie gemeng, u moet die oorskot betyds afsny. Ons taak is uiters eenvoudig: jy hoef net data te gee deur slegs MOSI en SCK te gebruik. Ons gaan na afdeling 25.3.4 (halfdupleks kommunikasie, halfdupleks kommunikasie), waar ons vind 1 horlosie en 1 eenrigting datadraad (1 horlosie en 1 eenrigting datastroom):
In hierdie modus gebruik die toepassing SPI in óf slegs versend óf slegs ontvang modus. / Die versend-alleen-modus is soortgelyk aan dupleksmodus: data word oorgedra op die versendingpen (MOSI in meestermodus of MISO in slaafmodus), terwyl die ontvangpen (MISO of MOSI onderskeidelik) as 'n normale I/O gebruik kan word speld. In hierdie geval is dit genoeg dat die toepassing die Rx-buffer ignoreer (as dit gelees word, sal daar geen data oorgedra word nie).
Groot, die MISO-pen is gratis, kom ons koppel die LAT-sein daaraan. Kom ons hanteer Slave Select, wat programmaties op STM32 beheer kan word, wat uiters gerieflik is. Ons lees die gelyknamige paragraaf in afdeling 25.3.1 SPI Algemene Beskrywing:
NSS sagteware beheer (SSM = 1) / Slaaf seleksie inligting is vervat in die SSI bis van die SPI_CR1 register. Die eksterne NSS-pen word vry gelaat vir ander toepassingsbehoeftes.
Dit is tyd om aan die registers te skryf. Ek het besluit om SPI2 te gebruik, ons soek sy basisadres in die datablad - in afdeling 3.3 Memory Map (Memory Map):
Ons maak afdeling 25.3.3 oop met die veelseggende titel "Configuring SPI in master mode":
1. Stel die seriële koppelvlakklok met die BR[2:0] bisse in die SPI_CR1 register.
Die registers word in die verwysingshandleiding-afdeling met dieselfde naam versamel. Adres verskuiwing (adres verreken) CR1 het 0x00, by verstek word alle bisse skoongemaak (Stel waarde terug 0x0000):
Die BR bisse stel die kontroleerder klokverdeler, en bepaal dus die frekwensie waarteen die SPI sal werk. Die STM32-frekwensie sal 72 MHz wees, die LED-drywer, volgens sy datablad, werk teen 'n frekwensie van tot 25 MHz, so ons moet deur vier deel (BR[2:0] = 001).
2. Stel die CPOL en CPHA bisse om die verhouding tussen data-oordrag en seriële koppelvlakklok te definieer (sien diagram op bladsy 240)
Aangesien ons 'n datablad hier lees en nie na skematiese kyk nie, kom ons kyk noukeuriger na die tekstuele beskrywing van die CPOL en CPHA stukkies op bladsy 704 (SPI Algemene Beskrywing):
Klokfase en polariteit
Deur die CPOL- en CPHA-bisse van die SPI_CR1-register te gebruik, kan jy vier opsies vir tydsberekeningsverhoudings programmaties kies. Die CPOL (Klokpolariteit)-bis beheer die toestand van die kloksein wanneer geen data versend word nie. Hierdie bietjie beheer meester- en slaafmodusse. As CPOL teruggestel word, is die SCK-pen laag in rus. As die CPOL-bis ingestel is, is die SCK-pen hoog wanneer dit ledig is.
As die CPHA (Klokfase)-bis ingestel is, is die MSB-vangstrobe die tweede rand van die SCK-sein (val as CPOL skoongemaak word, of stygende rand as CPOL gestel is). Die data word vasgemaak met die tweede klokverandering. As die CPHA-bis skoongemaak word, is die hoë-bis-vangerstrobe die stygende rand van die SCK-sein (val as CPOL gestel is, of stygende flank as CPOL duidelik is). Data word vasgemaak met die eerste klokverandering.
Nadat ons hierdie kennis geproe het, kom ons tot die gevolgtrekking dat beide stukkies nul moet bly, want ons wil hê dat die SCK-sein laag moet bly wanneer dit nie gebruik word nie, en dat data op die stygende rand van die pols gestuur word (sien fig. stygende rand in datablad DM634).
Terloops, hier het ons die eerste keer 'n kenmerk van die woordeskat in die ST-datablaaie teëgekom: daarin word die frase "terugstel die bietjie na nul" geskryf om 'n bietjie terug te stelen nie bietjie skoon te maak, soos byvoorbeeld Atmega.
3. Stel die DFF-bis om die 8-bis of 16-bis datablokformaat te bepaal
Ek het spesifiek die 16-bis DM634 geneem om nie te pla met die oordrag van 12-bis PWM data, soos die DM633 nie. DFF maak sin om in eenheid te sit:
4. Konfigureer die LSBFIRST-bis in die SPI_CR1-register om die blokformaat te definieer
LSBFIRST, soos sy naam aandui, stel die transmissie op met die minste beduidende bietjie eerste. Maar die DM634 wil eers data MSB ontvang. Daarom laat ons dit herstel.
5. In hardeware-modus, as invoer vanaf die NSS-pen vereis word, ry die NSS-pen hoog tydens die hele greepoordragvolgorde. In NSS program af, stel die SSM en SSI bisse in die SPI_CR1 register. As die NSS-pen uitgevoer moet word, hoef slegs die SSOE-bis ingestel te word.
Installeer SSM en SSI om van NSS-hardewaremodus te vergeet:
#define SSI 0x0100
#define SSM 0x0200
_SPI2_ (_SPI_CR1) |= SSM | SSI; //enable software control of SS, SS high
6. Die MSTR en SPE bisse moet gestel word (hulle bly net gestel as die NSS hoog is)
Eintlik, met hierdie stukkies ken ons ons SPI as 'n meester toe en skakel dit aan:
SPI is gekonfigureer, kom ons skryf onmiddellik funksies wat grepe na die bestuurder stuur. Lees verder 25.3.3 "Konfigureer SPI in Meestermodus":
Data oordrag bestelling
Die oordrag begin wanneer 'n greep na die Tx-buffer geskryf word.
Die datagreep word in die skuifregister gelaai by parallel modus (vanaf die interne bus) tydens die oordrag van die eerste bis, waarna dit in gestuur word konsekwent MOSI-penmodus, eerste of laaste bietjie vorentoe afhangende van die instelling van die LSBFIRST-bis in die CPI_CR1-register. TXE-vlag word gestel na data-oordrag van Tx buffer na skuifregister, en 'n onderbreking word gegenereer as die TXEIE-bis in die CPI_CR1-register gestel is.
Ek het 'n paar woorde in die vertaling uitgelig om die aandag te vestig op een kenmerk van die implementering van SPI in STM-beheerders. Op die Atmega, die TXE vlag (Tx Leeg, Tx is leeg en gereed om data te ontvang) word eers gestel nadat die hele greep gestuur is uiterlik. En hier word hierdie vlag gestel nadat die greep in die interne skuifregister ingedruk is. Aangesien dit met al die bisse gelyktydig (in parallel) daarheen gestoot word en dan die data opeenvolgend versend word, word TXE gestel voordat die greep heeltemal gestuur word. Dit is belangrik omdat in die geval van ons LED-bestuurder, moet ons die LAT-pen trek nadat ons gestuur is alle data, d.w.s. net die TXE-vlag sal nie vir ons genoeg wees nie.
Wat beteken ons het nog 'n vlag nodig. Kom ons kyk na 25.3.7 - "Statusvlae":
<…>
BESIGE vlag
Die BSY-vlag word deur hardeware gestel en skoongemaak (om daarna te skryf het geen effek nie). Die BSY-vlag dui die toestand van die SPI-kommunikasielaag aan.
Dit herstel:
wanneer die oordrag voltooi is (behalwe in meestermodus as die oordrag deurlopend is)
wanneer SPI gedeaktiveer is
wanneer 'n meestermodusfout voorkom (MODF=1)
As die oordrag nie deurlopend is nie, word die BSY-vlag tussen elke data-oordrag skoongemaak.
Goed, dit sal handig te pas kom. Vind uit waar die Tx-buffer geleë is. Om dit te doen, lees die "SPI Data Register":
Bits 15:0 DR[15:0] Dataregister
Data ontvang of data wat oorgedra moet word.
Die dataregister word in twee buffers verdeel, een vir skryf (stuurbuffer) en een vir lees (ontvangbuffer). 'n Skryf na die dataregister skryf na die Tx-buffer, en 'n lees vanaf die dataregister sal die waarde terugstuur wat in die Rx-buffer vervat is.
Wel, die statusregister, waar daar TXE- en BSY-vlae is:
Wel, aangesien ons 16 keer twee grepe moet oordra, volgens die aantal uitsette van die LED-bestuurder, iets soos hierdie:
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();
}
Maar ons weet nog nie hoe om die LAT-pen te trek nie, so kom ons gaan terug na I/O.
Ken penne toe
In STM32F1 is die registers wat verantwoordelik is vir die toestand van die penne nogal ongewoon. Dit is duidelik dat daar meer van hulle as Atmega is, maar hulle verskil ook van ander STM-skyfies. Afdeling 9.1 GPIO Algemene beskrywing:
Elk van die algemene I/O-poorte (GPIO) het twee 32-bis konfigurasieregisters (GPIOx_CRL en GPIOx_CRH), twee 32-bis dataregisters (GPIOx_IDR en GPIOx_ODR), 'n 32-bis stel/terugstel register (GPIOx_BSRR), 'n 16-bis terugstel register (GPIOx_BRR) en 'n 32- bietjie blokkeer register (GPIOx_LCKR).
Ongewoon, en ook taamlik ongerieflik, is die eerste twee registers hier, want die 16 penne van die poort is oor hulle gestrooi in 'n "vier stukkies per broer"-formaat. Dié. penne XNUMX tot XNUMX is in CRL, en die res is in CRH. Terselfdertyd pas die oorblywende registers suksesvol die stukkies van al die poortpennetjies - dikwels bly die helfte "gereserveer".
Kom ons begin vir eenvoud aan die einde van die lys.
Ons het nie 'n blokkeerregister nodig nie.
Die stel- en terugstelregisters is nogal snaaks omdat hulle mekaar gedeeltelik dupliseer: jy kan alles net in BSRR skryf, waar die boonste 16 bisse die pen na nul sal terugstel, en die onderste op 1 gestel sal wees, of jy kan ook gebruik BRR, waarvan die onderste 16 bisse net die pen terugstel. Ek hou van die tweede opsie. Hierdie registers is belangrik omdat hulle atoomtoegang tot die penne bied:
Atoom installeer of herstel
Jy hoef nie onderbrekings te deaktiveer wanneer jy GPIOx_ODR op die bisvlak programmeer nie: jy kan een of meer bisse verander met 'n enkele APB2 atoomskryfbewerking. Dit word bereik deur 'n "1" te skryf na die stel/terugstel register (GPIOx_BSRR of, slegs vir terugstelling, GPIOx_BRR) van die bis wat verander moet word. Ander stukkies sal onveranderd bly.
Dataregisters het nogal sprekende name - IDR = insette Rigtingregister, invoerregister; ODR= Uitgawe Rigtingregister, uitsetregister. In die huidige projek het ons hulle nie nodig nie.
En uiteindelik registreer die beheer. Aangesien ons belangstel in die penne van die tweede SPI, naamlik PB13, PB14 en PB15, kyk ons dadelik na CRH:
En ons sien dat dit nodig sal wees om iets in stukkies van die 20ste tot die 31ste te skryf.
Ons het reeds uit die penne hierbo uitgepluis wat ons wil hê, so hier sal ek sonder 'n kiekie doen, net sê dat MODE die rigting stel (invoer as beide bisse op 0 gestel is) en die spoed van die pen (ons benodig 50MHz, d.w.s. beide pen na "1"), en CNF stel die modus: normale "druk-druk" - 00, "alternatief" - 10. By verstek, soos ons hierbo kan sien, het alle penne die derde bietjie van onder ( CNF0), stel dit hulle in modus drywende insette.
Aangesien ek van plan is om iets anders met hierdie skyfie te doen, vir eenvoud, het ek oor die algemeen alle moontlike MODE- en CNF-waardes vir beide die onderste en boonste beheerregisters gedefinieer.
(LAT_low net deur traagheid, op een of ander manier was dit altyd, laat dit vir jouself bly)
Nou is alles wonderlik, dit werk net nie. Omdat dit STM32 is, bespaar hulle elektrisiteit hier, wat beteken dat jy die klok van die nodige randapparatuur moet aanskakel.
Skakel klok aan
Die horlosie is verantwoordelik vir klok, hulle is ook Klok. En ons kon reeds die afkorting RCC opmerk. Ons soek dit in die dokumentasie: dit is Herstel en Klokbeheer (Bestuur van herstel en klok).
Soos hierbo genoem, het die mense van STM gelukkig die moeilikste deel van die klokonderwerp vir ons gedoen, waarvoor baie dankie aan hulle (ek sal weer 'n skakel gee na Di Halt se webwerfom dit duidelik te maak hoe verward dit is). Ons benodig slegs registers wat verantwoordelik is vir die aktivering van perifere klok (Periferal Clock Enable Registers). Kom ons soek eers die basisadres van die RCC, dit is heel aan die begin van die "Geheuekaart":
En klik dan óf op die skakel waar om iets in die tabel te probeer vind, óf, veel beter, gaan oor die beskrywings van die insluitende registers uit die afdelings oor aktiveer registers. Waar vind ons RCC_APB1ENR en RCC_APB2ENR:
En in hulle, onderskeidelik, stukkies wat die klok van SPI2, IOPB (I / O Port B) en alternatiewe funksies (AFIO) insluit.
As daar 'n geleentheid en begeerte is om te toets, dan verbind ons DM634 so: DAI na PB15, DCK na PB13, LAT na PB14. Ons voed die bestuurder van 5 volt, moenie vergeet om die gronde te kombineer nie.
STM8 PWM
PWM op STM8
Toe ek net hierdie artikel beplan het, het ek byvoorbeeld besluit om die een of ander funksionaliteit van 'n onbekende skyfie met behulp van slegs 'n datablad te probeer bemeester, sodat 'n skoenmaker nie sonder stewels sou uitkom nie. STM8 was perfek vir hierdie rol: eerstens het ek 'n paar Chinese borde met STM8S103 gehad, en tweedens is dit nie baie gewild nie, en daarom berus die versoeking om te lees en 'n oplossing op die internet te vind op die afwesigheid van dieselfde oplossings.
By verstek werk STM8 teen 'n frekwensie van 2 MHz, dit moet onmiddellik reggestel word.
HSI-klok (hoë intern)
Die HSI-klok is afgelei van 'n interne 16 MHz RC-ossillator met 'n programmeerbare verdeler (1 tot 8). Dit word in die klokverdelerregister (CLK_CKDIVR) ingestel.
Let wel: HSI RC-ossillator met 'n verdeler van 8 word gekies as die hoofklokbron by opstart.
Ons vind die adres van die register in die datablad, die beskrywing in refman en sien dat die register skoongemaak moet word:
Aangesien ons PWM gaan laat loop en LED's gaan koppel, kom ons kyk na die pinout:
Die skyfie is klein, baie funksies is op dieselfde penne opgeskort. Wat tussen vierkantige hakies is, is "alternatiewe funksionaliteit", dit word omgeskakel deur "opsiegrepe" (opsie grepe) - iets soos Atmega versmelt. U kan hul waardes programmaties verander, maar dit is nie nodig nie, want. Die nuwe funksionaliteit word eers geaktiveer na 'n herlaai. Dit is makliker om ST Visual Programmer (afgelaai met Visual Develop) te gebruik, wat hierdie grepe kan verander. Die pinout wys dat die uitsette CH1 en CH2 van die eerste timer tussen vierkantige hakies versteek is; dit is nodig om die AFR1 en AFR0 bisse in STVP te stel, en die tweede een sal ook die uitset CH1 van die tweede timer van PD4 na PC5 oordra.
Dus, 6 penne sal die LED's beheer: PC6, PC7 en PC3 vir die eerste timer, PC5, PD3 en PA3 vir die tweede.
Die opstel van die I/O-penne self op die STM8 is eenvoudiger en meer logies as op die STM32:
die eerste beheerregister CR1 stel die druk-trek-modus (1) of oop drein (0) wanneer dit uitgegee word; aangesien ek die LED's met katodes aan die skyfie koppel, laat ek nulle hier;
die tweede beheerregister CR2 stel die klokspoed in wanneer dit uitgestuur word: 1 = 10 MHz
PWM Frekwensie – frekwensie waarmee die timer tik;
Outo-herlaai, AR - outo-gelaaide waarde, tot wat die timer sal tel (pulsperiode);
Dateer gebeurtenis, UEV – 'n gebeurtenis wat plaasvind wanneer die timer tot AR getel het;
PWM-dienssiklus - PWM dienssiklus, dikwels genoem "dienssiklus";
Vang/Vergelyk waarde – waarde om vas te vang/vergelyk, tel tot waar die timer iets sal doen (in die geval van PWM, keer dit die uitsetsein om);
vooraflaai waarde - voorafgelaaide waarde. waarde vergelyk kan nie verander terwyl die timer tik nie, anders sal die PWM-siklus breek. Daarom word nuwe oorgedra waardes in die buffer geplaas en uitgetrek wanneer die timer die einde van die aftelling bereik en teruggestel word;
Randbelyn и Middelgerigte modusse – belyning op die grens en in die middel, dieselfde as atmelovskie Vinnige PWM и Fase-korrekte PWM.
OCiREF, Uitset Vergelyk Verwysing Sein - die verwysingsuitsetsein, in werklikheid, wat op die ooreenstemmende pen in PWM-modus verskyn.
Soos reeds duidelik uit die pinout is, het twee timers PWM-vermoëns - die eerste en tweede. Albei is 16-bis, die eerste een het baie bykomende kenmerke (dit kan veral op en af tel). Ons moet albei op dieselfde manier werk, so ek het besluit om met die ooglopend swakker tweede een te begin, om nie per ongeluk iets te gebruik wat nie daarin is nie. Een of ander probleem is dat die beskrywing van die PWM-funksionaliteit van alle timers in die verwysingshandleiding in die hoofstuk oor die eerste timer (17.5.7 PWM-modus) is, so jy moet heeltyd heen en weer deur die dokument spring.
PWM op STM8 het 'n belangrike voordeel bo Atmega PWM:
PWM met randbelyning
Rekeningkonfigurasie van onder na bo
Optelling is aktief as die DIR-bis in die TIM_CR1-register duidelik is
Voorbeeld
Die voorbeeld gebruik die eerste PWM-modus. Die PWM verwysingsein OCiREF word hoog gehou solank TIM1_CNT < TIM1_CCRi. Andersins neem dit 'n lae vlak. As die waarde om te vergelyk in die TIM1_CCRi-register groter is as die outolaaiwaarde (TIM1_ARR-register), word die OCiREF-sein op 1 gehou. As die vergelykingswaarde 0 is, word OCiREF op nul gehou....
STM8 timer tydens gebeurtenis opdateer tjeks eers waarde vergelyk, en produseer dan eers 'n verwysingsein. In Atmega bewe die timer eers, en vergelyk dan, as gevolg waarvan, wanneer compare value == 0 die uitset is 'n naald wat op een of ander manier hanteer moet word (byvoorbeeld deur die logika programmaties om te keer).
So wat ons wil doen: 8-bis PWM (AR == 255), tel van onder na bo, belyning langs die grens. Aangesien die gloeilampe met katodes aan die skyfie gekoppel is, behoort die PWM 0 uit te voer (LED aan) tot waarde vergelyk en 1 daarna.
Ons het al van sommige gelees PWM-modus, dus vind ons die gewenste register van die tweede timer deur te soek in die verwysingshandleiding vir hierdie frase (18.6.8 - TIMx_CCMR1):
110: Eerste PWM-modus - wanneer van onder na bo getel word, is die eerste kanaal aktief solank TIMx_CNT < TIMx_CCR1. Andersins is die eerste kanaal onaktief. [verder in die dokument, foutiewe kopieer-plak vanaf timer 1] 111: Tweede PWM-modus - wanneer van onder na bo getel word, is die eerste kanaal onaktief totdat TIMx_CNT < TIMx_CCR1. Andersins is die eerste kanaal aktief.
Aangesien die LED's met katodes aan die MK gekoppel is, pas die tweede modus ons (die eerste een ook, maar ons weet dit nog nie).
Bit 3 OC1PE: Aktiveer vooraflaai-uitset 1
0: Voorlaai register op TIMx_CCR1 gedeaktiveer. Jy kan enige tyd na TIMx_CCR1 skryf. Die nuwe waarde werk dadelik.
1: Voorlaai register op TIMx_CCR1 geaktiveer. Lees/skryf-bewerkings kry toegang tot die vooraflaairegister. Die voorafgelaaide waarde van TIMx_CCR1 word tydens elke opdateringsgebeurtenis in die skaduregister gelaai.
*Let wel: Voorlaairegisters moet geaktiveer wees vir PWM-modus om behoorlik te werk. Dit is opsioneel in enkelseinmodus (die OPM-bis word in die TIMx_CR1-register gestel).
Goed, skakel alles aan wat jy nodig het vir die drie kanale van die tweede timer:
Die tweede timer kan net van onder na bo tel, belyning op die grens, niks hoef verander te word nie. Stel die frekwensiedeler, byvoorbeeld, op 256. Vir die tweede timer word die deler in die TIM2_PSCR-register gestel en is 'n krag van twee:
Dit bly om die gevolgtrekkings en die tweede timer self aan te skakel. Die eerste taak word deur registers opgelos Vang/Vergelyk Aktiveer: daar is twee van hulle, drie kanale is asimmetries oor hulle gestrooi. Hier kan ons ook leer dat dit moontlik is om die polariteit van die sein te verander, m.a.w. in beginsel kan PWM-modus 1 ook gebruik word. Ons skryf:
Kom ons skryf 'n eenvoudige analoog van AnalogWrite (), wat die werklike waardes sal deurgee aan die timer vir vergelyking. Die registers word voorspelbaar benoem Vang/Vergelyk registers, daar is twee van hulle vir elke kanaal: die lae 8 bisse in TIM2_CCRxL en die hoë bisse in TIM2_CCRxH. Aangesien ons 8-bis PWM begin het, is dit genoeg om slegs die lae bisse te skryf:
Die aandagtige leser sal opmerk dat ons 'n effens defekte PWM het, nie in staat is om 100% vulling uit te gee nie (teen 'n maksimum waarde van 255 word die sein met een timersiklus omgekeer). Vir LED's speel dit nie 'n rol nie, en die aandagtige leser raai reeds hoe om dit reg te stel.
PWM op die tweede timer werk, gaan na die eerste.
Die eerste timer het presies dieselfde stukkies in dieselfde registers (dis net dat daardie stukkies wat in die tweede timer "gereserveer" gebly het, aktief gebruik word vir allerhande gevorderde dinge in die eerste). Daarom is dit genoeg om die adresse van dieselfde registers in die datablad te vind en die kode te kopieer. Wel, verander die waarde van die frekwensieverdeler, want. die eerste timer wil nie 'n krag van twee kry nie, maar 'n presiese 16-bis waarde in twee registers Prescaler High и Laagte. Ons doen alles en ... die eerste timer werk nie. Wats fout?
Die enigste manier om die probleem op te los is deur na die hele afdeling oor die beheerregisters van timer 1 te kyk, waar ons een soek wat die tweede timer nie het nie. daar sal wees 17.7.30 Pouseregister (TIM1_BKR), waar daar 'n bietjie soos hierdie is:
Die derde mini-projek is om agt RGB-LED's aan die tweede timer in PWM-modus te koppel en hulle verskillende kleure te laat vertoon. Dit is gebaseer op die konsep van LED-multipleksing, wat bestaan uit die feit dat as jy die LED's baie, baie vinnig aan- en afskakel, dit vir ons sal lyk asof hulle voortdurend aan is (volharding van visie, traagheid van visuele persepsie). Ek het eenkeer gedoen so iets op arduino.
Die algoritme van werk lyk soos volg:
verbind die anode van die eerste RGB LED;
het dit aangesteek en die nodige seine aan die katodes gegee;
gewag vir die einde van die PWM-siklus;
verbind die anode van die tweede RGB LED;
het dit aangesteek...
Wel, ens. Natuurlik, vir pragtige werk, is dit nodig dat die anodeverbinding en die "ontsteking" van die LED gelyktydig plaasvind. Wel, amper. In elk geval, ons moet 'n kode skryf wat waardes sal uitvoer in drie kanale van die tweede timer, dit sal verander wanneer UEV bereik word en terselfdertyd die tans aktiewe RGB LED verander.
Aangesien die LED-omskakeling outomaties is, moet jy "videogeheue" skep van waar die onderbrekingshanteerder data sal ontvang. Dit is 'n eenvoudige skikking:
uint8_t colors[8][3];
Om die kleur van 'n spesifieke LED te verander, sal dit genoeg wees om die nodige waardes in hierdie skikking te skryf. En die veranderlike sal verantwoordelik wees vir die nommer van die aktiewe LED
uint8_t cnt;
Demux
Vir behoorlike multipleksing benodig ons, vreemd genoeg, die CD74HC238 demultiplekser. Demultiplexer - 'n skyfie wat die operateur in hardeware implementeer <<. Deur drie invoerpennetjies (bis 0, 1 en 2) voer ons hom 'n drie-bis getal X, en in reaksie aktiveer hy die uitsetnommer (1<<X). Die oorblywende insette van die skyfie word gebruik om die hele ontwerp te skaal. Ons benodig hierdie skyfie nie net om die aantal besette penne van die mikrobeheerder te verminder nie, maar ook vir veiligheid - om nie per ongeluk meer LED's as moontlik aan te skakel en nie die MK te verbrand nie. Die skyfie kos 'n sent, dit moet altyd in die noodhulptassie by die huis gehou word.
CD74HC238 sal verantwoordelik wees vir die verskaffing van spanning aan die anode van die verlangde LED. In 'n volwaardige multipleks sal dit spanning aan die kolom verskaf deur die P-MOSFET, maar in hierdie demo kan jy dit direk doen, want. dit trek 20mA, volgens Absolute Maksimum Graderings in die datablad. Van datablad CD74HC238 ons benodig 'n pinout en hierdie cheat sheet:
H = hoë spanning vlak, L = lae spanning vlak, X - gee nie om nie
Ons koppel E2 en E1 aan grond, E3, A0, A1 en A3 aan penne PD5, PC3, PC4 en PC5 van STM8. Aangesien die tabel hierbo beide lae en hoë vlakke bevat, stel ons hierdie penne as druk-trekpennetjies op.
PWM
PWM op die tweede timer is op dieselfde manier gekonfigureer as in die vorige storie, met twee verskille:
Eerstens moet ons die onderbreking aktiveer Dateer gebeurtenis op (UEV) wat 'n funksie sal oproep om die aktiewe LED te skakel. Dit word gedoen deur die bietjie te verander Opdateer Onderbreking Aktiveer in 'n register met 'n spreeknaam
Die tweede verskil hou verband met so 'n verskynsel van multipleksing as Ghosting - parasitiese gloed van diodes. In ons geval kan dit voorkom as gevolg van die feit dat die timer, wat 'n onderbreking op die UEV veroorsaak het, aanhou tik, en die onderbrekingshanteerder het nie tyd om die LED te skakel voordat die timer iets na die uitsette begin skryf nie. Om dit te bekamp, sal jy die logika moet omkeer (0 = maksimum helderheid, 255 = niks is aan nie) en nie uiterste dienssikluswaardes toelaat nie. Dié. verseker dat na UEV die LED's heeltemal geblus is vir een PWM-siklus.
Vermy om r, g en b op 255 te stel en onthou om hulle om te keer wanneer jy gebruik.
Onderbreek
Die essensie van die onderbreking is dat die skyfie onder sekere omstandighede ophou om die hoofprogram uit te voer en een of ander eksterne funksie oproep. Onderbrekings vind plaas as gevolg van eksterne of interne invloede, insluitend vanaf die timer.
Toe ons die eerste keer 'n projek in ST Visual Develop geskep het, afgesien van main.c ons het 'n venster met 'n geheimsinnige lêer gekry stm8_interrupt_vector.coutomaties by die projek ingesluit. In hierdie lêer is 'n funksie aan elke onderbreking geheg NonHandledInterrupt. Ons moet ons funksie aan die verlangde onderbreking bind.
Die datablad het 'n tabel van onderbrekingsvektore, waar ons die een vind wat ons benodig:
Ons moet die LED by UEV verander, so onderbreking #13 is nodig.
Gevolglik, eerstens, in die lêer stm8_interrupt_vector.c verander die naam van die funksie verantwoordelik vir onderbreking nommer 13 (IRQ13) by verstek na ons eie:
{0x82, TIM2_Overflow}, /* irq13 */
Tweedens sal ons 'n lêer moet skep main.h inhoud soos hierdie:
@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;
}
Dit bly om onderbrekings moontlik te maak. Dit word gedoen met 'n samesteller-opdrag. rim - jy sal dit moet soek Programmeringshandleiding:
//enable interrupts
_asm("rim");
Nog 'n samesteller-instruksie - sim - Skakel onderbrekings af. Hulle moet gedeaktiveer word terwyl nuwe waardes na die "videogeheue" geskryf word sodat 'n onderbreking wat op 'n ongelukkige oomblik veroorsaak word, nie die skikking bederf nie.
As ten minste iemand wat hierdie artikel nuttig is, dan het ek dit nie verniet geskryf nie. Ek sal bly wees vir kommentaar en opmerkings, ek sal probeer om alles te beantwoord.