Hey guys. i am having some trouble writing from Serial.read() to a 2d array.
Code is as follows:
char inData[17][19];
char inChar;
byte index = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
while(Serial.available() > 0) //only read if there is any data
{
if(index < 16)
{
inChar = Serial.read(); //read from Serial
inData[index] = inChar; //store it in inData
index++; //make ready for next time - Next array "downwards"
}
}
}
which gives me "incompatible types in assignment of 'char' to 'char [19]"
What i believe is that i might need to index in the 2nd []. that would be inChar[][here] i just don't know how to do it.
I have been putting google into overdrive, but i can't seem to find anything about it that i understand.
so what i want is to be able to fill this 2d array with a line of text from the Serial monitor.
EG.
If i send
"bob" enter
"bert" enter
"tim" enter
i will be able to just call the array lines like so
inData[0] would be "bob"
inData[1] would be "bert"
inData[2] would be "tim"
i hope you understand.
how would i go about doing this?
char inData[17][19];
char inChar;
byte index = 0;
byte linenumber=0;
void setup() {
Serial.begin(9600);
}
void loop() {
while(Serial.available() > 0) //only read if there is any data
{
if ((linenumber<17) && (index < 19))
{
inChar = Serial.read(); //read from Serial
if (inChar==13)
{
linenumber++;
index=0;
}
inData[linenumber][index] = inChar; //store it in inData
index++; //make ready for next time - Next array "downwards"
}
}
}
i will be able to just call the array lines like so
inData[0] would be "bob"
inData[1] would be "bert"
inData[2] would be "tim"
you only need to read the enter, and pass to the next row of the array. I don't if it makes sense for you?
int row;
(...)
while(Serial.available() > 0) //only read if there is any data
{
inChar = Serial.read(); //read from Serial
if (inChar == 13) { // NEW LINE
row++;
inData[row][index] = '\0';
index=0;
}
else if (inChar >= 32) { // SAVE if it is a PRINTABLE char
inData[row][index] = inChar; //store it in inData
index++; //make ready for next time - Next array "downwards"
}
}
What I did was detect if the incoming char is a char with ASCII code 13 (Carriage Return), and if is I change the line by incrementing the "row" variable and return to the first "index". I only save the characters if they are greater or equal than the ASCII 32 (the space). Usually this character marks the beginning of the "printable" characters area. An character with an ASCII less than 32 is an character for control purposes (like the Carriage Return). When you press "enter", normally they are sent 2 characters the Line Feed (ASCII 10 - change to the next line) and the Carriage Return (ASCII 13 - return to the begin of the new line). So as I don't want to save the ASCII 10 I need the second if. This line:
inData[row][index] = '\0';
marks the end of the string.
I hope you understand this.
Regards.
EDIT: as j514 don't explain what he did I spend more time writing my reply but if you note is more or less the same.
EDIT2: as j514 don't have inData[row][index] = '\0'; you will not be able to print each line with some function to print data (for example to the serial port).
i will be able to just call the array lines like so
inData[0] would be "bob"
inData[1] would be "bert"
inData[2] would be "tim"
you only need to read the enter, and pass to the next row of the array. I don't if it makes sense for you?
int row;
(...)
while(Serial.available() > 0) //only read if there is any data
{
inChar = Serial.read(); //read from Serial
if (inChar == 13) { // NEW LINE
row++;
inData[row][index] = '\0';
index=0;
}
else if (inChar >= 32) { // SAVE if it is a PRINTABLE char
inData[row][index] = inChar; //store it in inData
index++; //make ready for next time - Next array "downwards"
}
}
Maybe you need to take a look at [this](http://benborowiec.com/wp-content/uploads/2011/07/better_ascii_table.jpg).
What I did was detect if the incoming char is a char with ASCII code 13 (Carriage Return), and if is I change the line by incrementing the "row" variable and return to the first "index". I only save the characters if they are greater or equal than the ASCII 32 (the space). Usually this character marks the beginning of the "printable" characters area. An character with an ASCII less than 32 is an character for control purposes (like the Carriage Return). When you press "enter", normally they are sent 2 characters the Line Feed (ASCII 10 - change to the next line) and the Carriage Return (ASCII 13 - return to the begin of the new line). So as I don't want to save the ASCII 10 I need the second `if`. This line:
inData[row][index] = '\0';
marks the end of the string.
I hope you understand this.
Regards.
EDIT: as j514 don't explain what he did I spend more time writing my reply :) but if you note is more or less the same.
EDIT2: as j514 don't have `inData[row][index] = '\0';` you will not be able to print each line with some function to print data (for example to the serial port).
Well, nevermind my other post. you explained it very well, and i am pretty sure i understand how it works, though i still have questions.
When i send a line from Serial monitor, it will still "catch" the enter right? i just wanna make sure i understand.
Also, how would i go about printing this? i should be able to print it like inData[1][4] right? though this would only give me one char.
here's a revised version with consideration for the trailing null and serial output.
Hope that helps!
char inData[17][19];
char inChar;
byte index = 0;
byte linenumber=0;
void setup() {
Serial.begin(9600);
}
void loop() {
while(Serial.available() > 0) //only read if there is any data
{
if ((linenumber<17) && (index < 19))
{
inChar = Serial.read(); //read from Serial
if (inChar==13) // if character is the enter key
{
inData[linenumber][index] = 0; // trailing null
serial.println(inData[linenumber]); // show received line
linenumber++;
index=0;
} else
{
inData[linenumber][index] = inChar; //store it in inData
index++; //make ready for next time - Next array "downwards"
}
}
}
}
To send the data back to the serial line, you can use this:
char inData[17][19];
char inChar;
byte index = 0;
int row=0;
void setup() {
Serial.begin(9600);
}
void loop() {
while(Serial.available() > 0) //only read if there is any data
{
inChar = Serial.read(); //read from Serial
if (inChar == 13) { // NEW LINE
inData[row][index] = '\0';
Serial.println(inData[row]);
row++;
index=0;
}
else if (inChar >= 32) { // SAVE if it is a PRINTABLE char
inData[row][index] = inChar; //store it in inData
index++; //make ready for next time - Next array "downwards"
}
}
}
I had one error in my last post. The line:
inData[row][index] = '\0';
must be before we increment the row number. Sorry about that.
Take a look to the line that sends back the string:
Serial.println(inData[row]);
You don't need the "second dimension". You may think that you what to send all the string and not only the character [n].
i should be able to print it like inData[1][4] right? though this would only give me one char.
Your guess is right. If you try to send "inData[1][4]" you only send the 5th character of the 2nd string. (remember that the arrays starts at zero)
About you other question:
When i send a line from Serial monitor, it will still "catch" the enter right? i just wanna make sure i understand.
You can chose in a drop box at the bottom of the serial monitor if you want to send only the char 13, or only the 10 or the 2 or none.
Aight, so my eyes are getting itchy, and i haven't got much hair left. let the stress commence!
So i wanna try to make a system to check if whatever i enter, is already on the list. for that i made this:
char namecheck[19];
byte namecheckindex = 0;
char inChar;
void namechecker()
{
while(Serial.available() > 0) //only read if there is any data
{
inChar = Serial.read(); //read from Serial
if (inChar==13) // if character is the enter key
{
namecheck[namecheckindex] = 0; // trailing null
Serial.println(namecheck[namecheckindex]); // show received line
namecheckindex=0;
} else
{
namecheck[namecheckindex] = inChar; //store it in inData
namecheckindex++; //make ready for next time - Next array "downwards"
}
}
}
it should essentially just be a copy of the code you gave me, but with names changed, and the namecheck only being a standard array instead of 2d array.
i want this, so that i can unload inChar to namecheck, namecheck will then somehow go through the inData array and check if the entry is already there somewhere. if it is, it will delete the entry, if it isn't then it will enter it on the first open space.
Like this
i enter
"bob"
"bert"
"alice"
namecheck will go through inData and find that these names ins't there.
this will fill the first 3 "lines" in my char inData[17][19]; from the other code.
then i enter "bert" again, namecheck will go through inData and find that "bert is already there.
it will then delete "bert"
though i can't even get the code for printing out my array, working.
i have been staring at it for 1 hour now, and i think i am getting tunnel vision. what am i doing wrong?
also, any tips on my namecheck system, and how to create it ?
Thank you PeterH. Maybe this comment have something to do with the arge of the other day.(BTW you never answer me)
I don't forgot, but I let some work to kasperhangard do. In my code I only take care about the correct way to read (and check the new line), and not about the dimensions. (as kasperhangard have the dimension check in the "original" code, I believe that he knows how and why do it)
Serial.println(namecheck[namecheckindex]); // show received line
This doesn't print the received buffer, it just 'prints' the null terminator. To print the buffer, you need to remove the [ namecheckindex ] so that you pass the whole buffer to println.
You still need to do bounds checking on both indices of the array.
To add the extra logic you describe, you will need to be able to detect whether the string held in namecheck is already in the inData array. A for loop to call strcmp() on each element in the inData array would do that. To remove an entry, you would just null the first character of the string. To add an entry you would just find an empty entry and then use strncpy() to copy the string from namecheck to the empty entry. You can know whether a given entry is empty, because the first char of the string will be null.
Serial.println(namecheck[namecheckindex]); // show received line
This doesn't print the received buffer, it just 'prints' the null terminator. To print the buffer, you need to remove the [ namecheckindex ] so that you pass the whole buffer to println.
You still need to do bounds checking on both indices of the array.
To add the extra logic you describe, you will need to be able to detect whether the string held in namecheck is already in the inData array. A for loop to call strcmp() on each element in the inData array would do that. To remove an entry, you would just null the first character of the string. To add an entry you would just find an empty entry and then use strncpy() to copy the string from namecheck to the empty entry. You can know whether a given entry is empty, because the first char of the string will be null.
Oh ty. i didn't realise the fact that it wasn't a 2d array.
i will try to look into for loops. i haven't done any of those before.
void namechecker()
{
while(Serial.available() > 0) //only read if there is any data
{
inChar = Serial.read(); //read from Serial
if (namecheckindex < 16)
{
if (inChar==13) // if character is the enter key
{
namecheck[namecheckindex] = 0; // trailing null
Serial.println(namecheck); // show received line
namecheckindex=0;
}
else
{
namecheck[namecheckindex] = inChar; //store it in inData
namecheckindex++; //make ready for next time - Next array "downwards"
}
}
}
}
won't this do the boundries?
i mean, if the index gets too high, it can't go any further, can it?
kasperhangard:
won't this do the boundries?
i mean, if the index gets too high, it can't go any further, can it?
Sort of, but not quite. As it stands, if the namecheck array ever filled up then you would stop processing any new characters, so you would never know when to process the buffer. It will work better if you put the 'if(namecheckindex < 16)' condition around the two lines of code that append the character to namecheck. I recommend that you append the null character to the array after each character added rather than just append it before you decide to process the array. It isn't essential, but will save you from bugs later on - perhaps in some other project down the road - where you decide to pass the incomplete buffer to any function that expects it to be terminated.
I don't see where the 16 comes from but you would be safer to define a const value which is the maximum number of characters that the array can hold, and to define this next to / as part of the array declaration so that they stay consistent with each other as your code evolves. Remember that this will be one less than the size of the array since you need one byte at the end to hold the null terminator. You could declare it like this:
const byte MAX_INPUT_LENGTH 16;
char namecheck[MAX_INPUT_LENGTH+1]; // allow space for the null terminator
BareMinimum.ino: In function 'void namechecker()':
BareMinimum:64: error: cannot convert 'char ()[19]' to 'const char' for argument '1' to 'int strcmp(const char*, const char*)'
BareMinimum:73: error: incompatible types in assignment of 'char' to 'char [19]'
So i obviously messed up big time, i just can't seem to graps how the strcmp works. also, i don't know how to append the null after namecheck has been moved over to inData.
Also, is this what you had in mind with the boundries?
inData is an array of string buffers. To check whether it contains a given string you need to loop through each element in the array comparing the string at that position against your candidate string.
for(byte i = 0; i < NAME_COUNT; i++)
{
if(strcmp(inData[i], namecheck) == 0)
{
Serial.print("is already here at position ");
Serial.println(i);
break; // bail out of the for loop; presumably there's no point searching the rest of the array
}
}
PeterH:
inData is an array of string buffers. To check whether it contains a given string you need to loop through each element in the array comparing the string at that position against your candidate string.
for(byte i = 0; i < NAME_COUNT; i++)
{
if(strcmp(inData[i], namecheck) == 0)
{
Serial.print("is already here at position ");
Serial.println(i);
break; // bail out of the for loop; presumably there's no point searching the rest of the array
}
}
Oh ofcourse.. what is namecount? the amount of lines, where names can be written?
I mean, the index for the "height" of the 2d array?