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 | D5 | Д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“. | бРСТА |
11.2.8.2. Регистар на статус на IICS
За MK серии AC, AW, Dx, EL, GB, GT, JM, LC, QE, QG, SG, SH, SL
Регистрирајте се | Мод | Д7 | D6 | D5 | Д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 | D5 | Д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 | D5 | Д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 | D5 | Д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 | D5 | Д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.
Во 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_Start();
Каде n- број на искористениот i2c модул на нашиот микроконтролер. Функцијата ќе врати 0 ако има грешка во магистралата и 1 ако се е во ред.
За да пренесеме податоци до slave ја користиме функцијата:
I2Cn_Write(непотпишана ознака slave_address, непотпишан знак *buf, непотпишан долго броење, непотпишан долг END_mode);
- n- број на користен модул
- роб_адреса- 7-битна slave адреса.
- *буф- покажувач кон нашите податоци - бајт или бајт низа.
- брои- бројот на пренесени бајти на податоци.
- END_режим- што да правите откако ќе ги префрлите податоците на робот, END_MODE_STOP - пренесе сигнал СТОП, или END_MODE_RESTART испрати повторно СТАРТ, генерирајќи сигнал РЕСТАРТи јасно му стави до знаење на одделението дека седницата со него не е завршена и сега ќе се читаат податоци од него.
I2Cn_Read(char slave_address, char *ptrdata, непотпишан долго броење, непотпишан долг END_mode);
- n- број на користен модул
- роб_адреса- 7-битна slave адреса.
- *буф- покажувач на променлива или низа во која примаме податоци, напишете char или short int
- брои- број на примени бајти на податоци.
- END_режим- што да правите откако ќе добиете податоци од робот - END_MODE_STOP - пренесе сигнал СТОП, или END_MODE_RESTART испрати сигнал РЕСТАРТ.
Адресата на микроколото се формира од состојбата на пиновите А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(unsigned char wData) ( I2C1_Start(); // Генерирајте го сигналот START I2C1_Write(PCFMODE/END_STF); 1 бајт податоци и генерира СТОП сигнал) char PCF8574A_reg ; // променливата што ја пишуваме во PCF8574 void main () ( I2C1_Init_Advanced(400000, &_GPIO_MODULE_I2C1_PB67); // Стартувајте го I2C delay_ms(25); // Почекајте малку PCF8574A_reg.b0. = 1; // исклучете ја втората ЛЕР додека (1) ( delay_ms(500); PCF8574A_reg.b0 = ~PCF8574A_reg.b0; PCF8574A_reg.b1 = ~PCF8574A_reg.b1; // инвертирај ја состојбата на LED диодиите (delay_ms(500); ; // пренесете податоци на нашиот 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(PCFAMO,Transfer/END_ST); 1 бајт податоци и генерира СТОП сигнал) void I2C_PCF8574_ReadReg (unsigned char rData) ( I2C1_Start(); // Генерирајте го START сигналот I2C1_Read(PCF8574A_ADDR, &rData, 1, END_MODE_STOP); // Прочитајте 1 бајт на податоци и STOPF; //променлива што ја пишуваме на 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 (PCF8574 A_Out); // Прочитајте од PCF8574 ако (~ PCF8574A_OUT.B6) PCF8574A_REG.B0 = ~ PCF8574A_REG.B0; вклучете/исклучете ја нашата 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 познато место
#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; //регистар за привремено складирање за податоци испратени до PCF8574 void I2C_PCF8574_WriteReg(unsigned char wData) //функција за испраќање податоци преку i2c на чипот PCF8574 ( I2C1_Start(); I2C1_Write(PCF81DE,ENDwData) КОМАНДА (кар 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.b. битови 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_WriteReg (lcd_reg) ; delay_us (300); lcd_reg.EN = 0; // ресетирајте го пулсот на стробот на 0, индикаторот ги чита податоците I2C_PCF8574_WriteReg (lcdregl_0); .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) voCid0; _Init_Advanced(400000, &_GPIO_MODULE_I2C1_PB67 );//иницијализирајте го нашиот I2c модул во M K 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.
Ти посакувам успех!