Pausing a loop to run another in Arduino - arduino

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.

Related

Can i somehow add millis to this code somewhere in the buttons or in the modes?

i need to add millis in my code but i dont know exactly where should be ok to add millis or where is it acctually needed.Because i have used only delay till now can you help me and tell me where can millis be implemented in this piece of code.If it is possible to add millis somewhere in or after the button modes or switch case because it would be nicer if the modes changed properly because for now their changing either when the button is pressed normal or somtimes you need to pres the button twice to change to the next mode.I would apriciate all the help.
const int BUTTON_SWITCH = 8;
const int BUTTON_ALARM = 9;
const int KNOB = A0;
const int TEMP = A1;
const int tempRES = 10000; // the resistance of the NTC at 25'C is 10k ohm
const int NTC_MATERIAL_CONSTANT = 3950;
const int RED_LED = 4;
const int BUZZER = 3;
int index = 1;
double value;
int state = 0;
unsigned long time_now = 0;
int period = 1000;
char incomingOption;
#include "Display.h"
void setup() {
Serial.begin(9600);
pinMode(BUTTON_SWITCH, INPUT_PULLUP);
pinMode(BUTTON_ALARM, INPUT_PULLUP);
pinMode(RED_LED, OUTPUT);
}
float get_temperature()
{
float temperature, resistance;
int value;
value = analogRead(TEMP);
resistance = (float)value * tempRES / (1024 - value); // Calculate resistance
/* Calculate the temperature according to the following formula. */
temperature = 1 / (log(resistance / tempRES) / NTC_MATERIAL_CONSTANT + 1 / 298.15) - 273.15;
return temperature;
}
void loop() {
if (digitalRead(BUTTON_SWITCH) == LOW) { // button for switching the 3 modes
index = index + 1;
}
if (digitalRead(BUTTON_ALARM) == LOW) { // button for the alarm
displayAlarm();
}
if (Serial.available()) {
// Read entire buffer up to newline character
// Since on the C# side, serialPort1.WriteLine appends a newline character
String respond = Serial.readStringUntil('\n');
if (respond == "RESET") {
digitalWrite(RED_LED, LOW);
digitalWrite(BUZZER, LOW);
}
}
if (index > 3) { // when the code is on the last mode press the button to turn back to the first mode
index = 1;
}
get_temperature();
float celcius;
celcius = get_temperature();
if(celcius<16 || celcius>27){ // if the temperature becomes less than 16 degrees or goes higher than 27 degrees turn on the alarm
displayAlarm();
}
switch (index) {
case 1: displayTime(); break; // switch between the 3 different modes
case 2: displayTemp(); break;
case 3: displayAngle(); break;
}
}
void displayTime() {
float timer = Serial.parseFloat(); // take the current time from the c# application and display it on the arduino board
Display.show(timer);
}
void displayTemp() {
float celcius;
celcius = get_temperature(); // mode for displaying the current temperature
Display.show(celcius);
}
void displayAngle() {
int value = analogRead(KNOB); // read and save analog value from the potentionmeter
value = map(value, 0, 1023, 0, 30); // Map value 0-1023 to 0-30
Display.show(value);
}
void displayAlarm() {
Serial.println("Alarm");
digitalWrite(RED_LED, HIGH);
tone(BUZZER, 1500, 700);
}

Problem with interruptions in Arduino Uno

I work with interruptions in Arduino UNO. In this project, I want to when the Door is opened the LED blink 10 times, and when the door is closed again, stop blinking the LED and exit the function. But in this code the LED only turn on and off once and it does not flash again.
My other problem is that, when the door is opened or closed, sometimes the opened or closed word appears several times in the Series monitor.
const byte LED_Red = 13;
const byte DOOR_SENSOR = 2; // magnetic door sensor pin
volatile int SensorState = LOW; // 0 close - 1 open wwitch
void setup()
{
Serial.begin(9600);
pinMode(LED_Red, OUTPUT);
pinMode(DOOR_SENSOR, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(DOOR_SENSOR), DoAction, CHANGE);
}
void DoAction()
{
SensorState = digitalRead(DOOR_SENSOR);
if (SensorState == HIGH) {
Serial.println("Opened");
blinkLED(10, 500);
}
else {
Serial.println("Closed");
}
}
void blinkLED(int repeats, int time)
{
for (int i = 0; i < repeats; i++) {
if (SensorState == HIGH) {
digitalWrite(LED_Red, HIGH);
delay(time);
digitalWrite(LED_Red, LOW);
delay(time);
}
else
return;
}
}
void loop()
{
}
You can't simply put a delay() on an interrupt's function. You need to just set a flag when the door is opened and based on that start blinkLED inside the main loop.
I also recommend you to use millis() function for an unblocking delay inside blinkLED function (e.g when you want to stop blinking while the door is closed).
const byte LED_Red = 13;
const byte DOOR_SENSOR = 2; // magnetic door sensor pin
// flag to check door is opened
volatile bool isOpened = false;
//flag to check already blinked
volatile bool isBlinked = false;
void setup()
{
Serial.begin(9600);
pinMode(LED_Red, OUTPUT);
pinMode(DOOR_SENSOR, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(DOOR_SENSOR), DoAction, CHANGE);
}
void DoAction()
{
if (digitalRead(DOOR_SENSOR) == HIGH)
{
//Serial.println("Opened");
isOpened = true;
}
else
{
isOpened = false;
isBlinked = false;
//Serial.println("Closed");
}
}
void blinkLED(int repeats, int time)
{
byte LEDState = LOW;
unsigned long delay_start = millis();
for (int i = 0; i < 2 * repeats; i++)
{
//Toggle LED state
if (LEDState == HIGH)
LEDState = LOW;
else
LEDState = HIGH;
// set value
digitalWrite(LED_Red, LEDState);
// some unblocking delay
while (millis() - delay_start < time)
{
// return if door is closed
if (!isOpened)
{
// turn off LED
digitalWrite(LED_Red, LOW);
return;
}
}
delay_start = millis();
}
isBlinked = true;
}
void loop()
{
// Check isBlinked beacue don't want to blink again until door is closed
if (isOpened && !isBlinked)
{
blinkLED(10, 500);
}
}

How to translate code from Arduino to Raspberry Pi?

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:

quadrature encoder using photo interrupts

I a trying to program an encoder using photo interrupts and a 7474 d flip flop. I believe my wiring is correct. It is simply wiring the photo interrupt to the arduino and having the pin out going through the 7474. Also one of the wires goes to pin 4 to digital read.
Below is my code. For some reason I can't get the photo interrupts to read the turn of the wheel.
const int clock = 0; //pin 2 is interrupt 0
const int dirPin = 4; //the number of the LED pin
//const int ledPin = 13;
int count = 0;
int dir = 0;
//int clockA = 0;
void setup(){
pinMode(dirPin, INPUT);
Serial.begin(9600);
attachInterrupt(clock, program, RISING);
}
void loop()
{
delay(50);
}
void program()
{
dir = digitalRead(dirPin);
if (dir == HIGH)
{
count ++;
}
else
{
count --;
}
Serial.println(count*30);
}
Don't put the Serial.println() in the interrupt handler. Inside a handler other interrupts are disabled. Do as little work as possible and return. The handler should just update the count and can mark a flag to tell the main loop to process.
int count = 0;
int newcounts = 0;
void loop() {
delay(100);
if (newcounts) {
Serial.println(count*30);
newcounts = 0
}
}
void program() {
// ... update count
newcounts = 1;
}

Arduino calculating the frequency - what am I doing wrong here?

I'm a newbie when it comes to electronics and Arduino - so the best way is to just to play around with it, right?
I have started a small project that utilize and LDR (Light Density Resistor) and want to use it to calculate the frequency that a light beam is blocked or turned off.
For debugging purposes I setup a small LED that blinks at a defined frequency (5 Hz etc.) and use a LCD to display the output.
I have a problem with my top right corner... It seems as it performs wrongly. It was the intention that it should show the registered frequency, but while debugging I have set it to show the number of counts in an interval of 5 sec (5,000 msec). But it appears as 24 is the max no matter what frequency I set (When I get it to show the right number [5 sec x 5 Hz = 25] I will divide by the time interval and get the results in Hz). It also shows 24.0 for 9 Hz etc..
I also have this: YouTube video
...but some fumbling in the beginning caused the LED to move a bit so it counted wrong. But in the end it "works".. But the 24.0 keeps being constant
This is my code:
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 8, 9, 10, 11 , 12);
int booBlocked = 0;
int counter = 0;
int checkValue = counter + 1;
int ledPin = 3; // LED connected to digital pin 3
int value = LOW; // previous value of the LED
long previousMillis = 0; // will store last time LED was updated
long freqency = 5; // Hz (1/sec)
long thousand = 1000;
long interval = thousand / freqency; // milliseconds
//long interval = 59; // interval at which to blink (milliseconds)
int tValue = 0; // Threshold value used for counting (are calibrated in the beginning)
long pMillis = 0;
long inter = 5000;
int pCount = 0;
float freq = 0; // Calculated blink frequency...
void setup() {
lcd.begin(16, 2);
lcd.setCursor(0,1); lcd.print(interval);
lcd.setCursor(4,1); lcd.print("ms");
pinMode(ledPin, OUTPUT); // sets the digital pin as output
lcd.setCursor(0,0); lcd.print(freqency);
lcd.setCursor(4,0); lcd.print("Hz");
}
void loop() {
// Print LDR sensor value to the display
int sensorValue = analogRead(A0);
lcd.setCursor(7,1);
lcd.print(sensorValue);
delay(100);
if (millis() > 5000){
doCount(sensorValue);
updateFreq();
lcd.setCursor(7+5,0);
lcd.print(freq);
} else {
setThresholdValue(sensorValue);
lcd.setCursor(7+5,1);
lcd.print(tValue);
}
// LED BLINK
if (millis() - previousMillis > interval) {
previousMillis = millis(); // remember the last time we blinked the LED
// if the LED is off turn it on and vice-versa.
if (value == LOW)
value = HIGH;
else
value = LOW;
digitalWrite(ledPin, value);
}
}
void updateFreq(){
long now = millis();
long t = now - pMillis;
if (t >= 10000) {
freq = (float) (counter - pCount);
//freq = ((float) (counter - pCount)) / (float) 10.0;
pMillis = now; // remember the last time we blinked the LED
pCount = counter;
}
}
void setThresholdValue(int sensorValue){
if (sensorValue > int(tValue/0.90)){
tValue = int (sensorValue*0.90);
}
}
void doCount(int sensorValue){
// Count stuff
if (sensorValue < tValue){
booBlocked = 1;
//lcd.setCursor(0,0);
//lcd.print("Blocked");
} else {
booBlocked = 0;
//lcd.setCursor(0,0);
//lcd.print(" ");
}
if (booBlocked == 1) {
if (counter != checkValue){
counter = counter + 1;
lcd.setCursor(7,0);
lcd.print(counter);
}
} else {
if (counter == checkValue){
checkValue = checkValue + 1;
}
}
}
UPDATE
A more "clean" code (please see my own answer)
#include <LiquidCrystal.h>
// Initiate the LCD display
LiquidCrystal lcd(7, 8, 9, 10, 11 , 12); // see setup at http://lassenorfeldt.weebly.com/1/post/2013/02/ardunio-lcd.html
long updateInterval = 150; // ms
long updateTime = 0;
// Declare the pins
int ledPin = 3; // LED connected to digital pin 3
// LED setup
int value = LOW; // previous value of the LED
long previousMillis = 0; // will store last time LED was updated
long freqency = 16; // Hz (1/sec)
long thousand = 1000;
long blinkInterval = thousand / freqency; // milliseconds
//// LDR counter variables ////
// Counting vars
static int counter = 0;
int booBlocked = 0;
int checkValue = counter + 1;
// Calibration vars
long onBootCalibrationTime = 5000; // time [time] to use for calibration when the system is booted
static int threshold = 0; // Value used for counting (calibrated in the beginning)
float cutValue = 0.90; // Procent value used to allow jitting in the max signal without counting.
// Frequency vars
float freq = 0; // Calculated blink frequency...
long frequencyInterval = 5000; // time [ms]
long pMillis = 0;
int pCount = 0;
void setup() {
// Setup the pins
pinMode(ledPin, OUTPUT); // sets the digital pin as output
// display static values
lcd.begin(16, 2);
lcd.setCursor(0,0); lcd.print(freqency);
lcd.setCursor(4,0); lcd.print("Hz");
lcd.setCursor(0,1); lcd.print(blinkInterval);
lcd.setCursor(4,1); lcd.print("ms");
// Setup that allows loggin
Serial.begin(9600); // Allows to get a readout from Putty (windows 7)
}
void loop() {
long time = millis();
int sensorValue = analogRead(A0);
// Blink the LED
blinkLED(time);
// Calibrate or Count (AND calculate the frequency) via the LDR
if (time < onBootCalibrationTime){
setThresholdValue(sensorValue);
} else {
doCount(sensorValue);
updateFreq(time);
}
// Update the LCD
if (time > updateTime){
updateTime += updateInterval; // set the next time to update the LCD
// Display the sensor value
lcd.setCursor(7,1); lcd.print(sensorValue);
// Display the threshold value used to determined if blocked or not
lcd.setCursor(7+5,1); lcd.print(threshold);
// Display the count
lcd.setCursor(7,0);
lcd.print(counter);
// Display the calculated frequency
lcd.setCursor(7+5,0); lcd.print(freq);
}
}
void blinkLED(long t){
if (t - previousMillis > blinkInterval) {
previousMillis = t; // remember the last time we blinked the LED
// if the LED is off turn it on and vice-versa.
if (value == LOW)
value = HIGH;
else
value = LOW;
digitalWrite(ledPin, value);
}
}
void setThresholdValue(int sValue){
if (sValue > int(threshold/cutValue)){
threshold = int (sValue*cutValue);
}
}
void doCount(int sValue){
if (sValue < threshold){
booBlocked = 1;
} else {
booBlocked = 0;
}
if (booBlocked == 1) {
if (counter != checkValue){
counter = counter + 1;
}
} else {
if (counter == checkValue){
checkValue = checkValue + 1;
}
}
}
void updateFreq(long t){
long inter = t - pMillis;
if (inter >= frequencyInterval) {
freq = (counter - pCount) / (float) (inter/1000);
pMillis = t; // remember the last time we blinked the LED
pCount = counter;
}
}
This code does not fix my question, but is just more easy to read.
The issue with your plan is that a light density resistor is going to pick up all the ambient light around and therefore be completely environment sensitive.
Have any other project hopes? This one seems like an engineering learning experience, not a coding one.
Have you thought of motor projects? Personally I'm more into home automation, but motor projects are almost instantly rewarding.
I'd recommend to re-write your doCount() function along these lines to make things simpler and easier to grasp:
void doCount(int sensorValue){
static int previousState;
int currentState;
if ( previousState == 0 ) {
currentState = sensorValue > upperThreshold;
} else {
currentState = sensorValue > lowerThreshold;
}
if ( previousState != 0 ) {
if ( currentState == 0 ) {
counter++;
}
}
previousState = currentState;
}
Let lowerThreshold and upperThreshold be, for example, 90% and 110%, respectively, of your former tValue, and you have a hysteresis to smoothen the reaction to noisy ADC read-outs.
I think i found one of the bugs.. I was using a delay() which caused some trouble..
I cleaned up the code:
#include <LiquidCrystal.h>
// Initiate the LCD display
LiquidCrystal lcd(7, 8, 9, 10, 11 , 12); // see setup at http://lassenorfeldt.weebly.com/1/post/2013/02/ardunio-lcd.html
long updateInterval = 150; // ms
long updateTime = 0;
// Declare the pins
int ledPin = 3; // LED connected to digital pin 3
// LED setup
int value = LOW; // previous value of the LED
long previousMillis = 0; // will store last time LED was updated
long freqency = 16; // Hz (1/sec)
long thousand = 1000;
long blinkInterval = thousand / freqency; // milliseconds
//// LDR counter variables ////
// Counting vars
static int counter = 0;
int booBlocked = 0;
int checkValue = counter + 1;
// Calibration vars
long onBootCalibrationTime = 5000; // time [time] to use for calibration when the system is booted
static int threshold = 0; // Value used for counting (calibrated in the beginning)
float cutValue = 0.90; // Procent value used to allow jitting in the max signal without counting.
// Frequency vars
float freq = 0; // Calculated blink frequency...
long frequencyInterval = 5000; // time [ms]
long pMillis = 0;
int pCount = 0;
void setup() {
// Setup the pins
pinMode(ledPin, OUTPUT); // sets the digital pin as output
// display static values
lcd.begin(16, 2);
lcd.setCursor(0,0); lcd.print(freqency);
lcd.setCursor(4,0); lcd.print("Hz");
lcd.setCursor(0,1); lcd.print(blinkInterval);
lcd.setCursor(4,1); lcd.print("ms");
// Setup that allows loggin
Serial.begin(9600); // Allows to get a readout from Putty (windows 7)
}
void loop() {
long time = millis();
int sensorValue = analogRead(A0);
// Blink the LED
blinkLED(time);
// Calibrate or Count (AND calculate the frequency) via the LDR
if (time < onBootCalibrationTime){
setThresholdValue(sensorValue);
} else {
doCount(sensorValue);
updateFreq(time);
}
// Update the LCD
if (time > updateTime){
updateTime += updateInterval; // set the next time to update the LCD
// Display the sensor value
lcd.setCursor(7,1); lcd.print(sensorValue);
// Display the threshold value used to determined if blocked or not
lcd.setCursor(7+5,1); lcd.print(threshold);
// Display the count
lcd.setCursor(7,0);
lcd.print(counter);
// Display the calculated frequency
lcd.setCursor(7+5,0); lcd.print(freq);
}
}
void blinkLED(long t){
if (t - previousMillis > blinkInterval) {
previousMillis = t; // remember the last time we blinked the LED
// if the LED is off turn it on and vice-versa.
if (value == LOW)
value = HIGH;
else
value = LOW;
digitalWrite(ledPin, value);
}
}
void setThresholdValue(int sValue){
if (sValue > int(threshold/cutValue)){
threshold = int (sValue*cutValue);
}
}
void doCount(int sValue){
if (sValue < threshold){
booBlocked = 1;
} else {
booBlocked = 0;
}
if (booBlocked == 1) {
if (counter != checkValue){
counter = counter + 1;
}
} else {
if (counter == checkValue){
checkValue = checkValue + 1;
}
}
}
void updateFreq(long t){
long inter = t - pMillis;
if (inter >= frequencyInterval) {
freq = (counter - pCount) / (float) (inter/1000);
pMillis = t; // remember the last time we blinked the LED
pCount = counter;
}
}
Its not as precise as I wished.. but I believe that this is might due to the way I blink the LED.
I also discovered that float cutValue = 0.90; has an influence... lowering the bar to 0.85 decrease the calculated frequency.. ??
I changed the code completely after Albert was so kind to help me out using his awesome FreqPeriodCounter library
I also added a potentiometer to control the frequency
Here is my code:
#include <FreqPeriodCounter.h>
#include <LiquidCrystal.h>
// FrequencyCounter vars
const byte counterPin = 3; // Pin connected to the LDR
const byte counterInterrupt = 1; // = pin 3
FreqPeriodCounter counter(counterPin, micros, 0);
// LCD vars
LiquidCrystal lcd(7, 8, 9, 10, 11 , 12); // see setup at http://lassenorfeldt.weebly.com/1/post/2013/02/ardunio-lcd.html
long updateInterval = 200; // ms
long updateTime = 0;
// LED vars
int ledPin = 5; // LED connected to digital pin 3
int value = LOW; // previous value of the LED
float previousMillis = 0; // will store last time LED was updated
static float freqency; // Hz (1/sec)
static float pfreqency;
static float blinkInterval; // milliseconds
boolean logging = true; // Logging by sending to serial
// Use potentiometer to control LED frequency
int potPin = 5; // select the input pin for the potentiometer
int val = 0; // variable to store the value coming from the sensor
void setup(void){
// Setup the pins
pinMode(ledPin, OUTPUT); // sets the digital pin as output
val = analogRead(potPin);
freqency = map(val, 0, 1023, 0, 25); // Hz (1/sec)
pfreqency = freqency;
blinkInterval = 1000 / (freqency*2); // milliseconds
// LCD display static values
lcd.begin(16, 2);
lcd.setCursor(0,0); lcd.print(freqency);
lcd.setCursor(4,0); lcd.print("Hz");
lcd.setCursor(14,0); lcd.print("Hz");
lcd.setCursor(0,1); lcd.print(blinkInterval);
lcd.setCursor(4,1); lcd.print("ms");
//
attachInterrupt(counterInterrupt, counterISR, CHANGE);
// Logging
if (logging) {Serial.begin(9600);}
}
void loop(void){
// Loop vars
float time = (float) millis();
float freq = (float) counter.hertz(10)/10.0;
// Blink the LED
blinkLED(time);
if (logging) {
if(counter.ready()) Serial.println(counter.hertz(100));
}
// Update the LCD
if (time > updateTime){
updateTime += updateInterval; // set the next time to update the LCD
lcdNicePrint(7+3, 0, freq); lcd.setCursor(14,0); lcd.print("Hz");
val = analogRead(potPin);
freqency = map(val, 0, 1023, 1, 30);
if (freqency != pfreqency){
pfreqency = freqency;
blinkInterval = 1000 / (freqency*2); // milliseconds
lcdNicePrint(0,0, freqency); lcd.setCursor(4,0); lcd.print("Hz");
lcd.setCursor(0,1); lcd.print(blinkInterval);
lcd.setCursor(4,1); lcd.print("ms");
}
}
}
void lcdNicePrint(int column, int row, float value){
lcd.setCursor(column, row); lcd.print("00");
if (value < 10) {lcd.setCursor(column+1, row); lcd.print(value);}
else {lcd.setCursor(column, row); lcd.print(value);}
}
void blinkLED(long t){
if (t - previousMillis > blinkInterval) {
previousMillis = t; // remember the last time we blinked the LED
// if the LED is off turn it on and vice-versa.
if (value == LOW)
value = HIGH;
else
value = LOW;
digitalWrite(ledPin, value);
}
}
void counterISR()
{ counter.poll();
}

Resources