I'm having troubles trying to use two 595 shift registers to output numbers on a 4 digit 7seg display.
I've gotten to the point of displaying numbers correctly, but I'm now having the issue that the output is flashing some garbage between the digits being displayed. How do I prevent this from happening?
I'm pretty sure the issue is that as I'm using bytes to send to the registers it is latching between bytes being displayed.
Here is my code
int latchPin = 5;
int clockPin = 6;
int dataPin = 4;
int i = 0;
int waitTime = 500;
// digits from the right
byte colDig[4] =
{
B00001000, // digit 1
B00000100, // digit 2
B00000010, // digit 3
B00000001, // digit 4
};
const byte digit[10] = //seven segment digits in bits
{
B11000000, // 0
B11111001, // 1
B10100100, // 2
B10110000, // 3
B10011001, // 4
B10010010, // 5
B10000010, // 6
B11111000, // 7
B10000000, // 8
B10011000, // 9
};
void setup()
{
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
void loop()
{
// step through each digit then increment
// the counter by one, until nine
for(int j = 0;j<9;j++){
updateShiftRegister(0, j);
delay(waitTime);
updateShiftRegister(1, j);
delay(waitTime);
updateShiftRegister(2, j);
delay(waitTime);
updateShiftRegister(3, j);
delay(waitTime);
}
}
void updateShiftRegister(int col, int num)
{
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, colDig[col]);
shiftOut(dataPin, clockPin, MSBFIRST, digit[num]);
digitalWrite(latchPin, HIGH);
}
So it looks like I was sort of correct,
The shiftOut function sets the clock pin to low at the end of the function, effectively forcing a latch.
By slightly modifying the code on this page I was able to stop this and it works perfect now.
http://arduino.cc/en/Tutorial/ShftOut23
// the heart of the program
void shiftItOut(int myDataPin, int myClockPin, byte myDataOut) {
// This shifts 8 bits out MSB first,
//on the rising edge of the clock,
//clock idles low
//internal function setup
int i=0;
int pinState;
pinMode(myClockPin, OUTPUT);
pinMode(myDataPin, OUTPUT);
//clear everything out just in case to
//prepare shift register for bit shifting
digitalWrite(myDataPin, 0);
digitalWrite(myClockPin, 0);
//for each bit in the byte myDataOut
//NOTICE THAT WE ARE COUNTING DOWN in our for loop
//This means that %00000001 or "1" will go through such
//that it will be pin Q0 that lights.
for (i=7; i>=0; i--) {
digitalWrite(myClockPin, 0);
//if the value passed to myDataOut and a bitmask result
// true then... so if we are at i=6 and our value is
// %11010100 it would the code compares it to %01000000
// and proceeds to set pinState to 1.
if ( myDataOut & (1<<i) ) {
pinState= 1;
}
else {
pinState= 0;
}
//Sets the pin to HIGH or LOW depending on pinState
digitalWrite(myDataPin, pinState);
//register shifts bits on upstroke of clock pin
digitalWrite(myClockPin, 1);
//zero the data pin after shift to prevent bleed through
digitalWrite(myDataPin, 0);
}
//stop shifting
//digitalWrite(myClockPin, 0);
}
Simply commenting out that last digitalWrite fixed it all.
Related
I'm trying to build a small hygrometer based on the DHT11 and I'm having a bit of an "issue" with the code size. I want to run it on an Attiny45 and it's a wee bit too big (352 bytes too big to be exact). I am aware that I could just use an Attiny85 and have space to spare or don't use a bootloader and barely fit it in (94%) but I kind of want to make my life harder than it needs to be and figure out how to reduce size since it'll probably come in handy in the future. Treat it as a learning experience if you will.
What it's supposed to do:
Read DHT11 input
Display results on 2 two-digit 7-segment displays (so I guess 4 7-segments in total)
Go to sleep most of the time to preserve battery
Wake up every 8 seconds to update sensor values (without turning on the display)
Wake up on a button press to display the values for humidity and temperature
Side note: 7-segments are adressed via two 74HC595s of which I am using 7 outputs each for the displays and 1 each for a transistor that connects the display in question to GND. There's a schematic at the bottom if you're interested.
As pointed out, my main issue is code size so if anyone has any tips on how to reduce that (or any other tips how to improve the code) please let me know.
I hope I'm asking the question properly, if not please let me know.
Compiler output:
Sketch uses 3872 bytes (110%) of program storage space. Maximum is 3520 bytes.text section exceeds available space in board
Global variables use 107 bytes (41%) of dynamic memory, leaving 149 bytes for local variables. Maximum is 256 bytes.
Sketch too big; see https://support.arduino.cc/hc/en-us/articles/360013825179 for tips on reducing it.
Error compiling for board ATtiny45/85 (Optiboot).
Code:
/*
Humidity/Temperature sensor setup with DHT-11
Two digits for humidity
Two digits for temperature
Button to wake up from sleep
NPNs activated via 8th bit in 74HC595s, always alternating
Author: ElectroBadger
Date: 2021-11-02
Version: 1.0
*/
/*
Reduce power consumption:
- Run at 1 MHz internal clock
- Turn off ADC
- Use SLEEP_MODE_PWR_DOWN
*/
#include "DHT.h" //DHT-11 sensor
#include <avr/sleep.h> // Sleep Modes
#include <avr/power.h> // Power management
#include <avr/wdt.h> //Doggy stuff
//define attiny pins
#define INT_PIN PB4
#define DATA PB1
#define SENSOR PB3
#define LATCH PB2
#define CLK PB0
//define other stuff
#define SENSOR_TYPE DHT11
#define LED_DELAY 50
//changing variables
short ones_data; //16-bits for display of ones
short tens_data; //16-bits for display of tens
byte sevSeg, measurements; //7-segment bit pattern / wait time between LEDs [ms] / # of measurements taken
bool firstPair, btnPress; //tracks which pair of 7-segments is on; tracks button presses
uint32_t oldMillis, sleepTimer; //tracks the last acquisition time and wakeup time
//Initialize sensor
DHT dht(SENSOR, SENSOR_TYPE);
//Shifts 16 bits out MSB first, on the rising edge of the clock.
void shiftOut(int dataPin, int clockPin, short toBeSent){
int i=0;
int pinState = 0;
//Clear everything out just in case
digitalWrite(dataPin, 0);
digitalWrite(clockPin, 0);
//Loop through bits in the data bytes, COUNTING DOWN in the for loop so that
//0b00000000 00000001 or "1" will go through such that it will be pin Q0 that lights.
for(i=0; i<=15; i++){
digitalWrite(clockPin, 0);
//if the value passed to myDataOut AND a bitmask result
//is true then set pinState to 1
if(toBeSent & (1<<i)){
pinState = 1;
}
else{
pinState = 0;
}
digitalWrite(dataPin, pinState); //Sets the pin to HIGH or LOW depending on pinState
digitalWrite(clockPin, 1); //Shifts bits on upstroke of clock pin
digitalWrite(dataPin, 0); //Zero the data pin after shift to prevent bleed through
}
digitalWrite(clockPin, 0); //Stop shifting
}
//Converts an int <10 to a bit pattern for 7-segment displays
short toSegments(int value){
byte pattern = 0b00000000; //create empty pattern
//Using a switch...case (3878 bytes) if...else if...else uses 3946 bytes
switch(value){
case 0:
pattern = 0b01111110;
break;
case 1:
pattern = 0b00110000;
break;
case 2:
pattern = 0b01101101;
break;
case 3:
pattern = 0b01111001;
break;
case 4:
pattern = 0b00110011;
break;
case 5:
pattern = 0b01011011;
break;
case 6:
pattern = 0b01011111;
break;
case 7:
pattern = 0b01110000;
break;
case 8:
pattern = 0b01111111;
break;
case 9:
pattern = 0b01111011;
break;
default:
pattern = 0b00000000;
break;
}
return pattern;
}
void goToSleep(){
//Turn off 7-segments and NPNs
digitalWrite(LATCH, 0);
shiftOut(DATA, CLK, 0b0000000000000000);
digitalWrite(LATCH, 1);
//Set deep sleep mode
set_sleep_mode (SLEEP_MODE_PWR_DOWN);
ADCSRA = 0; // turn off ADC
power_all_disable (); // power off ADC, Timer 0 and 1, serial interface
cli(); // timed sequence coming up, so disable interrupts
btnPress = false;
measurements = 0;
resetWatchdog (); // get watchdog ready
sleep_enable (); // ready to sleep
sei(); // interrupts are required now
sleep_cpu (); // sleep
sleep_disable (); // precaution
power_all_enable (); // power everything back on
}
ISR(PCINT_VECTOR){
btnPress = true;
sleepTimer = millis();
}
// watchdog interrupt
ISR(WDT_vect){
wdt_disable(); //disable watchdog
}
void resetWatchdog(){
MCUSR = 0; //clear various "reset" flags
WDTCR = bit (WDCE) | bit (WDE) | bit (WDIF); //allow changes, disable reset, clear existing interrupt
//set interrupt mode and an interval (WDE must be changed from 1 to 0 here)
WDTCR = bit (WDIE) | bit (WDP3) | bit (WDP0); //set WDIE, and 8 seconds delay
wdt_reset(); //pat the dog
}
void setup(){
resetWatchdog(); // do this first in case WDT fires
cli(); //Disable interrupts during setup
pinMode(INT_PIN, INPUT_PULLUP); //Set interrupt pin as input w/ internal pullup
pinMode(DATA, OUTPUT); //Set serial data as output
pinMode(CLK, OUTPUT); //Set shift register clock as output
pinMode(LATCH, OUTPUT); //Set output register (latch) clock as output
// Interrupts
PCMSK = bit(INT_PIN); //Enable interrupt handler (ISR)
GIFR |= bit(PCIF); // clear any outstanding interrupts
GIMSK |= bit(PCIE); //Enable PCINT interrupt in the general interrupt mask
//default conditions
/* bit 0-6: ones digits
bit 7: NPN for units digits
bit 8-14: ones digits
bit 15: NPN for tens digits
*/
ones_data = 0b0000000000000000;
tens_data = 0b0000000000000000;
measurements = 0;
firstPair = true;
btnPress = false;
oldMillis = 0;
sleepTimer = 0;
//Start sensor
dht.begin();
delay(1000); //wait 1s for sensor to stabilize
sei(); //Enable interrupts after setup
}
void loop(){
if((millis()-oldMillis) > 1000){
//Slow sensor, so readings may be up to 2 seconds old
byte hum = dht.readHumidity(); //Read humidity
byte temp = dht.readTemperature(); //Read temperatuer in °C
//update tens bit string
tens_data = 0b0000000000000000; //reset to all 0s
sevSeg = toSegments(hum/10); //convert tens of humidity to 7-segment logic
tens_data |= sevSeg; // bitwise OR the result with the output short
tens_data = tens_data << 8; //shift by 8 so it's almost in the right place (see below)
sevSeg = toSegments(temp/10); //convert tens of temperature to 7-segment logic
tens_data |= sevSeg; // bitwise OR the result with the output short
tens_data = tens_data << 1; //shift by 1 so everything is in the right place
tens_data |= 0b0000000100000000; //set NPN for tens pair to active and ones NPN to inactive
//update ones bit string
ones_data = 0b0000000000000000; //reset to all 0s
sevSeg = toSegments(hum%10); //convert ones of humidity to 7-segment logic
ones_data |= sevSeg; // bitwise OR the result with the output short
ones_data = ones_data << 8; //shift by 8 so it's almost in the right place (see below)
sevSeg = toSegments(temp%10); //convert ones of temperature to 7-segment logic
ones_data |= sevSeg; // bitwise OR the result with the output short
ones_data = ones_data << 1; //shift by 1 so everything is in the right place
ones_data |= 0b0000000000000001; //set NPN for ones pair to active and tens NPN to inactive
oldMillis = millis(); //I don't much care about the few ms lost
} //during data acquisition
if(btnPress){
//shift out the next batch of data to the display
digitalWrite(LATCH, 0); //Set latch pin LOW so nothing gets shifted out
if(firstPair){
shiftOut(DATA, CLK, tens_data); //Shift out LED states for 7-segments of tens
firstPair = false;
}
else{
shiftOut(DATA, CLK, ones_data); //Shift out LED states for 7-segments of ones
firstPair = true;
}
digitalWrite(LATCH, 1); //sent everything out in parallel
delay(LED_DELAY); //wait for some time until switching to the other displays
if((millis()-sleepTimer) > 6000){ //Sleep after 6s display time
goToSleep();
}
}
else{
if(measurements > 5){
goToSleep();
}
}
}
DHT11 hygrometer schematic
Okay so thanks to the input of Mat I tried substituting the DHT11 library with something more sleek, which took me a while to get up and running. I ended up using this as a base, edited around a bit and commented heavily for my benefit.
I added my updated code below for anyone interested (thanks for pointing out the correct highlighting issue), there's also a github with the rest of the design files.
Seems the library is really heavy, as the compiler output shows:
Compiler output:
Sketch uses 2354 bytes (66%) of program storage space. Maximum is 3520 bytes.
Global variables use 104 bytes (40%) of dynamic memory, leaving 152 bytes for local variables. Maximum is 256 bytes.
Code:
/*
Humidity/Temperature sensor setup with DHT-11
Two digits for humidity
Two digits for temperature
Button to wake up from sleep
NPNs activated via 8th bit in 74HC595s, always alternating
Author: ElectroBadger
Date: 2021-11-09
Version: 2.0
*/
/*
Reduce power consumption:
- Run at 1 MHz internal clock
- Turn off ADC
- Use SLEEP_MODE_PWR_DOWN
*/
//#include "DHT.h" // DHT-11 sensor
#include <avr/sleep.h> // Sleep Modes
#include <avr/power.h> // Power management
#include <avr/wdt.h> // Doggy stuff
// define attiny pins
#define INT_PIN PB4
#define DATA PB1
#define SENSOR PB3
#define LATCH PB2
#define CLK PB0
// define other stuff
//#define SENSOR_TYPE DHT11
#define LED_DELAY 50
//fixed variables
//array lookup for number display; ascending order: 0, 1, 2, ...
const byte numLookup[] = {
0b01111110, //0
0b00110000, //1
0b01101101, //2
0b01111001, //3
0b00110011, //4
0b01011011, //5
0b01011111, //6
0b01110000, //7
0b01111111, //8
0b01111011 //9
};
// changing variables
short ones_data; // 16-bits for display of ones
short tens_data; // 16-bits for display of tens
byte sevSeg, measurements; // 7-segment bit pattern / wait time between LEDs [ms] / # of measurements taken
bool firstPair, btnPress; // tracks which pair of 7-segments is on; tracks button presses
uint32_t oldMillis, sleepTimer; // tracks the last acquisition time and wakeup time
byte humI, humD, tempI, tempD; // values of humidity and temperature (we're only gonna need integral parts but I need all for the checksum)
// Initialize sensor
//DHT dht(SENSOR, SENSOR_TYPE);
// Shifts 16 bits out MSB first, on the rising edge of the clock.
void shiftOut(int dataPin, int clockPin, short toBeSent) {
int i = 0;
int pinState = 0;
// Clear everything out just in case
digitalWrite(dataPin, 0);
digitalWrite(clockPin, 0);
// Loop through bits in the data bytes
for (i = 0; i <= 15; i++) {
digitalWrite(clockPin, 0);
// if the value AND a bitmask result is true then set pinState to 1
if (toBeSent & (1 << i)) {
pinState = 1;
}
else {
pinState = 0;
}
digitalWrite(dataPin, pinState); // sets the pin to HIGH or LOW depending on pinState
digitalWrite(clockPin, 1); // shifts bits on upstroke of clock pin
digitalWrite(dataPin, 0); // zero the data pin after shift to prevent bleed through
}
digitalWrite(clockPin, 0); // Stop shifting
}
void start_signal(byte SENSOR_PIN) {
pinMode(SENSOR_PIN, OUTPUT); // set pin as output
digitalWrite(SENSOR_PIN, LOW); // set pin LOW
delay(18); // wait 18 ms
digitalWrite(SENSOR_PIN, HIGH); // set pin HIGH
pinMode(SENSOR_PIN, INPUT_PULLUP); // set pin as input and pull to VCC (10k)
}
boolean read_dht11(byte SENSOR_PIN) {
uint16_t rawHumidity = 0;
uint16_t rawTemperature = 0;
uint8_t checkSum = 0;
uint16_t data = 0;
unsigned long startTime;
for (int8_t i = -3; i < 80; i++) { // loop 80 iterations, representing 40 bits * 2 (HIGH + LOW)
byte high_time; // stores the HIGH time of the signal
startTime = micros(); // stores the time the data transfer started
// sensor should pull line LOW and keep for 80µs (while SENSOR_PIN == HIGH)
// then pull HIGH and keep for 80µs (while SENSOR_PIN == LOW)
// then pull LOW again, aka send data (while SENSOR_PIN == HIGH)
do { // waits for sensor to respond
high_time = (unsigned long)(micros() - startTime); // update HIGH time
if (high_time > 90) { // times out after 90 microseconds
Serial.println("ERROR_TIMEOUT");
return;
}
}
while (digitalRead(SENSOR_PIN) == (i & 1) ? HIGH : LOW);
// actual data starts at iteration 0
if (i >= 0 && (i & 1)) { // if counter is odd, do this (only counts t_on time and ignores t_off)
data <<= 1; // left shift data stream by 1 since we are at a the next bit
// TON of bit 0 is maximum 30µs and of bit 1 is at least 68µs
if (high_time > 30) {
data |= 1; // we got a one
}
}
switch ( i ) {
case 31: // bit 0-16 is humidity
rawHumidity = data;
break;
case 63: // bit 17-32 is temperature
rawTemperature = data;
case 79: // bit 33-40 is checksum
checkSum = data;
data = 0;
break;
}
}
// Humidity
humI = rawHumidity >> 8;
rawHumidity = rawHumidity << 8;
humD = rawHumidity >> 8;
// Temperature
tempI = rawTemperature >> 8;
rawTemperature = rawTemperature << 8;
tempD = rawTemperature >> 8;
if ((byte)checkSum == (byte)(tempI + tempD + humI + humD)) {
return true;
}
else {
return false;
}
}
void goToSleep() {
// Turn off 7-segments and NPNs
digitalWrite(LATCH, 0);
shiftOut(DATA, CLK, 0b0000000000000000);
digitalWrite(LATCH, 1);
set_sleep_mode (SLEEP_MODE_PWR_DOWN); // Set deep sleep mode
ADCSRA = 0; // turn off ADC
power_all_disable (); // power off ADC, Timer 0 and 1, serial interface
cli(); // timed sequence coming up, so disable interrupts
btnPress = false; // reset button flag
measurements = 0; // reset measurement counter
resetWatchdog (); // get watchdog ready
sleep_enable (); // ready to sleep
sei(); // interrupts are required now
sleep_cpu (); // sleep
sleep_disable (); // precaution
power_all_enable (); // power everything back on
}
ISR(PCINT0_vect) {
btnPress = true;
sleepTimer = millis();
}
// watchdog interrupt
ISR(WDT_vect) {
wdt_disable(); // disable watchdog
}
void resetWatchdog() {
MCUSR = 0; //clear various "reset" flags
WDTCR = bit (WDCE) | bit (WDE) | bit (WDIF); //allow changes, disable reset, clear existing interrupt
WDTCR = bit (WDIE) | bit (WDP3) | bit (WDP0); //set WDIE, and 8 seconds delay
wdt_reset();
}
void setup() {
resetWatchdog(); // do this first in case WDT fires
cli(); // disable interrupts during setup
pinMode(INT_PIN, INPUT_PULLUP); // set interrupt pin as input w/ internal pullup
pinMode(DATA, OUTPUT); //set serial data as output
pinMode(CLK, OUTPUT); //set shift register clock as output
pinMode(LATCH, OUTPUT); //set output register (latch) clock as output
pinMode(SENSOR, INPUT); //set DHT11 pin as input
// Interrupts
PCMSK = bit(INT_PIN); // enable interrupt handler (ISR)
GIFR |= bit(PCIF); // clear any outstanding interrupts
GIMSK |= bit(PCIE); // enable PCINT interrupt in the general interrupt mask
//default conditions
/* bit 0-6: ones digits
bit 7: NPN for units digits
bit 8-14: ones digits
bit 15: NPN for tens digits
*/
ones_data = 0b0000000000000000;
tens_data = 0b0000000000000000;
measurements = 0;
firstPair = true;
btnPress = false;
oldMillis = 0;
sleepTimer = 0;
humI = 0;
humD = 0;
tempI = 0;
tempD = 0;
// Start sensor
//dht.begin();
sei(); // enable interrupts after setup
}
void loop() {
if ((millis() - oldMillis) > 1000) {
// slow sensor, so readings may be up to 2 seconds old
//byte hum = dht.readHumidity(); //Read humidity
//byte temp = dht.readTemperature(); //Read temperatuer in °C
delay(2000); // wait for DHT11 to start up
start_signal(SENSOR); // send start sequence
if(read_dht11(SENSOR)){
// update tens bit string
tens_data = 0b0000000000000000; // reset to all 0s
tens_data |= numLookup[humI / 10]; // bitwise OR the result with the output short
tens_data = tens_data << 8; // shift by 8 so it's almost in the right place (see below)
tens_data |= numLookup[tempI / 10]; // bitwise OR the result with the output short
tens_data = tens_data << 1; // shift by 1 so everything is in the right place
tens_data |= 0b0000000100000000; // set NPN for tens pair to active and ones NPN to inactive
// update ones bit string
ones_data = 0b0000000000000000; // reset to all 0s
ones_data |= numLookup[humI % 10]; // bitwise OR the result with the output short
ones_data = ones_data << 8; // shift by 8 so it's almost in the right place (see below)
ones_data |= numLookup[tempI % 10]; // bitwise OR the result with the output short
ones_data = ones_data << 1; // shift by 1 so everything is in the right place
ones_data |= 0b0000000000000001; // set NPN for ones pair to active and tens NPN to inactive
}
else{
tens_data = 0b1001111110011100;
ones_data = 0b0000101000001011;
}
oldMillis = millis(); // I don't much care about the few ms lost during data acquisition
}
if (btnPress) {
// shift out the next batch of data to the display
digitalWrite(LATCH, 0); // Set latch pin LOW so nothing gets shifted out
if (firstPair) {
shiftOut(DATA, CLK, tens_data); // shift out LED states for 7-segments of tens
firstPair = false; // reset first digit flag
}
else {
shiftOut(DATA, CLK, ones_data); //Shift out LED states for 7-segments of ones
firstPair = true; //set first digit flag
}
digitalWrite(LATCH, 1); //sent everything out in parallel
delay(LED_DELAY); //wait for some time until switching to the other displays
if ((millis() - sleepTimer) > 6000) { //Sleep after 6s display time
goToSleep();
}
}
else {
if (measurements > 3) {
goToSleep();
}
}
}
I am using a version of an Arduino CNC board that is found here to drive 4 wheels on a small wheeled robot. The shield came with A4988 stepper drivers and I got them to work fine, however the motors were much louder than intended so I went searching for another driver and found the TMC2208. I saw that the pin-outs were the same as long as the boards themselves aligned the enable pins on the shield.
The problem however seems to be in the code though. I am using the Accelstepper library in my code and everything works fine with the A4988 driver board. When I swapped just the boards, nothing happened in my program. I went looking on the TMCStepper library git to try and find some help. I managed to at lease get the steppers working using a version of the 'Simple' example. I tried to take out as much as possible while still being able to move the motors so that I could use it in my actual program. I still am not having any luck.
When I run this program
#include <TMCStepper.h>
#define EN_PIN 8 // Enable
#define DIR_PIN1 5 // Direction
#define STEP_PIN1 2 // Step
#define DIR_PIN2 6 // Direction
#define STEP_PIN2 3
#define DIR_PIN3 7 // Direction
#define STEP_PIN3 4
#define DIR_PIN4 13 // Direction
#define STEP_PIN4 12
#define SW_RX1 55 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX1 60 // TMC2208/TMC2224 SoftwareSerial transmit pin
#define SW_RX2 56 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX2 61
#define SW_RX3 57 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX3 62
#define SW_RX4 58 // TMC2208/TMC2224 SoftwareSerial receive pin
#define SW_TX4 63
#define R_SENSE 0.11f // Match to your driver
TMC2208Stepper driverX(SW_RX1, SW_TX1, R_SENSE);
TMC2208Stepper driverY(SW_RX1, SW_TX1, R_SENSE);
TMC2208Stepper driverZ(SW_RX1, SW_TX1, R_SENSE);
TMC2208Stepper driverA(SW_RX1, SW_TX1, R_SENSE); // Software serial
void setup() {
pinMode(EN_PIN, OUTPUT);
pinMode(STEP_PIN1, OUTPUT);
pinMode(DIR_PIN1, OUTPUT);
pinMode(STEP_PIN2, OUTPUT);
pinMode(DIR_PIN2, OUTPUT);
pinMode(STEP_PIN3, OUTPUT);
pinMode(DIR_PIN3, OUTPUT);
pinMode(STEP_PIN4, OUTPUT);
pinMode(DIR_PIN4, OUTPUT);
digitalWrite(EN_PIN, LOW); // Enable driver in hardware
driverX.begin();
driverY.begin();
driverZ.begin();
driverA.begin(); // SPI: Init CS pins and possible SW SPI pins
// UART: Init SW UART (if selected) with default 115200 baudrate
driverX.microsteps(16); // Set microsteps to 1/16th
}
void loop() {
// Run 5000 steps and switch direction in software
for (uint16_t i = 5; i>0; i++) {
digitalWrite(STEP_PIN1, HIGH);
digitalWrite(STEP_PIN2, HIGH);
digitalWrite(STEP_PIN3, HIGH);
digitalWrite(STEP_PIN4, HIGH);
delayMicroseconds(160);
digitalWrite(STEP_PIN1, LOW);
digitalWrite(STEP_PIN2, LOW);
digitalWrite(STEP_PIN3, LOW);
digitalWrite(STEP_PIN4, LOW);
delayMicroseconds(160);
}
the motors just continuously spin, so I know that the drivers actually work.
My main code is below.
#include <AccelStepper.h>
#include <TMCStepper.h>
const int stepperCount = 4;
AccelStepper BLStepper(AccelStepper::DRIVER, 2, 5);
AccelStepper FLStepper(AccelStepper::DRIVER, 3, 6);
AccelStepper FRStepper(AccelStepper::DRIVER, 4, 7);
AccelStepper BRStepper(AccelStepper::DRIVER, 12, 13);
#define R_SENSE 0.11f
// define pins numbers
#define stepX_PIN 2
#define dirX_PIN 5
#define stepX_RX 55
#define dirX_TX 60
#define stepY_PIN 3
#define dirY_PIN 6
#define stepY_RX 56
#define dirY_TX 61
#define stepZ_PIN 4
#define dirZ_PIN 7
#define stepZ_RX 57
#define dirZ_TX 62
#define stepA_PIN 12
#define dirA_PIN 13
#define stepA_RX 58
#define dirA_TX 63
#define enPin_PIN 8
TMC2208Stepper driverX(stepX_RX, dirX_TX, R_SENSE);
TMC2208Stepper driverY(stepY_RX, dirY_TX, R_SENSE);
TMC2208Stepper driverZ(stepZ_RX, dirZ_TX, R_SENSE);
TMC2208Stepper driverA(stepA_RX, dirA_TX, R_SENSE);
//Front left wheel
//const int stepX_PIN = 2;
//const int dirX_PIN = 5;
//Front right wheel
//const int stepY_PIN = 3;
//const int dirY_PIN = 6;
//Back left wheel
//const int stepZ_PIN = 4;
//const int dirZ_PIN = 7;
//Back right wheel
//const int stepA_PIN = 12;
//const int dirA_PIN = 13;
//const int enPin_PIN = 8;
char split = ':'; //this is the character that would be used for seperating the different parts of your commands
//the syntax for commands would be: command:value1:value2
int listSize = 5; //the amount of commands in the list
String commands[] = {"hello", "add", "sub", "YMOV", "XMOV"}; //the list of every command name
void setup()
{
Serial.begin(115200); //sets the data transfer rate for the serial interface
//9600 is good for basic testing, but should be as high
//as possible for both devices
FRStepper.setMaxSpeed(300);
FRStepper.setAcceleration(200);
BRStepper.setMaxSpeed(300);
BRStepper.setAcceleration(200);
FLStepper.setMaxSpeed(300);
FLStepper.setAcceleration(200);
BLStepper.setMaxSpeed(300);
BLStepper.setAcceleration(200);
pinMode(stepX_PIN, OUTPUT);
pinMode(dirX_PIN, OUTPUT);
pinMode(stepY_PIN, OUTPUT);
pinMode(dirY_PIN, OUTPUT);
pinMode(stepZ_PIN, OUTPUT);
pinMode(dirZ_PIN, OUTPUT);
pinMode(stepA_PIN, OUTPUT);
pinMode(dirA_PIN, OUTPUT);
pinMode(enPin_PIN, OUTPUT);
digitalWrite(enPin_PIN, LOW);
digitalWrite(dirX_PIN, HIGH);
digitalWrite(dirY_PIN, HIGH);
digitalWrite(dirZ_PIN, HIGH);
digitalWrite(dirA_PIN, HIGH);
//digitalWrite(stepX_PIN, HIGH);
//digitalWrite(stepY_PIN, HIGH);
//digitalWrite(stepZ_PIN, HIGH);
//digitalWrite(stepA_PIN, HIGH);
driverX.begin();
driverY.begin();
driverZ.begin();
driverA.begin();
FRStepper.setEnablePin(enPin_PIN);
FLStepper.setEnablePin(enPin_PIN);
BRStepper.setEnablePin(enPin_PIN);
BLStepper.setEnablePin(enPin_PIN);
FRStepper.enableOutputs();
FLStepper.enableOutputs();
BRStepper.enableOutputs();
BLStepper.enableOutputs();
}
void loop()
{
CommCheck(); //checks serial buffer for data commands
runMotors();
}
void runMotors()
{
if ((FLStepper.distanceToGo() != 0) || (FRStepper.distanceToGo() != 0) || (BLStepper.distanceToGo() != 0) || (BRStepper.distanceToGo() != 0))
{
FRStepper.enableOutputs();
FLStepper.enableOutputs();
BRStepper.enableOutputs();
BLStepper.enableOutputs();
FLStepper.run();
BLStepper.run();
FRStepper.run();
BRStepper.run();
if ((FLStepper.distanceToGo() == 0) && (FRStepper.distanceToGo() == 0))
{
CommConfirm();
}
}
//if (movementComplete == true)
//{
//CommConfirm();
//}
//if (
//if ((FLStepper.distanceToGo() == 0) || (FRStepper.distanceToGo() == 0) || (BLStepper.distanceToGo() == 0) || (BRStepper.distanceToGo() == 0))
//{
//CommConfirm();
//}
}
void CommCheck()
{
if(Serial.available()) //checks to see if there is serial data has been received
{
//int len = Serial.available(); //stores the character lengh of the command that was sent
//this is used for command parsing later on
String command = Serial.readString(); //stores the command as a text string
int len = command.length();
//Serial.println(command);
Serial.flush();
//command.remove(len-2,1); //removes characters added by the pi's serial data protocol
//command.remove(0,2);
//len -= 3; //updates the string length value for parsing routine
int points[2] = {0, 0}; //offset points for where we need to split the command into its individual parts
for(int x = 0; x < len; x++) //this loop will go through the entire command to find the split points based on
{ //what the split variable declared at the top of the script is set to.
//Serial.print("Char ");
//Serial.print(x);
//Serial.print("- ");
//Serial.println(command[x]);
if(command[x] == split) //this goes through every character in the string and compares it to the split character
{
if(points[0] == 0) //if the first split point hasn't been found, set it to the current spot
{
points[0] = x;
}
else //if the first spot was already found, then set the second split point
{ //this routine is currently only set up for a command syntax that is as follows
points[1] = x; //command:datavalue1:datavalue2
}
}
}
CommParse(command, len, points[0], points[1]); //now that we know the command, command length, and split points,
} //we can then send that information out to a routine to split the data
} //into individual values.
void CommParse(String command, int len, int point1, int point2)
{
//Serial.print("Command Length: ");
//Serial.println(len);
//Serial.print("Split 1: ");
//Serial.println(point1);
//Serial.print("Split 2: ");
//Serial.println(point2);
String com = command; //copy the full command into all 3 parts
String val1 = command; //this is needed for the string manipulation
String val2 = command; //that follow
com.remove(point1, len - point1); //each of these use the string remove to delete
val1.remove(point2, len - point2); //the parts of the command that aren't needed
val1.remove(0, point1 + 1); //basically splitting the command up into its
val2.remove(0, point2 + 1); //individual pieces
val2.remove(val2.length()-1,1);
CommLookup(com, val1, val2); //these pieces are then sent to a lookup routine for processing
}
void CommLookup(String com, String val1, String val2)
{
int offset = 255; //create a variable for our lookup table's offest value
//we set this to 255 because there won't be 255 total commands
//and a valid command can be offset 0, so it's just to avoid
//any possible coding conflicts if the command sent doesn't
//match anything.
for(int x = 0; x < listSize; x++) //this goes through the list of commands and compares
{ //them against the command received
if(commands[x] == com)
{
offset = x; //if the command matches one in the table, store that command's offset
}
}
switch(offset) //this code compares the offset value and triggers the appropriate command
{
case 0: //essentially a hello world. | Syntax: hello:null:null
CommHello(); //this activates the hello world subroutine | returns Hello!
break;
case 1: //adds both values together and return the sum. | Syntax: add:value1:value2
CommAdd(val1.toInt(), val2.toInt()); //this activates the addition subroutine | returns value1 + value2
break;
case 2: //subtracts both values and return the difference | Syntax: subtract:value1:value2
CommSub(val1.toInt(), val2.toInt()); //this activates the subtraction subroutine | returns value1 - value2
break;
case 3:
yMovement(val1.toInt(), val2.toInt());
break;
case 4:
xMovement(val1.toInt(), val2.toInt());
default: //this is the default case for the command lookup and will only
Serial.println("Command not recognized"); //trigger if the command sent was not known by the arduino
break;
}
}
void CommHello() //each of these routines are what will be triggered when they are successfully processed
{
Serial.println("Hello!");
CommConfirm();
}
void CommAdd(int val1, int val2)
{
Serial.println(val1 + val2);
CommConfirm();
}
void CommSub(int val1, int val2)
{
Serial.println(val1 - val2);
CommConfirm();
}
void yMovement(int val1, int val2)
{
if (val1 < 0) {
//Serial.println("YMOVNEG");
int yMoveNew = (val1 * (-20.72));
//Serial.println(val1 * (-1));
//delay(500);
FRStepper.move(-yMoveNew);
BRStepper.move(-yMoveNew);
FLStepper.move(-yMoveNew);
BLStepper.move(-yMoveNew);
}
else {
//Serial.println(val1);
int yMoveNew = (val1 * (20.72));
//Serial.println(yMoveNew);
//Serial.println(val1);
//delay(500);
FRStepper.move(yMoveNew);
BRStepper.move(yMoveNew);
FLStepper.move(yMoveNew);
BLStepper.move(yMoveNew);
}
}
void xMovement(int val1, int val2)
{
if (val1 < 0) {
//Serial.println(val1);
int xMoveNew = (val1 * (-20.72));
//Serial.println(xMoveNew);
//Serial.println(val1 * (-1));
//delay(1000);
FLStepper.move(-xMoveNew);
BLStepper.move(xMoveNew);
FRStepper.move(xMoveNew);
BRStepper.move(-xMoveNew);
//delayMicroseconds(500);
}
else {
int xMoveNew = (val1 * (20.72));
//Serial.println(val1);
//delay(1000);
FLStepper.move(xMoveNew);
BLStepper.move(xMoveNew);
FRStepper.move(xMoveNew);
BRStepper.move(xMoveNew);
//delayMicroseconds(500);
}
}
void CommConfirm()
{
Serial.println("Done");
delay(750);
}
When I run my code, a Pi sends two values that equals step counts, however with the new drivers nothing happens. I tried also looking at and following the AccelStepper example on the git but I guess I have something wrong.
Any help would be appreciated.
I have a rotary encoder and a DC gear motor connected to my Arduino UNO. I would like to rotate the DC motor at a certain angle. As I right now, I have written a code that reads the position of my encoder as I rotate it and prints out the position and the angle. I have also written code that runs the dc motor at fixed amount of time.
I would like to rotate the dc motor at a certain angle. For example, if I input 90 degrees my motor should rotate 90 degrees and stop.
I'm using pin 2 and pin 3 for my channel A and B (ENCODER)
I'm using pin 9 to control my dc motor.
I have no clue how to approach this... any thoughts?
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int lcd_case = 0;
volatile int timeToRun = 0;
int motorPin = 6;
#define BTN_RIGHT 0
#define BTN_LEFT 1
#define BTN_UP 2
#define BTN_DOWN 3
#define BTN_SELECT 4
#define BTN_NONE 5
#define SELECT 6
#define RESET 7
#define PIN
#define encoderPinA 2
#define encoderPinB 3
#define CPR 256
volatile int counter =0;
volatile boolean flag;
volatile int var_degrees =0;
void setup() {
pinMode(3, OUTPUT);
pinMode(encoderPinA, INPUT);
pinMode(encoderPinB, INPUT);
Serial.begin (9600);
attachInterrupt(digitalPinToInterrupt(encoderPinA), isr_2, RISING);
lcd.clear();
}
void loop() {
if(flag == true){
var_degrees = ((360/256.0)*counter);
Serial.println(var_degrees);
//lcd.setCursor(0, 1);
//lcd.print("Degrees: ");
//lcd.setCursor(9, 1);
//lcd.print(var_degrees);
flag = false;
}
lcd_case = readButtons();
int read_button = analogRead (0);
//Depending on which button we pressed, we performan action
switch (lcd_case) {
case BTN_RIGHT:
{
break;
}
case BTN_LEFT:
{
break;
}
case BTN_UP:
{
timeToRun = timeToRun +1;
lcd.setCursor(0, 1);
lcd.print("Degrees: ");
lcd.setCursor(9, 1);
lcd.print(timeToRun);
delay(500);
break;
}
case BTN_DOWN:
{
if (timeToRun > 0) {
timeToRun = timeToRun - 1;
lcd.setCursor(0, 1);
lcd.print("Degrees: ");
lcd.setCursor(9, 1);
lcd.print(timeToRun);
delay(500);
break;
}
}
case BTN_SELECT:
{
analogWrite(motorPin, 255);
// I NEED TO ROTATE MOTOR BASED ON ANGLE IN ENCODER
delay(timeToRun * 100); //ONLY ROTATES DC MOTOR IN SECONDS
break;
}
case RESET:
{
break;
}
}
}
//Interrupts
void isr_2(){
flag = true;
if(digitalRead(encoderPinA) == HIGH){
if(digitalRead(encoderPinB) == LOW){
counter = counter -1; //COUNTER CLOCK WISE
}
else{
counter = counter +1; //CLOCK WISE
}
}
else{ //IF PIN A IS LOW
if(digitalRead(encoderPinB) == LOW){
counter = counter +1; //CLOCK WISE
}
else{
counter = counter -1 ; //COUNTER CLOCK WISE
}
}
}
int readButtons() {
int read_button;
read_button = analogRead (0);
if (read_button < 50) {
return BTN_RIGHT;
}
if (read_button < 195) {
return BTN_UP;
}
if (read_button < 400) {
return BTN_DOWN;
}
if (read_button < 600) {
return BTN_LEFT;
}
if (read_button < 800) {
return BTN_SELECT;
}
else
return BTN_NONE;
}
It's good that you are correctly reading the position of the armature of your motor. Now is the time to use PID and closed loop! Tuned PID is a controller that helps your motor to go to the desired position at the best possible time with the lowest possible overshoot(error) It takes a control course to learn all of this. You will basically need a feedback loop that takes the "desired angle", give it to the controller which moves the motor. Then you get the current position of the motor, which will be fed back to the origin of the system. Your "desired angle" minus "current angle" will be how much your motor should move each time the micro controller go over the loop.
Here is how the feedback loop looks like:
And here is link to learn control. Good luck!
Control Tutorials
Edit 2: I should probably give you an intro on what PID is as well. PID controller is made of three different components:
Proportional
Integral
Derivative
Each time you get your "Desired Angle" - "Actual Angle" or "e" as shown in diagram, you will times it by Kp. Find its derivative with respect to previous e and times it by Kd, and find the integral of the errors and times it by Ki. You can start by ignoring Ki and integral, and add it if it was needed later. After you got Kpe+Kdd(e)/dt, this values is the percentage of power you will output to your motor. Kp and Kd and Ki is where the real engineering comes into play. You should find them using the transfer function of your system and fine-tune them in MatLab or a similar software. These values are usually low (less than 1). It really depends on your system. For my motor, they were Kp=0.001 and Kd=0.02
I am working on a stereo controller and have 1 rotary encoder with a push button. When I push the button it cycles through the options and the rotary encoder lets me set the intensity. I want the individual intensities to remain when I am switching back and forth. When I turn the bass to 50% and then set the volume to 80% I want to come back and the base still be at 50%. The problem I am having is that the intensities are transferring over.
For prototyping I am using 3 LEDS. I can set individual brightness but when I go to change the next LED it automatically changes to the intensity of the previous LED.
The reasoning behind this is that when I set the bass and treble and the volume I don't want the values jumping around when I come back to change something. I want to pick off where it left off.
I think the structure I am going for is a counter based on cases. A common variable outside the case is incremented by the rotary encoder and then stored in case if that is possible.
/*
** Rotary Encoder Example
** Use the Sparkfun Rotary Encoder to vary brightness of LED
**
** Sample the encoder at 200Hz using the millis() function
*/
int brightness = 0; // how bright the LED is, start at half brightness
int fadeAmount = 30; // how many points to fade the LED by
unsigned long currentTime;
unsigned long loopTime;
const int pin_A = 4; // pin 12
const int pin_B = 5; // pin 11
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;
const int green = 11;
const int blue = 10;
const int red=9;
int last_bright=0;
int mode = 0; // Selector State (Initial state = ALL OFF)
int val = 0; // Pin 13 HIGH/LOW Status
int butState = 0; // Last Button State
int modeState = 0;
int selected=710;
int greenvol=0;
int redvol=0;
int bluevol=0;
int select_bright=0;
void setup() {
// declare pin 9 to be an output:
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(pin_A, INPUT);
pinMode(pin_B, INPUT);
currentTime = millis();
loopTime = currentTime;
}
void loop() {
// get the current elapsed time
currentTime = millis();
brightness=select_bright;
if(currentTime >= (loopTime + 5)){
// 5ms since last check of encoder = 200Hz
encoder_A = digitalRead(pin_A); // Read encoder pins
encoder_B = digitalRead(pin_B);
if((!encoder_A) && (encoder_A_prev)){
// A has gone from high to low
if(encoder_B) {
// B is high so clockwise
// increase the brightness, dont go over 255
if(brightness + fadeAmount <= 255) brightness += fadeAmount;
}
else {
// B is low so counter-clockwise
// decrease the brightness, dont go below 0
if(brightness - fadeAmount >= 0) brightness -= fadeAmount;
}
}
encoder_A_prev = encoder_A; // Store value of A for next time
// set the brightness of pin 9:
analogWrite(selected, brightness);
last_bright=brightness;
loopTime = currentTime; // Updates loopTime
}
// end of rotary encoder
val = digitalRead(8);
delay(5);
// If we see a change in button state, increment mode value
if (val != butState && val == HIGH){
mode++;
}
butState = val; // Keep track of most recent button state
// No need to keep setting pins *every* loop
if (modeState != mode)
// If no keys have been pressed yet don't execute
// the switch code below
{
switch ( mode ) {
case 2:
selected=red;
select_bright=redvol;
redvol=last_bright;
break;
case 3:
selected=green;
select_bright=greenvol;
greenvol = last_bright;
break;
default:
selected=blue;
select_bright=bluevol;
bluevol = last_bright;
mode = 1;
break;
}
}
}
I'd store the brightness value in an array and then use an index to change only one led.
Here is a (i hope) working example. Try it and see if it fits your needs ;)
I made some other changes (you can see them in the comments). Anyway I suggest you to add at least
debouncing on the encoder and the button pins
the complete encoder checking, i.e. check if either A or B changed, and in both directions.
Here is the code; just let me know ;)
byte fadeAmount = 30;
const byte pin_button = 8;
const byte pin_A = 4; // pin 12
const byte pin_B = 5; // pin 11
unsigned long loopTime;
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;
// Array to store the brightness of the
// red (0), green (1) and blue (2) leds
byte brightnesses[3];
byte lastbrightnesses[3];
byte currentLed;
// Pins for red (0), green (1) and blue (2) leds
byte led_pins[] = {9, 10, 11};
void setup() {
pinMode(pin_button, INPUT);
pinMode(pin_A, INPUT);
pinMode(pin_B, INPUT);
// set the brightnesses to their initial states
// and the lastbrightnesses to ANOTHER value
for (currentLed=0; currentLed<3; i++)
{
pinMode(led_pins[currentLed], OUTPUT);
brightnesses[currentLed] = 255;
lastbrightnesses[currentLed] = 0;
}
currentLed = 0;
loopTime = millis() - 5;
}
void loop() {
// I prefer this instead of yours
// because this is overflow-safe
if((millis() - loopTime) >= 5) {
loopTime += 5;
// Check encoder
encoder_A = digitalRead(pin_A);
encoder_B = digitalRead(pin_B);
if((!encoder_A) && (encoder_A_prev)){
// A has gone from high to low
if(encoder_B) {
// B is high so clockwise
// Again, this is overflow-safe
// And it compensates for not reaching the end of the values
if(brightnesses[currentLed] <= 255 - fadeAmount)
brightnesses[currentLed] += fadeAmount;
else
brightnesses[currentLed] = 255;
}
else {
// B is low so counter-clockwise
// decrease the brightness, dont go below 0
if(brightnesses[currentLed] >= fadeAmount)
brightnesses[currentLed] -= fadeAmount;
else
brightnesses[currentLed] = 0;
}
}
encoder_A_prev = encoder_A; // Store value of A for next time
// I'd read the button every 5ms too
val = digitalRead(pin_button);
if (val != butState && val == HIGH){
currentLed++;
if (currentLed >= 3) currentLed = 0;
butState = val;
}
}
// Here you can also check only currentLed instead
// of every led if you can only change it through
// the encoder
byte i;
for (i=0; i<3; i++)
{
if (lastbrightnesses[i] != brightnesses[i])
{
analogWrite(led_pins[i], brightnesses[i]);
lastbrightnesses[i] = brightnesses[i];
}
}
}
I am trying to get my LED to flash when the hypotenuse enters certain range. But it seems like it's passing that value of hypotenuse range more times than it should. LED Flashes for about good 30 -40 times before it goes back to being normal. Not sure how to fix this problem.
This is my processing code:
import processing.serial.*;
float r_height; // rise of the slope
float r_width; // run of the slope
float hypotnuse; // hypotenuse of the right angle
int d = 20; // diameter of the chocolate
float x ; // x of the chocolate destination
float y ; // y of the chocolate destination
int ledGlow; // how much the LED will glow
Serial myPort; // serial port object
void setup () {
size (510, 510); // size of the canvas
String portName = Serial.list()[8]; // my arduino port
myPort = new Serial(this, portName, 9600);
background (0); // color of the background
fill(204); // fill of the ellipse
ellipseMode (CORNER); //Ellipse mode
x = 0; //The placement on initial X for chocolate
y = 0; // the placement on initial Y for chocolate
ellipse (x, y, d, d); // ellipse
frameRate (30);
}
void draw () {
r_height = mouseY - y; // rise
r_width = mouseX - x; //run
hypotnuse = sqrt (( (sq(r_height)) + (sq (r_width)))); //A^2 +B^2 = C^2
ledGlow = 255 - (round (hypotnuse/2.84)); // flipping the values
myPort.write(ledGlow); // The value being sent to the Arduino
println (ledGlow);
}
This is the arduino code:
float val; // Data received from the serial port
int ledPin = 9;
void setup() {
pinMode(ledPin, OUTPUT); // Set pin as OUTPUT
Serial.begin(9600); // Start serial communication at 9600 bps
}
void loop() {
if (Serial.available())
{ // If data is available to read,
val = Serial.read(); // read it and store it in val
// long steps2move = val.toInt();
}
if (val > 230) {
analogWrite (ledPin, 255) ; // I have already tried digitalWrite
delay (100);
analogWrite (ledPin, 1) ;
delay (100);
}
else if (val < 230) {
analogWrite(ledPin, val);
}
}
UPDATED ARDUINO:
float val; // Data received from the serial port
int ledPin = 9; // Set the pin to digital I/O 13
unsigned long currentTime = 0;
unsigned long pastTime = 0;
int currentState = 0;
int wait = 0;
void setup() {
pinMode(ledPin, OUTPUT); // Set pin as OUTPUT
Serial.begin(9600); // Start serial communication at 9600 bps
}
void loop() {
if (Serial.available())
{ // If data is available to read,
val = Serial.read(); // read it and store it in val
// long steps2move = val.toInt();
}
if (val > 230) {
pastTime = currentTime;
currentTime = millis();
unsigned long timePassed = currentTime - pastTime;
if(timePassed >= wait)
{
switch(currentState )
{
case 0:
digitalWrite(9, HIGH);
wait = 500;
currentState = 1;
break;
case 1:
digitalWrite(9, LOW);
wait = 500;
currentState = 0;
break;
}
}
}
else if (val < 230) {
analogWrite(ledPin, val/2);
}
}
The processing code is presumably writing out to serial constantly. However, when the hypotenuse enters the range you've set, the Arduino has those delay() calls. I think that will be causing it to lag behind, so it keeps flashing while it clears the backlog of serial data that came in during the delays.
I think a better approach is to avoid using delay() at all, so the Arduino can handle the serial data as fast as possible. On each loop, it should first grab the latest serial data (if there is any). Based on that, it should figure out and store what the LED should currently be doing (i.e. whether it should be flashing, or else what brightness it should be).
After that (regardless of whether any serial data was actually received), the LED can be updated from the stored state. Remember not to use delay() for the flashing though. Instead, you could keep track of the last time it flashed on, and figure out if 100 ms has passed since then (using millis()). If so, switch it off. If another 100 ms has passed, switch it back on.
This approach decouples the flash timing from the serial data, so hopefully it should work better.