STM32, sériové rozhranie I2C. STM32, sériové rozhranie I2C Popis i2c rozhrania Stm32 pokračoval

Niekto má rád koláče, niekto nie.

Rozhranie i2c je široko rozšírené a používané. V stm32f4 sú až tri moduly, ktoré implementujú tento protokol.
Prirodzene, s plná podpora celá táto vec.

Práca s modulom je vo všeobecnosti rovnaká ako v iných ovládačoch: zadáte mu príkazy, on ich vykoná a oznámi výsledok:
I> Išli sme ŠTART.
S> Ok, poslal som to.
Ja> Super, pošlite adresu. Takto: 0xXX.
S> Ok, poslal som to. Bolo mi povedané, že ACK. Poďme ďalej.
Som stále nažive, dobre. Tu je číslo registra: 0xYY, - poďme.
S> Odoslané, prijaté ACK.
I> Teraz mu pošlite údaje, tu je bajt: 0xZZ.
S> Odoslaný, súhlasí s ďalšími: ACK.
Jeb na neho, ešte nie. Išli STOP.
S> Dobre.

A všetko je približne v tomto duchu.

IN tento ovládač i2c kolíky sú roztrúsené po portoch takto:
PB6: I2C1_SCL
PB7: I2C1_SDA

PB8: I2C1_SCL
PB9: I2C1_SDA

PB10: I2C2_SCL
PB11: I2C2_SDA

PA8: I2C3_SCL
PC9: I2C3_SDA
Vo všeobecnosti je vhodné pozrieť sa na pinout periférnych zariadení na strane 59.

Prekvapivo na prácu s i2c potrebujete všetky jeho registre, našťastie ich je málo:
I2C_CR1- príkazy do modulu na odosielanie príkazov/stavov a výber prevádzkových režimov;
I2C_CR2- nastavenie DMA a indikácia pracovnej frekvencie modulu (2-42 MHz);
I2C_OAR1- nastavenie adresy zariadenia (pre slave), veľkosti adresy (7 alebo 10 bitov);
I2C_OAR2- nastavenie adresy zariadenia (ak existujú dve adresy);
I2C_DR- register údajov;
I2C_SR1- register stavu modulu;
I2C_SR2- stavový register (podriadený, musí sa prečítať, ak sú v SR1 nastavené príznaky ADDR alebo STOPF);
I2C_CCR- nastavenie rýchlosti rozhrania;
I2C_TRISE- nastavenie časovania hrán.

Polovica z nich je však typu „napíš a zabudni“.

Doska STM32F4-Discovery už má I2C zariadenie, s ktorým môžete cvičiť: CS43L22, audio DAC. Pripája sa na piny PB6/PB9. Hlavná vec je nezabudnúť použiť vysokú úroveň na pin PD4 (tam sedí ~RESET), inak DAC nebude reagovať.

Postup nastavenia je približne nasledovný:
1 . Povoliť taktovanie portov a samotného modulu.
Potrebujeme piny PB6/PB9, takže musíme nastaviť bit 1 (GPIOBEN) v registri RCC_AHB1ENR, aby sme povolili port.
A nastavte bit 21 (I2C1EN) v registri RCC_APB1ENR, aby ste aktivovali modul I2C. Pre druhý a tretí modul sú čísla bitov 22 a 23.
2 . Ďalej sa konfigurujú kolíky: výstup Oped Drain (GPIO->OTYPER), režim alternatívnej funkcie (GPIO->MODER) a číslo alternatívnej funkcie (GPIO->AFR).
Na želanie môžete nakonfigurovať pull-up (GPIO->PUPDR), ak nie je na doske (a pull-up k napájaniu oboch liniek je potrebný v akejkoľvek forme). Číslo pre I2C je vždy rovnaké: 4. Je pekné, že pre každý typ periférie existuje samostatné číslo.
3 . Aktuálna frekvencia hodín periférie Fpclk1 (vyjadrená v MHz) je indikovaná v registri CR2. Ako som pochopil, je to potrebné na výpočet rôznych časovaní protokolov.
Mimochodom, mali by byť aspoň dva pre normálny režim a aspoň štyri pre rýchly režim. A ak potrebujete plnú rýchlosť 400 kHz, musíte ju tiež vydeliť 10 (10, 20, 30, 40 MHz).
Maximálna povolená frekvencia hodín: 42 MHz.
4 . Rýchlosť rozhrania sa konfiguruje v registri CCR a zvolí sa režim (normálny/rýchly).
Význam je: Tsck = CCR * 2 * Tpckl1, t.j. perióda SCK je úmerná CCR (pre rýchly režim je všetko trochu zložitejšie, ale je to popísané v RM).
5 . Nastaví sa maximálny čas nábežnej hrany v registri TRISE. Pre štandardný režim je tento čas 1 µs. V registri musíte napísať počet cyklov zbernice, ktoré sa zmestia do tohto času, plus jeden:
ak cyklus Tpclk1 trvá 125 ns, potom zapíšte (1000 ns / 125 ns) + 1 = 8 + 1 = 9.
6 . Voliteľne je povolené generovanie signálov prerušenia (chyba, stav a údaje);
7 . Modul sa zapne: príznak PE v registri CR1 je nastavený na 1.

Potom modul funguje ako má. Stačí implementovať správne poradie príkazov a skontrolovať výsledky. Napríklad záznam v registri:
1 . Najprv je potrebné poslať ŠTART nastavením príznaku s rovnakým názvom v registri CR1. Ak je všetko ok, tak sa po určitom čase nastaví príznak SB v registri SR1.
Chcel by som poznamenať jeden bod - ak na linke nie je žiadny ťah (a sú na 0), potom tento príznak nemusí vôbec čakať.
2 . Ak je príznak prijatý, pošleme adresu. Pri sedembitovej adrese ju jednoducho zapíšeme do DR presne tak, ako bude na riadku (7 bitov adresy + smerový bit). Pre desaťbitový, zložitejší algoritmus.
Ak zariadenie odpovie na adresu ACK, potom sa v registri SR1 objaví príznak ADDR, ak nie, zobrazí sa príznak AF (Acknowledge failure).
Ak sa zobrazí ADDR, musíte si prečítať register SR2. Nemusíte sa tam na nič pozerať, iba sekvenčné čítanie SR1 a SR2 tento príznak resetuje. A kým je príznak nastavený, SCL je držaný nadradeným zariadením na nízkej úrovni, čo je užitočné, ak potrebujete požiadať vzdialené zariadenie, aby počkalo pred odoslaním údajov.
Ak je všetko v poriadku, potom sa modul prepne do režimu príjmu alebo prenosu dát v závislosti od najmenej významného bitu odosielanej adresy. Pre písanie musí byť nula, pre čítanie musí byť jedna.
ale pozeráme sa na záznam, tak budeme predpokladať, že tam bola nula.
3 . Ďalej pošleme adresu registra, ktorý nás zaujíma. Rovnakým spôsobom to zapísať do DR. Po prenose sa nastavia príznaky TXE (vyrovnávacia pamäť prenosu je prázdna) a BTF (prenos dokončený).
4 . Nasledujú údaje, ktoré je možné odoslať, kým zariadenie odpovie ACK. Ak je odpoveďou NACK, tieto príznaky sa nenastavia.
5 . Po dokončení prevodu (alebo v prípade neočakávaného stavu) posielame STOP: v registri CR1 je nastavený rovnomenný príznak.

Pri čítaní je všetko po starom. Zmeny až po napísaní adresy registra.
Namiesto zápisu údajov sa znova odošle START (reštart) a adresa sa odošle s nastaveným najmenej významným bitom (znamienko čítania).
Modul bude čakať na dáta zo zariadenia. Aby ste ho povzbudili k odoslaniu ďalších bajtov, musíte pred prijatím nastaviť príznak ACK v CR1 (takže po prijatí modul pošle rovnaké ACK).
Keď vás to omrzí, odstráňte vlajku, zariadenie uvidí NACK a stíchne. Potom obvyklým spôsobom pošleme STOP a radujeme sa z prijatých dát.

Tu je to isté vo forme kódu:
// Inicializujte modul void i2c_Init(void) ( uint32_t Clock = 16000000UL; // Frekvencia hodín modulu (system_stm32f4xx.c sa nepoužíva) uint32_t Speed ​​​​= 100000UL; // 100 kHz port 100 kHz /> Povolenie taktovania GPIAHENOBCC |= RCC_AHB1ENR_GPIOBEN; // Nastavenie kolíkov PB6, PB9 // Otvorenie odtoku! GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_9; // Rozšírenie je externé, takže ho tu nemožno nakonfigurovať! // v prípade potreby, pozri register GPIOB->PUPDR // Číslo alternatívnej funkcie GPIOB ->AFR &= ~(0x0FUL<< (6 * 4)); // 6 очистим GPIOB->AFR |= (0x04UL<< (6 * 4)); // В 6 запишем 4 GPIOB->AFR &= ~(0x0FUL<< ((9 - 8) * 4)); // 9 очистим GPIOB->AFR |= (0x04UL<< ((9 - 8) * 4)); // В 9 запишем 4 // Режим: альтернативная функция GPIOB->MODERNÉ &= ~((0x03UL<< (6 * 2)) | (0x03UL << (9 * 2))); // 6, 9 очистим GPIOB->MODERNÉ |= ((0x02UL<< (6 * 2)) | (0x02UL << (9 * 2))); // В 6, 9 запишем 2 // Включить тактирование модуля I2C1 RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // V tomto bode by mal byť I2C vypnutý // Resetovať všetko (SWRST == 1, reset) I2C1->CR1 = I2C_CR1_SWRST; // PE == 0, toto je hlavná vec I2C1->CR1 = 0; // Predpokladáme, že bežíme z RC (16 MHz) // V systéme hodín nie sú žiadne preddeličky (všetky 1) // Toto všetko by sme mali priateľsky vypočítať z // skutočnej taktovacej frekvencie modulu I2C1->CR2 = Hodiny / 1000000UL; // 16 MHz // Upravte frekvenciu ( // Tclk = (1 / Fperiph); // Stehno = Tclk * CCR; // Tlow = stehno; // Fi2c = 1 / CCR * 2; // CCR = Fperiph / ( Fi2c * 2); uint16_t Hodnota = (uint16_t)(Hodiny / (Rýchlosť* 2)); // Minimálna hodnota: 4 if(Hodnota< 4) Value = 4; I2C1->CCR = hodnota; ) // Nastavte čas nábehu limitu // V štandardnom režime je tento čas 1000 ns // K frekvencii vyjadrenej v MHz jednoducho pripočítame jednotku (pozri RM str. 604). I2C1->TRISE = (Hodiny / 1000000UL) + 1; // Povolenie modulu I2C1->CR1 |= (I2C_CR1_PE); // Teraz môžete niečo urobiť ) // Odoslať bajt bool i2c_SendByte(uint8_t adresa, uint8_t register, uint8_t údaje) ( if(!i2c_SendStart()) návrat false; // adresa čipu if(!i2c_SendAddress(Address)) return i2c_SendStop (); // Registrácia adresy if(!i2c_SendData(Register)) return i2c_SendStop(); // Údaje if(!i2c_SendData(Data)) return i2c_SendStop(); // Stop! i2c_SendStop(); return true; ) // Receive byte bool i2c_ReceiveByte(uint8_t Address, uint8_t Register, uint8_t * Data) ( if(!i2c_SendStart()) return false; // Chip address if(!i2c_SendAddress(Address)) return i2c_SendStop(!); // Register address if() i2c_SendData(Register)) return i2c_SendStop(); // Reštart if(!i2c_SendStart()) return false; // Adresa čipu (čítaj) if(!i2c_SendAddress(Address | 1)) return i2c_SendStop(); // Prijmite bajt if(!i2c_ReceiveData(Data)) return i2c_SendStop(); // Stop! i2c_SendStop(); return true; ) Použitie: ( uint8_t ID = 0; i2c_Init(); // Predpokladáme, že PD4 je nastavené na vysokú úroveň a DAC funguje (to sa musí nejako urobiť) // Pošlite bajt do zariadenia s adresou 0x94, aby sa zaregistrovalo 0x00 s hodnotou 0x00. i2c_SendByte(0x94, 0x00, 0x00); // Prijme bajt zo zariadenia s adresou 0x94 z registra 0x01 (ID) do premennej buffera i2c_ReceiveByte(0x94, 0x01, &ID); )
Samozrejme, nemôžete to urobiť okrem príkladu školenia. Čakanie na dokončenie akcie je na tak rýchly ovládač príliš dlhé.

(Príručka vývojára pre mikrokontroléry rodiny HCS08)

Na ovládanie modulu I2C sa používa 6 špeciálnych funkčných registrov:

  • IICC - prvý riadiaci register modulu I2C;
  • IICC2 - druhý riadiaci register modulu I2C;
  • IICS - register stavu modulu I2C;
  • IICF - register prenosovej rýchlosti modulu I2C;
  • IICA - register adries modulu I2C;
  • IICD je dátový register modulu I2C.

MCU série QE obsahuje 2 I2C moduly a teda dva riadiace registre každého typu. Napríklad prvý stavový register je IIC1S a druhý stavový register je IIC2S.

11.2.8.1. riadiaci register IICC

Pre sériu MK AC. AW, Dx, EL, GB, GT, JM, LC, QE. Q.G. SG, SH, SL
Registrovať Režim D7 D6 D5 D4 D3 D2 D1 D0
IICC Čítanie IICEN IICIE MST TX TXAK 0 0 0
Záznam RSTA
Resetovať 0 0 0 0 0 0 0 0
Popis bitov:
Názov bitu Popis Symbol v jazyku C
IICEN Bit aktivácie modulu I2C:
0 — I2C regulátor je deaktivovaný;
1 - Ovládač I2C je povolený.
biIICEN
IICIE Bit povolenia prerušenia modulu z I2C:
0 - prerušenia požiadaviek I2C sú zakázané;
1 - Prerušenia požiadaviek I2C sú povolené.
bHCIE
MST Bit výberu prevádzkového režimu ovládača I2C:
0 - I2C regulátor pracuje v režime Slave;
1 - Regulátor I2C pracuje v režime Master.
Keď sa tento bit zmení z 0 na 1, vygeneruje sa stav Štart. Naopak, keď sa bit zmení z 1 na 0, vygeneruje sa podmienka Stop.
bMST
TX Bit výberu smeru prenosu na dátovej linke SDA:
0 — linka funguje pre vstup;
1 - riadok pracuje pre výstup.
bTX
TXAK Potvrdzovací bit v režime príjmu:
0 - po prijatí bajtu sa vygeneruje potvrdzovací bit;
1 - vygeneruje sa bajtový nepotvrdený bit.
Tento bit riadi generovanie potvrdzovacieho bitu po prijatí dátového bajtu bez ohľadu na to, či ide o slave alebo master.
bTXAK
RSTA Ak modul I2C pracuje v režime master, zápis 1 do tohto bitu spôsobí opätovné vygenerovanie stavu Štart – „Reštart“. bRSTA

11.2.8.2. Stavový register IICS

Pre sériu MK AC, AW, Dx, EL, GB, GT, JM, LC, QE, QG, SG, SH, SL
Registrovať Režim D7 D6 D5 D4 D3 D2 D1 D0
IICS Čítanie TCF IAAS ZANEPRÁZDNENÝ ARBL 0 SRW IICIF RXAK
Záznam
Resetovať 0 0 0 0 0 0 0 0
Popis bitov:
Názov bitu Popis Symbol v jazyku C
TCF Bit dokončenia výmeny. Nastaviť po dokončení výmeny jedného bajtu:
0 – výmena nebola dokončená;
1 - výmena dokončená.
Príznak TCF sa vymaže na 0, keď sa číta údajový register IICD (v režime príjmu) alebo keď sa zapisuje údajový register IICD (v režime vysielania).
bTCF
IAAS Príznak adresy otroka. Nastavte, či zariadenie pracuje v režime slave a adresa prenášaná v hlavnej správe sa rovná adrese slave, ktorá je uložená v registri adries IICA.
Pri zápise do registra IICC sa príznak vymaže.
bIAAS
ZANEPRÁZDNENÝ Príznak rušnej linky. Tento príznak sa nastaví, ak modul I2C rozpoznal štartovací bit na linke. Príznak sa vymaže, keď modul deteguje stop bit na linke.
0 — zbernica I2C je voľná;
1 - zbernica I2C je obsadená.
bBUSY
ARBL Príznak straty arbitráže:
0 - žiadne porušenia pri prevádzke zbernice I2C;
1 – dochádza k strate arbitráže. Modul I2C musí chvíľu počkať a potom znova spustiť prenos.
bARBL
SRW Bit smeru vysielania slave. Tento bit označuje stav bitu R/W v poli adresy:
0 - otrok prijíma. Vodca prenáša na otroka;
1 - slave vysiela. Vodca prijíma od otroka.
bSRW
IICIF Príznak žiadostí o neobslúžené prerušenie pre modul I2C. Nastavte na 1, ak je nastavený jeden z príznakov: TCF, IAAS alebo ARBL.
0 - žiadne neobsluhované prerušenia;
1 - existujú neobsluhované prerušenia.
Príznak sa resetuje napísaním 1.
bIICIF
RXAK Majster potvrdí bit:
0—podriadený potvrdený príjem údajov;
1 — Slave nepotvrdil príjem údajov.
Tento bit odráža stav poľa ASK na časovom diagrame výmeny.
bRXAK

11.2.8.3. Register adries IICA

Registrovať Režim D7 D6 D5 D4 D3 D2 D1 D0
IICA Čítanie ADDR
Záznam
Resetovať 0 0 0 0 0 0 0 0

Tento register ukladá 7-bitovú podriadenú adresu, ktorú vývojár priradil toto zariadenie pri vývoji systému. Táto adresa sa automaticky porovnáva s adresovým kódom, ktorý slave prijal v poli adresy na zbernici I2C. Ak sa adresy zhodujú, nastaví sa bit IAAS v stavovom registri IICS.

11.2.8.4. Register prenosovej rýchlosti IICF

Pre sériu MK AC, AW, Dx, EL, GB, GT, JM, LC, QE, QG, SG, SH, SL
Registrovať Režim D7 D6 D5 D4 D3 D2 D1 D0
IICF Čítanie MULT ICR
Záznam
Resetovať 0 0 0 0 0 0 0 0
Popis bitov:

Hodnoty koeficientov SCL_DIV a SDA_HV

ISR SCL_DIV SDA_HV ISR SCL_DIV SDA_HV
0x00 20 7 0x20 160 17
0x01 22 7 0x21 192 17
0x02 24 8 0x22 224 33
0x03 26 8 0x23 256 33
0x04 28 9 0x24 288 49
0x05 30 9 0x25 320 49
0x06 34 10 0x26 384 65
0x07 40 10 0x27 480 65
0x08 28 7 0x28 320 33
0x09 32 7 0x29 384 33
0x0A 36 9 0x2A 448 65
0x0B 40 9 0x2B 512 65
0x0C 44 11 0x2C 576 97
0x0D 48 11 0x2D 640 97
0x0E 56 13 0x2E 768 129
0x0F 68 13 0x2F 960 129
0x10 48 9 0x30 640 65
0x11 56 9 0x31 768 65
0x12 64 13 0x32 896 129
0x13 72 13 0x33 1024 129
0x14 80 17 0x34 1152 193
0x15 88 17 0x35 1280 193
0x16 104 21 0x36 1536 257
0x17 128 21 0x37 1920 257
0x18 80 9 0x38 1280 129
0x19 96 9 0x39 1536 129
0x1A 112 17 0x3A 1792 257
0x1B 128 17 0x3B 2048 257
0x1C 144 25 0x3C 2304 385
0x1D 160 25 0x3D 2560 385
0x1E 192 33 0x3E 3072 513
0x1F 240 33 0x3F 3840 513

Tento register ukladá dve bitové polia, ktoré určujú parametre rýchlosti a časovania I2C výmeny. Frekvencia synchronizačných signálov je určená vzorcom:

Čas ustálenia údajov SDA_hold_time na zbernici I2C je časový interval medzi okamihom, kedy je signál SCL nastavený na 0 a zmenami údajov na linke SDA. Priradené parametrom SDA_HV (SDA_Hold_Value) z tabuľky pre faktor ICR registra prenosovej rýchlosti:

.

11.2.8.5. dátový register IICD

Pre sériu MK AC, AW, Dx, EL, GB, GT, JM, LC, QE, QG, SG, SH, SL
Registrovať Režim D7 D6 D5 D4 D3 D2 D1 D0
IICD Čítanie I2C ÚDAJE
Záznam
Resetovať 0 0 0 0 0 0 0 0

Ak modul I2C pracuje v režime master, potom operácia zápisu do tohto registra iniciuje komunikáciu I2C (ale len ak je bit smeru komunikácie v riadiacom registri IICC nastavený správne, t.j. TX = 1). Prvý bajt po stave Štart, ktorý program zapíše do dátového registra, interpretujú podriadené jednotky ako adresu zariadenia. Preto musí program správne sformovať obsah prvého bajtu. Operácia čítania registra vráti posledný bajt prijatý cez I2C. Operácia čítania registra tiež iniciuje začiatok prijímania ďalšieho bajtu, ale len ak je správne nastavený bit smeru komunikácie v riadiacom registri IICC, t.j. pri TX = 0! Keď je TX = 1, operácia čítania registra nespôsobí prijatie nového bajtu cez I2C z podriadeného zariadenia.

Ak modul I2C pracuje v režime slave, potom sa údaje zapísané do tohto registra prenesú na linku SDA zbernice I2C, keď hlavné zariadenie vykoná cyklus príjmu z tohto slave zariadenia. Operácia čítania registra vráti posledný bajt prijatý od mastera.

11.2.8.6. Riadiaci register IICC2

Pre sériu MK AC, Dx, EL, JM, QE, SG, SH, SL
Registrovať Režim D7 D6 D5 D4 D3 D2 D1 D0
IICC Čítanie GCAEN ADEXT 0 0 0 AD10 AD9 AD8
Záznam
Resetovať 0 0 0 0 0 0 0 0

Prvé kroky s kompilátorom STM32 a mikroC pre architektúru ARM – časť 4 – pripojenie LCD založené na I2C, pcf8574 a HD4478

Nasledujúci článok by som rád venoval práci s bežným rozhraním i2c, ktoré sa často používa v rôznych mikroobvodoch pripojených k mikrokontroléru.

