Morse Code Arduino by toggling the same LED light - arduino

Suppose I want to create the app which allow user enter a message on Android and display it in Morse code on the Arduino by toggling the LED.
A message in Morse code consists of series of dashes (LONGS) and dots (shorts).
These dashes and dots can then be displaying by turning the LED on for the correct number of time units.
#include <Usb.h>
#include <AndroidAccessory.h>
#define LED_PIN 13
#define SHORT 0
#define LONG 1
#define LETTER 2
#define WORD 3
#define STOP 4
#define UNIT 250
AndroidAccessory acc("testing",
"morse_code",
"CoolAccessory",
"1.0",
"http://www.example.com/CoolAccessory",
"0000000012345678");
void setup()
{
// set communiation speed
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
acc.powerOn();
}
void loop()
{
byte msg[125];
if (acc.isConnected()) {
int len = acc.read(msg, sizeof(msg), 1); // read data into msg variable
if (len > 0) { // Only do something if a message has been received.
displayMorseCode(msg, len);
}
}
else
digitalWrite(LED_PIN , LOW); // turn off light
}
//For toggle the LED for certain length of time use the delay()
//call delay(UNIT) to pause execution of UNIT milliseconds
//long unit *3 , short = unit
void displayMorseCode(byte* msg, int len) {
// TODO :Interpret the message toggle LED on and off to display the
morse code
if (msg[0] == 1)
digitalWrite(LED_PIN,HIGH);
else
digitalWrite(LED_PIN,LOW);
}
The message consists of the following values, which have been defined as constants:
SHORT:a dot in morse
LONG:a dash morse
LETTER: the end of a letter in morse
WORD: the end of a word in morse
STOP: the end of the morse
ex: message"SOS" encoded as (SHORT,SHORT,SHORT,LETTER,LONG,LONG,LONG,LETTER,SHORT,SHORT,SHORT,LETTER,WORD,STOP)
How to implementing displayMorseCode this function?

