Сканер i2c шины hal

Видео:STM32. CMSIS. Урок#06: I2C. Теория. Сканер I2C адресов. Отправка и прием данных. MemWrite, MemRead.Скачать

STM32. CMSIS. Урок#06: I2C. Теория. Сканер I2C адресов. Отправка и прием данных. MemWrite, MemRead.

STM Урок 9. HAL. Шина I2C. Продолжаем работу с DS3231

Видео:STM32 Сканер I2C шины, ищем брак от АлиСкачать

STM32 Сканер I2C шины, ищем брак от Али

HAL. Шина I2C. Продолжаем работу с DS3231

На прошлом занятии мы как следует ознакомились с шиной I2C, а также с микросхемой часов реального времени DS3231, создали и настроили проект в Cube MX и Keil.

На данном занятии мы продолжим работать с тем же проектом и уже займёмся непосредственно кодом.

В файл main.h мы также добавим переменную для данных

В неё мы будем принимать значения сразу всех 7 регистров микросхемы и, предварительно заполнив в ней все ячейки, туда же и отправлять, когда будем устанавливать время в часах.

Екстерналим ее в i2c.c, также напишем там переменную для строки и напишем там две функции для работы с шиной.

extern uint8_t aTxBuffer[8];

void I2C_WriteBuffer(I2C_HandleTypeDef hi, uint8_t DEV_ADDR, uint8_t sizebuf)

while(HAL_I2C_Master_Transmit(&hi, (uint16_t)DEV_ADDR,(uint8_t*) &aTxBuffer, (uint16_t)sizebuf, (uint32_t)1000)!= HAL_OK)

if (HAL_I2C_GetError(&hi) != HAL_I2C_ERROR_AF)

void I2C_ReadBuffer(I2C_HandleTypeDef hi, uint8_t DEV_ADDR, uint8_t sizebuf)

while(HAL_I2C_Master_Receive(&hi, (uint16_t)DEV_ADDR, (uint8_t*) &aTxBuffer, (uint16_t)sizebuf, (uint32_t)1000)!= HAL_OK)

if (HAL_I2C_GetError(&hi) != HAL_I2C_ERROR_AF)

Первая функция будет для передачи данных в шину, а вторая – для приема.

Входные параметры в первой функции:

I2C_HandleTypeDef hi – идентификатор шины I2C.

DEV_ADDR – адрес устройства

sizebuf – количество байт, которые мы будем передавать.

Дальше идёт цикл, из которого мы выйдем тогда, когда данные передадутся и мы получим статус HAL_OK.

Статус нам уже будет возвращать стандартная функция передачи данных в I2C из библиотеки HAL HAL_I2C_Master_Transmit. В данную функцию мы передаём практически те же параметры, некоторые из них только явно преобразованы несколько в другой тип, а также передаём таймаут в милисекундах. Это не значит, что функция будет именно столько времени выполняться. При успешном выполнении мы будем из функции возвращаться мгновенно. А вот если что-то пойдёт не так, то будем ждать именно столько времени, а затем всё равно выйдем, правда с ошибкой.

Затем мы проверяем передачу на ошибку, и в случае, если она будет, то выведем текст ошибки на дисплей.

Во второй функции абсолютно такие же входные параметры, только там мы уже будем читать байты и отправлять их в тот же буфер.

Тело функции также аналогично телу предыдущей функции, только библиотечная фунция там уже применена HAL_I2C_Master_Receive.

Создадим для этих двух функций прототипы в файле i2c.h

void I2C_WriteBuffer(I2C_HandleTypeDef hi, uint8_t DEV_ADDR, uint8_t sizebuf);
void I2C_ReadBuffer(I2C_HandleTypeDef hi, uint8_t DEV_ADDR, uint8_t sizebuf);

Убираем весь код по дисплею кроме инициализации из главной функции.

Начинаем работать с шиной в главной функции main()

Сначала удалим код вывода тестовых строк на экран дисплея. Оставим только вот это

/* USER CODE BEGIN 2 */
LCD_ini();
LCD_Clear();

/* USER CODE END 2 */

Дальше уже начнем работать с функциями.

Пишем код в бесконечный цикл

while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)

Здесь мы сначала установим позицию строки в дисплее, инициализируем буфер, вернее не весь, а только его самую первую ячейку.

Далее мы передадим адрес устройства и адрес первого регистра микросхемы.

Пишем дальше в бесконечный цикл

Читайте также: Летние шины 195 65 r15 в саратове

while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY)

А затем мы уже считаем все 7 регистров в буфер из RTC

Так как данные мы приняли в двоично-десятичном коде, то мы не можем их нормально показать без преобразования. Поэтому напишем две функции преобразования в файле RTC.c

uint8_t RTC_ConvertFromDec(uint8_t c)

uint8_t RTC_ConvertFromBinDec(uint8_t c)

Также пропишем им прототипы в одноименном хедере.

uint8_t RTC_ConvertFromDec(uint8_t c); //перевод двоично-десятичного числа в десятичное

uint8_t RTC_ConvertFromBinDec(uint8_t c); //перевод десятичного числа в двоично-десятичное

date = RTC_ConvertFromDec(date); //Преобразуем в десятичный формат

LCD_SendChar((char) ((date/10)%10) + 0x30);

LCD_SendChar((char) (date%10) + 0x30);

month = RTC_ConvertFromDec(month); //Преобразуем в десятичный формат

LCD_SendChar((char) ((month/10)%10) + 0x30);

LCD_SendChar((char) (month%10) + 0x30);

year = RTC_ConvertFromDec(year); //Преобразуем в десятичный формат

LCD_SendChar((char) ((year/10)%10) + 0x30);

LCD_SendChar((char) (year%10) + 0x30);

day = RTC_ConvertFromDec(day); //Преобразуем в десятичный формат

LCD_SendChar((char) (day%10) + 0x30);

hour = RTC_ConvertFromDec(hour); //Преобразуем в десятичный формат

LCD_SendChar((char) ((hour/10)%10) + 0x30);

LCD_SendChar((char) (hour%10) + 0x30);

min = RTC_ConvertFromDec(min); //Преобразуем в десятичный формат

LCD_SendChar((char) ((min/10)%10) + 0x30);

LCD_SendChar((char) (min%10) + 0x30);

sec = RTC_ConvertFromDec(sec); //Преобразуем в десятичный формат

LCD_SendChar((char) ((sec/10)%10) + 0x30);

LCD_SendChar((char) (sec%10) + 0x30);

LCD_SendChar((char) ((i/100)%10) + 0x30);

LCD_SendChar((char) ((i/10)%10) + 0x30);

LCD_SendChar((char) (i%10) + 0x30);

LCD_SendChar((char) (((i+500)/100)%10) + 0x30);

LCD_SendChar((char) (((i+500)/10)%10) + 0x30);

LCD_SendChar((char) ((i+500)%10) + 0x30);

LCD_SendChar((char) (((i+750)/100)%10) + 0x30);

LCD_SendChar((char) (((i+750)/10)%10) + 0x30);

LCD_SendChar((char) ((i+750)%10) + 0x30);

В этом длинном коде мы для всех регистров микросхемы по очереди сначала из соответствующей ячейки буфера, в который мы данные регистры считали, сначала берём показание в переменную, затем преобразовываем в обычный десятичный вид, Затем десятки и единицы превращаем в символы в соответствии с таблицей ascii, и затем выводим на дисплей. Потом в конце применяем задержку 100 милисекунд, затем весь процесс повторяется сначала.

Остальной код из бесконечного цикла, оставшийся из проекта по тестированию и подключения дисплея, мы пока не убираем.

Соберём код и прошьём контроллер. Посмотрим, как у нас всё это работает.

Сканер i2c шины hal

Отладочную плату, дисплей LCD 20×4 и модуль RTC DS3231 с микросхемой памяти можно приобрести здесь:

Видео:Установщик адресов Flash-i2cСкачать

Установщик адресов Flash-i2c

Дружим STM32 с LCD дисплеем 1604 по I2C шине (библиотека HAL)

В этой статье я хотел бы рассказать о своем опыте подключения LCD дисплеев к микроконтроллеру STM32 с использованием библиотеки HAL по I2C шине.

Сканер i2c шины hal

Подключать буду дисплей 1602 и 2004. Они оба имеют припаянный I2C адаптер на основе чипа PCF8574T. Отладочной платой выступит Nucleo767ZI, а средой разработки – STM32CubeIDE 1.3.0.

Про принцип работы I2C шины подробно рассказывать не буду, советую заглянуть сюда и сюда.

Создаем проект, выбираем отладочную плату:

Сканер i2c шины hal

Указываем, что будем использовать I2C1. Также я подключу UART5 для общения с платой, это нужно для получения информации от платы об адресе дисплея.

Сканер i2c шины hal

Сканер i2c шины hal

В этом же окне можно посмотреть номера ножек, к которым подключается дисплей, в моем случае получилось так:

Сканер i2c шины hal

Для начала подключим всего один дисплей, я начну с 1602. Также я подключу известный бывалым ардуинщикам адаптер USB-UART CH340 для получения данных с платы.

Сканер i2c шины hal

Обратите внимание, адаптер подключается RX к TX и TX к RX, перемычка на адаптере стоит на 3.3В

Сканер i2c шины hal

Рассмотрим подробнее работу с микросхемой PCF8574T и дисплеем. Ниже приведена принципиальная схема модуля с дисплеем:

Читайте также: Зимние шины в барабинске

Сканер i2c шины hal

Микросхема PCF8574T по функционалу схожа с регистром сдвига 74hc595 – она получает по I2C интерфейсу байт и присваивает своим выводам (P0-P7) значения соответствующего бита.

Рассмотрим какие выводы микросхемы соединены с дисплеем и за что отвечают:

  • Вывод Р0 микросхемы соединен с выводом RS дисплея, отвечающего за то, принимает дисплей данные (1) или инструкции по работе дисплея (0);
  • Вывод Р1 соединен с R\W, если 1 – запись данных в дисплей, 0 – считывание;
  • Вывод Р2 соединен с CS – вывод, по изменению состояния которого идет считывание;
  • Вывод Р3 – управление подсветкой;
  • Выводы Р4 — Р7 служат для передачи данных дисплею.

К одной I2C шине может быть подключено несколько устройств одновременно. Для того, чтобы можно было обращаться к конкретному устройству, каждое из них имеет свой адрес, для начала выясним его. Если контакты А1, А2 и А3 на плате адаптера не запаяны, то адрес будет скорее всего 0х27, но лучше проверить. Для этого напишем небольшую функцию, которая покажет адреса всех устройств, которые подключены к I2C шине:

Данная функция опрашивает все адреса от 0 до 127 и если с этого адреса поступил ответ, она отправляет номер этого адреса в 16-тиричной форме в UART.

Для общения с платой я использую программу Termite. По умолчанию скорость UART у микроконтроллера устанавливается в значении 115200, необходимо установить такую же в термите. Вызываем функцию в основном теле программы, прошиваем плату и коннектимся в термите к нашему микроконтроллеру:

Сканер i2c шины hal

Точками отображаются все адреса, с которых ответ не был получен. Адрес у моего дисплея 0х26, так как я запаял перемычку А0. Теперь подключим второй дисплей параллельно первому, и посмотрим, что выдаст программа:

Сканер i2c шины hal

Имеем два адреса: 0х26 (дисплей 1602) и 0х27 (дисплей 2004). Теперь о том, как работать с дисплеем. Микроконтроллер посылает байт адреса, а все устройства, подключенные к шине, сверяют его со своим. Если он совпадает, то модуль начинает общение с микроконтроллером. В первую очередь нужно настроить дисплей: откуда будет идти отсчет символов и в какую сторону, как будет вести себя курсор и т.п. После этого уже можно будет передавать дисплею информацию для вывода. Особенность в том, что мы можем использовать только 4 бита для передачи информации, т.е. данные необходимо разбивать на две части. Данные хранятся в старших битах (4-7), а младшие биты используются для указания того, будет ли включена подсветка (3 бит), приходят ли данные для вывода или же настройки работы дисплея (вывод RS, 0 бит), и 2 бит, по изменению которого происходит считывание, т.е чтобы отправить 1 байт данных необходимо отправить 4 байта – 1й байт будет содержать 4 бита информации, 2й бит в состояние 1, 2й байт это повторение 1-го, только уже 2й бит в состояние 0. 3й и 4й байт аналогично, только там содержится вторая половина данных. Звучит немного непонятно, покажу на примере:

Разберем все по порядку. В начале идут переменные, хранящие в себе адрес дисплея, и биты настроек, которые необходимо отправлять каждый раз вместе с данными. В функции отправки мы в первую очередь проверяем, есть ли по записанному адресу модуль. В случае получения сообщения HAL_OK начинаем формировать байты для отправки. В начале байт, который мы будем отправлять, необходимо разделить на две части, оба из них записать в старшие биты. Допустим, мы хотим, чтобы дисплей отобразил символ ‘s’, в двоичной системе это 1110011 (калькулятор). С помощью логической операции & мы записываем в переменную up = 01110000, т.е. записываем только старшие биты. Младшие биты в начале сдвигаются влево на 4 символа, а потом записываются в переменную lo = 00110000. Дальше мы формируем массив из 4 байт, которые содержат информацию о символе, который необходимо вывести. Теперь к существующим байтам приписываем биты конфигурации (0-3 биты). После этого отправляем байт адреса и 4 байта информации на дисплей с помощью функции HAL_I2C_Master_Transmit();

Читайте также: Шины для мазда сх 5 зимние размер

Но не спешите загружать программу, ведь в начале необходимо задать настройки дисплею. На сайте есть прекрасная переведенная таблица с командами для настройки дисплея. Сверив ее с документацией, я пришел к следующим оптимальным для себя настройкам:

Эти команды поместим перед началом бесконечного цикла, чтобы настройки отправлялись единожды перед началом работы (как void setup у ардуинки). Функция I2C_send помимо байта требует указать, будут отправляться настройки дисплея или же данные. Если второй аргумент функции 0, то настройки, а если 1, то данные.

И последний штрих – нужна функция, которая будет отправлять сроку посимвольно. Тут все довольно просто:

Собрав все эти функции воедино можно написать:

Сканер i2c шины hal

Отлично, с дисплеем 1602 разобрались, теперь 2004. Разница между ними минимальная, даже этот код будет отлично работать. Все отличие сводится к организации адресов ячеек на дисплее. В обоих дисплеях память содержит 80 ячеек, в дисплее 1602 первые 16 ячеек отвечают за первую строчку, а за вторую строчку отвечают ячейки с 40 по 56. Остальные ячейки памяти на дисплей не выводятся, поэтому, если отправить на дисплей 17 символов, последний не перенесется на вторую строчку, а будет записан в ячейку памяти, не имеющую выхода на дисплей. Чуть более наглядно, память устроена так:

Сканер i2c шины hal

Для перевода строки я пользовался командой I2C_send(0b11000000,0);, она просто переходит к 40 ячейке. В дисплее 2004 все поинтереснее.

Первая строка — ячейки с 1 по 20
Вторая строка — ячейки с 40 по 60
Третья строка — ячейки с 21 по 40
Четвертая строка — ячейки с 60 по 80,
т.е. если отправить команду

Сканер i2c шины hal

Для организации переходов между строками необходимо переводить на нужную ячейку памяти курсор вручную, либо можно программно дополнить функцию. Я пока остановился на ручном варианте:

Сканер i2c шины hal

На этом пожалуй все с этими дисплеями, полезные ссылки, благодаря которым я смог во всем этом разобраться:

  1. Код во многом посмотрел вот тут
  2. Таблицы для конфигурации дисплея смотрел тут
  3. Порядок действий смотрел тут

🎬 Видео

Программирование МК STM32. УРОК 8. HAL. Шина I2C. Подключаем микросхему RTC DS3231Скачать

Программирование МК STM32. УРОК 8. HAL. Шина I2C. Подключаем микросхему RTC DS3231

Урок 24. Узнаём адреса устройств на шине I2CСкачать

Урок 24. Узнаём адреса устройств на шине I2C

Что такое I2C ??? Подключаем GY-521 и Oled 96*16 к STM 32Скачать

Что такое I2C ??? Подключаем GY-521 и Oled 96*16 к STM 32

Логический анализатор шины i2cСкачать

Логический анализатор шины i2c

Введение в шину I2CСкачать

Введение в шину I2C

I2C. Краткая теория с примером. STM32 CubeIDE.Скачать

I2C. Краткая теория с примером. STM32 CubeIDE.

Подключение нескольких устройств, датчиков по I2C (АйТуСи) шинеСкачать

Подключение нескольких устройств, датчиков по I2C (АйТуСи) шине

STM32: Интерфейсная шина I2C. Подключаем HDC1080.Скачать

STM32: Интерфейсная шина I2C. Подключаем HDC1080.

Сканер I2C eeprom AT24C04Скачать

Сканер I2C eeprom AT24C04

Проверка работоспособности шины I2CСкачать

Проверка работоспособности шины I2C

Шина данных i2c - декодируем/синхронизируем с помощью осциллографа Lecroy!Скачать

Шина данных i2c - декодируем/синхронизируем   с помощью осциллографа Lecroy!

MCP2515, контроллер CAN шины с интерфейсом SPIСкачать

MCP2515, контроллер CAN шины с интерфейсом SPI

Урок 9. Адреса модулей на шине I2C. Arduino (что такое I2C, адресация, как изменить адрес модуля)Скачать

Урок 9. Адреса модулей на шине I2C. Arduino (что такое I2C, адресация, как изменить адрес модуля)

Лекция 308. Шина I2CСкачать

Лекция 308.  Шина I2C

STM32: Сканер I2C шини на stm32f103c8Скачать

STM32: Сканер I2C шини на stm32f103c8

Шина I2C.Скачать

Шина I2C.

Программирование МК STM32. Урок 172. CMSIS. STM32F1. I2C. Подключаем внешний EEPROMСкачать

Программирование МК STM32. Урок 172. CMSIS. STM32F1. I2C. Подключаем внешний EEPROM
Поделиться или сохранить к себе:
Технарь знаток