NodeMCU EEPROM how to detemine there was no value set earlier - microcontroller

i am trying to save IP address and password in NODE MCU EEPROM. Here is the code snippet.
The problem is the first time i am reading, i am getting garbage values because there were no values set earlier, so how do i determine if there were values set earlier so that i can place default values.
#include <Arduino.h>
#include <EEPROM.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
const char* ssid_default = "NodeMCU";
const char* pass_default = "1234";
uint addr = 0;
ESP8266WebServer server(80);
struct
{
int was_set = 9090; // already Set = 9090, other numbers = not set
char ssid_default[40] = "NODEMCU";
char pass_default[40] = "1234";
int step = 0;
/* data */
}creds;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
EEPROM.begin(512);
delay(5000);
EEPROM.get(addr, creds);
Serial.print("Default SSID: ");
Serial.println(String(creds.ssid_default));
Serial.print("Default Pass:");
Serial.println(String(creds.pass_default));
Serial.print("Times Executed: ");
Serial.println(String(creds.step));
creds.step = creds.step + 1;
EEPROM.put(addr, creds);
Serial.println("Times Executed Incremented, Re-plug Devise to see changes");
EEPROM.commit();
}
void loop() {
delay(1000);
// put your main code here, to run repeatedly:
}

You already have a magic element in your struct that you could check for its special value after reading the EEPROM.
/*...*/
EEPROM.get(addr, creds);
if (creds.was_set != 9090) {
/* set default values */
}
/*...*/
Most application implement a checksum to not only check for unset data, but also for changed data. The algorithm depends on your needs, but don't invent something new, use well-known ones like CRC.
Edit:
Depending on the size of your magic number or checksum, there will always be a small probability that a random set of bits will be recognized as correct/initialized. With a 32-bit value this probability can never be smaller than 2^(-32), which is about 1 in 4 billions.
A checksum has the advantage over a magic value that all values are taken into account.
There is no such thing like 100% safety.

Related

SD.open() returns true but does not create a file

I'm facing a specific problem with SD card and Arduino. I want to create a function that creates a new file on the SD card for a different day. For now, I'm simulating calendar with ints. I know that problem was already discussed but I can't seem to find a similarly discussed problem.
Code:
#include <stdlib.h> // included for floatToString
#include <math.h>
#include <SPI.h>
#include <SD.h>
int year = 2014;
int month = 11;
int day = 4;
char dateTitle[20]; //= "0000000000.txt";
void printDateTitle(char* dateTitle, int Y, int M, int D){
//char dateTitle[20];
sprintf(dateTitle, "%4d-%02d-%02d.txt", Y, M, D);
return;
}
const int chipSelect = 4;
void setup() {
//printDateTitle(dateTitle, year, month, day);
Serial.begin(9600);
while (!Serial) {
;
}
Serial.print("Initializing SD card...");
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
while (1);
}
Serial.println("card initialized.");
}
void loop() {
Serial.print(dateTitle);
delay(1000);
File dataFile = SD.open(dateTitle, FILE_WRITE);
if (dataFile){
dataFile.println("something");
dataFile.close();
Serial.print(day);
Serial.println("something");
delay(1000);
} else
Serial.println("Error");
}
In the code, I have a function void printDateTitle that formats the inputs from the calendar to string which I want to use as a title for the file.
And also, when I define a function in the void loop() with printDateTitle(dateTitle, year, month, day); I get an "Error" in the output meaning SD.open = false.
The problem is that even though SD.open returns true it doesn't create a file on the SD card. .txt is included in the char array. I have also used capital .TXT.
I would be grateful for all the bits of advice regarding the problem.
For the reference, I'm using Arduino Uno and Micro SD card Adapter with Arduino IDE.
The Arduino SD Library documentation states that it uses the "short 8.3 names for files". Therefore only files with 8 characters as name and 3 for file extension are valid. For example: 12345678.txt is valid, 123456789.txt would be invalid.
Your date string (2014-11-04.txt) is to long because it has 10 characters instead of only 8.
Also make sure you've formatted the SD card to a FAT16 or FAT32 file system.

Arduino SD card fails to write when used with another SPI device

