STM32, soros I2C interfész. STM32, soros interfész I2C Stm32 interfész i2c leírás folytatása

Van, aki szereti a pitét, van, aki nem.

Az i2c interfész széles körben elterjedt és használatos. Az stm32f4-ben akár három modul is megvalósítja ezt a protokollt.
Természetesen azzal teljes támogatás ezt az egészet.

A modullal való munkavégzés általában ugyanaz, mint más vezérlőknél: parancsokat adsz neki, végrehajtja azokat, és jelentést készít az eredményről:
I> Elmentünk START.
S> Rendben, elküldtem.
Én> Cool, küldd el a címet most. Így: 0xXX.
S> Oké, elküldtem. Azt mondták nekem, hogy ACK. Menjünk tovább.
I> Még élek, jó. Itt a törzsszám: 0xYY, - gyerünk.
S> Elküldve, ACK érkezett.
I> Most küldje el neki az adatokat, itt a bájt: 0xZZ.
S> Elküldve, beleegyezik többbe: ACK.
Bassza meg, még ne. Elmentek STOP.
S> Oké.

És nagyjából minden ebben a szellemben zajlik.

BAN BEN ezt a vezérlőt Az i2c érintkezői így vannak szétszórva a portokon:
PB6: I2C1_SCL
PB7: I2C1_SDA

PB8: I2C1_SCL
PB9: I2C1_SDA

PB10: I2C2_SCL
PB11: I2C2_SDA

PA8: I2C3_SCL
PC9: I2C3_SDA
Általában célszerű megnézni a perifériák kivezetését az 59. oldalon.

Meglepő módon az i2c használatához minden regiszterre szükség van, szerencsére kevés van belőlük:
I2C_CR1- parancsok a modulhoz parancsok/állapotok küldésére és működési módok kiválasztására;
I2C_CR2- DMA beállítása és a modul működési frekvenciájának kijelzése (2-42 MHz);
I2C_OAR1- az eszköz címének beállítása (szolga esetén), címméretének beállítása (7 vagy 10 bit);
I2C_OAR2- az eszköz címének beállítása (ha két cím van);
I2C_DR- adatnyilvántartás;
I2C_SR1- modulállapot regiszter;
I2C_SR2- állapotregiszter (slave, akkor kell olvasni, ha az ADDR vagy a STOPF jelzők be vannak állítva az SR1-ben);
I2C_CCR- az interfész sebességének beállítása;
I2C_TRISE- élek időzítésének beállítása.

A fele azonban „írd le és felejtsd el” típusú.

Az STM32F4-Discovery kártyán már van egy I2C eszköz, amivel lehet gyakorolni: CS43L22, audio DAC. A PB6/PB9 érintkezőkhöz csatlakozik. A lényeg, hogy ne felejtsünk el magas szintet alkalmazni a PD4 lábra (a ~RESET ott van), különben a DAC nem válaszol.

A beállítási eljárás körülbelül a következő:
1 . A portok és maga a modul órajelének engedélyezése.
A PB6/PB9 lábakra van szükségünk, ezért be kell állítanunk az 1. bitet (GPIOBEN) az RCC_AHB1ENR regiszterben a port engedélyezéséhez.
És állítsa be a 21. bitet (I2C1EN) az RCC_APB1ENR regiszterben, hogy engedélyezze az I2C modult. A második és harmadik modul bitszáma 22, illetve 23.
2 . Ezután a tűk konfigurálva vannak: Oped Drain kimenet (GPIO->OTYPER), alternatív működési mód (GPIO->MODER) és alternatív funkciószám (GPIO->AFR).
Igény szerint konfigurálhat egy felhúzást (GPIO->PUPDR), ha az nincs a táblán (és mindkét vonal tápellátására való felhúzás bármilyen formában szükséges). Az I2C száma mindig ugyanaz: 4. Jó, hogy minden perifériatípushoz külön szám tartozik.
3 . Az Fpclk1 periféria aktuális órajel-frekvenciája (MHz-ben kifejezve) a CR2 regiszterben van feltüntetve. Ha jól értem, erre a különböző protokollidőzítések kiszámításához van szükség.
Egyébként normál módhoz legalább kettőnek, gyors módhoz pedig legalább négynek kell lennie. Ha pedig 400 kHz-es teljes sebességre van szüksége, akkor azt is el kell osztani 10-zel (10, 20, 30, 40 MHz).
Maximális megengedett órajel: 42 MHz.
4 . Az interfész sebessége a CCR regiszterben van konfigurálva, és a mód van kiválasztva (normál/gyors).
A jelentése: Tsck = CCR * 2 * Tpckl1, azaz. az SCK periódus arányos a CCR-rel (a gyors módnál minden kicsit bonyolultabb, de az RM-ben le van írva).
5 . A TRISE regiszterben a maximális felfutó él ideje be van állítva. Normál módban ez az idő 1 µs. A regiszterbe be kell írni az ebbe az időbe beleférő buszciklusok számát, plusz egyet:
ha a Tpclk1 ciklus 125 ns-ig tart, akkor írjon (1000 ns / 125 ns) + 1 = 8 + 1 = 9.
6 . A megszakítási jelek (hiba, állapot és adatok) generálása opcionálisan engedélyezett;
7 . A modul bekapcsol: a CR1 regiszter PE jelzője 1-re van állítva.

Ezután a modul úgy működik, ahogy kell. Csak a parancsok helyes sorrendjét kell végrehajtania, és ellenőriznie kell az eredményeket. Például egy nyilvántartási bejegyzés:
1 . Először a START parancsot kell küldenie egy azonos nevű zászló beállításával a CR1 regiszterben. Ha minden rendben van, akkor egy idő után az SB flag be lesz állítva az SR1 regiszterben.
Egy dolgot szeretnék megjegyezni - ha nincs felhúzás a vonalon (és 0-nál vannak), akkor ez a zászló egyáltalán nem várhat.
2 . Ha megérkezik a zászló, akkor elküldjük a címet. Egy hétbites címet egyszerűen csak úgy írjuk DR-be, ahogy a sorban lesz (7 címbit + iránybit). Tízbites esetén egy bonyolultabb algoritmus.
Ha a készülék ACK-vel válaszol a címre, akkor az SR1 regiszterben megjelenik az ADDR jelző, ha nem, akkor az AF (Acknowledge error) jelző.
Ha megjelenik az ADDR, akkor be kell olvasnia az SR2 regisztert. Ott nem kell semmit nézni, csak az SR1 és SR2 szekvenciális leolvasása visszaállítja ezt a jelzőt. És amíg a jelző be van állítva, az SCL-t alacsonyan tartja a master, ami akkor hasznos, ha meg kell kérnie a távoli eszközt, hogy várjon az adatok küldése előtt.
Ha minden rendben van, akkor a modul az elküldött cím legkisebb jelentőségű bitjétől függően átkapcsol adatfogadási vagy átviteli módba. Íráshoz nullának, olvasáshoz egynek kell lennie.
de nézzük a rekordot, tehát feltételezzük, hogy ott egy nulla volt.
3 . Ezután elküldjük a minket érdeklő nyilvántartás címét. Ugyanígy leírva a DR. Az átvitel után a TXE (az átviteli puffer üres) és a BTF (átvitel befejeződött) jelzők be vannak állítva.
4 . Ezután jönnek az elküldhető adatok, miközben a készülék ACK-vel válaszol. Ha a válasz NACK, akkor ezek a jelzők nem lesznek beállítva.
5 . Az átvitel befejeztével (vagy váratlan feltétel esetén) STOP-ot küldünk: a CR1 regiszterben az azonos nevű zászlót állítjuk be.

