Correct value only when printing to serial console

I'm trying to make a simple project that lets someone control the RGB values of an RGB LED with a Wii Nunchuck. I just got a Nunchucky (a simple breakout board to use the Wiimote Nunchuck peripheral) today, along with an Arduino Mega, and wanted to test both out. I'm just reading the values of the X axis of the Nunchuck's joystick and mapping the values to 0-255. You can only control one value - either red, green, or blue - at a time, by pressing and holding a tact switch.

I'll include most of my code. I removed the redundant parts for the green and blue leads of the LED, which are exactly the same, with different respective variables for the button and LED pin.

#include "Wire.h"
#include "WiiChuck.h"

WiiChuck chuck = WiiChuck();

// pins for push buttons
const int redButton = 26;

// pins for color of RGB LED
const int redPin = 11;

int joyX = 0;

void setup() {
	pinMode(redPin, OUTPUT);
	pinMode(redButton, INPUT);
	
	Serial.begin(9600);
	
	chuck.begin();
	chuck.update();
}

void loop() {
	int rBtnState = digitalRead(redButton);
	
	if (rBtnState == HIGH) {
		chuck.update();
		joyX = map(chuck.readJoyX(), -103, 90, 0, 255);
		
		setColor(redPin, joyX);
		joyX = 0;
		rBtnState = 0;
	}
}

void setColor(int currentPin, int color)
{
	//Serial.println(color);
	analogWrite(currentPin, color);
}

The problem is, it only works when the second-to-last line of code (Serial.println(color);) is uncommented. With absolutely zero changes whatsoever to any other code in this sketch or wiring in my circuit, commenting the serial print line breaks it. Instead of writing the mapped value from the joystick, it just seems to use a value of 255, regardless of the actual value.

This might not be a big problem if my Mega didn't freeze and cease all processing after a couple seconds of using serial. It's not just that serial stops sending anything; the sketch stops completely and nothing will work at all. Still, I don't see why using the serial console would make something completely unrelated to serial work. The Nunchuck library uses I2C, but even if I leave Serial.begin(9600); it still doesn't work, which should make sense.

Is my Mega defective? Either I'm doing something horribly wrong, or something is wrong with the serial capabilities of my new Mega.

Thank you to anyone who can help me!

Either I'm doing something horribly wrong, or something is wrong with the serial capabilities of my new Mega.

Likely, neither one. The Serial.println() statement is sending a stream of characters to the serial port. When the outgoing serial buffer gets full, the function blocks until there is room in the buffer. This takes a tiny amount of time at 115200. It takes 12 times as long at the stone age pace you are using. That (tiny) delay may be enough to affect the incorrectly creating WiiChuck instance.

Try leaving that commented out, but add a delay(5); statement after it. Does that allow the program to operate correctly?

WiiChuck chuckyCheese;

is the correct way to create the instance of the class. You should never invoke the constructor explicitly as you are doing.

Likely, neither one. The Serial.println() statement is sending a stream of characters to the serial port. When the outgoing serial buffer gets full, the function blocks until there is room in the buffer. This takes a tiny amount of time at 115200. It takes 12 times as long at the stone age pace you are using. That (tiny) delay may be enough to affect the incorrectly creating WiiChuck instance.

Try leaving that commented out, but add a delay(5); statement after it. Does that allow the program to operate correctly?

WiiChuck chuckyCheese;

is the correct way to create the instance of the class. You should never invoke the constructor explicitly as you are doing.

That seems to make sense. I can't think of anything else that could cause this problem. As for the incorrect construction, blame the creator of the library. :slight_smile: I just copied a part of an example from its page on this site. I'll report back later when I get a chance to test it.

Very punny. :stuck_out_tongue:

Well, I added the delay(5);... and it works! You must've had the right idea, because it works exactly as I intended it to now. Now to add more features. 8)

Many thanks, PaulS!

Keeping cutting the delay() amount, until it quits working (reliably). 5 milliseconds may be (a lot) longer than needed.

It seems to work just the same with 1 millisecond. Would it make much difference to use a different method for delaying, like keeping track of time with millis()? It could possibly work with less than 1 millisecond, but I don't know if the reduction in CPU cycles would be worth it, assuming there would be some.

I know for what I'm doing here it wouldn't make a difference, but I plan on using the Nunchuck with a TFT touch shield, where I might need something faster.

It could possibly work with less than 1 millisecond

There's a delayMicroseconds() function for really short delays. That's worth investigating. At some point, the overhead of waiting for the right time to do something takes longer than simply twiddling your thumbs for a few milliseconds. And, the code gets more complicated. It all depends on the performance impact of the delay().

