Notifications
Clear all

Converting Serial Data into PWM

10 Posts
4 Users
3 Likes
7,893 Views
(@garnold)
Member
Joined: 5 years ago
Posts: 81
Topic starter  

I'm having a really hard time taking the information from the serial.read function and turning it into something that I can use to dim an LED.

Here's the story, I just finished watching this video on how to control an LED via BT and it worked perfect.

After I was done I thought I would be a smart a..... and change the code to allow me to dim the LED. Wow did I fall hard. 

I'm using this tool for my controlling app on my phone that will send 0 - 255 via serial.

https://play.google.com/store/apps/details?id=com.giumig.apps.bluetoothserialmonitor&hl=en_US&rdid=com.giumig.apps.bluetoothserialmonitor

So the final goal is to be able to move the slider and have it change the brightness of the LED. I did do some debugging and see that in the serial monitor when I send in 255 I get 50 53 53 10. After more testing I can see that I always get a 10 so I'm guessing that is a line break? Well, I'm actually not guessing that because i did more testing and see that it is the line break.

So what is the 50 53 53? How do I covert that to a number I can use in an anolog.write statement?

 

Thank you all!


   
Quote
(@garnold)
Member
Joined: 5 years ago
Posts: 81
Topic starter  

After more digging I found some code to help me with this. Below is my sketch. I ended up not using the voltage divider since I changed over to a Wemos D1 Mini which is a 3.3v system. I think that is cool correct?

 

#include <SoftwareSerial.h>
SoftwareSerial BTserial(D2, D3); // RX | TX
// Connect the HC-05 TX to Wemos D1 Mini pin 2 RX.
// Connect the HC-05 RX to Wemos D1 Mini pin 3 TX through a voltage divider.
// Did not use the voltage divider because Wemos D1 Mini is 3.3v system
#define ledPin D1

String inString = "";

void setup() {
// put your setup code here, to run once:
pinMode(ledPin, OUTPUT);
BTserial.begin(9600); // Default communication rate of the Bluetooth module
}

void loop() {
// put your main code here, to run repeatedly:
// Read serial input:
while (BTserial.available() > 0) {
int inChar = BTserial.read();
if (isDigit(inChar)) {
// convert the incoming byte to a char and add it to the string:
inString += (char)inChar;
}
// if you get a newline, print the string, then the string's value:
if (inChar == '\n') {
BTserial.print("Value:");
BTserial.println(inString.toInt());
BTserial.print("String: ");
BTserial.println(inString);
analogWrite(ledPin,inString.toInt());
// clear the string for new input:
inString = "";
}
}
}


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
 

I am not exactly sure what you are trying to achieve but wouldn't something like this be enough

if(Serial.available() > 0){
int mVal = Serial.parseInt();
if(mVal  < 256){
analogWrite(ledPin, mVal);
}
}

This would certainly work on an Arduino!

 

 


   
ReplyQuote
(@garnold)
Member
Joined: 5 years ago
Posts: 81
Topic starter  

@pugwash

All give it a shot! I'm just playing and learning right now. I wanted to see if I could dim an LED from data pulled in from the serial port. Thank you


   
ReplyQuote
Mandy
(@amanda)
Member
Joined: 5 years ago
Posts: 74
 
Posted by: @garnold

So what is the 50 53 53? How do I covert that to a number I can use in an anolog.write statement?

These are characters, according to the ascii table:

char(50) = "2"

char(53) = "5"

char(10) = LineFeed

So 50,53,53,10 equates to the text string "255\n"

Just add the .toInt() to the end of the string to get the value as an integer:

int analogAnswer = theString.toInt();

Does that help?

This post was modified 5 years ago by Mandy

The 600 series had rubber skin. We spotted them easy, but these are new. They look human... sweat, bad breath, everything. Very hard to spot.


   
garnold and Robo Pi reacted
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
 

I assume that if you are reading in from Serial input character by character, and then checking that the character is a digit, then this is some form of error checking.

The way you have coded this is unfortunately wrong. What your code is actually doing, is just filtering out any non-digits. It is not reacting to input errors.

For example: If you enter "1a3", you will get 13 as the result because you are just skipping the "a" and the program is not returning any error.

Furthermore, if you are only using single digit integers, the simplest conversion from char to int is:

int mVal = int(char(50)) - 48; // returns 2 as an integer

This saves adding .toInt() which saves space in the compiled code.


   
ReplyQuote
(@pugwash)
Sorcerers' Apprentice
Joined: 5 years ago
Posts: 923
 

Finally, this is how I would code the Arduino sketch to handle PWM, for testing, if I was going to change later from the Serial monitor to BlueTooth, as no error checking would be required if the values are controlled by a slider. It should be noted that the Arduino cannot handle runtime errors.

 

//sets digital pin 3 to pulse width value

const int outPin = 3;

void setup() {

Serial.begin(9600);
pinMode(outPin, OUTPUT);
Serial.println("Input required pulse width as percentage!");

}

void loop() {

int mVal; // holds the PWM value as percent

if(Serial.available() > 0){
mVal = Serial.parseInt();
if(mVal < 101){
int tVal = (mVal*255)/100;
analogWrite(outPin, tVal);
}
Serial.print("pulse width = "); Serial.print(mVal); Serial.println("%");
}
}

 

One thing I would do is get a BlueTooth smartphone app with a slider control that I could set up for the range 0 to 100%, for pulse width as a percentage.


   
garnold reacted
ReplyQuote
(@garnold)
Member
Joined: 5 years ago
Posts: 81
Topic starter  

@pugwash

Thank you very much!

You are correct and I'm controlling the Arduino via BT. I did snag a few apps to handle sending in the serial information. 

Here is a link to one of the apps with a slider in it. The odd thing is that the slider is not working? I can use this app in serial mode that allows me to just type in stuff which controls the LED just fine. I'm not sure what's up with that so I'll have to do some testing on what the slider is sending.

 

https://play.google.com/store/apps/details?id=com.giumig.apps.bluetoothserialmonitor


   
ReplyQuote
(@mjwhite)
Member
Joined: 5 years ago
Posts: 34
 

@pugwash

Another way of converting from char to int would be:

int mVal = char(50) - '0';

where the char

 '0'

equals 48 in ascii.   Although it's not as readable as your solution.


   
ReplyQuote
Mandy
(@amanda)
Member
Joined: 5 years ago
Posts: 74
 
Posted by: @pugwash

Furthermore, if you are only using single digit integers, the simplest conversion from char to int is:

int mVal = int(char(50)) - 48; // returns 2 as an integer

This saves adding .toInt() which saves space in the compiled code.

It's not single digit integers it's a char array so you will have to loop through the array and then convert all the numerics via base 10 :

int pugwash(string value) {
for (int n = 1; n > stringLength: n++) {
if ((value[n] <= 48) & (value[n] >= 58)) {
int mVal[n] = int(value[n]) - 48;
} else {
mVal[n] = 0;
}
return (mVal[0] * 100) + ( mVal[1] * 10) + mVal[3];
}

Or you could just do:
int answer = value.toInt();

 

 

This post was modified 5 years ago by Mandy

The 600 series had rubber skin. We spotted them easy, but these are new. They look human... sweat, bad breath, everything. Very hard to spot.


   
ReplyQuote