I'm having this little problem with some easy code, basically what I'm doing is sending information via the serial port via a program I wrote in Java. The information is getting their for basic statements (IE, can turn on lights and stuff) but I'm having errors getting it to decode strings with number values send to it.
So for example, I'm sending strings that look like this
BS//:+000/+000/+000
and the decoding method I'm using looks like this.
After adding the string via this:
if (inputString.startsWith("BS//:")) //**fixed
{
inputInfoToBaseStepper(inputString);
baseStepperRunAction(baseStepperRotCount, baseStepperRotStepSize, baseStepperTime);
}
Sends it too...
void inputInfoToBaseStepper(String baseStepper)
{
baseStepperRotCount = baseStepper.substring(6,9).toInt();
baseStepperRotStepSize = baseStepper.substring(10,13).toInt();
baseStepperTime = baseStepper.substring(15,18).toInt();
}
Which should decode and run
void baseStepperRunAction (int rotations, int StepSize, int delayTime)
{
for (int rotations; rotations >=0; rotations--)
{
baseStepper.step(StepSize);
delay(delayTime);
}
}
Problem seems to be that it doesn't decode... ideas I'm sort of lost at this stage. :/
(total past of the code, I know the information is getting there, just not compiling like it should.)
#include <Stepper.h>
//#include <HardwareSerial.h>
// int intensity = 0; // led intensity this is needed just as example for this sketch
String inputString = ""; // a string to hold incoming data (this is general code you can reuse)
boolean stringComplete = false; // whether the string is complete (this is general code you can reuse)
int stepsPerRevolution = 64; //at 5.625 degrees a step
// initialize the stepper library on pins 8 through 11:
Stepper baseStepper(stepsPerRevolution, 2,3,4,5); // protocols start with //BS:
Stepper shoulderStepper(stepsPerRevolution, 6,7,8,9); // protocols start with //SS:
Stepper armStepper(stepsPerRevolution, 10,11,12,13); // protocols start with //AS:
//--------baseStepper--------//
int baseStepperRotCount = 0; //how many rotations in the for loop is needed
int baseStepperRotStepSize = 0; // how large should the steps be...
int baseStepperTime = 0; //delay time needed between each step (delay); so the stepper can do it's work.
//--------shoulderStepper--------//
int shoulderStepperRotCount =0;
void setup() {
// initialize serial: (this is general code you can reuse)
Serial.begin(115200);
}
void loop() {
// when a newline arrives:
if (stringComplete) {
//these are test if statements, they serve no purpose after the intial boot, but must be included to test the connectivity;
if (inputString.startsWith("alpha"))
{
boolean msgRecognized = true;
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
inputString = "";
stringComplete = false;
}
else if (inputString.startsWith("beta"))
{
boolean msgRecognized = true;
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
inputString = "";
stringComplete = false;
}
//---------------------///
//these statements set the engines and prepare for running of the program.
if (inputString.startsWith("//BS:")) // "BS//:+000/+000/+000"
{
inputInfoToBaseStepper(inputString);
baseStepperRunAction(baseStepperRotCount, baseStepperRotStepSize, baseStepperTime);
}
else if (inputString.startsWith("//SS:"))
{
//inputInfoToShoulderStepper();
//outputConfirmed();
}
else if (inputString.startsWith("//AS:"))
{
//inputInfoToArmStepper();
// outputConfirmed();
}
if(inputString.startsWith("alp://")) { // OK is a message I know (this is general code you can reuse)
boolean msgRecognized = true;
if(inputString.substring(6,10) == "kprs") { // KeyPressed }
msgRecognized = false; // this sketch doesn't know other messages in this case command is ko (not ok)
// Prepare reply message if caller supply a message id (this is general code you can reuse)
int idPosition = inputString.indexOf("?id=");
if(idPosition != -1) {
String id = inputString.substring(idPosition + 4);
// print the reply
Serial.print("alp://rply/");
if(msgRecognized) { // this sketch doesn't know other messages in this case command is ko (not ok)
Serial.print("ok?id=");
} else {
Serial.print("ko?id=");
}
Serial.print(id);
Serial.write(255); // End of Message
Serial.flush();
}
}
// clear the string:
inputString = "";
stringComplete = false;
}
}
}
/*
Send listen messages
int index = 0;
for (index = 0; index < digitalPinListeningNum; index++) {
if(digitalPinListening[index] == true) {
int value = digitalRead(index);
if(value != digitalPinListenedValue[index]) {
digitalPinListenedValue[index] = value;
Serial.print("alp://dred/");
Serial.print(index);
Serial.print("/");
Serial.print(value);
Serial.write(255);
Serial.flush();
}
}
}
for (index = 0; index < analogPinListeningNum; index++) {
if(analogPinListening[index] == true) {
int value = analogRead(index);
if(value != analogPinListenedValue[index]) {
analogPinListenedValue[index] = value;
Serial.print("alp://ared/");
Serial.print(index);
Serial.print("/");
Serial.print(value);
Serial.write(255); // End of Message
Serial.flush();
}
}
}
} */
//this method decodes and stores inputs
void inputInfoToBaseStepper(String baseStepper)
{
baseStepperRotCount = baseStepper.substring(6,9).toInt(); // B S / / : + 0 0 0 / + 0 0 0 / + 0 0 0
baseStepperRotStepSize = baseStepper.substring(10,13).toInt();// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8
baseStepperTime = baseStepper.substring(15,18).toInt();
}
//this method runs the base stepper off the decoded actions.
void baseStepperRunAction (int rotations, int StepSize, int delayTime)
{
for (int rotations; rotations >=0; rotations--)
{
baseStepper.step(StepSize);
delay(delayTime);
}
}
/*
SerialEvent occurs whenever a new data comes in the
hardware serial RX. This routine is run between each
time loop() runs, so using delay inside loop can delay
response. Multiple bytes of data may be available.
This is general code you can reuse.
*/
void serialEvent() {
while (Serial.available() && !stringComplete) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}
Related
I have the below code that creates a delay in-between drawing characters from a string, this works using println() however does not work when using the text() function. The code is supposed to wait an allotted time then print the next character, I'm really not sure what I'm doing wrong.
int startTimer;
int waitTime = 500;
boolean funcRun = true;
void setup(){
size(500, 500);
startTimer = millis();
}
void draw(){
while(funcRun){
textAnim("hello");
}
}
void textAnim(String textInput){
int counter = 0;
int x = 10;
while(counter < textInput.length()){
if(millis() - startTimer>waitTime){
text(textInput.charAt(counter), x , 100);
startTimer = millis();
++counter;
x = x + 10;
}
funcRun = false;
}
}
The displayed screen is updated at the end of the draw() function. So your while loop is fully executed and the completed text is shown. You'll have to modify the code such that it will constantly refresh/redraw the screen, and updates the displayed text based on the time loop.
For example like this:
int currentTime;
int waitTime = 500;
int characters_to_display = 0;
boolean stringComplete = false;
String textInput = "Hello";
void setup() {
size(500, 500);
currentTime = millis();
}
void draw() {
// Update text to be shown. increaseCharIndex() is called while the text is not yet fully displayed
if (stringComplete == false) {
increaseCharIndex();
}
//Draw screen:
// draw background to clear screen
background(0);
// display (a substring of) the text
text(textInput.substring(0, characters_to_display), 10, 100);
}
void increaseCharIndex() {
// if the waitperiod has passed, increase the number of characters to be displayed
if (millis() - currentTime>waitTime) {
currentTime = millis();
characters_to_display++;
}
// if the full text will be shown, end the call to increaseCharIndex()
if (characters_to_display >= textInput.length())
{
stringComplete = true;
}
}
im learning coding with arduino and c#. my program send by bluetooth commands to do for platform with stepper motors ( simple list of moves).
Step first - After recive informations, prepare them to use (format !,.(...)# (eg. !1,100.3,90.# mean move forward(1) for 100 ms, move left(3) 90 ms. ! -start of stream # - end of stream)
Step two - execute moves
Step three - if no more, proceed loop till next information come to Serial1 (which mean start step first.
And it even works, but after first recived string my Serial1.available() returns false ;/
i have no idea why? is he busy or what? i can't recive second string of commands
#define a1 4 //stepper motor connection
#define a2 3
#define b1 5
#define b2 6
int licznikRuch = 0; // counter for tabMove
int licznikCzas = 0;// counter for tabTime
int kolejka = 0;
bool CiagRuch = false;
bool CiagCzas = false; //
bool Zakonczono = false; //
int SubPoczatek, SubKoniec; // substring start / substring end
bool Wykonaj = false;
String tabMove[100];
String tabTime[100];
String inputString = "";
String StringCzas = "";
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial1.begin(9600); //
Serial2.begin(9600);
inputString.reserve(200);
for(int i = 0; i < 100; i++){
tabMove[i] = "";
tabTime[i] = "";
}
pinMode(19, OUTPUT);pinMode(17,OUTPUT);
pinMode(51,OUTPUT);
pinMode(a1, OUTPUT); pinMode(a2, OUTPUT);
pinMode(b1, OUTPUT); pinMode(b2, OUTPUT);
digitalWrite(a1,LOW); digitalWrite(a2,LOW);
digitalWrite(b1,LOW); digitalWrite(b2,LOW);
}
void loop() {
// put your main code here, to run repeatedly:
if(Zakonczono){ // operacje na wczytanym ciagu. wydobycie rozkazow i czasu
Serial.println(inputString);
for(int i = 0; i < inputString.length();i++){
if(inputString[i] == '!'){
for(int l =0;l<100;l++){
Wykonaj = false;
tabTime[l] = "";
tabMove[l] = "";
licznikCzas = 0;
licznikRuch = 0;
}
}
if(inputString[i] == '#'){
Wykonaj = true;
}
if(inputString[i] == '.'){
SubKoniec = i;
tabTime[licznikCzas++] = inputString.substring(SubPoczatek+1,SubKoniec);
CiagCzas = false;
StringCzas = "";
}
if(inputString[i] == ','){
tabMove[licznikRuch++] = inputString[i-1];
CiagCzas = true;
SubPoczatek = i;
}
}
for(int i = 0; i< licznikCzas;i++)
Serial.println(i+"Ruch"+tabMove[i]+"Czas:"+tabTime[i]);
Zakonczono = false;
inputString= "";
}
while(Wykonaj) // if you cut off whole this loop Serial1 is still available and recive commands
{
if(tabMove[kolejka] == "1") // move forward
{
digitalWrite(a1,LOW);
digitalWrite(a2,HIGH);
digitalWrite(b1,LOW);
digitalWrite(b2,HIGH);
delay(tabTime[kolejka].c_str());
Serial.print("1");
digitalWrite(a1,LOW);
digitalWrite(a2,LOW);
digitalWrite(b1,LOW);
digitalWrite(b2,LOW);
kolejka++;
// Serial.print(kolejka);
}
if(tabMove[kolejka] == "2"){ // left
digitalWrite(a1,LOW);
digitalWrite(a2,HIGH);
digitalWrite(b1,HIGH);
digitalWrite(b2,LOW);
delay(tabTime[kolejka].c_str());
Serial.print("2");
digitalWrite(a1,LOW);
digitalWrite(a2,LOW);
digitalWrite(b1,LOW);
digitalWrite(b2,LOW);
kolejka++;
}
if(tabMove[kolejka] == "3"){ // right
digitalWrite(a1,HIGH);
digitalWrite(a2,LOW);
digitalWrite(b1,LOW);
digitalWrite(b2,HIGH);
delay(tabTime[kolejka].c_str());
Serial.print("3");
digitalWrite(a1,LOW);
digitalWrite(a2,LOW);
digitalWrite(b1,LOW);
digitalWrite(b2,LOW);
kolejka++;
}
if(tabMove[kolejka] == "4"){ // back
digitalWrite(a1,HIGH);
digitalWrite(a2,LOW);
digitalWrite(b1,HIGH);
digitalWrite(b2,LOW);
delay(tabTime[kolejka].c_str());
Serial.print("3");
digitalWrite(a1,LOW);
digitalWrite(a2,LOW);
digitalWrite(b1,LOW);
digitalWrite(b2,LOW);
kolejka++;
}
if(tabMove[kolejka] == ""){
Wykonaj = false;
if(!Serial1.available())
Serial.print("Serial1 not avaliable ;("); // ???
break;
}
}
}
void serialEvent1(){
char Znak = "_";
// char PoprzedniZnak = Znak;
while(Serial1.available()){
// Serial.write(Znak);
Znak = (char)Serial1.read();
inputString+= Znak;
if(Znak == '\n')
Zakonczono = true;
kolejka = 0;
}
}
Alright, first of all, let's get out of the way the silly things:
Have your tried to connect/reconnect the usb from your pc to arduino?
Have you tried to restart your pc and unplug the usb?
Have you checked that you have NO wire attached to pin 0 (RX) pin once you upload the code? This is a very common mistake, if it's the case take out the wire from pin 0 before you upload, then upload and put in the wire again after the upload is FULLY complete (you will get the white writings when it is)
Make sure that your pc drives are up to date, and you can see the serial in both your periferials, AND the IDE and it's connected properly
Ok now that this is out the way, a few suggestions:
Write the error number in the post, Serial.available is false, does not mean anything, should Serial.available = true and then something happens and you trigger the condition of Serial.available false?
Your code is a mess (no offense), make sure you make it a little nicer if you want others to give it a shot!
Now to your problem:
I don't know wheter you mean that your code is bad or it's the serial as serial port that is going ape.
So here is 2 solutions
For the code:
What you wrote here will not work and that's why the serial is not available:
void serialEvent1(){
char Znak = "_";
// char PoprzedniZnak = Znak;
while(Serial1.available()){ //What kind of condition is this?
// Serial.write(Znak);
Znak = (char)Serial1.read(); //This does not work! Why using char and convert when
//You can use a string!
inputString+= Znak;
if(Znak == '\n')
Zakonczono = true;
kolejka = 0;
}
}
It should be this:
void serialEvent1(){
String Znak = "_";
while(Serial1.available() == 0){
// Serial.write(Znak);
Znak = Serial1.readString();
inputString+= Znak;
if(Znak == '\n') //This is quite weird if a char or a String ==
//enter(button)?
Zakonczono = true;
kolejka = 0;
}
}
0 if you want it to start on an input into the serial, plus I would SERIOUSLY recommended that you do not use a while loop if this is a choice program, unless you encompass all the choices in the while loop and then you have another while loop that takes care of other choices
But said that let's go over the second solution:
Serial as in hardware:
You have to write me the error number you are getting otherwise I cannot help you, check my steps above and make sure that you are not making one of those mistakes, if you are not please write your error number in the post.
Hope it helped!
And that I wasn't too harsh ;)
I am working on a MFC app that need to get the same output with the console app. The console app can display the input data from serial port. I want to get the input with the MFC dialog app and display it into edit control box. Since I am still new to C++, it seems quite challenging to me. Any suggestions for the workaround? Thanks in advance!
The console app code:
enum { EOF_Char = 27 };
int ShowError (LONG lError, LPCTSTR lptszMessage)
{
// Generate a message text
TCHAR tszMessage[256];
wsprintf(tszMessage,_T("%s\n(error code %d)"), lptszMessage, lError);
return 1;
}
int __cdecl _tmain (int /*argc*/, char** /*argv*/)
{
CSerial serial;
LONG lLastError = ERROR_SUCCESS;
lLastError = serial.Open(_T("COM1"), 0, 0, false);
lLastError = serial.Setup(CSerial::EBaud9600, CSerial::EData8,CSerial::EParNone, CSerial::EStop1);
lLastError = serial.SetupHandshaking(CSerial::EHandshakeHardware);
// ** The query command to get input data **
lLastError = serial.Write(":MEAS:FREQuency?\n");
// Register only for the receive event
lLastError = serial.SetMask(CSerial::EEventBreak |
CSerial::EEventCTS |
CSerial::EEventDSR |
CSerial::EEventError |
CSerial::EEventRLSD |
CSerial::EEventRecv);
if (lLastError != ERROR_SUCCESS)
return ::ShowError(serial.GetLastError(), _T("Unable to set COM-port event mask"));
// Use 'non-blocking' reads,cuz we don't know how many bytes will be received.
lLastError = serial.SetupReadTimeouts(CSerial::EReadTimeoutNonblocking);
if (lLastError != ERROR_SUCCESS)
return ::ShowError(serial.GetLastError(), _T("Unable to set COM-port read timeout."));
// Keep reading data, until an EOF (CTRL-Z) has been received
bool fContinue = true;
do
{
// Wait for an event
lLastError = serial.WaitEvent();
if (lLastError != ERROR_SUCCESS)
return ::ShowError(serial.GetLastError(), _T("Unable to wait for a COM-port event."));
// Save event
const CSerial::EEvent eEvent = serial.GetEventType();
// Handle break event
if (eEvent & CSerial::EEventBreak)
{ printf("\n### BREAK received ###\n"); }
// Handle CTS event
if (eEvent & CSerial::EEventCTS)
{ printf("\n### Clear to send %s ###\n", serial.GetCTS()?"on":"off"); }
// Handle error event
if (eEvent & CSerial::EEventError)
{
printf("\n### ERROR: ");
switch (serial.GetError())
{
case CSerial::EErrorBreak: printf("Break condition"); break;
case CSerial::EErrorMode: printf("Unsupported mode"); break;
case CSerial::EErrorOverrun: printf("Buffer overrun"); break;
case CSerial::EErrorTxFull: printf("Output buffer full"); break;
default: printf("Unknown"); break;
}
printf(" ###\n");
}
// Handle RLSD/CD event
if (eEvent & CSerial::EEventRLSD)
{ printf("\n### RLSD/CD %s ###\n", serial.GetRLSD()?"on":"off"); }
// Handle data receive event
if (eEvent & CSerial::EEventRecv)
{
// Read data, until there is nothing left
DWORD dwBytesRead = 0;
char szBuffer[101];
do
{
// Read data from the COM-port
lLastError = serial.Read(szBuffer,sizeof(szBuffer)-1,&dwBytesRead);
if (lLastError != ERROR_SUCCESS)
return ::ShowError(serial.GetLastError(), _T("Unable to read from COM-port."));
if (dwBytesRead > 0)
{
// Finalize the data, so it is a valid string
szBuffer[dwBytesRead] = '\0';
// **Display the data/Need the same output for EditBox**
printf("%s", szBuffer);
// Check if EOF (CTRL+'[') has been specified
if (strchr(szBuffer,EOF_Char))
fContinue = false;
}
}
while (dwBytesRead == sizeof(szBuffer)-1);
}
}
while (fContinue);
// Close the port again
serial.Close();
return 0;
}
Since my knowledge in C++ was not good enough, so I was not aware of my problems were how to break the loop in the above code & the conversion between char array and CString. This is my answer :
void Singlemode::OnBnClickedButton3()
{
CString str3;
// TODO: Add your control notification handler code here
CSerial serial;
LONG lLastError = ERROR_SUCCESS;
lLastError = serial.Open(_T("COM1"), 0, 0, false);
lLastError = serial.Setup(CSerial::EBaud9600, CSerial::EData8, CSerial::EParNone, CSerial::EStop1);
lLastError = serial.SetupHandshaking(CSerial::EHandshakeHardware);
lLastError = serial.Write(":MEAS:FREQuency?\n");
// Register only for the receive event
// Use 'non-blocking' reads, because we don't know how many bytes
// will be received. This is normally the most convenient mode
// (and also the default mode for reading data).
bool fContinue = true;
do
{
// Wait for an event
lLastError = serial.WaitEvent();
// Save event
const CSerial::EEvent eEvent = serial.GetEventType();
// Handle data receive event
if (eEvent & CSerial::EEventRecv)
{
// Read data, until there is nothing left
DWORD dwBytesRead = 0;
char szBuffer[101];
do
{
// Read data from the COM-port
lLastError = serial.Read(szBuffer, sizeof(szBuffer) - 1, &dwBytesRead);
if (dwBytesRead > 0)
{
// Finalize the data, so it is a valid string
szBuffer[dwBytesRead] = '\0';
// Display the data
str3 = CString(szBuffer); // conversion to display
show_result.SetWindowText(str3);
fContinue = false; // break the loop
}
} while (dwBytesRead == sizeof(szBuffer) - 1);
}
} while (fContinue);
}
I very new to Arduino Uno and need some advice....so here we go.
I want to use my Arduino to:
1. read my serial data --received as plain text
2. look for a specific word within a line of data received
3. only transmit/print the complete string if it contains the specific "word"
I found this sketch and it works only if I'm looking for char
// Example 3 - Receive with start- and end-markers
const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;
void setup() {
Serial.begin(9600);
Serial.println("<Arduino is ready>");
}
void loop() {
recvWithStartEndMarkers();
showNewData();
}
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
void showNewData() {
if (newData == true) {
Serial.print("This just in ... ");
Serial.println(receivedChars);
newData = false;
}
}
I think it is better to use String class methods.
you can get the Data using Serial.readString()
then use the String methods for looking for a specific word.
Here are some useful links
https://www.arduino.cc/en/Serial/ReadString
https://www.arduino.cc/en/Reference/StringObject
I am trying to work with the sim900, what I am trying to do, is: 1- read the serial port, 2- input everything into a string, 3- search a parameter in that string, 4- clean the string.
The code is really simple, but i cant understand what i am doing wrong.
If anyone make something similar, or knows how to do it I will be graceful.
Thank you very much
Jose Luis
String leido = " ";
void setup(){ // the Serial1 baud rate
Serial.begin(9600);
Serial1.begin(9600);
}
String leido = " ";
void setup(){
// the Serial1 baud rate
Serial.begin(9600);
Serial1.begin(9600);
}
void loop()
{
//if (Serial1.available()) { Serial.write(Serial1.read()); } // Sim900
if (Serial.available()) { Serial1.write(Serial.read()); } // pc
leido = LeerSerial();
Serial.println(leido);
if (find_text("READY",leido)==1){leido = " ";}
}
String LeerSerial(){
char character;
while(Serial1.available()) {
character = Serial1.read();
leido.concat(character);
delay (10); }
if (leido != "") { Serial1.println(leido);return leido; }
}
int find_text(String needle, String haystack) {
int foundpos = -1;
for (int i = 0; (i < haystack.length() - needle.length()); i++) {
if (haystack.substring(i,needle.length()+i) == needle) {
foundpos = 1;
}
}
return foundpos;
}
You shouldn't be using == to compare strings in C/C++, since that compares pointers. A better option is strcmp or even better strncmp, check this reference.
Back to your code, try something like this:
if (strncmp(haystack.substring(i,needle.length()+i), needle, needle.length()) == 0) {
foundpos = 1;
}
Can you get away by simply using String's indexOf() ?:
String leido = " ";
void setup() {
// the Serial1 baud rate
Serial.begin(9600);
Serial1.begin(9600);
}
void loop()
{
//if (Serial1.available()) { Serial.write(Serial1.read()); } // Sim900
if (Serial.available()) {
Serial1.write(Serial.read()); // pc
}
leido = LeerSerial();
Serial.println(leido);
if (leido.indexOf("READY") == 1) {
leido = " ";
}
}
String LeerSerial() {
char character;
while (Serial1.available()) {
character = Serial1.read();
leido.concat(character);
delay (10);
}
if (leido != "") {
Serial1.println(leido);
return leido;
}
}
Note that this assumes "READY" is always at index 1.
Maybe it's worth checking if the indexOf("READY") is greater than -1 (present in the string) ?