Olvasáskor minden a régi. Változás csak a regisztrációs cím megírása után történik.
Adatírás helyett újra START (újraindítás) kerül elküldésre, és a cím a legkisebb jelentőségű bitkészlettel (olvasott jel) kerül elküldésre.
A modul adatokat vár az eszközről. Ahhoz, hogy a következő bájtokat küldje, be kell állítania az ACK jelzőt a CR1-ben a fogadás előtt (hogy a fogadás után a modul ugyanazt az ACK-t küldje).
Ha megunta, távolítsa el a zászlót, a készülék NACK-t fog látni és elhallgat. Ezt követően a szokásos módon STOP-ot küldünk, és örülünk a kapott adatoknak.

Itt ugyanaz, kód formában:
// A modul inicializálása void i2c_Init(void) ( uint32_t Clock = 16000000UL; // Modul órajel-frekvencia (a system_stm32f4xx.c nincs használatban) uint32_t Sebesség = 100000UL; // ROB-port 100 kHB CC EN 100 kHB |= RCC_AHB1ENR_GPIOBEN; // PB6, PB9 tűk beállítása // Nyissa ki a lefolyót! GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_9; // A felhúzás külső, ezért itt nem konfigurálható! // Ha szükséges, lásd a GPIOB->PUPDR regisztert // Az alternatív GPIOB függvény száma ->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->MODER &= ~((0x03UL<< (6 * 2)) | (0x03UL << (9 * 2))); // 6, 9 очистим GPIOB->MODER |= ((0x02UL<< (6 * 2)) | (0x02UL << (9 * 2))); // В 6, 9 запишем 2 // Включить тактирование модуля I2C1 RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; // Ezen a ponton az I2C-t ki kell kapcsolni // Minden visszaállítása (SWRST == 1, reset) I2C1->CR1 = I2C_CR1_SWRST; // PE == 0, ez a fő I2C1->CR1 = 0; // Feltételezzük, hogy RC-ről futunk (16 MHz) // Az órarendszerben nincsenek előskálázók (mind 1) // Békés módon mindezt a modul aktuális órajeléből kell kiszámítanunk // I2C1->CR2 = Óra / 1000000UL; // 16 MHz // A frekvencia beállítása ( // Tclk = (1 / Fperiph); // Thigh = Tclk * CCR; // Tlow = comb; // Fi2c = 1 / CCR * 2; // CCR = Fperiph // ( Fi2c * 2); uint16_t Érték = (uint16_t) (Óra / (Sebesség * 2)); // Minimális érték: 4 if(Érték< 4) Value = 4; I2C1->CCR = érték; ) // Állítsa be a határérték emelkedési idejét // Normál módban ez az idő 1000 ns // Egyszerűen hozzáadunk egyet a MHz-ben kifejezett frekvenciához (lásd RM 604. oldal). I2C1->TRISE = (Óra / 1000000UL) + 1; // I2C1->CR1 modul engedélyezése |= (I2C_CR1_PE); // Most már tehetsz valamit ) // Bájtos bool küldése i2c_SendByte(uint8_t Address, uint8_t Register, uint8_t Data) ( if(!i2c_SendStart()) return false; // Chip cím if(!i2c_SendAddress(Address)) returnSi (); // Cím regisztrálása if(!i2c_SendData(Register)) return i2c_SendStop(); // Data if(!i2c_SendData(Data)) return i2c_SendStop(); // Stop! i2c_SendStop(); return true; ) // Receive byte bool i2c_ReceiveByte(uint8_t cím, uint8_t Regiszter, uint8_t * Data) ( if(!i2c_SendStart()) return false; // Chip cím if(!i2c_SendAddress(Address)) return i2c_SendStop(); // Cím regisztrálása if(! i2c_SendData(Register)) return i2c_SendStop(); // Újraindítás if(!i2c_SendStart()) return false; // Chipcím (olvasás) if(!i2c_SendAddress(Address | 1)) return i2c_SendStop(); // Bájt fogadása if(!i2c_ReceiveData(Data)) return i2c_SendStop(); // Stop! i2c_SendStop(); return true; ) Használat: ( uint8_t ID = 0; i2c_Init(); // Feltételezzük, hogy a PD4 magas szintre van állítva és a DAC működik (ezt valahogy meg kell tenni) // Küldj egy bájtot a 0x94 című eszközre, hogy a 0x00-at 0x00 értékkel regisztrálja. i2c_SendByte(0x94, 0x00, 0x00); // Egy bájt fogadása a 0x94 címmel rendelkező eszközről a 0x01 (ID) regiszterből az i2c_ReceiveByte(0x94, 0x01, &ID) változó pufferbe; )
Természetesen ezt nem teheti meg, kivéve egy képzési példában. A művelet befejezésére várni túl hosszú egy ilyen gyors vezérlő számára.

(Fejlesztői útmutató a HCS08 család mikrovezérlőihez)

Az I2C modul vezérléséhez 6 speciális funkcióregisztert használnak:

  • IICC - az I2C modul első vezérlőregisztere;
  • IICC2 - az I2C modul második vezérlőregisztere;
  • IICS - I2C modul állapotregiszter;
  • IICF - I2C modul adatátviteli sebesség regiszter;
  • IICA - I2C modul címregiszter;
  • Az IICD az I2C modul adatregisztere.

A QE sorozatú MCU 2 db I2C modult és ennek megfelelően minden típusból két vezérlőregisztert tartalmaz. Például az első állapotregiszter az IIC1S, a második állapotregiszter az IIC2S.

11.2.8.1. IICC vezérlőregiszter

MK sorozatú AC-hoz. AW, Dx, EL, GB, GT, JM, LC, QE. Q.G. SG, SH, SL
Regisztráció Mód D7 D6 D5 D4 D3 D2 D1 D0
IICC Olvasás IICEN IICIE MST TX TXAK 0 0 0
Rekord RSTA
Visszaállítás 0 0 0 0 0 0 0 0
Bitek leírása:
Bit név Leírás Szimbólum C nyelven
IICEN I2C modul engedélyező bit:
0 — az I2C vezérlő le van tiltva;
1 - Az I2C vezérlő engedélyezve van.
bIICEN
IICIE Modulmegszakítás engedélyező bit az I2C-ből:
0 - Az I2C kérés megszakítások le vannak tiltva;
1 – Az I2C kérés megszakítások engedélyezve vannak.
bHCIE
MST I2C vezérlő üzemmódválasztó bit:
0 - az I2C vezérlő Slave módban működik;
1 - Az I2C vezérlő Master módban működik.
Amikor ez a bit 0-ról 1-re változik, a rendszer egy Start állapotot generál. Fordítva, amikor egy bit 1-ről 0-ra változik, egy Stop feltétel generálódik.
bMST
TX Átviteli irány kiválasztó bit az SDA adatvonalon:
0 — a sor bemenetre működik;
1 - sor működik a kimenetre.
bTX
TXAK Nyugtázó bit fogadási módban:
0 - egy nyugtázó bit generálódik egy bájt fogadása után;
1 - egy bájt nyugtázatlan bit jön létre.
Ez a bit vezérli a nyugtázó bit generálását egy adatbájt fogadása után, függetlenül attól, hogy az egy slave vagy egy mester.
bTXAK
RSTA Ha az I2C modul mester módban működik, akkor erre a bitre 1-est írva a Start - „Újraindítás” állapot újragenerálódik. bRSTA

