I am trying to fix the bug in my code - I have 7Digit display, which must count up from 0 to 99 when button is not pressed, or count down from 99 to 0 when button is pressed.
I have the issue with counting up, the issue happens, when the display must show numbers as 10,20,30 etc. While countin it up, after number 09 there is 00 instead of 10, after 19 there is 10 instead of 20 etc.
I am attching below a fragment of code responsible for counting up and down:
void Refresh_Display() {
AT91C_BASE_PIOB->PIO_CODR = A|B|C|D|E|F|G;
}
void set_Number(int number) {
AT91C_BASE_PIOB->PIO_SODR = LEFTDIGIT;
AT91C_BASE_PIOB->PIO_CODR = RIGHTDIGIT;
Refresh_Display();
Display_Number(number%10);
delay(5000);
AT91C_BASE_PIOB->PIO_SODR = RIGHTDIGIT;
AT91C_BASE_PIOB->PIO_CODR = LEFTDIGIT;
Refresh_Display();
Display_Number(number/10);
delay(5000);
}
void countdown(int i) {
while(1) {
if(i<=0) {
i = 99;
}
set_Number(i);
i--;
if(!BP1_Status) {
counter = i;
break;
}
}
}
void countup(int i) {
while(1) {
i++;
if(i>=99) {
i = 0;
}
set_Number(i);
if(BP1_Status) {
counter = i;
break;
}
}
}
int main(void){
Port_init();
Button_init();
while(1) {
for (volatile int i=0;i<100;i++) {
if(BP1_Status) {
countdown(counter);
} else if (!BP1_Status) {
countup(counter);
}
}
}
}
I have a solution for that problem:
In the ARM processor AT91SAM9263 there are registers PIO_CODR and PIO_SODR. The first one register is refreshing data, the second one Sets the data to be driven on the I/O line.
I have swapped the method of display the numbers on two 7Segment Displays. On the left, there are displayed, the decimal numbers are displayed as number/10 and the units as numbers%10to receive 0 digit on second display while showing 10 or 20 value.
void set_Number(int number) {
AT91C_BASE_PIOB->PIO_CODR = LEFTDIGIT;
AT91C_BASE_PIOB->PIO_SODR = RIGHTDIGIT;
Refresh_Display();
Display_Number(number/10);
delay(5000);
AT91C_BASE_PIOB->PIO_CODR = RIGHTDIGIT;
AT91C_BASE_PIOB->PIO_SODR = LEFTDIGIT;
Refresh_Display();
Display_Number(number%10);
delay(5000);
}
Related
Im currently trying to code a timer on a D1 mini that has three tactile switches and will display on a 64x48 OLED display, switch 1 and 2 will increase and decrease the time and 3 will start the time you have put in.
As of now when as it turns on the timer is in a stopped state and you can set your desired time input with switch 1 and 2 and then start the timer with switch 3 but when the timer counts down I want it to stop at 00:00 for you to then input a new time with switch 1 and 2 and then start it again with switch 3. The timer keeps going and does not appear to stop at 00:00.
Here is the code:
#include <Wire.h>
#include <Adafruit_SSD1306.h>
// SCL GPIO5
// SDA GPIO4
#define OLED_RESET 0 // GPIO0
Adafruit_SSD1306 display(OLED_RESET);
int switch1 = D3;
int switch2 = D4;
int switch3 = D5;
int minutes = 0;
int seconds = 0;
int originalMinutesValue = 0;
int originalSecondsValue = 0;
bool timerRunning = false;
bool isReset = false;
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display();
delay(2000);
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(4,16);
pinMode(switch1, INPUT);
pinMode(switch2, INPUT);
pinMode(switch3, INPUT);
originalMinutesValue = minutes;
originalSecondsValue = seconds;
}
void loop() {
if(digitalRead(switch1) == LOW) {
if(seconds == 0) {
if(minutes > 0) {
minutes--;
seconds = 59;
}
} else {
seconds--;
}
delay(200);
}
if(digitalRead(switch2) == LOW) {
if(seconds == 59) {
minutes++;
seconds = 0;
} else {
seconds++;
}
delay(200);
}
if(digitalRead(switch3) == LOW) {
timerRunning = !timerRunning;
if(timerRunning && !isReset) {
isReset = true;
}
delay(200);
}
if(timerRunning){
if(seconds==0){
if(minutes>0){
minutes--;
seconds=59;
}else{
if(isReset){
minutes = originalMinutesValue;
seconds = originalSecondsValue;
isReset = false;
}else {
timerRunning = false;
}
}
}else{
seconds--;
}
delay(1000);
}
display.clearDisplay();
display.setCursor(4,16);
if(minutes < 10) {
display.print("0");
}
display.print(minutes);
display.print(":");
if(seconds < 10) {
display.print("0");
}
display.print(seconds);
display.display();
}
I have tried a lot of different workarounds but cannot get it to work. Please let me know if you might know the problem.
I have three screens in the LCD connected to the 8051-microcontroller that scroll to the different screen when the button is pressed but I want to return back to the initial screen when again button is pressed. How can I do that, thank you?
#include <stdio.h>
#include <string.h>
#include <stdint.h>
void change_screen(void);
int count = 0;
void change_screen(void)
{
if (modebutton == 1) { // when button is pressed
if (count == 0) {
count++;
delay(100);
display_screen1();
modebutton=0;
}
else if (count == 1) {
count++;
delay(100);
display_screen2();
modebutton=0;
}
else if (count == 2) {
display_screen3();
count = 0;
}
}
}
You can use the remainder operator % for this.
Example:
void change_screen(void) {
static unsigned count = 0;
if(modebutton) {
delay(100);
modebutton = 0;
switch(count) {
case 0: display_screen1(); break; // first fourth ...
case 1: display_screen2(); break; // second fifth
case 2: display_screen3(); break; // third sixth
}
count = (count + 1) % 3; // 0,1,2 then 0,1,2 etc...
}
}
I have a barcode code but need it to recognize the barcode so it can print to serial monitor. I have searched that I need to have it convert to int from char but have yet to find a way to do that if that is the answer.
For example I scan a barcode and if it is a certain number, then the serial monitor will print it.
#include <hid.h>
#include <hiduniversal.h>
#include <usbhub.h>
#include <Usb.h>
#include <hidboot.h>
#include <avr/pgmspace.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Bridge.h>
#include <FileIO.h>
#include <TM1637Display.h>
#define DEBUG true
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
const byte BarcodeLength = 11;
const int buzzer = 2;
const int CLK = 9; //Set the CLK pin connection to the display
const int DIO = 8; //Set the DIO pin connection to the display
const int DIO2 = 7; // Set 2nd DIO pin to second connection to display
const int CLK2 = 6; // Set the 2nd CLK pin to the second connection to display.
const int procTime = 5; // this is the time it takes for the process to finish countdown
int NumStep = 0; //Variable to interate
TM1637Display countdownDisplay(CLK, DIO); //set up the 4-Digit Display.
TM1637Display DelayedDisplay(CLK2, DIO2); //set up the 4-Digit Display.
class BarcodeReader : public KeyboardReportParser
{
USB Usb;
USBHub Hub;
HIDUniversal Hid;
HIDBoot<HID_PROTOCOL_KEYBOARD> Keyboard;
uint8_t buffer[15];
byte length;
bool valid;
void addCharacter(uint8_t c);
public:
BarcodeReader();
void begin();
void task();
const uint8_t* barcode();
void reset();
protected:
virtual void OnKeyDown(uint8_t mod, uint8_t key);
};
BarcodeReader::BarcodeReader()
: Usb()
, Hub(&Usb)
, Hid(&Usb)
, Keyboard(&Usb)
, length(0)
, valid(false)
{
}
void BarcodeReader::begin()
{
if (Usb.Init() == -1) {
Serial.println("OSC did not start.");
}
else
Serial.println("Barcode Ready");
Hid.SetReportParser(1, this);
}
void BarcodeReader::task()
{
Usb.Task();
}
void BarcodeReader::addCharacter(uint8_t c)
{
if (valid) {
// already have a barcode, new one will overwrite it
reset();
}
// could check for \n or \r if necessary, or even implement a timing
// mechanism for detecting end of barcode input, but for now we just
// assume fixed width field with no output separators
buffer[length++] = c;
//buffer[length] = '\0';
if (buffer[length] == '\0')
{
valid = true;
}
};
// return value no longer valid after another call to task()
const uint8_t* BarcodeReader::barcode()
{
return (valid) ? buffer : 0;
}
void BarcodeReader::reset()
{
length = 0;
valid = false;
}
void BarcodeReader::OnKeyDown(uint8_t mod, uint8_t key) {
uint8_t c = OemToAscii(mod, key);
if (c) addCharacter(c);
}
BarcodeReader barcodeReader;
void setup() {
countdownDisplay.showNumberDec(0);
DelayedDisplay.showNumberDec(0);
Bridge.begin();
Console.begin();
FileSystem.begin();
Serial.begin(9600);
if (DEBUG) Console.println("Done setup");
lcd.begin(16, 2);
pinMode(buzzer,OUTPUT);
//Serial.begin(115200);
lcd.print("Please Scan Your ID: ");
barcodeReader.begin();
countdownDisplay.setBrightness(0x0a); //set the diplay to maximum brightness
DelayedDisplay.setBrightness(0x0a);
}
void loop() {
//char *goodCards = { "1234567" };
//String dataString = "Testing, 1, 2, 3...";
File dataFile = FileSystem.open("/mnt/sda1/datalog.txt", FILE_APPEND);
// If the file opens successfully, write the string to it, close the file,
// and print the information to the Serial monitor.
barcodeReader.task();
const char* barcode = barcodeReader.barcode();
if (barcode || dataFile) {
lcd.print(barcode);
dataFile.print(barcode);
Serial.print(barcode);
barcodeReader.reset();
dataFile.close();
//If the barcode is the word 'Setup' then print setup to the screen
//search array of char conver strcmp(). You are sending 0101 not the actual value of 1234567
// collect all the input, convert it to an int
if(barcode == "0001") {
{
Serial.println(": SETUP");
}
}
}
//timer and barcode
//
// if(barcode == "1234567") {
// Serial.print(barcode);
// Serial.println(": SETUP");
//
//// analogWrite(A1,0);
//// analogWrite(A2,0);
// }
// if(barcode == "KAYAMAD") {
// Serial.print(barcode);
// Serial.println(": RUN");
//
//// analogWrite(A0,0);
//// analogWrite(A2,0);
// countdownDisplay.showNumberDec(0);
// DelayedDisplay.showNumberDec(0);
// for(int NumStep = procTime; NumStep > 0 ; NumStep--) //Interrate NumStep
// {
// countdownDisplay.showNumberDec(NumStep); //Display the Variable value;
// //DelayedDisplay.showNumberDec(NumStep); //Display the Variable value;
// delay(1000); //A second delay between steps.
// }
//
// for (int NumStep = 0; NumStep < 5 ; NumStep++) //Interrate NumStep
// {
// //countdownDisplay.showNumberDec(NumStep); //Display the Variable value;
// DelayedDisplay.showNumberDec(NumStep); //Display the Variable value;
// countdownDisplay.showNumberDec(0);
// delay(1000); //A second delay between steps.
//
// }
//
// }
//
// else if (barcode == "2234663") {
// Serial.print(barcode);
// Serial.println(": DELAY");
//
//// analogWrite(A0,0);
//// analogWrite(A1,0);
// countdownDisplay.showNumberDec(0);
// DelayedDisplay.showNumberDec(0);
//
//
// for (int NumStep = 0; NumStep < 5 ; NumStep++) //Interrate NumStep
// {
// //countdownDisplay.showNumberDec(NumStep); //Display the Variable value;
// DelayedDisplay.showNumberDec(NumStep); //Display the Variable value;
// countdownDisplay.showNumberDec(0);
// delay(1000); //A second delay between steps.
//
// }
//
//
// }
//
// If there is a problem opening the file, send an error to the Serial monitor
else {
if (DEBUG) Console.println("Error opening datalog.txt");
}
}
"Number" you get Computer sees as text, not number. We are sure that barcode will always be number. Conver char to int with atoi function.
Here's an example:
const char *bar = "123";
int bc = atoi(bar);
How can I detect how long a button was pressed / released in Arduino and then print some custom output after that?
Arduino can only detect the state of your button (pressed OR unpressed).
You could use a timer variable (based on this example from their docs) to save the exact time when you pressed or released the button, so you can check the difference between both variables to calculate how long it is on hold or idle.
The code could look like this:
const int buttonPin = 2;
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button
int startPressed = 0; // the moment the button was pressed
int endPressed = 0; // the moment the button was released
int holdTime = 0; // how long the button was hold
int idleTime = 0; // how long the button was idle
void setup() {
pinMode(buttonPin, INPUT); // initialize the button pin as a input
Serial.begin(9600); // initialize serial communication
}
void loop() {
buttonState = digitalRead(buttonPin); // read the button input
if (buttonState != lastButtonState) { // button state changed
updateState();
}
lastButtonState = buttonState; // save state for next loop
}
void updateState() {
// the button has been just pressed
if (buttonState == HIGH) {
startPressed = millis();
idleTime = startPressed - endPressed;
if (idleTime >= 500 && idleTime < 1000) {
Serial.println("Button was idle for half a second");
}
if (idleTime >= 1000) {
Serial.println("Button was idle for one second or more");
}
// the button has been just released
} else {
endPressed = millis();
holdTime = endPressed - startPressed;
if (holdTime >= 500 && holdTime < 1000) {
Serial.println("Button was held for half a second");
}
if (holdTime >= 1000) {
Serial.println("Button was held for one second or more");
}
}
}
However, if you want to trigger an event while the button is still pressed (or maybe you want to increment a counter in some display), you can still do the same math.
Change your condition in the loop function to be like this:
if (buttonState != lastButtonState) {
updateState(); // button state changed. It runs only once.
} else {
updateCounter(); // button state not changed. It runs in a loop.
}
And then implement your new function like this:
void updateCounter() {
// the button is still pressed
if (buttonState == HIGH) {
holdTime = millis() - startPressed;
if (holdTime >= 1000) {
Serial.println("Button is held for more than a second");
}
// the button is still released
} else {
idleTime = millis() - endPressed;
if (idleTime >= 1000) {
Serial.println("Button is released for more than a second");
}
}
}
for your interest here's an example of code using 2 arrays to store button states of arduino pin given to the corresponding input button. During the loop you can do a simple check with the wanted repeat:
if(button_down(But1_pin, BTN_LOOP_DELAY_MS))
{
// code here repeated if the button is either clicked or maintained
}
button_down() also defers the first repeat by DELAY_WAIT_BEFORE_REPEAT ms.
Here the full tested example:
#define BTN_LOOP_DELAY_MS 100
#define DELAY_WAIT_BEFORE_REPEAT 500
#define NB_MAX_PIN_INPUT 13
#define But1_pin 7
#define But2_pin 6
// array to check status change
bool prev_button[NB_MAX_PIN_INPUT];
unsigned long button_last_down[NB_MAX_PIN_INPUT];
// macro : our read init with prev_button storage
#define READ_INIT_BUTTON(pin) \
do{ \
pinMode(pin, INPUT); \
prev_button[pin] = digitalRead(pin); \
} while(false)
// function at the end of the code
bool button_down(byte pin_num, unsigned int delay_repeated);
void setup() {
READ_INIT_BUTTON(But1_pin);
READ_INIT_BUTTON(But2_pin);
Serial.begin(115200);
}
void loop() {
if(button_down(But1_pin, BTN_LOOP_DELAY_MS))
{
Serial.print("new inpulse");
Serial.print(millis());
Serial.println();
}
if(button_down(But2_pin, BTN_LOOP_DELAY_MS))
{
Serial.println("button2");
}
}
bool button_down(byte pin_num, unsigned int delay_repeated)
{
bool b = digitalRead(pin_num);
bool r = false;
unsigned long currentMillis = millis();
if(prev_button[pin_num] != HIGH && b == HIGH)
{
r = true;
button_last_down[pin_num] = currentMillis + DELAY_WAIT_BEFORE_REPEAT;
}
else if(b == HIGH
&& prev_button[pin_num] == HIGH
&& currentMillis > button_last_down[pin_num]
&& currentMillis - button_last_down[pin_num] > delay_repeated
)
{
// save the last time we give a button impusle at true
button_last_down[pin_num] = currentMillis;
r = true;
}
// store button state, if changed
if(prev_button[pin_num] != b)
{
prev_button[pin_num] = b;
}
return r;
}
This following steps works:
If the button state satisfies.
Then read the millis() values one time(Using flag) and find the
duration by comparing with current millis() value.
void buttonLongPress() {
uint32_t duration = 0;
if (digitalRead(button_pin) == LOW) {
if (pressReadLimit == 0) {
pressTime = millis();
pressReadLimit = 1;
}
duration = millis() - pressTime;
if (duration >= 3000) {
Serial.println("Long press");
}
Serial.println(duration);
} else {
duration = 0;
pressReadLimit = 0;
}
}
Serial monitor result
I am trying to create Menu Selection process.if SELECT button pressed once should display the Display parameter and if select button pressed twice should goes to Set_parameter window(Where we set parameter). once it is display parameter using up and down arrow Choose the Display window .But problem i am facing here is It enter the Display parameter but comes out Menu window directly .
Circuit diagram for LCD is given here
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
// Pin configuration of the buttons
#define btnRIGHT 0 // Okay
#define btnUP 1 // inc
#define btnDOWN 2 // dec
#define btnLEFT 3 // Select
#define btnSELECT 4 // Menu
#define btnNONE 5
#define beeper A1 // Alarm buzzer
#define shortBeep 100
#define longBeep 500
int button_counter=0;
void setup()
{
Serial.begin(9600);
}
void loop()
{
Select_Menu();
}
void Select_Menu()
{
lcd.begin(16,2);
lcd.setCursor(0,0);
lcd.print("MENU");
int button=read_LCD_buttons();
if(button==btnSELECT)
{
button_counter=button_counter+1
}
if(button_counter==1)
{
Display_function();
}else if((button_counter==2))
{
Set_function();
}else
{
button_counter=0;
}
}
void Display_function()
{
int button = read_LCD_buttons();
if(button==btnUP)
{
button_counter=button_counter+1;
Serial.print("button_counter");
Serial.println(button_counter);
}else if(button==btnDOWN)
{
button_counter=button_counter-1;
Serial.println(button_counter);
}
if (button_counter>5)
{
button_counter=1;
}else
while(button_counter<5)
{
int button = read_LCD_buttons();
if(button != prev_button && button != btnNONE)
{
prev_button = button;
//timedBeep(shortBeep,2);
}
if ((((button ==btnUP )||(button_counter==1))||((button ==btnDOWN )))&&(prev_button==btnUP)
{
digitalClockDisplay();//timedBeep(200,1);
}else if((((button ==btnUP )||(button_counter==2))||((button ==btnDOWN )))&&(prev_button==btnUP))
{
Display_angle();//timedBeep(200,1);
}else if((((button ==btnUP )||(button_counter==3))||((button ==btnDOWN )))&&(prev_button==btnUP))
{
Display_coordinate();//timedBeep(200,1);
}else if((((button ==btnUP )||(button_counter==4))||((button ==btnDOWN )))&&(prev_button==btnUP))
{
button_loop();//timedBeep(500,4);
}else if((((button ==btnUP )||(button_counter==5))||((button ==btnDOWN )))&&(prev_button==btnUP))
{
Display_Wind();//timedBeep(200,1);
}
}
}
void Display_Wind()
{
lcd.setCursor(0,0);
lcd.print("WS kmph:");
lcd.print(Wind_Kmph);
lcd.setCursor(0,1);
lcd.print("WS m/s:");
lcd.print(Wind_Speed);
}
void button_loop()
{
lcd.begin(16,2);
lcd.setCursor(0,0);
lcd.print("Welcome");
}
void Display_coordinate()
{
lcd.begin(16,2);
lcd.setCursor(0,0);
lcd.print("Latitude:");
lcd.print(latitude);
lcd.setCursor(0,1);
lcd.print("Longitude:");
lcd.print(longitude);
}
void Display_angle()
{
lcd.begin(16,2);
lcd.setCursor(0,0);
lcd.print("DESIRED: ");
lcd.print(tracker_des_angle,DEC);
lcd.setCursor(0,1);
lcd.print("ACTUAL: ");
lcd.print(tracker_actual_pos,DEC);
}
void digitalClockDisplay()
{
lcd.begin(16,2);
lcd.setCursor(0,0);
lcd.print("Date:");
lcd.print(local_day);
lcd.print("/");
lcd.print(local_month);
lcd.print("/");
lcd.print(local_year);
lcd.setCursor(0,1);
lcd.print("Time:");
lcd.print(local_h);
lcd.print(":");
lcd.print(local_m);
lcd.print(":");
lcd.print(local_s);
lcd.print(" ");
}
int read_LCD_buttons()
{
adc_key_in = analogRead(0); // read the value from the sensor
// my buttons when read are centered at these valies: 0, 131, 307, 481, 722
// we add approx 50 to those values and check to see if we are close
// No button pressed should be 1023
if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
if (adc_key_in < 50) return btnRIGHT;
if (adc_key_in < 195) return btnUP;
if (adc_key_in < 380) return btnDOWN;
if (adc_key_in < 555) return btnLEFT;
if (adc_key_in < 790) return btnSELECT;
return btnNONE; // when all others fail, return this...
}
You have a flow control problem.
Your main loop runs SelectMenu() in there you enter Display_function() which contains no loop so it reaches the end and returns to SelectMenu() which then returns to loop() which again calls SelectMenu() redrawing your menu and overwriting the display with the menu again.
There are many ways to solve this, but as this is an arduino environment where resources are anything other than endless I would suggest you make each "page" its own loop breaking out of it when needing to move on. Do not switch pages inside the loops or you will build up quite the callstack.
Pseudo code:
loop():
#print and handle input
if (navigate)
Display_function()
Display_function():
while(true)
# print and do whatever
if (nav_angle)
Display_angle()
else if (nav_coord)
Display_coordinate()
#... etc.
if (nav_back)
return
Display_angle():
while(true)
#do stuff
if (nav_back)
return
This should give you the idea, it will work as long as you don't have too deep of a structure and run out of memory.