MCU Sch for button
I have 5 buttons which i have mapped to EXTI interrupts.
PA0,PA1,PA2,PA3,PA15
I have observed that when the button on the PA0 is pressed , it invokes EXTI interrupt for PA1 and vice-versa. PA2 and PA3 behave similarly.
Here is the callback function
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == GPIO_PIN_0)
{
val1++;
}
if(GPIO_Pin == GPIO_PIN_1)
{
val2++;
}
if(GPIO_Pin == GPIO_PIN_2)
{
val3++;
}
if(GPIO_Pin == GPIO_PIN_3)
{
val4++;
}
}
Pressing Key0 should only increment val1 , but it increments val2 and vice-versa
Here is the ISR
void EXTI0_1_IRQHandler(void)
{
/* USER CODE BEGIN EXTI0_1_IRQn 0 */
/* USER CODE END EXTI0_1_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
/* USER CODE BEGIN EXTI0_1_IRQn 1 */
/* USER CODE END EXTI0_1_IRQn 1 */
}
I have checked noise on the power rail and i see none.
In one version, there was debounce added too (although you cannot see it in the current version)
When I place a breakpoint in the ISR , a false interrupt on PA1 is triggered when the button on PA0 is pressed (val1 should increment, instead val2 increments)
I also tried disabling the Interrupt once it enters the ISR and re-enabling the interrupt in main() after it is processed. But it behaves in the same erratic way.
Can someone point out if there is some mistake in my code or any other issue?
Thanks in advance
Related
First of all sorry for my weak English
I have Arduino Leonardo
and I have a push-button ok?
When I click the button the letter 'W' is printed to the notepad
ok?
I Want when I keep holding the button the 'w' Letter is printed
why? like in games when I keep holding on 'W' letter the player will move, then when I release my finger the player will stop.
Please please please I need your help because I'm a beginner
This is my code
#include "Keyboard.h"
const int buttonPin = 4; // input pin for pushbutton
int previousButtonState = HIGH; // for checking the state of a pushButton
void setup() {
// make the pushButton pin an input:
pinMode(buttonPin, INPUT);
// initialize control over the keyboard:
Keyboard.begin();
}
void loop() {
// read the pushbutton:
int buttonState = digitalRead(buttonPin);
// if the button state has changed,
if ((buttonState != previousButtonState)
// and it's currently pressed:
&& (buttonState == HIGH)) {
// type out a message
Keyboard.print("W");
}
// save the current button state for comparison next time:
previousButtonState = buttonState;
}
First, the reason why your code only acts as if the button was pressed once are the following lines
// if the button state has changed,
if ((buttonState != previousButtonState)
// and it's currently pressed:
&& (buttonState == HIGH)) {
so, this will only be true once after the button gets pressed. If you remove the previous state check and only check if the button is currently high it will trigger a press every time your programm loops. This will have side effects though, like a short press will likely trigger multiple times.
Fortunately, there is another function provided by the keyboard library to solve this issue: Keyboard.press()
When called, Keyboard.press() functions as if a key were pressed and held on your keyboard. Useful when using modifier keys. To end the key press, use Keyboard.release() or Keyboard.releaseAll().
https://www.arduino.cc/reference/en/language/functions/usb/keyboard/keyboardpress/
So, if you modify your code like this:
void loop() {
// read the pushbutton:
int buttonState = digitalRead(buttonPin);
// if the button state has changed,
if (buttonState != previousButtonState){
if( buttonState == HIGH ) {
Keyboard.press('w');
}else{
Keyboard.release('w');
}
}
// save the current button state for comparison next time:
previousButtonState = buttonState;
}
it will act exactly as if the keyboard button keeps beeing pressed.
Please note that currently the script will likely act as if the button is pressed a few times per press because of bouncing. You could fix this issue by adding a small delay after the button press and release part. This will give the button time to settle to the new state. Read more about bouncing here: https://www.allaboutcircuits.com/textbook/digital/chpt-4/contact-bounce/
I'm facing a programming question in which I want to trigger some code whenever a capacitive touch sensor has been touched for 100 ms (to distinguish false positives in my prototype). My sensor is touched by this code
if (digitalRead(touchPin))
Now whenever it has been touched for 100ms I want some other code (for instance, activating a LED) to run. I can't really seem to find a solution because my startTime = millis() variable keeps resetting.
Does anyone know how to tackle this problem?
You need a bool variable, to store last state (TRUE if touched and FALSE if not)
Also, you need to store time when it has been changed to TRUE. Time could be taken by millis() function
If your bool variable is true, check, if time passed is more than your 100 ms.
So:
// In your global scope:
...
// Last touch state
bool isTouched = FALSE;
// time, when last touch happened
int touched_t = 0;
// In your loop:
...
bool isTouchedNow = (digitalRead(touchPin) == HIGH);
// Touch state is changed till last measure:
if (isTouchedNow != isTouched)
{
// Set "last isTouched state" to new one
isTouched = isTouchedNow;
// If it wasn't touched before, store current time (else zero):
touched_t = isTouched ? millis() : 0;
}
else //If touch state isn't changed till last time:
{
//If state was "touched" and now it "touched", and 100ms has passed:
if (isTouched && touched_t > 0 && millis() - touched_t > 100)
{
// Call your function, that should be called,
// whan sensor is touched for 100 ms (activate a LED of something)
DOTHESTUFF();
}
}
...
I'm trying out some beginner Arduino programming.
The task is to make the board I have (ESP8266) play some music and then the music should stop when I press the button, and then restart when I press it again.
Here's my code,
#include "pitches.h" // contains frequencies for notes
#define PIN_BUTTON 0 // the button
#define PIN_BUZZER 13 // the digital pin the Buzzer is attached to
bool stop = false; // button pressed
void play_note(int freq){
if (freq > 0 && !stop){
analogWrite(PIN_BUZZER, 512);
analogWriteFreq(freq);
} else {
analogWrite(PIN_BUZZER, 0);
}
}
void stopMusic(){
stop = !stop;
play_note(0);
}
void setup() {
pinMode(PIN_BUZZER, OUTPUT);
pinMode(PIN_BUTTON, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(PIN_BUTTON), stopMusic, RISING);
}
void loop() {
// intro
play_note(NOTE_E7);
delay(110);
play_note(NOTE_E7);
delay(220);
play_note(NOTE_E7);
delay(220);
play_note(NOTE_C7);
delay(110);
play_note(NOTE_E7);
delay(220);
play_note(NOTE_G7);
delay(440);
play_note(NOTE_G6);
delay(440);
}
The problem is, that the button is being inconsistent. Sometimes, on pressing it, the music will immediately stop. Other times, it will keep playing and I'll have to press it once or twice more. Similarly, when I want the music to start again, it will sometimes start as soon as I press the button, but other times I will need to press it twice or more to get the music back up. I don't know whats causing this. Suggestions?
The button is most likely a mechanical one. They bounce, i.e. open and close the contacts after a press or release for a short time. You have to wait until the button has settled (typically 5-20ms, actual value depends on the button and should be specified in the datasheet) before you check for a new value.
This is called de-bouncing.
Alternatively you can check the button from a periodic timer interrupt. But that would degrade reaction time.
You should probably add some debounce logic to your code.
https://www.arduino.cc/en/Tutorial/Debounce
I have one scenario problem and I don't want to use interrupts cause the same problem will be there I will be forced to use delay to insure that specific time did pass.
the problem:
I don't want to use the delay function cause it stops the other tasks to be checked or executed taking a situation:
I have motor that run 6 seconds if button1 is pressed and if a man press button2 the motor 2 immediately need to be turned on and work for 2 second.
so the code will be like this:
main ()
{
if( Rd0 == 0 ) // is button1 is pressed
{
RunMotre1();
__delay_ms(6000);
StopMotor1();
}
if( Rd1 == 0 ) // is button2 is pressed
{
RunMotor2();
__delay_ms(2000);
StopMotor2();
}
}
the problem of this code if we pressed the button b to start Motor 2 he will
not work cause the system is blocked on delay and wait it to be finished .
and that cause that if we start -> press button 1->motor 1 runing -> pressing buTTon2 to start Motor2-> Motor2 not working until the 6 seconds be passed.
so is there a way to resolve this problem case.
for example if exists comparing who mutch time Motor1 did run if is greate or = 6 secound then stop the motor 1 example (samthing like this if exist) :
Time counter1;
Time Counter2;
main()
{
if( Rd0 == 0 ) // is button 1 to start motor1 is presed ?
{
RunMotre1();
counter1.start();
}
if(counter1.CurentElapsedTimes==6 Secound) // is motor1 did run 6 seconds
{
counter1.stop();
counter1.Initialise();
StopMotor1();
}
if( Rd1 == 0 ) // is button 2 to start motor2 is pressed.
RunMotor2();
counter2.start();
}
if(counter2.CurentElapsedTimes==2 Secound) // is motor2 did run 2 seconds
{
counter2.stop();
counter2.Initialise();
StopMotor2();
}
or any solution
platform pic microcontroller using xc8 compiler
PRESUPPOSITION: I don't know which PIC you are using, but I assume that it has at least a free timer.
The problem here is that you need something to track the time as it passes. My suggestion is to use the same technique that the Arduino FW uses: setup a timer to fire an interrupt every X milliseconds/seconds, then in the interrupt service routine (ISR) update a counter.
When you press the button set the counter, then wait for the counter to reach another value before turning the motor off.
I'll write here a small pseudo-code example, since I don't remember how to properly write an ISR with a PIC compiler nor I know what is your PIC (and, so, the commands to initialize the timer).
I chose to use a timer granularity of 100ms, but you can change it as you prefer.
I also chose to set counter as a 8-bit variable; it can count up to 25.5 seconds, but since the highest delay is 6 seconds it's ok.
Note that you need just ONE timer, so you can add any number of motors without the need for adding counters
char counter;
char motor1StartTime;
char motor2StartTime;
bool motor1Running;
bool motor2Running;
Timer1_ISR()
{
counter++;
}
main()
{
counter = 0;
motor1StartTime = 0;
motor2StartTime = 0;
motor1Running = false;
motor2Running = false;
// Setup the timer to trigger the Timer1_ISR every 100ms
...
while(1)
{
if( Rd0 == 0 )
{ // If the button is pressed start the motor and save the counter
RunMotor1();
motor1StartTime = counter;
motor1Running = true;
}
if ((motor1Running) && ((counter - motor1StartTime) >= 60))
{ // If the motor is running from more than 6 seconds, shut it down
StopMotor1();
motor1Running = false;
}
if( Rd1 == 0 )
{ // If the button is pressed start the motor and save the counter
RunMotor2();
motor2StartTime = counter;
motor2Running = true;
}
if ((motor2Running) && ((counter - motor2StartTime) >= 20))
{ // If the motor is running from more than 2 seconds, shut it down
StopMotor2();
motor2Running = false;
}
}
}
Im trying to figure out how to dim a led over time(time is defined by the user lets call it rampUp). Im using arduino with the adafruit breakout PWM-Servo-Driver (http://www.adafruit.com/products/815) with the library : https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library
this breakout has 4095 steps (0-4095) so now my problem:
I want to be able to take a variable ( int minutes) and send that to a method that will dim a LED from 0 to 4095 in a equal light intensity increase for the period minutes. I want the increase to be incremented by 1 each time it increases.
So how do I write the method without using delay() ?
void dimLights(int rampUp){
// some code to regulate the increase of the third value in setPWM one step at a time over a period of rampUp(int in minutes)
led.setPWM(0,0,4095);
}
the reason for not wanting to use delay() is because it will pause/stop the rest of the program.
I actually implemented something close recently:
void loop() {
/* ... */
if (rampUp != 0)
led.setPWM(0,0,rampUp);
}
void led_update() {
// here you can prescale even more by using something like
// if (++global_led_idx == limit) {
// global_led_idx = 0;
++rampUp;
}
void start() {
TCCR1B |= _BV(WGM12);
// set up timer with prescaler = FCPU/1024 = 16MHz/1024 ⇒ 60ms
TCCR1B |= _BV(CS12) | _BV(CS10);
TCCR1B &= ~_BV(CS11);
// initialize counter
OCR1A = 0x0000;
// enable global interrupts
sei();
// enable overflow interrupt
TIMSK1 |= _BV(OCIE1A);
}
void TAGByKO_LED::stop() {
TIMSK1 &= ~_BV(OCIE1A);
rampUp = 0;
}
ISR(TIMER1_COMPA_vect, ISR_NOBLOCK) {
led_update();
}
then you can call start() to start the timer, or stop() to stop it. You can read more documentation about the registers I've been using here and the ISR statement. Beware that it's one of the most tricky things of AVRs to really understand, and even then you'll always need to have a cheatsheet or the datasheet close by.
You may also use #sr-richie's solution with timers, but do only setup variables in the dimLights() function, and call led.setPWM() only within the loop().