11.2.8.2. IICS állapotnyilvántartás

MK sorozathoz AC, AW, Dx, EL, GB, GT, JM, LC, QE, QG, SG, SH, SL
Regisztráció Mód D7 D6 D5 D4 D3 D2 D1 D0
IICS Olvasás TCF IAAS ELFOGLALT ARBL 0 SRW IICIF RXAK
Rekord
Visszaállítás 0 0 0 0 0 0 0 0
Bitek leírása:
Bit név Leírás Szimbólum C nyelven
TCF Csere befejező bit. Állítsa be, miután egy bájt cseréje befejeződött:
0 – a csere nem fejeződött be;
1 - csere befejeződött.
A TCF jelző 0-ra törlődik, amikor az IICD adatregisztert olvassák (vételi módban), vagy amikor az IICD adatregisztert írják (adási módban).
bTCF
IAAS Slave cím jelző. Állítsa be, hogy az eszköz szolga üzemmódban üzemel, és a master üzenetben továbbított cím megegyezik az IICA címregiszterben tárolt slave címmel.
A zászló törlődik, amikor az IICC regiszterbe ír.
bIAAS
ELFOGLALT Foglalt vonal zászló. Ez a jelző akkor van beállítva, ha az I2C modul felismerte a vonal kezdőbitjét. A jelző törlődik, ha a modul stopbitet észlel a vonalon.
0 — az I2C busz szabad;
1 - Az I2C busz foglalt.
bBUSY
ARBL Választottbírósági veszteségjelző:
0 - nincs szabálysértés az I2C busz működésében;
1 – a választottbíróság elveszett. Az I2C modulnak várnia kell egy ideig, majd újra kell kezdenie az átviteli műveletet.
BARBL
SRW Slave átviteli irány bit. Ez a bit jelzi az R/W bit állapotát a címmezőben:
0 - rabszolga elfogadja. A vezető továbbítja a rabszolgának;
1 - slave ad. A vezető a rabszolgától kap.
bSRW
IICIF Kiszolgálatlan megszakítási kérelmek jelzője az I2C modulhoz. Állítsa 1-re, ha az egyik jelző be van állítva: TCF, IAAS vagy ARBL.
0 - nincs szolgáltatás nélküli megszakítás;
1 - szolgáltatás nélküli megszakítások vannak.
A zászlót úgy állítjuk vissza, hogy 1-et írunk rá.
bIICIF
RXAK Master nyugtázó bit:
0 – szolga megerősítette az adatok fogadását;
1 — a slave nem nyugtázta az adatvételt.
Ez a bit tükrözi az ASK mező állapotát a csere időzítési diagramján.
bRXAK

11.2.8.3. IICA címregiszter

Regisztráció Mód D7 D6 D5 D4 D3 D2 D1 D0
IICA Olvasás CÍM
Rekord
Visszaállítás 0 0 0 0 0 0 0 0

Ez a regiszter tárolja a fejlesztő által hozzárendelt 7 bites slave címet ez az eszköz a rendszer fejlesztése során. Ezt a címet a rendszer automatikusan összehasonlítja azzal a címkóddal, amelyet a slave kapott az I2C buszon a címmezőben. Ha a címek megegyeznek, az IICS állapotregiszter IAAS bitje be van állítva.

11.2.8.4. IICF adatátviteli sebesség nyilvántartás

MK sorozathoz AC, AW, Dx, EL,GB, GT, JM, LC, QE, QG, SG, SH, SL
Regisztráció Mód D7 D6 D5 D4 D3 D2 D1 D0
IICF Olvasás MULT ICR
Rekord
Visszaállítás 0 0 0 0 0 0 0 0
Bitek leírása:

Az SCL_DIV és SDA_HV együtthatók értékei

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

Ez a regiszter két bitmezőt tárol, amelyek meghatározzák az I2C csere sebességét és időzítési paramétereit. A szinkronizációs jelek frekvenciáját a következő képlet határozza meg:

Az SDA_hold_time adatbeállítási idő az I2C buszon az az időintervallum, amely az SCL jel 0-ra állításának pillanata és az SDA vonalon lévő adatok változása között eltelt. A táblázatból az SDA_HV (SDA_Hold_Value) paraméterrel hozzárendelve az adatátviteli sebességregiszter ICR-tényezőjéhez:

.

11.2.8.5. IICD adatnyilvántartás

MK sorozathoz AC, AW, Dx, EL,GB, GT, JM, LC, QE, QG, SG, SH, SL
Regisztráció Mód D7 D6 D5 D4 D3 D2 D1 D0
IICD Olvasás I2C ADATOK
Rekord
Visszaállítás 0 0 0 0 0 0 0 0

Ha az I2C modul master módban működik, akkor egy írási művelet ebbe a regiszterbe kezdeményez I2C kommunikációt (de csak akkor, ha az IICC vezérlőregiszterben a kommunikációs irány bitje helyesen van beállítva, azaz TX = 1). A Start állapot utáni első bájtot, amit a program az adatregiszterbe ír, a slave-ek eszközcímként értelmezik. Ezért a programnak helyesen kell alkotnia az első bájt tartalmát. A regiszterolvasási művelet az I2C-n keresztül kapott utolsó bájtot adja vissza. A regiszter olvasási művelete kezdeményezi a következő bájt vételének megkezdését is, de csak akkor, ha az IICC vezérlőregiszterben a kommunikációs irány bitje helyesen van beállítva, pl. TX = 0-nál! TX = 1 esetén a regiszter olvasási művelet nem okoz új bájt fogadását I2C-n keresztül a slave-től.

Ha az I2C modul slave módban működik, akkor az ebbe a regiszterbe írt adatok az I2C busz SDA vonalára kerülnek átvitelre, amikor a master eszköz vételi ciklust hajt végre ettől a slave-től. A regiszter olvasási művelete a mestertől kapott utolsó bájtot adja vissza.

11.2.8.6. IICC2 vezérlőregiszter

MK sorozathoz AC, Dx, EL, JM, QE, SG, SH, SL
Regisztráció Mód D7 D6 D5 D4 D3 D2 D1 D0
IICC Olvasás GCAEN ADEXT 0 0 0 AD10 AD9 AD8
Rekord
Visszaállítás 0 0 0 0 0 0 0 0

Első lépések az STM32 és mikroC fordítóval az ARM architektúrához – 4. rész – I2C, pcf8574 és HD4478 alapú LCD csatlakozás

A következő cikket a közös i2c interfésszel való munkának szeretném szentelni, amelyet gyakran használnak a mikrokontrollerhez csatlakoztatott különféle mikroáramkörökben.

Az I2C egy olyan busz, amely két fizikai kapcsolaton keresztül működik (a közös vezetéken kívül). Elég sokat írnak róla az interneten, vannak jó cikkek a Wikipédián. Ezenkívül a busz működési algoritmusa nagyon világosan le van írva. Röviden, a busz egy kétvezetékes szinkron busz. Egyszerre legfeljebb 127 eszköz lehet a buszon (az eszköz címe 7 bites, erre később visszatérünk). Az alábbiakban egy tipikus diagram látható az eszközöknek az i2c buszhoz való csatlakoztatására, ahol az MK a fő eszköz.


