Nikita kozlovtcev

Вопрос мастерам или ардуино Шредингера.

9 сообщений в этой теме

Есть задача, опрашивать несколько ардуино по I2C с целью вывести полученное на дисплей.
Рабочий код прикладываю, подсоединял по мануалу пробовал подтягивать SCL и SDA резисторами на 1,5кОм.
Вопрос в следующем.
Почему то поле некоторого времени слейв перестает определятся.
Скан видит любую перефирию I2C кроме ардуинки

Код (C++):

Код мастера

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x26,16,2);
#include <Wire.h>
char co = 0 ;

void setup() 
  {
 
  Wire.begin();        // join i2c bus (address optional for master)
  lcd.init();
  lcd.backlight();
  Serial.begin(9600);  
  }
 
void loop() 
  {
     
     Wire.requestFrom(0x10, 4,true);
     lcd.setCursor(0,0);
     while (Wire.available()) 
        { 
          co = Wire.read(); 
          Serial.print(co);         
          lcd.print(co);   
        }
        delay(200);
    
   
     Serial.print(" ");
     
     Wire.requestFrom(0x10, 7,true);    // request 6 bytes from slave device #8
     lcd.setCursor(4,0);
     while (Wire.available()) 
        { 
          co = Wire.read(); 
          Serial.print(co);         
          lcd.print(co);   
        }
   
  Serial.print("\n");
  delay(200);
  lcd.clear();
}



Код (C++):

Код слейва


01 #include <Wire.h>
02
03 byte stat = true;
04
05 char c[4] = {'N','O',' ',' '};
06 float x = 322.345;
07 void setup() {
08  Wire.begin(0x10);
09  pinMode(13, OUTPUT);
10  Serial.begin(9600);
11  Wire.onRequest(requestEvent);
12 }
13
14 void loop() {
15  digitalWrite(13, LOW);
16  delay(100);
17
18 }
19
20 void requestEvent() {
21  if (stat == true)
22  {
23
24  Wire.write(c,sizeof c);
25  stat = false;
26  }else
27  {
28  char outstr[7];
29  dtostrf(x,7, 3, outstr);
30  Wire.write(outstr,sizeof outstr);
31  stat = true;
32  }
33  digitalWrite(13, HIGH);
34
35
36
37
38 }

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Быстрый заказ печатных плат

Полный цикл производства PCB по низким ценам!

  • x
    мм
Заказать Получить купон на $5.00
BARS_    560

Перепиши код в AVR Studio и все будет работать

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
4 минуты назад, BARS_ сказал:

Перепиши код в AVR Studio и все будет работать

Буду пробовать, вы думаете это из за кривого компилятора?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
BARS_    560
Только что, Nikita kozlovtcev сказал:

кривого компилятора

Скорее из-за кривого кода

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
BARS_    560
Только что, Nikita kozlovtcev сказал:

как AVR студия поможет?

Поможет разобраться с работой контроллера, в частности интерфейса TWI (I2C, но назван по другому). Вот как его запустишь, так и виснуть перестанет.

С какой целью выбран I2C?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
2 минуты назад, BARS_ сказал:

Поможет разобраться с работой контроллера, в частности интерфейса TWI (I2C, но назван по другому). Вот как его запустишь, так и виснуть перестанет.

Так то на асемблере запускал.

А на си не писал раньше, из за этого и проблемы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
BARS_    560
Только что, Nikita kozlovtcev сказал:

Так то на асемблере запускал

Так и напиши на асме, там же код короткий совсем. Почему именно I2C?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Первое что бросилось в слейве, зачем ты в скорости обмена данных прописал адрес слейва? Wire.begin(0x10); Адресс слейва можно считать кодом сканера, и его можно менять перемычкамит на плате слейва(если есть, смотря что за устройство). Данные в ардуинно иде через библиотеку Wire, отправлял через другие три функции, и к тому же ты насадил на I2C и дисплей и передаешь данные куда-то, возможно в этом конфликт, так как нужно смотреть что в библиотеке на 1602 прописано, там ведь тоже все время идет обмен данными, в таком случае дисплей на I2Cоставляй, а прием передачу данных делай по ЮАРту.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ваша публикация должна быть проверена модератором

Гость
Вы не авторизованы. Если у вас есть аккаунт, пожалуйста, войдите.
Ответить в тему...

×   Вставлено в виде отформатированного текста.   Восстановить форматирование

  Разрешено не более 75 смайлов.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.

Загрузка...

  • Похожие публикации

    • Автор: Дмитрий Мартынов
      Здравствуйте!
      Пишу программу на C++ для управления LCD (HD44780) по I2C через модуль расширения портов ввода/вывода PCF8574AT.
      void LCD_I2C::readBF() { transmitByte(0b00001110); //transmits E, RW set to HIGH and RS, set to LOW _delay_ms(5); transmitByte(0b00001010); //transmits E, RS set to LOW and RW set to HIGH _delay_ms(5); initRestart(); transmitAddrRW(0b01111111); //sends PCF8574AT address + SLA+R do { receiveDataAck(); PORTA = storage; } while((storage & (1 << BF)) != 0); //wait until BF is 0 initRestart(); transmitAddrRW(0b01111110); } Метод void transmitByte(uint8_t data) после инициализации состояния "Старт" и отправки адреса устройства + SLA+W отправляет байт данных по TWI с ожиданием бита подтверждения (команды работают верно, проверял по регистру статуса TWI - 0x08, 0x10 и 0x24).
      Метод void transmitAddrRW(uint8_t address) отправляет соответственно SLA+W/R + адрес устройства (команда работает также верно). Нареканий к работе TWI у меня нет, т.к. недавно с его помощью успешно запустил часы DS1307 с интеграцией LCD.
      После передачи запроса на чтение флага занятости инициализируется состояние "ПОВСТАРТ", отправляется адрес устройства + SLA+R, далее идет цикл - запрос байта данных (состояние выводов PCF8574AT) с отправкой бита подтверждения uint8_t receiveDataAck() (команды работают также верно, возвращает storage = TWDR) и вывод storage на порт А микроконтроллера (там установлены светодиоды).
      Чтение регистра данных TWDR после принятия байта данных (receiveDataAck()) дает следующий результат - 0b00000010 - установлен только бит RW микросхемы. Таким образом, флаг занятости BF = DB7 = 7й бит оказывается сразу же сброшенным, происходит мгновенный выход из цикла - контроллер дисплея не успевает скушать информацию, и инициализация не выполняется (неудачную инициализацию определяю по отсутствию курсора). Ожидалось, что флаг занятости будет установлен в единицу и произойдет несколько итераций перед выходом из цикла.
      При замене метода ожидания сброса флага занятости BF на программную задержку в 250 мс везде, где это требует datasheet - инициализация происходит успешно (появляется курсор, как и должно быть).

      Вопрос: что можно сделать, чтобы вместо _delay_ms(250) использовать readBF(), т.к. этот путь мне кажется более верным (уж очень не хочется использовать задержку .__.)? Возможно, проблема в микросхеме, которая неверно выдает информацию при чтении? (Имеется вторая микросхема, она вообще не работает:D)

      З.Ы. На фото виден результат чтения флага BF и Adress Counter - установлен только бит RW.  



      З.Ы.Ы Кому интересно - вот функция main(). Повторюсь - проблема только в методе readBF():
      void LCD_I2C::init() { setBitRate(20000); initStart(); transmitAddrRW(0b01111110); //send PCF8574AT address + SLA+W _delay_ms(60); sendInstruction(0b00110000); //function set 8-bit operation _delay_ms(20); sendInstruction(0b00110000); //function set 8-bit operation _delay_ms(5); sendInstruction(0b00110000); //function set 8-bit operation _delay_ms(5); sendInstruction(0b00100000); //function set 4-bit operation readBF(); //_delay_ms(250); //debug!! sendInstruction(0b00100000); //function set 4-bit operation, 2 lines, 5x8 dots sendInstruction(0b10000000); readBF(); //_delay_ms(250); //debug!! sendInstruction(0b00000000); //display off, cursor off, blinking off sendInstruction(0b10000000); readBF(); //_delay_ms(250); //debug!! sendInstruction(0b00000000); //display clear sendInstruction(0b00010000); readBF(); //_delay_ms(250); //debug!! sendInstruction(0b00000000); //entry mode set increment, display shift off sendInstruction(0b01100000); readBF(); //_delay_ms(250); //debug!! sendInstruction(0b00000000); //display on, cursor off, blinking off sendInstruction(0b11100000); readBF();/ }  
    • Автор: ximik_se
      Всем привет.

      Решил сделать небольшую домашнюю метеостанцию.

      Есть приемник с экраном, куда выводится инфа (построено на ATMEGA 328P) и есть передатчик, который посылает инфу по возудху (построено на ATtiny85).

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

      При этом время между измерениями не меньше 20 сек.

      В общем заказал я себе с Китаюшки более точные датчики - 

      CJMCU-1080 HDC1080
      Вещица прекрасная, но общается по I2C.

      А библиотеку рабочую под нее я смог найти только одну "ClosedCube_HDC1080.h" и никаких модификаций под ATtiny я найти не смог.

      Для ее работы соответственно нужен Wire.h

      В общем решил я его поковырять самостоятельно, хоть и не прогер. Забрался во внутренности ClosedCube_HDC1080.cpp и везде заменил Wire на TinyWireM (некий аналог Wire для ATtiny).

      И у меня даже получилось считывать валжность, но вот вместо температуры приходит гадость. Ибо при компиляции Arduino IDE ругалась на строку (я ее ниже в коде закомментировал)
      uint8_t buf[4]; for (int i = 1; i < (seconds*66); i++) { TinyWireM.beginTransmission(_address); TinyWireM.write(0x00); TinyWireM.endTransmission(); delay(20); TinyWireM.requestFrom(_address, (uint8_t)4); // TinyWireM.readBytes(buf, (size_t)4); } Ошибку пишет следующую:

      \ClosedCube_HDC1080.cpp: In member function 'void ClosedCube_HDC1080::heatUp(uint8_t)':

      \ClosedCube_HDC1080.cpp:81:13: error: 'class USI_TWI' has no member named 'readBytes'

      TinyWireM.readBytes(buf, (size_t)4);
      Может есть ребята более понимающие в коде и сумеющие победить эту проблему, чтобы и температуру этот датчик смог передавать через ATtiny85.

      Вот полный текст файла ClosedCube_HDC1080.cpp (уже замененный ну и строчка закоментирована):
      #include <TinyWireM.h> #include "ClosedCube_HDC1080.h" ClosedCube_HDC1080::ClosedCube_HDC1080() { } void ClosedCube_HDC1080::begin(uint8_t address) { _address = address; TinyWireM.begin(); // Heater off, 14 bit Temperature and Humidity Measurement Resolution TinyWireM.beginTransmission(_address); TinyWireM.write(CONFIGURATION); TinyWireM.write(0x0); TinyWireM.write(0x0); TinyWireM.endTransmission(); } HDC1080_Registers ClosedCube_HDC1080::readRegister() { HDC1080_Registers reg; reg.rawData = (readData(CONFIGURATION) >> 8); return reg; } void ClosedCube_HDC1080::writeRegister(HDC1080_Registers reg) { TinyWireM.beginTransmission(_address); TinyWireM.write(CONFIGURATION); TinyWireM.write(reg.rawData); TinyWireM.write(0x00); TinyWireM.endTransmission(); delay(10); } void ClosedCube_HDC1080::heatUp(uint8_t seconds) { HDC1080_Registers reg = readRegister(); reg.Heater = 1; reg.ModeOfAcquisition = 1; writeRegister(reg); uint8_t buf[4]; for (int i = 1; i < (seconds*66); i++) { TinyWireM.beginTransmission(_address); TinyWireM.write(0x00); TinyWireM.endTransmission(); delay(20); TinyWireM.requestFrom(_address, (uint8_t)4); // TinyWireM.readBytes(buf, (size_t)4); } reg.Heater = 0; reg.ModeOfAcquisition = 0; writeRegister(reg); } float ClosedCube_HDC1080::readT() { return readTemperature(); } float ClosedCube_HDC1080::readTemperature() { uint16_t rawT = readData(TEMPERATURE); return (rawT / pow(2, 16)) * 165 - 40; } float ClosedCube_HDC1080::readH() { return readHumidity(); } float ClosedCube_HDC1080::readHumidity() { uint16_t rawH = readData(HUMIDITY); return (rawH / pow(2, 16)) * 100; } uint16_t ClosedCube_HDC1080::readManufacturerId() { return readData(MANUFACTURER_ID); } uint16_t ClosedCube_HDC1080::readDeviceId() { return readData(DEVICE_ID); } uint16_t ClosedCube_HDC1080::readData(uint8_t pointer) { TinyWireM.beginTransmission(_address); TinyWireM.write(pointer); TinyWireM.endTransmission(); delay(9); TinyWireM.requestFrom(_address, (uint8_t)2); byte msb = TinyWireM.read(); byte lsb = TinyWireM.read(); return msb << 8 | lsb; }  
    • Автор: Wyfinger
      Всем привет.
      Существуют ли готовые модули для измерения мгновенных значений тока и напряжения (ток до 100 А, напряжение до 250 вольт)?
      Т.е. измерять нужно с частотой 1000-5000 герц, точность 14-16 бит, связь по SPI лучше всего.
      Вообще нужно хотя-бы 4 канала по току и 4 по напряжению. Но лучше, чтобы можно было на одну шину ставить несколько модулей, расширяя количество каналов.
      Обрабатывать данные собираюсь на STM32F104 (хотя с ним никогда не работал) или Arduino Due, но это не важно.
      Понятно что можно взять АЦП и шунт или делитель напряжения, но хотелось бы готовый модуль и уже с оптической развязкой.
      Подскажите если кто сталкивался.
       
    • Автор: StasRadeon
      Люди добрые, помогите кто может!
      потому что имею HD44780 + PCF8547, хотел сделать i2c library.
      скажите пожалуйста где делаю неправильно.
      прикрепляю PrintScreen от Proteus ISIS

      #include <htc.h> #define _XTAL_FREQ 4000000 //******************************************************** #pragma config FOSC = INTRC_CLKOUT// Oscillator Selection bits (INTOSC oscillator: CLKOUT function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config MCLRE = OFF // RE3/MCLR pin function select bit (RE3/MCLR pin function is digital input, MCLR internally tied to VDD) #pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled) #pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled) #pragma config BOREN = ON // Brown Out Reset Selection bits (BOR enabled) #pragma config IESO = OFF // Internal External Switchover bit (Internal/External Switchover mode is disabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled) #pragma config LVP = ON // Low Voltage Programming Enable bit (RB3/PGM pin has PGM function, low voltage programming enabled) // CONFIG2 #pragma config BOR4V = BOR40V // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V) #pragma config WRT = OFF // Flash Program Memory Self Write Enable bits (Write protection off) //******************************************************** #define LCD_DISPLAYMODE 0x08 #define pic_frq 16000 // controller frequenc #define i2c_frq 400 // #define gen_frq (((pic_frq / i2c_frq) / 4) - 1) void i2cByteWrite(char, char, char); void i2cTxData(char); void LCD_dat(char); void LCD_cmd(char); void LCD_clr(void); void LCD_int(void); void LCD_str(char *); void LCD_ROMstr(const char *); void LCD_posyx(char,char); void LCD_hex(char); void i2c_init(); //////////// Main ////////////////////////////////// void main(void){ char msgStart[] ="LCD Work"; unsigned char num = 0; OSCCON = 0b00110000; //4Mhz TRISC = 0b11111111; PORTC = 0x00; i2c_init(); LCD_int(); // ------------------------------------------------------ LCD_str(msgStart); // LCD_dat(' '); LCD_dat('!'); // ------------------------------------------------------ LCD_posyx(1,0); // LCD_ROMstr("12345"); while(1){ LCD_posyx(0,14); // LCD_hex(num++); // __delay_ms(1000); // 1000msec } } void i2c_init() { TRISC3 = 1; TRISC4 = 1; SSPSTAT = 0b10000000; // Slew rate disabled SSPCON = 0b00101000; //(0x28) SSPEN = 1, I2C Master mode, clock = FOSC/(4*(SSPADD+1)) SSPCON2 = 0b00000000; // SSPADD = gen_frq; } // ----------------------------------------------------------- void i2cByteWrite(char addr, char cont, char data){ SEN = 1; // Start condition while(SEN); // if (Start condition) i2cTxData(addr); // i2cTxData(cont); // i2cTxData(data); // SSPIF = 0; // PEN = 1; // Stop condition while(PEN); // Stop condition } void i2cTxData(char data){ SSPIF = 0; // SSPBUF = data; // while(!SSPIF); // } // ----------------------------------------------------------- void LCD_dat(char chr){ i2cByteWrite(0xA0, 0x80, chr); __delay_us(60); // 60 usec } // ----------------------------------------------------------- void LCD_cmd(char cmd){ i2cByteWrite(0xA0, 0x00, cmd); if(cmd & 0xFC) // __delay_us(60); // 60usec else __delay_ms(3); // 3msec } // ----------------------------------------------------------- void LCD_clr(void){ LCD_cmd(0x01); //Clear Lcd } void LCD_posyx(char ypos, char xpos){ unsigned char pcode; switch(ypos & 0x03){ // case 0: pcode=0x80;break; // 1line case 1: pcode=0xC0;break; // 2line case 2: pcode=0x94;break; // 3line case 3: pcode=0xD4;break; // 4line } LCD_cmd(pcode += xpos); // } // ----------------------------------------------------------- void LCD_str(char *str){ while(*str) // LCD_dat(*str++); // } // ----------------------------------------------------------- void LCD_ROMstr(const char *str){ while(*str) // LCD_dat(*str++); // } // ----------------------------------------------------------- void LCD_hex(char c){ const char hexch[] ="aaaa"; LCD_dat(hexch[c >> 4]); // LCD_dat(hexch[c & 0xF]); // } // ----------------------------------------------------------- void LCD_int(void){ __delay_ms(100); // LCD_cmd(0x28); // 4 bit mode LCD_cmd(LCD_DISPLAYMODE | 0x00); // Display on Cursor=0 Blink=0 LCD_cmd(0x06); // Entry Inc/Dec=1 Shift=0 LCD_cmd(0x01); // Clear Display }

    • Автор: Ittido
      Добрый день. Пытаюсь сделать конвеер для аппаратного TWI модуля ATMega8. Контроллер в режиме мастера периодически работает с 4 разными устройствами на шине. LCD1602 висит также на шине I2C. Инициализация проходит информация на LCD выводится. Далее идёт процесс опроса времени с DS3231. Время передаётся но в конце при передаче СТОП на линию І2С. СТОП не проходит. Логический анализатор показывает на линии SCL - 1, SDA - 0. В регистре статуса F8. Ожидание ни к чему не приводит. Продолжение кода тоже. Как с этим бороться может кто сталкивался.