Проблема с SPI-коммуникациями с использованием NodeMCU v 3, Nano и SD

Недавно я купил NodeMCU 8266 v 3 (Lolin), и он отлично работает. Я установил модуль SD-карты Catalex (со встроенным стабилизатором 5-3,3 В), и все было хорошо. Затем я установил Lolin с Arduino Uno и/или Nano, работающими для связи SPI, и все заработало правильно. Поэтому, когда я попытался поставить Lolin в качестве главного устройства и двух подчиненных устройств (Nano и SD-карту), все они работали с SPI, это не сработало.

Если я настрою Vcc SD-карты на 5 вольт, Lolin сможет «увидеть» ее и инициализировать, но связь между Lolin и Nano выйдет из строя (Lolin может отправлять данные, но получает только мусор; Nano может принимать и, соответственно, отвечать). Когда я отключаю кабель SD Vcc, связь работает.

Поэтому я попытался исправить эту ситуацию, используя двунаправленный переключатель уровня, и Лолин кажется замороженным.

Любая помощь приветствуется.

wired

Кодекс Лолин (как мастер).

/*Master — ESP12e создает переменную строку для отправки подчиненному — Nano_ChipSelect
и получить переменный ответ.

Основное использование ESP12e: COM5
* Связь SPI с NANO в качестве ведомого в GPIO 0 = D3
* Wi-Fi связь
* DS3231 для часов реального времени
* SD-память Catex
*/

/*---------------( Import needed libraries )-------------------------------------*/
#include <ESP8266WiFi.h>                            // Wi-Fi
#include <WiFiClientSecure.h>                       // SSL-клиент
#include <SPI.h>                                    // SPI-коммуникации
#include <SD.h>                                     // Карта памяти SD
#include <Wire.h>                                   // Связь RTC
#include "RtcDS3231.h"                              // RTC от maluma

/*---------------( Define Constants )--------------------------------------------*/
#define Nano_ChipSelect             D3              // Сигнал выбора ведомого для NANO
#define SD_ChipSelect               D8              // Сигнал выбора ведомого для SD

/*---------------( Declare objects )---------------------------------------------*/
RtcDS3231<TwoWire>    Rtc(Wire);
File                  myFile;
WiFiClientSecure      client;

/*---------------( Declare Special settings--------------------------------------*/
SPISettings           Set_SPI_NANO( 1000000, MSBFIRST, SPI_MODE0 );

/*---------------( Declare Constants )--------------------*/
String        defaultChatId         = "5"; 
char          ssid[]                = "scouts";     // SSID сети (имя)
char          password[]            = "R";   // сетевой ключ

/*---------------( Declare Variables )-------------------------------------------*/
bool          switch_Red            = false;
bool          switch_Yell           = false;
bool          switch_Green          = false;
unsigned int  temp_ESP12e            = 0;
unsigned int  temp_nano             = 0;
unsigned int  hum_nano              = 0;
char          datestring[20];
char          Nano_S_to_send[]      = "0000000000000000000000000|";
// "RRYYGcGYYYYcMMDDHcHMMSScc|"
// 01234567890123456789012345
// 0 1 2
char          Nano_S_to_receive []  = "0000000000000000000000000|";
// "TTTTTcHHHHcIIIcDDDDDcc|
// 01234567890123456789012345
// 0 1 2
byte          Leds                  = 0;

#define countof( a ) ( sizeof( a ) / sizeof( a[ 0 ] ) )

void _printDateTime( const RtcDateTime& dt ) {  //---------------------------------
    snprintf_P(datestring, 
            countof(datestring),
            PSTR("%04u/%02u/%02u %02u:%02u:%02u"),
            dt.Year(),
            dt.Month(),
            dt.Day(),
            dt.Hour(),
            dt.Minute(),
            dt.Second() );
}