Az i2c esetében minden eszköz (mester és slave) nyitott kimenetet használ. Egyszerűen fogalmazva, CSAK a FÖLDRE tudják vonzani az abroncsot. A magas buszszintet felhúzó ellenállások biztosítják. Ezen ellenállások értékét általában 4,7 és 10 kOhm közötti tartományban választják ki. Az i2c meglehetősen érzékeny az eszközöket összekötő fizikai vonalakra, így ha nagy kapacitású kapcsolatot használnak (például hosszú vékony vagy árnyékolt kábelt), akkor ennek a kapacitásnak a hatása „elmoshatja” a jel széleit és zavarhatja a jelet. normál működés gumiabroncsok. Minél kisebb a felhúzó ellenállás, ez a kapacitás annál kisebb hatással van a jelélek jellemzőire, de annál NAGYOBB TERheli az i2c interfészek kimeneti tranzisztorait. Ezeknek az ellenállásoknak az értékét minden egyes megvalósításhoz kiválasztják, de nem lehetnek kisebbek 2,2 kOhm-nál, különben egyszerűen égetheti a kimeneti tranzisztorokat a busszal működő eszközökben.

A busz két vonalból áll: SDA (adatvonal) és SCL (órajel). Órajelzi a busz Master eszközt, általában a mi MK. Ha az SCL magas, az információ az adatbuszról kerül kiolvasásra. Az SDA állapot csak alacsony órajel esetén módosítható.. Ha az SCL magas, az SDA jele megváltozik a jelek generálásakor RAJT (ha az SCL magas, az SDA jele magasról alacsonyra változik) és ÁLLJ MEG - ha az SCL szint magas, az SDA jele alacsonyról magasra változik).

Külön meg kell mondani, hogy az i2c-ben a cím 7 bites számként van megadva. 8 - a legkisebb jelentőségű bit az adatátvitel irányát jelzi 0 - azt jelenti, hogy a slave adatokat küld, 1 - fogad.. Röviden, az i2c-vel való munka algoritmusa a következő:

  • Magas szintű SDA és SCL- a busz ingyenes, lehet dolgozni
  • Mester liftek SCL 1-re, és megváltoztatja az állapotot S.D.A. 1-től 0-ig - vonzza a talajhoz - jel keletkezik RAJT
  • A master egy 7 bites slave címet továbbít egy iránybittel (adatok be S.D.A. mikor kerülnek kiállításra SCL a földre húzva, és a rabszolga elolvassa, amikor elengedi). Ha a slave-nek nincs ideje „megragadni” az előző bitet, akkor vonzza SCL a földre, világossá téve a mester számára, hogy az adatbusz állapotát nem kell megváltoztatni: "Még olvasom az előzőt." Miután a mester elengedte a gumit, ellenőrzi a rabszolga elengedte?.
  • A 8 bit cím továbbítása után a master generálja a 9. órajelet és felszabadítja az adatbuszt. Ha a rabszolga meghallotta a címét, és elfogadta, akkor ő meg fogja nyomni S.D.A. a földre. Így jön létre a jel KÉRDEZ- elfogadva, minden rendben. Ha a rabszolga nem ért semmit, vagy egyszerűen nincs ott, akkor nem lesz senki, aki megnyomja a gumit. a mester megvárja az időtúllépést, és megérti, hogy nem értették meg.
  • A cím továbbítása után, ha beállítottuk az irányt mestertől rabszolgáig(a cím 8 bitje egyenlő 1-gyel), majd a master továbbítja az adatokat a slave-nek, nem felejtve el ellenőrizni a KÉRDEZ a slave-től, várja, hogy a szolga eszköz feldolgozza a bejövő információkat.
  • Amikor a master adatokat kap a slave-től, a master maga generál egy jelet KÉRDEZ minden bájt fogadása után, és a slave vezérli a jelenlétét. A mester nem küldhet konkrétan KÉRDEZ a parancs elküldése előtt ÁLLJ MEG, általában egyértelművé téve a slave számára, hogy nincs szükség további adatok megadására.
  • Ha a master általi adatküldés (írási mód) után adatokat kell kiolvasni a slave-ről, majd a master újra generálja a jelet RAJT , elküldi a slave címet olvasási jelzővel. (ha a parancs előtt RAJT nem került átadásra ÁLLJ MEG akkor alakul egy csapat ÚJRAKEZD). Ez a mester-szolga kommunikáció irányának megváltoztatására szolgál. Például átadjuk a regiszter címét a slave-nek, majd kiolvasunk belőle adatokat.)
  • A slave-vel végzett munka befejeztével a master jelet generál ÁLLJ MEG- az órajel magas szintjén adatbusz-átmenetet képez 0-ról 1-re.
Az STM 32 hardveresen megvalósított i2c busz adó-vevőkkel rendelkezik. Egy MK-ban 2 vagy 3 ilyen modul lehet, ezek konfigurálásához speciális regisztereket használnak, amelyeket a használt MK hivatkozásában ismertetnek.

MicroC-ben az i2c (valamint minden periféria) használata előtt megfelelően inicializálni kell. Ehhez a következő függvényt használjuk (Inicializálás mesterként):

I2Cn_Init_Advanced(előjel nélküli hosszú: I2C_ClockSpeed, const Module_Struct *modul);

  • n- például a használt modul száma I2C1 vagy I2C2.
  • I2C_ClockSpeed- buszsebesség, 100000 (100 kbs, normál mód) vagy 400000 (400 kbs, gyors mód). A második négyszer gyorsabb, de nem minden eszköz támogatja
  • *modul- mutasson például egy periféria modulra &_GPIO_MODULE_I2C1_PB67, ne felejtsük itt el azt Kódasszisztens (ctrl-space ) sokat segít.
Először nézzük meg, hogy a busz szabad-e, van erre funkció I2Cn_Is_Idle(); 1-et ad vissza, ha szabad a busz, és 0-t, ha csere van rajta.

I2Cn_Start();
Ahol n- mikrokontrollerünk használt i2c moduljának száma. A függvény 0-t ad vissza, ha hiba van a buszon, és 1-et, ha minden rendben van.

Az adatok szolgának való átviteléhez a következő funkciót használjuk:

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

  • n- a használt modul száma
  • rabszolga_cím- 7 bites slave cím.
  • *buf- egy mutató az adatainkra - egy bájt vagy bájttömb.
  • számol- az átvitt adatbájtok száma.
  • END_mód- mi a teendő az adatok szolgának történő átvitele után, END_MODE_STOP - jelet továbbítani ÁLLJ MEG, vagy END_MODE_RESTART Küldd újra RAJT, jelet generál ÚJRAKEZDés világossá téve az osztálynak, hogy a vele való foglalkozás még nem ért véget, és most adatokat olvasnak ki tőle.
Adatok olvasásához a slave-től használja a következő funkciót:

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

  • n- a használt modul száma
  • rabszolga_cím- 7 bites slave cím.
  • *buf- egy mutató egy változóra vagy tömbre, amelybe adatokat kapunk, írjuk be, hogy char vagy short int
  • számol- a fogadott adatbájtok száma.
  • END_mód- mit kell tenni a slave-től kapott adatok után - END_MODE_STOP - jelet továbbítani ÁLLJ MEG, vagy END_MODE_RESTART jelet küldeni ÚJRAKEZD.