I have an ADXL355 accelerometer attached to an Adafruit Feather Adalogger. I can configure and read the sensor. I can also write binary values to the SD card. The problem occurs when I try to read from the sensor and then write that data to the SD card. The only thing I can think of is I'm somehow messing up the SPI communication but I can't see where. I looked through pins_arduino.h for my board and the SD Card (pin 4) is on a different register than pin 10 so I don't see how I'm breaking things.
My operations proceed like this. Global sensor creation, Serial.begin, SD.begin, SPI.begin, Test sensor connection, Create file for output on SD card, Initialize sensor, Read sensor FIFO, Write to file, repeat last 2 forever.
The file is created but remains at 0 file size, ie nothing is actually written to the card.
The sensor can operate at 4 kHz which was hard to achieve using the digitalWrite functions so I switched to using the port registers on the Feather. I do it like this:
#include <SM_ADXL355_SPI_fast.h>
#include <SPI.h>
#include <SD.h>
#define cardSelect 4
ADXL355_SPIF adxl355(&DDRB, &PORTB, _BV(6)); // values taken from pins_arduino.h, tested and working on pin 10
void setup() {
Serial.begin(57600);
while(!Serial){
// wait for Serial
}
SD.begin(cardSelect);
SPI.begin();
while(!adxl355.TestConnection()){
delay(1000);
}
adxl355.OpenFile("TestSPI.bin");
adxl355.Initialize(1, 10, 0); // set range to 2g's, frequency to 4 Hz and filter to off
}
void loop() {
while(true){ // avoid Arduino overhead of their loop function
adxl355.ReadFIFO();
adxl355.WriteFIFOToFile();
}
}
Here is the ADXL constructor
ADXL355_SPIF::ADXL355_SPIF(volatile uint8_t * outReg, volatile uint8_t * outPort, uint8_t bitValue) : sensorOutReg(outReg), sensorPort(outPort), sensorBitValue(bitValue){
*sensorOutReg |= sensorBitValue;
*sensorPort |= sensorBitValue;
sensorWriteCount = 0;
}
TestConnection tests that the DeviceID reads 0xAD. Initialize sets the G range, sample rate in Hz and filter. I have tested these with serial output and they work properly.
OpenFile looks like this:
bool ADXL355_SPIF::OpenFile(const String& fileName){
sensorFile = SD.open(fileName, FILE_WRITE);
if (!sensorFile){
Serial.print("Could not create file: ");
Serial.println(fileName);
return false;
}
return true;
}
After running this a file does get created on the SD card called "TESTSPI.BIN" with 0 file size.
ReadFIFO reads the numbers of entries in FIFO, stored as fifoCount and then populates a buffer (sensorFIFO[32][3]) with the values from the FIFO. I've printed this buffer to Serial to show that it's working. Here is that function
void ADXL355_SPIF::ReadFIFO(){
ReadRegister(ADXL355_RA_FIFO_ENTRIES, 1);
fifoCount = buffer[0];
ReadFIFOInternal();
return;
}
void ADXL355_SPIF::ReadFIFOInternal(){
SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
*sensorPort &= ~sensorBitValue;
uint8_t spiCommand = ADXL355_RA_FIFO_DATA << 1 | ADXL355_READ;
SPI.transfer(spiCommand);
int i = 0;
unsigned long tempV;
unsigned long value;
while(i < fifoCount){
for (int ptr = 0; ptr < 3; ++ptr){
buffer[0] = SPI.transfer(0x0);
value = buffer[0];
value <<= 12;
tempV = SPI.transfer(0x0);
tempV <<= 4;
value |= tempV;
tempV = SPI.transfer(0x0);
tempV >>=4;
value |= tempV;
if (buffer[0] & 0x80) {
value |= 0xFFF00000;
}
long lValue = static_cast<long>(value);
sensorFIFO[i][ptr] = scaleFactor * lValue;
}
i += 3;
}
SPI.endTransaction();
*sensorPort |= sensorBitValue;
return;
}
Here is WriteFIFOToFile:
void ADXL355_SPIF::WriteFIFOToFile(){
if (fifoCount > 0){
sensorFile.write(reinterpret_cast<const char *>(&sensorFIFO), 4 * fifoCount);
}
sensorWriteCount += fifoCount;
if (sensorWriteCount >= 100){
sensorFile.flush();
sensorWriteCount = 0;
}
}
After allowing this to run for a while the file size is always 0. I tried a simple binary write function just to test the card. It looks like this and it worked.
#include <SD.h>
#define cardSelectPin 4
const float pi=3.14159;
File oFile;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while(!Serial){
// wait for serial
}
SD.begin(cardSelectPin);
oFile = SD.open("Test.bin", FILE_WRITE);
Serial.println(sizeof(int));
Serial.println(sizeof(float));
float testFloat[32][3];
for (int i = 0; i < 32; ++i){
for (int j = 0; j < 3; ++j){
testFloat[i][j] = pi * (i + 1) + j;
}
}
oFile.write(reinterpret_cast<const char *>(&testFloat), sizeof(float) * 96);
oFile.close();
Serial.println("Finished writing file.");
}
void loop() {
// put your main code here, to run repeatedly:
}
The problem was that flush was not being called correctly. I had created a buffer to hold data from the FIFO and it would flush the card when it would get full enough such that a subsequent read would overflow. At that time it would call flush. This is what was intended with the variable sensorWriteCount. This variable was of type uint8_t when it should have been a uint16_t.
Changing to the correct type fixed the problem. I would have deleted this question because it boils down to a typo, but once an answer has been posted the system doesn't allow that.
The only difference between the not-working sketch and the working one is the closing of the sd card. The sd card MUST be closed, I had the same problem you have and I assume that the file gets its boundaries written in its filesystem at file close call.
To solve your issue, use a push button. When you push it, it will close the file and stop reading/processing sensors. You can also use this button to start reading and recording sensors data on sd card again (toggle).

Using MSPf5529 with UART returns spacing cedilla in Mac

I'm trying to use the MSPF5529 with my mac. I've downloaded code composer studio and can easily access the chip as well as blink lights and any other application I need.
The goal is for me to print a message using UART through serial communication on my Mac. I am currently using an application called "goSerial" in order to communicate with the chip. My code below initializes UART, takes in a single character, and then it is supposed to print out a character, and then blink a light. However, instead, the code takes in the character, and prints out a strange symbol, called a spacing cedilla, with a hex value of 0xFC, and then blinks the light.
This symbol appears regardless of which character I put into the MSP430 buffer.
My code is listed below. Has anyone had this problem before? How do I solve this?
void Init_UART(void);
void OUTA_UART(unsigned char A);
unsigned char INCHAR_UART(void);
#include "msp430f5529.h"
#include "stdio.h"
int main(void){
volatile unsigned char a;
volatile unsigned int i;
WDTCTL = WDTPW + WDTHOLD;
Init_UART();
a=INCHAR_UART();
a=INCHAR_UART();
OUTA_UART(a);
// go blink the light to indicate code is running
P1DIR |= 0x01;
for (;;){
P1OUT ^= 0x01; i = 10000;
do i--;
while (i != 0); }
}
void OUTA_UART(unsigned char A){
while ((UCA1STAT&UCBUSY));
// send the data to the transmit buffer
UCA1TXBUF =A;
}
unsigned char INCHAR_UART(void){
while ((UCA1STAT&UCBUSY) == 0);
// go get the char from the receive buffer
return (UCA1RXBUF);
}
void Init_UART(void){
P4SEL |= 0x30; // Port 4.4 and port 4.5 controls the transfer
UCA1CTL1|= UCSWRST; // Put state machine in reset
UCA1CTL1|= UCSSEL_1; //Choose 32765Hz
UCA0BR0=3; // Baud rate = 9600
UCA0BR1=0; // Choose 32765 hz
UCA1MCTL=0x06; // Modulation UCBRSx=3, UCBFx = 0
UCA1CTL1 &= ~UCSWRST; // Put USCI in operation mode
}
The UCBUSY flag is not very useful, and cannot be used like this.
That a byte has been received is indicated by UCRXIFG:
while (!(UCA1IFG & UCRXIFG)) ;
return UCA1RXBUF;
That a byte can be sent is indicated by UCTXIFG:
while (!(UCA1IFG & UCTXIFG)) ;
UCA1TXBUF = a;

Arduino RC-522 RFID reader - comparing values in a byte array

I'm using the following code to successfully read IDs from MIFARE cards to the serial monitor.
#include <SPI.h>
#include <MFRC522.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
int readflag;
byte readCard[4];
#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
///////////////////////////////////////// Setup ///////////////////////////////////
void setup() {
Serial.begin(9600);
SPI.begin();
mfrc522.PCD_Init();
mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max);
lcd.begin(20, 4);
}
///////////////////////////////////////////////////////////////////////////////
// Main loop
///////////////////////////////////////////////////////////////////////////////
void loop () {
do {
readflag = checkread();
}
while (!readflag);
//If card detected do this
recordid();
}
///////////////////////////////////////////////////////////////////////////////
// Stores the ID of the card that's been detected in readCard byte array
///////////////////////////////////////////////////////////////////////////////
void recordid() {
mfrc522.PICC_IsNewCardPresent();
mfrc522.PICC_ReadCardSerial();
lcd.clear();
for (int i = 0; i < 4; i++) {
readCard[i] = mfrc522.uid.uidByte[i];
Serial.print( mfrc522.uid.uidByte[i], HEX);
}
Serial.println("");
mfrc522.PICC_HaltA();
}
/////////////////////////////////////////////
// Returns 1 if a card has been detected
/////////////////////////////////////////////
int checkread() {
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return 0; } //no card detected
mfrc522.PICC_HaltA();
return 1; } //card detected
I have 12 cards and the serial monitor is telling me that their ID's are (hex):
3278CE3F
F5C9FD29
2FC640
82BA7A3F
2BD7A3F
52B77A3F
B2E5640
F2DD640
E2ECCC3F
22B3640
2FD640
73D5B7AC
I understand these are being stored in the readCard byte array.
I would like to compare the current value of this byte array to a known value to determine whether an instruction is run (e.g. a blink of an LED)
Something like this:
If (readCard = 2FD640) {
turn on LED
}
I have been able to do this successfully using this if statement:
if ( (uint32_t)readCard == 0x3FCE7832)
for example card one. However, it will not work with the cards with IDs that are not 8 digits long i.e. card 11 (2FD640).
Can anyone help me implement this in code?
Many thanks.
I dont know why if ( (uint32_t)readCard == 0x3FCE7832) worked for you; it shouldnt, since you are casting a byte pointer to a 32-bit integer. What you should have done is:
Declare readCard as a uint8_t pointer and not byte
The comparison should be like this: if (*((uint32_t *)readCard) == 0x3FCE7832)
But like you said, this wont work for the 11th card. You have to right-pad the reversed literal with zeros, like this: if (*((uint32_t *)readCard) == 0x40D62F00). To obtain the reversed literal (e.g. 0x2FDD640), write out the complete byte left padded with zeros to make 8 digits (e.g. 0x02FDD640). Then reverse the order of the bytes (e.g. 0x40D6FD02).
You could also store the card UIDs as arrays in your code and compare them byte-by-byte so that there is no dependence on the size of the UID to create 32-bit ints.
You could use a union like this:
union
{
byte Bytes[4];
uint32_t Integer;
} UnionCard;
Use it like this:
UnionCard Uc;
Fill it similar to your readCard[i] in the loop like this:
Uc.Bytes[i] = mfrc522.uid.uidByte[i];
Get the UInt with:
Uc.Integer;

Brightness on digital output varies based on level input type

Basically, I am following the tutorial code in BarGraph for the LED bar graph. I do not have a potentiometer, so I thought to mimic it by using a Processing serial write, based on the dimmer example in Dimmer. I have set the sensorReading value to the input from the Processing application (updating its grid to be 1023 elements) like so:
int sensorReading;
if (Serial.available()) {
// Read the most recent byte (which will be from 0 to 1023):
sensorReading = Serial.read();
}
This does light up the LEDs based on my mouse position in the grid in the Processing application. However the LEDs are very dim. If I change how I set the sensorReading value to:
int sensorReading = random(0, 1023);
Then the LEDs light up much brighter. Since the LEDs are all on the digital out pins I thought it would just send on/off based on the sensorReading value and would not have anything to do with how bright. What am I missing?
Here is the Processing code:
// Dimmer - sends bytes over a serial port
// by David A. Mellis
//
// This example code is in the public domain.
import processing.serial.*;
Serial port;
void setup() {
size(256, 150);
println("Available serial ports:");
println(Serial.list());
// Uses the first port in this list (number 0). Change this to
// select the port corresponding to your Arduino board. The last
// parameter (for example, 9600) is the speed of the communication. It
// has to correspond to the value passed to Serial.begin() in your
// Arduino sketch.
//port = new Serial(this, Serial.list()[0], 9600);
// If you know the name of the port used by the Arduino board, you
// can specify it directly like this.
port = new Serial(this, "COM6", 9600);
}
void draw() {
// Draw a gradient from black to white
for (int i = 0; i < 1024; i++) {
stroke(i);
line(i, 0, i, 150);
}
// Write the current X-position of the mouse to the serial port as
// a single byte.
port.write(mouseX);
}
Here is the Arduino code:
// These constants won't change:
const int analogPin = A0; // The pin that the potentiometer is attached to.
const int ledCount = 10; // The number of LEDs in the bar graph.
int ledPins[] = {
2, 3, 4, 5, 6, 7,8,9,10,11 }; // An array of pin numbers to which LEDs are attached.
void setup() {
Serial.begin(9600);
// Loop over the pin array and set them all to output:
for (int thisLed = 0; thisLed < ledCount; thisLed++) {
pinMode(ledPins[thisLed], OUTPUT);
}
}
void loop() {
// Read the potentiometer:
// int sensorReading = random(0, 1023);
// delay(250);
byte streamReading;
if (Serial.available()) {
// Read the most recent byte (which will be from 0 to 255):
sensorReading = Serial.read();
}
//Serial.println(sensorReading);
// Map the result to a range from 0 to the number of LEDs:
int ledLevel = map(sensorReading, 0, 255, 0, ledCount);
// Loop over the LED array:
for (int thisLed = 0; thisLed < ledCount; thisLed++) {
// If the array element's index is less than ledLevel,
// turn the pin for this element on:
if (thisLed < ledLevel) {
digitalWrite(ledPins[thisLed], HIGH);
}
// Turn off all pins higher than the ledLevel:
else {
digitalWrite(ledPins[thisLed], LOW);
}
}
}
Problem: Your processing code is sending data constantly, sending serial data to your Arduino all the time:
Called directly after setup(), the draw() function continuously
executes the lines of code contained inside its block until the
program is stopped or noLoop() is called. draw() is called
automatically and should never be called explicitly.
This causes your Arduino sketch to update the LED on/off status frequently, and given how you read the data, this will result in LEDs pulsing really fast.
Solution: The simplest fix would be to add a delay to either the Arduino or the Processing sketch. An even better solution would be to modify the Processing code to only send data when the value changes; although note that since mouse values change almost constantly and that those changes wouldn't be significant for the Arduino code, you still might have a lot of unnecessary flickering. However, if you fix the serial read function in your Arduino code, the flickering will not be as much of a problem anyway.)
Code: Modify your Processing code to track the last reading, and only update if it is different:
int lastMouseX;
void draw() {
// draw a gradient from black to white ...
int newMouseX = mouseX;
if (newMouseX != lastMouseX) {
lastMouseX = newMouseX
// write the current X-position of the mouse to the serial port as
// a single byte
port.write(mouseX);
}
Other issues: First of all there is an issue if you are expecting a value 0-1024: the Arduino's analogWrite() function takes a byte 0-255.
Secondly, as Martin Thompson points out, you are probably sending a string such as 128 from your processing application, and then using its ASCII values to set the intensity. Since ASCII values of 0 through 9 are in the 48-57 range, that will give you a relatively low intensity. Note that when a string of more than one byte somes in (such as 128) you are using only only one byte for intensity. So you have two options:
Send a real binary byte, not a string. This is what is done in the dimmer example you show
Send a string, and then convert it to its binary representation. For this you will need to read all the characters up until some delimiter (such as CR, or space), collect them up, and then convert.
This code might look something like this:
#include <stdlib.h>
int idxChar = 0;
#define BUFFER_SIZE 10
char strIntensity[BUFFER_SIZE];
...
while (Serial.available()) {
// read the string representation of a byte
// assuming bytes are separated by non-numeric characters
// and never overflow
char ch = Serial.read();
if ( (ch >= '0') && (ch <= '9') ) {
strIntensity[idxChar++] = ch;
} else {
strIntensity[idxChar] = 0;
sensorReading = atoi(strIntensity);
idxChar = 0;
}
if (idxChar>=BUFFER_SIZE-1) {
// (need space for the null char at the end too
// Buffer overflow. Bail
idxChar = 0;
}
}
// read the most recent byte (which will be from 0 to 1023)
Bytes go from 0 to 255. And they (usually) represent characters from the ASCII character set.
If you are expecting to read numbers between 0 and 1023 they could be being transmitted a character at a time (ie a character 1 followed by a character 0 would represent the number 10) - in which case you have to parse them to turn them into a number that can be used as you expect.
The parseInt function is probably what you need - a tutorial on reading ASCII integers can be found here

Resources