void _create_data_for_nano() {  //---------------------------------------------------------- ------
  RtcDateTime now = Rtc.GetDateTime();
  _printDateTime( now );
  //;
  // RRYYGcGYYYYcMMDDHcHMMSScc|
  // 0000000000000000000000000|
  Nano_S_to_send[ 0 ] = _getbit( Leds, 0 );  // красный статус
  Nano_S_to_send[ 1 ] = _getbit( Leds, 1 );  // красный статус
  Nano_S_to_send[ 2 ] = _getbit( Leds, 2 );  // желтый статус
  Nano_S_to_send[ 3 ] = _getbit( Leds, 3 );  // желтый статус
  Nano_S_to_send[ 4 ] = _getbit( Leds, 4 );  // зеленый статус
  Nano_S_to_send[ 5 ] = _Nano_CRC( 0, 5 );
  Nano_S_to_send[ 6 ] = _getbit( Leds, 5 );  //зеленый статус
  Nano_S_to_send[ 7 ] = datestring[ 0 ];  //г
  Nano_S_to_send[ 8 ] = datestring[ 1 ];  //г
  Nano_S_to_send[ 9 ] = datestring[ 2 ];  //г
  Nano_S_to_send[ 10 ] = datestring[ 3 ];  //г
  Nano_S_to_send[ 11 ] = _Nano_CRC( 6, 5 );
  Nano_S_to_send[ 12 ] = datestring[ 5 ];  //м
  Nano_S_to_send[ 13 ] = datestring[ 6 ];  //м
  Nano_S_to_send[ 14 ] = datestring[ 8 ];  //д
  Nano_S_to_send[ 15 ] = datestring[ 9 ];  //д
  Nano_S_to_send[ 16 ] = datestring[ 11 ];  //час
  Nano_S_to_send[ 17 ] = _Nano_CRC( 12, 5 );
  Nano_S_to_send[ 18 ] = datestring[ 12 ];  //час
  Nano_S_to_send[ 19 ] = datestring[ 14 ];  //м
  Nano_S_to_send[ 20 ] = datestring[ 15 ];  //м
  Nano_S_to_send[ 21 ] = datestring[ 17 ];  //с
  Nano_S_to_send[ 22 ] = datestring[ 18 ];  //с
  Nano_S_to_send[ 23 ] = _Nano_CRC( 18, 5 );
  Nano_S_to_send[ 24 ] = _Nano_CRC( 0, 24 );
}

char _getbit( byte data, byte pos ){
  byte b = data >> pos;
  b = b & 1;
  char b1[] = { '0' };
  if( b ) b1[ 0 ] = '1';
  return b1[ 0 ];
}

char _Nano_CRC( byte pos, byte lon ) {  //----------------------------------------------------- -------
  int  suma = 0;
  bool par  = false;
  for( int i = 0 ; i < lon ; i++ ) {
    suma += char( Nano_S_to_send[ i + pos ] );
    if( par )  {
      suma += 2 * char( Nano_S_to_send[ i + pos ] );
    }
    par = !par;
  }
  int  b = suma/10;
  if( suma != b*10 )  b++; 
  b *= 10;
  char resultado[ 2 ]; 
  itoa( b - suma, resultado, 10 );
  return resultado[ 0 ];
}

void _transfer_data_to_NANO_by_spi() {  //-------------------------------------------------------
  char c[2];
  digitalWrite( SD_ChipSelect, HIGH );
  cli();
  byte index2 = 0;
  SPI.beginTransaction( Set_SPI_NANO );
  digitalWrite( Nano_ChipSelect, LOW );
  byte num_char_to_transfer = sizeof( Nano_S_to_send ) ;
  for( byte index = 0 ; index <= num_char_to_transfer ; index++ ) {
    c[ 1 ] = ( Nano_S_to_send[ index ] );
    c[ 0 ] = SPI.transfer( c[ 1 ] );
    if( index != num_char_to_transfer ) Nano_S_to_receive [ index2 ] = 'E';
    if( c[ 0 ] != '\0' ) {
      Nano_S_to_receive [ index2 ] = c[ 0 ];
    }
    if( index != 0 ) index2++;
    delayMicroseconds( 2 );
  }
  digitalWrite(Nano_ChipSelect, HIGH);
  //Serial.print("-->");Serial.print(Nano_S_to_receive);Serial.println("<--");
  sei();  
  SPI.endTransaction ();
}