Próbáljunk meg valamit összekötni az MK-nkkal. Először is: a széles körben elterjedt PCF8574(A) mikroáramkör, amely az i2c buszon keresztül vezérelt bemeneti/kimeneti portok bővítője. Ez a chip csak egy belső regisztert tartalmaz, ez a fizikai I/O portja. Vagyis ha átadsz neki egy bájtot, az azonnal ki lesz téve a következtetéseinek. Ha egy bájtot számolsz belőle (Transmit RAJT cím olvasási zászlóval, jelzéssel REESTERT, olvassa el az adatokat, és végül jelet generál ÁLLJ MEG), akkor a kimenetein tükrözi a logikai állapotokat. Csatlakoztassuk a mikroáramkörünket az adatlapnak megfelelően:


A mikroáramkör címe a tűk állapotából alakul ki A0, A1, A2. Mikroáramkörhöz PCF8574 a cím a következő lesz: 0100A0A1A2. (Például nálunk az A0, A1, A2 magas szinten van, így a mikroáramkörünk címe 0b0100 lesz 111 = 0x27). Mert PCF8574A - 0111A0A1A2, amely a csatlakozási rajzunkkal a 0b0111 címet adja 111 = 0x3F. Ha mondjuk az A2 földelve van, akkor a cím PCF8574A akarat 0x3B. Összesen 16 mikroáramkör szerelhető egyidejűleg egy i2c buszra, egyenként 8 PCF8574A és PCF8574.

Próbáljunk meg valamit átvinni, inicializálni az i2c buszt és átvinni valamit a PCF8574-ünkre.

#define PCF8574A_ADDR 0x3F //PCF8574-ünk címe void I2C_PCF8574_WriteReg(unsigned char wData) ( I2C1_Start(); // START jel generálása I2C1_Write(PCF8574A_ADDR,&wDaEND átvitele a /by_,/1,&wDa) adatok STOP jel) char PCF8574A_reg ; // a PCF8574-ben írt változó void main () ( I2C1_Init_Advanced(400000, &_GPIO_MODULE_I2C1_PB67); // Indítsa el az I2C delay_ms(25); // Várjon egy kicsit PCF8574A_reg.b0 az első LED világít 0; //.8b7 = 1; // kapcsolja ki a második LED-et, miközben (1) ( delay_ms(500); PCF8574A_reg.b0 = ~PCF8574A_reg.b0; PCF8574A_reg.b1 = ~PCF8574A_reg.b1; // megfordítja a LED-ek állapotát I2C_WFrite85A (4F_WFrite857) ; // adatok átvitele PCF8574-ünkre ) )
Lefordítjuk és lefuttatjuk a programunkat, és látjuk, hogy a LED-jeink felváltva villognak.
Valamiért csatlakoztattam a LED-ek katódját a PCF8574-ünkhöz. Az a helyzet, hogy ha logikai 0-t adunk a kimenetre, akkor a mikroáramkör őszintén lehúzza a kimenetét a földre, de ha logikai 1-est adunk, akkor 100 μA áramforráson keresztül a + tápra kapcsolja. Vagyis a kimeneten nem lehet „becsületes” logikai 1-et kapni. És nem gyújthat be 100 µA-es LED-et. Ez azért történt, hogy a PCF8574 kimenetet a bemenetre konfigurálják további regiszterek nélkül. Egyszerűen az 1. kimeneti regiszterbe írunk (lényegében Vdd-re állítva a lábak állapotát), és egyszerűen rövidre zárhatjuk a testtel. Az áramforrás nem engedi, hogy az I/O bővítőnk kimeneti fokozata „kiégjen”. Ha a lábat a földre húzzuk, akkor rajta van a talajpotenciál, és a logikai 0 beolvasásra kerül. Ha a lábat +-ra húzzuk, akkor a logikai 1 lesz beolvasva.Egyrészt egyszerű, de másrészt ezt mindig emlékeznie kell, amikor ezekkel a mikroáramkörökkel dolgozik.


Próbáljuk leolvasni a bővítő chipünk érintkezőinek állapotát.

#define PCF8574A_ADDR 0x3F //A PCF8574-ünk címe void I2C_PCF8574_WriteReg(unsigned char wData) ( I2C1_Start(); // A START jel generálása I2C1_Write(PCF8574A_ADDR, &wDaEND átvitele a /byte_,/1, &wPta data); STOP signal) void I2C_PCF8574_ReadReg (előjel nélküli char rData) ( I2C1_Start(); // A START jel generálása I2C1_Read(PCF8574A_ADDR, &rData, 1, END_MODE_STOP); // Olvasson 1 bájtnyi adatot, és generálja a PCF_5 jelet. //változó, amit a PCF8574 char-ba írunk PCF8574A_out; // az általunk beolvasott változó és a PCF8574 char lad_state; //a LED-ünk be vagy ki van kapcsolva void main () ( I2C1_Init_Advanced(400000, &_GPIO_MODULE_I2C1_PB67); // Indítsa el az I2C delay_ms(25); // Várjon egy kicsit PCF8574A_reg.b0 = 0; // világítsa meg az első LED-et PCF8.5b7 1; / / kapcsolja ki a második LED-et PCF8574A_reg.b6 = 1; // Húzza ki a 6-os és 7-es érintkezőket a tápellátáshoz. PCF8574A_reg.b7 = 1; while (1) ( delay_ms(100); I2C_PCF8574_WriteReg (PCF8574A_reg); // write data PCF8574-be I2C_PCF8574_ReadReg (PCF8574 A_out ); // olvasás a PCF8574-ből if (~PCF8574A_out.b6) PCF8574A_reg.b0 = ~PCF8574A_reg.b0; // Ha a PCF 1. 4. bitje meg van nyomva a 7. kapcsolja be/ki a LED-ünket, ha (~PCF8574A_out .b7) PCF8574A_reg.b1 = ~PCF8574A_reg.b1; // hasonló 2 gombhoz és 2 LED-hez ) )
Most a gombok megnyomásával kapcsoljuk be vagy ki a LED-ünket. A mikroáramkörnek van egy másik kimenete INT. Egy impulzus generálódik rajta minden alkalommal, amikor az I/O bővítőnk lábainak állapota megváltozik. Az MK külső megszakítási bemenetéhez csatlakoztatva (a következő cikkek egyikében elmondom, hogyan kell konfigurálni a külső megszakításokat és hogyan kell velük dolgozni).

A portbővítőnkkel csatlakoztassunk rajta egy karakteres kijelzőt. Ezekből nagyon sok van, de szinte mindegyik vezérlő chipre épül HD44780és a klónjai. Én például egy LCD2004-es kijelzőt használtam.


A hozzá és a HD44780 vezérlőhöz tartozó adatlap könnyen megtalálható az interneten. Csatlakoztassuk a kijelzőnket a PCF8574-hez, az övét pedig az STM32-höz.

HD44780 párhuzamos kapuzott interfészt használ. Az adatátvitel 8 (egy órajelben) vagy 4 (2 órajelben) kapuimpulzussal történik a kimeneten E. (a kijelző vezérlője leolvasó élen, átmenet 1-ről 0-ra). Következtetés R.S. jelzi, hogy küldünk-e adatokat a kijelzőnkre ( RS = 1) (a megjelenítendő karakterek valójában ASCII kódok) vagy a ( RS = 0). RW az adatátvitel, írás vagy olvasás irányát jelzi. Általában adatokat írunk a kijelzőre, így ( RW=0). Az R6 ellenállás szabályozza a kijelző kontrasztját. Nem csatlakoztathatja egyszerűen a kontrasztbeállító bemenetet a földhöz vagy a tápellátáshoz, különben nem fog látni semmit.. A VT1 a kijelző háttérvilágításának be- és kikapcsolására szolgál az MK parancsoknak megfelelően. A MicroC-nek van egy könyvtára az ilyen kijelzőkkel párhuzamos interfészen keresztül történő munkavégzéshez, de általában drága 8 lábat költeni egy kijelzőre, így szinte mindig a PCF8574-et használom az ilyen képernyőkkel való munkához. (Ha valakit érdekel, írok egy cikket a MicroC-be épített HD44780 alapú kijelzőkkel való munkavégzésről párhuzamos interfészen keresztül.) A csereprotokoll nem különösebben bonyolult (4 adatvonalat fogunk használni, és 2 óraciklusban továbbítjuk az információkat), ezt jól mutatja a következő időzítési diagram:


Mielőtt adatokat továbbítana a kijelzőnkre, szervizparancsok átadásával inicializálni kell. (az adatlapon le van írva, itt csak a leggyakrabban használtakat mutatjuk be)

  • 0x28- kommunikáció az indikátorral 4 vonalon keresztül
  • 0x0C- engedélyezze a képkimenetet, tiltsa le a kurzor megjelenítését
  • 0x0E- engedélyezze a képkimenetet, engedélyezze a kurzor megjelenítését
  • 0x01- törölje a kijelzőt
  • 0x08- letiltja a képkimenetet
  • 0x06- a szimbólum megjelenése után a kurzor 1 ismerős hellyel mozog
Mivel gyakran kell dolgoznunk ezzel az indikátorral, létrehozunk egy beépülő modul könyvtárat "i2c_lcd.h" . Ehhez be Projekt menedzser Fejléc fájlok és válassz Új fájl hozzáadása . Hozzuk létre a fejléc fájlunkat.

#define PCF8574A_ADDR 0x3F //PCF8574-ünk címe #define DB4 b4 // Megfelelés a PCF8574 lábak és a jelző között #define DB5 b5 #define DB6 b6 #define DB7 b7 #define EN b3 #define RW b1 BL b0 // háttérvilágítás vezérlése #define dislenth 20 // karakterek száma a kijelzőnkban static unsigned char BL_status; // a háttérvilágítás állapotát tároló változó (be/ki) void lcd_I2C_Init(void); // Megjelenítés és PCF8574 inicializálási függvény void lcd_I2C_txt(char *pnt); // Szövegsort jelenít meg, a paraméter egy mutató erre a sorra void lcd_I2C_int(int pnt); // Egy egész változó értékét jeleníti meg, a paraméter a kimeneti érték void lcd_I2C_Goto(unsigned short row, unsigned short col); // a kurzort a megadott pozícióba mozgatja, paraméterek sora - sor (1-től 2-ig vagy 4-ig a kijelzőtől függően) és col - (1-től kiesőig) void lcd_I2C_cls(); // Törli a képernyőt void lcd_I2C_backlight (unsigned short int state); // Engedélyezi (1 adáskor és letiltja - 0 adáskor a kijelző háttérvilágítását)
Most írjuk le a funkcióinkat, és ismét rátérünk Projekt menedzser kattintson jobb gombbal a mappára Források és válassz Új fájl hozzáadása . Hozzon létre egy fájlt "i2c_lcd.c" .

#include "i2c_lcd.h" //include fejlécfájlunk char lcd_reg; //ideiglenes tárolási regiszter a PCF8574-nek küldött adatokhoz void I2C_PCF8574_WriteReg(unsigned char wData) //függvény adatküldéshez i2c-n keresztül a PCF8574 chipre ( I2C1_Start(); I2C1_Write(LCF8574A_ADDR,&wDachar) (LCF8574A_ADDR,&wDachar) com) / /parancs küldésének funkciója a kijelzőnkre (lcd_reg = 0; //0-t írjon az ideiglenes regiszterbe lcd_reg.BL = BL_status.b0; //beállítja a háttérvilágítás tűjét a háttérvilágítást tároló változó értékének megfelelően állapot lcd_reg.DB4 = com.b4; // a parancsunk 4 legjelentősebb bitjét állítsa be az indikátor adatbuszra: lcd_reg.DB5 = com.b5; lcd_reg.DB6 = com.b6; lcd_reg.DB7 = com.b7; lcd_reg .EN = 1; //állítsa be a villogó kimenetet 1-re I2C_PCF8574_WriteReg ( lcd_reg); //írjon a PCF8574 regiszterbe, ténylegesen adatokat küldjön a delay_us (300) jelzőnek; //várjon az időtúllépésre lcd_reg.EN = 0; // állítsa vissza a villogó impulzust 0-ra, a jelző beolvassa az adatokat I2C_PCF8574_WriteReg (lcd_reg); delay_us (300) ; lcd_reg = 0; lcd_reg.BL = BL_status.b0; lcd_reg.DB4 = com.b0; /4/s bitek 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) //adatok (ASCII karakterkód) küldése az indikátornak ( lcd_reg = 0; lcd_reg.BL = BL_status.b0; lcd_reg.EN = 1; lcd_reg.RS = 1; //karakter küldése eltér a parancsok küldésétől, ha az RS bitet 1-re állítja lcd_reg.DB4 = com.b4; //állítsa be a 4 legjelentősebb bitet a bemeneteken 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; // a villogó impulzus visszaállítása 0-ra, a jelző beolvassa az adatokat I2C_PCF8574_WriteReg (lcd_reg); delay_us;0reg_l;0reg_l (c3dl); .BL = BL_status.b0; lcd_reg.EN = 1; lcd_reg.RS = 1; lcd_reg.DB4 = com.b0; //állítsa be a 4 legkisebb jelentőségű bitet a bemeneteken 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_us (300_Ind) vanced(400000, &_GPIO_MODULE_I2C1_PB67 ); //inicializálja az I2c modulunkat M K delay_ms(200) ; lcd_Command(0x28); // Megjelenítés 4 bit per órajel módban delay_ms (5); lcd_Command(0x08); //A kijelzőre történő adatkimenet letiltása delay_ms (5); lcd_Command(0x01); //Kijelző törlése delay_ms (5); lcd_Command(0x06); //Automatikus kurzoreltolás engedélyezése a delay_ms (5) szimbólum megjelenítése után; lcd_Command(0x0C); //Információ megjelenítésének bekapcsolása a kurzor megjelenítése nélkül delay_ms (25); ) void lcd_I2C_txt(char *pnt) //Egy karaktersorozatot jelenít meg a kijelzőn ( unsigned short int i; //ideiglenes karaktertömb indexváltozó char tmp_str; //ideiglenes karaktertömb, hossza 1-el nagyobb, mint a kijelző hossza sort, mivel a sort egy NULL ASCII karakterrel kell befejezni сiv Most csatlakoztassuk az újonnan létrehozott könyvtárat a fájlhoz a fő funkciónkkal:

#include "i2c_lcd.h" //include fejlécfájlunk aláírás nélkül int i; //ideiglenes változószámláló void main() ( lcd_I2C_Init(); //a kijelző inicializálása lcd_I2C_backlight (1); //a háttérvilágítás bekapcsolása lcd_I2C_txt ("Hello habrahabr"); //a sor megjelenítése while (1) ( delay_ms() 1000) ; lcd_I2C_Goto (2,1); //ugrás a 2. sor 1. karakterére lcd_i2c_int (i); //az i++ érték megjelenítése; //a számláló növelése ) )

Ha minden helyesen van összeszerelve, akkor a kijelzőn szöveget és másodpercenként növekvő számlálót kell látnunk. Általában semmi bonyolult :)

