Send over infrared on Arduino - arduino

I need to transmit an infrared signal using the Arduino to run a Samsung TV.
I tried the following code:
// Lucas Eckels
// Http://lucaseckels.com
// IR remote control emitter for NEC protocol remote, as described at
// Http://www.sbprojects.com/knowledge/ir/nec.htm
// Tested on a Samsung LCD TV.
#include <util/delay.h>
#define IR_PIN 13
// With CONTINOUS defined, the first command is repeated continuously until
// You reset the Arduino. Otherwise, it sends the code once, then waits for
// Another command.
#define CONTINUOUS
// Times are in microseconds
#define ON_START_TIME 4500
#define OFF_START_TIME 4500
#define ON_TIME 580
#define OFF_TIME_ONE 1670
#define OFF_TIME_ZERO 540
#define DEVICE_1 7
#define DEVICE_2 7
void setup() {
pinMode (IR_PIN, OUTPUT);
digitalWrite(IR_PIN, LOW);
Serial.begin(9600);
delay(1000);
Serial.write("Starting up..\n");
}
byte command = 0;
int commandCount = 0;
bool commandReady = false;
void loop() {
if (commandReady) {
Serial.print("Writing command");
Serial.print(command, DEC);
Serial.print("\n");
writeStart();
// Writing device code
writeByte(DEVICE_1);
writeByte(DEVICE_2);
// Writing command code
writeByte(command);
writeByte(~command);
writeEnd();
delay(100);
#ifndef CONTINUOUS
commandReady = false;
command = 0;
commandCount = 0;
#endif
return;
}
if (Serial.available () > 0) {
// Read in a 3-digit decimal command code.
byte incoming = Serial.read();
if (incoming <= '9 ' || incoming >= '0') {
command *= 10;
command += incoming - '0 ';
++commandCount;
}
if (commandCount == 3) {
commandReady = true;
}
}
}
void writeStart() {
modulate(ON_START_TIME);
delayMicroseconds(OFF_START_TIME);
}
void writeEnd() {
modulate(ON_TIME);
}
void writeByte(byte val) {
// Starting with the LSB, write out the
for (int i = 0x01; i & 0xFF; i <<= 1) {
modulate(ON_TIME);
if (val & i) {
delayMicroseconds (OFF_TIME_ONE);
} else {
delayMicroseconds (OFF_TIME_ZERO);
}
}
}
void modulate(int time) {
int count = time / 26;
byte portb = PORTB;
byte portbHigh = portb | 0x20; // Pin 13 is controlled by 0x20 on PORTB.
byte portbLow = portb & ~0x20;
for (int i = 0; i <= count; i++) {
// The ideal version of this loop would be:
// DigitalWrite(IR_PIN, HIGH);
// DelayMicroseconds(13);
// DigitalWrite(IR_PIN, LOW);
// DelayMicroseconds(13);
// But I had a hard time getting the timing to work right. This approach was found
// Through experimentation.
PORTB = portbHigh;
_delay_loop_1(64);
PORTB = portbLow;
_delay_loop_1(64);
}
PORTB = portb;
}
The code compiles but is not working for me.

I wrote this to control an LG TV and Sony Amplifier. You would just need to save your own raw codes to the header file and off you go:
https://github.com/gotnull/SiriProxy-TV-Control/blob/master/arduino-remote/Remote/Remote.pde
// This procedure sends a 38KHz pulse to the IRledPin
// for a certain # of microseconds. We'll use this whenever we need to send codes
void pulseIR(long microsecs) {
// we'll count down from the number of microseconds we are told to wait
cli(); // this turns off any background interrupts
while (microsecs > 0) {
// 38 kHz is about 13 microseconds high and 13 microseconds low
digitalWrite(IRledPin, HIGH); // this takes about 3 microseconds to happen
delayMicroseconds(10); // hang out for 10 microseconds
digitalWrite(IRledPin, LOW); // this also takes about 3 microseconds
delayMicroseconds(10); // hang out for 10 microseconds
// so 26 microseconds altogether
microsecs -= 26;
}
sei(); // this turns them back on
}
I'd also recommend taking a read through Ladyada's wonderful tutorial:
Sensor tutorials - IR remote receiver/decoder tutorial