//For toggle the LED for certain length of time use the delay()
//call delay(UNIT) to pause execution of UNIT milliseconds
//long unit *3 , short = unit
void displayMorseCode(byte* msg, int len) {
int delayT = 0;
int unit = 300;
// TODO :Interpret the message toggle LED on and off to display the
morse code
for (int i = 0 ; i< len; i++)
{
if (msg[i] == 1) {
digitalWrite(LED_PIN,HIGH);
delayT = 3*unit;
}
else {
digitalWrite(LED_PIN,LOW);
delayT = unit;
}
delay(delayT);
}
This is a very simple answer, that will change the duration depending on the byte received. Now you must create a dictionary for each byte, so that depending on the byte (i.e. S = short,short,short) you create the write output, in the same way I showed you, but you should change digitalWrite() with the new function, that will create each letter's morse code. So the if condition would be for each letter (i.e. if (msg[i] == 83) - the S in decimal ASCII-)

Related

how to read char array from serial monitor and command arduino accordingly?

currently, I am working on a project to read char inputs from serial monitor and command Arduino to switch on/off specific pins. The problem I am facing is, I am unable to read the complete char array entered in the serial monitor. can anyone tell me what am I doing wrong?
#define X 13 //led pin
char txt[15];
int i;
int Status=0;
void setup() { // put your setup code here, to run once:
pinMode(X,OUTPUT);// setting the pin flow of control as output
Serial.begin(9600);
while(!Serial)
{
; //to wait for pc to connect
}
Serial.println("\nHome Automation");
dashprint();
}
void loop() { // put your main code here, to run repeatedly:
if(Serial.available()>0)
{ i=0;
while(Serial.available()>0) //if serial available
{ char inchar=Serial.read();
txt[i]=inchar; // add char to txt string
i++;// increment to where to write next
txt[i]='\0'; //null termination
}
Serial.print(txt);
check();
}
}
void dashprint() //to print dashes
{
Serial.println("-----------------------------------------------");
Serial.println("give me some command"); //ask for command
}
void check()
{ if(strncmp(txt,"ON",2)==0)
{
digitalWrite(X,HIGH);
Status=1;
}
else if(strncmp(txt,"OFF",3)==0)
{ digitalWrite(X,LOW);
Status=0;
}
else if(txt=="STATUS")
{
}
else Serial.println("ERROR");
}
output:
Home Automation
give me some command
OERROR
NERROR
ERROR
expected output:
Home Automation
give me some command
ON
Your arduino is too fast to read the text "ON" in one round.
9600 is 1 ms per character.
A simple workaround is, to add a little delay
if(Serial.available()>0) {
delay(3); // wait for the whole message
i=0;
while(Serial.available()>0) {
...
ADD:
Additionally, you obviously receive a '\n' (newline) character. Make sure it's not causing troubles.
And increase the delay or have a better approach in general, if you expect more than 3 characters ( "STATUS" )
struct MYObject {char a[256];};
//structure works well with EEPROM put and get functions.
//also lets to input large strings, more then 64 bytes, as http
void setup() {
MYObject str ={" "};
Serial.begin(115200);
while (!Serial.available()) delay (10); //wait for string
int i = 0;
int k= Serial.available();
while (k > 0){
char inchar = Serial.read(); //read one by one character
str.a[i] = inchar;
i++;
if (k < 3) delay (10); //it gives possibility to collect more characters on stream
k = Serial.available();
}
str.a[i]='\0'; //null terminator
//now lets see result
Serial.println(str.a);
//.....
}

How to stop multiple reads of an RFID card

I'm using an 125Khz RFID module RDM6300 with arduino nano.
While the card is near the RFID reader the loop will read the card multiple times. I want it to read only once while the card is near the reader then read it again if a new connection is being made.
*This code is not writen by me, this is the source:
https://github.com/Wookai/arduino-rfid
// define constants for pins
//int SUCCESS = 10;
//int ERROR = 13;
// variables to keep state
int readVal = 0; // individual character read from serial
unsigned int readData[10]; // data read from serial
int counter = -1; // counter to keep position in the buffer
char tagId[11]; // final tag ID converted to a string
char* authorizedTags[4]; // array to hold the list of authorized tags
// fills the list of authorzied tags
void initAuthorizedTags() {
// add your own tag IDs here
authorizedTags[0] = "0400680B85";
authorizedTags[1] = "0400063EB9";
authorizedTags[2] = "040004F3F5";
authorizedTags[3] = "04006813AB";
}
void setup() {
Serial.begin(9600);
// pinMode(SUCCESS, OUTPUT);
//pinMode(ERROR, OUTPUT);
initAuthorizedTags();
}
// check if the tag ID we just read is any of the authorized tags
int checkTag() {
int i;
for (i = 0; i < 4; ++i) {
if (strcmp(authorizedTags[i], tagId) == 0) {
return 1;
}
}
return 0;
}
// convert the int values read from serial to ASCII chars
void parseTag() {
int i;
for (i = 0; i < 10; ++i) {
tagId[i] = readData[i];
}
tagId[10] = 0;
}
// once a whole tag is read, process it
void processTag() {
// convert id to a string
parseTag();
// print it
printTag();
// check if the tag is authorized
if (checkTag() == 1) {
tagSuccess(); // if so, perform an action (blink a led, open a door, etc...)
} else {
tagFailed(); // otherwise, inform user of failure
}
}
void printTag() {
Serial.print("Tag value: ");
Serial.println(tagId);
}
// perform an action when an authorized tag was read
void tagSuccess() {
Serial.println("Tag authorized.");
// here, we simply turn on the success LED for 2s
// digitalWrite(SUCCESS, HIGH);
//digitalWrite(ERROR, LOW);
// delay(2000);
}
// inform the user that the tag is not authorized
void tagFailed() {
Serial.println("Unauthorized access!");
//digitalWrite(SUCCESS, LOW);
// digitalWrite(ERROR, HIGH);
// delay(2000);
}
// this function clears the rest of data on the serial, to prevent multiple scans
void clearSerial() {
while (Serial.read() >= 0) {
; // do nothing
}
}
void loop() {
// turn LEDs off
// digitalWrite(SUCCESS, LOW);
// digitalWrite(ERROR, LOW);
if (Serial.available() > 0) {
// read the incoming byte:
readVal = Serial.read();
// a "2" signals the beginning of a tag
if (readVal == 2) {
counter = 0; // start reading
}
// a "3" signals the end of a tag
else if (readVal == 3) {
// process the tag we just read
processTag();
// clear serial to prevent multiple reads
clearSerial();
// reset reading state
counter = -1;
}
// if we are in the middle of reading a tag
else if (counter >= 0) {
// save valuee
readData[counter] = readVal;
// increment counter
++counter;
}
}
}
Thank you.
Thank you for your answers. I tried to accept the multiple reads and print only one but it keeps printing "already read" instead of reading the card first time, this is the code:
void printTag() {
if(strcmp(tagId,previous)==1){
strcpy(previous, tagId);
Serial.print("Tag value: ");
Serial.println(tagId);
}
else
{
Serial.print("already read");
}
}
I also tried to put the delay after end of tag but it still reads the card multiple times.
I tried another code, it still reads the tag multiple times.
#include <SoftwareSerial.h>
// RFID | Nano
// Pin 1 | D2
// Pin 2 | D3
SoftwareSerial Rfid = SoftwareSerial(2,3);
int timer=0;
int reference = 1000;
int card_status = 0;
void setup() {
// Serial Monitor to see results on the computer
Serial.begin(9600);
// Communication to the RFID reader
Rfid.begin(9600);
}
void read() {
// check, if any data is available
// as long as there is data available...
while(Rfid.available() > 0 ){
// read a byte
int r = Rfid.read();
// print it to the serial monitor
Serial.print(r, DEC);
Serial.print(" ");
}
// linebreak
Serial.println();
timer=0;
}
void loop()
{
if((Rfid.available() > 0 ) && (card_status == 0) )
{
read();
}
if((!Rfid.available() > 0 ) && (card_status == 1) )
{
card_status=0;
}
}
I'm sorry for the late response. I forgot about this topic.
I solved the problem by making the arduino wait for a response after writing the RFID code for the frist time.
I was able to do that because my arduino was sending the code to a C# application via serial port.
Here is how it works: the arduino prints the RFID code on the serial, from there it is picked up by the C# application which searches a database to see if the code is stored there. Depending on the result, the application prints a character('y' or 'n') which is picked up by the arduino. Depending on the character recieved, the arduino lights up a led ( green or red) and makes a noise. Now a new RFID reading can be made.
Here is the code:
#include <SoftwareSerial.h>
#include "RDM6300.h"
SoftwareSerial rdm_serial(8, 9);
RDM6300<SoftwareSerial> rdm(&rdm_serial);
String comanda;
char c="";
int led_verde = 2;
int led_rosu = 7;
int buzzer = 12;
int i;
void buzz(int n = 1)
{
for (int i = 0; i < n; i++) {
digitalWrite(buzzer, LOW);
delay(200);
digitalWrite(buzzer, HIGH);
delay(200);
}
}
void ledVerde()
{
digitalWrite(led_verde, HIGH);
buzz(1);
delay(1000);
digitalWrite(led_verde, LOW);
}
void ledRosu()
{
digitalWrite(led_rosu, HIGH);
buzz(3);
delay(1000);
digitalWrite(led_rosu, LOW);
}
void setup()
{
pinMode(led_verde, OUTPUT);
pinMode(led_rosu, OUTPUT);
pinMode(buzzer, OUTPUT);
digitalWrite(led_verde, LOW);
digitalWrite(led_rosu, LOW);
digitalWrite(buzzer, HIGH);
Serial.begin(9600);
}
void loop()
{
static unsigned long long last_id = 0;
last_id = rdm.read();
rdm.print_int64(last_id);
Serial.println();
rdm_serial.end();
Serial.flush();
while(!Serial.available());
c=Serial.read();
if(c=='y')
{
ledVerde();
c="";
}
if(c=='n')
{
ledRosu();
}
Serial.flush();
last_id="";
c="";
rdm_serial.begin(9600);
}
You can find the RDM6300 library here: https://github.com/arliones/RDM6300-Arduino
Long time passed the original question, but maybe my answer would be useful for future visitors.
The RDM6300 works by:
automatically reading the data, and then
your code transfers the read data to the buffer for further processing.
Imagine it as a Baggage carousel in the airport. There are multiple luggage (data) on the carousel (reader), and you pick them one by one (transferring to buffer).
So, the problem of multiple reads, is that you have got read data in the reader (luggage on the carousel), that your code is gradually transferring them to the buffer (picking the luggage up).
In our example, if you don't like to collect all luggage, you can ask someone to take some of them, before they reach to you.
The below code does this. While you have data in the reader (the card is near to the reader), it transfers data from reader to buffer and then zeros all of them in the buffer:
First, place this code before "void setup()":
boolean multipleRead = false;
This defines a false/true variable to tell if this is the first time you are reading the tag (false), or it's being read multiple times (true).
Then, put this one at the end of the code block that shows the tag is fully read. If you are using Michael Schoeffler's library for your RDM6300/630 RFID, put it after "else if (ssvalue == 3) {":
multipleRead = true;
It change the variable to true, when your tag is read. That tells the program that your first read is done and the next upcoming read(s) would be "multiple read" and you don't want them.
Then put this at the end of the RFID reader code (if your RFID code is under void loop (), put the below code just after "void loop (){":
if (multipleRead) {
while (ssrfid.available() > 0) {
int ssvalue = ssrfid.read(); // read
if (ssvalue == -1) { // no data was read
break;
}
}
for (int x = 0; x < 14; x++)
{
buffer[x] = 0;
}
multipleRead = false;
}
It empties the reader and then zeros the buffer, while there is a card nearby. When you move the card away, multipleRead value would turn to false, which let another RFID reading loop to initiate.
Hope that helped :)
I guess what you want is a edge trigger instead of level trigger with time limit.
For example, you may prefer to read a RFID card when it firstly comes near to the antenna, once only; when it keeps to contact the antenna, still take no more actions. When you remove the card and place it again near to the antenna, the MCU starts to read the card again.
If so, the following code could be for your reference. What I have done is just to add 1 more flag to keep checking the card_status before checking if a RFID card comes near to the antenna.
int card_status = 0; //0:readable; 1:not-readable
if ( (Serial.available() > 0) && (card_status == 0) ) {
card_status = 1; //disable to read card after exit this loop
//your code, a card is near to the antenna, try to read it.
readVal = Serial.read();
if (readVal == 2) {
counter = 0; // start reading
} else if (readVal == 3) {
processTag();
clearSerial();
counter = -1;
} else if (counter >= 0) {
readData[counter] = readVal;
++counter;
}
}
reset the card status when no RFID signal comes in && card status is true,
if ( (!(Serial.available() > 0)) && (card_status == 1) ) {
card_status = 0; //enable to read card again
//no signal, no card is near to the antenna.
}
You can set a delay (e.g. delay(2000)) after reading the (end of tag). A delay of (say) 2 seconds will allow the user to move the card far enough away from the reader. Note that delay is a blocking command which might not suit your purposes, in which case you could be looking at using the millis count to activate/deactivate the Serial.read.
Another option is to accept the multiple reads, but keep a state of which card has been read. If the new card number is the same as the old card number (within a reasonable timeframe) then just ignore.

iMac Apple remote ir decoding

I am trying to modify an Arduino sketch to use an old Apple remote IR transmitter. It works, and I have a list of the HEX codes for the various buttons. What is confusing me is that the sketch won't compile with the HEX codes included, but will do so if I convert them to DEC equivalent. And, the Serial outputs as defined in sketch lines 102 to 126 work, but the LEDs do not seem to perform as suggested. I don't know if it is tied to the HEX/DEC issue, or where to look. The code, as it now stands, is below. It includes comments referring to the remote's frequency , which I have not addressed. Thanks for helping me to understand this.
/*
This sketch uses Ken Shirriff's *awesome* IRremote library:
https://github.com/shirriff/Arduino-IRremote
Hardware setup:
* The output of an IR Receiver Diode (38 kHz demodulating
version) should be connected to the Arduino's pin 11.
* The IR Receiver diode should also be powered off the
Arduino's 5V and GND rails.
* A common cathode RGB LED is connected to Arduino's pins
5, 9, and 6 (red, green, and blue pins).
*/
#include <IRremote.h> // Include the IRremote library
/* Setup constants for SparkFun's IR Remote: */
#define NUM_BUTTONS 6 // The remote has 6 buttons
/* Define the IR remote button codes. We're only using the
least signinficant two bytes of these codes. Each one
should actually have 0x10EF in front of it. Find these codes
by running the IRrecvDump example sketch included with
the IRremote library.*/
const uint16_t BUTTON_PLUS = 2011254893; // i.e. 0x10EFD827
const uint16_t BUTTON_MINUS = 2011246701;
const uint16_t BUTTON_LEFT = 2011271277;
const uint16_t BUTTON_RIGHT = 2011258989;
const uint16_t BUTTON_MENU = 2011283565;
const uint16_t BUTTON_STARTSTOP = 2011275373;
//const uint16_t BUTTON_LEFT = 0x10EF;
//const uint16_t BUTTON_RIGHT = 0x807F;
//const uint16_t BUTTON_CIRCLE = 0x20DF;
/* Connect the output of the IR receiver diode to pin 11. */
int RECV_PIN = 11;
/* Initialize the irrecv part of the IRremote library */
IRrecv irrecv(RECV_PIN);
decode_results results; // This will store our IR received codes
uint16_t lastCode = 0; // This keeps track of the last code RX'd
/* Setup RGB LED pins: */
enum ledOrder // Make an enum to add some clarity in the code
{
RED, // 0
GREEN, // 1
BLUE // 2
};
const int rgbPins[3] = {5, 9, 6}; // Red, green, blue pins respectively
byte rgbValues[3] = {55, 23, 200}; // This keeps track of channel brightness
byte activeChannel = RED; // Start with RED as the active channel
boolean ledEnable = 1; // Start with the LED on.
void setup()
{
Serial.begin(9600); // Use serial to debug.
irrecv.enableIRIn(); // Start the receiver
/* Set up the RGB LED pins: */
for (int i=0; i<3; i++)
{
pinMode(rgbPins[i], OUTPUT);
analogWrite(rgbPins[i], rgbValues[i]);
}
}
// loop() constantly checks for any received IR codes. At the
// end it updates the RGB LED.
void loop()
{
if (irrecv.decode(&results))
{
/* read the RX'd IR into a 16-bit variable: */
uint16_t resultCode = (results.value & 65535); //0xFFFF
/* The remote will continue to spit out 0xFFFFFFFF if a
button is held down. If we get 0xFFFFFFF, let's just
assume the previously pressed button is being held down */
if (resultCode == 65535) //0xFFFF
resultCode = lastCode;
else
lastCode = resultCode;
// This switch statement checks the received IR code against
// all of the known codes. Each button press produces a
// serial output, and has an effect on the LED output.
switch (resultCode)
{
case BUTTON_PLUS:
Serial.println("+");
if (ledEnable) ledEnable = 0;
else ledEnable = 1; // Flip ledEnable
break;
case BUTTON_MINUS:
Serial.println("-");
activeChannel = RED;
break;
case BUTTON_LEFT:
Serial.println("<-");
activeChannel = GREEN;
break;
case BUTTON_RIGHT:
Serial.println("->");
activeChannel = BLUE;
break;
case BUTTON_MENU:
Serial.println("Menu");
rgbValues[activeChannel]++; // Increment brightness
break;
case BUTTON_STARTSTOP:
Serial.println("-> =");
rgbValues[activeChannel]--; // Decrement brightness
break;
// case BUTTON_LEFT:
// Serial.println("Left");
// rgbValues[activeChannel] = 0; // Min brightness (off)
// break;
// case BUTTON_RIGHT:
// Serial.println("Right");
// rgbValues[activeChannel] = 255; // Max brightness
// break;
// case BUTTON_CIRCLE:
// Serial.println("Circle");
// rgbValues[activeChannel] = 127; // Medium brightness
// break;
default:
Serial.print("Unrecognized code received: 0x");
Serial.println(results.value, HEX);
break;
}
irrecv.resume(); // Receive the next value
}
// Every time through the loop, update the RGB LEDs:
if (ledEnable)
{
for (int i=0; i<3; i++)
{
analogWrite(rgbPins[i], rgbValues[i]);
}
}
else
{
for (int i=0; i<3; i++)
{
analogWrite(rgbPins[i], 0);
}
}
}
If you say your code does not compile if you use hex notation for those numbers it would help to provide the actual code that does not compile, because the code you posted here compiles even if I enter hex numbers instead of decimals.
As gre_gor already pointed out in his comment you also have a problem with your values.
const uint16_t BUTTON_PLUS = 2011254893;
Here you're trying to store 2011254893 in a 16bit unsigned integer.
If all 16 bits are 1 you end up with 2^16 -1 which is 65535.
So that is the maximum number you can store in a variable of type uint16_t.
If you assign larger values to that variable you will cause a so called integer overflow. The actual value stored in your variable will be 2011244893 modulus 65536, which is 20589. That's not the value you were supposed to assign.
If you read the comments in that code carefully:
Define the IR remote button codes. We're only using the least
signinficant two bytes of these codes. Each one should actually
have 0x10EF in front of it.
Also read this on integer overflow and I guess it wouldn't hurt if you make your self familiar with data types in general.
https://en.wikipedia.org/wiki/Integer_overflow
http://www.cplusplus.com/articles/DE18T05o/

Arduino readString(); code runs slow

I have the following code which I need to execute quickly, yet its taking a lot of time to change the value, anyway over way of making this task quicker?
I am using indexOf() and substring() to accomplish this task.
This is for changing the strip LED colors.
// declare LED Series A Pins R-G-B (PWM Pins)
int const AledRedPin = 6;
int const AledGreenPin = 5;
int const AledBluePin = 3;
// declare LED Series B Pins R-G-B (PWM Pins)
int const BledRedPin = 10;
int const BledGreenPin = 11;
int const BledBluePin = 9;
// serial input variable & string
// initialise LED Series A Pins R-G-B (PWN Value: 0 to 255)
// initial value = 255
int AledRed = 255;
int AledGreen = 255;
int AledBlue = 255;
// initialise LED Series A Pins R-G-B (PWN Value: 0 to 255)
// initial value = 255
int BledRed = 255;
int BledGreen = 255;
int BledBlue = 255;
//serial input
String Command = "";
//string manipulation
int cmdindexval = 0;
String CommandType = "";
int CommandValue = 0;
String Series = "";
void setup() {
// put your setup code here, to run once:
// start serial
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB
}
// set LED Series A Pins as Output R-G-B
pinMode(AledRedPin, OUTPUT);
pinMode(AledGreenPin, OUTPUT);
pinMode(AledBluePin, OUTPUT);
// set LED Series B Pins as Output R-G-B
pinMode(BledRedPin, OUTPUT);
pinMode(BledGreenPin, OUTPUT);
pinMode(BledBluePin, OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
// read from serial if it's available
if (Serial.available() > 0) {
Command = Serial.readString(); //read string from serial monitor
cmdindexval = Command.indexOf('='); //read characters until '=' then assign the value
CommandType = Command.substring(0, cmdindexval); //assign the value from 0 to cmdindexval
//Series = Command.substring(0, 1); //read first character
CommandValue = Command.substring(cmdindexval + 1).toInt(); //assign the value after '=' and convert string to Int
Serial.println(CommandType + " ,is equal to " + CommandValue + " ,Series: " + Series);
//if (Series == "A") {
if (CommandType == "ACledRed"){
AledRed = CommandValue;
}
else if (CommandType == "ACledGreen"){
AledGreen = CommandValue;
}
else if (CommandType == "ACledRedBlue") {
AledBlue = CommandValue;
}
//}
//else if (Series == "B") {
if (CommandType == "BCledRed") {
BledRed = CommandValue;
}
else if (CommandType == "BCledGreen") {
BledGreen = CommandValue;
}
else if (CommandType == "BCledBlue") {
BledBlue = CommandValue;
}
//}
} //end serial
analogWrite(AledRedPin, AledRed);
analogWrite(AledGreenPin, AledGreen);
analogWrite(AledBluePin, AledBlue);
analogWrite(BledRedPin, BledRed);
analogWrite(BledGreenPin, BledGreen);
analogWrite(BledBluePin, BledBlue);
}
From the Arduino docs on readString:
Serial.readString() reads characters from the serial buffer into a string. The function terminates if it times out (see setTimeout()).
and the docs on setTimeout:
Serial.setTimeout() sets the maximum milliseconds to wait for serial data when using Serial.readBytesUntil(), Serial.readBytes(), Serial.parseInt() or Serial.parseFloat(). It defaults to 1000 milliseconds.
This means that the readString is always waiting 1 sec to make sure that the sending of the string is finished and has the complete string.
Unfortunately that means it's slow to respond. You could lower the timeout with the setTimeout, but you would still have some delay, or if you set it too low you could potentially get incomplete stings.
The best solution would be to use readStringUntil, so you know you have a complete string when you get a terminator character (like a newline).
Replace
Command = Serial.readString();
with
Command = Serial.readStringUntil('\n');
and make sure you set the Serial monitor so send the newline character.
Edit: see important update at the end.
This can be made significantly faster, but first let's have a look at the work that has to be done in every loop iteration with the current code:
As #gre_gor already explained, you could be losing some time in readString().
for each value, between 15 and 20 bytes have to be sent, read, parsed and converted to int.
for each received value (R, G or B), analogWrite() is called 6 times (and analogWrite() isn't really fast). This means that in order to change the two series, analogWrite() is called 36 times (and this is probably where most time is lost). And if no serial data is available, analogWrite() is still called 6 times.
and also, Serial.println() is called each time in the example - so it would be best to turn this off.
To speed this up, the RGB values could be sent in a small buffer (assuming you have control over the sending side as well), and read with Serial.readBytesUntil().
If the values for both A and B are sent together, the 6 RGB values can be sent as 6 bytes:
byte rcvBuffer[7];
void loop() {
if (Serial.available() > 0) {
// message: RGBRGBx - but see update below
int numRead = Serial.readBytesUntil(0x78, rcvBuffer, 7); // 0x78 is 'x'
if (numRead == 7) { // or 6, see below
analogWrite(AledRedPin, rcvBuffer[0]);
analogWrite(AledGreenPin, rcvBuffer[1]);
analogWrite(AledBluePin, rcvBuffer[2]);
analogWrite(BledRedPin, rcvBuffer[3]);
analogWrite(BledGreenPin, rcvBuffer[4]);
analogWrite(BledBluePin, rcvBuffer[5]);
}
// else ignore this read - could be a first unaligned read
}
}
If only the values for A or B are sent together:
byte rcvBuffer[5];
void loop() {
// You could probably even remove the Serial.available() check
if (Serial.available() > 0) {
// message: TRGBx where T is Type ('A' or 'B')
int numRead = Serial.readBytesUntil(0x78, rcvBuffer, 5); // 0x78 is 'x'
if (numRead == 5) { // or 4, see below
switch (rcvBuffer[0]) {
case 'A':
analogWrite(AledRedPin, rcvBuffer[1]);
analogWrite(AledGreenPin, rcvBuffer[2]);
analogWrite(AledBluePin, rcvBuffer[3]);
break;
case 'B':
analogWrite(BledRedPin, rcvBuffer[1]);
analogWrite(BledGreenPin, rcvBuffer[2]);
analogWrite(BledBluePin, rcvBuffer[3]);
break;
default :
// do nothing, or send error message
}
}
}
}
I used 'x' as the stop byte to make it visible, but you could as well use a zero byte.
Now, I'm not really sure if readBytesUntil() also reads the terminating byte into the buffer or skips it, and can't test this right now. But I would think only the RGB values are read into the buffer. In this case you'll have to change those values to the ones I put in the comments.
To save even more time, you could check each value and only call analogWrite() if that value did change since the last call (for each R, G and B).
Update: Obviously we can't just use 'x' or a zero byte as the stop byte, because each of the RGB values could also be an 'x' or zero byte (it's getting late here :). And while ReadBytes() could be used instead, it's better to have a stop byte to keep the buffers aligned. So I would suggest to use 0xff (255) as the stop byte and make sure none of the RGB values can be 0xff.
And just in case there could be other message types in the future, each message could also be prepended with a message code (1 or 2 bytes).
I always use readBytesUntil()whenever I use the serial port for communication.
It gets the job done, it always gets the entire string, but the same problem as readString()takes at least 1000ms to complete.
Using both Serial.setTimeout() and Serial.readBytesUntil() worked fine for me, by reducing the delay.
Something like:
Serial.setTimeout(250);
inData = Serial.readStringUntil('\n');

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