A következő cikkben folytatjuk az i2c protokoll és a vele működő eszközök megismerését. Fontolja meg az EEPROM 24XX memória és az MPU6050 gyorsulásmérő/giroszkóp használatát.

Ma új vendég került a műtőasztalunkra, ez egy Microchip termék, az MCP23008-E portbővítő. Ennek a dolognak a célja (ahogy a neve is sugallja), hogy növelje a mikrokontroller I/O lábainak számát, ha azok hirtelen elégtelenné válnának. Persze ha szükségünk van a lábakra és a kijáratokra, akkor vihetjük, és nem törődünk vele. Ha bemeneti lábakra van szüksége, akkor van egy szigorú logikán alapuló megoldás. Ha bemenetekre és kimenetekre is szükségünk van, és a bemenetekhez vezérelt felhúzásra is, akkor a portbővítő talán a legnormálisabb megoldás. Ami a készülék árát illeti, nagyon szerény - körülbelül egy dollár. Ebben a cikkben megpróbálom részletesen leírni, hogyan kell vezérelni ezt a mikroáramkört az AVR mikrovezérlővel.

Először egy kicsit a jellemzőkről:

  • 8 független port érintkező
  • Interfész a külvilággal való kommunikációhoz - I2C (1,7 MHz-ig terjedő frekvencia)
  • Személyre szabható felhúzás a bejáratokhoz
  • Megránthatja a lábát, amikor bizonyos bemenetek állapota megváltozik
  • Három bemenet a mikroáramkör címének beállításához (8 eszközt akaszthat egy buszra)
  • Üzemi feszültség 1,8 és 5,5 volt között
  • Alacsony áramfelvétel
  • Tokozások nagy választéka (PDIP/SOIC/SSOP/QFN)

Inkább az I2C interfészt használom, kevés bekötéssel vonz :-) ha viszont nagyon gyors (10 MHz-ig) kell, akkor az MCP23S08-ban található SPI interfészt kell használni. A különbség az MCP23S08 és az MCP23008 között, ha jól értem, csak az interfészben és a chip címének beállítására szolgáló lábak számában van. Ki szereti a rövidebbet? A mikruhi pinoutja az adatlapon van, semmiképpen nem érdekes, és itt nem is vesszük figyelembe. Ezért azonnal térjünk át arra, hogyan kezdjünk el dolgozni ezzel az eszközzel. Minden munka bizonyos adatok írásán és kiolvasásán múlik a mikroáramkör regisztereiből. Örömömre egyáltalán nem volt sok nyilvántartás – csak tizenegy. A regiszterek adatainak írása és kiolvasása nagyon egyszerű, írjon róla. Igaz, hogy nem regiszterekről beszélünk, de az elv ugyanaz. Most már csak azt kell kitalálni, hogy melyik regiszterekből mit kell kiolvasni, és melyik regiszterekből mit kell írni. Ebben természetesen segítségünkre lesz az adatlap. Az adatlapból megtudjuk, hogy a mikroáramkör a következő regiszterekkel rendelkezik:

IODIR regiszter
Meghatározza az adatáramlás irányát. Ha egy adott lábnak megfelelő bitet egyre állítjuk, akkor a láb bemenet. Ha nullára állítja, lépjen ki. Röviden, ez a regiszter analóg a DDRx-hez az AVR-ben (csak az AVR-ben az 1 egy kimenet, a 0 pedig a bemenet).

IPOL nyilvántartás
Ha egy regiszterbit be van állítva, akkor a bemeneti inverzió engedélyezve van a megfelelő lábhoz. Ez azt jelenti, hogy ha rönköt alkalmaz a lábára. nulla, akkor a GPIO regiszterből egynek minősül és fordítva. Ennek a funkciónak a hasznossága erősen megkérdőjelezhető.

GPINTEN nyilvántartás
Ennek a regiszternek minden bitje egy adott port tűjének felel meg. Ha a bit be van állítva, akkor a bemenetként konfigurált megfelelő port tűje megszakítást okozhat. Ha a bitet alaphelyzetbe állítja, akkor bármit is csinál a port lábbal, nem lesz fennakadás. A megszakítási feltételeket a következő két regiszter határozza meg.

DEFVAL regiszter
A bemenetre konfigurált lábak aktuális értéke folyamatosan összehasonlításra kerül ezzel a regiszterrel. Ha hirtelen az aktuális érték kezd eltérni attól, ami ebben a regiszterben van, akkor megszakítás történik. Egyszerűen fogalmazva, ha a bit be van állítva, a megszakítás akkor következik be, amikor a szint magasról alacsonyra változik a megfelelő lábon. Ha a bitet alaphelyzetbe állítják, a megszakítás egy felfutó élen történik.

INTCON nyilvántartás
Ennek a regiszternek minden bitje egy adott port tűjének felel meg. Ha a bit tiszta, akkor a logikai szint minden ellentétes változása megszakítást okoz. Ha a bit be van állítva, a megszakítás előfordulását a DEFVAL regiszter befolyásolja (egyébként teljesen figyelmen kívül hagyja).

IOCON regiszter
Ez a beállítások regisztere. Négy bitből áll:
SEQOP— bit vezérli a cím automatikus növelését. Ha telepítve van, az automatikus növelés le van tiltva, ellenkező esetben engedélyezve van. Ha kikapcsoljuk, nagyon gyorsan le tudjuk olvasni ugyanannak a regiszternek az értékét, mivel nem kell minden alkalommal továbbítanunk a címét. Ha gyorsan be kell olvasnia mind a 11 regisztert, akkor az automatikus növelést engedélyezni kell. Minden alkalommal, amikor egy bájtot kiolvasnak a regiszterből, maga a cím eggyel nő, és nem kell továbbítani.
DISSLW- ki tudja, mi ez a bit. Hiába csavarom, még mindig működik minden. Örülnék, ha valaki elmagyarázná.
HAEN— INT kimenet beállítási bit. Ha be van állítva, a pin nyitott lefolyóként van konfigurálva, ha a bit vissza van állítva, akkor az INT lábon lévő aktív szint határozza meg az INTPOL bitet
INTPOL— meghatározza az aktív szintet az INT lábon. Ha be van állítva, az aktív szint egy, egyébként nulla.

Még van egy kis HAEN de ebben a chipben nem használják (be/kikapcsolja a hardvercímző lábakat az MCP23S08-ban)

GPPU regisztráció
Vezérli a bemenet felhúzását. Ha a bit be van állítva, akkor egy 100 kOhm-os ellenálláson keresztül a tápegységhez való felhúzás jelenik meg a megfelelő tűn.

INTF regiszter
Interrupt flag regiszter. Ha a bit be van állítva, ez azt jelenti, hogy a megfelelő port láb megszakítást okozott. Természetesen a GPINTEN regiszterben engedélyezni kell a megszakításokat a szükséges szakaszokhoz

INTCAP regiszter
Megszakítás esetén a teljes port beolvasásra kerül ebbe a regiszterbe. Ha ezek után több megszakítás van, akkor ennek a regiszternek a tartalmát nem írja felül az új érték, amíg azt ki nem olvastuk vagy a GPIO-t.

GPIO nyilvántartás
A regiszter adatainak kiolvasásakor a logikai szinteket a port lábain olvassuk le. Az adatok rögzítésekor logikai szinteket állítunk be. Ebbe a regiszterbe történő íráskor ugyanazok az adatok automatikusan beírásra kerülnek az OLAT regiszterbe

OLAT nyilvántartás
Ebbe a regiszterbe adatot írva kiadjuk az adatokat a portra. Ha onnan olvasol adatokat, akkor azt olvasod, ami fel van írva, és nem azt, ami valójában a port bemenetein van. A bemenetek olvasásához csak GPIO-t használunk.

A regiszterek leírása véleményem szerint teljesen normális, és senkit sem szabad elrontania. Most, csak a móka kedvéért, írjunk egy kis bemutatót, amely lekérdezi a portbővítőhöz csatlakoztatott 4 gombot, és állapotuktól függően 4, ugyanahhoz a bővítőhöz csatlakoztatott megfelelő LED-et világít vagy kikapcsol. A példa a lehető legegyszerűbb lesz, minden megszakítás nélkül. Egyszerűen folyamatosan leolvassuk a gombok állapotát, és ezt az állapotot megjelenítjük a LED-eken. Készülékünk diagramja így fog kinézni:

A megszakító tűt nem kell csatlakoztatni, itt nincs rá szükségünk, de a reset láb felhúzása szükséges! Sok időt töltöttem, amíg rájöttem, hogy a portbővítőm rendszeresen visszaállt a meghúzás hiánya miatt. Most pedig térjünk rá a kódra. Természetesen írunk. Egyszerű kód:

Program rashiritel; const AdrR=%01000001; //Az olvasási bit const-ot tartalmazó chip címe AdrW=%01000000; //A bitrekordot tartalmazó chip címe var r:byte; ///Az eljárás a Dat változóból adatokat ír a regiszterbe az Adr címen Procedure WriteReg(Dat,Adr:byte); Kezdje TWI_Start(); TWI_Write(AdrW); TWI_Write(Adr); TWI_Write(Dat); TWI_Stop(); Vége; ///A függvény a regiszterértéket adja vissza az Adr címen. Funkció ReadReg(Adr:byte):byte; var a:byte; Kezdje TWI_Start(); TWI_Write(AdrW); TWI_Write(Adr); TWI_Start(); TWI_Write(AdrR); a:=TWI_Olvasás(0); TWI_Stop(); eredmény:=a; Vége; kezdődik TWI_INIT(200000); ///Az i2c inicializálása WriteReg(%00001111,0x00); //A legalacsonyabb 4 bit bemenet, a maradék 4 bit pedig kimenet WriteReg(%00001111,0x06); //Tovább felhúzás 4 bemenethez Míg TRUE do Begin r:=ReadReg(0x09); //Olvassuk be a bemenetek állapotát r:= NOT r; //Szükséges a bitek invertálása, különben a LED-ek világítanak a gomb elengedésekor r:= r shl 4; //Eltolás 4 bitet balra... WriteReg(r,0x0A); //A gombok vége állapotának megjelenítése; vége.

Közzétéve 2016.10.26

Az előző cikkben az STM32 működését néztük meg az I 2 C busszal Masterként. Vagyis ő volt a vezető, és lekérdezte az érzékelőt. Most tegyük az STM32-t Slave-vé, és válaszoljon a kérésekre, vagyis maga is érzékelőként működik. 255 bájt memóriát foglalunk le a 0-tól 0xFF-ig terjedő címekkel rendelkező regiszterek számára, és lehetővé tesszük, hogy a Mester írhassa/olvassa ezeket. És hogy a példa ne legyen olyan egyszerű, készítsük el az STM32-t analóg-digitális átalakítóvá I 2 C interfésszel. Az ADC 8 csatornát dolgoz fel. A vezérlő a transzformációk eredményét a mesternek adja át a regiszterekből történő kiolvasáskor. Mivel az ADC átalakítás eredménye 12 bit, ezért minden ADC csatornához 2 regiszterre (2 byte) van szükségünk.

i2c_slave.h beállításokat tartalmaz:

I2CSLAVE_ADDR– készülékünk címe;

ADC_ADDR_START– az ADC konverziók eredményéért felelős regiszterek kezdőcíme.

Fájlban i2c_slave.c minket leginkább a funkciók érdekelnek get_i2c1_ramÉs set_i2c1_ram. Funkció get_i2c1_ram felelős a nyilvántartások adatainak kiolvasásáért. Adatokat küld vissza a megadott címről, amelyet a Mester kap. Esetünkben az adatok a tömbből kerülnek kiolvasásra i2c1_ram, de ha a Mester regisztercímeket kér az ADC eredményekhez lefoglalt tartományból, akkor elküldi az ADC konverziós adatokat.

get_i2c1_ram:

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

Funkció set_i2c1_ram– a Mestertől kapott adatokat a megadott című regiszterekbe írja. Esetünkben az adatokat egyszerűen egy tömbbe írjuk i2c1_ram. De ez nem kötelező. Hozzáadhat például egy csekket, és amikor egy bizonyos szám megérkezik egy bizonyos címre, végrehajthat bizonyos műveleteket. Így különböző parancsokat küldhet a mikrokontrollernek.

set_i2c1_ram:

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

Az inicializálás nagyon egyszerű:

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

Először beállítjuk a vezérlő maximális működési frekvenciáját. A maximális sebességre akkor van szükség, ha az I 2 C buszon bármilyen késleltetést el kell kerülni, majd elindítjuk az ADC működését DMA segítségével. RÓL RŐL . RÓL RŐL . És végül inicializáljuk az I 2 C buszt mint Rabszolga. Mint látható, semmi bonyolult.

Most csatlakoztassuk STM32 modulunkat a Raspberry Pi-hez. Csatlakoztassunk potenciométereket az ADC csatornákhoz. És leolvassuk az ADC-jelzőket a vezérlőnkről. Ne felejtse el, hogy az I 2 C busz működéséhez felhúzó ellenállásokat kell telepítenie a busz minden vonalára.

A Raspberry konzolban nézzük meg, hogy a készülékünk látható-e az I 2 C buszon (kb.):

I2cdetect -y 1

Amint látja, az eszköz címe 0x27, bár megadtuk a 0x4E-t. Ha lesz időd, gondold át, miért történt ez.

Az I 2 C-Slave eszköz regisztereiből való olvasáshoz hajtsa végre a következő parancsot:

I2cget -y 1 0x27 0x00

Ahol:
0x27- készülék címe,
0x00– regisztrálja a címet (0x00…0xFF).

Az I 2 C-Slave eszköz regisztereibe való íráshoz hajtsa végre a következő parancsot:

I2cset -y 1 0x27 0xA0 0xDD

De:
0x27- készülék címe,
0xA0- regisztrációs cím
0xDD-8 bites adat (0x00…0xFF)

Az előző parancs a 0xDD számot írta a regiszterbe 0xA0(az első 16 regiszterbe lehet írni, de nincs értelme, de az ADC-nek vannak fenntartva). Most pedig olvassuk:

I2cget -y 1 0x27 0xA0

Az ADC-csatorna adatok olvasásának egyszerűsítése érdekében írtam egy szkriptet:

#!/usr/bin/env python import smbus importálási idő busz = smbus.SMBus(1) address = 0x27 while (1): ADC = (); i tartományban (0, 8): LBS = busz.olvasott_byte_adat(cím, 0x00+i*2) MBS = busz.olvasott_byte_adat(cím, 0x00+i*2+1) ADC[i] = MBS*256 + LBS nyomtatás ADC time.sleep(0.2)

Lekérdezi és megjeleníti mind a 8 ADC csatorna eredményét a konzolon.

Hasonló módon több mikrokontroller is kombinálható. Az egyik legyen Master(), a másik Slave.

Sok sikert!




Top