STM32, сериски интерфејс I2C. STM32, сериски интерфејс I2C Stm32 интерфејс i2c описот продолжи

Некои луѓе сакаат пити, некои не.

Интерфејсот i2c е широко распространет и се користи. Во stm32f4 има дури три модули кои го имплементираат овој протокол.
Нормално, со целосна поддршкацелата оваа работа.

Работата со модулот е, генерално, иста како и кај другите контролери: му давате команди, тој ги извршува и го известува резултатот:
I> Отидовме СТАРТ.
С> Ок, го испратив.
Јас> Кул, прати ја адресата сега. Вака: 0xXX.
S> Добро, го испратив. Ми беше кажано дека ACK. Ајде да продолжиме.
Јас> Сè уште жив, добро. Еве го бројот на регистарот: 0xYY, - ајде да одиме.
S> Испратено, примено ACK.
I> Сега испратете му ги податоците, еве го бајтот: 0xZZ.
S> Испратено, тој се согласува на повеќе: ACK.
Јас> Да го ебам, уште не. Отидоа СТОП.
S> Во ред.

И сè е приближно во овој дух.

ВО овој контролер i2c пиновите се расфрлани низ портите вака:
PB6: I2C1_SCL
PB7: I2C1_SDA

PB8: I2C1_SCL
PB9: I2C1_SDA

PB10: I2C2_SCL
PB11: I2C2_SDA

PA8: I2C3_SCL
PC9: I2C3_SDA
Општо земено, погодно е да се погледне пинот на периферните уреди на страница 59.

Изненадувачки, за да работите со i2c ви требаат сите негови регистри, за среќа има неколку од нив:
I2C_CR1- команди на модулот за испраќање команди/состојби и избор на режими на работа;
I2C_CR2- поставување на DMA и означување на работната фреквенција на модулот (2-42 MHz);
I2C_OAR1- поставување на адресата на уредот (за slave), големината на адресата (7 или 10 бита);
I2C_OAR2- поставување на адресата на уредот (ако има две адреси);
I2C_DR- регистар на податоци;
I2C_SR1- регистар за статус на модул;
I2C_SR2- статусен регистар (slave, мора да се прочита ако знаменцата ADDR или STOPF се поставени во SR1);
I2C_CCR- поставување на брзината на интерфејсот;
I2C_TRISE- поставување на тајмингот на рабовите.

Сепак, половина од нив се од типот „запиши и заборави“.

Плочката STM32F4-Discovery веќе има уред I2C со кој можете да вежбате: CS43L22, аудио DAC. Тој е поврзан со пиновите PB6/PB9. Главната работа е да не заборавите да примените високо ниво на иглата PD4 (~RESET седи таму), инаку DAC нема да реагира.

Постапката за поставување е приближно како што следува:
1 . Дозволете тактирање на портите и самиот модул.
Потребни ни се пиновите PB6/PB9, затоа треба да поставиме бит 1 (GPIOBEN) во регистарот RCC_AHB1ENR за да ја овозможиме портата.
И поставете бит 21 (I2C1EN) во регистарот RCC_APB1ENR за да го овозможите I2C модулот. За вториот и третиот модул, битните броеви се 22 и 23, соодветно.
2 . Следно, пиновите се конфигурирани: Oped Drain излез (GPIO->OTYPER), алтернативен режим на функција (GPIO->MODER) и алтернативен број на функција (GPIO->AFR).
Ако сакате, можете да конфигурирате влечење (GPIO->PUPDR), ако го нема на таблата (и потребно е повлекување до напојувањето на двете линии во која било форма). Бројот за I2C е секогаш ист: 4. Убаво е што има посебен број за секој тип на периферни уреди.
3 . Тековната фреквенција на часовникот на периферниот уред Fpclk1 (изразена во MHz) е означена во регистарот CR2. Како што разбирам, ова е потребно за да се пресметаат различни тајминзи на протоколот.
Патем, треба да биде најмалку два за нормален режим и најмалку четири за брз режим. И ако ви треба целосна брзина од 400 kHz, тогаш таа исто така мора да се подели со 10 (10, 20, 30, 40 MHz).
Максимална дозволена фреквенција на часовникот: 42 MHz.
4 . Брзината на интерфејсот е конфигурирана во регистарот CCR и се избира режимот (нормален/брз).
Значењето е: Tsck = CCR * 2 * Tpckl1, т.е. периодот на SCK е пропорционален на CCR (за брзиот режим сè е малку понезгодно, но тоа е опишано во РМ).
5 . Максималното време на издигнувачки раб во регистарот TRISE е прилагодено. За стандарден режим, ова време е 1 µs. Во регистарот треба да го напишете бројот на автобуски циклуси што се вклопуваат во ова време, плус еден:
ако циклусот Tpclk1 трае 125 ns, тогаш напишете (1000 ns / 125 ns) + 1 = 8 + 1 = 9.
6 . Генерирањето сигнали за прекин (грешка, статус и податоци) е опционално овозможено;
7 . Модулот се вклучува: знамето PE во регистарот CR1 е поставено на 1.

Тогаш модулот работи како што треба. Треба само да го имплементирате правилниот редослед на команди и да ги проверите резултатите. На пример, запис во регистарот:
1 . Прво треба да испратите СТАРТ со поставување на знаменце со исто име во регистарот CR1. Ако сè е во ред, тогаш по некое време знамето SB ќе биде поставено во регистарот SR1.
Би сакал да забележам една точка - ако нема повлекување на линијата (а тие се на 0), тогаш ова знаме можеби нема да чека воопшто.
2 . Ако знамето е примено, тогаш ја испраќаме адресата. За седум-битна адреса, едноставно ја пишуваме во DR точно како што ќе биде на линијата (7 битови за адреса + бит за насока). За десет битни, покомплексен алгоритам.
Ако уредот одговори на адресата со ACK, тогаш знамето ADDR ќе се појави во регистарот SR1. Ако не, тогаш ќе се појави знамето AF (Потврди неуспех).
Ако се појави ADDR, треба да го прочитате регистарот SR2. Не мора да гледате ништо таму, само секвенциското читање на SR1 и SR2 го ресетира ова знаме. И додека знамето е поставено, SCL се држи ниско од главниот, што е корисно ако треба да побарате од далечинскиот уред да почека пред да испрати податоци.
Ако сè е во ред, тогаш модулот ќе се префрли на режимот на примање или пренос на податоци, во зависност од најмалку значајниот бит од испратената адреса. За пишување мора да биде нула, за читање мора да биде еден.
но го гледаме записот, па ќе претпоставиме дека таму имало нула.
3 . Следно ја испраќаме адресата на регистарот што не интересира. На ист начин, запишувајќи го во ДР. По преносот, се поставуваат знаменцата TXE (баферот за пренос е празен) и BTF (преносот е завршен).
4 . Следуваат податоците што може да се испратат додека уредот одговара со ACK. Ако одговорот е NACK, овие знаменца нема да се постават.
5 . По завршувањето на преносот (или во случај на неочекувана состојба), испраќаме СТОП: истоименото знаме е поставено во регистарот CR1.

