Для связи с датчиками часто используется шина I2C (Inter-Integrated Circuit).
Данная шина является синхронной, имеет 2 информационных сигнала SDA (Serial Data) и SCL (Serial Clock)
По умолчанию линии SDA и SCL притянуты к VCC (через резистор 4,7k-10k)
- Начало передачи определяется Start последовательностью — провал SDA при высоком уровне SCL
- При передаче информации от Master к Slave, ведущий генерирует такты на SCL и выдает биты на SDA. Которые ведомый считывает когда SCL становится 1.
- При передачи информации от Slave к Master, ведущий генерирует такты на SCL и смотрит состояние линии SDA — считывает данные.
Ведомый, когда SCL уходит в 0, выставляет на SDA бит, который мастер считывает когда поднимет SCL обратно. - Заканчивается все STOP последовательностью. Когда при высоком уровне на SCL линия SDA переходит с низкого на высокий уровень.
Создадим проект в CubeMX и сделаем настройки как на рисунке
Скорость выбрана 100кГц (standart mode)
Генерируем проект.
DevAddress — адрес устройства (7 бит). Важно сделать сдвиг
к примеру если адрес устройства 0x7F (0’b0111 1111), то DevAddress = 0x7F<<1; // DevAddress = 0xFE (0’b1111 1110)
Запись в I2C
HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
Чтение из устройства по I2C
HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
Есть специальные функции для работы с I2C памятью, но честно говоря я почти всегда переписывал их.
HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
Стоит отметить, что работа с шиной I2C является блокирующей — т.е. программа ждет пока передадутся/придут данные или истечет таймаут.
В отличие от асинхронного UART где был возможен прием по прерыванию.

