19. STM32. Програмування STM32F103. I2C Master


11.10.2016

Шина I2C досить популярна і дуже багато сенсорів та інших пристроїв використовують саме I2C. Я не буду писати хто, коли і для чого винайшов цю шину та як по ній бігають байти. Цієї інформації повно у Інтернеті, для цього існує Вікіпедія. Коли Ви тримаєте в руках сенсор і бажаєте якнайшвидше отримати з нього дані, та вирішити поставлену задачу, Вам вистачить наступного мінімуму знань:

  1. Шина I2C - це двопровідна шина з лініями SCL, SDA. Теоретично, на одну шину I2C можна паралельно підключити до 112 пристроїв.
  2. Обидві лінії шини мають бути через резистори підключеними до живлення. Рекомендований номінал резисторів залежить від швидкості та інших параметрів шини. Зазвичай мало хто з цим морочиться і ставлять резистори у межах від 4.7кОм до 10кОм. Резисторів має бути по одному на кожну лінію. Якщо Ви підключаєте декілька модулів, а на кожному модулі вже впаяні підтягуючі резистори, то виходить, що резистори вмикаються паралельно і їх сумарний опір стає меншим. Це не дуже добре. Та, якщо ви вмикаєте лише два таких модуля і на кожному впаяні резистори по 10 кОм, тоді сумарний опір буде 5КОм, що попадає у межі допустимої норми і шина I2C, скоріш за все, буде працювати. Але повторюю: чіпляти на кожну лінію більше одного резистора - не дуже гарна ідея.
  3. Кожен пристрій на шині I2C має окрему адресу.
  4. На шині I2C може бути лише один Master і один, або декілька Slave.
  5. Швидкість шини може бути різною. Зазвичай використовують два стандарти 100 і 400 КГц. Швидкість лінії має визначатися по самому повільному пристрою на шині. Якщо Slave не встигає, він може "притримати" шину і всі його будуть чекати. Та такий підхід, хоч і є стандартом, але на практиці працює не завжди. У випадку, коли Master не вміє чекати (цим, наприклад страждають мікрокомп`ютери), на шині починається безлад. Тобто, некоректна робота одного з пристроїв на шині I2C (не важливо, у якій ролі - Master або Slave) може викликати проблеми у роботі усіх приладів.
  6. Якщо напруга живлення контролера відрізняється від напруги живлення датчика, вони мають вмикатися через двонаправлену схему узгодження логічних рівнів.

Розглянемо приклад використання датчика атмосферного тиску BMP280. Підключимо модуль датчика, як зазначено на схемі. На модулі датчика є запаяні резистори для кожної з ліній шини I2C, тому нам не треба нічого вигадувати. Схема підключення:

stm32_bmp280

Налаштування шини виконується наступним чином:

1. Вмикається тактування потрібної шини I2C. У STM32 їх може бути декілька. У нашому мікроконтролері 2 шини I2C. 2. Вмикається тактування GPIO порту на якому висять SCL, SDA відповідної шини I2C. 3. Налаштовують GPIO виходи, як альтернативні для роботи у ролі SCL, SDA. 4. Вмикається шина I2C. 5. Налаштовуються параметри шини I2C.

Приклад:


void I2C1_init(void)
{
    I2C_InitTypeDef  I2C_InitStructure;
    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    /* Configure I2C_EE pins: SCL and SDA */
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* I2C configuration */
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0x38;
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 100000;

    /* I2C Peripheral Enable */
    I2C_Cmd(I2C1, ENABLE);
    /* Apply I2C configuration after enabling it */
    I2C_Init(I2C1, &I2C_InitStructure);
}

Після чого можна приступати до роботи.

Для того, щоб звернутися до датчика, ми маємо знати його адресу. Знаючи адресу, ми зможемо посилати йому, або читати з нього, інформацію. Ми можемо звернутися до датчика і вказати адресу його регістра, з якого ми бажаємо отримати, або в який бажаємо записати, інформацію. У документації до датчиків вказані адреси регістрів та їх призначення. Керування датчиками виконується, зазвичай, записом у певний регістр певного числа (команди). Або відправкою певної команди на адресу датчика (без зазначення адреси регістра). Обмін інформацією залежить від реалізації того чи іншого датчика. Насправді це здається складним лише вперше. У багатьох випадках для різних датчиків функції запису та читання мало чим відрізняються. Наприклад, функція запису байта у регістр виглядає так:


void bmp280WriteByte(unsigned char address, unsigned char data)
{
  I2C_GenerateSTART(I2C1,ENABLE);
  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));

  I2C_Send7bitAddress(I2C1, BMP280_addr, I2C_Direction_Transmitter);
  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

  I2C_SendData(I2C1,address);
  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  I2C_SendData(I2C1,data);
  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

  I2C_GenerateSTOP(I2C1,ENABLE);

  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
//----------------------------------------

Зазвичай, для інших датчиків вона виглядає аналогічно. Те саме стосується зчитування даних. Відмінності можуть бути у деталях. Наприклад, при зчитуванні багатобайтних даних у деяких датчиків першими йдуть старші розряди, а у інших - молодші розряди. Все стане зрозуміліше коли ви розглянете приклад. Повний текст програми наводити немає сенсу. Проект з назвою Example_i2C_Master можна скачати на сторінці прикладів.

Бажаю успіхів!

Дивись також:

STM32
Коментарі:
Додати коментар
Code
* - обов'язкові поля

Архіви