C Example Of SD Card Reading
idbruce
Posts: 6,197
It was my intention of posting this code as an example, which I am, but there is a problem with it, and I would like to know what it is. Besides the main function, there is the SD_PrintValidFileLine(void) function and the void SD_PrintAllCharacters(void) function. Both of these functions work individually, but when run consecutively, one fails. I have tried inserting a pause, thinking that the file was not closed yet, but this did not help.
EDIT: I wish we could get an editor that works with proper tab layout
#include <stdio.h>
#include "simpletools.h"
#define SD_DI 8
#define SD_DO 9
#define SD_CS 12
#define SD_CLK 15
static void SD_PrintValidFileLine(void)
{
FILE * pFile;
char fileline[100];
pFile = fopen("debug.txt","r");
if(pFile == NULL)
{
print("Error opening file");
}
else
{
do
{
if (fgets(fileline, 100, pFile) != NULL )
{
// Exclude lines that begin with certain characters
// E.G. Remove newlines, carriage returns, and lines
// that begin with a semi-colon.
if(fileline[0] != 59 && fileline[0] != 13 && fileline[0] != 10)
{
print(fileline);
}
}
}
while(fileline[0] != EOF);
fclose(pFile);
}
}
static void SD_PrintAllCharacters(void)
{
FILE * pFile;
int c;
pFile = fopen("debug.txt","r");
if(pFile == NULL)
{
print("Error opening file");
}
else
{
do
{
c = getc(pFile);
print("%c", c);
}
while(c != EOF);
fclose (pFile);
}
}
int main(void)
{
#if defined SD_DO && defined SD_CLK && defined SD_DI && defined SD_CS
// Mount SD card
sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS);
print("Print Valid File Lines\n\n");
SD_PrintValidFileLine();
pause(2000);
print("Print All Characters\n\n");
SD_PrintAllCharacters();
#else
print("The proper inputs and outputs must be defined for SD card usage");
#endif
return 0;
}
EDIT: I wish we could get an editor that works with proper tab layout

Comments
Unfortunately, I don't see any issues with the code as you've posted it
With what symptoms?
I tried them both with -1 also and with int instead of char, but still no good, however I did not try NULL fgets. I will try that.
I will redeclare the function to provide a result. That is the most likely answer.
No, I mean one after the other
is almost certainly wrong, there is no EOF stored in the data read from a file (or sd card or anything). EOF is only a special return value from certain LibC functions, like fgetc() (but not fgets()), but that's it. It's not a character found in a file stream.
-Tor
Here is a nice working example.
#include <stdio.h> #include "simpletools.h" #define SD_DI 8 #define SD_DO 9 #define SD_CS 12 #define SD_CLK 15 static int SD_PrintValidFileLine(void) { FILE * pFile; char fileline[100]; pFile = fopen("debug.txt","r"); if(pFile == NULL) { print("Error opening file"); } else { do { if (fgets(fileline, 100, pFile) != NULL ) { // Exclude lines that begin with certain characters // E.G. Remove newlines, carriage returns, and lines // that begin with a semi-colon. if(fileline[0] != 59 && fileline[0] != 13 && fileline[0] != 10) { print(fileline); } } } while(fileline[0] != NULL); fclose(pFile); } return -1; } static int SD_PrintAllCharacters(void) { FILE * pFile; int c; pFile = fopen("debug.txt","r"); if(pFile == NULL) { print("Error opening file"); } else { do { c = getc(pFile); print("%c", c); } while(c != EOF); fclose (pFile); } return -1; } int main(void) { int nResult; #if defined SD_DO && defined SD_CLK && defined SD_DI && defined SD_CS // Mount SD card sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS); print("Print Valid File Lines\n\n"); nResult = SD_PrintValidFileLine(); print("\n\n"); if(nResult == -1) { print("SD_PrintValidFileLine() returned successfully"); } print("\n\n"); print("Print All Characters\n\n"); nResult = SD_PrintAllCharacters(); print("\n\n"); if(nResult == -1) { print("SD_PrintAllCharacters() returned successfully"); } #else print("The proper inputs and outputs must be defined for SD card usage"); #endif return 0; }do { ... } while (!feof(pFile));Also, in SD_PrintAllCharacters you want to test for EOF first before printing it.
while((c = getc(pFile)) != EOF) { printf("%c", c); }I would have to agree on both accounts. It looks a whole lot better.
#include <stdio.h> #include "simpletools.h" #define SD_DI 8 #define SD_DO 9 #define SD_CS 12 #define SD_CLK 15 #define DEBUG 1 #ifdef DEBUG #define DEBUG_ERROR 2 #else // set to zero to optimise out #define DEBUG_ERROR 0 #endif static uint8_t debug_flags; static int SD_PrintValidFileLine(void) { FILE * pFile; char fileline[100]; pFile = fopen("debug.txt","r"); if(pFile == NULL) { if(DEBUG && (debug_flags & DEBUG_ERROR)) { print("ERROR - The file could not be opened!"); } } else { do { if (fgets(fileline, 100, pFile) != NULL ) { // Exclude lines that begin with certain characters // E.G. Remove newlines, carriage returns, and lines // that begin with a semi-colon. if(fileline[0] != 59 && fileline[0] != 13 && fileline[0] != 10) { print(fileline); } } } while(!feof(pFile)); fclose(pFile); } return -1; } static int SD_PrintAllCharacters(void) { FILE * pFile; int c; pFile = fopen("debug.txt","r"); if(pFile == NULL) { if(DEBUG && (debug_flags & DEBUG_ERROR)) { print("ERROR - The file could not be opened!"); } } else { do { while((c = getc(pFile)) != EOF) { print("%c", c); } } while(c != EOF); fclose (pFile); } return -1; } int main(void) { int nResult; debug_flags |= DEBUG_ERROR; #if defined SD_DO && defined SD_CLK && defined SD_DI && defined SD_CS // Mount SD card sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS); print("Print Valid File Lines\n\n"); nResult = SD_PrintValidFileLine(); print("\n\n"); if(nResult == -1) { print("SD_PrintValidFileLine() returned successfully"); } print("\n\n"); print("Print All Characters\n\n"); nResult = SD_PrintAllCharacters(); print("\n\n"); if(nResult == -1) { print("SD_PrintAllCharacters() returned successfully"); } #else if(DEBUG && (debug_flags & DEBUG_ERROR)) { print("ERROR - The proper inputs and outputs must be defined for SD card usage!"); } #endif return 0; }I suppose it can.
For those who care, over next couple of days, I will be extending this sample to manioulate data.
EDIT: Actually it will be a different example, more specifically reading a file line and manipulating the contents.
#include <stdio.h> #include "simpletools.h" #define SD_DI 8 #define SD_DO 9 #define SD_CS 12 #define SD_CLK 15 #define DEBUG 1 #ifdef DEBUG #define DEBUG_ERROR 2 #else // set to zero to optimise out #define DEBUG_ERROR 0 #endif static uint8_t debug_flags; static int SD_PrintValidFileLine(void) { FILE * pFile; char fileline[100]; pFile = fopen("debug.txt","r"); if(pFile == NULL) { if(DEBUG && (debug_flags & DEBUG_ERROR)) { print("ERROR - The file could not be opened!"); } } else { do { if (fgets(fileline, 100, pFile) != NULL ) { // Exclude lines that begin with certain characters // E.G. Remove newlines, carriage returns, and lines // that begin with a semi-colon. if(fileline[0] != 59 && fileline[0] != 13 && fileline[0] != 10) { print(fileline); } } } while(!feof(pFile)); fclose(pFile); } return -1; } static int SD_PrintAllCharacters(void) { FILE * pFile; int c; pFile = fopen("debug.txt","r"); if(pFile == NULL) { if(DEBUG && (debug_flags & DEBUG_ERROR)) { print("ERROR - The file could not be opened!"); } } else { while((c = getc(pFile)) != EOF) { print("%c", c); } fclose (pFile); } return -1; } int main(void) { int nResult; debug_flags |= DEBUG_ERROR; #if defined SD_DO && defined SD_CLK && defined SD_DI && defined SD_CS // Mount SD card sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS); print("Print Valid File Lines\n\n"); nResult = SD_PrintValidFileLine(); print("\n\n"); if(nResult == -1) { print("SD_PrintValidFileLine() returned successfully"); } print("\n\n"); print("Print All Characters\n\n"); nResult = SD_PrintAllCharacters(); print("\n\n"); if(nResult == -1) { print("SD_PrintAllCharacters() returned successfully"); } #else if(DEBUG && (debug_flags & DEBUG_ERROR)) { print("ERROR - The proper inputs and outputs must be defined for SD card usage!"); } #endif return 0; }Your loop can be simplified to:
while (fgets(fileline, 100, pFile)) { // Exclude lines that begin with certain characters // E.G. Remove newlines, carriage returns, and lines // that begin with a semi-colon. if(fileline[0] != 59 && fileline[0] != 13 && fileline[0] != 10) { print(fileline); } }Or how about this?
while(!feof(pFile)) { fgets(fileline, 100, pFile); // Exclude lines that begin with certain characters // E.G. Remove newlines, carriage returns, and lines // that begin with a semi-colon. if(fileline[0] != 59 && fileline[0] != 13 && fileline[0] != 10) { print(fileline); } }Considering that fgets will return upon EOF, I would agree that your loop is better.
So the code now becomes:
#include <stdio.h> #include "simpletools.h" #define SD_DI 8 #define SD_DO 9 #define SD_CS 12 #define SD_CLK 15 #define DEBUG 1 #ifdef DEBUG #define DEBUG_ERROR 2 #else // set to zero to optimise out #define DEBUG_ERROR 0 #endif static uint8_t debug_flags; static int SD_PrintValidFileLine(void) { FILE * pFile; char fileline[100]; pFile = fopen("debug.txt","r"); if(pFile == NULL) { if(DEBUG && (debug_flags & DEBUG_ERROR)) { print("ERROR - The file could not be opened!"); } } else { while(fgets(fileline, 100, pFile)) { // Exclude lines that begin with certain characters // E.G. Remove newlines, carriage returns, and lines // that begin with a semi-colon. if(fileline[0] != 59 && fileline[0] != 13 && fileline[0] != 10) { print(fileline); } } fclose(pFile); } return -1; } static int SD_PrintAllCharacters(void) { FILE * pFile; int c; pFile = fopen("debug.txt","r"); if(pFile == NULL) { if(DEBUG && (debug_flags & DEBUG_ERROR)) { print("ERROR - The file could not be opened!"); } } else { while((c = getc(pFile)) != EOF) { print("%c", c); } fclose (pFile); } return -1; } int main(void) { int nResult; debug_flags |= DEBUG_ERROR; #if defined SD_DO && defined SD_CLK && defined SD_DI && defined SD_CS // Mount SD card sd_mount(SD_DO, SD_CLK, SD_DI, SD_CS); print("Print Valid File Lines\n\n"); nResult = SD_PrintValidFileLine(); print("\n\n"); if(nResult == -1) { print("SD_PrintValidFileLine() returned successfully"); } print("\n\n"); print("Print All Characters\n\n"); nResult = SD_PrintAllCharacters(); print("\n\n"); if(nResult == -1) { print("SD_PrintAllCharacters() returned successfully"); } #else if(DEBUG && (debug_flags & DEBUG_ERROR)) { print("ERROR - The proper inputs and outputs must be defined for SD card usage!"); } #endif return 0; }In this current example, I have eliminated grabbing the fille characters one by one, but I have expanded the program pertaining to grabbing filelines and manipulating the data. This program demonstrates some very useful techniques and functions, for those learning C. Basically, this program is the start of a GCODE parser, in which filelines are grabbed from a GCODE file and the various sections of data are stored within a GCODE structure, and during the course of the processing, the results are displayed on the terminal. Additionally, there is an ample amount of comments within the source code to give you a good idea of what is occuring and how it is done.
I have also attached some GCODE commands in the text file below, so that you can test it out.
From this point forward, this specific example and it's growth will documented at this location: http://forums.parallax.com/showthread.php/159950-The-Teacup-Port-A-Work-In-Progress-3D-Printer-Firmware
####WARNING######
If you decide to run this project, please ensure that you set the proper IO pins for your SD card reader in config.h!!!