SD Card and 74HC595


In my previous blog, I explained usage of Shift register using Node MCU and shown how to extend the additional digital input and output pins using 74HC595 and CD4021B shift register. In this blog we will use 74HC595 along with SD card and Node MCU.

74HC595: This is serial to parallel shift out register. You can use 8 digital output.This works in synchronous serial communication.

SD Card: SD Card will be used to store the data.


SD Card and 74HC595 Schematic

PIN Connections:

SD Card Node MCU 74HC595N
MISO D6 (GPIO12)
SCK D5 (GPIO14) SCK/SRCLK/SH_CP (PIN: 11)
CLOCK PIN

D3 (GPIO0) RCK/SH_CP/RCKL (PIN: 12)
LATCH
MOSI D7 (GPIO13) SER/DS (PIN: 14)
DATA
CS/SS D8 (GPIO15)
GND GND G/OE

VCC (3.3V) SCL/MR/SRCLR
VCC VU (5V)




Once connection is made, you can use Arduino IDE to program the device. First thing is to initialise the Output pins as below,

pinMode(LATCHOUT_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);

SD Card Initialisation can be done as below,

pinMode(CHIPSELECT_PIN, OUTPUT);
// see if the card is present and can be initialized:
if (!SD.begin(CHIPSELECT_PIN)) {
// don't do anything more:
Serial.println("Card failed, or not present");
return false;
} else {
if (!isBaseDirAvailable()) {
createDirectory();
}
return true;
}
Serial.println("card initialized.");

Once initialisation is complete, then call the write and read method of the SD card to read or write on SD card device. Also in parallel you can set the digital output pin as per requirement.

Reading the file:

File readFile = SD.open(ROOT_DIRECTORY);
readFile.rewindDirectory();
dataReader(readFile, 0);
readFile.flush();
readFile.close();

Here if you are reading the files in loop then make sure that you rewind directory.

Writing the file:

if (!checkSpace(MINIMUM_SDCARD_SIZE)) {
deleteFile();
}
//SdFile::dateTimeCallback(TimeRecorder::dateTime);
File dataFile = SD.open(filename, FILE_WRITE);
uint32_t fileSize = dataFile.size();
fileSize /= 1024;

// if the file is available, write to it:
if (dataFile) {
dataFile.println(output);
// print to the serial port too:
//Serial.println(output);
} else {
Serial.println("Error in reading/opening file " + filename);
//dataFile.clearWriteError();
//Serial.print("Write Error: ");
}
dataFile.flush();
dataFile.close();

In above code before writting multiple files, we are checking the space. Also, if you are using Real Time Clock then you may want current timestamp while writting the file. This can be acheived as below,

SdFile::dateTimeCallback(TimeRecorder::dateTime); //TimeRecorder is your RTC setup class

dateTime callback method can be as below,

static void dateTime(uint16_t* date, uint16_t* time) {
static RTC_DS1307 RTCCall;
DateTime now = RTCCall.now();
// return date using FAT_DATE macro to format fields
*date = FAT_DATE(now.year(), now.month(), now.day());

// return time using FAT_TIME macro to format fields
*time = FAT_TIME(now.hour(), now.minute(), now.second());
}