При читање се е исто. Се менува само по пишување на адресата на регистарот.
Наместо да се пишуваат податоци, СТАРТ се испраќа повторно (рестартира) и адресата се испраќа со најмалку значајно множество на битови (знак за читање).
Модулот ќе чека податоци од уредот. За да го поттикнете да ги испраќа следните бајти, треба да го поставите знамето ACK во CR1 пред да го примите (така што по добивањето модулот ќе го испрати истиот ACK).
Кога ќе се изморите од тоа, отстранете го знамето, уредот ќе го види NACK и ќе молчи. По што испраќаме СТОП на вообичаен начин и се радуваме на добиените податоци.

Еве го истото во форма на код:
// Иницијализирајте го модулот void i2c_Init(void) ( uint32_t Часовник = 16000000UL; // Фреквенција на часовникот на модулот (system_stm32f4xx.c не се користи) uint32_t Брзина = 100000UL; // 100 kHB заклучува ROB-Rz // |= RCC_AHB1ENR_GPIOBEN; // Поставете ги пиновите PB6, PB9 // Отворете го одводот! GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_9; // Повлекувањето е надворешно, така што не може да се конфигурира, ако е потребно, овде! // видете го регистарот GPIOB->PUPDR // Број на алтернативната функција 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->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; // Во овој момент I2C треба да се исклучи // Ресетирајте сè (SWRST == 1, ресетирајте) I2C1->CR1 = I2C_CR1_SWRST; // PE == 0, ова е главната работа I2C1->CR1 = 0; ( I2C1->CR2 = Часовник / 1000000UL; // 16 MHz // Прилагодете ја фреквенцијата ( // Tclk = (1 / Fperiph); // Бутот = Tclk * CCR; // Tlow = Бутот; // Fi2c = 1 / CCR * 2; // CCR = Fperiph / ( Fi2c * 2); uint16_t Вредност = (uint16_t) (Часовник / (Брзина * 2)); // Минимална вредност: 4 ако (Вредност< 4) Value = 4; I2C1->CCR = Вредност; ) // Поставете го времето за зголемување на границата // Во стандардниот режим, ова време е 1000 ns // Едноставно додаваме една на фреквенцијата изразена во MHz (видете RM стр. 604). I2C1->TRISE = (Часовник / 1000000UL) + 1; // Овозможи модул I2C1->CR1 |= (I2C_CR1_PE); ( (); // Регистрирај ја адресата if(!i2c_SendData(регистрирај се)) врати i2c_SendStop(); // Податоци ако(!i2c_SendData(податоци)) врати i2c_SendStop(); // Стоп! i2c_SendStop(); врати точно;) // Прими бајти bool i2c_ReceiveByte(uint8_t адреса, uint8_t Регистрирај се, uint8_t * Податоци) ( if(!i2c_SendStart()) врати неточно; // Адреса на чип if(!i2c_SendAddress(Address)) врати i2c_SendSend Регистрирај адреса if(!/) i2c_SendData(регистрирај се)) врати i2c_SendStop(); // Рестартирај ако(!i2c_SendStart()) врати неточно; // Адреса на чип (читај) ако(!i2c_SendAddress(Адреса | 1)) врати i2c_SendStop(); // Прими со if(!i2c_ReceiveData(Data)) врати i2c_SendStop(); // Стоп! i2c_SendStop(); врати точно; ) Употреба: ( uint8_t ID = 0; i2c_Init(); // Претпоставуваме дека PD4 е поставен на високо ниво и DAC работи (ова мора некако да се направи) // Испратете бајт на уредот со адреса 0x94, за да регистрирате 0x00 со вредност 0x00. i2c_SendByte (0x94, 0x00, 0x00); // Примање бајт од уредот со адреса 0x94 од регистарот 0x01 (ID) во променливата бафер i2c_ReceiveByte(0x94, 0x01, &ID); )
Се разбира, не можете да го направите ова освен во пример за обука. Чекањето за завршување на дејството е предолго за толку брз контролер.

(Водич за програмери за семејни микроконтролери HCS08)

За контрола на модулот I2C, се користат 6 специјални регистри на функции:

  • IICC - прв контролен регистар на модулот I2C;
  • IICC2 - втор контролен регистар на модулот I2C;
  • IICS - регистар за статус на модулот I2C;
  • IICF - регистар на брзина на бауд на модулот I2C;
  • IICA - Регистар за адреси на модулот I2C;
  • IICD е регистар на податоци за модулот I2C.

MCU од серијата QE содржи 2 I2C модули и, соодветно, два контролни регистри од секој тип. На пример, првиот статусен регистар е IIC1S, а вториот статусен регистар е IIC2S.

11.2.8.1. IICC контролен регистар

За МК серија AC. AW, Dx, EL, GB, GT, JM, LC, QE. Ќ.Г. SG, SH, SL
Регистрирајте се Мод Д7 D6 Д5 Д4 Д3 Д2 Д1 D0
IICC Читање IICEN IICIE МСТ Тексас TXAK 0 0 0
Снимајте RSTA
Ресетирај 0 0 0 0 0 0 0 0
Опис на битови:
Име на бит Опис Симбол во јазикот Ц
IICEN Бит за овозможување на I2C модул:
0 — I2C контролерот е оневозможен;
1 - Контролерот I2C е овозможен.
bIICEN
IICIE Бит за овозможување прекин на модулот од I2C:
0 - Прекините на барањето I2C се оневозможени;
1 - Овозможени се прекини на барање I2C.
bHCIE
МСТ Бит за избор на режим на работа на контролерот I2C:
0 - Контролорот I2C работи во режим Slave;
1 - Контролорот I2C работи во Master режим.
Кога овој бит се менува од 0 на 1, се генерира Старт состојба. Спротивно на тоа, кога бит се менува од 1 на 0, се генерира состојба Stop.
bMST
Тексас Бит за избор на насока на пренос на податочната линија SDA:
0 — линијата работи за влез;
1 - линија работи за излез.
bTX
TXAK Бит за потврда во режим на примање:
0 - бит за потврда се генерира по добивањето на бајт;
1 - се генерира бајт непотврден бит.
Овој бит го контролира генерирањето на бит за потврда по добивањето податочен бајт, без разлика дали е slave или master.
bTXAK
RSTA Ако модулот I2C работи во главен режим, тогаш пишувањето 1 на овој бит предизвикува повторно генерирање на состојбата Start - „Restart“. bRSTA

11.2.8.2. Регистар на статус на IICS