String _txt2str( int valor ){  //-------------------------------------------------------- --------
  char v_txt[]= "000";
  itoa( valor, v_txt, 10 );
  String v_text = "";
  for( int i = 0 ; i < 4 ; i++ ){
    if( v_txt[ 3-i ] != '\0' ) {
      v_text = v_txt[ 3-i ]+ v_text;
    }
  }  
  return v_text;
}

int _convierte( byte pos ){  //-------------------------------------------------------- ----------
    char temporal [] = "     ";
    for( int i = 0 ; i < 4 ; i++ )  {
      temporal [ i ] = Nano_S_to_receive [ i + 1 + pos ];
    }    
    int temp = atoi( temporal);
    return temp;
}

void setup() {   /*-----------( SETUP: RUNS ONCE )------------------------------*/
  pinMode( SD_ChipSelect,   OUTPUT );          // настроить строку как вывод
  pinMode( Nano_ChipSelect, OUTPUT );          // настроить строку как вывод

  Serial.begin( 115200 );              // запускаем последовательный монитор
  digitalWrite( SD_ChipSelect,   HIGH );       // переключить на ВЫСОКИЙ, чтобы отключить
  digitalWrite( Nano_ChipSelect, HIGH );       // переключить на HIGH, чтобы отключить ведомое устройство

  Serial.println();
  Serial.print( "compiled: " );Serial.print( __DATE__ );
  Serial.print( " at " );Serial.println( __TIME__ );
  Serial.print( "Connecting Wifi: " );
  Serial.println( ssid );

  Rtc.Begin();

  RtcDateTime compiled = RtcDateTime( __DATE__, __TIME__ );
  RtcDateTime now = Rtc.GetDateTime();
  _printDateTime( now );
  Serial.print(" --- Initialized WiFi at "); 
  Serial.println( datestring );

  if ( !Rtc.IsDateTimeValid() )   {
        Serial.println( "RTC lost confidence in the DateTime!" );
        Rtc.SetDateTime( compiled );
        RtcDateTime now = Rtc.GetDateTime();
        _printDateTime( now );
  }

  if( !Rtc.GetIsRunning() )  {
    Serial.println( "RTC was not actively running, starting now" );
    Rtc.SetIsRunning( true );
  }

   if ( now < compiled )     {
    Serial.println( "RTC is older than compile time!  (Updating DateTime)");
    Rtc.SetDateTime( compiled );
  } else if( now > compiled )    {
      Serial.println( "RTC is newer than compile time. (this is expected)" );
    } else if ( now == compiled )     {
        Serial.println( "RTC is the same as compile time!");
      }
  Rtc.Enable32kHzPin( false );
  Rtc.SetSquareWavePin( DS3231SquareWavePin_ModeNone ); 

  Serial.print( "Initializing SD card..." );

  SPI.begin();             
  /* begin SPI at 1 Mbit rate most significat bit first & mode 0 */
  SPI.beginTransaction( SPISettings( 1000000, MSBFIRST, SPI_MODE0 ) );
  digitalWrite( SD_ChipSelect, LOW );   

  if ( !SD.begin( SD_ChipSelect ) ) {
    Serial.println( "initialization failed!" );
    return;
  }
  myFile = SD.open( "Log_1.txt", FILE_WRITE );
  if (myFile) {                           // если файл открылся нормально, пишем в него:
    myFile.println( "YYYY:MM:DD:HH:MM:SS:TNANO:HNANO:TESP12e" );
    // закрываем файл:
    myFile.close();
  } else {                             // если файл не открылся, вывести ошибку:
    Serial.println( "error opening file Log_1.txt" );
  }

  digitalWrite( SD_ChipSelect, HIGH );
  SPI.endTransaction();

  Serial.println( "*****  initialization done. ******" );
}

