Всем привет! Решил просканировать шину I2С и при этом не использовать ардуиновских продуктов - с ними и так все понятно и просто . Выбрал аппаратную реализацию и ...не могу найти проблему - сообщает код состояния шины 0х48 ( т.е. адрес отправлен и ACK не получен)
Код:
/*atmega 328 * 2708.cpp *27/08/24 настроил uart * Created: 27.08.2024 21:34:56 * Author : Павел */ #define F_CPU 8000000UL // Тактовая частота микроконтроллера #include <avr/io.h> #include <util/delay.h> // Библиотека программной задержки #define BAUD 9600UL // Задание скорости обмена по UART #define SPEED ((F_CPU+BAUD*8)/(BAUD*16)-1) #define F_I2C 100000UL #define TWBR_VALUE (((F_CPU)/(F_I2C)-16)/2) void out_UART (uint8_t); void Init_i2c(void) // Настройка режима мастера { PORTC |=( 1<<PC5|1<<PC4); // Включим подтяжку на ноги, вдруг юзер на резисторы пожмотился DDRC &=~(1<<PC5|1<<PC4);
/*выдаем на шину пакет SLA-R*/ TWDR = (adress<<1)|1; TWCR = (1<<TWINT)|(1<<TWEN); while(!(TWCR & (1<<TWINT))); uint8_t a=TWSR; //if(a==0x08){ while(!(UCSR0A&(1<<UDRE0))); // Ожидание готовности UART к передаче UDR0 = a; //} //while(!(UCSR0A&(1<<UDRE0))); // Ожидание готовности UART к передаче //UDR0 =0xFF; _delay_ms(100); }
/* Replace with your application code */ while (1) { } }
//////////////////////////////////////////////////////////// // ПРИЕМ/ПЕРЕДАЧА ДАННЫХ UART //////////////////////////////////////////////////////////// void out_UART(uint8_t data){ // Передача байта через UART while(!(UCSR0A&(1<<UDRE0))); // Ожидание готовности UART к передаче UDR0 = data; // Запись в регистр UDR байта данных начинает процесс передачи }
PORTC |=( 1<<PC5|1<<PC4); // Включим подтяжку на ноги, вдруг юзер на резисторы пожмотился
как это спасёт от отсутствия подтяжки на линии?
Порт у МК устроен так, что когда он настроен на вход его регистр вывода своей лог.1 включает подтяжку к VCC.
_________________ Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ Актуальность репозитория: 1 июля 2025 года Если чего-то не хватает с сайта st.com - пишите, докачаю.
Использование модульных источников питания открытого типа широко распространено в современных устройствах. Присущие им компактность, гибкость в интеграции и высокая эффективность делают их отличным решением для систем промышленной автоматизации, телекоммуникационного оборудования, медицинской техники, устройств «умного дома» и прочих приложений. Рассмотрим подробнее характеристики и особенности трех самых популярных вариантов AC/DC-преобразователей MW открытого типа, подходящих для применения в промышленных устройствах - серий EPS, EPP и RPS представленных на Meanwell.market.
PORTC |=( 1<<PC5|1<<PC4); // Включим подтяжку на ноги, вдруг юзер на резисторы пожмотился
как это спасёт от отсутствия подтяжки на линии?
Не, не! не пожмотился - на отладочной плате PinBoard они есть и я их задействовал
Добавлено after 3 minutes 4 seconds: Были мысли, что хватаю данные из регистра состояния до того , как ведомый успел подать сигнал на шину и для этого еще одну задержку ввел после отправки адреса
Добавлено after 1 minute 18 seconds: еще вот тут поправил
Нет, без библиотек. Всё своё, по минимуму). А, извиняюсь.( I2C на мастере программный.
можете мне пример из вашего готового с вариантом опроса шины avr скинуть в тексте кода? - я бы сравнил, что не так у меня . Даташит перевел, все прочитал и даже вроде все понятно, кроме того брал за основу готовый пример, где понимаю все "до винтика" - но в моем варианте не заработало
Были мысли, что хватаю данные из регистра состояния до того , как ведомый успел подать сигнал на шину и для этого еще одну задержку ввел после отправки адреса
задержка вряд ли.. ACK на 9-м такте формируется..
p7070 писал(а):
готовый пример
ну точно, DI HALT же, судя по реплике))
если что, то мой код на асме, и он один в один из даташита (Table 26-2) и без проверок статуса
if (!i2c_start(DEVICE | WRITE)) return false; if (!i2cWriteAddress(address)) return false; do ack = i2cWrite(*buffer++); while (--size); i2c_stop(); return ack; }
Так софтовый же). И в/в по хитрому. Но логика должна быть понятна.
А, софтовый, ок, понятно. Я тоже в одном проекте не захотел обрабатывать кучу ошибок в аппаратнос I2C (только уже на STM32F4) и написал простой программный мастер. Т.к. слейв один и это обычная флешка всё работает стабильно. Но я всё равно подстраховался и подтянул снаружи 4,7к. Скорости порядка 500кГц.
_________________ Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ Актуальность репозитория: 1 июля 2025 года Если чего-то не хватает с сайта st.com - пишите, докачаю.
Даже не сомневаюсь, что будут работать примеры - уже проверял чужие реализации, но хочеться вернуться к вопросу,а то уже обсуждение пошло в самостоятельное плавание: есть фрагмент кода, который перебирает адреса, сдвигает их и формирует блок "адрес устройства + сигнал на чтение", все регистры настроены и есть старт + передача блока адреса в шину - но почему при передоре адресов не откликнулся ни один номер ? чьл не так?
/*выдаем на шину пакет SLA-R*/ TWDR = (adress<<1)|1; TWCR = (1<<TWINT)|(1<<TWEN); while(!(TWCR & (1<<TWINT))); uint8_t a=TWSR; while(!(UCSR0A&(1<<UDRE0))); // Ожидание готовности UART к передаче UDR0 = a; }
Добавлено after 44 minutes 34 seconds: ВСЁ!!! нашёл ошибку - и исправил - код подтверждения получен - сейчас программу поправлю, чтоб при успешном отклике адрес устройства выводила
слейв один и это обычная флешка всё работает стабильно. Но я всё равно подстраховался и подтянул снаружи 4,7к. Скорости порядка 500кГц.
У меня на 40 кГцах работало нестабильно с резисторами по 10к. Но там питание было грязное, а 3-вольтовый слейв понимал логическую единицу примерно от 2.7В и выше. Пришлось поставить 4.7к, причём линии клока оказалось достаточно. Осциллографом я видел сильно заваленные (дальше середины тактового импульса) фронты клока, которые стали заметно круче с резистором на 4к7. На 80 кГцах оно после этого заработало (по паспорту оно 100-килогерцовое), но мне так быстро и не надо было, 40 вполне достаточно. В общем, я бы на резисторах не экономил. На спичках больше сэкономишь!
во-первых, в приведенном тобой коде проверки кода подтверждения не видать. во-вторых, где была ошибка?рассказывай, не интригуй нас.
какая уж тут интрига? сперва я частоту задранную понизил TWBR - было с ошибкой:
Код:
#define TWBR_VALUE (((F_CPU)/(F_I2C)-16)/2)
сделал:
Код:
#define TWBR_VALUE (((F_CPU)/(F_I2C)-16)/8)
далее проверял TWSR не верно - хотя в даташите читал. что нужно без учета младших байтов (т.е. без предделителя) - и я поступил так:
Код:
uint8_t a=TWSR>>3;
позже. когда перевел таблицу из даташита понял. почему код должен быть 0Х08 при отправке адреса. Нужно было исправит :
Код:
uint8_t a=TWSR&0xF8;
а далее выводить адрес и значение TWSR:
этосейчас стало просто , когда получилось - а вначале казалось сложно и непонятно - сейчас присупил к ведомому утсройству DS3231 и пока так же есть трудности.пробую без готовых библиотек по даташиту
хотя в даташите читал. что нужно без учета младших байтов
не байтов, а битов. байт - это все 8 битов регистра.
p7070 писал(а):
код должен быть 0Х08 при отправке адреса
во-первых, 0х08 - это код старта, а не отправки адреса. когда ты перебираешь адреса, повторный старт дает код 0х10. поэтому нужно проверять оба кода. а при отправке адреса успешный код равен 0х18, а не успешный код адреса равен 0х20. и здесь нужно проверять на успешную отправку адреса и неуспешную. если на отправку адреса получишь 0х18, значит устройство найдено и ответило. а если получишь 0х20, то адрес был неверный.
_________________ Мудрость приходит вместе с импотенцией... Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
[quote="p7070"] если на отправку адреса получишь 0х18, значит устройство найдено и ответило. а если получишь 0х20, то адрес был неверный.
Да - перепроверил, причем выводил и по-парно "адрес устройства - статус" и после по услочию только адрес "откликнувшийся" на запрос, причем адреса уже знал и перебором по порядку еще раз их обнаружил ( ранее тест на ардуино) . Но это не всё - далее решил соединить уже проверенный код запуска дисплея 1602, чтоб не мониторить посылки по терминалу ..но столкнулся с новой проблемой и пришлось вернуться к коду с дисплеем - не могу решить поблему (используя готовую библиотеку) вывод второй строки только при первом запуске и далее только после снятия питания и повторного подключения. Однако при перезапуске процессора кнопкой резет - вторая строка не выводится на дисплей. Порядок - заливка программы - вывод двух строк, далее резет и загружена только одна строка , если выкл и вновь вкл питание - две строки.
Код:
#define F_CPU 8000000UL //#define Line " - %d" //#define BAUD 9600UL // Задание скорости обмена по UART //#define SPEED ((F_CPU+BAUD*8)/(BAUD*16)-1) //#define F_I2C 100000UL //#define TWBR_VALUE (((F_CPU)/(F_I2C)-16)/8)
Сейчас этот форум просматривают: serg_svd и гости: 17
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения