Arduino как контроллер max31855

Тема в разделе "Arduino & Shields", создана пользователем Nekto_nikto, 27 мар 2022.

  1. Nekto_nikto

    Nekto_nikto Гик

    Всем привет, пробую делать цифровой датчик температуры для 3D принтера на Arduino, которая по замыслу должна маскироваться под контроллер прописанный в прошивке принтера, выше упомянутый MAX31855.
    Связь там идет по SPI, нужные контакты на плате я нашел и подпаялся, возникла проблема со скетчем, т.к. поднимаю SPI на регистрах, видимо принтеру что то не нравится в ответе, раз он раз за разом выплевывает мне ошибку "Open circuit", как если бы первый бит был равен не нулю. Но я то посылаю все нули :/
    Код прилагаю
    Код (C++):
    #include "pins_arduino.h"

    byte buf[4]={0,0,0,0};              // буфер который будем передавать master-у
    int *val=(int*)&buf[2];             // переменная в которой храним значение температуры

    String S;                           // Переменная передаваемая через COM порт
    char c[256];

    void SlaveInit(void)
    {
      // Initialize SPI pins.
      pinMode(MISO, OUTPUT);
      pinMode(SCK, INPUT);
      pinMode(MOSI, INPUT);
      pinMode(SS, INPUT);
       // Включаем SPI
      SPCR |= _BV(SPE);
      // Включаем прерывание SPI
      SPCR |= _BV(SPIE);
      // Включаем режим SPI slave, помещая ноль в бит MSTR регистра SPCR
      SPCR &= ~_BV(MSTR);
    }


    // Передаем по SPI значение температуры
    SPItransfer()
    {
      // Приводим значение передаваемых бит в формат передачи данных контроллером MAX31855
      // Читаем регистр данных SPDR, чтоб master увидел что его команда прочитана
      byte tmp=SPDR;
      delay(10);
      // Пишем старший байт ответа в регистр данных
      SPDR = buf[3];
      // ждем когда будет сброшен бит WCOL, что значит что master прочел байт
      while(SPSR | (1<<WCOL));
      delay(10);
      // пишем следующий байт ответа в регистр данных
      SPDR = buf[2];
      // ждем когда будет сброшен бит WCOL, что значит что master прочел байт
      while(SPSR | (1<<WCOL));
      delay(10);
      // пишем следующий байт ответа в регистр данных
      SPDR = buf[1];
      // ждем когда будет сброшен бит WCOL, что значит что master прочел байт
      while(SPSR | (1<<WCOL));
      delay(10);
      // пишем младший байт ответа в регистр данных
      SPDR = buf[0];
      // ждем когда будет сброшен бит WCOL, что значит что master прочел байт
      while(SPSR | (1<<WCOL));
      delay(10);
    }


    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
      SlaveInit();
      Serial.println("Slave Initialized");

      *val=0;
      ultoa(*val,c,10);
      S=c;
      Serial.println("val=" + S);
      *val=*val<<3;
      /*ultoa(*val,c,10);
      S=c;
      Serial.println("val=" + S);
      ultoa(buf[2],c,10);
      S=c;
      Serial.println("buf[2]=" + S);
      ultoa(buf[3],c,10);
      S=c;
      Serial.println("buf[3]=" + S);*/

    }


    //Вектор прерывания по запросу мастера SPI линии
    ISR(SPI_STC_vect)
    {
        /*
        В регистре состояния SPSR нас интересует бит WCOL, который будет сниматься после того как
        master прочтет первый бит пересылаемый slave-ом
        Т.е. после пересылки первого байта ответа нам нужно будет дождаться автоматического обнуления
        бита WCOL в регистре SPSR, который установится после того как мы запишем первый байт в регистр
        данных SPDR
        */

        //
        SPItransfer();
    }


    void loop() {
      // put your main code here, to run repeatedly:

    }
     
    Последнее редактирование: 27 мар 2022
  2. b707

    b707 Гуру

    вообще-то "Open circuit" означает в общем случае что-то типа "обрыв линии" или "нет связи", а вовсе не какие биты в ответе

    В коде несколько синтаксических ошибок, он у вас даже компилироваться не должен.
    Если по сути - вы инициализируете свою программу как слейв, а сами даже не читаете команду мастера. Может он у вас совсем не то спрашивает. что вы ему пихаете в ответ..
     
    Последнее редактирование: 27 мар 2022
  3. Nekto_nikto

    Nekto_nikto Гик

    Тоже в эту сторону думал, особенно после просмотра примера по ссылке https://forum.arduino.cc/index.php?topic=184527.0
    Но в даташите на тот же MAX31855 не нашел ничего на эту тему, только формат ответного сообщения на 10 странице и все.
    Сейчас скачал либу от adafruit для общения ардуинки с этим контроллером, на первый взгляд там только 4 байта в ответ отправляют.
     
  4. Nekto_nikto

    Nekto_nikto Гик

    Перепроверил на всякий случай пины к которым подпаял свою ардуино.
    Почитал еще про SPI и понял что на шине в моем случае может быть только одно устройство, либо датчик, либо дисплей. По этой причине перекинул дисплей на I2C шину в прошивке принтера.
    Попробовал отсылать принтеру ответ -1, как в примере выше, что с ним, что без него, так и пишет обрыв линии.
     
  5. Nekto_nikto

    Nekto_nikto Гик

    Пробовал выводить значение бита из регистра данных SPDR, в результате понял что обработчик прерывания SPI не вызывается, т.к. изначально инициализированное значение переменной не меняется как задумано в обработчике прерывания.
    Может кто либо подсказать почему такое может быть?
    P.S. пробовал впаивать пин ss непосредственно к GND. После чего в одном из примеров увидел что master, по окончании передачи данных отпускает пин ss обратно в высокий лог уровень, сигнализируя что передача окончена. Подумал что к GND припаивать не стоило и припаял все обратно как нужно :/
     
  6. b707

    b707 Гуру

    какой переменной - val ? Не знаю. что у вас было задумано - но так как написано в коде в первом сообщении, оно действительно у вас не меняется. И не должно. судя по коду.
     
  7. b707

    b707 Гуру

    это почему?
     
  8. Nekto_nikto

    Nekto_nikto Гик

    val у меня является указателем на 3 и 4 байты буфера,который нужно передать маскируясь под датчик, т.к. именно там по установленному в MAX31855 формату, хранится значение измеренной температуры. Я работаю с этим указателем, как с переменной, т.к. это удобнее, чем насиловать себе мозг с отдельными байтами.

    ну сколько ни читал статьи про SPI кругом пишут что если пин SS один, то общаться сможем только с одним устройством, т.к. когда мастер опускает этот пин в низкий лог уровень, он сигнализирует подчиненному устройству что сейчас общается с ним...
     
  9. b707

    b707 Гуру

    это вы к чему написали? Речь-то вроде о другом - что val у вас в коде не меняется, а не о том. куда она указывает...
    правильно пишут. Но что мешает для каждого устройства завести отдельный Ss пин и общаться со многими устройствами?
     
    Последнее редактирование: 29 мар 2022
  10. Nekto_nikto

    Nekto_nikto Гик

    вообще то меняется вот здесь
    Код (C++):
    *val=*val<<3;
    а то что выше оно равно нулю, так это просто пример, если поставить какое либо значение, то val изменится в 8 раз, после сдвига влево на 3 единицы.
    То что оно меняется я проверил еще до того как опубликовал кусок кода. моя проблема именно в том что не получается подружить принтер и контроллер, чтоб они друг друга видели, не получается даже когда в коде использую не регистры, а библиотеку ESP.h результат такой же, не происходит SPI прерывание. Вопрос только в том почему...

    а ниже код на библиотеке, по которому я и понял что прерывание не происходит:

    Код (C++):
    #include "pins_arduino.h"
    #include "SPI.h"


    byte b=0;
    byte buf[4]={0,0,0,0};              // буфер который будем передавать master-у
    int *val=(int*)&buf[2];             // переменная в которой храним значение температуры

    String S;                           // Переменная передаваемая через COM порт
    char c[32];

    void SlaveInit(void)
    {
      // Initialize SPI pins.
      pinMode(MISO, OUTPUT);
      pinMode(SCK, INPUT);
      pinMode(MOSI, INPUT);
      pinMode(SS, INPUT);
      SPI.begin();                // Включаем SPI
      SPI.setBitOrder(MSBFIRST);  // Устанавливаем порядок следования бит при обмене данными
      SPCR |= _BV(SPE);           // Включаем режим slave
      SPI.attachInterrupt();      // Подключаем прерывание SPI

    }


    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
      SlaveInit();
      Serial.println("Slave Initialized");
     
      *val=300;
      ultoa(*val,c,10);
      S=c;
      Serial.println("val=" + S);
      *val=*val<<3;
      buf[1]=25;
      buf[0]=0;
      /*ultoa(*val,c,10);
      S=c;
      Serial.println("val=" + S);
      ultoa(buf[2],c,10);
      S=c;
      Serial.println("buf[2]=" + S);
      ultoa(buf[3],c,10);
      S=c;
      Serial.println("buf[3]=" + S);*/

    }


    //Вектор прерывания по запросу мастера SPI линии
    ISR(SPI_STC_vect)
    {
      b = SPDR;
      SPI.transfer(255);
      // передаем 4 байта значения температуры в заданном формате, от старшего к младшему
      SPI.transfer(buf[3]);
      SPI.transfer(buf[2]);
      SPI.transfer(buf[1]);
      SPI.transfer(buf[0]);
    }


    void loop() {
      // put your main code here, to run repeatedly:
    Serial.println("Coming byte= " + (String)b);
    }
     
    Последнее редактирование: 29 мар 2022