DelayMicroseconds is fairly accurate, and will be precise enough for your task. However you are right in staying away from DigitalWrite. It takes about 50 times as many clock-cycles to complete compared to direct port assignment (PORTB=... ) which takes exactly one. You will only be able to time a 38MHz pulse that way. I don't know what your _delay_loop_1 does, but everything else seems okay. (aside from the "i + +" but that's a cut'n'paste typo I guess)
Have you checked that it actually lights up? a phone or cheap digicam will actually show you the IR on the screen.

Related

Arduino send bad signal to interrupt pin

I have connected coin hopper and coin acceptor to one arduino uno, coin acceptor connected to pin 2, coin hopper to pin 3 - sensor and pin 7 - relay. When coin hopper switch relay, it is executing coininterrupt
for coin hopper I am using this script link
coin acceptor script: link
I need this 2 scripts working on 1 arduino
my code:
#define SENSOR 3
#define RELAY 7
#define ACCEPTOR 2
volatile boolean insert = false;
int pulse=0,count;
char sen;
int temp=0;
unsigned long int timer;
void setup()
{
Serial.begin(9600);
pinMode(SENSOR,INPUT_PULLUP);
pinMode(RELAY,OUTPUT);
sen=digitalRead(SENSOR);
digitalWrite(RELAY, HIGH);
attachInterrupt(digitalPinToInterrupt(ACCEPTOR), coinInterrupt, RISING);
}
void loop()
{
if (insert) {
insert = false;
Serial.println("coin");
delay(1000);
}
if(Serial.available())
{
timer=millis();
// temp is amount to dispense send to arduino
temp=Serial.parseInt();
if(temp>0){
digitalWrite(RELAY,LOW);}
}
sen=(sen<<1)|digitalRead(SENSOR);
// if hopper sensor read drop coin
if(sen==1)
{
timer=millis();
pulse++;
sen&=0x03;
Serial.println("out 1");
//if dispensed coins equal with coins to dispense stop engine
if(pulse==temp)
{
digitalWrite(RELAY,HIGH);
pulse=0;
temp=0;
}
}
// if amount dispensed is not equal with amount to dispense and engine running, stop
if((digitalRead(RELAY)==LOW)&(millis()-timer>2000))
{
digitalWrite(RELAY,HIGH);
pulse=0;
temp=0;
}
}
void coinInterrupt() {
insert = true;
}
I was trying to change pins (arduino uno support interrupts on pin 2 and 3 only) but problem still appears so I guess there is issue in the code
your sketch does not run in this state :
first fix errors :
declare insert as volatile
remove cpulse (not used anywhere)
change 'if()' to (I suppose) 'if (insert) ....'
remove stuff with 'sen' var : simply use if(digitalRead(SENSOR)) or if(!digitalRead(SENSOR))
except if you need to store relay state.
use logical operators like || or && unless you really need bitwise operations
example of result sketch :
#define SENSOR 3
#define RELAY 7
volatile boolean insert = false;
byte amountToDispense = 0;
int pulse = 0;
int temp = 0;
unsigned long int timer;
void setup()
{
Serial.begin(9600);
pinMode(SENSOR, INPUT_PULLUP);
pinMode(RELAY, OUTPUT);
digitalWrite(RELAY, HIGH);
attachInterrupt(digitalPinToInterrupt(2), coinInterrupt, RISING);
}
void loop()
{
if (insert ) {
insert = false;
Serial.println("coin");
delay(1000);
}
if (Serial.available())
{
timer = millis();
temp = Serial.parseInt();
if (temp > 0) {
//amountToDispense = Serial.read() - 48;
digitalWrite(RELAY, LOW);
}
}
if (digitalRead(SENSOR))
{
timer = millis();
pulse++;
Serial.println("out 1");
if (pulse >= temp)
{
digitalWrite(RELAY, HIGH);
pulse = 0;
temp = 0;
}
}
if (!digitalRead(RELAY) && (millis() - timer > 2000))
{
digitalWrite(RELAY, HIGH);
pulse = 0;
temp = 0;
}
}
void coinInterrupt() {
insert = true;
}
What is this supposed to do?
sen=(sen<<1)|digitalRead(SENSOR);
You init sen with digitalRead(SENSOR);
Assuming that pin is LOW when you start the sketch and turns HIGH, sen will become 1.
Next you do sen &= 0x03 so sen is still 1.
Again sen=(sen<<1)|digitalRead(SENSOR); , sen will either be 2 or 3.
Next loop run sen=(sen<<1)|digitalRead(SENSOR); sen is now 4 or 6. and so on...
I don't have time to think about what you want to achieve but this is definitely a problem as you'll only enter if (sen == 1) once and never again.
If this is not sufficient you should probably improve your post as it is unclear what arduino sends bad signal to interrup pin is supposed to mean. That doesn't make sense. Explain the expected behaviour of your program and how it behaves instead. add more comments so it becomes clear what you intend to do with each block of code so we don't have to interpret