void loop() {  //---------------------------------------------------------- ----------------------

  Serial.println("*********** E S P 1 2 ***********");
  RtcTemperature temp = Rtc.GetTemperature();
  temp_ESP12e = temp.AsFloat() * 100;                         // Температура системы

  _create_data_for_nano();
  _transfer_data_to_NANO_by_spi();       // подпрограмма передачи для отправки и получения данных
  //_check_received_data();

  Serial.print( "->NANO:" );Serial.print(    Nano_S_to_send );Serial.println(":");
  Serial.print( "NANO<-:" );Serial.print( Nano_S_to_receive );Serial.println(":");

  Leds++;
  if( Leds > 64 ) Leds = 0;
  delay(5000);
}

Код nano (как подчиненный)

/* Slave - Nano receive a variable string, byte by byte from 
 *  master - ESP12e and create a variable answer 

      Slave NANO use:    COM3
           * SPI communications 
           * an AM2302 sensor for temperature and humidity
           * timers
*/

/*---------------( Import needed libraries )-------------------------------------*/
#include <SPI.h>
#include <DHT.h>
#include "DHT_U.h"
#include "SimpleTimer.h"
#include "Adafruit_Sensor.h"

/*---------------( Define Constants )--------------------------------------------*/
#define switch_Yell       2
#define switch_Green      4
#define switch_Red        6
#define DHTPIN            9         // Контакт, подключенный к датчику DHT.

#define DHTTYPE           DHT22     // DHT 22 (AM2302)

/*---------------( Declare objects )---------------------------------------------*/
SimpleTimer timer;
DHT_Unified dht(DHTPIN, DHTTYPE);

/*---------------( Declare Special settings--------------------------------------*/

/*---------------( Declare Constants )--------------------*/

/*---------------( Declare Variables )-------------------------------------------*/
uint32_t       waiting_for_AM2302;
char           string_to_receive[] = "0000000000000000000000000|";
// "RRYYGcGYYYYcMMDDHcHMMSScc|"
// 01234567890123456789012345
// 0 1 2
char           string_to_answer[]  = "0000000000000000000000000|";
// "TTTTTcHHHHcIIIcDDDDDcc|
// 01234567890123456789012345
// 0 1 2
volatile byte  index;
volatile bool  receivedone;  /* used as reception complete flag */
byte           Dummy               = 0;

// функция, которая будет многократно вызываться функцией таймера
void Read_AM2302() {  //---------------------------------------------------------- ----------------

  int tempera    = -1;
  int humidit    = -1;
  int illumin    = -1;
  int dummy       = -1;
  sensors_event_t event;  
  // Получить событие температуры и вывести его значение.
  dht.temperature().getEvent(&event);  
  if (isnan(event.temperature)) {
    Serial.println("Error reading temperature!");
  }
  else {
    tempera = event.temperature * 10;
  }
  // Получить событие влажности и вывести его значение.
  dht.humidity().getEvent(&event);
  if (isnan(event.relative_humidity)) {
    Serial.println("Error reading humidity!");
  }
  else {
    humidit = event.relative_humidity * 10;
  }

// темпера = 9;
// влажность = 72;
  illumin = 143;

  _create_answer( tempera,   0 );
  string_to_answer[  5 ] = _CRC(  0,  5 );
  _create_answer( humidit,      6 );
  string_to_answer[ 11 ] = _CRC(  6,  5 );
  _create_answer( illumin, 12 );
  string_to_answer[ 17 ] = _CRC( 12,  5 );
  //_create_answer(Dummy, 18);
  string_to_answer[ 18 ] = _getbit( Dummy, 4 );
  string_to_answer[ 19 ] = _getbit( Dummy, 3 );
  string_to_answer[ 20 ] = _getbit( Dummy, 2 );
  string_to_answer[ 21 ] = _getbit( Dummy, 1 );
  string_to_answer[ 22 ] = _getbit( Dummy, 0 );
  string_to_answer[ 23 ] = _CRC( 18,  5 );
  string_to_answer[ 24 ] = _CRC(  0, 24 );
  /*
  Serial.print(" Temperature =");Serial.println( tempera );
  Serial.print(" Humidity     =");Serial.println( humidit );
  Serial.print(" Illumination =");Serial.println( illumin );
  Serial.print(" Dummy       =");Serial.println( Dummy   );
  Serial.print("Answer-->"); Serial.println( string_to_answer );
  */
}

char _getbit( byte data, byte pos ){
  byte b = data >> pos;
  b = b & 1;
  char b1[] = { '0' };
  if( b ) b1[ 0 ] = '1';
  return b1[ 0 ];
}

char _CRC( byte pos, byte lon ) {  //----------------------------------------------------- --------
  int  suma = 0;
  bool par  = false;
  for( int i = 0 ; i < lon ; i++ ) {
    suma += char( string_to_answer[ i + pos ] );
    if( par )  {
      suma += 2 * char( string_to_answer[ i + pos ] );
    } 
    /*
    Serial.print(" i=");Serial.print(i);
    Serial.print(" d=");Serial.print(string_to_answer[ i + pos ] );
    Serial.print(" s=");Serial.println( suma); 
    */
    par = !par;
  }
  int  b = suma/10;
  if( suma != b*10 ) b++;
  b *= 10;
  char result[ 2 ]; 
  itoa( b - suma, result, 10 );
  /*
  Serial.print( "-S-" );Serial.print( sum );      Serial.println("---");
  Serial.print( "-B-" );Serial.print( b );        Serial.println("---");
  Serial.print( "-R-" );Serial.print( result[ 0 ] );Serial.println("---");
  */
  return result[ 0 ];
}
                   // 9 0
void _create_answer( int data, byte pos) {  //----------------------------------------------------
  char temporal[] = {'\0','\0','\0','\0','\0'};  // маска
  byte longitud = 5;          // позиция desde 0 hasta n
  byte puntero = pos + longitud; //5
  itoa( data, temporal, 10 );//9
  //Serial.print("-t-");Serial.println(temporal);
  //Serial.print("-s-");Serial.println(sizeoftemporal);
  for( int i = longitud ; i >= 0 ; i-- ) {
    //Serial.print("-val-");Serial.println((temporal[i]));
    if( temporal[i] != '\0' ) {
    string_to_answer[ puntero-- ] = temporal [ i ];
    }
  }
}

// Процедура прерывания SPI
ISR (SPI_STC_vect) {  //---------------------------------------------------------- ----------------
  uint8_t oldsrg = SREG;
  cli();
  string_to_receive[ index ] = SPDR;
  SPDR = string_to_answer[ index ];
  if( string_to_receive [index] == '\0' ) receivedone = true;
  if( index < sizeof( string_to_receive ) ) index++;
  sei();
  SREG = oldsrg;
}

void setup (){  //---------------------------------------------------------- ----------------------
  Serial.begin (115200);

  pinMode(MISO, OUTPUT);
  SPCR |= _BV(SPE);    // включаем SPI в ведомом режиме
  SPCR |= _BV(SPIE);   // включаем прерывания

  index = 0;
  receivedone = false;
  SPI.attachInterrupt();    /* Attach SPI interrupt */
  dht.begin();
  sensor_t sensor;
  dht.temperature().getSensor(&sensor);
  dht.humidity().getSensor(&sensor);
  waiting_for_AM2302 = sensor.min_delay / 1000;
  Serial.println("------------------------------------");
  Serial.println("Temperature");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); 
  Serial.println(" *C");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); 
  Serial.println(" *C");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); 
  Serial.println(" *C");  
  Serial.println("------------------------------------");
  Serial.println("Humidity");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); 
  Serial.println("%");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); 
  Serial.println("%");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution); 
  Serial.println("%");  
  Serial.println("------------------------------------");
  timer.setInterval( waiting_for_AM2302, Read_AM2302 );
  pinMode( switch_Red,   OUTPUT );
  pinMode( switch_Yell,  OUTPUT );
  pinMode( switch_Green, OUTPUT );
  digitalWrite( switch_Red,   LOW );
  digitalWrite( switch_Yell,  LOW );
  digitalWrite( switch_Green, LOW );

}

void loop () {  //------------------------------------------------------------------------ ----------------------
    timer.run();
  if (receivedone) {         /* Check and print received buffer if any */
    Serial.println( "************ N A N O ************" );
    Serial.print( "ESP12e<-:" );Serial.print( string_to_receive );Serial.println( ":" );
    Serial.print( "->ESP12e:" );Serial.print( string_to_answer );Serial.println( ":" );
    //_check_received_data();
    digitalWrite( switch_Red,   string_to_receive[ 1 ] - 48 );
    digitalWrite( switch_Yell,  string_to_receive[ 3 ] - 48 );
    digitalWrite( switch_Green, string_to_receive[ 6 ] - 48 );
    string_to_receive[index] = 0;
    index = 0;
    receivedone = false;

    Dummy++;
    if( Dummy > 32 ) Dummy = 0;
  }
}

Вот вид последовательного монитора

Master
    ******* L O L I N *******
    ->NANO:1111191201800204282452676|:
    NANO<-:000EEEEEEEE :                     --- connected at 5V
    ******* L O L I N *******
    ->NANO:0000080201810204282453192|:
    NANO<-:00<:
    ******* L O L I N *******
    ->NANO:0000080201810204282453642|:
    NANO<-:EEEEEEEEEEEEEEEEEEEEEE:          ---- connected at 3.3 V
    ******* L O L I N *******                 
    ->NANO:1000070201810204282454160|:
    NANO<-:0000990007250014320806510|:      ---- disconnected

Slave
    ************ N A N O ************
    LOLIN<-:1111191201800204282452676|
    ->LOLIN:0000990007250014320806510|
    ************ N A N O ************
    LOLIN<-:0000080201810204282453192|
    ->LOLIN:0000990007250014320806510|
    ************ N A N O ************
    LOLIN<-:0000080201810204282453642|
    ->LOLIN:0000990007250014320806510|
    ************ N A N O ************
    LOLIN<-:1000070201810204282454160|
    ->LOLIN:0000990007250014320806510|

, 👍-1

Обсуждение

как вы подключили контакты Slave Select (SS, CS), @Juraj

как ты получаешь 5v на лолин плате? (не по ВИНу)., @dandavis

Привет, я получаю 5 В от контакта + 5 В Nano или VV Lolin, или, как вы можете видеть на картинке, оба MCU вместе для тестирования, но когда эта работа будет работать, я собираюсь подключить источник питания к Vin на обоих MCU и Vcc модуля карты DS3231 и Catalex Sd., @GERMAN

Для Nano я использую D3 от Lolin, а для SD я использую D8 (желтые провода). D1 и D2 предназначены для связи I2C с RTC., @GERMAN

земля лолина связана с землей нано?, @Juraj

Да, на картинке не показан кабель groud между Esp8266 и Nano, но я пробую обе формы, и они подключены к одному и тому же ПК экранированными USB-кабелями., @GERMAN

USB не сделал хорошего заземления в моей настройке SPI Nano с Wemos, @Juraj


1 ответ


0

Используйте буфер с тремя состояниями на выводах MISO устройств SPI, используя выбор ведомого устройства как активный. Это единственный способ заставить его работать.

,

Спасибо, я тоже так думал, это аппаратная проблема; Жду буфер TI SN74LS07 ex со средним распространением время задержки 12 нс согласно паспорту., @GERMAN

Привет, jurag, dandavis и @sundayfantasy, обновляю мою проблему. SD-карта имеет встроенный шлюз TI **sn74lvc125a Quadruple Bus Buffer Gate с выходами с 3 состояниями**, но по неизвестной причине он никогда не останавливает сигнал MISO, поэтому я просто поставил Fairchild **4N35** и верю или нет он работает нормально. Я жду новую SD и дополнительное оборудование, чтобы проверить, что здесь происходит., @GERMAN

Привет @sundaysfantasy, я только что поставил **4N35**, и он работает, @GERMAN

Хорошо, что он работает и с оптопарой., @sundaysfantasy