Всем привет, пробую делать цифровой датчик температуры для 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: }
вообще-то "Open circuit" означает в общем случае что-то типа "обрыв линии" или "нет связи", а вовсе не какие биты в ответе В коде несколько синтаксических ошибок, он у вас даже компилироваться не должен. Если по сути - вы инициализируете свою программу как слейв, а сами даже не читаете команду мастера. Может он у вас совсем не то спрашивает. что вы ему пихаете в ответ..
Тоже в эту сторону думал, особенно после просмотра примера по ссылке https://forum.arduino.cc/index.php?topic=184527.0 Но в даташите на тот же MAX31855 не нашел ничего на эту тему, только формат ответного сообщения на 10 странице и все. Сейчас скачал либу от adafruit для общения ардуинки с этим контроллером, на первый взгляд там только 4 байта в ответ отправляют.
Перепроверил на всякий случай пины к которым подпаял свою ардуино. Почитал еще про SPI и понял что на шине в моем случае может быть только одно устройство, либо датчик, либо дисплей. По этой причине перекинул дисплей на I2C шину в прошивке принтера. Попробовал отсылать принтеру ответ -1, как в примере выше, что с ним, что без него, так и пишет обрыв линии.
Пробовал выводить значение бита из регистра данных SPDR, в результате понял что обработчик прерывания SPI не вызывается, т.к. изначально инициализированное значение переменной не меняется как задумано в обработчике прерывания. Может кто либо подсказать почему такое может быть? P.S. пробовал впаивать пин ss непосредственно к GND. После чего в одном из примеров увидел что master, по окончании передачи данных отпускает пин ss обратно в высокий лог уровень, сигнализируя что передача окончена. Подумал что к GND припаивать не стоило и припаял все обратно как нужно :/
какой переменной - val ? Не знаю. что у вас было задумано - но так как написано в коде в первом сообщении, оно действительно у вас не меняется. И не должно. судя по коду.
val у меня является указателем на 3 и 4 байты буфера,который нужно передать маскируясь под датчик, т.к. именно там по установленному в MAX31855 формату, хранится значение измеренной температуры. Я работаю с этим указателем, как с переменной, т.к. это удобнее, чем насиловать себе мозг с отдельными байтами. ну сколько ни читал статьи про SPI кругом пишут что если пин SS один, то общаться сможем только с одним устройством, т.к. когда мастер опускает этот пин в низкий лог уровень, он сигнализирует подчиненному устройству что сейчас общается с ним...
это вы к чему написали? Речь-то вроде о другом - что val у вас в коде не меняется, а не о том. куда она указывает... правильно пишут. Но что мешает для каждого устройства завести отдельный Ss пин и общаться со многими устройствами?
вообще то меняется вот здесь Код (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); }