I2C je zbernica, ktorá funguje cez dve fyzické pripojenia (okrem spoločného vodiča). Pomerne veľa sa o tom píše na internete, na Wikipédii sú dobré články. Okrem toho je veľmi jasne popísaný algoritmus prevádzky zbernice. Stručne povedané, zbernica je dvojvodičová synchrónna zbernica. Na zbernici môže byť súčasne až 127 zariadení (adresa zariadenia je 7-bitová, k tomu sa vrátime neskôr). Nižšie je uvedená typická schéma pripojenia zariadení na zbernicu i2c, pričom MK je hlavným zariadením.


Pre i2c všetky zariadenia (hlavné aj podriadené) používajú výstupy s otvoreným odtokom. Jednoducho povedané, dokážu pritiahnuť pneumatiku LEN K ZEME. Vysoká úroveň zbernice je zabezpečená pull-up odpormi. Hodnota týchto rezistorov sa zvyčajne volí v rozsahu od 4,7 do 10 kOhm. i2c je dosť citlivý na fyzické linky spájajúce zariadenia, takže ak sa použije spojenie s veľkou kapacitou (napríklad dlhý tenký alebo tienený kábel), vplyv tejto kapacity môže „rozmazať“ okraje signálu a rušiť normálna operácia pneumatiky. Čím menší je pull-up rezistor, tým menší vplyv má táto kapacita na charakteristiky signálových hrán, ale tým VÄČŠIE ZAŤAŽENIE výstupných tranzistorov na rozhraniach i2c. Hodnota týchto odporov sa vyberá pre každú konkrétnu implementáciu, ale nemala by byť menšia ako 2,2 kOhm, inak môžete jednoducho spáliť výstupné tranzistory v zariadeniach, ktoré pracujú so zbernicou.

Zbernica pozostáva z dvoch liniek: SDA (dátová linka) a SCL (hodinový signál). Hodiny zariadenia Bus Master, obyčajne naša MK. Keď je hodnota SCL vysoká, informácie sa čítajú z dátovej zbernice. Stav SDA je možné zmeniť len vtedy, keď je signál hodín nízky.. Keď je SCL vysoký, signál na SDA sa pri generovaní signálov mení ŠTART (keď je SCL vysoký, signál na SDA sa zmení z vysokého na nízky) a STOP - keď je úroveň SCL vysoká, signál na SDA sa mení z nízkej na vysokú).

Samostatne by sa malo povedať, že v i2c je adresa špecifikovaná ako 7-bitové číslo. 8 - najmenej významný bit udáva smer prenosu dát 0 - znamená, že slave bude vysielať dáta, 1 - prijímať.. Stručne povedané, algoritmus pre prácu s i2c je nasledujúci:

  • Vysoká úroveň na SDA a SCL- autobus je zadarmo, môžete začať pracovať
  • Majstrovské výťahy SCL na 1 a zmení stav S.D.A. od 1 do 0 - pritiahne ho k zemi - vytvorí sa signál ŠTART
  • Master vysiela 7-bitovú adresu slave so smerovým bitom (údaje o S.D.A. sú vystavené, keď SCL stiahnuté na zem a prečítané otrokom po uvoľnení). Ak otrok nestihne „uchopiť“ predchádzajúci kúsok, pritiahne SCL k zemi, čím je masterovi jasné, že stav dátovej zbernice nie je potrebné meniť: "Stále čítam predchádzajúcu." Potom, čo majster uvoľnil pneumatiku, skontroluje pustil ju otrok?.
  • Po prenesení 8 bitov adresy master vygeneruje 9. takt a uvoľní dátovú zbernicu. Ak otrok počul jeho adresu a prijal ju, potom on bude tlačiť S.D.A. na zem. Takto vzniká signál OPÝTAŤ SA- akceptované, všetko v poriadku. Ak otrok ničomu nerozumie alebo tam jednoducho nie je, potom nebude mať kto stlačiť pneumatiku. majster počká na časový limit a pochopí, že nebol pochopený.
  • Po odoslaní adresy, ak máme nastavený smer z pána na otroka(8 bitov adresy sa rovná 1), potom master odošle údaje podriadenému, pričom nezabudne skontrolovať prítomnosť OPÝTAŤ SA od slave, čakajúc, kým slave zariadenie spracuje prichádzajúce informácie.
  • Keď master prijme dáta od slave, master sám vygeneruje signál OPÝTAŤ SA po prijatí každého bajtu a slave kontroluje jeho prítomnosť. Majster nemôže konkrétne odoslať OPÝTAŤ SA pred odoslaním príkazu STOP, zvyčajne dáva otrokovi jasne najavo, že nie je potrebné poskytovať žiadne ďalšie údaje.
  • Ak je po odoslaní dát masterom (režim zápisu) potrebné načítať dáta z slave, potom master generuje signál znova ŠTART , odoslanie adresy slave s príznakom čítania. (ak pred príkazom ŠTART nebol prenesený STOP potom sa vytvorí tím REŠTART). Používa sa na zmenu smeru komunikácie master-slave. Napríklad odošleme adresu registra podriadenému zariadeniu a potom z neho načítame údaje.)
  • Po ukončení práce s podriadeným generuje master signál STOP- pri vysokej úrovni hodinového signálu tvorí prechod dátovej zbernice z 0 na 1.
STM 32 má hardvérovo implementované transceivery zbernice i2c. Takéto moduly môžu byť v MK 2 alebo 3. Na ich konfiguráciu sa používajú špeciálne registre, popísané v referencii pre použitý MK.

V MicroC sa musí pred použitím i2c (ako aj akéhokoľvek periférneho zariadenia) správne inicializovať. Na to používame nasledujúcu funkciu (Inicializácia ako master):

I2Cn_Init_Advanced(dlhé bez znamienka: I2C_ClockSpeed, const Module_Struct *modul);

  • n- číslo použitého modulu, napr I2C1 alebo I2C2.
  • I2C_ClockSpeed- rýchlosť zbernice, 100 000 (100 kbs, štandardný režim) alebo 400 000 (400 kbs, rýchly režim). Druhý je 4-krát rýchlejší, no nie všetky zariadenia ho podporujú
  • *modul- ukazovateľ na periférny modul, napr &_GPIO_MODULE_I2C1_PB67, nezabudnime tu na to Asistent kódu (ctrl-space ) veľmi pomáha.
Najprv skontrolujte, či je zbernica voľná; existuje na to funkcia I2Cn_Is_Idle(); vrátenie 1, ak je autobus voľný, a 0, ak je na ňom výmena.

I2Cn_Start();
Kde n- číslo použitého i2c modulu nášho mikrokontroléra. Funkcia vráti 0, ak je chyba na zbernici a 1, ak je všetko v poriadku.

Na prenos údajov do podriadeného zariadenia používame funkciu:

I2Cn_Write(unsigned char slave_address, unsigned char *buf, unsigned long count, unsigned long END_mode);

  • n- číslo použitého modulu
  • adresa_otroka- 7-bitová podriadená adresa.
  • *buf- ukazovateľ na naše dáta - bajtové alebo bajtové pole.
  • počítať- počet prenesených dátových bajtov.
  • END_mode- čo robiť po prenose údajov do podriadeného zariadenia, END_MODE_STOP - vysielať signál STOP, alebo END_MODE_RESTART poslať znova ŠTART, generovanie signálu REŠTART a dať oddeleniu najavo, že relácia s ním sa neskončila a teraz sa z neho budú čítať údaje.
Na čítanie údajov z podriadeného zariadenia použite funkciu:

I2Cn_Read(char slave_address, char *ptrdata, unsigned long count, unsigned long END_mode);

  • n- číslo použitého modulu
  • adresa_otroka- 7-bitová podriadená adresa.
  • *buf- ukazovateľ na premennú alebo pole, do ktorého dostávame dáta, napíšte char alebo short int
  • počítať- počet prijatých dátových bajtov.
  • END_mode- čo robiť po prijatí údajov od otroka - END_MODE_STOP - vysielať signál STOP, alebo END_MODE_RESTART vyslať signál REŠTART.
Skúsme niečo napojiť na našu MK. Na začiatok: rozšírený mikroobvod PCF8574(A), čo je expandér vstupných/výstupných portov ovládaných cez zbernicu i2c. Tento čip obsahuje iba jeden vnútorný register, ktorým je jeho fyzický I/O port. To znamená, že ak jej odovzdáte bajt, okamžite bude vystavená jej záverom. Ak z toho spočítate bajt (Transmit ŠTART adresa s príznakom čítania, signál RESTERT, prečítať údaje a nakoniec vygenerovať signál STOP) potom na svojich výstupoch premietne logické stavy. Pripojme náš mikroobvod podľa údajového listu:


Adresa mikroobvodu je vytvorená zo stavu kolíkov A0, A1, A2. Pre mikroobvod PCF8574 adresa bude: 0100A0A1A2. (Napríklad máme A0, A1, A2 na vysokej úrovni, takže adresa nášho mikroobvodu bude 0b0100 111 = 0x27). Pre PCF8574A - 0111A0A1A2, ktorá s našou schémou zapojenia dá adresu 0b0111 111 = 0x3F. Ak je povedzme A2 pripojený k zemi, potom adresa pre PCF8574A bude 0x3B. Celkovo je možné na jednu i2c zbernicu súčasne namontovať 16 mikroobvodov, každý po 8 PCF8574A a PCF8574.

Skúsme niečo preniesť, inicializovať zbernicu i2c a niečo preniesť do nášho PCF8574.

#define PCF8574A_ADDR 0x3F //Adresa nášho PCF8574 void I2C_PCF8574_WriteReg(unsigned char wData) ( I2C1_Start(); // Generovanie signálu START I2C1_Write(PCF8574Ate_ADDR); STOP signál ) char PCF8574A_reg ; // premenná, ktorú zapisujeme do PCF8574 void main () ( I2C1_Init_Advanced(400000, &_GPIO_MODULE_I2C1_PB67); // Spustite I2C delay_ms(25); // Chvíľu počkajte PCF8574A_reg.b0 = 1. 1 PCF85, rozsvieti sa prvá LED 0; // = 1; // vypnite druhú LED, kým (1) ( delay_ms(500); PCF8574A_reg.b0 = ~PCF8574A_reg.b0; PCF8574A_reg.b1 = ~PCF8574A_reg.b1; // invertuje stav LED diód I27C_PCFreg85 ; // prenos údajov do nášho PCF8574 ) )
Kompilujeme a spúšťame náš program a vidíme, že naše LED diódy striedavo blikajú.
Katódu LED som pripojil k nášmu PCF8574 z nejakého dôvodu. Ide o to, že keď je na výstup privedená logická 0, mikroobvod poctivo stiahne svoj výstup k zemi, ale keď sa použije logická 1, pripojí ho k + napájaniu cez zdroj prúdu 100 μA. To znamená, že na výstupe nemôžete získať „čestnú“ logickú 1. A nemôžete rozsvietiť LED s 100 µA. Toto bolo urobené s cieľom nakonfigurovať výstup PCF8574 na vstup bez ďalších registrov. Jednoducho zapíšeme do výstupného registra 1 (v podstate nastavíme stavy pinov na Vdd) a môžeme ho jednoducho skratovať k zemi. Súčasný zdroj nedovolí, aby sa výstupný stupeň nášho I/O expandéra „vypálil“. Ak je noha pritiahnutá k zemi, potom je na nej potenciál zeme a číta sa logická 0. Ak je noha pritiahnutá k +, potom sa číta logická 1. Na jednej strane je to jednoduché, ale na druhej strane pri práci s týmito mikroobvodmi by ste na to mali vždy pamätať.


Skúsme si prečítať stav pinov nášho expandovacieho čipu.

#define PCF8574A_ADDR 0x3F //Adresa nášho PCF8574 void I2C_PCF8574_WriteReg(unsigned char wData) ( I2C1_Start(); // Generovanie signálu START I2C1_Write(PCF8574Ate_ADTA,_ADDR, generovať dáta, & 1.prenos dát) STOP signál ) void I2C_PCF8574_ReadReg (nepodpísaný znak rData) ( I2C1_Start(); // Vygenerovanie signálu START I2C1_Read(PCF8574A_ADDR, &rData, 1, END_MODE_STOP); // Prečítanie 1 bajtu dátového signálu) a vygenerovanie 4 PCAF STOPcharreg //premenná, ktorú zapisujeme do PCF8574 char PCF8574A_out; // premenná, do ktorej čítame a PCF8574 char lad_state; //naša LED je zapnutá alebo vypnutá void main () ( I2C1_Init_Advanced(400000, &_GPIO_MODULE_I2C1_PB67); // Start I2C delay_ms(25); // Chvíľu počkajte PCF8574A_reg.b0 = 0; // rozsvieťte prvú LED diódu PCF8574 1; / / vypnite druhú LED diódu PCF8574A_reg.b6 = 1; // Zapnite napájanie kolíkov 6 a 7. PCF8574A_reg.b7 = 1; zatiaľ čo (1) ( delay_ms(100); I2C_PCF8574_WriteReg (PCF8574A write data_reg); do PCF8574 I2C_PCF8574_ReadReg (PCF85 74A_out); // čítanie z PCF8574, ak (~PCF8574A_out.b6) PCF8574A_reg.b0 = ~PCF8574A_reg.b0; // Ak je stlačené tlačidlo 0,85 zo 4. bitu zapnite/vypnite našu LED diódu), ak (~PCF8574A_out .b7) PCF8574A_reg.b1 = ~PCF8574A_reg.b1; // podobné pre 2 tlačidlá a 2 LED ) )
Teraz stlačením tlačidiel zapneme alebo vypneme LED. Mikroobvod má ďalší výstup INT. Pri každej zmene stavu pinov nášho I/O expandéra sa na ňom generuje impulz. Jeho pripojením k externému vstupu prerušenia nášho MK (ako nakonfigurovať externé prerušenia a ako s nimi pracovať, vám poviem v jednom z nasledujúcich článkov).

Využime náš expandér portov na pripojenie znakového displeja cez neho. Je ich veľmi veľa, ale takmer všetky sú postavené na báze čipu ovládača HD44780 a jeho klony. Napríklad som použil LCD2004 displej.


Datasheet k nemu a ovládaču HD44780 možno ľahko nájsť na internete. Pripojme náš displej k PCF8574 a jej k nášmu STM32.

HD44780 používa paralelné hradlové rozhranie. Dáta sa prenášajú 8 (za hodinový cyklus) alebo 4 (za 2 hodinové cykly) hradlovými impulzmi na kolíku E. (čítané ovládačom displeja na zostupnej hrane, prechod z 1 na 0). Záver R.S. označuje, či odosielame údaje na náš displej ( RS = 1) (znaky, ktoré by sa mali zobraziť, sú v skutočnosti kódy ASCII) alebo príkaz ( RS = 0). RW označuje smer prenosu dát, zápisu alebo čítania. Zvyčajne zapisujeme údaje na displej, takže ( RW = 0). Rezistor R6 riadi kontrast displeja. Vstup nastavenia kontrastu nemôžete jednoducho pripojiť k zemi alebo napájaniu, inak nič neuvidíte.. VT1 slúži na zapínanie a vypínanie podsvietenia displeja podľa príkazov MK. MicroC má knižnicu na prácu s takýmito displejmi cez paralelné rozhranie, ale zvyčajne je drahé stráviť 8 nôh na displeji, takže na prácu s takýmito obrazovkami takmer vždy používam PCF8574. (Ak by to niekoho zaujímalo, napíšem článok o práci s displejmi na báze HD44780 zabudovanými v MicroC cez paralelné rozhranie.) Výmenný protokol nie je nijak zvlášť zložitý (použijeme 4 dátové linky a informácie prenesieme v 2 hodinových cykloch), jasne to ukazuje nasledujúci časový diagram:


Pred prenosom údajov na náš displej je potrebné ho inicializovať odovzdaním servisných príkazov. (popísané v datasheete, tu uvádzame len tie najpoužívanejšie)

  • 0x28- komunikácia s indikátorom cez 4 linky
  • 0x0C- povoliť výstup obrazu, zakázať zobrazenie kurzora
  • 0x0E- povoliť výstup obrazu, povoliť zobrazenie kurzora
  • 0x01- vymazať indikátor
  • 0x08- zakázať výstup obrazu
  • 0x06- po zobrazení symbolu sa kurzor posunie o 1 známe miesto
Keďže s týmto indikátorom budeme musieť pracovať pomerne často, vytvoríme si knižnicu zásuvných modulov "i2c_lcd.h" . Na tento účel v Projektový manažér Súbory hlavičky a vyberte si Pridať nový súbor . Vytvorme náš hlavičkový súbor.

#define PCF8574A_ADDR 0x3F //Adresa nášho PCF8574 #define DB4 b4 // Korešpondencia medzi pinmi PCF8574 a indikátorom #define DB5 b5 #define DB6 b6 #define DB7 b7 #define EN b3 #define RW b1 #define b BL b0 // ovládanie podsvietenia #define displenth 20 // počet znakov v našom riadku zobrazenia static unsigned char BL_status; // premenná ukladajúca stav podsvietenia (zapnuté/vypnuté) void lcd_I2C_Init(void); // Zobrazenie a inicializačná funkcia PCF8574 void lcd_I2C_txt(char *pnt); // Zobrazí riadok textu, parameter je ukazovateľ na tento riadok void lcd_I2C_int(int pnt); // Zobrazuje hodnotu celočíselnej premennej, parametrom je výstupná hodnota void lcd_I2C_Goto(unsigned short row, unsigned short col); // presunie kurzor na zadanú pozíciu, parametre riadok - riadok (od 1 do 2 alebo 4 v závislosti od zobrazenia) a col - (od 1 po displenth)) void lcd_I2C_cls(); // Vymaže obrazovku void lcd_I2C_backlight (unsigned short int state); // Povolí (pri prenose 1 a deaktivuje - pri prenose 0 podsvietenie displeja)
Teraz si popíšme naše funkcie, znova prejdeme na Projektový manažér kliknite pravým tlačidlom myši na priečinok Zdroje a vyberte si Pridať nový súbor . Vytvorte súbor "i2c_lcd.с" .

#include "i2c_lcd.h" //zahrnie náš hlavičkový súbor char lcd_reg; //registrácia na dočasné ukladanie údajov odoslaných do PCF8574 void I2C_PCF8574_WriteReg(unsigned char wData) //funkcia na odosielanie údajov cez i2c do čipu PCF8574 ( I2C1_Start(); I2C1_Write(PCF8574A_COMD) (DMOoid_COMDATA) (DMOoid, LCD_COMDATA) v&wData char com) / /funkcia odoslania príkazu na náš displej ( lcd_reg = 0; //zapísanie 0 do dočasného registra lcd_reg.BL = BL_status.b0; //nastavenie pinu podsvietenia podľa hodnoty premennej ukladajúcej stav podsvietenia lcd_reg.DB4 = com.b4; // nastavenie 4 najvýznamnejších bitov nášho príkazu na dátovú zbernicu indikátora lcd_reg.DB5 = com.b5; lcd_reg.DB6 = com.b6; lcd_reg.DB7 = com.b7; r /resetujte impulz blesku na 0, indikátor načíta údaje I2C_PCF8574_WriteReg (lcd_reg); delay_us (300) ; lcd_reg = 0; lcd_reg.BL = BL_status.b0; lcd_reg.DB4 = najmenej com.b0; významné bity lcd_reg.DB5 = com.b1; lcd_reg.DB6 = com.b2; lcd_reg.DB7 = com.b3; lcd_reg.EN = 1; I2C_PCF8574_WriteReg(lcd_reg); delay_us(300); lcd_reg.EN = 0; I2C_PCF8574_WriteReg(lcd_reg); delay_us(300); ) void LCD_CHAR (unsigned char com) //odoslanie údajov (kód znakov ASCII) do indikátora ( lcd_reg = 0; lcd_reg.BL = BL_status.b0; lcd_reg.EN = 1; lcd_reg.RS = 1; //odoslanie znaku sa líši od odosielania príkazov nastavením bitu RS na 1 lcd_reg.DB4 = com.b4; //nastavenie 4 najvýznamnejších bitov na vstupoch lcd_reg.DB5 = com.b5; lcd_reg.DB6 = com.b6; lcd_reg.DB7 = com.b7; I2C_PCF8574_WriteReg (lcd_reg) ; delay_us (300); lcd_reg.EN = 0; // resetujte impulz blesku na 0, indikátor načíta údaje I2C_PCF8574_WriteReg (lcd_300); d delay (=reg_300); lclc .BL = BL_status.b0; lcd_reg.EN = 1; lcd_reg.RS = 1; lcd_reg.DB4 = com.b0; //nastavenie 4 najmenej významných bitov na vstupoch lcd_reg.DB5 = com.b1; lcd_reg.DB6 = com.b2; lcd_reg.DB7 = com.b3; I2C_PCF8574_WriteReg ( lcd_reg); delay_us (300); lcd_reg.EN = 0; I2C_PCF8574_WriteReg (lcd_reg); delay_us) (3010); delay_us) vI10 _Init_Advanced(400000, &_GPIO_MODULE_I2C1_PB67 //inicializujte náš modul I2c pre MK delay_ms(200); lcd_Command(0x28); // Zobrazenie v 4 bitoch na režim hodín delay_ms (5); lcd_Command(0x08); //Zakáže výstup dát na displej delay_ms (5); lcd_Command(0x01); //Vymaže zobrazenie delay_ms (5); lcd_Command(0x06); //Povolenie automatického posunu kurzora po zobrazení symbolu delay_ms (5); lcd_Command(0x0C); //Zapne zobrazovanie informácií bez zobrazenia kurzora delay_ms (25); ) void lcd_I2C_txt(char *pnt) //Výstup reťazca znakov na displej ( unsigned short int i; //premenná indexu dočasného poľa znakov char tmp_str; //dočasné pole znakov, dĺžka o 1 väčšia ako dĺžka displeja riadok, pretože riadok musí byť ukončený сiv znakom NULL ASCII 0x00 strncpy(tmp_str, pnt, displenth); //nekopírujte viac ako displenth znakov pôvodného reťazca do nášho dočasného reťazca pre (i=0; i Teraz pripojíme novovytvorenú knižnicu k súboru s našou hlavnou funkciou:

#include "i2c_lcd.h" //zahrnie náš hlavičkový súbor unsigned int i; //počítadlo dočasnej premennej void main() ( lcd_I2C_Init(); //inicializácia displeja lcd_I2C_backlight (1); //zapnutie podsvietenia lcd_I2C_txt ("Ahoj habrahabr"); //zobrazenie riadku pri (1) ( delay_ms( 1000) ; lcd_I2C_Goto (2,1); //prechod na znak 1 v riadku 2 lcd_i2c_int (i); //zobrazenie hodnoty i++; //zvýšenie počítadla ) )

Ak je všetko správne zostavené, mali by sme vidieť text na indikátore a počítadlo, ktoré sa zvyšuje každú sekundu. Vo všeobecnosti nie je nič zložité :)

V ďalšom článku budeme pokračovať v chápaní protokolu i2c a zariadení, ktoré s ním pracujú. Zoberme si prácu s pamäťou EEPROM 24XX a akcelerometrom/gyroskopom MPU6050.

Dnes je na našom operačnom stole nový hosť, je to produkt Microchip, expandér portov MCP23008-E. Táto vec je určená (ako už názov napovedá) na zvýšenie počtu I/O nôh mikrokontroléra, ak sa náhle stanú nedostatočnými. Samozrejme, ak potrebujeme nohy a východy, potom to môžeme vziať a nestarať sa o to. Ak potrebujete vstupné nohy, potom existuje riešenie založené na prísnej logike. Ak potrebujeme vstupy aj výstupy a tiež riadený pull-up pre vstupy, potom je expandér portov snáď najnormálnejším riešením. Pokiaľ ide o cenu zariadenia, je veľmi skromná - asi dolár. V tomto článku sa pokúsim podrobne popísať, ako ovládať tento mikroobvod pomocou mikrokontroléra AVR.

Najprv trochu o vlastnostiach:

  • 8 nezávislých portov
  • Rozhranie pre komunikáciu s vonkajším svetom - I2C (frekvencia do 1,7 MHz)
  • Prispôsobiteľné vyťahovanie pre vchody
  • Môže trhnúť nohou, keď sa zmení stav určitých vstupov
  • Tri vstupy pre nastavenie adresy mikroobvodu (na jednu zbernicu môžete zavesiť 8 zariadení)
  • Prevádzkové napätie od 1,8 do 5,5 voltov
  • Nízka spotreba prúdu
  • Veľký výber krytov (PDIP/SOIC/SSOP/QFN)

Najradšej používam rozhranie I2C, láka ma malým počtom zapojení :-) ak však potrebujete veľmi vysokú rýchlosť (až 10 MHz), musíte použiť rozhranie SPI, ktoré je v MCP23S08. Rozdiel medzi MCP23S08 a MCP23008, ako som to pochopil, je len v rozhraní a v počte nôh pre nastavenie adresy čipu. Kto má rád niečo kratšie? Pinout mikruhi je v datasheete, nie je ničím zaujímavý a nebude sa tu brať do úvahy. Preto okamžite prejdime k tomu, ako začať pracovať s týmto zariadením. Všetka práca spočíva v zapisovaní a čítaní určitých údajov z registrov mikroobvodu. Na moje potešenie nebolo registrov vôbec veľa - iba jedenásť. Zápis a čítanie údajov z registrov je veľmi jednoduché, píšte o tom. Je pravda, že nehovoríme o registroch, ale princíp je rovnaký. Teraz už len ostáva vymyslieť, z ktorých registrov čo čítať a do ktorých registrov čo zapisovať. S tým nám samozrejme pomôže datasheet. Z údajového listu sa dozvedáme, že mikroobvod má nasledujúce registre:

register IODIR
Určuje smer, ktorým prúdia údaje. Ak je bit zodpovedajúci určitej vetve nastavený na jednotku, potom je časť vstupom. Ak je vynulovaný, ukončite ho. Stručne povedané, tento register je analogický s DDRx v AVR (iba v AVR je 1 výstup a 0 je vstup).

registra IPOL
Ak je nastavený bit registra, potom je pre príslušný úsek povolená inverzia vstupu. To znamená, že ak na nohu priložíte poleno. nula sa potom z registra GPIO považuje za jednotku a naopak. Užitočnosť tejto funkcie je veľmi otázna.

registra GPINTEN
Každý bit tohto registra zodpovedá špecifickému pinu portu. Ak je bit nastavený, potom príslušný pin portu nakonfigurovaný ako vstup môže spôsobiť prerušenie. Ak je bit resetovaný, potom bez ohľadu na to, čo robíte s portom, nedôjde k prerušeniu. Podmienky prerušenia sú nastavené nasledujúcimi dvoma registrami.

registra DEFVAL
Aktuálna hodnota kolíkov nakonfigurovaných pre vstup sa neustále porovnáva s týmto registrom. Ak sa zrazu aktuálna hodnota začne líšiť od hodnoty v tomto registri, dôjde k prerušeniu. Jednoducho povedané, ak je bit nastavený, prerušenie nastane, keď sa úroveň zmení z vysokej na nízku na zodpovedajúcej vetve. Ak sa bit vynuluje, prerušenie nastane na stúpajúcej hrane.

registra INTCON
Každý bit tohto registra zodpovedá špecifickému pinu portu. Ak je bit čistý, potom akákoľvek zmena logickej úrovne na opačnú spôsobí prerušenie. Ak je bit nastavený, výskyt prerušenia je ovplyvnený registrom DEFVAL (inak je úplne ignorovaný).

register IOCON
Toto je register nastavení. Skladá sa zo štyroch bitov:
SEQOP— bit riadi automatické zvyšovanie adresy. Ak je nainštalovaný, automatické zvyšovanie je zakázané, v opačnom prípade je povolené. Ak ho vypneme, vieme veľmi rýchlo prečítať hodnotu toho istého registra vďaka tomu, že nemusíme zakaždým prenášať jeho adresu. Ak potrebujete rýchlo prečítať postupne všetkých 11 registrov, musíte povoliť automatické zvýšenie. Zakaždým, keď sa z registra načíta bajt, samotná adresa sa zvýši o jeden a nebude sa musieť prenášať.
DISSLW— ktovie, čo je to za kúsok. Nech to krútim akokoľvek, všetko stále funguje. Bol by som rád, keby to niekto vysvetlil.
HAEN— Bit nastavenia výstupu INT. Ak je nastavený, kolík je nakonfigurovaný ako otvorený odtok, ak je bit resetovaný, potom aktívna úroveň na vetve INT určuje bit INTPOL
INTPOL— určuje aktívnu úroveň na úseku INT. Ak je nastavená, aktívna úroveň je jedna, inak nula.

Ešte je trochu HAEN ale v tomto čipe sa nepoužíva (zapína/vypína hardvérové ​​adresovacie kolíky v MCP23S08)

register GPPU
Ovláda vytiahnutie vstupu. Ak je bit nastavený, potom sa na príslušnom kolíku objaví ťah k napájaniu cez 100 kOhm odpor.

register INTF
Register príznakov prerušenia. Ak je bit nastavený, znamená to, že zodpovedajúca vetva portu spôsobila prerušenie. Samozrejme, prerušenia pre požadované úseky musia byť povolené v registri GPINTEN

register INTCAP
Keď dôjde k prerušeniu, celý port sa načíta do tohto registra. Ak je po tomto viac prerušení, tak obsah tohto registra nebude prepísaný novou hodnotou, kým ju alebo GPIO neprečítame.

GPIO register
Pri čítaní údajov z registra čítame logické úrovne na pinoch portu. Pri zaznamenávaní údajov nastavujeme logické úrovne. Pri zápise do tohto registra sa rovnaké údaje automaticky zapisujú aj do registra OLAT

register OLAT
Zapísaním údajov do tohto registra vydáme údaje na port. Ak odtiaľ čítate dáta, budete čítať to, čo bolo zapísané, a nie to, čo je v skutočnosti na vstupoch portu. Na čítanie vstupov používame iba GPIO.