За MK серии AC, AW, Dx, EL, GB, GT, JM, LC, QE, QG, SG, SH, SL
Регистрирајте се Мод Д7 D6 Д5 Д4 Д3 Д2 Д1 D0
IICS Читање TCF IAAS ЗАФАТЕН АРБЛ 0 SRW IICIF RXAK
Снимајте
Ресетирај 0 0 0 0 0 0 0 0
Опис на битови:
Име на бит Опис Симбол во јазикот Ц
TCF Бит за завршување на размената. Поставете откако ќе заврши размената на еден бајт:
0 — размена не е завршена;
1 - размената е завршена.
Знамето TCF се брише на 0 кога се чита регистарот на податоци IICD (во режим на примање) или кога е запишан регистарот на податоци IICD (во режим на пренос).
bTCF
IAAS Знаме на адреса на роб. Поставете дали уредот работи во slave режим и адресата пренесена во главната порака е еднаква на slave адресата, која е зачувана во регистарот за адреси IICA.
Знамето се брише кога се пишува во регистарот IICC.
bIAAS
ЗАФАТЕН Знаме на зафатена линија. Ова знаменце е поставено ако I2C модулот го препознал почетниот бит на линијата. Знамето се брише кога модулот ќе открие стоп бит на линијата.
0 — I2C автобусот е бесплатен;
1 - автобусот I2C е зафатен.
б ЗАФАТЕН
АРБЛ Знаме за арбитражна загуба:
0 - нема прекршувања во работата на автобусот I2C;
1 – има загуба на арбитражата. Модулот I2C мора да почека некое време и потоа повторно да ја започне операцијата за пренос.
BARBL
SRW Бит за насока за пренос на роб. Овој бит ја означува состојбата на битот R/W во полето за адреса:
0 - роб прифаќа. Водачот му пренесува на робот;
1 - робот пренесува. Водачот добива од робот.
bSRW
IICIF Знаме на несервисирани барања за прекин за модулот I2C. Поставете на 1 ако е поставено едно од знаменцата: TCF, IAAS или ARBL.
0 - нема несервисирани прекини;
1 - има несервисирани прекини.
Знамето се ресетира со пишување 1 на него.
bIIICIF
RXAK Мастер признај малку:
0-потврдено примање податоци со роб;
1 — робот не го потврди примањето на податоците.
Овој бит ја рефлектира состојбата на полето ASK на временскиот дијаграм на размената.
bRXAK

11.2.8.3. Регистар за адреси на IICA

Регистрирајте се Мод Д7 D6 Д5 Д4 Д3 Д2 Д1 D0
IICA Читање ADDR
Снимајте
Ресетирај 0 0 0 0 0 0 0 0

Овој регистар ја складира 7-битната slave адреса што ја доделил развивачот овој уредпри развивање на системот. Оваа адреса автоматски се споредува со кодот за адреса што го добил робот во полето за адреса на магистралата I2C. Ако адресите се совпаѓаат, битот IAAS во статусниот регистар IICS е поставен.

11.2.8.4. Регистар на Baud Rate на IICF

За MK серии AC, AW, Dx, EL, GB, GT, JM, LC, QE, QG, SG, SH, SL
Регистрирајте се Мод Д7 D6 Д5 Д4 Д3 Д2 Д1 D0
МИЦФ Читање МУЛТ МЦП
Снимајте
Ресетирај 0 0 0 0 0 0 0 0
Опис на битови:

Вредности на коефициентите SCL_DIV и 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

Овој регистар складира две битни полиња кои ги одредуваат параметрите за брзина и време на размената на I2C. Фреквенцијата на сигналите за синхронизација се одредува со формулата:

Времето на смирување на податоците SDA_hold_time на магистралата I2C е временскиот интервал помеѓу моментот кога SCL сигналот е поставен на 0 и податоците на SDA линијата се менуваат. Доделено со параметарот SDA_HV (SDA_Hold_Value) од табелата за факторот ICR на регистарот за брзина на бауд:

.

11.2.8.5. IICD регистар на податоци

За MK серии AC, AW, Dx, EL, GB, GT, JM, LC, QE, QG, SG, SH, SL
Регистрирајте се Мод Д7 D6 Д5 Д4 Д3 Д2 Д1 D0
IICD Читање I2C ПОДАТОЦИ
Снимајте
Ресетирај 0 0 0 0 0 0 0 0

Ако модулот I2C работи во главниот режим, тогаш операцијата за запишување на овој регистар иницира комуникација I2C (но само ако битот за насока на комуникација во контролниот регистар IICC е правилно поставен, т.е. TX = 1). Првиот бајт по состојбата на Start, кој програмата го запишува во регистарот на податоци, робовите го толкуваат како адреса на уредот. Затоа, програмата мора правилно да ја формира содржината на првиот бајт. Операцијата за читање на регистарот го враќа последниот бајт примен преку I2C. Операцијата за читање на регистарот исто така го иницира почетокот на примањето на следниот бајт, но само ако битот за насока на комуникација во контролниот регистар IICC е правилно поставен, т.е. во TX = 0! Со TX = 1, операцијата за читање на регистарот нема да предизвика прием на нов бајт преку I2C од slave.

Ако I2C модулот работи во slave режим, тогаш податоците запишани во овој регистар ќе бидат префрлени на SDA линијата на I2C магистралата кога главниот уред ќе изврши циклус на примање од овој slave. Операцијата за читање на регистарот го враќа последниот бајт добиен од главниот.

11.2.8.6. Контролен регистар IICC2

За MK серии AC, Dx, EL, JM, QE, SG, SH, SL
Регистрирајте се Мод Д7 D6 Д5 Д4 Д3 Д2 Д1 D0
IICC Читање GCAEN ADEXT 0 0 0 АД10 AD9 AD8
Снимајте
Ресетирај 0 0 0 0 0 0 0 0

Први чекори со STM32 и mikroC компајлер за ARM архитектура - Дел 4 - I2C, pcf8574 и HD4478 базирана LCD врска

Следниот напис би сакал да го посветам на работа со заедничкиот интерфејс i2c, кој често се користи во разни микроциркули поврзани со микроконтролер.

I2C е автобус кој работи преку две физички врски (покрај заедничката жица). На интернет се пишува доста за тоа, има добри статии на Википедија. Дополнително, алгоритмот за работа на автобусот е многу јасно опишан. Накратко, автобусот е синхрона магистрала со две жици. До 127 уреди можат да бидат во автобусот во исто време (адресата на уредот е 7-битна, ќе се вратиме на ова подоцна). Подолу е типичен дијаграм за поврзување уреди со магистралата i2c, со MK како главен уред.


За i2c, сите уреди (и господар и slaves) користат излези со отворен одвод. Едноставно кажано, тие можат да ја привлечат гумата САМО на ЗЕМЈЕ. Високото ниво на магистрала е обезбедено со отпорници за повлекување. Вредноста на овие отпорници обично се избира во опсег од 4,7 до 10 kOhm. i2c е доста чувствителен на физичките линии што ги поврзуваат уредите, па ако се користи врска со голема капацитивност (на пример, долг тенок или заштитен кабел), влијанието на оваа капацитивност може да ги „замати“ рабовите на сигналот и да се меша со нормално функционирањеГуми. Колку е помал отпорот за повлекување, толку помалку влијание има оваа капацитивност врз карактеристиките на рабовите на сигналот, но толку е ПОГОЛЕМО ТОВАРУВАЊЕТО на излезните транзистори на интерфејсите i2c. Вредноста на овие отпорници е избрана за секоја специфична имплементација, но тие не треба да бидат помали од 2,2 kOhms, во спротивно можете едноставно да ги запалите излезните транзистори во уредите што работат со магистралата.

Автобусот се состои од две линии: SDA (линија за податоци) и SCL (такт сигнал). Часовник на главниот уред на автобусот, обично нашиот МК. Кога SCL е висока, информациите се читаат од магистралата за податоци. Состојбата на SDA може да се промени само кога сигналот на часовникот е слаб.. Кога SCL е висок, сигналот на SDA се менува кога се генерираат сигнали СТАРТ (кога SCL е висок сигналот на SDA се менува од високо на ниско) и СТОП - кога нивото на SCL е високо, сигналот на SDA се менува од ниско на високо).

Одделно, треба да се каже дека во i2c адресата е наведена како 7-битен број. 8 - најмалку значајниот бит ја означува насоката на пренос на податоци 0 - значи дека робот ќе пренесува податоци, 1 - прима.. Накратко, алгоритмот за работа со i2c е како што следува:

  • Високо ниво на SDA и SCL- автобусот е бесплатен, можете да започнете со работа
  • Главни лифтови SCLна 1, и ја менува состојбата С.Д.А.од 1 до 0 - го привлекува на земја - се формира сигнал СТАРТ
  • Господарот пренесува 7-битна slave адреса со бит за насока (податоци за С.Д.А.се изложуваат кога SCLвлечен на земја и прочитан од робот кога ќе се ослободи). Ако робот нема време да го „зграби“ претходниот бит, тој привлекува SCLдо темел, со што му е јасно на господарот дека состојбата на магистралата за податоци не треба да се менува: „Сè уште ја читам претходната“. Откако господарот ќе ја ослободи гумата, тој проверува дали робот ја пушти?.
  • По преносот на 8 бита од адресата, мајсторот го генерира 9-от такт и ја ослободува магистралата за податоци. Ако робот ја слушнал неговата адреса и ја прифатил, тогаш тој ќе притисне С.Д.А.до земјата. Така се формира сигналот ПРАШАЈ- прифати, се е во ред. Ако робот не разбира ништо, или едноставно не е таму, тогаш нема да има кој да ја притисне гумата. мајсторот ќе чека тајмаут и ќе разбере дека не бил разбран.
  • По пренесувањето на адресата, доколку сме го поставиле правецот од господар до роб(8 бита од адресата се еднакви на 1), потоа господарот ги пренесува податоците до slave, не заборавајќи да го провери присуството на ПРАШАЈод slave, чекајќи slave уредот да ги обработи дојдовните информации.
  • Кога господарот прима податоци од slave, самиот господар генерира сигнал ПРАШАЈпо примањето на секој бајт, а робот го контролира неговото присуство. Господарот можеби нема конкретно да испрати ПРАШАЈпред да ја испратите командата СТОП, обично му става до знаење на робот дека нема потреба да дава повеќе податоци.
  • Ако, по испраќањето податоци од страна на господарот (режим за запишување), потребно е да се прочитаат податоците од slave, тогаш господарот повторно го генерира сигналот СТАРТ , испраќајќи ја адресата на робот со знаменце за читање. (ако пред командата СТАРТне беше пренесен СТОПтогаш се формира тим РЕСТАРТ). Ова се користи за промена на насоката на комуникацијата господар-роб. На пример, ја пренесуваме адресата на регистарот на робот, а потоа читаме податоци од него.)
  • По завршувањето на работата со робот, господарот генерира сигнал СТОП- на високо ниво на сигналот на часовникот, формира премин на податочна магистрала од 0 до 1.
STM 32 има хардверски имплементирани i2c магистрални примопредаватели. Во МК може да има 2 или 3 такви модули.За нивно конфигурирање се користат специјални регистри, опишани во референцата за употребениот МК.

Во MicroC, пред да се користи i2c (како и кој било периферен уред), мора правилно да се иницијализира. За да го направите ова, ја користиме следнава функција (Иницијализирање како главен):

I2Cn_Init_Advanced (непотпишан долго: I2C_ClockSpeed, const Module_Struct *module);

  • n- број на користениот модул, на пример I2C1или I2C2.
  • I2C_ClockSpeed- брзина на автобусот, 100000 (100 kbs, стандарден режим) или 400000 (400 kbs, брз режим). Вториот е 4 пати побрз, но не го поддржуваат сите уреди
  • *модул- покажувач на периферен модул, на пример &_GPIO_MODULE_I2C1_PB67, да не го заборавиме овде тоа Помошник за кодови (ctrl-простор ) многу помага.
Прво, да провериме дали автобусот е бесплатен; постои функција за ова I2Cn_Is_Idle();враќајќи 1 ако автобусот е бесплатен и 0 ако има размена на него.

I2Cn_Start();
Каде n- број на искористениот i2c модул на нашиот микроконтролер. Функцијата ќе врати 0 ако има грешка во магистралата и 1 ако се е во ред.

За да пренесеме податоци до slave ја користиме функцијата:

I2Cn_Write(непотпишана ознака slave_address, непотпишан знак *buf, непотпишан долго броење, непотпишан долг END_mode);

  • n- број на користен модул
  • роб_адреса- 7-битна slave адреса.
  • *буф- покажувач кон нашите податоци - бајт или бајт низа.
  • брои- бројот на пренесени бајти на податоци.
  • END_режим- што да правите откако ќе ги префрлите податоците на робот, END_MODE_STOP - пренесе сигнал СТОП, или END_MODE_RESTART испрати повторно СТАРТ, генерирајќи сигнал РЕСТАРТи јасно му стави до знаење на одделението дека седницата со него не е завршена и сега ќе се читаат податоци од него.
За да прочитате податоци од slave, користете ја функцијата:

I2Cn_Read(char slave_address, char *ptrdata, непотпишан долго броење, непотпишан долг END_mode);

  • n- број на користен модул
  • роб_адреса- 7-битна slave адреса.
  • *буф- покажувач на променлива или низа во која примаме податоци, напишете char или short int
  • брои- број на примени бајти на податоци.
  • END_режим- што да правите откако ќе добиете податоци од робот - END_MODE_STOP - пренесе сигнал СТОП, или END_MODE_RESTART испрати сигнал РЕСТАРТ.
Ајде да се обидеме да поврземе нешто со нашата МК. Да започнеме со: широко распространето PCF8574(A) микроколо, кое е проширување на влезно/излезни порти контролирани преку магистралата i2c. Овој чип содржи само еден внатрешен регистар, кој е неговата физичка влезна/излезна порта. Односно, ако и поминеш бајт, веднаш ќе биде изложен на нејзините заклучоци. Ако изброите бајт од него (Пренеси СТАРТадреса со знаменце за читање, сигнал РЕСТЕРТИРАЈ,прочитајте ги податоците и конечно генерирате сигнал СТОП) тогаш ќе ги одразува логичките состојби на неговите излези. Ајде да го поврземе нашиот микроспој во согласност со листот со податоци:


Адресата на микроколото се формира од состојбата на пиновите А0, А1, А2. За микроспој PCF8574адресата ќе биде: 0100A0A1A2. (На пример, имаме A0, A1, A2 на високо ниво, така што адресата на нашиот микроциркут ќе биде 0b0100 111 = 0x27). За PCF8574A - 0111A0A1A2, кој со нашиот дијаграм за поврзување ќе ја даде адресата 0b0111 111 = 0x3F. Ако, да речеме, A2 е поврзан со земјата, тогаш адресата за PCF8574Aќе 0x3B. Севкупно, 16 микроциркути можат да се монтираат истовремено на една магистрала i2c, по 8 PCF8574A и PCF8574.

Ајде да се обидеме да префрлиме нешто, да ја иницијализираме магистралата i2c и да префрлиме нешто на нашиот PCF8574.

#define PCF8574A_ADDR 0x3F //Адреса на нашиот PCF8574 void I2C_PCF8574_WriteReg(непотпишан знак wData) ( I2C1_Start(); // Генерирајте го сигналот START I2C1_Write(PCFAMODE/END_ST); Префрлете 1 бајт податоци и генерирајте STOP сигнал ) char PCF8574A_reg ; // променливата што ја пишуваме во PCF8574 void main () ( I2C1_Init_Advanced(400000, &_GPIO_MODULE_I2C1_PB67); // Стартувајте го I2C delay_ms(25); // Почекајте малку PCF8574A_reg.b0. = 1; // turn off the second LED while (1) ( delay_ms(500); PCF8574A_reg.b0 = ~PCF8574A_reg.b0; PCF8574A_reg.b1 = ~PCF8574A_reg.b1; // invert the state of the LEDs I2C_PCF8574_WriteReg (PCF8574A_reg) ; // пренесете податоци на нашиот PCF8574 ))
Ја составуваме и ја извршуваме нашата програма и гледаме дека нашите LED диоди трепкаат наизменично.
Со причина ја поврзав катодата на LED диодите со нашиот PCF8574. Работата е во тоа што кога се испорачува логичка 0 на излезот, микроциркутот искрено го влече својот излез на земја, но кога ќе се примени логичка 1, го поврзува на + напојување преку струен извор од 100 μA. Тоа е, не можете да добиете „искрена“ логичка 1 на излезот. И не можете да запалите LED со 100 µA. Ова беше направено со цел да се конфигурира излезот PCF8574 на влезот без дополнителни регистри. Едноставно пишуваме на излезниот регистар 1 (во суштина поставувајќи ги состојбите на пинот на Vdd) и едноставно можеме да го скратиме до земјата. Тековниот извор нема да дозволи излезната фаза на нашиот В/И експандер да „изгори“. Ако ногата е повлечена на земја, тогаш потенцијалот за заземјување е на неа, и се чита логичното 0. Ако ногата се повлече на +, тогаш се чита логичното 1. Од една страна, тоа е едноставно, но од друга, секогаш треба да го запомните ова кога работите со овие микроциркути.


Ајде да се обидеме да ја прочитаме состојбата на пиновите на нашиот експандер чип.

#define PCF8574A_ADDR 0x3F //Адреса на нашиот PCF8574 void I2C_PCF8574_WriteReg(unsigned char wData) ( I2C1_Start(); // Генерирајте го сигналот START I2C1_Write(PCFAMOTA/END_ST); Префрлете 1 бајт податоци и генерирајте STOP сигнал ) void I2C_PCF8574_ReadReg (непотпишан знак rData) ( I2C1_Start(); // Генерирајте го START сигналот I2C1_Read(PCF8574A_ADDR, &rData, 1, END_MODE_STOP); // Прочитајте 1 од знакот PCF8 и STOP; //променлива што ја пишуваме на PCF8574 char PCF8574A_out; // променливата во која читаме и PCF8574 char lad_state; //нашата ЛЕР е вклучена или исклучена како празна главна () ( I2C1_Init_Advanced (400000, &_GPIO_MODULE_I2C1_PB67); // Стартувајте го I2C delay_ms(25); // Почекајте малку PCF8574A_reg.b0 = 0; //reg51 bA запали ја првата LED 1; / / исклучете го вториот LED PCF8574A_reg.b6 = 1; // Повлечете ги пиновите 6 и 7 на напојување. PCF8574A_reg.b7 = 1; додека (1) ( delay_ms(100); I2C_PCF8574_WriteReg (PCF8574A data); до PCF8574 I2C_PCF8574_ReadReg (PCF85 74A_out); // прочитајте од PCF8574 ако (~PCF8574A_out.b6) PCF8574A_reg.b0 = ~PCF8574A_reg.b0; //точи 7 t е притиснато на копчето PCF85 од 1. 0, тогаш вклучете/исклучете ја нашата LED диода) ако (~PCF8574A_out .b7) PCF8574A_reg.b1 = ~PCF8574A_reg.b1; // слично за 2 копчиња и 2 LED диоди ) )
Сега со притискање на копчињата ја вклучуваме или исклучуваме нашата ЛЕД. Микроциркулата има друг излез ИНТ. На него се генерира пулс секогаш кога се менува состојбата на пиновите на нашиот В/И експандер. Со поврзување на влезот за надворешни прекини на нашиот МК (ќе ви кажам како да ги конфигурирате надворешните прекини и како да работите со нив во една од следните статии).

Ајде да го користиме нашиот проширувач на порти за да поврземе приказ на знаци преку него. Има многу од нив, но скоро сите се изградени врз основа на контролорски чип HD44780и неговите клонови. На пример, користев LCD2004 дисплеј.


Листот со податоци за него и контролерот HD44780 може лесно да се најдат на Интернет. Ајде да го поврземе нашиот екран со PCF8574, а нејзиниот, соодветно, со нашиот STM32.

HD44780користи паралелен затворен интерфејс. Податоците се пренесуваат со 8 (по такт) или 4 (на 2 тактни циклуси) порти импулси на пинот Е. (читано од контролерот на екранот на опаѓачки раб, премин од 1 до 0). Заклучок Р.С.покажува дали испраќаме податоци на нашиот екран ( РС = 1) (ликовите што треба да ги прикаже се всушност ASCII кодови) или командата ( РС = 0). RWозначува насока на пренос на податоци, пишување или читање. Обично пишуваме податоци на екранот, така што ( RW=0). Резисторот R6 го контролира контрастот на екранот. Не можете едноставно да го поврзете влезот за прилагодување на контрастот со заземјување или напојување, во спротивно нема да видите ништо.. VT1 се користи за вклучување и исклучување на позадинското осветлување на екранот според командите MK. MicroC има библиотека за работа со такви дисплеи преку паралелен интерфејс, но обично е скапо да се потрошат 8 нозе на дисплеј, така што скоро секогаш го користам PCF8574 за работа со такви екрани. (Ако некој е заинтересиран, ќе напишам статија за работа со екрани базирани на HD44780 вградени во MicroC преку паралелен интерфејс.) Протоколот за размена не е особено комплициран (ќе користиме 4 линии за податоци и ќе пренесуваме информации во 2 циклуси на часовници). тоа е јасно прикажано со следниот временски дијаграм:


Пред да префрлите податоци на нашиот екран, тие мора да се иницијализираат со предавање на команди за сервис. (опишано во листот со податоци, овде ги претставуваме само најкористените)

  • 0x28- комуникација со индикаторот преку 4 линии
  • 0x0C- овозможете излез на слика, оневозможете прикажување на курсорот
  • 0x0E- овозможете излез на слика, овозможете прикажување на курсорот
  • 0x01- исчистете го индикаторот
  • 0x08- оневозможи излез на слика
  • 0x06- откако ќе се прикаже симболот, курсорот се поместува за 1 познато место
Бидејќи ќе треба да работиме со овој индикатор доста често, ќе создадеме библиотека со приклучок "i2c_lcd.h" . За таа цел во Проектен менаџер Заглавие датотеки и изберете Додадете нова датотека . Ајде да ја создадеме нашата датотека за заглавие.

#define PCF8574A_ADDR 0x3F //Адреса на нашиот PCF8574 #define DB4 b4 // Кореспонденција помеѓу пиновите PCF8574 и индикаторот #define DB5 b5 #define DB6 b6 #define DB7 b7 #define EN b3 bdefin #define BL b0 // контрола на задно осветлување #define displenth 20 // број на знаци во нашата линија за прикажување статички непотпишан знак BL_status; // променлива што ја зачувува состојбата на позадинското осветлување (вклучено/исклучено) void lcd_I2C_Init(void); // Екран и функција за иницијализација на PCF8574 void lcd_I2C_txt(char *pnt); // Прикажува линија од текст, параметарот е покажувач на оваа линија void lcd_I2C_int(int pnt); // Ја прикажува вредноста на цела променлива, параметарот е излезна вредност void lcd_I2C_Goto(непотпишан краток ред, непотпишан кратка колона); // го поместува курсорот до одредената позиција, параметри ред - линија (од 1 до 2 или 4 во зависност од екранот) и коло - (од 1 до дисплент)) void lcd_I2C_cls(); // Ја брише празнината на екранот lcd_I2C_backlight (непотпишана кратка int состојба); // Овозможува (кога се пренесува 1 и се оневозможува - кога се пренесува 0 позадинското осветлување на екранот)
Сега да ги опишеме нашите функции, повторно одиме на Проектен менаџердесен клик на папката Извори и изберете Додадете нова датотека . Направете датотека "i2c_lcd.с" .

#include "i2c_lcd.h" //вклучи ја нашата датотека за заглавие char lcd_reg; ( ) неважечки LCD_COMMAND ( char com) / /функција за испраќање команда на нашиот дисплеј ( lcd_reg = 0; //напиши 0 во привремениот регистар lcd_reg.BL = BL_status.b0; //поставете го иглата за задно осветлување во согласност со вредноста на променливата што ја складира состојба на позадинско осветлување lcd_reg.DB4 = com.b4 // поставете ги 4-те најзначајни бита од нашата команда на магистралата за податоци за индикатори lcd_reg.DB5 = com.b5; lcd_reg.DB6 = com.b6; lcd_reg.DB7 = com.b7; lcd_reg.EN = 1; //поставете го излезот на строб на 1 I2C_PCF8574_WriteReg ( lcd_reg); // запишете во регистарот PCF8574, всушност испраќајќи податоци до индикаторот delay_us (300); //почекајте истекот на времето lcd_reg.EN = 0; /ресетирај го пулсот на строб на 0, индикаторот ги чита податоците I2C_PCF8574_WriteReg (lcd_reg); delay_us (300) ; lcd_reg = 0; lcd_reg.BL = BL_status.b0; lcd_reg.DB4 = најмалку за com. значајни битови lcd_reg.DB5 = com.b1; lcd_reg.DB6 = com.b2; lcd_reg.DB7 = com.b3; lcd_reg.EN = 1; I2C_PCF8574_WriteReg(lcd_reg); одложување_нас (300); lcd_reg.EN = 0; I2C_PCF8574_WriteReg(lcd_reg); одложување_нас (300); ) void LCD_CHAR (непотпишан char com) //испраќање податоци (ASCII шифра на знаци) до индикаторот ( lcd_reg = 0; lcd_reg.BL = BL_status.b0; lcd_reg.EN = 1; lcd_reg.RS = 1; //испраќање знак се разликува од испраќањето наредби со поставување на битот RS на 1 lcd_reg.DB4 = com.b4; //поставете ги 4-те најзначајни бита на влезовите lcd_reg.DB5 = com.b5; lcd_reg.DB6 = com.b6; lcd_reg.DB7 = com.b7; i2c_pcf8574_writeerg (lcd_reg); delation_us (300); lcd_reg.en = 0; // Ресетирајте го пулсот на Strobe на 0, индикаторот ги чита податоците i2c_pcf8574_writeerg (LCD_REG); DEALE_US (300); .BL = BL_status.b0; lcd_reg.EN = 1; lcd_reg.RS = 1; lcd_reg.DB4 = com.b0; //поставете ги 4-те најмалку значајни бита на влезовите 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); доцнење (2c_it) voCd0); C1_Init_Advanced(400000, &_GPIO_MODULE_I2C1_PB67 //иницијализирајте го нашиот I2c модул за MK delay_ms(200); lcd_Command(0x28); // Приказ во 4 бита по режим на часовник delay_ms (5); lcd_Command (0x08); //Оневозможи излез на податоци на екранот delay_ms (5); lcd_Command (0x01); //Исчисти го прикажувањето delay_ms (5); lcd_Command (0x06); //Овозможи автоматско поместување на курсорот по прикажувањето на симболот delay_ms (5); lcd_Command (0x0C); //Вклучи прикажување информации без прикажување на курсорот delay_ms (25); ) void lcd_I2C_txt(char *pnt) //Излезете низа знаци на дисплејот (непотпишан краток int i; //променлива индекс на низа на привремени знаци char tmp_str; //привремена низа знаци, должина 1 поголема од должината на екранот линија, бидејќи линијата треба да се заврши сiv со NULL ASCII знак 0x00 strncpy(tmp_str, pnt, displenth); //копирајте не повеќе од диспленти знаци од оригиналната низа во нашата привремена низа за (i=0; i Сега ајде да ја поврземе новосоздадената библиотека со датотеката со нашата главна функција:

#include "i2c_lcd.h" //вклучи ја нашата датотека за заглавие непотпишана int i; //привремена променлива бројач void main() ( lcd_I2C_Init(); //иницијализирајте го екранот lcd_I2C_backlight (1); //вклучете го задно осветлување lcd_I2C_txt („Здраво habrahabr“); //прикажете ја линијата додека (1) ( delay_ms( 1000).

Ако сè е правилно составено, тогаш треба да видиме текст на индикаторот и бројач што се зголемува секоја секунда. Во принцип, ништо комплицирано :)

Во следната статија ќе продолжиме да го разбираме протоколот i2c и уредите што работат со него. Ајде да размислиме да работиме со EEPROM 24XX меморија и акцелерометарот/жироскопот MPU6050.

Денес има нов гостин на нашата операциона маса, ова е производ на Microchip, проширување на портата MCP23008-E. Оваа работа е наменета (како што имплицира името) да го зголеми бројот на влезно-излезни краци на микроконтролерот доколку наеднаш станат недоволни. Се разбира, ако ни требаат нозете и излезите, тогаш можеме да го земеме и да не се грижиме за тоа. Ако ви требаат влезни ногарки, тогаш постои решение засновано на строга логика. Ако ни требаат и влезови и излези, а исто така и контролирано повлекување за влезовите, тогаш проширувачот на портата е можеби најнормалното решение. Што се однесува до цената на уредот, таа е многу скромна - околу еден долар. Во оваа статија ќе се обидам детално да опишам како да го контролирате овој микроспој користејќи го микроконтролерот AVR.

Прво, малку за карактеристиките:

  • 8 независни пинови на пристаништето
  • Интерфејс за комуникација со надворешниот свет - I2C (фреквенција до 1,7 MHz)
  • Приспособливо влечење за влезови
  • Може да ја згрчи ногата кога ќе се промени состојбата на одредени влезови
  • Три влеза за поставување на адресата на микроциркутот (можете да обесувате 8 уреди на една шина)
  • Работен напон од 1,8 до 5,5 волти
  • Ниска потрошувачка на струја
  • Голем избор на куќишта (PDIP/SOIC/SSOP/QFN)

Претпочитам да го користам интерфејсот I2C, тој ме привлекува со мал број жици :-) меѓутоа, ако ви треба многу голема брзина (до 10 MHz), тогаш треба да го користите интерфејсот SPI што е присутен во MCP23S08. Разликата помеѓу MCP23S08 и MCP23008, како што јас разбирам, е само во интерфејсот и во бројот на краци за поставување на адресата на чипот. Кој сака нешто пократко? Пинаутот на микрухи е во листот со податоци, никако не е интересен и нема да се разгледува овде. Затоа, веднаш да продолжиме со тоа како да започнеме да работиме со овој уред. Целата работа се сведува на пишување и читање одредени податоци од регистрите на микроциркутот. На мое задоволство, воопшто немаше многу регистри - само единаесет. Пишувањето и читањето податоци од регистри е многу едноставно, објавувајте за тоа. Точно е дека не зборуваме за регистри, но принципот е ист. Сега останува само да дознаеме од кои регистри да читаме и од кои регистри да пишуваме. Се разбира, листот со податоци ќе ни помогне во ова. Од листот со податоци дознаваме дека микроциркулата ги има следните регистри:

ИОДИР регистар
Ја одредува насоката во која течат податоците. Ако битот што одговара на одредена нога е поставен на еден, тогаш кракот е влез. Ако се ресетира на нула, излезете. Накратко, овој регистар е аналоген на DDRx во AVR (само во AVR 1 е излез, а 0 е влез).

IPOL регистар
Ако е поставен бит за регистар, тогаш е овозможена влезна инверзија за соодветната крака. Ова значи дека ако нанесете дневник на ногата. нула тогаш од регистарот GPIO се смета за еден и обратно. Корисноста на оваа функција е многу сомнителна.

GPINTEN регистар
Секој бит од овој регистар одговара на специфичен пин на портот. Ако битот е поставен, тогаш соодветниот пин на портата конфигуриран како влез може да предизвика прекин. Ако битот се ресетира, тогаш што и да правите со кракот на пристаништето, нема да има прекин. Условите за прекин се поставени од следните два регистри.

DEFVAL регистар
Тековната вредност на пиновите конфигурирани за внесување постојано се споредува со овој регистар. Ако одеднаш моменталната вредност почне да се разликува од она што е во овој регистар, тогаш се јавува прекин. Едноставно кажано, ако битот е поставен, прекинот ќе се случи кога нивото ќе се промени од високо на ниско на соодветната нога. Ако битот се исчисти, прекинот се јавува на растечкиот раб.

Регистар INTCON
Секој бит од овој регистар одговара на специфичен пин на портот. Ако битот е јасен, тогаш секоја промена на логичкото ниво на спротивното предизвикува прекин. Ако битот е поставен, појавата на прекинот е под влијание на регистарот DEFVAL (во спротивно целосно се игнорира).

IOCON регистар
Ова е регистарот за поставки. Се состои од четири бита:
SEQOP— автоматско зголемување на адресата на бит-контролите. Ако е инсталиран, автоматското зголемување е оневозможено, во спротивно е овозможено. Ако го исклучиме, можеме многу брзо да ја прочитаме вредноста на истиот регистар поради фактот што не мораме секој пат да ја пренесуваме неговата адреса. Ако треба брзо да ги прочитате сите 11 регистри за возврат, тогаш мора да се овозможи автоматско зголемување. Секој пат кога ќе се прочита бајт од регистарот, самата адреса ќе се зголемува за еден и нема да мора да се пренесува.
DISSLW- кој знае што е ова малку. Како и да го извртам, сè уште функционира. Ќе ми биде драго ако некој објасни.
ХАЕН— Бит за подесување на излезот INT. Ако е поставено, пинот е конфигуриран како отворен одвод, ако битот се ресетира, тогаш активното ниво на ногата INT го одредува битот INTPOL
ИНТПОЛ— го одредува активното ниво на ногата INT. Ако е поставено, активното ниво е едно, инаку нула.

Има уште малку ХАЕНно не се користи во овој чип (вклучува/исклучува хардверски адресни пинови во MCP23S08)

Регистар на GPPU
Го контролира повлекувањето на влезот. Ако битот е поставен, тогаш на соодветниот пин ќе се појави повлекување до напојувањето преку отпорник од 100 kOhm.

INTF регистар
Прекинете го регистарот со знаменце. Ако битот е поставен, тоа значи дека соодветната нога на портата предизвикала прекин. Се разбира, прекините за потребните краци мора да бидат овозможени во регистарот GPINTEN

Регистар INTCAP
Кога ќе дојде до прекин, целата порта се чита во овој регистар. Ако после ова има повеќе прекини, тогаш содржината на овој регистар нема да биде препишана со новата вредност додека не ја прочитаме или GPIO.

GPIO регистар
Кога читаме податоци од регистарот, ги читаме логичките нивоа на пиновите на портата. Кога снимаме податоци, поставуваме логички нивоа. При запишување во овој регистар, истите податоци автоматски се запишуваат во OLAT регистарот

OLAT регистар
Со запишување податоци во овој регистар, ние ги пренесуваме податоците во портата. Ако читаш податоци од таму, ќе прочиташ што е запишано, а не што е всушност на влезовите на портот. За читање на влезови користиме само GPIO.

Описот на регистрите, според мене, е сосема нормален и не треба никому да му пречи. Сега, само за забава, ајде да напишеме мало демо со кое ќе се анкетираат 4 копчиња поврзани со проширувачот на пристаништето и во зависност од нивната состојба, ќе се запалат или исклучат 4 соодветни LED диоди поврзани со истиот проширувач. Примерот ќе биде што е можно поедноставен, без никакви прекини. Ние едноставно постојано ја читаме состојбата на копчињата и ја прикажуваме оваа состојба на LED диодите. Дијаграмот на нашиот уред ќе изгледа вака:

Пинот за прекин не мора да биде поврзан, не ни треба овде, но потребно е влечење за ногата за ресетирање! Поминав многу време додека не сфатив дека мојот експандер на портот периодично се ресетира поради недостаток на затегнување. Сега да дојдеме до кодот. Секако дека ќе пишуваме на . Едноставен код:

Програма раширител; const AdrR=%01000001; //Адреса на чипот со бит за читање const AdrW=%01000000; //Адреса на чипот со бит запис var r:byte; ///Постапката запишува податоци од променливата Dat во регистарот на адресата Adr Procedure WriteReg(Dat,Adr:byte); Започнете со TWI_Start(); TWI_Write (AdrW); TWI_Write (Adr); TWI_Write(Dat); TWI_Stop(); Крај; ///Функцијата ја враќа вредноста на регистарот на адресата Adr Функција ReadReg(Adr:byte):byte; var a:byte; Започнете со TWI_Start(); TWI_Write (AdrW); TWI_Write (Adr); TWI_Start(); TWI_Write (AdrR); a:=TWI_Read(0); TWI_Stop(); резултат:=а; Крај; започнете TWI_INIT (200000); ///Иницијализирање на i2c WriteReg(%00001111,0x00); //Најмалите 4 бита се влезови, а останатите 4 бита се излези WriteReg(%00001111,0x06); //На pull-up за 4 влезови Додека TRUE направи Започнете r:=ReadReg(0x09); //Прочитајте ја состојбата на влезовите r:= НЕ r; //Потребно е да се превртат битовите, инаку LED диодите ќе светнат кога ќе се ослободи копчето r:= r shl 4; //Префрли 4 бита налево... WriteReg(r,0x0A); //Прикажи ја состојбата на крајот на копчињата; крај.

Објавено на 26.10.2016 година

Во претходната статија, ја разгледавме работата на STM32 со автобусот I 2 C како мајстор. Односно, тој бил лидер и го испрашувал сензорот. Сега да го направиме STM32 Slave и да одговориме на барањата, односно, тој самиот работи како сензор. Ќе доделиме 255 бајти меморија за регистри со адреси од 0 до 0xFF и ќе му дозволиме на Master да ги запише/чита. И за да не биде толку едноставен примерот, ајде да го направиме нашиот STM32 конвертор од аналогно во дигитално со интерфејс I 2 C. ADC ќе обработи 8 канали. Контролорот ќе му ги даде резултатите од трансформациите на мајсторот при читање од регистри. Бидејќи резултатот од конверзијата на ADC е 12 бита, потребни ни се 2 регистри (2 бајти) за секој ADC канал.

i2c_slave.чсодржи поставки:

I2CSLAVE_ADDR– адреса на нашиот уред;

ADC_ADDR_START– почетната адреса на регистрите кои се одговорни за резултатите од ADC конверзиите.

Во датотека i2c_slave.внајмногу сме заинтересирани за функциите get_i2c1_ramИ set_i2c1_ram. Функција get_i2c1_ramе одговорен за читање податоци од регистри. Ги враќа податоците од наведената адреса, која му се дава на мајсторот. Во нашиот случај, податоците се читаат од низата i2c1_ram, но ако Master побара адреси на регистри од опсегот доделен за ADC резултати, тогаш се испраќаат податоците за конверзија на ADC.

get_i2c1_ram:

Uint8_t get_i2c1_ram(uint8_t adr) ( //податоци за ADC ако ((ADC_ADDR_START<= adr) & (adr < ADC_ADDR_START + ADC_CHANNELS*2)) { return ADCBuffer; } else { // Other addresses return i2c1_ram; } }

Функција set_i2c1_ram– ги запишува податоците добиени од мајсторот во регистри со наведената адреса. Во нашиот случај, податоците едноставно се запишуваат во низа i2c1_ram. Но, ова е опционално. Можете, на пример, да додадете чек и, кога одреден број ќе пристигне на одредена адреса, да извршите некои дејства. На овој начин можете да испраќате различни команди до микроконтролерот.

set_i2c1_ram:

Празно set_i2c1_ram(uint8_t adr, uint8_t val) ( i2c1_ram = val; врати; )

Иницијализирањето е прилично едноставно:

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

Прво ја поставивме максималната работна фреквенција на контролорот. Потребна е максимална брзина кога треба да се избегнат какви било доцнења на магистралата I 2 C. Потоа ја започнуваме операцијата ADC користејќи DMA. ЗА . ЗА . И, конечно, ја иницијализираме магистралата I 2 C како Роб. Како што можете да видите, ништо комплицирано.

Сега да го поврземе нашиот STM32 модул со Raspberry Pi. Ајде да ги поврземе потенциометрите со ADC каналите. И ние ќе ги читаме индикаторите за ADC од нашиот контролер. Не заборавајте дека за да функционира магистралата I 2 C, треба да инсталирате отпорници за повлекување на секоја линија од автобусот.

Во конзолата Raspberry, ајде да провериме дали нашиот уред е видлив на автобусот I 2 C (за тоа):

I2cоткривам -y 1

Како што можете да видите, адресата на уредот 0x27, иако наведовме 0x4E. Кога ќе имате време, размислете зошто се случи ова.

За да прочитате од регистрите на уредот I 2 C-Slave, извршете ја командата:

I2cget -y 1 0x27 0x00

Каде:
0x27- адреса на уредот,
0x00– адреса на регистрација (0x00…0xFF).

За да запишете во регистрите на уредот I 2 C-Slave, извршете ја командата:

I2cset -y 1 0x27 0xA0 0xDD

Де:
0x27- адреса на уредот,
0xA0– адреса на регистрација
0xDD-8-битни податоци (0x00…0xFF)

Претходната команда го напиша бројот 0xDD во регистарот 0xA0(можете да пишете на првите 16 регистри, но нема поента, но тие се резервирани за ADC). Сега да прочитаме:

I2cget -y 1 0x27 0xA0

За да го поедноставам процесот на читање податоци за каналот ADC, напишав скрипта:

#!/usr/bin/env python import smbus увоз време магистрала = smbus.SMBus(1) адреса = 0x27 додека (1): ADC = (); за i во опсег (0, 8): LBS = bus.read_byte_data (адреса, 0x00+i*2) MBS = автобус.read_byte_data (адреса, 0x00+i*2+1) ADC[i] = MBS*256 + LBS печатење ADC time.sleep(0,2)

Ги анкетира и ги прикажува резултатите од сите 8 ADC канали на конзолата.

На сличен начин, можете да комбинирате неколку микроконтролери. Еден од нив треба да биде Master(), другиот Slave.

Ти посакувам успех!




Врв