Stroboscope with Arduino

first sorry for my bad english
I'm a student and I want to make a Stroboscope with Arduino for my school project
The frequency is variable between 10hz to 3000 hz and it changes using a rotary encoder
that when normally rotate the encoder 1 step frequency \pm 1hz and when rotate encoder when it pushed down frequency \pm 100hz
and Arduino make a PWM signal on pin 13 and it connect to a high power npn transistor and it turn on and off a 10 watt led
I code it using Encoder.h library by Paul Stoffregen and tone() function
but I have a PROBLEM
I code this program and upload it to Arduino Uno but it doesn't work IDK where is the problem
#include <Encoder.h>
#define ENCODER_PULSES_PER_STEP 1
int f = 10;
int direction;
Encoder myEnc(2, 3);
int t = 0;
void setup() {
pinMode(13, OUTPUT);
pinMode(4, INPUT_PULLUP);
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
direction = myEnc.read();
}
void loop() {
if (abs(direction) >= ENCODER_PULSES_PER_STEP) {
if (direction > 0) {
if (digitalRead(4) == 1) {
f++;
if (f >> 2500)f = 2500;
}
else {
f = f + 100;
if (f >> 2500)f = 2500;
}
} else {
if (digitalRead(4) == 1) {
f--;
if (f << 10)f = 10;
}
else {
f = f - 100;
}
}
myEnc.write(0);
}
tone(13, f);
}
When your program starts the function setup is executed once.
Then in an infinite loop the function loop is executed.
As you have direction = myEnc.read(); only in setup you'll only read the encoder once.
From the Encoder library's documentation:
/* Encoder Library - TwoKnobs Example
* http://www.pjrc.com/teensy/td_libs_Encoder.html
*
* This example code is in the public domain.
*/
#include <Encoder.h>
// Change these pin numbers to the pins connected to your encoder.
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
Encoder knobLeft(5, 6);
Encoder knobRight(7, 8);
// avoid using pins with LEDs attached
void setup() {
Serial.begin(9600);
Serial.println("TwoKnobs Encoder Test:");
}
long positionLeft = -999;
long positionRight = -999;
void loop() {
long newLeft, newRight;
newLeft = knobLeft.read();
newRight = knobRight.read();
if (newLeft != positionLeft || newRight != positionRight) {
Serial.print("Left = ");
Serial.print(newLeft);
Serial.print(", Right = ");
Serial.print(newRight);
Serial.println();
positionLeft = newLeft;
positionRight = newRight;
}
// if a character is sent from the serial monitor,
// reset both back to zero.
if (Serial.available()) {
Serial.read();
Serial.println("Reset both knobs to zero");
knobLeft.write(0);
knobRight.write(0);
}
}
Notice the differences between your and their code.
Another more simple example from the GitHub repository to satisfy Juraj.
/* Encoder Library - Basic Example
* http://www.pjrc.com/teensy/td_libs_Encoder.html
*
* This example code is in the public domain.
*/
#include <Encoder.h>
// Change these two numbers to the pins connected to your encoder.
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
Encoder myEnc(5, 6);
// avoid using pins with LEDs attached
void setup() {
Serial.begin(9600);
Serial.println("Basic Encoder Test:");
}
long oldPosition = -999;
void loop() {
long newPosition = myEnc.read();
if (newPosition != oldPosition) {
oldPosition = newPosition;
Serial.println(newPosition);
}
}
Also note that << is the binary left shift operator, not the less than operator < !
In if (f << 10)f = 10; you'll shift f 10 bits to the left. As this results in a number > 0, which is true, this condition will alway be met.
Same for >> which is the bitwise right shift operator, not greater then!

