Avr315

Полезные страницы

  • Набор GyverKIT – большой стартовый набор Arduino моей разработки, продаётся в России
  • Каталог ссылок на дешёвые Ардуины, датчики, модули и прочие железки с AliExpress у проверенных продавцов
  • Подборка библиотек для Arduino, самых интересных и полезных, официальных и не очень
  • Полная документация по языку Ардуино, все встроенные функции и макросы, все доступные типы данных
  • Сборник полезных алгоритмов для написания скетчей: структура кода, таймеры, фильтры, парсинг данных
  • Видео уроки по программированию Arduino с канала “Заметки Ардуинщика” – одни из самых подробных в рунете
  • Поддержать автора за работу над уроками
  • Обратная связь – сообщить об ошибке в уроке или предложить дополнение по тексту ([email protected])

Testing the final program code

In the main program, you can see EEPROM testing routines that show everything is working correctly. Test routine checks single-byte write to custom address location and then reading. On the terminal screen, you can view if the written and read results are the same. Also, a page write test is done. It writes 16 bytes of information to page 5 and then reads them to a different buffer. Then write and read buffers are compared, and if both are equal – a success message is displayed on the terminal screen. Main program:

#include <stdio.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "usart.h"
#include "ee24c16.h"
//set stream pointer
FILE usart0_str = FDEV_SETUP_STREAM(USART0SendByte, USART0ReceiveByte, _FDEV_SETUP_RW);
int main(void)
{
    uint8_t u8ebyte;
    uint8_t u8erbyte;
    uint16_t u16eaddress = 0x07F0;
    uint8_t page = 5;
    uint8_t i;
    uint8_t eereadpage;
    uint8_t eewritepage = { 10, 44, 255, 46, 80, 87, 43, 130,
                                210, 23, 1, 58, 46, 150, 12, 46 };
//Initialize USART0
USART0Init();
//
TWIInit();
//assign our stream to standard I/O streams
stdin=stdout=&usart0_str;
printf("\nWrite byte %#04x to eeprom address %#04x", 0x58, u16eaddress);
if (EEWriteByte(u16eaddress, 0x58) != ERROR)
{
    printf_P(PSTR("\nRead byte From eeprom"));
    if (EEReadByte(u16eaddress, &u8ebyte) != ERROR)
    {
        printf("\n*%#04x = %#04x", u16eaddress, u8ebyte);
    }
    else printf_P(PSTR("\nStatus fail!"));

}   
else printf_P(PSTR("\nStatus fail!"));
    
printf_P(PSTR("\nWriting 16 bytes to page 5 "));
if(EEWritePage(page, eewritepage) != ERROR)
{
    printf_P(PSTR("\nReading 16 bytes from page 5 "));
    if (EEReadPage(page, eereadpage) != ERROR)
    {
        //compare send and read buffers
        for (i=0; i<16; i++)
        {
            if (eereadpage != eewritepage)
            {
                break;
            }       
                else continue;
        }
        if (i==16)
            printf_P(PSTR("\nPage write and read success!"));
        else
            printf_P(PSTR("\nPage write and read fail!"));
    } else printf_P(PSTR("\nStatus fail!"));

}else printf_P(PSTR("\nStatus fail!"));

printf_P(PSTR("\nContinue testing EEPROM from terminal!"));
    while(1)
    {
        printf("\nEnter EEPROM address to write (MAX = %u): ", EEMAXADDR);
        scanf("%u",&u16eaddress);
        printf("Enter data to write to EEPROM at address %u: ", u16eaddress);
        scanf("%u",&u8ebyte);
        printf_P(PSTR("\nWriting..."));
        EEWriteByte(u16eaddress, u8ebyte);
        printf_P(PSTR("\nTesting..."));
        if (EEReadByte(u16eaddress, &u8erbyte) !=ERROR)
            {
                if (u8ebyte==u8erbyte)
                    printf_P(PSTR("\nSuccess!"));
                else
                    printf_P(PSTR("\nFail!"));
            }
            else printf_P(PSTR("\nStatus fail!"));

        //TODO:: Please write your application code 
    }
}

You can play around by sending data bytes to custom address locations from the terminal screen and test various data memory locations.

AVR Studio 5 project files for download . Have fun!

AVR I2C interface registers

