Проблема с 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, связь работает.
Поэтому я попытался исправить эту ситуацию, используя двунаправленный переключатель уровня, и Лолин кажется замороженным.
Любая помощь приветствуется.
Кодекс Лолин (как мастер).
/*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|
@GERMAN, 👍-1
Обсуждение1 ответ
Используйте буфер с тремя состояниями на выводах 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
- Считыватель Rfid и экран SD-карты не работают вместе
- Какие контакты можно использовать для выбора микросхемы (CS, CC) на Arduino Nano Every?
- Более 4 MCP23S17 на 1 шине SPI
- Проблема с NRF24L01
- Аппаратный SPI Arduino NANO не работает
- Nano не может получить ответ от ENC28J60 Ethernet Shield
- Проблемы nRF24l01+. Данные принимаются как 0
- Правильное использование SPI с ISR
как вы подключили контакты 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