I could not make IRsend from the IRremote library to work

Hello i am using an arduino mkr1000 so send and IR signal using the IRremote library for mkr1000 IRremote library. I am having problems with IRsend.
First i used the IRdump example to get the data from my remote button. When i finished this i tried the IRsend example but it seems to be not working.
I temporarily replaced with a ordinary LED to show if it is really blinking, but it is not. I have tested the both the ordinary LED and IR LED that they worked.
I also think that i have wired the LED correctly according to the example
PIN 3 -> LED -> Resistor -> Ground
My circuit was further confirmed correct when i upload a sketch that makes it blink.
Basically i am trying to send a NEC 32bit signal, 0x2FD807F
but i guess they were not able to finish the library of send for mkr1000???
in this post a comment was made with a code but did not really have any detail on how to use it.
here is where i am currently at
int IR_S = 3;
void setup()
{
pinMode(IR_S,OUTPUT);
}
void loop() {
IR_Sendcode(0x2FD807F);
delay(1000);
}
void IR_Send38KHZ(int x,int bit) //Generate 38KHZ IR pulse
{
for(int i=0;i<x;i++)//15=386US
{
if(bit==1)
{
digitalWrite(IR_S,1);
delayMicroseconds(9);
digitalWrite(IR_S,0);
delayMicroseconds(9);
}
else
{
digitalWrite(IR_S,0);
delayMicroseconds(20);
}
}
}
void IR_Sendcode(uint8_t data) // Send the data
{
for(int i=0;i<8;i++)
{
if((data&0x01)==0x01)
{
IR_Send38KHZ(23,1);
IR_Send38KHZ(64,0);
}
else
{
IR_Send38KHZ(23,1);
IR_Send38KHZ(21,0);
}
data=data>>1;
}
}
I while i was waiting for replies i created my own code. I have finished and tested it. It should theoretically work on any arduino.
/*
This is a code for NEC Infrared Transmission Protocol Transmitter
NEC specifications are
~ Carrier Frequency is 38kHz
* Logical '0' – a 562.5µs pulse burst followed by a 562.5µs space, with a total transmit time of 1.125ms
* Logical '1' – a 562.5µs pulse burst followed by a 1.6875ms space, with a total transmit time of 2.25ms
- a 9ms leading pulse burst (16 times the pulse burst length used for a logical data bit)
- a 4.5ms space
- the 8-bit address for the receiving device
- the 8-bit logical inverse of the address
- the 8-bit command
- the 8-bit logical inverse of the command
- a final 562.5µs pulse burst to signify the end of message transmission.
Example,
If the code recieved from the data dump from the IRremote library is 0x2FD807F
-0x02 is address
-0xFD is the inverse address
-0x80 is the command
-0x7F is the inverse command
THIS PROGRAM IS A BLOCKING PROGRAM
*/
#define IR 3
#define CarrierFreqInterval 11
void setup() {
pinMode(IR, OUTPUT);
digitalWrite(IR, LOW);
}
void loop() {
// unsigned long start = micros();
transmit(0x02FD807F);
// unsigned long ends = micros();
// unsigned long delta = ends - start;
// Serial.println(delta);
delay(500);
}
void transmit(uint32_t data) {
//Function for transmiting the data
uint32_t bitcount = 0x80000000;
// 9ms pulse burst
for (int i = 0; i < 355; i++) {
digitalWrite(IR, HIGH);
delayMicroseconds(CarrierFreqInterval);
digitalWrite(IR, LOW);
delayMicroseconds(CarrierFreqInterval);
}
// 4.5ms space
delayMicroseconds(4500);
//8bit address,adress inverse,command,command inverse
while ( bitcount != 0b0) {
if ((data & bitcount) == bitcount) {
pulseHIGH();
}
else {
pulseLOW();
}
bitcount = bitcount >> 1;
}
//final pulse burst
for (int i = 0; i < 21; i++) {
digitalWrite(IR, HIGH);
delayMicroseconds(CarrierFreqInterval);
digitalWrite(IR, LOW);
delayMicroseconds(CarrierFreqInterval);
}
}
void pulseHIGH() {
// Pulse 38KHz good for a LOGIC '1'
for (int i = 0; i < 21; i++) {
digitalWrite(IR, HIGH);
delayMicroseconds(CarrierFreqInterval);
digitalWrite(IR, LOW);
delayMicroseconds(CarrierFreqInterval);
}
delay(1);
delayMicroseconds(687.5);
}
void pulseLOW() {
// Pulse 38KHz good for a LOGIC '0'
for (int i = 0; i < 21; i++) {
digitalWrite(IR, HIGH);
delayMicroseconds(CarrierFreqInterval);
digitalWrite(IR, LOW);
delayMicroseconds(CarrierFreqInterval);
}
delayMicroseconds(562.5);
}