AVR microcontroller is using TWI (Two Wire Interface) terminology when talking about I2C. So all registers are named TWI.

One important register is bit rate register TWBR. It is used to scale down CPU frequency into SCL. Additionally, two bits (TWPS1 and TWPS2) in status register TWSR to prescale SCL frequency with values 1, 4, 16, and 64. You can find the formula in the datasheet that is used to calculate SCL end frequency:

As usually there is a control register TWCR which has a set of bits that are used to enable TWI to interrupt, TWI, Start and Stop.

Status register TWSR holds earlier mentioned prescaller bits, but its primary purpose of sensing I2C bus status with TWS bits. TWDR is a data register used to hold the next byte to transmit or receive the byte. TWAR and TWARM registers are used when AVR works as an I2C slave.

Что такое I2C?

c — это аббревиатура от Inter-Integrated Circuit (меж-интеграционная цепь или последовательная асимметричная шина).

I2C — низкоскоростной последовательный протокол связи, подходящий для передачи данных на короткие расстояния. Если вам необходимо передавать данные на большие расстояния, этот протокол не рекомендуется. Пример простой сети I2C показан ниже.

Как видно на диаграмме, преимущество использования I2C состоит в том, что для связи с несколькими устройствами требуется всего два провода.

Вся связь проходит по двум проводам к ведущему и ведомым устройствам и от них. Это очень полезно при выполнении проектов Arduino, так как Arduino имеет ограниченное количество входных/выходных контактов.

Многие датчики и модули, предназначенные для Arduino используют I2C для связи.

Подключение программатора

Программатор, или Ардуину в качестве программатора, подключить очень просто. Смотрим распиновку и подключаем:

  • Шину ISP: пины MOSI, MISO и SCK. Они есть на всех МК
  • Сброс RST
  • Землю GND. Любую из имеющихся, они соединены внутри МК
  • Если МК не питается от своего источника, подключаем заодно VCC

Например ATmega328p подключаем к USB ASP (обсуждали в прошлом уроке) 6-пин вот так:  Примечание: да, другие компоненты не нужны. Новый (из магазина)  МК тактируется от внутреннего генератора на 8 МГц и может без проблем прошиваться прямо так как на схеме выше. Тиньки к тому же USB ASP подключаются так: Для удобства я использую макетку-дигиспарк, на которой разведены пины как раз под ISP 6-пин хэдер: втыкается выпирающим “ключом” в сторону МК. В плате выведены 8 пинов, нам нужны верхние 6 (на фото видно не запаянные пины ниже штекера). Купить можно тут.   Также можно прошивать МК через Arduino (Arduino as ISP, обсуждали в прошлом уроке). Схема для ATtiny85:   Примечание: конденсатор нужен обязательно! Подключили. Что дальше? Дальше мы уже можем работать с фьюзами через программу avrdudeprog (обсуждали в прошлом уроке), выбрав в списке соответствующий программатор и в списке МК – соответствующий МК. Также через эту программу можно загрузить скомпилированный “бинарник” – файл прошивки. Но нас всё-таки интересует работа через Arduino IDE.

Когда ведущие устройства не могут уживаться вместе

Часть того, что делает I2C настолько универсальной, – это поддержка нескольких ведущих устройств. Но, как показывает предыдущий раздел, ведущие устройства не всегда хорошо работают вместе. Логика I2C устройства должна быть в состоянии определить, свободна ли шина; если шину занял другой мастер, то устройство до запуска своей собственной транзакции ждет, пока не завершится текущая транзакция. Но что происходит, когда два (или более) мастера пытаются инициировать транзакцию одновременно? I2C обеспечивает эффективное и удивительно простое решение этой неприятной, если бы она случилась, проблемы. Этот процесс называется «арбитраж», и он полагается на гибкость схемы шины I2C с открытым стоком: если один мастер пытается привести сигнал к логической единице, а другой мастер пытаются привести сигнал к логическому нулю, то «выиграет» мастер с логическим нулем, и, кроме того, «проигравший» может обнаружить, что фактическое состояние на выходе отличается от состояния, которое он хотел установить:

Арбитраж на шине I2C

Эта схема показывает основу арбитража I2C; процесс происходит следующим образом:

  1. Оба мастера генерируют стартовые биты и осуществляют свои передачи.
  2. Если мастера выбирают на линии одни и те же логические уровни, ничего не происходит.
  3. Как только мастера пытаются установить на линии разные логические уровни, мастер, установивший на линии логический ноль, объявляется победителем; а проигравший обнаруживает несоответствие логических уровней и отказывается от своей передачи.

Потратьте минутку, чтобы оценить простоту и эффективность этого механизма:

  • Победитель продолжает свою передачу без перерыва – нет поврежденных данных, нет конфликта устройств, нет необходимости в перезапуске транзакции.
  • Теоретически проигравший мог контролировать адрес ведомого устройства в ходе процесса арбитража и фактически принимать правильные данные, если так оказалось, что он и является этим ведомым устройством.
  • Если конкурирующие мастера запрашивают данные от одного и того же ведомого устройства, процесс арбитража не требует необязательного прерывания транзакции – не будет обнаружено ошибки, и ведомое устройство выведет свои данные на шину, чтобы их могли получить несколько мастеров.

Где применяется протокол I2C

Протокол I2C используется для передачи информации только на короткие расстояния. Он обеспечивает достаточно надежную передачу данных из-за наличия в нем сигнала синхронизации. Обычно данный протокол используется для передачи информации от датчиков или других устройств ведущим устройствам. В данном случае несомненным удобством использования протокола I2C является то, что при обмене данными с ведомыми устройствами ведущий микроконтроллер использует минимум линий (контактов). Если вам нужна связь на более далекие расстояния, то вам необходимо присмотреться к протоколу RS232, если же вам нужна более надежная связь чем в протоколе I2C, то вам лучше использовать протокол SPI.

Проблемы при использовании с ATtiny

В библиотеке для буферов используется большой объем памяти. Он включает в себя 3 разных байтовых буфера, каждый размером 32 байта. Это не большая проблема для ATmega, но ATtiny (например, ATtiny48) обладает меньшим количеством RAM (512/1K у ATmega, и 256/512 у ATtiny). Когда я попытался использовать библиотеку Wire на ATtiny, у меня появлялись случайные сбои, зависания и т.д. Как только я изменил размер буфера (в .\libraries\Wire\utility\twi.h) на 6, всё отлично заработало.

Не делайте ошибку, думая, что вы можете просто указать в своем скетче  потому, что это не работает. Способ, которым Arduino IDE компилирует ваш код, не очевиден. Библиотека компилируется отдельно от вашего скетча, а затем линкуется с ним. Поэтому вам придется изменить размер буфера в заголовочном файле библиотеки, который также включается в исходном файле библиотеки (twi.c).

Сколько байт?

Каждая транзакция начинается одинаково: стартовый бит, адрес, чтение/запись, ACK/NACK. После этого любое количество байт данных может быть отправлено от мастера к ведомому устройству или от ведомого к мастеру, причем после каждого байта следует ACK или NACK. NACK может быть полезен как способ сказать: «прекрати отправку данных!»

Например, мастер может захотеть получать непрерывный поток данных от ведомого устройства (например, датчик температуры); за каждым байтом следует ACK, и если мастеру необходимо обратить внимание на что-то еще, он может послать ведомому устройству NACK и начать новую транзакцию, когда будет снова готов

Многобайтовая транзакция

Тестирование Arduino I2C

А вот и самая захватывающая часть — включение питания и тестирование!

Используя Arduino IDE, загрузите эскиз мастера Arduino в одну из Ардуино. Затем загрузите скетч наследника в другую Arduino.

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

Наш код принимает положение потенциометра мастера и посылает его ведомому устройству через I2C. Затем ведомое устройство использует полученное значение для настройки времени задержки мигания светодиода. То же самое происходит и с положением потенциометра ведомого.

Ставим “ядро”

Для того, чтобы работать с Attiny через Arduino IDE, нам нужно установить так называемое ядро, или как оно называется в самой IDE – плату. Для ATmega328 у нас уже есть стандартное ядро, например плата Arduino NANO. Но тут есть нюанс: внутренние настройки “платы” NANO рассчитаны на работу с загрузчиком (bootloader) и с внешним тактированием 16  Мгц, то есть лучше не рисковать и установить ядро, которое поддерживает работу без загрузчика и с возможностью выбора частоты, чтобы иметь полный контроль над платой. Могу посоветовать вот эти:

  • GyverCore – ядро для ATmega328, которое разработали мы с коллегой. Лёгкое и быстрое, возможность работы без загрузчика и широкий выбор вариантов тактирования. Ссылка для менеджера плат: https://alexgyver.github.io/package_GyverCore_index.json
  • MiniCore – ядро для поддержки и расширенной настройки МК ATmega328, ATmega168, ATmega88, ATmega48 и ATmega8. Ссылка для менеджера плат: https://mcudude.github.io/MiniCore/package_MCUdude_MiniCore_index.json
  • ATTinyCore – ядро для поддержки и расширенной настройки МК ATtiny 441/841, 44/84, 45/85, 461/861, 48/88, 828, 1634, 87, 167. Ссылка для менеджера плат: http://drazzy.com/package_drazzy.com_index.json
  • MicroCore – ядро для поддержки и расширенной настройки МК ATtiny13, ATtiny13A и ATtiny13V. Ссылка для менеджера плат: https://mcudude.github.io/MicroCore/package_MCUdude_MicroCore_index.json
  • megaTinyCore – ядро для поддержки и расширенной настройки МК ATtiny 3217, 1617, 817, 417, 3216, 1616, 816, 416, 1614, 814, 414, 214, 412, 212, 1607, 807, 1606, 806, 406, 1604, 804, 404, 204, 402, 202. Новые модели шьются по UPDI, по этой теме читайте отличную статью на русском языке. Можно сделать программатор из обычной Ардуины – читай тут. Данное ядро можно установить через менеджер плат, ищите по названию Arduino megaAVR board package, никаких ссылок вставлять не нужно.
  • MightyCore – ядро для поддержки и расширенной настройки МК ATmega8535, ATmega16, ATmega32, ATmega164, ATmega324, ATmega644 и ATmega1284. Ссылка для менеджера плат: https://mcudude.github.io/MightyCore/package_MCUdude_MightyCore_index.json
  • MegaCore – ядро для поддержки и расширенной настройки МК ATmega64, ATmega128, ATmega640, ATmega1280, ATmega1281, ATmega2560, ATmega2561, AT90CAN32, AT90CAN64 и AT90CAN128. Ссылка для менеджера плат: https://mcudude.github.io/MegaCore/package_MCUdude_MegaCore_index.json

Как установить ядро: идём в Файл/Настройки и вставляем ссылку в окно дополнительных ссылок для менеджера плат   Далее идём в Инструменты/Плата/Менеджер плат… и находим нужное ядро. Устанавливаем   После этого в списке плат появится новое семейство плат/МК на выбор. Я буду работать с ATtiny85   Нас интересует меню Clock – тактирование. ATtiny85 интересна тем, что может тактироваться от внутреннего источника на 8 МГц, но также может его “умножить” на 2 и получится 16 МГц, этот вариант называется 16 MHz (PLL). Это очень круто, потому что голый чип будет работать с почти максимальной скоростью, что делает его ничуть не хуже той же Arduino Nano. Выбираем программатор из списка (я буду прошивать при помощи USB ASP). Однократно выполним Инструменты/Записать загрузчик, чтобы применить настройки тактирования:   Про остальные менюшки и варианты можно догадаться из их названия, или почтить подробное описание на GitHub по ссылкам выше.

Часть первая, I2C и библиотека «Wire».

Последовательный протокол обмена данными IIC (также называемый I2C — Inter-Integrated Circuits, межмикросхемное соединение). Разработана фирмой Philips Semiconductors в начале 1980-х как простая 8-битная шина внутренней связи для создания управляющей электроники. Так как право на использование его стоит денег фарма Atmel назвала его TWI, но смысл от этого не меняется.

Как это работает ?

Для передачи данных используются две двунаправленные лини передачи данных. SDA (Serial Data) шина последовательных данных и SCL (Serial Clock) шина тактирования. Обе шины подтянуты резисторами к плюсовой шине питания. Передача/Прием сигналов осуществляется прижиманием линии в 0, в единичку устанавливается сама, за счет подтягивающих резисторов.

В сети есть хотя бы одно ведущее устройство (Master), которое инициализирует передачу данных и генерирует сигналы синхронизации и ведомые устройства (Slave), которые передают данные по запросу ведущего. У каждого ведомого устройства есть уникальный адрес, по которому ведущий и обращается к нему. Конечно понятно что Ведущий это наш микроконтроллер , а ведомый наша память. Ведущее устройство начинает прижимать шину SCL  к нулю с определенной частотой, а шину SDA прижимать или отпускать на определенное число тактов передавая Единичку или Нолик. Передача данных начинается с сигнала START потом передается 8 бит данных и 9-тым битом Ведомое устройство подтверждает прием байт  прижимая шину SDA к минусу. Заканчивается передача сигналом STOP.

Библиотека «Wire».

Для облегчения обмена данными с устройствами по шине I2C для Arduino написана стандартная библиотека Wire которая есть уже в комплекте IDE. Она имеет следующие основные функции:

Wire.begin(Address) вызывается один раз для инициализации  и подключения к шини как Ведущий или Ведомое устройство. Если Address не задан подключаемся как Мастер устройство.

Wire.beginTransmission(address)  начинает передачу на ведомое I2C устройство с заданным адресом.

Wire.endTransmission() прекращает передачу данных ведомому. Функция возвращает значение типа byte:

  • 0 — успех.
  • 1- данные слишком длинны для заполнения буфера передачи.
  • 2 — принят NACK при передаче адреса.
  • 3 — принят NACK при передаче данных.
  • 4 — остальные ошибки.

Wire.write() запись данных  от ведомого устройства в отклик на запрос от ведущего устройства, или ставит в очередь байты для передачи от мастера к ведомому устройству.Фактически записывает данные в буфер. Размер буфера 32 байта ( минус 2 байта адрес, фактически 30 байт), а передает буфер функция Wire.endTransmission().

  • Wire.write(value) — value: значение для передачи, один байт.
  • Wire.write(string) — string: строка для передачи, последовательность байтов.
  • Wire.write(data, length) — data: массив данных для передачи, байты. length: количество байтов для передачи.

Wire.read() Считывает байт, который был передан от ведомого устройства к ведущему или который был передан от ведущего устройства к ведомому. Возвращаемое значение byte : очередной принятый байт.

Это самые основные функции библиотеке, остальные мы рассмотрим по ходу пьесы ))

Старт без стопа

Протокол I2C допускает нечто, называемое условием «повторного старта». Это происходит, когда мастер инициирует транзакцию со стартовым битом, а затем инициирует новую транзакцию через другой стартовый бит без промежуточного стопового бита следующим образом:

Повторный старт

Эта функция может использоваться всякий раз, когда одному ведущему устройству необходимо выполнить две или более отдельных транзакции. Однако есть ситуация, когда условие повторного старта особенно удобно.

Допусти, у вас есть ведомое устройство, которое хранит информацию в банке регистров. Вы хотите запросить данные из регистра с адресом 160, 0xA0 в шестнадцатеричном формате. Протокол I2C не позволяет мастеру отправлять данные и получать данные в одной транзакции. Следовательно, вы должны выполнить транзакцию записи, чтобы указать адрес регистра, а затем отдельную транзакцию чтения для извлечения данных. Хотя этот подход может привести к проблемам, поскольку мастер освобождает шину в конце первой транзакции, и, таким образом, другой мастер может занять шину и не дать первому мастеру получить нужные ему данных. Кроме того, второй мастер может взаимодействовать с тем же ведомым устройством и задать другой адрес регистра… Если первый мастер затем займет шину и прочитает данные без повторного указания адреса регистра, он будет считывать неправильные данные! Если второй мастер затем попытается выполнить транзакцию чтения в своей процедуре «запись и затем чтение», то это также закончится чтением неверных данных! Этого системного сбоя стоит ожидать, но, к счастью, условие повторного старта может предотвратить этот беспорядок, инициировав вторую транзакцию (чтение) без освобождения шины.

Пример использования повторного старта

Coding I2C interface functions

For debugging purposes, USART is used, which was discussed in earlier tutorials. So we are going to set it to 9600 baud and use it as library usart.h.

To have excellent control of the I2C interface, let’s split the whole process into multiple functions. First of all, we need to initialize TWI (I2C):

void TWIInit(void)
{
    //set SCL to 400kHz
    TWSR = 0x00;
    TWBR = 0x0C;
    //enable TWI
    TWCR = (1<<TWEN);
}

So we set the bit rate register to 0x0C value, which sets SCL to 400kHz. We don’t need additional prescallers, so set TWSR to 0. And finally, we enable TWI by setting TWEN bit to “1”.

Next, we take care of TWIStart and TWIStop functions that generate start and stop signals.

void TWIStart(void)
{
    TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
}
//send stop signal
void TWIStop(void)
{
    TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

We need to set TWSTA and stop TWSTO bits along with TWINT and TWEN bits for a start. After the start signal is sent, we need to wait for status (until TWINT resets zero).

Another function is TWIWrite:

void TWIWrite(uint8_t u8data)
{
    TWDR = u8data;
    TWCR = (1<<TWINT)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
}

It writes a data byte to the TWDR register, which is shifted to the SDA line. Waiting for transmission complete within a while loop is essential. After which status can be read from status register TWSR.

Reading is done similarly. I have written two functions where one transmits ACK signal after byte transfer while another doesn’t:

uint8_t TWIReadACK(void)
{
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
    while ((TWCR & (1<<TWINT)) == 0);
    return TWDR;
}
//read byte with NACK
uint8_t TWIReadNACK(void)
{
    TWCR = (1<<TWINT)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
    return TWDR;
}

And finally, we are going to use the reading status function:

uint8_t TWIGetStatus(void)
{
    uint8_t status;
    //mask status
    status = TWSR & 0xF8;
    return status;
}

We need to read the upper five bits from the TWSR register, so we mask three lower bits. As we will see, reading status messages is an essential part of detecting failures in I2C communication.

Протокол I2C в Arduino

На следующем рисунке показаны контакты платы Arduino UNO, которые используются для связи по протоколу I2C.

Линия протокола I2C Контакт платы Arduino UNO
SDA A4
SCL A5

Для осуществления связи по протоколу I2C в плате Arduino используется библиотека <Wire.h>. В ней содержатся следующие функции для связи по протоколу I2C.

1. Wire.begin(address).

Эта команда производит инициализацию библиотеки Wire и осуществляет подключение к шине I2C в качестве ведущего (master) или ведомого (slave). 7-битный адрес ведомого в данной команде является опциональным и если он не указан , то устройство (плата Arduino) подключается к шине I2C в качестве ведущего (master).

2. Wire.read().

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

3. Wire.write().

Эта функция используется для записи данных в устройство, являющееся ведомым или ведущим.

От ведомого ведущему (Slave to Master): ведомый записывает (передает) данные ведущему когда в ведущем работает функция Wire.RequestFrom().

От ведущему ведомому (Master to Slave): в этом случае функция Wire.write() должна использоваться между вызовами функций Wire.beginTransmission() и Wire.endTransmission().

Функцию Wire.write() можно использовать в следующих вариантах:

  • Wire.write(value); value — значение передаваемого одиночного байта;
  • Wire.write(string) – для передачи последовательности байт;
  • Wire.write(data, length); data – массив данных для передачи в виде байт, length – число байт для передачи.

4. Wire.beginTransmission(address).

Эта функция используется для начали передачи по протоколу I2C устройству с заданным адресом ведомого (slave address). После этого вызывается функция Wire.write() с заданной последовательностью байт для передачи, а после нее функция endTransmission() для завершения процесса передачи.

5. Wire.endTransmission().

Эта функция используется для завершения процесса передачи ведомому устройству, который до этого был инициирован функциями beginTransmission() и Wire.write().

6. Wire.onRequest().

Эта функция вызывается когда ведущий запрашивает данные с помощью функции Wire.requestFrom() от ведомого устройства. В этом случае мы можем использовать функцию Wire.write() для передачи данных ведущему.

7. Wire.onReceive().

Эта функция вызывается когда ведомое устройство получает данные от ведущего. В этом случае мы можем использовать функцию Wire.read() для считывания данных передаваемых ведущим.

8. Wire.requestFrom(address,quantity).

Эта функция используется в ведущем устройстве чтобы запросить байты (данные) с ведомого устройства. После этого используется функция Wire.read() чтобы принять данные переданные ведомым устройством.
address: 7-битный адрес устройства, с которого запрашиваются байты (данные).
quantity: число запрашиваемых байт.

Технические характеристики модуля

  • Напряжение питания: DC6 ~12 V / DC 5,0 Micro USB
  • Измерение напряжения: 0 ~ 200 В, точность: 0,05 В
  • Регулируемый диапазон тока: 0 ~ 20 A, точность: 0.05 A
  • Диапазон измерения емкости АКБ: 0 ~ 999.999 Ач, точность: 0.01 Ач
  • Диапазон накопительной мощности: 0 ~ 99999.9 Втч, точность: 0.01 Втч
  • Диапазон измерения мощности: 0 ~ 2999,99 Вт, точность: 0,01 Вт
  • Диапазон измерения сопротивления: 1 ~ 999,9 Ом, Точность: 0,01 Ом
  • Диапазон измерения температур: 0 ~ 99 градусов, точность: 1 градус
  • Вентилятор охлаждения автоматически стартует с тока > 0.5 A или температуры > 45 С
  • Вход/выход: 20 А винтовые клеммы + USB
  • Время обновления: > 500 мс
  • Скорость измерения: около 2 с
  • Перенапряжение и перегрузка по току есть оповещение и защита.

Стоимость менее 2000 рублей — не так уж и много. Параметры зато обнадеживающие, а именно: мощность 180 Вт, ток 20 А, напряжение 200 В. Можно предположить, что 99% источников питания могут быть нагружены этим.

Управление устройством — две кнопки / энкодера. На самом деле оказалось, что эти ручки являются потенциометрами для установки тока 0-20 А, где одна устанавливает его ​​грубо, а другая точно. Этот метод уже много лет используется в популярных китайских источниках питания. Все результаты измерения доступны на одном экране. Есть несколько на разных языках, и после первого запуска выбираем тот, который подходит лучше всего, он остается навсегда. Далее в меню есть опция установки зуммера для превышения напряжения или тока, как вверх, так и вниз, что будет полезно при тестовой разрядке аккумуляторных батарей.

Использование прибора сводится к подключению источника питания 12 В постоянного тока и подключению проверяемого блока питания. Есть несколько типов разъемов: обычные винтовые разъемы, типовая розетка питания и 4 типа USB — тип A / большой плоский / мини-USB, микро-USB и тип C. Кроме того, есть кабели с зажимами типа «крокодил» и дополнительный адаптер для крокодилов.

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

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

Но это было не всегда так красочно. До этого уже ремонтировалась похожая нагрузка. Сначала после подключения напряжения с током всего несколько ампер сгорел силовой транзистор. После снятия радиатора оказалось, что термопаста вообще отсутствует, а сам транзистор был припаян, поэтому он не касался радиатора идеально плоско. Первоначальный какой-то полевой транзистор из серии IRFP был установлен в корпусе TO-247, вроде IRFP450. Поскольку поверхность радиатора намного больше, чем у этого транзистора, возникла идея установить больший, в корпусе TO-264, как раз нашелся GT60M104. Этот транзистор подошел бы почти идеально, если бы не датчик температуры, который припаян на плате рядом с транзистором, и больший корпус перекрывался с этим датчиком примерно на миллиметр. Поэтому подшлифовал транзистор так, чтобы он поместился рядом с датчиком, конечно заполнил всё термопастой хорошего качества и после сборки радиатора уже работает отлично. После ремонта снял с устройства все 180 Вт, радиатор не достигает более 45 градусов, что кажется отличным результатом.

Полезное: Измеритель электрического и электромагнитного поля BENETECH

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

В общем это полезное по своим возможностям и дешевое устройство, которое называется активная загрузка или электронная загрузка на английском языке. Правда словосочетание «искусственная нагрузка» более привычно в нашей стране.

Заключение

В данной статье рассмотрены важные детали I2C, которые влияют на разработку программного или низкоуровнего аппаратного обеспечения. Если ваш микроконтроллер включает аппаратные модули I2C или SMBus, то некоторые детали реализации будут обрабатываться автоматически. Хотя это и удобно, но не оправдывает безграмотность потому, что вам всё равно нужно знать хотя бы немного (и, возможно, немного больше) о том, как на самом деле работает I2C. Кроме того, если вы когда-нибудь окажетесь на необитаемом острове без аппаратных модулей I2C, представленная здесь информация поможет вам на пути к разработке чисто программных I2C функций (с так называемой побитовой обработкой).

Рейтинг
( Пока оценок нет )
Editor
Editor/ автор статьи

Давно интересуюсь темой. Мне нравится писать о том, в чём разбираюсь.

Понравилась статья? Поделиться с друзьями:
Семинар по технике
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: