I have an Arduino Uno program and want to translate it code a Raspberry Pi 2. I am building a robotic kitchen pantry, and coded an LED state machine in order to represent it. The physical machine I plan to control has two main functions.
Functions
(1) The elevator moves to one of these three levels:
- 0 : Reset / Home
- 1 : Shelve 1
- 2 : Shelve 2
(2) The shelves move in/out of the elevator.
- Mount
- Unmount
I am currently using LEDs to represent motors / sensors in order to unit test my code. I understand that in order to make my code more robust I will require better handling of timing, something that the Raspberry Pi can afford to do.
Here is my current code:
// Sensors for shelves. True if shelf is loaded.
boolean s1 = false;
boolean s2 = false;
// Buttons to ask to shelves.
boolean input1 = false;
boolean input2 = false;
// Elevator level (0, 1, or 2)
int elevator = 0;
// Elevator Level LEDs (Red)
int elevatorReset = 13;
int elevatorOne = 12;
int elevatorTwo = 11;
// Shelve State LEDs (Green) (On if loaded, Off if hidden)
int ShelveOne = 10; // Top Shelve
int ShelveTwo = 9; // Bottom Shelve
// Buttons
int ButtonOne = 2; // Request Shelve One
int ButtonTwo = 3; // Request Shelve Two
int ButtonReset = 4; // Request Reset
// Debouncing
unsigned long lastTime1 = 0;
unsigned long lastTime2 = 0;
const long interval = 300;
void setup() {
pinMode(elevatorReset, OUTPUT); // declare LED as output
pinMode(elevatorOne, OUTPUT); // declare LED as output
pinMode(elevatorTwo, OUTPUT); // declare LED as output
pinMode(ShelveOne, OUTPUT); // declare LED as output
pinMode(ShelveTwo, OUTPUT); // declare LED as output
pinMode(ButtonOne, INPUT); // make button 1 an input
pinMode(ButtonTwo, INPUT); // make button 2 an input
pinMode(ButtonReset, INPUT); // make button 3 an input
}
void loop() {
unsigned long currentTime = millis();
level(0);
// Request Shelf 1
if (digitalRead(ButtonOne) == LOW)
{
pickup(1);
deliver(1);
}
// Request Shelf 2
if (digitalRead(ButtonTwo) == LOW)
{
pickup(2);
deliver(2);
}
// Request Reset
if (digitalRead(ButtonReset) == LOW)
{
reset();
}
}
void pickup(int num){
if (num == 1)
{
level(0);
delay(500);
level(1);
delay(500);
load(1);
}
else if (num == 2)
{
level(0);
delay(500);
level(1);
delay(500);
level(2);
delay(500);
load(2);
}
else if (num == 0)
{
}
}
void dropoff(int num){
if (num == 1)
{
level(1);
delay(500);
unload(1);
}
else if (num == 2)
{
level(1);
delay(500);
level(2);
delay(500);
unload(2);
}
}
void deliver(int num)
{
if (elevator == 1)
{
delay(1000);
level(0);
//blink();
}
if (elevator == 2)
{
delay(1000);
level(1);
delay(500);
level(0);
//blink();
}
}
void level(int num)
{
if (num == 0)
{
digitalWrite(elevatorReset, HIGH);
digitalWrite(elevatorOne, LOW);
digitalWrite(elevatorTwo, LOW);
elevator = 0;
}
else if (num == 1)
{
digitalWrite(elevatorReset, LOW);
digitalWrite(elevatorOne, HIGH);
digitalWrite(elevatorTwo, LOW);
elevator = 1;
}
else if (num == 2)
{
digitalWrite(elevatorReset, LOW);
digitalWrite(elevatorOne, LOW);
digitalWrite(elevatorTwo, HIGH);
elevator = 2;
}
}
void load(int num){
if (num == 1)
{
digitalWrite(ShelveOne, HIGH);
digitalWrite(ShelveTwo, LOW);
s1 = true;
}
else if (num == 2)
{
digitalWrite(ShelveOne, LOW);
digitalWrite(ShelveTwo, HIGH);
s2 = true;
}
}
void unload(int num){
if (num == 1)
{
digitalWrite(ShelveOne, LOW);
s1 = false;
}
else if (num == 2)
{
digitalWrite(ShelveTwo, LOW);
s2 = false;
}
}
void reset()
{
if (s1 == true)
{
delay(500);
dropoff(1);
delay(500);
level(0);
}
else if (s2 == true)
{
delay(500);
dropoff(2);
delay(500);
level(1);
delay(500);
level(0);
}
}
void blink ()
{
delay(1000);
while( !(digitalRead(ButtonOne) == LOW || digitalRead(ButtonTwo) == LOW || digitalRead(ButtonReset) == LOW) )
{
digitalWrite(elevatorReset, HIGH); // wait for a second
delay(200);
digitalWrite(elevatorReset, LOW); // wait for a second
delay(200);
}
}
Just to clarify, you can still use C++ to develop apps for Win10 IoT.
I built for you a similar one in C#:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Devices.Gpio;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace App6
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
private static GpioPin GpioPin1;
private static GpioPin GpioPin2;
private static GpioPin GpioPin3;
private static GpioPin GpioPin4;
private static GpioPin GpioPin5;
private static GpioPin GpioPin6;
private static GpioPin GpioPin7;
private static GpioPin GpioPin8;
// Sensors for shelves. True if shelf is loaded.
bool s1 = false;
bool s2 = false;
// Buttons to ask to shelves.
bool input1 = false;
bool input2 = false;
// Elevator level (0, 1, or 2)
int elevator = 0;
// Elevator Level LEDs (Red)
int elevatorReset = 13;
int elevatorOne = 12;
int elevatorTwo = 11;
// Shelve State LEDs (Green) (On if loaded, Off if hidden)
int ShelveOne = 10; // Top Shelve
int ShelveTwo = 9; // Bottom Shelve
// Buttons
int ButtonOne = 2; // Request Shelve One
int ButtonTwo = 3; // Request Shelve Two
int ButtonReset = 4; // Request Reset
// Debouncing
long lastTime1 = 0;
long lastTime2 = 0;
const long interval = 300;
private DispatcherTimer timer;
public MainPage()
{
this.InitializeComponent();
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(500);
timer.Tick += Timer_Tick;
InitGPIO();
}
private void InitGPIO()
{
var gpio = GpioController.GetDefault();
// Show an error if there is no GPIO controller
if (gpio == null)
{
GpioPin1 = null;
GpioPin2 = null;
GpioPin3 = null;
GpioPin4 = null;
GpioPin5 = null;
GpioPin6 = null;
GpioPin7 = null;
GpioPin8 = null;
return;
}
//pinMode(elevatorReset, OUTPUT); // declare LED as output
//pinMode(elevatorOne, OUTPUT); // declare LED as output
//pinMode(elevatorTwo, OUTPUT); // declare LED as output
//pinMode(ShelveOne, OUTPUT); // declare LED as output
//pinMode(ShelveTwo, OUTPUT); // declare LED as output
//pinMode(ButtonOne, INPUT); // make button 1 an input
//pinMode(ButtonTwo, INPUT); // make button 2 an input
//pinMode(ButtonReset, INPUT); // make button 3 an input
GpioPin1 = gpio.OpenPin(elevatorReset);
GpioPin2 = gpio.OpenPin(elevatorOne);
GpioPin3 = gpio.OpenPin(elevatorTwo);
GpioPin4 = gpio.OpenPin(ShelveOne);
GpioPin5 = gpio.OpenPin(ShelveTwo);
GpioPin6 = gpio.OpenPin(ButtonOne);
GpioPin7 = gpio.OpenPin(ButtonTwo);
GpioPin8 = gpio.OpenPin(ButtonReset);
GpioPin1.Write(GpioPinValue.Low);
GpioPin2.Write(GpioPinValue.Low);
GpioPin3.Write(GpioPinValue.Low);
GpioPin4.Write(GpioPinValue.Low);
GpioPin5.Write(GpioPinValue.Low);
GpioPin1.SetDriveMode(GpioPinDriveMode.Output);
GpioPin2.SetDriveMode(GpioPinDriveMode.Output);
GpioPin3.SetDriveMode(GpioPinDriveMode.Output);
GpioPin4.SetDriveMode(GpioPinDriveMode.Output);
GpioPin5.SetDriveMode(GpioPinDriveMode.Output);
// Check if input pull-up resistors are supported
if (GpioPin6.IsDriveModeSupported(GpioPinDriveMode.InputPullUp))
GpioPin6.SetDriveMode(GpioPinDriveMode.InputPullUp);
else
GpioPin6.SetDriveMode(GpioPinDriveMode.Input);
if (GpioPin7.IsDriveModeSupported(GpioPinDriveMode.InputPullUp))
GpioPin7.SetDriveMode(GpioPinDriveMode.InputPullUp);
else
GpioPin7.SetDriveMode(GpioPinDriveMode.Input);
if (GpioPin8.IsDriveModeSupported(GpioPinDriveMode.InputPullUp))
GpioPin8.SetDriveMode(GpioPinDriveMode.InputPullUp);
else
GpioPin8.SetDriveMode(GpioPinDriveMode.Input);
}
private void Timer_Tick(object sender, object e)
{
//unsigned long currentTime = millis();
level(0);
// Request Shelf 1
if (GpioPin6.Read() == GpioPinValue.Low)
{
pickup(1);
deliver(1);
}
// Request Shelf 2
if (GpioPin7.Read() == GpioPinValue.Low)
{
pickup(2);
deliver(2);
}
// Request Reset
if (GpioPin8.Read() == GpioPinValue.Low)
{
reset();
}
}
async void pickup(int num)
{
if (num == 1)
{
level(0);
await Task.Delay(500);
level(1);
await Task.Delay(500);
load(1);
}
else if (num == 2)
{
level(0);
await Task.Delay(500);
level(1);
await Task.Delay(500);
level(2);
await Task.Delay(500);
load(2);
}
else if (num == 0)
{
}
}
async void dropoff(int num)
{
if (num == 1)
{
level(1);
await Task.Delay(500);
unload(1);
}
else if (num == 2)
{
level(1);
await Task.Delay(500);
level(2);
await Task.Delay(500);
unload(2);
}
}
async void deliver(int num)
{
if (elevator == 1)
{
await Task.Delay(1000);
level(0);
//blink();
}
if (elevator == 2)
{
await Task.Delay(1000);
level(1);
await Task.Delay(500);
level(0);
//blink();
}
}
void level(int num)
{
if (num == 0)
{
GpioPin1.Write(GpioPinValue.High);
GpioPin2.Write(GpioPinValue.Low);
GpioPin3.Write(GpioPinValue.Low);
elevator = 0;
}
else if (num == 1)
{
GpioPin1.Write(GpioPinValue.Low);
GpioPin2.Write(GpioPinValue.High);
GpioPin3.Write(GpioPinValue.Low);
elevator = 1;
}
else if (num == 2)
{
GpioPin1.Write(GpioPinValue.Low);
GpioPin2.Write(GpioPinValue.Low);
GpioPin3.Write(GpioPinValue.High);
elevator = 2;
}
}
void load(int num)
{
if (num == 1)
{
GpioPin4.Write(GpioPinValue.High);
GpioPin5.Write(GpioPinValue.Low);
s1 = true;
}
else if (num == 2)
{
GpioPin4.Write(GpioPinValue.Low);
GpioPin5.Write(GpioPinValue.High);
s2 = true;
}
}
void unload(int num)
{
if (num == 1)
{
GpioPin4.Write(GpioPinValue.Low);
s1 = false;
}
else if (num == 2)
{
GpioPin5.Write(GpioPinValue.Low);
s2 = false;
}
}
async void reset()
{
if (s1 == true)
{
await Task.Delay(500);
dropoff(1);
await Task.Delay(500);
level(0);
}
else if (s2 == true)
{
await Task.Delay(500);
dropoff(2);
await Task.Delay(500);
level(1);
await Task.Delay(500);
level(0);
}
}
async void blink()
{
await Task.Delay(1000);
while (!(GpioPin6.Read() == GpioPinValue.Low || GpioPin7.Read() == GpioPinValue.Low || GpioPin8.Read() == GpioPinValue.Low))
{
GpioPin1.Write(GpioPinValue.High); // wait for a second
await Task.Delay(200);
GpioPin1.Write(GpioPinValue.Low); // wait for a second
await Task.Delay(200);
}
}
}
}
There are a few items to realize here
IoT Applications have the concept of a background application. See documentation here: http://ms-iot.github.io/content/en-US/win10/BackgroundApplications.htm
Note: It says background App, which may be confusing as it does not run like a background app in typical UWP does. The bootloader for IoT removes performance and cpu priority bottlenecks typically imposed on Background Applications for UWP and therefor runs just like a Foreground Application, just it is headless and a bit of an easier headless starting point. It also more closely resembles your Arduino code.
You should use enums for managing your state so it is centralized and easier to deal with.
In windows 10 IoT, you have the ability to setup event handlers for when events happen and process them instead of necessarily looping and watching. This will help in that events will be queued up and then processed. It may not be quite as speedy in some scenarios however, but in this instance it should be fine. If you need to loop, you may want to spin off a task that loops and watches
Finally in an event based multi-threaded system, you will need to guard processing state changes simultaneously from different threads by locking an object.
I have provided sample code based on your code base addressing all of the above. Note it is not completed, but should serve as a good starting point.
First you will need to create a background application and add a reference to the IoT extensions.
Here is the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Http;
using Windows.ApplicationModel.Background;
using Windows.Devices.Gpio;
using System.Threading.Tasks;
// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409
// Sensors for shelves. True if shelf is loaded.
namespace BackgroundApplication1
{
public sealed class StartupTask : IBackgroundTask
{
public enum MachineState
{
unknown,
initial,
elevatorLevelOne,
elevatorLevelTwo,
transitionOnetoTwo,
transitionTwotoOne,
transitionOnetoReset,
transitionTwotoReset
}
private MachineState currentState;
private object lObj;
// Elevator Level LEDs (Red)
private const int elevatorResetPin = 13;
private const int elevatorOnePin = 12;
private const int elevatorTwoPin = 11;
//Gpio for each
GpioPin elevOneLed;
GpioPin resetLed;
GpioPin elevTwoLed;
// Shelve State LEDs (Green) (On if loaded, Off if hidden)
private const int ShelveOnePin = 10; // Top Shelve
private const int ShelveTwoPin = 9; // Bottom Shelve
GpioPin shelfOneLed;
GpioPin shelfTwoLed;
// Buttons
private const int ButtonOne = 2; // Request Shelve One
private const int ButtonTwo = 3; // Request Shelve Two
private const int ButtonReset = 4; // Request Reset
// Debouncing
long lastTime1 = 0;
long lastTime2 = 0;
const long interval = 300;
public void Run(IBackgroundTaskInstance taskInstance)
{
this.Initialize();
Task.Run(() =>
{
while (true)
{
//thats right...do nothing.
}
});
}
public void Initialize()
{
GpioController gCon = GpioController.GetDefault();
//Elevator LEDs
elevOneLed = gCon.OpenPin(elevatorResetPin);
resetLed = gCon.OpenPin(elevatorOnePin);
elevTwoLed = gCon.OpenPin(elevatorTwoPin);
elevOneLed.SetDriveMode(GpioPinDriveMode.Output);
elevTwoLed.SetDriveMode(GpioPinDriveMode.Output);
resetLed.SetDriveMode(GpioPinDriveMode.Output);
//Shelf LEDs
shelfOneLed = gCon.OpenPin(ShelveOnePin);
shelfTwoLed = gCon.OpenPin(ShelveTwoPin);
shelfOneLed.SetDriveMode(GpioPinDriveMode.Output);
shelfTwoLed.SetDriveMode(GpioPinDriveMode.Output);
//Buttons
GpioPin buttonOne = gCon.OpenPin(ButtonOne);
GpioPin buttonTwo = gCon.OpenPin(ButtonTwo);
GpioPin buttonReset = gCon.OpenPin(ButtonReset);
buttonOne.SetDriveMode(GpioPinDriveMode.Input);
buttonTwo.SetDriveMode(GpioPinDriveMode.Input);
buttonReset.SetDriveMode(GpioPinDriveMode.Input);
buttonOne.ValueChanged += ButtonOne_ValueChanged;
buttonTwo.ValueChanged += ButtonTwo_ValueChanged;
buttonReset.ValueChanged += ButtonReset_ValueChanged;
this.GetShelfOne();
}
private void GetShelfOne()
{
switch(this.currentState)
{
case MachineState.unknown: this.Reset();
break;
case MachineState.elevatorLevelOne:
break;
case MachineState.elevatorLevelTwo: this.TransitionToShelfTwoFromOne();
break;
case MachineState.transitionOnetoReset: //handle the rest of your stuff similiarly...
break;
}
}
private void TransitionToShelfTwoFromOne()
{
this.shelfOneLed.Write(GpioPinValue.Low);
this.shelfTwoLed.Write(GpioPinValue.High);
this.currentState = MachineState.elevatorLevelTwo;
}
private void Reset()
{
throw new NotImplementedException();
}
private void ButtonReset_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{
throw new NotImplementedException();
}
private void ButtonTwo_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{
throw new NotImplementedException();
}
private void ButtonOne_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{
//rising edge means you pushed the button
if(args.Edge == GpioPinEdge.RisingEdge)
{
lock(lObj)
{
this.GetShelfOne();
}
}
//falling edge means you released the button.
//you could start a timer to see how long you held the button.
}
}
}
There are two ways:
Way 1 - You can directly use Arduino code onto your Windows IoT with minor changes.
Way 2 - By converting Arduino code into equivalent C# UWP.
Way 1: Use Arduino code directly on your Windows IoT
Setup Arduino Wiring for Windows IoT (refer this link)
Port your Arduino code (written above) onto your Windows IoT with pinmap of Raspberry Pi 2.
Important Note: There are some rules to port Arduino written code to Windows IoT which is described at ms-iot website. The Arduino code you have provided can directly be ported on to Raspberry Pi 2 (make sure to change Arduino pin numbers to RPi2 pinmap).
Way 2: Converting Arduino code to C# UWP
Converting Arduino code into C# UWP is not much complicated. You just have to convert Arduino functions into its equivalent C# UWP Windows IoT functions:
Related
Easy to handle received data with BLE but can't send data.
I'm using ESP32 BLE Uart code.
It's easy to get data from RxCharateristic but I don't know how to send data.
I'm trying to use TxCharacteristic to send data with BLE.
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint8_t txValue = 0;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++){
Serial.print(rxValue[i]);
}
}
}
};
void setup() {
Serial.begin(115200);
// Create the BLE Device
BLEDevice::init("TheOneSystem");
// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pTxCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pRxCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
}
void loop() {
if (deviceConnected) {
pTxCharacteristic->setValue(&txValue, 1);
pTxCharacteristic->notify();
txValue++;
delay(10); // bluetooth stack will go into congestion, if too many packets are sent
}
// disconnecting
if (!deviceConnected && oldDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
Serial.println("start advertising");
oldDeviceConnected = deviceConnected;
}
// connecting
if (deviceConnected && !oldDeviceConnected) {
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
}
I can easily handle received data with this part of code
class MyCallbacks: public BLECharacteristicCallbacks {
String bleData;
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++){
//Serial.print(rxValue[i]);
bleData=bleData+rxValue[i];
}
Serial.println();
Serial.println(bleData);
Serial.println("*********");
int first = bleData.indexOf(",");
String bleSSID = bleData.substring(0, first);
String blepw = bleData.substring(first+1, bleData.length());
Serial.println("Wifi : " + bleSSID + "," + "Password : " + blepw);
bleData="";
}
}
};
How to send data by using TxCharacteristic?
In my receiving code, I'm using this function to use callback.
if(pTxCharacteristic->canNotify()) {
pTxCharacteristic->registerForNotify(notifyCallback);
}
And here is my notifyCallback function i got from Google.
static void notifyCallback(
BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData,
size_t length,
bool isNotify){
Serial.println(data);
}
It seems like i have to add a little function in notifyCallback.
However errors continue to occur. I can't get data. Tnx for help.
I am trying to create a music box for my son, but i am having some trouble getting the SD card to work.
The idea is that when we scan a RFID tag we should get the corresponding mp3 file from the SD card.
I am using:
a ESP32 DOIT DEVKIT V1
RFID reader is a RFID-RC522
Micro SD card reader has no brand or model number on it. It just says "Micro sd card adapter" on the back and has 6 pins: cs, sck, mosi, miso, vcc, gnd
My problem is that both the RFID reader and the Micro SD Card reader should use SPI.
With the following code the RFID Card is working well. I just have no idea on how to add the SD Card reader (i have tried using the same pins as the rfid reader and also the HSPI pins, but without success!)
Any help is much appreciated!
#include <SPI.h>
#include <MFRC522.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <WebSocketsServer.h>
#include <ArduinoJson.h>
#include "web_index.h"
// Constants
const char *ssid = "****";
const char *password = "****";
const int dns_port = 53;
const int http_port = 80;
const int ws_port = 1337;
// Globals
AsyncWebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(1337);
char msg_buf[10];
// Tag reader variables
#define RFID_RC522_RST_PIN 27
#define RFID_RC522_SDA_PIN 5
MFRC522 mfrc522(RFID_RC522_SDA_PIN, RFID_RC522_RST_PIN);
bool rfid_tag_present_prev = false;
bool rfid_tag_present = false;
int _rfid_error_counter = 0;
bool _tag_found = false;
// Volume Variables
int VOLUME = 15;
int VOLUME_NORMAL_MAX = 30;
int VOLUME_LIMIT_MAX = 15;
int VOLUME_MAX = VOLUME_NORMAL_MAX;
int VOLUME_MIN = 0;
int VOLUME_CHANGE_AMOUNT = 1;
bool VOLUME_IS_LIMITED = false;
// Player variables
bool IS_PLAYING = false;
String TRACK_NAME = "-";
String ARTIST_NAME = "-";
// Button variables
const int BUTTON_VOL_DOWN_PIN = 34;
bool BUTTON_VOL_DOWN_STATE = HIGH;
bool BUTTON_VOL_DOWN_PREV_STATE = HIGH;
const int BUTTON_VOL_UP_PIN = 35;
bool BUTTON_VOL_UP_STATE = HIGH;
bool BUTTON_VOL_UP_PREV_STATE = HIGH;
const int BUTTON_STOP_PIN = 32;
bool BUTTON_STOP_STATE = HIGH;
bool BUTTON_STOP_PREV_STATE = HIGH;
const int BUTTON_NEXT_PIN = 33;
bool BUTTON_NEXT_STATE = HIGH;
bool BUTTON_NEXT_PREV_STATE = HIGH;
// Tag IDs
String TAG_TEST = "93 44 5C 92";
String TAG_BACH = "9C CD 69 0F";
/***********************************************************
Functions
*/
void volumeDecrease() {
if (VOLUME > VOLUME_MIN) {
VOLUME = VOLUME - VOLUME_CHANGE_AMOUNT;
broadcastUpdate();
}
}
void volumeIncrease() {
if (VOLUME < VOLUME_MAX) {
VOLUME = VOLUME + VOLUME_CHANGE_AMOUNT;
broadcastUpdate();
} else {
VOLUME = VOLUME_MAX;
broadcastUpdate();
}
}
void updateVolumeLimitState(bool state) {
VOLUME_IS_LIMITED = state;
broadcastUpdate();
}
void broadcastUpdate() {
DynamicJsonDocument doc(1024);
doc["volume"] = VOLUME;
doc["volume_min"] = VOLUME_MIN;
doc["volume_max"] = VOLUME_MAX;
doc["volume_is_limited"] = VOLUME_IS_LIMITED;
doc["is_playing"] = IS_PLAYING;
doc["track_name"] = TRACK_NAME;
doc["artist_name"] = ARTIST_NAME;
char json_string[1024];
serializeJson(doc, json_string);
webSocket.broadcastTXT(json_string);
}
void handleWsTextMessage(uint8_t client_num, uint8_t * payload) {
if ( strcmp((char *)payload, "getValues") == 0 ) {
broadcastUpdate();
} else if ( strcmp((char *)payload, "volume_down_button_click") == 0 ) {
volumeDecrease();
} else if ( strcmp((char *)payload, "volume_up_button_click") == 0 ) {
volumeIncrease();
} else if ( strcmp((char *)payload, "volume_limit_checkbox_on") == 0 ) {
updateVolumeLimitState(true);
} else if ( strcmp((char *)payload, "volume_limit_checkbox_off") == 0 ) {
updateVolumeLimitState(false);
} else { // Message not recognized
Serial.println("[%u] Message not recognized");
}
}
// Callback: receiving any WebSocket message
void onWebSocketEvent(uint8_t client_num, WStype_t type, uint8_t * payload, size_t length) {
// Figure out the type of WebSocket event
switch (type) {
// Client has disconnected
case WStype_DISCONNECTED:
Serial.printf("[%u] Disconnected!\n", client_num);
break;
// New client has connected
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(client_num);
Serial.printf("[%u] Connection from ", client_num);
Serial.println(ip.toString());
}
break;
// Handle text messages from client
case WStype_TEXT:
// Print out raw message
Serial.printf("[%u] Received text: %s\n", client_num, payload);
handleWsTextMessage(client_num, payload);
break;
// For everything else: do nothing
case WStype_BIN:
case WStype_ERROR:
case WStype_FRAGMENT_TEXT_START:
case WStype_FRAGMENT_BIN_START:
case WStype_FRAGMENT:
case WStype_FRAGMENT_FIN:
default:
break;
}
}
// Callback: send homepage
void onIndexRequest(AsyncWebServerRequest *request) {
const char* dataType = "text/html";
IPAddress remote_ip = request->client()->remoteIP();
Serial.println("[" + remote_ip.toString() +
"] HTTP GET request of " + request->url());
// request->send(SPIFFS, "/index.html", "text/html");
AsyncWebServerResponse *response = request->beginResponse_P(200, dataType, index_html_gz, index_html_gz_len);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
}
// Callback: send 404 if requested file does not exist
void onPageNotFound(AsyncWebServerRequest *request) {
IPAddress remote_ip = request->client()->remoteIP();
Serial.println("[" + remote_ip.toString() +
"] HTTP GET request of " + request->url());
request->send(404, "text/plain", "Not found");
}
/***********************************************************
Main
*/
void handleButtons() {
// VOLUME DOWN BUTTON
bool buttonVolDownState = digitalRead(BUTTON_VOL_DOWN_PIN);
if (buttonVolDownState == LOW && BUTTON_VOL_DOWN_PREV_STATE == HIGH) {
Serial.println("button down pressed");
volumeDecrease();
BUTTON_VOL_DOWN_PREV_STATE = LOW;
} else if (buttonVolDownState == HIGH && BUTTON_VOL_DOWN_PREV_STATE == LOW) {
BUTTON_VOL_DOWN_PREV_STATE = HIGH;
}
// VOLUME UP BUTTON
bool buttonVolUpState = digitalRead(BUTTON_VOL_UP_PIN);
if (buttonVolUpState == LOW && BUTTON_VOL_UP_PREV_STATE == HIGH) {
Serial.println("button up pressed");
volumeIncrease();
BUTTON_VOL_UP_PREV_STATE = LOW;
} else if (buttonVolUpState == HIGH && BUTTON_VOL_UP_PREV_STATE == LOW) {
BUTTON_VOL_UP_PREV_STATE = HIGH;
}
// STOP BUTTON
bool buttonStopState = digitalRead(BUTTON_STOP_PIN);
if (buttonStopState == LOW && BUTTON_STOP_PREV_STATE == HIGH) {
Serial.println("button stop pressed");
volumeIncrease();
BUTTON_STOP_PREV_STATE = LOW;
} else if (buttonStopState == HIGH && BUTTON_STOP_PREV_STATE == LOW) {
BUTTON_STOP_PREV_STATE = HIGH;
}
// NEXT BUTTON
bool buttonNextState = digitalRead(BUTTON_NEXT_PIN);
if (buttonNextState == LOW && BUTTON_NEXT_PREV_STATE == HIGH) {
Serial.println("button next pressed");
volumeIncrease();
BUTTON_NEXT_PREV_STATE = LOW;
} else if (buttonNextState == HIGH && BUTTON_NEXT_PREV_STATE == LOW) {
BUTTON_NEXT_PREV_STATE = HIGH;
}
}
String getTagUid() {
String content = "";
byte letter;
for (byte i = 0; i < mfrc522.uid.size; i++) {
content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}
content.toUpperCase();
String tag_uid = content.substring(1);
Serial.println("Getting tag uid");
Serial.println(content.substring(1));
return content.substring(1);
}
void checkTagValidity(String tag_uid) {
if (tag_uid == TAG_TEST) {
Serial.println("BLUE TAG");
ARTIST_NAME = "Blue Tag";
TRACK_NAME = "Super Track name";
IS_PLAYING = true;
broadcastUpdate();
} else if (tag_uid == TAG_BACH) {
Serial.println("BACH");
} else {
Serial.println("UNKNOWN CARD: ");
Serial.print(tag_uid);
}
}
void setup() {
// Init buttons
pinMode(BUTTON_VOL_DOWN_PIN, INPUT_PULLUP);
pinMode(BUTTON_VOL_UP_PIN, INPUT_PULLUP);
pinMode(BUTTON_STOP_PIN, INPUT_PULLUP);
pinMode(BUTTON_NEXT_PIN, INPUT_PULLUP);
// Start Serial port
Serial.begin(115200);
// Init SPI bus (for the tag reader)
SPI.begin();
// Init the tag reader
mfrc522.PCD_Init();
// Start access point
WiFi.softAP(ssid, password);
// Print our IP address
Serial.println();
Serial.println("AP running");
Serial.print("My IP address: ");
Serial.println(WiFi.softAPIP());
// On HTTP request for root, provide index.html file
server.on("/", HTTP_GET, onIndexRequest);
// 404 page
server.onNotFound(onPageNotFound);
// Start web server
server.begin();
// Start WebSocket server and assign callback
webSocket.begin();
webSocket.onEvent(onWebSocketEvent);
}
void loop() {
// Check for button clicks
handleButtons();
// Look for and handle WebSocket data
webSocket.loop();
rfid_tag_present_prev = rfid_tag_present;
_rfid_error_counter += 1;
if (_rfid_error_counter > 2) {
_tag_found = false;
}
// Detect Tag without looking for collisions
byte bufferATQA[2];
byte bufferSize = sizeof(bufferATQA);
// Reset baud rates
mfrc522.PCD_WriteRegister(mfrc522.TxModeReg, 0x00);
mfrc522.PCD_WriteRegister(mfrc522.RxModeReg, 0x00);
// Reset ModWidthReg
mfrc522.PCD_WriteRegister(mfrc522.ModWidthReg, 0x26);
MFRC522::StatusCode result = mfrc522.PICC_RequestA(bufferATQA, &bufferSize);
if (result == mfrc522.STATUS_OK) {
if ( ! mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue
return;
}
_rfid_error_counter = 0;
_tag_found = true;
}
rfid_tag_present = _tag_found;
// rising edge
if (rfid_tag_present && !rfid_tag_present_prev) {
Serial.println("Tag found");
// Get tag uid
String tag_uid = getTagUid();
// Check if valid tag
checkTagValidity(tag_uid);
}
// falling edge
if (!rfid_tag_present && rfid_tag_present_prev) {
Serial.println("Tag gone");
ARTIST_NAME = "-";
TRACK_NAME = "-";
IS_PLAYING = false;
broadcastUpdate();
}
}
Thanks to the comments from #romkey and #RamyHx i got it to work using the same SPI pins.
My problem was that i was using the same pin for the CS of both devices. Once i change it to different CS pins for the rfid and sd card reader it started working.
For the RFID i have used the pin D2, and for the sd card reader i have used the pin D5.
For the rfid i have change #define RFID_RC522_SDA_PIN 5 into #define RFID_RC522_SDA_PIN 2.
For the sd card i have used the code here, which assumes we are using the default pins (with CS connected to pin D5).
I'm working on a circuit that has two separate 4-bit binary counters with LEDs. I press a button and one counter begins counting to 15 in binary. I press a second button and the first counter pauses where it is and the second group of LEDs begin counting to 15 in binary. I got both counters working, but I can't get the first group to pause and the second to begin. I've tried using if statements with a boolean flag, but it messes up the first group of LEDs. How can I get ledPins1[] to pause when button2 is pressed, then resume when ledPins2[] finish?
int ledPin1[] = {2,3,4,5};
int ledPin2[] = {7,8,9,10};
int button1 = 11;
int button2 = 12;
boolean button1Last = LOW;
boolean button1Current = LOW;
boolean button2Last = LOW;
boolean button2Current = LOW;
void setup()
{
pinMode(button1, INPUT);
pinMode(button2, INPUT);
for(int i=0; i<4; i++)
{
pinMode(ledPin1[i], OUTPUT);
}
for(int i=0; i<4; i++)
{
pinMode(ledPin2[i], OUTPUT);
}
}
boolean waitForButtonPush1 (boolean lastStartSwitchState1)
{
boolean currentStartSwitchState1 = digitalRead(button1);
if(lastStartSwitchState1 != currentStartSwitchState1) delay(20);
currentStartSwitchState1 = digitalRead(button1);
return currentStartSwitchState1;
}
boolean waitForButtonPush2 (boolean lastStartSwitchState2)
{
boolean currentStartSwitchState2 = digitalRead(button2);
if(lastStartSwitchState2 != currentStartSwitchState2) delay(20);
currentStartSwitchState2 = digitalRead(button2);
return currentStartSwitchState2;
}
void loop()
{
button1Current = waitForButtonPush1(button1Last);
if(button1Last == LOW && button1Current == HIGH)
{
for (byte counter =0;counter<=15; counter++)
{
displayBinary(counter);
delay(500);
}
}
button2Current = waitForButtonPush2(button2Last);
if(button2Last == LOW && button2Current == HIGH)
{
for (byte counter =0;counter<=15; counter++)
{
displayBinary2(counter);
delay(500);
}
}
}
void displayBinary(byte numToShow)
{
for (int i =0;i<4;i++)
{
if (bitRead(numToShow, i)==1)
{
digitalWrite(ledPin1[i], HIGH);
}
else
{
digitalWrite(ledPin1[i], LOW);
}
}
}
void displayBinary2(byte numToShow)
{
for (int i =0;i<4;i++)
{
if (bitRead(numToShow, i)==1)
{
digitalWrite(ledPin2[i], HIGH);
}
else
{
digitalWrite(ledPin2[i], LOW);
}
}
}
Welcome to the world of embedded devices!
Getting a small microprocessor to do several things at the same time is a bit tricky.
The key is to never block. No calls to delay(), no sending large buffers on the serial port at 9600 bauds in one go, etc...
There are some simple techniques to do it, one of the most commonly used is finite state machines.
Let's analyse your app a bit.
2 similar dssplay counters, with delay
2 buttons, buttons usually need to be debounced, that also involves a delay.
Some code, for you to tinker with:
// ****************************
// pinout
static const byte ledPin1[] = { 2, 3, 4, 5 };
static const byte ledPin2[] = { 7, 8, 9, 10 };
constexpr byte button1 = 11; // using constexpr for these saves 2 bytes of RAM.
constexpr byte button2 = 12;
// ****************************
// Counter data
static constexpr unsigned int led_delay = 500; // 500 ms, for all counters.
// constexpr ?? arduino supports c++17. Not all features in the main .ino
// module and all features in .cpp modules.
// Hint: you could have a member variable in the structure below for delay,
// this would allow for counters running at different speeds, or add buttons
// to increase/decrease speed.
// we have only 2 states, but you could add more, like running
// backwards, or run a different chase pattern maybe?
enum class led_counter_state : byte
{
stopped,
running,
};
struct led_counter_data_t
{
led_counter_state state; // STATE
byte counter; // counter current value
unsigned int timestamp; // used for timing.
const byte* leds; // LED pins.
};
static led_counter_data_t led_counter[2];
void led_display_init()
{
for (byte i = 0; i < 2; ++i)
{
led_counter[i].state = led_counter_state::stopped;
led_counter[i].counter = 0;
led_counter[i].timestamp = 0;
}
led_counter[0].leds = ledPin1;
led_counter[1].leds = ledPin2;
}
// ****************************
// LED cotrrol
static void leds_display_value(const led_counter_data_t& cntr)
{
for (byte i = 0, val = cntr.counter; i < 4; ++i, val >>= 1)
digitalWrite(cntr.leds[i], val & 0x01);
}
static void leds_control(led_counter_data_t& cntr)
{
const auto now = (unsigned int)millis(); // keep track of time.
switch(cntr.state)
{
default: // something is wrong.. stop.
cntr.state = led_counter_state::stopped;
// fall through ...
case led_counter_state::stopped:
return; // if not running, do nothing
case led_counter_state::running:
if (now - cntr.timestamp >= led_delay) // check delay
{
if (++cntr.counter > 15) // advance counter.
cntr.counter = 0;
leds_display_value(cntr); // show value.
cntr.timestamp = now; // keep track of time.
}
break;
}
}
static void leds_start(led_counter_data_t& cntr)
{
if (cntr.state != led_counter_state::stopped)
return;
cntr.state = led_counter_state::running;
if (++cntr.counter > 15) // advance counter.
cntr.counter = 0;
led_display_value(cntr); // show value.
cntr.timestamp = (unsigned int)millis();
}
static void leds_stop(led_counter_data_t& cntr)
{
cntr.state = led_counter_state::stopped;
}
// ****************************
// switch inputs data
static constexpr byte switch_debounce_delay = 30; // 30ms is a good value for
// debouncing
struct switch_data_t
{
byte sw1_state : 1; // no need to waste more than 1 bit per switch
byte sw2_state : 1;
byte timestamp; // we'll only count to 30 ms, so 1 byte timestamp will do
};
static switch_data_t switch_data;
// ****************************
// switch inputs code
static void control_inputs()
{
const auto now = (byte)millis();
if (now - switch_data.timestamp < switch_debounce_delay)
return;
switch_data.timestamp = now;
// All switch control logic is regrouped here, and isolated
// form other control code, this makes the logic easier to
// write, read, and debug.
bool b = digitalRead(button1);
if (b & !switch_data.sw1_state) // button was pushed right now.
{
if (led_counter[0].state == led_counter_state::stopped)
{
leds_start(led_counter[0]); // start counter 1
leds_stop(led_counter[1]); // stop counter 2
}
else
{
leds_stop(led_counter[0]); // stop counter 1
}
}
switch_data.sw1_state = b;
b = digitalRead(button2);
if (b & !switch_data.sw2_state) // button was pushed right now.
{
if (led_counter[1].state == led_counter_state::stopped)
{
leds_start(led_counter[1]); // start counter 2
leds_stop(led_counter[0]); // stop counter 1
}
else
{
leds_stop(led_counter[1]); // stop counter 2
}
}
switch_data.sw2_state = b;
}
// ****************************
void setup()
{
pinMode(button1, INPUT);
pinMode(button2, INPUT);
for (byte i = 0; i < 4; ++i)
{
digitalWrite(ledPin1[i], LOW);
pinMode(ledPin1[i], OUTPUT);
digitalWrite(ledPin2[i], LOW);
pinMode(ledPin2[i], OUTPUT);
}
led_display_init();
}
// ****************************
// The goal, always, is to exit loop() as fast as possible, so
// everything will run smoothly, and appear to run simultaneously.
void loop()
{
control_inputs();
leds_control(led_counter[0]);
leds_control(led_counter[1]);
}
I do not have an arduino with me, so I did not comppile nor ran this, but it should be pretty close. Let me know if you're having issues or have any questions.
Posted here is my code for my RPi master and Arduino slave project. I have an analog sensor connected to the Arduino and i am reading this data with Processing on the RPi. I am using Processing because I intend on generating a graph and waveform with the data. The code below seems to work, however, any slight movement of setup "disconnects" the slave device because I get the following message. "The device did not respond. Check the cabling and whether you are using the correct address." I have narrowed the problem down and found out that it always disconnects at the i2c.read();function. My question is whether there is some type of break function so that when this does happen processing moves on and tries again in the next iteration? Or if it is stuck in a loop is it waiting for some signal from the slave device? Does anyone have any suggestions on how to approach this?
Processing Code
import processing.io.*;
I2C i2c;
int val = 0;
void setup()
{
i2c = new I2C(I2C.list()[0]);
}
void draw ()
{
if (I2C.list() != null)
{
i2c.beginTransmission(0x04);
i2c.write(8);
byte[] in = i2c.read(1);
int accel = in[0];
println (accel);
}
}
Arduino Code
#include <Wire.h>
#define SLAVE_ADDRESS 0x04
int number = 5;
int state = 0;
const int zInput = A0;
int zRawMin = 493;
int zRawMax = 530;
float acceleration;
int accel;
void setup() {
analogReference(EXTERNAL);
pinMode(13,OUTPUT);
Serial.begin(9600); // start serial for output
Wire.begin(SLAVE_ADDRESS); // join i2c bus with address #8
Wire.onReceive(receiveData); // register event
Wire.onRequest(sendData);
Serial.println ("Ready");
}
void loop() {
int zRaw = ReadAxis (zInput);
acceleration = map (float(zRaw), float (zRawMin), float(zRawMax), -9.81, 9.81);
accel = int(acceleration);
//delay(100);
}
void receiveData(int byteCount)
{
while (0 < Wire.available())
{ // loop through all but the last
number = Wire.read(); // receive byte as a character
//Serial.print("data received");
Serial.println(number); // print the character
if (number==1)
{
if (state == 0)
{
digitalWrite(13,HIGH);
state = 1;
}
else
{
digitalWrite(13,LOW);
state = 0;
}
}
}
}
void sendData()
{
Wire.write(accel);
}
int ReadAxis(int axisPin)
{
long reading = 0;
int raw = analogRead(axisPin);
return raw;
}
Looks like a solution might be to use a try/catch block courtesy of #Kevin Workman. It works well for what I need it to do thx.
here is the updated Processing code.
import processing.io.*;
I2C i2c;
int val = 0;
void setup()
{
i2c = new I2C(I2C.list()[0]);
}
void draw ()
{
if (I2C.list() != null)
{
i2c.beginTransmission(0x04);
i2c.write(8);
try
{
byte[] in = i2c.read(1);
}
catch(Exception e)
{
i2c.endTransmission();
}
int accel = in[0];
println (accel);
}
}
I am trying to form a two player game which requires an audio reflex to a visual. by using littebits sound trigger for sound input and littbits arduino to connect it to the computer. But I am new to this and don't know how to connect arduino to processing and use the input from sound trigger to effect the score when a black square appears.
here is my code in processing and a sample arduino code I have taken from littlebits website and tried to modify a little.
thanks in advance!
float dice;
int playerOne = 0; //player 1 score (left paddle)
int playerTwo = 0; //player 2 score (right paddle)
boolean oneWins = false;
boolean twoWins = false;
void setup(){
size(500, 500);
smooth();
noStroke();
frameRate(2.5);
}
void draw() {
background(255);
showGUI();
dice = random(0, 3);
if (dice < 1.000001 && dice > 0.1){
fill ((0), (255), (0));
ellipse (250,250,100,100);
} else if (dice < 2.000001 && dice > 1.000001){
rectMode(RADIUS);
fill ((255), (0), (0));
rect (250,250,50,50);
} else if (dice < 3.000000 && dice > 1.000000){
rectMode(RADIUS);
fill ((0), (0), (255));
rect (250,250,50,50);
} else if (dice < 0.1){
rectMode(RADIUS);
fill(0);
rect(250,250,50,50);
}
}
----------arduino------
void setup() {
Serial.begin(9600); //Establish rate of Serial communication
establishContact(); //See function below
}
void loop() {
if (Serial.available() > 0) {
int inByte = Serial.read();
int leftTrigger = analogRead(A0);
Serial.print(leftTrigger, DEC);
Serial.print(",");
int rightTrigger = analogRead(A1);
Serial.println(rightTrigger, DEC);
}
}
void establishContact() {
while (Serial.available() <= 0) {
Serial.println("hello");
delay(300);
}
}
You need two pieces of code for this to work: one on the Arduino that sends commands, and one for Processing to receive and parse those commands.
I haven't used the littlebits modules, but here's a button example from this very detailed tutorial.
Arduino code:
int switchPin = 4; // switch connected to pin 4
void setup() {
pinMode(switchPin, INPUT); // set pin 0 as an input
Serial.begin(9600); // start serial communication at 9600bps
}
void loop() {
if (digitalRead(switchPin) == HIGH) { // if switch is ON,
Serial.print(1, BYTE); // send 1 to Processing
} else { // if the switch is not ON,
Serial.print(0, BYTE); // send 0 to Processing
}
delay(100); // wait 100 milliseconds
}
And the matching Processing code:
import processing.serial.*;
Serial port; // create object from Serial class
int val; // data received from the serial port
void setup() {
size(200, 200);
frameRate(10);
// open the port that the board is connected to
// and use the same speed (9600bps)
port = new Serial(this, 9600);
}
void draw() {
if (0 < port.available()) { // if data is available,
val = port.read(); // read it and store it in val
}
background(255); // set background to white
if (val == 0) { // if the serial value is 0,
fill(0); // set fill to black
} else { // if the serial value is not 0,
fill(204); // set fill to light gray
}
rect(50, 50, 100, 100);
}
Notice that the Arduino sends a value that Processing looks for and interprets. You can also look at the PhysicalPixel example from the Arduino IDE for an example on sending data from Processing to Arduino.