Opis registrov je podľa môjho názoru celkom normálny a nikoho by nemal vyviesť z miery. Teraz si len pre zábavu napíšme malú ukážku, ktorá sa bude pýtať na 4 tlačidlá pripojené k expandéru portov a v závislosti od ich stavu rozsvieti alebo zhasne 4 zodpovedajúce LED diódy pripojené k tomu istému expandéru. Príklad bude čo najjednoduchší, bez akýchkoľvek prerušení. Jednoducho neustále čítame stav tlačidiel a zobrazujeme tento stav na LED diódach. Schéma nášho zariadenia bude vyzerať takto:

Prerušovací kolík nemusí byť pripojený, tu ho nepotrebujeme, ale vyžaduje sa vytiahnutie pre resetovaciu nohu! Strávil som veľa času, kým som si uvedomil, že môj expandér portov bol pravidelne resetovaný kvôli nedostatočnému utiahnutiu. Teraz poďme ku kódu. Samozrejme budeme písať ďalej. Jednoduchý kód:

Program rashiritel; const AdrR=%01000001; //Adresa čipu s načítaným bitom const AdrW=%01000000; //Adresa čipu s bitovým záznamom var r:byte; ///Procedúra zapíše údaje z premennej Dat do registra na adresu Adr Procedure WriteReg(Dat,Adr:byte); Begin TWI_Start(); TWI_Write(AdrW); TWI_Write(Adr); TWI_Write(Dat); TWI_Stop(); Koniec; ///Funkcia vracia hodnotu registra na adrese Adr Function ReadReg(Adr:byte):byte; var a:byte; Begin TWI_Start(); TWI_Write(AdrW); TWI_Write(Adr); TWI_Start(); TWI_Write(AdrR); a:=TWI_Read(0); TWI_Stop(); vysledok:=a; Koniec; begin TWI_INIT(200000); ///Inicializácia i2c WriteReg(%00001111,0x00); //Najnižšie 4 bity sú vstupy a zvyšné 4 bity sú výstupy WriteReg(%00001111,0x06); //Zapnuté pull-up pre 4 vstupy Kým TRUE do Begin r:=ReadReg(0x09); //Prečítajte stav vstupov r:= NOT r; //Je potrebné prevrátiť bity, inak sa po uvoľnení tlačidla rozsvietia LED r:= r shl 4; //Posun o 4 bity doľava... WriteReg(r,0x0A); //Zobrazenie stavu tlačidiel end; koniec.

Zverejnené 26.10.2016

V predchádzajúcom článku sme sa pozreli na fungovanie STM32 so zbernicou I 2 C ako Master. To znamená, že bol vodcom a vypočúval senzor. Teraz urobme zo STM32 Slave a odpovedzme na požiadavky, to znamená, že sám funguje ako senzor. Vyčleníme 255 bajtov pamäte pre registre s adresami od 0 do 0xFF a umožníme Master ich zapisovať/čítať. A aby príklad nebol taký jednoduchý, urobme z nášho STM32 analógovo-digitálny prevodník s rozhraním I 2 C. ADC spracuje 8 kanálov. Kontrolér odovzdá výsledky transformácií Master pri čítaní z registrov. Pretože výsledok konverzie ADC je 12 bitov, potrebujeme 2 registre (2 bajty) pre každý kanál ADC.

i2c_slave.h obsahuje nastavenia:

I2CSLAVE_ADDR– adresa nášho zariadenia;

ADC_ADDR_START– počiatočná adresa registrov, ktoré sú zodpovedné za výsledky konverzií ADC.

V súbore i2c_slave.c nás najviac zaujímajú funkcie get_i2c1_ram A set_i2c1_ram. Funkcia get_i2c1_ram je zodpovedný za čítanie údajov z registrov. Vracia dáta zo zadanej adresy, ktorá je pridelená Masterovi. V našom prípade sa údaje načítajú z poľa i2c1_ram, ale ak Master požiada o adresy registrov z rozsahu prideleného pre výsledky ADC, potom sa odošlú údaje o konverzii ADC.

get_i2c1_ram:

Uint8_t get_i2c1_ram(uint8_t adr) ( //údaje ADC if ((ADC_ADDR_START<= adr) & (adr < ADC_ADDR_START + ADC_CHANNELS*2)) { return ADCBuffer; } else { // Other addresses return i2c1_ram; } }

Funkcia set_i2c1_ram– zapisuje dáta prijaté z Mastera do registrov so zadanou adresou. V našom prípade sa údaje jednoducho zapíšu do poľa i2c1_ram. Ale toto je voliteľné. Môžete napríklad pridať šek a keď príde určité číslo na určitú adresu, vykonať nejaké akcie. Týmto spôsobom môžete posielať rôzne príkazy do mikrokontroléra.

set_i2c1_ram:

Void set_i2c1_ram(uint8_t adr, uint8_t val) (i2c1_ram = val; return; )

Inicializácia je pomerne jednoduchá:

Int main(void) ( SetSysClockTo72(); ADC_DMA_init(); I2C1_Slave_init(); while(1) ( ) )

Najprv nastavíme maximálnu pracovnú frekvenciu regulátora. Maximálna rýchlosť je potrebná, keď sa treba vyhnúť akýmkoľvek oneskoreniam na zbernici I 2 C. Potom spustíme prevádzku ADC pomocou DMA. O . O . A nakoniec inicializujeme zbernicu I 2 C ako Otrok. Ako vidíte, nič zložité.

Teraz pripojíme náš modul STM32 k Raspberry Pi. Pripojme potenciometre ku kanálom ADC. A budeme čítať indikátory ADC z nášho ovládača. Nezabudnite, že aby zbernica I 2 C fungovala, musíte na každú linku zbernice nainštalovať pull-up odpory.

V konzole Raspberry skontrolujte, či je naše zariadenie viditeľné na zbernici I 2 C (o tom):

I2cdetect -y 1

Ako vidíte, adresa zariadenia 0x27, aj keď sme zadali 0x4E. Keď budete mať čas, zamyslite sa nad tým, prečo sa to stalo.

Na čítanie z registrov zariadenia I 2 C-Slave vykonajte príkaz:

I2cget -y 1 0x27 0x00

Kde:
0x27- adresa zariadenia,
0x00– adresa registra (0x00…0xFF).

Ak chcete zapisovať do registrov zariadenia I 2 C-Slave, vykonajte príkaz:

I2cset -y 1 0x27 0xA0 0xDD

De:
0x27- adresa zariadenia,
0xA0– registračná adresa
0xDD-8-bitové dáta (0x00…0xFF)

Predchádzajúci príkaz zapísal do registra číslo 0xDD 0xA0(môžete zapisovať do prvých 16 registrov, ale to nemá zmysel, ale sú vyhradené pre ADC). Teraz si prečítajme:

I2cget -y 1 0x27 0xA0

Aby som zjednodušil proces čítania údajov kanála ADC, napísal som skript:

#!/usr/bin/env python import smbus import time bus = smbus.SMBus(1) adresa = 0x27 while (1): ADC = (); pre i v rozsahu (0, 8): LBS = bus.read_byte_data(adresa, 0x00+i*2) MBS = bus.read_byte_data(adresa, 0x00+i*2+1) ADC[i] = MBS*256 + LBS tlačiť ADC time.sleep(0.2)

Zisťuje a zobrazuje výsledky všetkých 8 kanálov ADC na konzole.

Podobným spôsobom môžete kombinovať niekoľko mikrokontrolérov. Jeden z nich by mal byť Master(), druhý Slave.

Prajem ti úspech!




Hore