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/
Related
I am trying to implement error correction over an r/f communication between two arduinos. I tried adding a timer to it, in order to create a packet resend, but whenever it gets past the first send, it starts printing garbage ad infinity instead of doing the timer interrupt.
I tried messing around with the inside loop conditions some as well as trying to figure out what was wrong with the timer, but I couldn't figure it out. The problem seems to happen right around the first serial print, which is strange, because that part of the code is mostly unchanged.
(packets is a structure of two ints)
#include <ELECHOUSE_CC1101.h>
#include "packets.h"
// These examples are from the Electronics Cookbook by Simon Monk
// Connections (for an Arduino Uno)
// Arduino CC1101
// GND GND
// 3.3V VCC
// 10 CSN/SS **** Must be level shifted to 3.3V
// 11 SI/MOSI **** Must be level shifted to 3.3V
// 12 SO/MISO
// 13 SCK **** Must be level shifted to 3.3V
// 2 GD0
const int n = 61;
unsigned short int sequence = 0;
byte buffer[n] = "";
void setup() {
Serial.begin(9600);
Serial.println("Set line ending to New Line in Serial Monitor.");
Serial.println("Enter Message");
ELECHOUSE_cc1101.Init(F_433); // set frequency - F_433, F_868, F_965 MHz
// initialize timer1
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 0xFFFF; // Max value for overflow for now
TCCR1B |= (1 << CS12); // 256 prescaler
interrupts(); // enable all interrupts
}
Packet pckt, recieve;
ISR(TIMER1_OVR_vect){ // timer compare interrupt service routine
//Resend packet
ELECHOUSE_cc1101.SendData(buffer, pckt.data + pckt.seqNum);
int len = ELECHOUSE_cc1101.ReceiveData(buffer);
buffer[len] = '\0';
recieve.seqNum = buffer[n];
Serial.println("Interrupt");
}
void loop() {
if (Serial.available()) {
pckt.data = Serial.readBytesUntil('\n', buffer, n);
pckt.seqNum = sequence;
buffer[pckt.data] = '\0';
buffer[n-1] = pckt.seqNum;
Serial.println((char *)buffer);
ELECHOUSE_cc1101.SendData(buffer, pckt.data + pckt.seqNum);
TCNT1 = 0; // clear timer
TIMSK1 |= (1 << TOIE0); // enable timer compare interrupt
int len = ELECHOUSE_cc1101.ReceiveData(buffer);
while (recieve.seqNum <= sequence) {
}
TIMSK1 &= ~(1 << TOIE0); // turn off the timer interrupt
}
}
Sending data takes too long for interrupts. You should keep calls to send and receive buffers of data within the loop() function call tree. For example, sending a 12 bytes message via UART at 9600 bauds can take up to about 12ms.
You can use the timer interrupt to decrement a timeout counter, as is usually done on micro controllers, or use the millis() function to handle timings, as is easily done on Arduino.
I suggest you use the millis() function to compute timeouts.
example:
/* ... */
// I could not figure out what you were trying to do with
// pckt.seqNum.... Putting it at the end of the buffer
// makes no sense, so I've left it out.
// Moreover, its size is 2, so placing it at buffer[n-1] overflows the buffer...
enum machineState {
waitingForSerial,
waitingForResponse,
};
unsigned int time_sent; // Always use unsigned for variables holding millis()
// can use unsigned char for timeouts of 255
// milliseconds or less. unsigned int is good for about
// 65.535 seconds or less.
machineState state = waitingForSerial;
void loop()
{
switch(state)
{
case waitingForSerial:
pckt.data = Serial.readBytesUntil('\n', buffer, sizeof(buffer));
if (pckt.data > 0)
{
++pckt.seqNum;
Serial.write(buffer, pckt.data);
ELECHOUSE_cc1101.SetReceive();
ELECHOUSE_cc1101.SendData(buffer, pckt.data);
time_sent = millis();
state = waitingForResponse;
}
break;
case waitingForResponse:
if (ELECHOUSE_cc1101.CheckReceiveFlag())
{
auto len = ELECHOUSE_cc1101.ReceiveData(buffer)) // can use C++17 with duinos!!!
Serial.print("cc1101: ");
Serial.write(buffer, len);
state = waitingForSerial; // wait for another command from PC
}
// 1 second timeout, note the cast and subtraction, this is to avoid any
// issues with rollover of the millis() timestamp.
else if ((unsigned int)millis() - time_sent > 1000)
{
// resend ... stays stuck this way.
Serial.println("Retrying :(");
ELECHOUSE_cc1101.SendData(buffer, pckt.data);
time_sent = millis();
}
break;
default:
state = waitingForSerial;
Serial.println("unhandled state");
break;
}
}
I am trying to create a project that is similar to the one found here:
Easy Arduino Menus for Rotary Encoders
However, I am using an ESP32, and not an Arduino board.
To get to that far I need to get my Rotary Encoder working with his code:
Improved Arduino Rotary Encoder Reading
However, I can not compile the code and get an error on "PIND". This line:
reading = PIND & 0xC; // read all eight pin values then strip away all but pinA and pinB's values.
So my question is: Do you have an idea as to how I can adapt the encoder code to work with an ESP32?
Thanks a lot in advance. :)
His complete code:
/*******Interrupt-based Rotary Encoder Sketch*******
by Simon Merrett, based on insight from Oleg Mazurov, Nick Gammon, rt, Steve Spence
*/
static int pinA = 2; // Our first hardware interrupt pin is digital pin 2
static int pinB = 3; // Our second hardware interrupt pin is digital pin 3
volatile byte aFlag = 0; // let's us know when we're expecting a rising edge on pinA to signal that the encoder has arrived at a detent
volatile byte bFlag = 0; // let's us know when we're expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set)
volatile byte encoderPos = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255
volatile byte oldEncPos = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor)
volatile byte reading = 0; //somewhere to store the direct values we read from our interrupt pins before checking to see if we have moved a whole detent
void setup() {
pinMode(pinA, INPUT_PULLUP); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
pinMode(pinB, INPUT_PULLUP); // set pinB as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
attachInterrupt(0,PinA,RISING); // set an interrupt on PinA, looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below)
attachInterrupt(1,PinB,RISING); // set an interrupt on PinB, looking for a rising edge signal and executing the "PinB" Interrupt Service Routine (below)
Serial.begin(115200); // start the serial monitor link
}
void PinA(){
cli(); //stop interrupts happening before we read pin values
reading = PIND & 0xC; // read all eight pin values then strip away all but pinA and pinB's values
if(reading == B00001100 && aFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
encoderPos --; //decrement the encoder's position count
bFlag = 0; //reset flags for the next turn
aFlag = 0; //reset flags for the next turn
}
else if (reading == B00000100) bFlag = 1; //signal that we're expecting pinB to signal the transition to detent from free rotation
sei(); //restart interrupts
}
void PinB(){
cli(); //stop interrupts happening before we read pin values
reading = PIND & 0xC; //read all eight pin values then strip away all but pinA and pinB's values
if (reading == B00001100 && bFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
encoderPos ++; //increment the encoder's position count
bFlag = 0; //reset flags for the next turn
aFlag = 0; //reset flags for the next turn
}
else if (reading == B00001000) aFlag = 1; //signal that we're expecting pinA to signal the transition to detent from free rotation
sei(); //restart interrupts
}
void loop(){
if(oldEncPos != encoderPos) {
Serial.println(encoderPos);
oldEncPos = encoderPos;
}
}
The library(https://github.com/igorantolic/ai-esp32-rotary-encoder) you suggested is not very reliable. you get lot of false readings.
When I need to use a rotary encoder I stick to the example above.
I adapted it to ESP32:
As luck would have it it's nearly the same for GPIO34 and GPIO35.
GPIO34 is binary 100
GPIO35 is binary 1000
both 1100 or 0xC
https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf
Page 58:
GPIO_IN_REG --> GPIO 0...31
GPIO_IN1_REG --> GPIO 32...39
Please note GPIO 34, 35, 36 and 39 need pullup resistor. Else you can use INPUT_PULLUP
#include <Arduino.h>
static int pinA = 35;
static int pinB = 34;
volatile byte aFlag = 0;
volatile byte bFlag = 0;
volatile byte encoderPos = 0;
volatile byte oldEncPos = 0;
volatile byte reading = 0;
void IRAM_ATTR PinA()
{
cli();
reading = GPIO_REG_READ(GPIO_IN1_REG) & 0xC;
if (reading == B1100 && aFlag)
{
encoderPos--;
bFlag = 0;
aFlag = 0;
}
else if (reading == B1000)
bFlag = 1;
sei();
}
void IRAM_ATTR PinB()
{
cli();
reading = GPIO_REG_READ(GPIO_IN1_REG) & 0xC;
if (reading == B1100 && bFlag)
{
encoderPos++;
bFlag = 0;
aFlag = 0;
}
else if (reading == B100)
aFlag = 1;
sei();
}
void setup()
{
Serial.begin(115200);
pinMode(pinA, INPUT);
pinMode(pinB, INPUT);
attachInterrupt(digitalPinToInterrupt(pinA), PinA, RISING);
attachInterrupt(digitalPinToInterrupt(pinB), PinB, RISING);
}
void loop()
{
if (oldEncPos != encoderPos)
{
Serial.print("encoderPos: ");
Serial.println(encoderPos);
oldEncPos = encoderPos;
}
}
PIND is one of the registers for compatible Arduino boards only, which can be used for what is called direct port manipulation.
Specifically, PIND is the input register of port D (pins 0 to 7 on the UNO)
Reading this register for example, will give you the input state of each gpio from PIN0 to PIN7. In the Rotary Encoder this is used for reading the all the values of the PORTD in one go, and then mask other pins, except "pinA" and "pinB" which are pin 2 and pin 3 respectively.
This will not work on the ESP32 as that platform has no such register (remember you are doing direct hardware access here, and not going through a standard Arduino API)
You can look at GPIO_IN_REG in the ESP32 which you can use to read the GPIO pin states in a similar fashion.
GPIO_IN_REG will return the input values of GPIOs 0 - 31.
You can also try and use this library:
https://github.com/igorantolic/ai-esp32-rotary-encoder
if you need something already made, instead of reinventing the wheel, unless it is for your learning purposes.
I have an ADXL355 accelerometer attached to an Adafruit Feather Adalogger. I can configure and read the sensor. I can also write binary values to the SD card. The problem occurs when I try to read from the sensor and then write that data to the SD card. The only thing I can think of is I'm somehow messing up the SPI communication but I can't see where. I looked through pins_arduino.h for my board and the SD Card (pin 4) is on a different register than pin 10 so I don't see how I'm breaking things.
My operations proceed like this. Global sensor creation, Serial.begin, SD.begin, SPI.begin, Test sensor connection, Create file for output on SD card, Initialize sensor, Read sensor FIFO, Write to file, repeat last 2 forever.
The file is created but remains at 0 file size, ie nothing is actually written to the card.
The sensor can operate at 4 kHz which was hard to achieve using the digitalWrite functions so I switched to using the port registers on the Feather. I do it like this:
#include <SM_ADXL355_SPI_fast.h>
#include <SPI.h>
#include <SD.h>
#define cardSelect 4
ADXL355_SPIF adxl355(&DDRB, &PORTB, _BV(6)); // values taken from pins_arduino.h, tested and working on pin 10
void setup() {
Serial.begin(57600);
while(!Serial){
// wait for Serial
}
SD.begin(cardSelect);
SPI.begin();
while(!adxl355.TestConnection()){
delay(1000);
}
adxl355.OpenFile("TestSPI.bin");
adxl355.Initialize(1, 10, 0); // set range to 2g's, frequency to 4 Hz and filter to off
}
void loop() {
while(true){ // avoid Arduino overhead of their loop function
adxl355.ReadFIFO();
adxl355.WriteFIFOToFile();
}
}
Here is the ADXL constructor
ADXL355_SPIF::ADXL355_SPIF(volatile uint8_t * outReg, volatile uint8_t * outPort, uint8_t bitValue) : sensorOutReg(outReg), sensorPort(outPort), sensorBitValue(bitValue){
*sensorOutReg |= sensorBitValue;
*sensorPort |= sensorBitValue;
sensorWriteCount = 0;
}
TestConnection tests that the DeviceID reads 0xAD. Initialize sets the G range, sample rate in Hz and filter. I have tested these with serial output and they work properly.
OpenFile looks like this:
bool ADXL355_SPIF::OpenFile(const String& fileName){
sensorFile = SD.open(fileName, FILE_WRITE);
if (!sensorFile){
Serial.print("Could not create file: ");
Serial.println(fileName);
return false;
}
return true;
}
After running this a file does get created on the SD card called "TESTSPI.BIN" with 0 file size.
ReadFIFO reads the numbers of entries in FIFO, stored as fifoCount and then populates a buffer (sensorFIFO[32][3]) with the values from the FIFO. I've printed this buffer to Serial to show that it's working. Here is that function
void ADXL355_SPIF::ReadFIFO(){
ReadRegister(ADXL355_RA_FIFO_ENTRIES, 1);
fifoCount = buffer[0];
ReadFIFOInternal();
return;
}
void ADXL355_SPIF::ReadFIFOInternal(){
SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
*sensorPort &= ~sensorBitValue;
uint8_t spiCommand = ADXL355_RA_FIFO_DATA << 1 | ADXL355_READ;
SPI.transfer(spiCommand);
int i = 0;
unsigned long tempV;
unsigned long value;
while(i < fifoCount){
for (int ptr = 0; ptr < 3; ++ptr){
buffer[0] = SPI.transfer(0x0);
value = buffer[0];
value <<= 12;
tempV = SPI.transfer(0x0);
tempV <<= 4;
value |= tempV;
tempV = SPI.transfer(0x0);
tempV >>=4;
value |= tempV;
if (buffer[0] & 0x80) {
value |= 0xFFF00000;
}
long lValue = static_cast<long>(value);
sensorFIFO[i][ptr] = scaleFactor * lValue;
}
i += 3;
}
SPI.endTransaction();
*sensorPort |= sensorBitValue;
return;
}
Here is WriteFIFOToFile:
void ADXL355_SPIF::WriteFIFOToFile(){
if (fifoCount > 0){
sensorFile.write(reinterpret_cast<const char *>(&sensorFIFO), 4 * fifoCount);
}
sensorWriteCount += fifoCount;
if (sensorWriteCount >= 100){
sensorFile.flush();
sensorWriteCount = 0;
}
}
After allowing this to run for a while the file size is always 0. I tried a simple binary write function just to test the card. It looks like this and it worked.
#include <SD.h>
#define cardSelectPin 4
const float pi=3.14159;
File oFile;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while(!Serial){
// wait for serial
}
SD.begin(cardSelectPin);
oFile = SD.open("Test.bin", FILE_WRITE);
Serial.println(sizeof(int));
Serial.println(sizeof(float));
float testFloat[32][3];
for (int i = 0; i < 32; ++i){
for (int j = 0; j < 3; ++j){
testFloat[i][j] = pi * (i + 1) + j;
}
}
oFile.write(reinterpret_cast<const char *>(&testFloat), sizeof(float) * 96);
oFile.close();
Serial.println("Finished writing file.");
}
void loop() {
// put your main code here, to run repeatedly:
}
The problem was that flush was not being called correctly. I had created a buffer to hold data from the FIFO and it would flush the card when it would get full enough such that a subsequent read would overflow. At that time it would call flush. This is what was intended with the variable sensorWriteCount. This variable was of type uint8_t when it should have been a uint16_t.
Changing to the correct type fixed the problem. I would have deleted this question because it boils down to a typo, but once an answer has been posted the system doesn't allow that.
The only difference between the not-working sketch and the working one is the closing of the sd card. The sd card MUST be closed, I had the same problem you have and I assume that the file gets its boundaries written in its filesystem at file close call.
To solve your issue, use a push button. When you push it, it will close the file and stop reading/processing sensors. You can also use this button to start reading and recording sensors data on sd card again (toggle).
we are trying to code an RGB LED strip that has digital input using the arduino UNO. Our code verifies, but when we upload we get a lot of "Invalid library found in ..."
We are just trying to upload sample code off of instructables, and this is what it looks like:
/* Arduino Tutorial - How to use an RGB LED Strip
Dev: Michalis Vasilakis // Date 3/6/2016 // Ver 1.0
Info: www.ardumotive.com */
//Library
#include <Adafruit_NeoPixel.h>
//Constants
const int dinPin = 4; // Din pin to Arduino pin 4
const int numOfLeds = 8; // Number of leds
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(numOfLeds, dinPin, NEO_GRB + NEO_KHZ800);
// Color takes RGB values, from 0,0,0 up to 255,255,255
// e.g. White = (255,255,255), Red = (255,0,0);
int red = 255; //Value from 0(led-off) to 255().
int green = 00;
int blue = 0;
void setup() {
pixels.begin(); // Initializes the NeoPixel library
pixels.setBrightness(80); // Value from 0 to 100%
}
void loop() {
// For a set of NeoPixels the first NeoPixel is 0, second is 1, all the way up to the count of pixels minus one.
for(int i=0;i<numOfLeds;i++){
pixels.setPixelColor(i, pixels.Color(red,green,blue));
pixels.show(); // This sends the updated pixel color to the hardware.
delay(10); // Delay for a period of time to change the next led
}
}
Our LED's arent lighting up and we have updated all libraries, our IDE is version 1.8.1, and our board and still nothing. Does anyone know why?
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