I made a simple 1 button LED dimmer and I would like to have the LED go back to full brightness after the button has not been touched for a set amount of time. But the code I came up with does not seem to be working as I cannot dim the LED
int buttonPin = 12;
int LEDPin = 3;
int buttonVal;
int LEDbright = 0;
int dt = 500;
int fdt = 60000;
void setup() {
// put your setup code here, to run once:
pinMode(buttonPin, INPUT);
pinMode(LEDPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
static unsigned long whenButtonWasTouchedMs = 0;
buttonVal = digitalRead(buttonPin);
Serial.print("Button = ");
Serial.print(buttonVal);
Serial.print(", ");
delay(dt);
if (buttonVal == 1) {
LEDbright = LEDbright + 20;
whenButtonWasTouchedMs = millis();
}
Serial.println(LEDbright);
//
if (LEDbright > 255) {
LEDbright = 255;
delay(dt);
}
unsigned long afterButtonWasTouchedMs = millis() - whenButtonWasTouchedMs;
if (afterButtonWasTouchedMs >= 60000) {
LEDbright = 0;
analogWrite(LEDPin, LEDbright);
}
}
Your question doesn't seem to line up with how the code was written. It looks like you want to do the opposite (have the light get brighter when the button is held down, and then switch off 60 seconds after the button was released).
Here's the code I came up with to help with your stated problem:
int buttonPin = 12;
int LEDPin = 3;
int buttonVal;
int whenButtonWasTouched;
unsigned int LEDbright = 255;
int dt = 500;
int fdt = 60000;
unsigned long whenButtonWasTouchedMs = 0;
void setup() {
// put your setup code here, to run once:
pinMode(buttonPin, INPUT);
pinMode(LEDPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
//static unsigned long whenButtonWasTouchedMs = 0;
buttonVal = digitalRead(buttonPin);
Serial.print("Button = ");
Serial.print(buttonVal);
Serial.print(", ");
delay(dt);
if (buttonVal == 1) {
LEDbright = LEDbright - 20;
whenButtonWasTouchedMs = millis();
}
//
if (LEDbright < 20 || LEDbright > 255) { // The LEDbright > 255 part is because sometimes there can be an integer overflow if we don't keep this.
LEDbright = 0;
}
Serial.println(LEDbright);
unsigned long afterButtonWasTouchedMs = millis() - whenButtonWasTouched;
if (afterButtonWasTouchedMs >= 60000) {
LEDbright = 255;
}
analogWrite(LEDPin, LEDbright);
}
As you can see I changed it so that analogWrite is not in the if statement, it checks for integer overflows, and prints out the adjusted value for the led brightness. To make it grow brighter as the button is held and then switch off after 60 seconds just change the minus sign to a plus sign in the LEDbright adjustment line, and change some of the other values around.
int buttonPin = 12;
int LEDPin = 3;
int buttonVal;
unsigned int LEDbright = 0;
int dt = 500;
int fdt = 60000;
unsigned long whenButtonWasTouchedMs = 0;
void setup() {
// put your setup code here, to run once:
pinMode(buttonPin, INPUT);
pinMode(LEDPin, OUTPUT);
Serial.begin(9600);
}
void loop() {
//static unsigned long whenButtonWasTouchedMs = 0;
buttonVal = digitalRead(buttonPin);
Serial.print("Button = ");
Serial.print(buttonVal);
Serial.print(", ");
delay(dt);
if (buttonVal == 1) {
LEDbright = LEDbright + 20;
whenButtonWasTouchedMs = millis();
}
if (LEDbright > 255) {
LEDbright = 255;
delay(dt);
}
Serial.println(LEDbright);
unsigned long afterButtonWasTouchedMs = millis() - whenButtonWasTouchedMs;
if (afterButtonWasTouchedMs >= 60000) {
LEDbright = 0;
}
analogWrite(LEDPin, LEDbright);
}
I'm currently working on a project that is mostly run on a Raspberry pi, but has tasks complete by microcontroller. Currently, my RPi is sending a string of integers separated by commas to a microcontroller (ESP 32 Thing plus), the microcontroller is then converting that into an intergern array and using those values to set the level of a PWM output. Simultaneously, the microcontroller is reading an analogue input and storing those values into another int array, this data needs to be sent back to the RPi. I've been trying for ages to convert this into a string to be sent back, which works for the most part using sprintf() and strcat(), but it only works when I have just the number values. It would be good to have commas separate the numbers, but as soon as I do that, I get a really weird out put and the numbers start changing from their actual value to "1792" or 44" and it cycles between them or if I us a float array then I get 6 variables correct and then the rest are changes to "512".
Its a lot to send but possibly better to see the whole thing.
#include <stdio.h>
// variables to hold, parse and manipulate data
const byte numChars = 64;
const byte stringLength = 255;
char receivedChars[1000];
char tempChars[1000];
char messageFromPC[stringLength] = {0};
int MyArray[] = {};
int LaserMeasurmentArray[200] = {};
char LaserMeasurmentString[] = "";
int BrakeArray [60] = {10,200,600,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,500,0,0,0};
int AccelleratingArray [60] = {10,200,600,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,500,0,0,0};
int TimeStamps[200] = {};
char TimeStampString = '0';
int i = 0;
int SizeOfArray = 0;
int MyArraySize = 0;
int Counter = 0;
int CounterLaser = 0;
//Clutch/Brake Setup
int ClutchPin = 33;
int BrakePin = 27;
int ButtonPin = 32;
int ButtonState = LOW;
int Delay = 10;
int PWM = 1023;
const int LaserPin = A0;
//Millis variables
unsigned long PreviousMillisAccel = 0;
unsigned long PreviousMillisLaser = 0;
unsigned long CurrentMillis = 0;
const int PeriodWrite = 8;
const int PeriodRead = 5;
//Action States
boolean newData = false;
boolean SendData = false;
boolean AccellerationInProgress = false;
boolean BrakingInProgress = false;
//============
void setup() {
Serial.begin(115200);
//ledcSetup(ledChannel, freq, resolution);
ledcSetup(1, 5000, 10);
ledcSetup(2, 5000, 10);
//ledcAttachPin(LED, ledChannel);
ledcAttachPin(ClutchPin, 1);
ledcAttachPin(BrakePin, 2);
pinMode(LaserPin, INPUT);
pinMode(ButtonPin, INPUT_PULLUP);
}
//============
void loop() {
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
//Serial.print(receivedChars);
//Serial.println();
parseData();
//showParsedData();
//ButtonPress();
ButtonState = HIGH;
while (ButtonState == HIGH) {
ButtonState = digitalRead(ButtonPin);
}//while
Serial.println();
Serial.print("Accellerating");
Serial.println();
PWMSignal();
Serial.println();
Serial.print("Deccellerating");
Serial.println();
PWMSignal2();
newData = false;
ButtonState = HIGH;
while (ButtonState == HIGH) {
ButtonState = digitalRead(ButtonPin);
}//While
SendReply();
}
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= stringLength) {
ndx = stringLength - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void parseData() { // split the data into its parts
i = 0;
String serialResponse = tempChars;
char buf[sizeof(tempChars)];
serialResponse.toCharArray(buf, sizeof(buf));
char *p = buf;
char *str;
while ((str = strtok_r(p, ",", &p)) != NULL && i < 1180 ){ // delimiter is the comma
MyArray[i] = atoi(str);
//Serial.println(str);
MyArraySize = i;
i++;
}//While
}//parseData
//============
void showParsedData() {
for(int i = 0; i < MyArraySize+1; i++){
Serial.print(MyArray[i]);
Serial.print(",");
}//For
Serial.println();
}
void PWMSignal(){
int Counter = 0;
CounterLaser = 0;
CurrentMillis = millis();
AccellerationInProgress = true;
while(AccellerationInProgress == true) {
CurrentMillis = millis();
if (Counter == 60){
AccellerationInProgress = false;
}//if
else if (CurrentMillis - PreviousMillisAccel >= PeriodWrite) {
ledcWrite(1, AccelleratingArray[Counter]);
//Serial.println(AccelleratingArray[Counter]);
Counter = Counter + 1;
PreviousMillisAccel = CurrentMillis;
}//else if
if (CurrentMillis - PreviousMillisLaser >= PeriodRead){
LaserMeasurmentArray[CounterLaser] = analogRead(LaserPin);
Serial.println(LaserMeasurmentArray[CounterLaser]);
TimeStamps [CounterLaser] = CurrentMillis;
PreviousMillisLaser = CurrentMillis;
CounterLaser = CounterLaser + 1;
}//if
}//While Accel
ledcWrite(1, 0);
}//PWMSignal
void PWMSignal2() {
int Counter = 0;
BrakingInProgress = true;
while(BrakingInProgress == true) {
CurrentMillis = millis();
if (Counter == 60){
BrakingInProgress = false;
}//if
else if (CurrentMillis - PreviousMillisAccel >= PeriodWrite) {
ledcWrite(2, BrakeArray[Counter]);
//Serial.println(BrakeArray[Counter]);
Counter = Counter + 1;
PreviousMillisAccel = CurrentMillis;
}//else if
if (CurrentMillis - PreviousMillisLaser >= PeriodRead){
LaserMeasurmentArray[CounterLaser] = analogRead(LaserPin);
Serial.println(LaserMeasurmentArray[CounterLaser]);
TimeStamps [CounterLaser] = CurrentMillis;
PreviousMillisLaser = CurrentMillis;
CounterLaser = CounterLaser + 1;
}//if
}//While Accel
ledcWrite(1, 0);
ledcWrite(2, 0);
}//PWMSignal2
void SendReply() {
//Serial.println("Laser Data");
//Serial.println(sizeof(LaserMeasurmentArray));
for (int i = 0; i<=200; i++){
Serial.println(LaserMeasurmentArray[i]);
}
for (int i = 0; i <= 200; i++){
int buff = LaserMeasurmentArray[i];
char str [7];
sprintf(str,"%u" ,buff);
strcat(LaserMeasurmentString,str);
strcat(LaserMeasurmentString, ",");
}
Serial.print(LaserMeasurmentString);
}//sendReply
If someone could point out what I am doing wrong or have misunderstood, that would be great, thank you.
I have a school assignment to create a stopwatch using Multifunction Shield. The functionality is simple: the leftmost button is for start/stop and the rightmost button is for resetting, if the stopwatch is stopped. The precision is 100ms.
My code is working as expected I thought, but my teacher returned it saying that I cannot guarantee that the code is executed every 100ms so that the stopwatch does not lag behind. What am I doing wrong?
There's a bit of a legacy code from previous HW, hope it's not a problem.
// Funshield Constants
// Constants for switching ON/OFF
constexpr int ON = LOW;
constexpr int OFF = HIGH;
// 7-Segs
constexpr int latchPin = 4;
constexpr int clockPin = 7;
constexpr int dataPin = 8;
// Buzzer
constexpr int buzzerPin = 3;
// LEDS
constexpr int firstPin = 13;
constexpr int secondPin = 12;
constexpr int thirdPin = 11;
constexpr int fourthPin = 10;
// Buttons
constexpr int firstButton = A1;
constexpr int secondButton = A2;
constexpr int thirdButton = A3;
// Trimr
constexpr int trimrPin = A0;
// Digits
constexpr int digits[11] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0xFF };
constexpr int digitsPos[4] = { 0x08, 0x04, 0x02, 0x01 };
// End of Funshield Constants
// Beginning of the Program
// Buttons Variables
unsigned int buttons[] = {firstButton, secondButton, thirdButton};
unsigned int lengthOfButtons = sizeof(buttons) / sizeof(buttons[0]);
unsigned int previousButtonState[] = {1, 1, 1};
// Global Variables
unsigned long int previousMillis = millis();
unsigned int numberDigits[] = {0, 0, 0, 0};
unsigned int interval = 100;
bool isRunning = false;
int numberLength = 0;
int digitIndex = 0;
int dotIndex = 1;
int number = 0;
int DISPLAY_DECIMAL_DOT = 0x7F;
// Functions
unsigned long int displayController(unsigned long int previousMillis, unsigned int interval) {
unsigned long int currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
updateSetNumber(++number, 1);
}
return previousMillis;
}
int calculateNumberLength(int innerNumber) {
int len = 0;
while (innerNumber != 0) {
innerNumber = innerNumber / 10;
len++;
}
if (len <= dotIndex) len = dotIndex + 1;
return len;
}
void updateSetNumber(int innerNumber, int dot) {
numberLength = calculateNumberLength(innerNumber) - 1;
dotIndex = dot;
for (int i = 0; i < 4; i++) {
numberDigits[i] = innerNumber % 10;
innerNumber = innerNumber / 10;
}
}
void displayLoop() {
if (digitIndex > numberLength) {
digitIndex = (digitIndex + 1) % 4;
return;
}
if ((digitIndex == dotIndex) && (dotIndex > 0)) {
displayDigit(digits[numberDigits[digitIndex]] & DISPLAY_DECIMAL_DOT, digitsPos[digitIndex]);
} else {
displayDigit(digits[numberDigits[digitIndex]], digitsPos[digitIndex]);
}
digitIndex = (digitIndex + 1) % 4;
}
void displayDigit(byte digit, byte pos) {
digitalWrite(latchPin, OFF);
shiftOut(dataPin, clockPin, MSBFIRST, digit);
shiftOut(dataPin, clockPin, MSBFIRST, pos);
digitalWrite(latchPin, ON);
digitalWrite(latchPin, OFF);
}
// Program
void setup() {
for (int i = 0; i < lengthOfButtons; i++) {
pinMode(buttons[i], INPUT);
}
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}
void loop() {
if (isRunning) {
previousMillis = displayController(previousMillis, interval);
}
unsigned int currentButtonState = digitalRead(buttons[0]);
if ((!isRunning) && (digitalRead(buttons[2]) == ON)) {
digitIndex = 0;
number = 0;
updateSetNumber(number, 1);
}
displayLoop();
if (currentButtonState != previousButtonState[0]) {
if (currentButtonState == ON) {
isRunning = !isRunning;
}
previousButtonState[0] = currentButtonState;
}
}
The problem your teacher is pointing to is probably how you update previousMillis. Imagine that for some reason, an interrupt took too long or you fall victim to the fact that millis skips a number every now and then and your function doesn't get called until 102ms after the last time. Since you set previousMillis to currentMillis, you're going to be off by that 2ms from now on. Instead, add the interval to the previousMillis variable. That way you cancel out that little lag and the next tick is on time.
if(currentMillis - previousMillis >= interval) {
previousMillis += interval; // instead of = currentMillis which may be off
}
I have this problem where I try to set an output pin high for a set time and times.
I do the call with hapticFeedback(1000, 2, 1);
the variables are defined as
unsigned long hapticPreviousMillis = 0;
int hapticState = LOW;
int oneshotHaptic = 0;
here is the function. For some reason I only get the pin set HIGH and not the blinks and LOW
void hapticFeedback(int activeLength, int repeats, int oneshotHaptic) {
if (oneshotHaptic == 1) {
for (int x = 0; x <= repeats; x++) {
unsigned long currentMillis = millis();
if (currentMillis - hapticPreviousMillis >= (unsigned long)activeLength) {
hapticPreviousMillis = currentMillis;
if (hapticState == LOW) {
hapticState = HIGH;
}
else {
hapticState = LOW;
}
digitalWrite(haptic, hapticState);
}
}
}
oneshotHaptic = 0;
}
So I figured it out and if anyone else is looking for this here is what I came up with. It might not be the smoothest of code but it does what I intended it to do
in the loop I have
if (setOneshotHaptic == 1) {
hapticFeedback(activeLength);
}
and the haptic function look like this
void hapticFeedback(int activeLength) {
unsigned long currentMillis = millis();
if (currentMillis - hapticPreviousMillis >= (unsigned long)activeLength) {
hapticPreviousMillis = currentMillis;
if (x == repeats) {
setOneshotHaptic = false;
hapticState = HIGH;
x = 0;
}
if (hapticState == LOW) {
hapticState = HIGH;
x++;
}
else {
hapticState = LOW;
}
digitalWrite(haptic, hapticState);
}
}
whenever i like to have haptic feedback i can define the following vars
setOneshotHaptic = true;
repeats = 3;
activeLength = 1000;
When the number of repeats has been reached I lay down the oneshot, force the output to high for it to be low by the routine and finally reset my repeat counter.
There might be nicer ways to do this. However I couldn't find them and this works for me....
I want to convert a binary string I store from my two interrupts (ISR_INT1, ISR_INT0) into a decimal. I've tested this using gcc on my Mac and it works well, giving me the correct decimal. Testing on my Arduino I get a totally different decimal. I know the Arduino only goes up to 16-bit ints so I used a long instead see below. Any help or suggestions are greatly appreciated.
Here is my Arduino sketch:
#define MAX_BITS 100 // max number of bits
#define WEIGAND_WAIT_TIME 3000 // time to wait for another weigand pulse.
unsigned char databits[MAX_BITS]; // stores all of the data bits
unsigned char bitCount; // number of bits currently captured
unsigned char flagDone; // goes low when data is currently being captured
unsigned int weigand_counter; // countdown until we assume there are no more bits
unsigned long facilityCode = 0; // decoded facility code
unsigned long cardCode = 0; // decoded card code
String fullCard; // binary value full card number
int LED_GREEN = 11;
int LED_RED = 12;
int BEEP_BEEP = 10;
// interrupt that happens when INTO goes low (0 bit)
void ISR_INT0() {
fullCard += 0;
bitCount++;
flagDone = 0;
weigand_counter = WEIGAND_WAIT_TIME;
}
// interrupt that happens when INT1 goes low (1 bit)
void ISR_INT1() {
fullCard += 1;
databits[bitCount] = 1;
bitCount++;
flagDone = 0;
weigand_counter = WEIGAND_WAIT_TIME;
}
void setup() {
pinMode(LED_RED, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(BEEP_BEEP, OUTPUT);
digitalWrite(LED_RED, HIGH); // High = Off
digitalWrite(BEEP_BEEP, HIGH); // High = off
digitalWrite(LED_GREEN, LOW); // Low = On
pinMode(2, INPUT); // DATA0 (INT0)
pinMode(3, INPUT); // DATA1 (INT1)
Serial.begin(9600);
Serial.println("Snow RFID Reader PUT HID CARD ");
// binds the ISR functions to the falling edge of INTO and INT1
attachInterrupt(0, ISR_INT0, FALLING);
attachInterrupt(1, ISR_INT1, FALLING);
weigand_counter = WEIGAND_WAIT_TIME;
}
void loop() {
// This waits to make sure that there have been no more data pulses before processing data
if (!flagDone) {
if (--weigand_counter == 0)
flagDone = 1;
}
// if we have bits and we the weigand counter went out
if (bitCount > 0 && flagDone) {
unsigned char i;
Serial.print(" ");
Serial.print("Read ");
Serial.print(bitCount);
Serial.print(" bits. ");
Serial.print(fullCard);
**// THIS IS WHERE IT I TRY TO CONVERT MY BINARY STRING INTO A DECIMAL**
long fullCardInt = bin2dec(const_cast<char*>(fullCard.c_str()));
Serial.print(fullCardInt);
if (bitCount == 35) {
// 35 bit HID Corporate 1000 format
// facility code = bits 2 to 14
for (i = 2; i < 14; i++) {
facilityCode <<= 1;
facilityCode |= databits[i];
}
// card code = bits 15 to 34
for (i = 14; i < 34; i++) {
cardCode <<= 1;
cardCode |= databits[i];
}
printBits();
} else if (bitCount == 26) {
// standard 26 bit format
// facility code = bits 2 to 9
for (i = 1; i < 9; i++) {
facilityCode <<= 1;
facilityCode |= databits[i];
}
// card code = bits 10 to 23
for (i = 9; i < 25; i++) {
cardCode <<= 1;
cardCode |= databits[i];
}
printBits();
} else {
Serial.println("Unable to decode.");
}
// cleanup and get ready for the next card
bitCount = 0;
facilityCode = 0;
cardCode = 0;
for (i = 0; i < MAX_BITS; i++) {
databits[i] = 0;
}
}
}
void printBits() {
Serial.print("FC = ");
Serial.print(facilityCode);
Serial.print(", CC = ");
Serial.println(cardCode);
digitalWrite(LED_RED, LOW); // Red
if (cardCode == 12345) {
digitalWrite(LED_GREEN, HIGH);
}
delay(500);
digitalWrite(LED_RED, HIGH);
digitalWrite(LED_GREEN, LOW);
digitalWrite(BEEP_BEEP, LOW);
delay(500);
digitalWrite(BEEP_BEEP, HIGH);
delay(500);
digitalWrite(BEEP_BEEP, LOW);
delay(500);
digitalWrite(BEEP_BEEP, HIGH);
}
long bin2dec(const char *bin) {
int result = 0;
for (; *bin; bin++) {
if ((*bin != '0') && (*bin != '1'))
return -1;
result = result * 2 + (*bin - '0');
//if(result<=0) return -1;
}
return result;
}
This is what my serial terminal for my Arduino reads out
Snow RFID Reader PUT HID CARD
// bits read Binary string Incorrect decimal
Read 26 bits. 00001000000100000101010011 16723 FC = 16, CC = 8361
Here is my Test.cpp script
//THIS WORKS AND GIVES ME THE CORRECT DECIMAL
#include <stdio.h>
int bin2dec(const char *bin) {
int result=0;
for(;*bin;bin++) {
if((*bin!='0')&&(*bin!='1'))
return -1;
result=result*2+(*bin-'0');
}
return result;
}
int main (void) {
printf("%d\n", bin2dec("00001000000100000101010011"));
return(0);
}
This is what my test cpp script gives me which is correct.
S:g$ g++ main.cpp -o SnowTest
S:g$ ./SnowTest
2113875
As you said, int on Arduino are 16 bit.
Inside your function int bin2dec, you return an int and result is a int, so in Arduino your number is truncated to the 16 lsb (100000101010011) that in dec are 16723.
Use long instead
long bin2dec(const char *bin)
{
long result=0;
for(;*bin;bin++)
{
if((*bin!='0')&&(*bin!='1'))
return -1;
result=result*2+(*bin-'0');
//if(result<=0) return -1;
}
return result;
}