Please find complete program as below,
#include "Arduino.h"
#include <SPI.h>
#include <SD.h>
#define CHIPSELECT_PIN 15
#define MINIMUM_SDCARD_SIZE 100
//Pin connected to ST_CP of 74HC595
//D3
#define LATCHOUT_PIN 0
//Pin connected to SH_CP of 74HC595
//D5
#define CLOCK_PIN 14
////Pin connected to DS of 74HC595
//D7
#define DATAOUT_PIN 13
byte dataOut = 0xFF;
int fileCounter = 0;
String ROOT_DIRECTORY = "/gtlog";
boolean baseDir = false;
void setup() {
Serial.begin(115200);
cardInitialization();
initializeDigitalPIN();
}
// The loop function is called in an endless loop
void loop() {
String filename = getNextFileName();
writeFile(filename, "Test String");
delay(2000);
readFileFromRoot();
delay(2000);
setDigitalPINOut(dataOut);
}
String getNextFileName() {
//String filename = String("log") + (fileCounter++) + String(".txt");
String filename = ROOT_DIRECTORY + "/" + (fileCounter++) + String(".txt");
Serial.print("Filename is ");
Serial.println(filename);
return filename;
}
boolean cardInitialization() {
pinMode(CHIPSELECT_PIN, OUTPUT);
// see if the card is present and can be initialized:
if (!SD.begin(CHIPSELECT_PIN)) {
// don't do anything more:
Serial.println("Card failed, or not present");
return false;
} else {
if (!isBaseDirAvailable()) {
createDirectory();
}
return true;
}
Serial.println("card initialized.");
}
void readFileFromRoot() {
File readFile = SD.open(ROOT_DIRECTORY);
readFile.rewindDirectory();
dataReader(readFile, 0);
readFile.flush();
readFile.close();
}
void dataReader(File root, int numTabs) {
Serial.println("*****Reading file*****");
while (true) {
File entry = root.openNextFile();
if (!entry) {
Serial.println("No more files");
// no more files
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
}
Serial.println(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
dataReader(entry, numTabs + 1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
String fileName = entry.name();
Serial.print(fileName);
String line;
while (entry.available()) {
line = entry.readStringUntil('\n');
}
if (SD.exists(fileName)) {
Serial.println("Deleting the file " + fileName);
SD.remove(fileName);
Serial.print("File deleted");
}
//Serial.println(entry.size(), DEC);
//Serial.println(line);
}
entry.close();
}
}
void writeFile(String filename, String output) {
Serial.print("CustomSDCard::writeFile: ");
Serial.println(filename);
if (!checkSpace(MINIMUM_SDCARD_SIZE)) {
deleteFile();
}
//SdFile::dateTimeCallback(TimeRecorder::dateTime);
File dataFile = SD.open(filename, FILE_WRITE);
uint32_t fileSize = dataFile.size();
fileSize /= 1024;
// if the file is available, write to it:
if (dataFile) {
dataFile.println(output);
// print to the serial port too:
//Serial.println(output);
} else {
Serial.println("Error in reading/opening file " + filename);
//dataFile.clearWriteError();
//Serial.print("Write Error: ");
}
dataFile.flush();
dataFile.close();
}
boolean isBaseDirAvailable() {
return baseDir;
}
void deleteFile() {
File deleteFile = SD.open(ROOT_DIRECTORY);
deleteFile.rewindDirectory();
deleteEachFile(deleteFile, 0);
deleteFile.flush();
deleteFile.close();
}
void createDirectory() {
if (!SD.exists(ROOT_DIRECTORY)) {
SD.mkdir(ROOT_DIRECTORY);
}
baseDir = true;
}
void deleteEachFile(File root, int numTabs) {
while (true) {
File entry = root.openNextFile();
if (!entry) {
Serial.println("No more files");
// no more files
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
}
Serial.println(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
dataReader(entry, numTabs + 1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
String fileName = entry.name();
if (SD.exists(fileName)) {
Serial.println("Deleting the file " + fileName);
SD.remove(fileName);
Serial.print("File deleted");
}
//Serial.println(entry.size(), DEC);
//Serial.println(line);
}
entry.close();
}
}
bool checkSpace(uint32_t fileSize) {
Sd2Card card;
SdVolume volume;
if (!card.init(SPI_HALF_SPEED, CHIPSELECT_PIN) && !volume.init(card)) {
Serial.println("initialization failed. Things to check:");
Serial.println("* is a card inserted?");
Serial.println("* is your wiring correct?");
Serial.println(
"* did you change the chipSelect pin to match your shield or module?");
Serial.println(
"Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
return false;
} else {
uint32_t volumesize;
Serial.print("\nVolume type is FAT");
Serial.println(volume.fatType(), DEC);
Serial.println();
volumesize = volume.blocksPerCluster(); // clusters are collections of blocks
volumesize *= volume.clusterCount(); // we'll have a lot of clusters
volumesize *= 512; // SD card blocks are always 512 bytes
Serial.print("Volume size (bytes): ");
Serial.println(volumesize);
Serial.print("Volume size (Kbytes): ");
volumesize /= 1024;
if (volumesize > fileSize) {
return true;
} else {
return false;
}
}
}
void initializeDigitalPIN() {
//set pins to output because they are addressed in the main loop
pinMode(LATCHOUT_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
}
void setDigitalPINOut(byte variableData) {
digitalWrite(CLOCK_PIN, LOW);
digitalWrite(LATCHOUT_PIN, LOW);
shiftOut(DATAOUT_PIN, CLOCK_PIN, variableData);
digitalWrite(LATCHOUT_PIN, HIGH);
}
/*
* Sample from arduino tutorial website
*/
void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
// This shifts 8 bits out MSB first,
//on the rising edge of the clock,
//clock idles low
/*Serial.print("Data Before: ");
Serial.println(myDataPin);*/
//internal function setup
int i = 0;
int pinState;
pinMode(myClockPin, OUTPUT);
pinMode(myDataPin, OUTPUT);
//clear everything out just in case to
//prepare shift register for bit shifting
digitalWrite(myDataPin, 0);
digitalWrite(myClockPin, 0);
//for each bit in the byte myDataOut�
//NOTICE THAT WE ARE COUNTING DOWN in our for loop
//This means that %00000001 or "1" will go through such
//that it will be pin Q0 that lights.
for (i = 7; i >= 0; i--) {
digitalWrite(myClockPin, 0);
//if the value passed to myDataOut and a bitmask result
// true then... so if we are at i=6 and our value is
// %11010100 it would the code compares it to %01000000
// and proceeds to set pinState to 1.
if (myDataOut & (1 << i)) {
pinState = 1;
} else {
pinState = 0;
}
//Sets the pin to HIGH or LOW depending on pinState
digitalWrite(myDataPin, pinState);
//register shifts bits on upstroke of clock pin
digitalWrite(myClockPin, 1);
//zero the data pin after shift to prevent bleed through
digitalWrite(myDataPin, 0);
}
//stop shifting
digitalWrite(myClockPin, 0);
}
view raw SDCard hosted with ❤ by GitHub


Shift Registers (CD4021/74HC595) for increasing digital input and output pins

Arduino or Node MCU has limited digital pins and if you are using multiple sensors then there is chance that you may exaughst out of the digital input/output pins. In order to solve this issue, thank god we have Shift Registers. These shift registers can be used to increase the number of digital input and output pins. In this blog I will show you two shift registers which are used to increase digital input and output pins.

CD4021: This is parallel to serial shift in register. Using this shift register you can use upto 8 digital input. Also, this collects the input information asynchronously and all at once. You can call it Input Shift Register. Basically you can connect different digital inputs and collect the information.

74HC595: This is serial to parallel shift out register. You can use 8 digital output.This works in synchronous serial communication.


Schematic for 74HC595, CD4021BE and Node MCU


PIN Description is as below,


CD4021Node MCU74HC595N
Parallel Serial Controller (P/SC) (PIN: 9)D1 (GPIO5)
CLOCK (PIN: 10)
Clock PIN
D5 (GPIO14)SCK/SRCLK/SH_CP (PIN: 11)
CLOCK PIN
Q8 (PIN: 2)D2 (GPIO4)

D3 (GPIO0)RCK/SH_CP/RCKL (PIN: 12)
LATCH

D7 (GPIO13)SER/DS (PIN: 14)
DATA
GNDGNDG/OE
VCCVCCSCL/MR/SRCLR

Once connection is made, you can use Arduino IDE to program the device. First thing is to initialise the Input/Output pins as below,

pinMode(LATCHOUT_PIN, OUTPUT);
pinMode(LATCHIN_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
dataIn = 0;

dataIn = This is variable which stores the out values. For exampple, out of 8 output pin, you can set any bit and send signal to output shift registers.

Once Initialization is complete, then next step is to record Input/output values.
Set the output to 74HC595 output pins as below,

digitalWrite(CLOCK_PIN, LOW);
digitalWrite(LATCHOUT_PIN, LOW);
shiftOut(DATAOUT_PIN, CLOCK_PIN, variableData);
digitalWrite(LATCHOUT_PIN, HIGH);

Intial data out value is set as below,
byte dataOut = 0xFF;

Change the bit as per requirement and set theDigital pin out value.
Below code value is used to read the value from Input Shift Register.

digitalWrite(CLOCK_PIN, HIGH);
digitalWrite(LATCHIN_PIN, HIGH);
delayMicroseconds(5);
digitalWrite(LATCHIN_PIN, LOW);
dataIn = shiftIn(DATAIN_PIN, CLOCK_PIN);

Both Shift IN and Shift out functions are standard provided at link,
https://www.arduino.cc/en/Tutorial/ShiftOut
https://www.arduino.cc/en/Tutorial/ShiftIn

Please find complete program as below,
#include "Arduino.h"
//Pin connected to ST_CP of 74HC595
//D3
#define LATCHOUT_PIN 0
//Pin connected to SH_CP of 74HC595
//D5
#define CLOCK_PIN 14
////Pin connected to DS of 74HC595
//D7
#define DATAOUT_PIN 13
//D2
#define DATAIN_PIN 4
//LATCH IN PIN to P/S C of CD4021BE
//D1
#define LATCHIN_PIN 5
byte dataOut = 0xFF;
byte dataIn = 0;
void setup()
{
Serial.begin(115200);
initializeDigitalPIN();
}
// The loop function is called in an endless loop
void loop()
{
setDigitalPININ();
delay(1000);
setDigitalPINOut(dataOut);
}
void initializeDigitalPIN() {
//set pins to output because they are addressed in the main loop
pinMode(LATCHOUT_PIN, OUTPUT);
pinMode(LATCHIN_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
dataIn = 0;
}
void setDigitalPINOut(byte variableData) {
digitalWrite(CLOCK_PIN, LOW);
digitalWrite(LATCHOUT_PIN, LOW);
shiftOut(DATAOUT_PIN, CLOCK_PIN, variableData);
digitalWrite(LATCHOUT_PIN, HIGH);
}
void setDigitalPININ() {
digitalWrite(CLOCK_PIN, HIGH);
digitalWrite(LATCHIN_PIN, HIGH);
delayMicroseconds(5);
digitalWrite(LATCHIN_PIN, LOW);
dataIn = shiftIn(DATAIN_PIN, CLOCK_PIN);
}
/*
* Sample from arduino tutorial website
*/
byte shiftIn(int myDataPin, int myClockPin) {
int i;
int temp = 0;
int pinState;
byte myDataIn = 0;
pinMode(myClockPin, OUTPUT);
pinMode(myDataPin, INPUT);
//we will be holding the clock pin high 8 times (0,..,7) at the
//end of each time through the for loop
//at the begining of each loop when we set the clock low, it will
//be doing the necessary low to high drop to cause the shift
//register's DataPin to change state based on the value
//of the next bit in its serial information flow.
//The register transmits the information about the pins from pin 7 to pin 0
//so that is why our function counts down
for (i = 7; i >= 0; i--) {
digitalWrite(myClockPin, 0);
delayMicroseconds(0.2);
temp = digitalRead(myDataPin);
Serial.print(temp);
Serial.print(" = ");
if (temp) {
pinState = 1;
//set the bit to 0 no matter what
myDataIn = myDataIn | (1 << i);
} else {
//turn it off -- only necessary for debuging
//print statement since myDataIn starts as 0
pinState = 0;
}
//Debuging print statements
//Serial.print(pinState);
//Serial.print(" ");
//Serial.println (dataIn, BIN);
digitalWrite(myClockPin, 1);
}
//debuging print statements whitespace
/*Serial.println();
Serial.println(myDataIn);*/
//Serial.println(" ");
return myDataIn;
}
/*
* Sample from arduino tutorial website
*/
void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
// This shifts 8 bits out MSB first,
//on the rising edge of the clock,
//clock idles low
/*Serial.print("Data Before: ");
Serial.println(myDataPin);*/
//internal function setup
int i = 0;
int pinState;
pinMode(myClockPin, OUTPUT);
pinMode(myDataPin, OUTPUT);
//clear everything out just in case to
//prepare shift register for bit shifting
digitalWrite(myDataPin, 0);
digitalWrite(myClockPin, 0);
//for each bit in the byte myDataOut�
//NOTICE THAT WE ARE COUNTING DOWN in our for loop
//This means that %00000001 or "1" will go through such
//that it will be pin Q0 that lights.
for (i = 7; i >= 0; i--) {
digitalWrite(myClockPin, 0);
//if the value passed to myDataOut and a bitmask result
// true then... so if we are at i=6 and our value is
// %11010100 it would the code compares it to %01000000
// and proceeds to set pinState to 1.
if (myDataOut & (1 << i)) {
pinState = 1;
} else {
pinState = 0;
}
//Sets the pin to HIGH or LOW depending on pinState
digitalWrite(myDataPin, pinState);
//register shifts bits on upstroke of clock pin
digitalWrite(myClockPin, 1);
//zero the data pin after shift to prevent bleed through
digitalWrite(myDataPin, 0);
/* Serial.print("myDataPin: ");
Serial.print(myDataPin);
Serial.print(" myClockPin: ");
Serial.print(myClockPin);
Serial.print(" myDataPin: ");
Serial.println(myDataPin);*/
}
//stop shifting
digitalWrite(myClockPin, 0);
//Serial.print("74HC595 Data: ");
//Serial.println(myDataPin);
}



Eclipse for Arduino and Node MCU project



Arduino IDE is open source tool to develop embedded system or IoT (Internet Of Things) based project. It is very easy to learn and develop. Any newbie having background of C/C++ language can start development using Arduino IDE. More ever installation and setup is quite simple as well. But when you are working on medium or large project with complex functionality having multiple classes, then you will need more sophisticated IDE like Eclipse or Intellij. In this blog, I am going to explain you setup of Eclipse IDE with Arduino for NodeMCU based project. NodeMCU is Open Source IoT platform and now days used in many IoT projects. It runs on ESP8266 WIFI SOC(System On Chip).

Eclipse Arduino IDE NodeMCU IoT


  • Download and Install Eclipse: Download the Eclipse Photon C++ IDE. Extract the zip file on your computer hard drive. Go to extracted folder and open the eclipse.exe file.
  • Install Sloeber: Eclipse photon has Eclipse C++ IDE for Arduino 3.0 pre-installed. We will be using the Sloeber plugin in our example. So, Go to Help->Eclipse Marketplace and search for the Sloeber plugin and select the plugin and click Install. If you receive security warning, click on "Install Anyway". After installation, Eclipse will show message to restart. Make sure you accept pop up message and restart the Eclipse.


  • Configure the ESP8266 hardware: In order to add ESP8266 hardware, go to Windows->Preferences->Arduino. Select the select New button from Private hardware path section at right hand side pane and select ESP8266 hardware folder in your system. 
    • NOTE:ESP8266 hardware path can be as below C:\Users<<Username>>\AppData\Local\Arduino15\packages\esp8266\hardware
  • Platform and Board Selection: Go to Windows->Preferences->Arduino->Platform and Board. Select esp8266 from the list and apply and close the window.

  • Create the project: Go to File->New->Other->Arduino(Create Arduino Sketch)

  •  While creating project select values as below,
    • Platform folder: ESP8266 hardware folder from drop down list
    • Board: NodeMCU 1.0 (ESP-12E Module)
    • Upload Protocol: Default
    • Port: COM port values.  
    • CPU Frequency: 80 Hhz
    • Debug Port: Serial
    • Debug Level: Select value from drop down list 
    • Flash Size: 4M (3M SPIFFS) 
    • IwIP variant: v2 Lower Memory
    • Upload Speed: 115200
NOTE: Port will only appear in drop down when you have connected the NodeMCU to your computer through USB cable. Also, Make sure to select 115200 speed. Incorrect speed may gives error during sketch upload.

  • Once project is created, there may be some error. In order to fix the error, Right click on project, go to Properties->C/C++ Go to General ->Preprocessor Include Paths, Macros etc.
    • Apply the CDT Cross GCC Built-in Compiler Settings and close the window. 
    • Clean and Build the project.
            

    • Testing the Setup: Refer the sample program from Arduino examples. In our example, we have Real Time Clock (RTC) module which will use the RTClib library. You need to download the RTClib library from Arduino manage library. In order to add this external library, Go to Window->Preferences-Arduino and add private library path. Edit the Private Library path and add external library.
    • Build the project. Project->Build Project or you can use navigation mentioned as below.


    • Once you upload the sketch then console will show below output.
    • Serial monitor output can be show as below, Go to Serial Monitor View->Click on + button and add the port. 
      • Select Port from drop down & Baud Rate: 115200


    SD Card and 74HC595

    In my previous blog, I explained usage of Shift register using  Node MCU and  shown how to extend the additional digital input and output...