microphone sph0645 with I2S less sensitive after watchdog sleep with Adafruit Feather M0

I am using the Adafruit Feather M0 RFM69 with the Adafruit I2S MEMS Microphone Breakout SPH0645. Every second I take a reading (sampleRate = 16000, bits per sample = 32) using the I2S library and send it over the radio. This all works fine.
My problem is that, when I want to save power, I am getting weird readings after I wake the board from sleep (using Adafruit_SleepyDog library). The microphone somewhat still works, although it is much less sensitive, only picks up loud sounds and also returns 60dB in a quiet room. When I don't put it to sleep, in the same sound setting, I get 40dB. However, if I put a delay of 250ms after waking up, the microphone works fine again, like before, but this is obviously not saving energy then.
I wonder why this is happening. Is there something I can do to get the microphone to work quicker? I checked the datasheet, but it only says: "When Vdd is applied the microphone senses the
CLOCK line, if the frequency is greater than 900KHz, the microphone enters the normal mode of operation." This should not even take a few ms though?
Thanks in advance
#include <I2S.h>
#include <Adafruit_SleepyDog.h>
#include <SPI.h>
#include <RH_RF69.h>
/************ Radio Setup ***************/
#define RF69_FREQ 433.0
#define SLEEP
//#if defined(ARDUINO_SAMD_FEATHER_M0) // Feather M0 w/Radio
#define RFM69_CS 8
#define RFM69_INT 3
#define RFM69_RST 4
#define LED 13
//#endif
// radio
// Singleton instance of the radio driver
RH_RF69 rf69(RFM69_CS, RFM69_INT);
int transmit_interval = 1000;
int time_counter = 0;
int packetnum = 0;
// MIC
#define SAMPLES 1024//2048 // make it a power of two for best DMA performance
int samples[SAMPLES];
int measurementsdB = 0;
int current_measure;
#define ADC_SOUND_REF 65
#define DB_SOUND_REF 41
int sampleRate1 = 16000;
int bitsPerSample1 = 32;
typedef struct
{
uint8_t measurementdB = 123;
uint8_t battery = 111;
uint8_t test = 222;
} RadioMessage;
RadioMessage struct_message;
void setup()
{
delay(2000); // Wait so its easier to program
Serial.begin(115200);
//while (!Serial) { delay(1); } // wait until serial console is open, remove if not tethered to computer
// Init Mic
if (!I2S.begin(I2S_PHILIPS_MODE, sampleRate1, bitsPerSample1)) {
while (1); // do nothing
}
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
pinMode(RFM69_RST, OUTPUT);
digitalWrite(RFM69_RST, LOW);
Serial.println("Feather RFM69 TX Test!");
Serial.println();
// manual reset
digitalWrite(RFM69_RST, HIGH);
delay(10);
digitalWrite(RFM69_RST, LOW);
delay(10);
if (!rf69.init()) {
Serial.println("RFM69 radio init failed");
while (1);
}
Serial.println("RFM69 radio init OK!");
// Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM (for low power module)
// No encryption
if (!rf69.setFrequency(RF69_FREQ)) {
Serial.println("setFrequency failed");
}
// If you are using a high power RF69 eg RFM69HW, you *must* set a Tx power with the
// ishighpowermodule flag set like this:
rf69.setTxPower(20, true); // range from 14-20 for power, 2nd arg must be true for 69HCW
// The encryption key has to be the same as the one in the server
uint8_t key[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
rf69.setEncryptionKey(key);
Serial.print("RFM69 radio #"); Serial.print((int)RF69_FREQ); Serial.println(" MHz");
//GCLK->GENCTRL.bit.RUNSTDBY=1; // !! can go
}
void loop() {
Serial.println("START");
///// MIC
//PM->APBCMASK.reg |= PM_APBCMASK_I2S;
int a = 0;
while (a == 0) a = I2S.available();
uint8_t current_measure = sample_audio_signal(samples);
///// RADIO
if (true)//((time_counter + transmit_interval) < millis())
{
struct_message.measurementdB = current_measure;
//struct_message.battery = measuredvbat;
// Send a message!
/*
Serial.print("Array content: ");
uint8_t* bla = (uint8_t*) &struct_message;
for (int i = 0; i < 3; i++)
{
Serial.println(bla[i]);
}*/
rf69.send((const uint8_t*) &struct_message, sizeof(struct_message));
rf69.waitPacketSent();
Serial.print("Wait for reply");
// Now wait for a reply
uint8_t buf[RH_RF69_MAX_MESSAGE_LEN];
uint8_t len = sizeof(buf);
if (rf69.waitAvailableTimeout(100)) {
// Should be a reply message for us now
if (rf69.recv(buf, &len)) {
Serial.print("Got a reply: ");
Serial.println((char*)buf);
} else {
Serial.println("Receive failed");
}
} else {
Serial.println("No reply, is another RFM69 listening?");
}
Serial.println("Radio sleeping");
rf69.sleep();
time_counter = millis();
}
// sleep time
#ifdef SLEEP
int sleepMS = Watchdog.sleep(10);
delay(250);
#else
delay(1000);
#endif
Serial.println("loop ended");
}
void Blink(byte PIN, byte DELAY_MS, byte loops) {
for (byte i=0; i<loops; i++) {
digitalWrite(PIN,HIGH);
delay(DELAY_MS);
digitalWrite(PIN,LOW);
delay(DELAY_MS);
}
}
float sample_audio_signal(int samples[])
{
for (int i=0; i<SAMPLES; i++) {
int sample = 0;
while ((sample == 0) || (sample == -1) ) {
sample = I2S.read();
}
// convert to 18 bit signed
sample >>= 14;
samples[i] = sample;
}
// ok we have the samples, get the mean (avg)
float meanval = 0;
for (int i=0; i<SAMPLES; i++) {
meanval += samples[i];
}
meanval /= SAMPLES;
// subtract it from all samples to get a 'normalized' output
for (int i=0; i<SAMPLES; i++) {
samples[i] -= meanval;
}
// find the 'peak to peak' max
float maxsample, minsample;
minsample = 100000;
maxsample = -100000;
for (int i=0; i<SAMPLES; i++) {
minsample = min(minsample, samples[i]);
maxsample = max(maxsample, samples[i]);
}
int newdB = 20 * log10((float)maxsample / (float)ADC_SOUND_REF) + DB_SOUND_REF;
return newdB;
Ok, the best I got it down to is 3.8mA. I only got so far by leaving the voltage regulator and the internal oscillator (DFLL) on during sleeping.
After adding the following code to my setup routine, when board goes to sleep, the microphone still works after waking up:
SYSCTRL->DFLLCTRL.bit.RUNSTDBY=1;
SYSCTRL->VREG.bit.RUNSTDBY=1;
However, ideally I would like to get much less than that, but then the mic doesn't work...

Controlling LED using serial port

As part of a simple Automation project, I was trying to control some LEDs through serial port. I cannot make the following code working
int pin =0;
int state = 0;
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
if(Serial.read() == 'S' && Serial.read() == 'S') {
// Command to set the pin
pin = Serial.read() - 65;
state = Serial.read() - '0';
Serial.print("Set State Command received");
// Set the Pin
pinMode(pin, OUTPUT);
digitalWrite(pin, state == 0? LOW:HIGH);
}
}
}
I am sending "SSN1" from my python program to the Arduino serial port for testing, and nothing happens (I have an LED connected on pin 13)
SS - Set State Command
N - (pin no) + 'A' - Pin number 13
1 - State ( 0 = LOW, 1= HIGH)
You want to wait until 4 serial bytes accumulate on the serial buffer.
void loop() {
// polls the serial buffer
while (Serial.available() < 4);
if (Serial.read() == 'S' && Serial.read() == 'S') {
char type = Serial.read();
char pin = Serial.read() - 65;
// do something with the results
}
}
Note that you may want to implement some kind of padding (adding a fixed length of spaces, for example) between inputs, because the serial buffer may drop a byte or overflow, which can lead to unexpected results. Also, some people will complain about the while (Serial.available() < 4) command because computer scientists have been trained to think "polling = bad!", but in the case of an Arduino it makes no difference since it is only running a single task.
By the way, you can also use interrupts with Serial data, but that's out of the scope of this response.
actually I have also battled to get something similar right. due to the problems experienced with serial communication (sometime the messages are slow and sent in pieces, the ACII codes are difficult to remember) I went for a different solution. Basically I added a header ">" and a tail "<"to the message sent to the serial and I featured the Arduino code to consider the message between >< as command. I have then used ATOI to convert string to integer.
In the following code you will see that I have used the following numbers to get Arduino changing the status of pin2 and pin13.
Here are the commands associated to this code:
1000< set pin 13 HIGH,
2000< set pin 13 LOW,
3000< set pin 2 HIGH,
4000< set pin 2 LOW
So, simply send out to the serial those numbers between >< and it should work.
I have used the above also to set PWM speed simply manipulating the strings associated to the received messages. I have not included in this sample the PWM commands but only those related to pin 13 and pin 2. I thought that would be much simpler and safe to use numbers and string identifier to open and close the message.
Load the sketch, open the serial monitor and send >1000<, you should see the internal led on pin 13 lighting up, and so on. let me know if you need any additional help.
char inData[10];
int index;
boolean started = false;
boolean ended = false;
String message = "I am ready!, Send your command....";
void setup(){
Serial.begin(9600);
Serial.println(message);
pinMode (13, OUTPUT);
pinMode (2, OUTPUT);
}
void loop()
{
while(Serial.available() > 0)
{
char aChar = Serial.read();
if(aChar == '>')
{
started = true;
index = 0;
inData[index] = '\0';
}
else if(aChar == '<')
{
ended = true;
}
else if(started)
{
inData[index] = aChar;
index++;
inData[index] = '\0';
}
}
if(started && ended)
{
int inInt = atoi(inData);
// set pin 13 HIGH
if (inInt < 1000)
{
digitalWrite(13, HIGH);
}
//set pin 13 LOW
else if (inInt < 2000)
{
digitalWrite(13, LOW);
}
//set pin 2 HIGH
else if (inInt < 3000)
{
digitalWrite(2, HIGH);
}
//set il pin 2 LOW
else if (inInt < 4000)
{
digitalWrite(2, LOW);
}
started = false;
ended = false;
index = 0;
inData[index] = '\0';
}
}
Look at this example code from Arduino's Physical Pixel Tutorial
const int ledPin = 13; // the pin that the LED is attached to
int incomingByte; // a variable to read incoming serial data into
void setup() {
// initialize serial communication:
Serial.begin(9600);
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
}
void loop() {
// see if there's incoming serial data:
if (Serial.available() > 0) {
// read the oldest byte in the serial buffer:
incomingByte = Serial.read();
// if it's a capital H (ASCII 72), turn on the LED:
if (incomingByte == 'H') {
digitalWrite(ledPin, HIGH);
}
// if it's an L (ASCII 76) turn off the LED:
if (incomingByte == 'L') {
digitalWrite(ledPin, LOW);
}
}
Verify that you see SSN1 coming through on the serial monitor.
I improved my code as it look like this
int pin =0;
int state = 0;
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 3) { // I am using chunk of 4 characters/bytes as a command
// read the incoming byte:
if(Serial.read() == 'S' && Serial.read() == 'S') {
// Command to set the pin
pin = Serial.read() - 65;
state = Serial.read() - '0';
Serial.print("Set State Command received");
// Set the Pin
pinMode(pin, OUTPUT);
digitalWrite(pin, state == 0? LOW:HIGH);
}
delay(50);
}
}
It works perfectly for me. Due to the high frequency of looping, Arduino was not able pickup the bytes for consecutive read. So we are waiting for 4 bytes to accumulate in the buffer to read those (Arduino's serial buffer is 64 bytes).

Resources