Sending Serial data to modify variables in arduino

Hello,

First of all, I don't want anyone to just do the program for me, I enjoy the learning curve, and also I don't want anyone to think that I'm just asking you to write it all for me.

The problem:

I have an application of writing RFID Tags for different objects (sticky tags 13.56 MHz). I'm using an RFID NFC Module I bought on Ebay: http://www.ebay.com/itm/PN532-NFC-RFID-Reader-Writer-Module-Arduino-Compatible-/261278168864?pt=Vintage_Electronics_R2&hash=item3cd5647720

This module connected to an Arduino Nano 168, connects to a PC through a USB connection and sends/receives serial data from an executable file I just finished.

A simple Arduino sketch validated the communications and data transfer between Arduino and PC.

int ledPin = 13;
int ledState = LOW;

void setup() {
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  String pName = "";
  String pModel = ""; // variables not used in this sample sketch but used in the original
  String pSerial = ""; // variables not used in this sample sketch but used in the original
  String pDestination = ""; // variables not used in this sample sketch but used in the original

  if (Serial.available() > 0) {
    while(Serial.available() > 0) {
        // The length of the data is not random the NFC Module has 4 blocks to write at (for any Classic Mifare card) each block 
       // can write up to 16 characters of information... 4 blocks * 16 characters = 64 characters in total this example only reads
       // the first 16 (just copy paste the while loop after this until the delay and change variable name to read 16 more.
       while(pName.length() <= 16) {
         pName += char(Serial.read());
         
      // This part just blinks the LED to acknowledge serial data transfer
       if (ledState == Low) {
         ledState = HIGH;
       }
       else { 
           ledState = LOW;
        }
        digitalWrite(ledPin, ledState);
        delay (75);
      }
    
    // This outputs the received string
    Serial.print(pName);
    }
  }
}

As seen in the comments of this program, the Mifare Classic cards can store up to 4 blocks of information each consisting of up to 16 characters each. 16 characters * 4 blocks, 64 letters in total.

My program was able to start the serial transfer so that 16 characters per block are sent in order and the simple sketch returns the values in the same order.
So data transfer and receiving/acknowledgement is already done, all I want to do now is include my sketch or combine it with the provided (by manufacturer) nfc sketch to write via serial the values I'm going to be writing instead of having to upload a new sketch every time I want to change the values in the RFID cards.

The manufacturer's sketch is the following:

#include "Wire.h"
#include "nfc.h"

NFC_Module nfc;

void setup(void)

{
  Serial.begin(9600);
  nfc.begin();
  Serial.println("MF1S50 Reader Demo From Elechouse!");
  
  uint32_t versiondata = nfc.get_version();
  if(!versiondata) {
    //Serial.print("Didn't find PN53x board");
    while(1);
  }

  //Serial.print("found chip PN5");
  //Serial.println((versiondata>>24) & 0xFF, HEX);
  //Serial.print("Firmware ver. ");
  //Serial.print((versiondata >> 16) & 0xFF, DEC);
  //Serial.print('.');
  //Serial.println((versiondata>>8) & 0xFF, DEC);
  
  nfc.SAMConfiguration();
}

void loop(void)
{
  u8 buf[32],sta;
  
  sta = nfc.InListPassiveTarget(buf);
  if(sta&&buf[0] ==4) {
    
    Serial.print("UUID length" );
    Serial.print(buf[0], DEC);
    Serial.println();
    Serial.print("UUID: ");
    nfc.puthex(buf+1,buf[0]);
    Serial.println();
    
    u8 key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
    u8 blocknum = 4;
    sta = nfc.MifareAuthentication(0, blocknum, buf+1, buf[0], key);
    
    if(sta) {
      u8 block[16];
      Serial.println("Authentication success");
      
      strcpy((char*)block, "Value Block 4");
      sta = nfc.MifareWriteBlock(blocknum, block);
      
      if(sta) {
        
        Serial.println("Write block 4 successfully");
      }
      delay(500);
    }
  }
}

I thought I had combined it, however I have a few errors I will be putting up soon... The combined program is the following:

#include "Wire.h"
#include "nfc.h"

// Creating an instance of the NFC module to use
NFC_Module nfc;

int ledPin = 13;
int ledState = LOW;

// Getting Comms Ready
void setup() {
 Serial.begin(115200); // Baud Rate higher = faster
 nfc.begin(); // Startup the nfc module
 pinMode(ledPin, OUTPUT);
 
 uint32_t versiondata = nfc.get_version();
 if(!versiondata) {
   // Didn't find a module
   while(1);
  // Debugging options (not needed for real serial communications
  // Serial.print("found chip PN5");
  // Serial.println((versiondata>>24) & 0xFF, HEX);
  // Serial.print("Firmware ver. ");
  // Serial.print((versiondata >> 16) & 0xFF, DEC);
  // Serial.print('.');
  // Serial.println((versiondata>>8) & 0xFF, DEC);
  
  nfc.SAMConfiguration();

 }
 
}

// Main Program
void loop(void) {
  // Setting our initial string variables
  String pName = ""; 
  String pModel = "";
  String pSerial = "";
  String pDestination = "";
  String pBuffer = "";
  
  u8 buf[32], sta;
  
  // Checking for communications availability
  if (Serial.available() > 0) {
    // While communications are still active
    while(Serial.available() > 0) {
  
      sta = nfc.InListPassiveTarget(buf);
      if(sta&&buf[0] == 4) {
    
      // Debugging purposes again
      // Serial.print("UUID length");
      // Serial.print(bug[0], DEC);
      // Serial.println();
      // Serial.print("UUID: ");
      nfc.puthex(buf+1, buf[0]);
      // Serial.println();
    
        u8 key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
        u8 blocknum = 4;
        sta = nfc.MifareAuthentication(0, blocknum, buf+1, buf[0], key);
        char charBuff[16];
        if(sta) {
          char block[16];
          // Debugging 
          // Serial.println("Authentication success");  
  
          while(pName.length() <= 16) {
            // Take info and put it into variable
            pName += char(Serial.read());
            strcpy((char*)block, pName);
            sta = nfc.MifareWriteBlock(blocknum, block);
            
            if (sta) {
              // Debugging purposes
              if (ledState == LOW) { 
              ledState = HIGH;
              // Serial.println("Writting block 4 successful");  
              }
              else {
                ledState = LOW;
              }
              digitalWrite(ledPin, ledState);
            // Give it a time break
            
            delay(75);
            }
          }
           while(pModel.length() <= 16) {
             // Take info and put it in variable
             pModel += char(Serial.read());
             strcpy((char*)block, pModel);
             sta = nfc.MifareWriteBlock(blocknum, block);
             
             if (sta) {
              // Debugging purposes
              if (ledState == LOW) { 
              ledState = HIGH;
              // Serial.println("Writting block 4 successful");  
              }
              else {
                ledState = LOW;
              }
              digitalWrite(ledPin, ledState);
            // Give it a time break
            
            delay(75);
            }
          }
          
          while(pSerial.length() <= 16) {
             // Take info and put it in variable
             pSerial += char(Serial.read());
             strcpy((char*)block, pSerial);
             sta = nfc.MifareWriteBlock(blocknum, block);
             
             if (sta) {
              // Debugging purposes
              if (ledState == LOW) { 
              ledState = HIGH;
              // Serial.println("Writting block 4 successful");  
              }
              else {
                ledState = LOW;
              }
              digitalWrite(ledPin, ledState);
            // Give it a time break
            
            delay(75);
            }
          }
          while(pDestination.length() <= 16) {
             // Take info and put it in variable
             pDestination += char(Serial.read());
             strcpy((char*)block, pDestination);
             sta = nfc.MifareWriteBlock(blocknum, block);
             
             if (sta) {
              // Debugging purposes
              if (ledState == LOW) { 
              ledState = HIGH;
              // Serial.println("Writting block 4 successful");  
              }
              else {
                ledState = LOW;
              }
              digitalWrite(ledPin, ledState);
            // Give it a time break
            
            delay(75);
            }
          }
        }
      }
    }
    //Serial.print("pName is: ");
    Serial.print(pName);
    //Serial.print("pModel is: ");
    Serial.print(pModel);
    //Serial.print("pSerial is: ");
    Serial.print(pSerial);
    //Serial.print("pDestination is: ");
    Serial.print(pDestination);
  }
}

Sorry... appending to the one before... (max allowed characters was reached)

The error I'm getting right now is at line 157

SerialComms.ino: In function 'void loop()':
SerialComms:92: error: cannot convert 'String' to 'const char*' for argument '2' to 'char* strcpy(char*, const char*)'
SerialComms:93: error: invalid conversion from 'char*' to 'u8*'
SerialComms:93: error: initializing argument 2 of 'u8 NFC_Module::MifareWriteBlock(u8, u8*)'
SerialComms:113: error: cannot convert 'String' to 'const char*' for argument '2' to 'char* strcpy(char*, const char*)'
SerialComms:114: error: invalid conversion from 'char*' to 'u8*'
SerialComms:114: error: initializing argument 2 of 'u8 NFC_Module::MifareWriteBlock(u8, u8*)'
SerialComms:135: error: cannot convert 'String' to 'const char*' for argument '2' to 'char* strcpy(char*, const char*)'
SerialComms:136: error: invalid conversion from 'char*' to 'u8*'
SerialComms:136: error: initializing argument 2 of 'u8 NFC_Module::MifareWriteBlock(u8, u8*)'
SerialComms:156: error: cannot convert 'String' to 'const char*' for argument '2' to 'char* strcpy(char*, const char*)'
SerialComms:157: error: invalid conversion from 'char*' to 'u8*'
SerialComms:157: error: initializing argument 2 of 'u8 NFC_Module::MifareWriteBlock(u8, u8*)'
cannot convert 'String' to const char*' for argument '2' to 'char* strcpy(char*, const char*)'

line 157 is:

strcpy((char*)block, pName);

I understand the same or similar error will occur on the other 3 times I run that strcpy() function.
Also I understand I'm trying to convert a string into a char... I tried a few different ways like

pName.toCharArray(charBuff, 16);

Among others...

So I am looking for someone who can gladly and humbly help me understand and help me get this working properly.
I may have tried to chew on something too big for me, but I'm excited about finishing the visual studio program to connect to arduino and communicate to it via serial that I can't stop myself.

If you need any other information I may have missed, please don't hesitate to post it in a reply.

Thank you kindly,

You need to post the code that causes the errors. To solve them, you really need to get over the need to use the String class. The instances you are creating are all going to be a fixed size, so just use NULL terminated char arrays, instead.

I tried a few different ways like

Which doesn't tell us squat. We have no idea what type charBuff is, or, if it's an array, what size it is. Nor do we know what problems you had when you tried that.

I modified my code to receive the data directly onto a char variable of a fixed length (16) but I keep getting a bunch of weird letters and icons on the serial monitor. The code that I'm using is as follows:

char pName[16];
char buff[16];

void setup() {
  Serial.begin(115200);
}
void loop() {
  if (Serial.available()>0){
    while(Serial.available()>0){
      for (int i = 0; i<=15; i++){
        pName[i] = char(Serial.read());
        delay(75);  
      }  
      String str(pName);
      Serial.print(str);
      for (int i = 0; i<=15; i++){
        buff[i] = char(Serial.read());
        delay(250);  
      }  
      String str2(buff);
      Serial.print(str);
    } 
  }
}

The code right now is a back to "basics" since I was told to forget about strings. So my problem is in the serial monitor when I input less or even more letters than the 16 letters I get weird characters like these:

I type hello world once and I receive:

hello world
ÿÿÿÿhello world
ÿÿÿÿ

In the Code I am only converting to a string so that I don't have to make a for loop when sending back the array of chars.
Does anyone know why I'm getting my message sent back 1.5 times again and why with extra icons?

Thank you kindly

In your for loop, you are trying to read 16 characters, yet "hello world\n" is only 12 characters long.

So what happens is that you call "Serial.read()" when no serial input is available and therefore it will return -1.
-1 is "ff" in two's complement which in ascii is that funny "ÿ" character. So your string becomes: "hello world\nÿÿÿÿ".

Why you get this string printed twice? That is because you wrote Serial.print(str); instead Serial.print(str2); after the second loop.

Here is a snippet that should solve your problem. I have not tested it, so hope that if it does not work, at least you understand the general idea.

char buff[16+1] ;

void loop() {
  for (int i=0; i<16; i++) {
    while( serial.available == 0); // wait until the next character arrives
    buff[i] = char(Serial.read());
    if (buff[i] == '\n')
      break;
  }
  buff[i+1] = '\0';

  String str2(buff);
  Serial.print(str);

  // ..
  // second string reading the same way
  // ..
}

Hi,

Thanks for your quick response, yeah I noticed my typo there, but I still receive a second line with the proper syntax:

char pName[16];
char buff[16];

void setup() {
  Serial.begin(115200);
}
void loop() {
  if (Serial.available()>0){
    while(Serial.available()>0){
      for (int i = 0; i<=15; i++){
        pName[i] = char(Serial.read());
        delay(10);  
      }  
      String str(pName);
      Serial.print(str);
//      for (int i = 0; i<=15; i++){
//        buff[i] = char(Serial.read());
//        delay(250);  
//      }  
//      String str2(buff);
//      Serial.print(str);
//      
    } 
  }
}

Your snippet I get the general idea of it (waiting for each character to arrive to assign each incoming character into each position in the array. However I get an error on your snippet:

Invalid use of member(did you forget the '&'?)

sketch_dec02b.ino: In function 'void loop()':
sketch_dec02b:5: error: invalid use of member (did you forget the '&' ?)
sketch_dec02b:10: error: name lookup of 'i' changed for new ISO 'for' scoping
sketch_dec02b:4: error: using obsolete binding at 'i'

The highlighted line is at while( Serial.available == 0); // wait until the next character arrives

If this is the case, that I can indeed use == to wait for each character to arrive from serial then I think I'm in business :stuck_out_tongue:

Thanks!

EDIT: NVM Serial.available was missing the () in the available. but still get another error that this I'm not sure:

name lookup of 'i' changed for new ISO 'for' scoping

sketch_dec02b.ino: In function 'void loop()':
sketch_dec02b:13: error: name lookup of 'i' changed for new ISO 'for' scoping
sketch_dec02b:7: error: using obsolete binding at 'i'

line that has the error is:

buff[i+1] = '\0';

thanks

whoops :grin:

'i' does not exist outside the for loop.
Replace

for (int i=0; i<16; i++) {

with

int i;
for (i=0; i<16; i++) {

You are still trying to read 16 characters as soon as the first one arrives. That will not cut it.

This module connected to an Arduino Nano 168, connects to a PC through a USB connection and sends/receives serial data from an executable file I just finished.

Do you just want the arduino to act as a relay device between the module and an application running on the pc? Is the arduino to do more than just pass data?

Could you elaborate please?

I am able to read 16 characters as soon as they are sent and received, only problem right now in the big scope of things is that I can't do it with the char function. Only with the string function.

Now the only problem I'm having at the moment with the snippet provided is that the characters are stored in the buffer variable and if I type new information but less than the 16 characters, the leftover spots will continue to display the old characters.

I kind of fixed this with the exe program I made in visual studio by padding to the right with blank spaces, this ensures that I send and receive exactly 16 characters no more, no less.

But again, since the program works fine with strings and the NFC function requires characters, it's useless to me.

Thanks

EDIT: sorry zoomkat I didn't see your message. The arduino is being used to write NFC RFID tags from variables it gets from a PC, meaning that when I write in a text box in my PC program the data, it sends it to the arduino so that when I get the acknowledgement of the data transmission I can pass a tag near the NFC module and it automatically writes the values that I just gave it.

Sorry about the longest Run-on sentence I've ever written... I'm at work and typing from the phone is harder the longer the idea/sentence is.

I am able to read 16 characters as soon as they are sent and received, only problem right now in the big scope of things is that I can't do it with the char function. Only with the string function.

You can't do "it". What is "it"?

can't properly read 16 characters (ONLY) using the char function only. I can do it the way I explained at the beginning with strings not with characters. I just get too much "mumbo jumbo" information (yes I know its not mumbo jumbo).

maverick0106:
can't properly read 16 characters (ONLY) using the char function only. I can do it the way I explained at the beginning with strings not with characters. I just get too much "mumbo jumbo" information (yes I know its not mumbo jumbo).

Because you check if there is at least 1 character available, and then read all 16 of them. Doesn't make much sense.

Would you then enlighten me pretty please?

Thanks

Not exactly what you are doing, but the below code captures a character String sent from the serial monitor and then does things with the captured String. The captured String has a character appended to the end designating the servo to be controlled by the included value (the character could identify the desired RFID tag). The value/data in the string could be the new variable set for the designated RFID tag. When the designated RFID tag were actuated, the new variable could be sent to the arduino serial output. Basically you would send a new variable with tag designator to replace the old tag variable.

//zoomkat 11-22-12 simple delimited ',' string parse 
//from serial port input (via serial monitor)
//and print result out serial port
//multi servos added 

String readString;
#include <Servo.h> 
Servo myservoa, myservob, myservoc, myservod;  // create servo object to control a servo 

void setup() {
  Serial.begin(9600);

  //myservoa.writeMicroseconds(1500); //set initial servo position if desired

  myservoa.attach(6);  //the pin for the servoa control
  myservob.attach(7);  //the pin for the servob control
  myservoc.attach(8);  //the pin for the servoc control
  myservod.attach(9);  //the pin for the servod control 
  Serial.println("multi-servo-delimit-test-dual-input-11-22-12"); // so I can keep track of what is loaded
}

void loop() {

  //expect single strings like 700a, or 1500c, or 2000d,
  //or like 30c, or 90a, or 180d,
  //or combined like 30c,180b,70a,120d,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      if (readString.length() >1) {
        Serial.println(readString); //prints string to serial port out

        int n = readString.toInt();  //convert readString into a number

        // auto select appropriate value, copied from someone elses code.
        if(n >= 500)
        {
          Serial.print("writing Microseconds: ");
          Serial.println(n);
          if(readString.indexOf('a') >0) myservoa.writeMicroseconds(n);
          if(readString.indexOf('b') >0) myservob.writeMicroseconds(n);
          if(readString.indexOf('c') >0) myservoc.writeMicroseconds(n);
          if(readString.indexOf('d') >0) myservod.writeMicroseconds(n);
        }
        else
        {   
          Serial.print("writing Angle: ");
          Serial.println(n);
          if(readString.indexOf('a') >0) myservoa.write(n);
          if(readString.indexOf('b') >0) myservob.write(n);
          if(readString.indexOf('c') >0) myservoc.write(n);
          if(readString.indexOf('d') >0) myservod.write(n);
        }
         readString=""; //clears variable for new input
      }
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

Thanks zoomkat,

the problem that I'm facing vs the snippet you provided is that you don't care how many characters you read before receiving a ',' which would mean your limiter. It also looks like you're moving all the info you require into a string. Which is what I'm trying to avoid.

I am trying to avoid using strings because the RFID function to write the variables into the Tags uses char*... I've been trying to either start from char, or convert the string into an array of chars. But this function won't allow either:

........
            pName += char(Serial.read());
            strcpy((char*)block, pName);
            sta = nfc.MifareWriteBlock(blocknum, block);
.........

where pName is a string varialble (String pName = "")
block is a char array with 16 spaces to hold (char block[16])
where sta is a u8 variable (u8 sta)
blocknum is also an u8 variable (u8 blocknum)

for more information on this part of the code, please refer to the beginning of the post where I posted all my code

I'd appreciate anyone's help a lot

Thanks

Back in the day I used the below as part of some servo code where readString was captured from the serial port.

    char carray[6]; 
    readString.toCharArray(carray, sizeof(carray));

That looks pretty good, I'll check it out!

Thanks