Well, it works sometimes. Sometimes it works for like a minute, sometimes 5 seconds, sometimes 1 second, then it crashes. If I reset it, it doesn't help, but it seems if I remove power then plug it back in, it will work longer.

I'd guess that the RAM is overflowing, since I poll the Nunchuck so often and so many times. But I don't really know anything about manually managing RAM. Should I use malloc() and free() so the RAM isn't filled with the value of the joytick? I know I can't do PROGMEM since the value is determined at runtime. Is there a way to stop my program from filling the RAM and crashing?

Post a link to the library you are using. Post the code (all of it). Post links to the hardware.

Check this out:
http://playground.arduino.cc/Code/AvailableMemory
See if you really ARE running out of memory. The variation in times that you are seeing suggests that SRAM is not the issue.

Well, I've been playing with this a lot today, and all but one time it's worked without mysteriously stopping. I checked RAM usage, and it never went below 7209. Still have no idea why it did that, but as long as it keeps working there's no reason, let alone possibility, to try to fix it.

One site said the Nunchuck takes 3.3 volts, but works fine on 5v, so I was using 5v. But, I looked up the amperage of the Nunchuck and it's only 35mA, and the 3.3v rail on the Uno and Mega is 50mA, so as long as you don't overdraw it, it'll work fine. After I switched the Nunchuck from 5v to 3.3v I haven't had it freeze at all, so that may have been the problem.

Anyway, I found that delayMicroseconds(50) works perfectly fine. 20us is too slow, and ~25us it works, but the LED flickers some, since it doesn't have enough time to update. I could probably find something between 25 and 50us that works fine, but 50us is more than fine for now.

I'll just go ahead and post the code for posterity's sake, and so you can see if there are any problems with it, if you'd like. I am using this library for the Nunchuck.

#include "Wire.h"
#include <WiiChuck.h>

WiiChuck chuck;

// pins for push buttons
const int redButton = 26;
const int greenButton = 24;
const int blueButton = 22;

// pins for color of RGB LED
const int redPin = 11;
const int greenPin = 10;
const int bluePin = 9;

int color = 0;

void setup() {
	pinMode(redPin, OUTPUT);
	pinMode(greenPin, OUTPUT);
	pinMode(bluePin, OUTPUT);
	pinMode(redButton, INPUT);
	pinMode(greenButton, INPUT);
	pinMode(blueButton, INPUT);
	
	chuck.begin();
	chuck.update();
}

void loop() {
	int rBtnState = digitalRead(redButton);
	int gBtnState = digitalRead(greenButton);
	int bBtnState = digitalRead(blueButton);
	
	if (rBtnState == HIGH) {
		setColor(redPin);
		rBtnState = 0;
	}
	if (gBtnState == HIGH) {
		setColor(greenPin);
		gBtnState = 0;
	}
	if (bBtnState == HIGH) {
		setColor(bluePin);
		bBtnState = 0;
	}
}

void setColor(int currentPin) {
	delayMicroseconds(50);
	chuck.update();
	color = map(chuck.readJoyX(), -103, 90, 0, 255);
	
	analogWrite(currentPin, color);
	color = 0;
}

It's pretty simple so far. You just need 3 tact switches (or you could use toggle switches if you don't want to hold the button down while you use the Nunchuck) to change each color of the RGB LED. There are plenty of tutorials saying how to use tact switches and RGB LEDs, so it shouldn't be hard to find out how to if you don't know already.

You might want to use higher value resistors than some recommend, depending on the LED; my RGB LED with 270 ohms on each pin is slowly blinding me. :fearful:

After I switched the Nunchuck from 5v to 3.3v I haven't had it freeze at all, so that may have been the problem.

Excellent.

Anyway, I found that delayMicroseconds(50) works perfectly fine. 20us is too slow, and ~25us it works, but the LED flickers some, since it doesn't have enough time to update. I could probably find something between 25 and 50us that works fine, but 50us is more than fine for now.

What would you do with the 0.000025 seconds or less that you might save? I'd leave it and move on. Good work on finding the range that works.

my RGB LED with 270 ohms on each pin is slowly blinding me.

There's more than one use for electrical tape. 8)

PaulS:
What would you do with the 0.000025 seconds or less that you might save? I'd leave it and move on. Good work on finding the range that works.

Probably not much. It would probably, for my purposes, never make a difference how many CPU cycles it takes up, but part of me always strives for efficiency, so I'd feel more satisfied knowing I'm not wasting resources. But you're right, for this it makes no difference at all.

There's more than one use for electrical tape. 8)

Well then I wouldn't be able to see it at all! :stuck_out_tongue: