Why interrupt is stopping program instead of jumping back? - c

i'm working on arduino and i have made two modes in loop(),mode1 in while loop and mode second in while loop they have conditions to be met, i switch between them using button that interrupts routine that is currently executed,changes flags to force program to change to second mode and for some reason instead of breaking out of current while loop (since conditoins are not met anymore )to change to the other it just doesnt respond
or changes from automatic->stops responding
#define modeSwitch 2
boolean manual;
boolean automatic;
String sOld;
boolean flagPrint = false;
volatile int modeSwitchValue;
String receivedData = "";
String invitation = "Welcome to Morse Code Encoder!\nPlease choose a mode: Write 'automatic' for an automatic mode or 'manual' or manual code.\n";
void setup() {
pinMode(modeSwitch, INPUT);
attachInterrupt(0, changeMode, RISING);
manual = false;
automatic = false;
volatile int modeSwitchValue = 5;
Serial.begin(9600);
Serial.println(invitation);
}
void loop() {
if (Serial.available() > 0) {
receivedData = Serial.readStringUntil('\n');
if (receivedData == "manual" ) {
manual = true;
automatic = false;
modeSwitchValue = 0;
}
if ( receivedData == "automatic") {
automatic = true;
manual = false;
modeSwitchValue = 1;
}
while ((manual == true) && (modeSwitchValue == 0) ) {
String s = "Manual mode:";
while (checkPrint(s) == true) {
Serial.println(s);
}
automatic = false;
}
while ((automatic == true) && (modeSwitchValue == 1)) {
String s = "Automatic mode:";
while (checkPrint(s) == true) {
Serial.println(s);
}
manual = false;
}
}
}
void changeMode() {
if ( modeSwitchValue == 0) {
modeSwitchValue = 1;
automatic = true;
manual = false;
}
if ( modeSwitchValue == 1) {
modeSwitchValue = 0;
manual = true;
automatic = false;
}
}
I deleted checkPrint() function cause it only ensures msgs are printed once so its not essential to show here i think
I thought that while executing automatic code, i press button and it interrupts,changing mode variable then goes back to same place in program where the interrupt occured. then software notices that while loop condition of automatic mode is not fulfilled anymore so it breaks out to loop() and finds while loop of manual mode to be executed since the conditions are met. am i thinking wrong? or have i missed something?

If you really want to attach an ISR to the RISING edge of a button signal, you should ignore multiple triggers. Minimum 2 msec, but why not ignore everything that's unrealistic (e.g. 100 msec)
As you just toggle two states, I'd propose a boolean variable istate.
volatile bool istate; // the state maintained in the ISR changeMode
void changeMode() {
static unsigned long lastime;
if (millis() - lastime > 100) {
lastime = millis();
istate = ! istate;
}
}
All other redundant stuff (automatic, manual) can be built from that volatile ISR variable in the main code, if necessary.
In my unterstanding, the name buttonState is just wrong. And the variable unnecessary.
Do you know the data type enum?
enum {MANUAL, AUTO} mode;
if (istate) mode = AUTO;
else mode = MANUAL;
might be nice for your purpose.

You are mixing up assignment "=" and comparison "==" in your changeMode() function. Here is a corrected version of the function.
void changeMode() {
if ( buttonState == HIGH) {
modeSwitchValue = 1;
automatic = true;
manual = false;
buttonState = LOW;
}
if (buttonState == LOW) {
modeSwitchValue = 0;
manual = true;
automatic = false;
buttonState = HIGH;
}
}
You should also realize that mechanical buttons can have contact bounce. Since you are using an interrupt to detect changes in the button state you might get erratic behavior. Usually, it is better to poll the button state and apply a de-bounce time delay on the order of 20ms.
You also have not shared how the button is wired. Since you are detecting a rising edge, I assume that the button is wired to pull the pin high when pressed. If you are using a single-pole single-though button, you will need a pull down resistor to ground, otherwise the interrupt pin will float.
You can avoid the required pull-up or pull down resistor, by connecting a simple button between the input pin and ground. Then change your initialization code to
pinMode(pin, INPUT_PULLUP)
You will then want to trigger interrupt on the falling edge.
I hope this helps.

Related

ISR entered without any enabled when no interrupt flag is set. Double firing?

​
I am using the ADC on my STM32L431 with both DMA and interruption. Everything works fine, except that the ISR is often entered with none of the enabled interrupt flag being set.​
Initial ISR code:
void ADC1_IRQHandler()
{
if(LL_ADC_IsActiveFlag_JEOC(ADC1))
{
inj_buf[BL - DMA1_Channel1->CNDTR] = ADC1->JDR1;
}
else if(LL_ADC_IsActiveFlag_OVR(ADC1))
{
LL_ADC_ClearFlag_OVR(ADC1);
}
else
{
__NOP(); //A breakpoint is set here and it is reached quite often
}
}
Somebody pointed out in the post I posted on ST forum that this is caused by the program exiting ISR too soon, therefore the interrupt flag is not yet cleared, then the program would enter ISR again. As soon as the ISR entered the flag finally gets cleared.
Since then, I tried to fixed it by doing the following:
1.
void ADC1_IRQHandler()
{
if(LL_ADC_IsActiveFlag_JEOC(ADC1))
{
inj_buf[BL - DMA1_Channel1->CNDTR] = ADC1->JDR1;
__DSB();
}
else if(LL_ADC_IsActiveFlag_OVR(ADC1))
{
LL_ADC_ClearFlag_OVR(ADC1);
__DSB();
}
else
{
__NOP();
}
}
void ADC1_IRQHandler()
{
if(LL_ADC_IsActiveFlag_JEOC(ADC1))
{
inj_buf[BL - DMA1_Channel1->CNDTR] = ADC1->JDR1;
loop_cnt++; //Read - Modify - Write
if(loop_cnt >= 1024) loop_cnt = 0;
}
else if(LL_ADC_IsActiveFlag_OVR(ADC1))
{
LL_ADC_ClearFlag_OVR(ADC1);
loop_cnt++;
loop_cnt--;
}
else
{
__NOP();
}
}
According to this article by ARM
void ADC1_IRQHandler()
{
if(LL_ADC_IsActiveFlag_JEOC(ADC1))
{
inj_buf[BL - DMA1_Channel1->CNDTR] = ADC1->JDR1;
temp_isr = ADC1->ISR & 0x7FF; //Read immediately after write
}
else if(LL_ADC_IsActiveFlag_OVR(ADC1))
{
LL_ADC_ClearFlag_OVR(ADC1);
temp_isr = ADC1->ISR & 0x7FF;
}
else
{
__NOP();
}
}
According to this post on a different forum
But none of them solved the issue.
Please help! Thank you in advance!
This should be a comment rather than an answer, but I don't quite have enough reputation to just comment. Anyway...
Why are you reading the ADC values in the ISR and storing them in a buffer, if you are DMAing the data anyway? This seems pointless and confused. Are you DMAing into SRAM, or into another peripheral?
If the answer is SRAM, these ISRs are not required. Disable interrupts for the ADC, and (maybe, or maybe not) enable them for the DMA.

STM32 Uart Interrupt Burst transmit problem

I'm trying to implement uart in interrupt mode, but something go wrong obviously. Here is my problem: I want to send some strings as soon as possible (example: want to send 10 times string "test123") but for some reason that isn't possible (I make some mistake but can't understand where is that mistake). I use STM32CubeIDE, mcu is stm32f407vgt6. After first successful transmit code fall into Error_Handler() which is not acceptable. When I use delays between each transmit all string will be successful transmitted but why that can be done in this way.Here is code
uint8_t TxData[] = "test123\n";
bool flagTxCmpltUsart = true;
for(i = 0; i < 10; i++){`
if(HAL_UART_Transmit_IT(&huart3, TxData, strlen(TxData)) != HAL_OK)
{
Error_Handler();
}
Wait_Unit_Uart_Tx_Is_Complete();
Reset_Uart_Tx_Complete_Flag();}
void Reset_Uart_Tx_Complete_Flag(void)
{
flagTxCmpltUsart = false;
}
void Wait_Unit_Uart_Tx_Is_Complete(void)
{
while(!flagTxCmpltUsart){}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART3)
{
flagTxCmpltUsart = true;
}
}
Since void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) is called in the interrupt context, you should set your complete flag as
volatile bool flagTxCmpltUsart = true;
To make sure the compiler knows that is could change outside of the normal program flow.
You have to check your UART status, you'll get error if the transmission line is busy. Try to insert the following code between each call;
while (HAL_UART_GetState(&UartHandle) != HAL_UART_STATE_READY){
//Do Something..
}

function call not returning to correct location

struggling with what should be a simple function call and return (PIC micro, XC16 compiler). The return seems to go to the wrong location as if the program counter is not storing its value properly. Probably finger trouble on my part.
Function to determine the status of a switch (if switch held closed continue with output sequence, otherwise wait), not the best programming, I know.
void check() //check the switch status to continue or stop sequence
{
if (PORTFbits.RF2==0) //If the switch is closed then start time check
{
__delay_ms(500);
if (PORTFbits.RF2==0) //If the switch is still closed after 0.5s then resume sequence
{
return ;
}
}
check(); // otherwise loop, wait for next switch close
}
In the main function sequence some outputs (in a while loop)-
LATDbits.LATD0 = 1;
SaveD = LATD; // Save the status of the outputs
check(); // Check the switch status
__delay_ms(500);
LATD = 0;
LATDbits.LATD1 = 1;
SaveD = LATD;
check();
__delay_ms(500);
LATD = 0;
LATDbits.LATD2 = 1;
check();
The check() function is being called but the return goes back to the first instruction in main rather than executing the next instruction after the function call.
Am I doing something silly?
Regards
Active
Your problem stems from the fact that you are likely overflowing your stack.
Consider your code:
void check() //check the switch status to continue or stop sequence
{
if (PORTFbits.RF2==0) //If the switch is closed then start time check
{
__delay_ms(500);
if (PORTFbits.RF2==0) //If the switch is still closed after 0.5s then resume sequence
{
return ;
}
}
check(); // otherwise loop, wait for next switch close
}
In the case where PORTFbits.RF2 != 0 you will immediately fall through to the next call to check().
This means that in one or two instructions, you are recursing (when a function calls itself, that is named recursion - the function is a recursive function, it recurses on itself, etc.).
So, in a very small amount of time, you could have tens, hundreds, or thousands of calls to the check() function.
Each of those calls will push the return address of the call onto the stack, consuming stack space. Eventually, as some commenters have pointed out, you'll either crash the machine entirely, or force a reset. Forcing a reset will restart your code in main, as you have seen.
As written, your code will not return from the outermost check() call until the switch is closed. Assuming that is what you want, here's some code that might work:
void wait_for_switch()
{
while (1) {
if (PORTFbits.RF2 == 0) { /* Switch is closed. */
__delay_ms(500); /* Debounce interval. */
if (PORTFbits.RF2 == 0) return; /* Still closed? Done! */
}
else {
/* Wait for switch to close. */
__delay_ms(100);
}
}
}
UPDATE:
Hearing that your compiler isn't reloading the switch bits, led me to this alternative. I suspect that the first read of the bits in the function will work, so let's just put the port read into a function:
int read_portfbits_rf2() {
return PORTFbits.RF2;
}
void wait_for_switch()
{
while (1) {
if (read_portfbits_rf2() == 0) { /* Switch is closed. */
__delay_ms(500); /* Debounce interval. */
if (read_portfbits_rf2() == 0) return; /* Still closed? Done! */
}
else {
/* Wait for switch to close. */
__delay_ms(100);
}
}
}

Serial.print only once Arduino

I have a light sensor that prints the value of its input to the Serial monitor. It's pretty much a trip wire but when an object is in its way, it prints the value every 1 millisecond. If I add a delay it won;t trigger the second sensor until the delay is done. How would I get it to only print once, without any disturbance or interference with the other sensors?
void loop() {
if (analogRead(sensor1) == 0) {
timer.start ();
tStop = false;
//Serial.println (timer.elapsed());
Serial.println ("Start Time = 0");
}
This is quite an interesting problem, in the normal world of computers we would solve this via threading. However as you are running without an OS we have to do one of two things, implement coroutines (fake threading without an OS) or use asynchronous code and interrupts.
My understanding is that you print something when an object first comes into the way of your sensor, as the arduino uno as opposed to the due is not easy to implement coroutines on we shall try the interrupt route.
First you will likely be interested in this library http://playground.arduino.cc/Code/Timer1
It allows you to add an interrupt service routine to run on a timer. Use the attachInterrupt(function, period) function in the library for this.
In your interrupt service routine you will want to check the sensor, set a variable to say how long ago since it was last triggered and print the message if appropriate. This means your main loop is completely free to run other code and will not block your other sensors.
For example:
void TimFun()
{
static int LastRead;
if(LastRead && (0 == analogRead(sensor1))
{
Serial.println("SensorTrip");
}
LastRead = analogRead(sensor1);
}
void loop()
{
// Do other stuff here
}
void setup()
{
Timer1.initialize(100000);
Timer1.attachInterrupt(TimFun);
// Rest of setup Here
}
I managed to make an int before the void setup and then used a while loop. with in the if statement.
int i = 1;
if (analogRead(sensor1) == 0) {
timer.start ();
tStop = false;
while (i == 1) {
Serial.println ("Start Time = 0");
i++;
}
}
You probably should use an if instead of a while loop that will never execute more than once.
bool tripped = false;
void setup(){
//setup stuff here
}
void loop() {
if ( analogRead(sensor1) == 0 )
{
timer.start ();
tStop = false;
if ( tripped == false )
{
Serial.println ("Start Time = 0");
tripped = true;
}
}
}

How to set an int to 1 if dependent on a button and in a while loop?

I'm programming a robot, and unfortunately in its autonomous mode I'm having some issues.
I need to set an integer to 1 when a button is pressed, but in order for the program to recognize the button, it must be in a while loop. As you can imagine, the program ends up in an infinite loop and the integer values end up somewhere near 4,000.
task autonomous()
{
while(true)
{
if(SensorValue[positionSelectButton] == 1)
{
positionSelect = positionSelect + 1;
wait1Msec(0350);
}
}
}
I've managed to get the value by using a wait, but I do NOT want to do this. Is there any other way I can approach this?
assuming that the SensorValue comes from a physical component that is asynchronous to the while loop, and is a push button (i.e. not a toggle button)
task autonomous()
{
while(true)
{
// check whether
if(current_time >= next_detect_time && SensorValue[positionSelectButton] == 1)
{
positionSelect = positionSelect + 1;
// no waiting here
next_detect_time = current_time + 0350;
}
// carry on to other tasks
if(enemy_is_near)
{
fight();
}
// current_time
current_time = built_in_now()
}
}
Get the current time either by some built-in function or incrementing an integer and wrap around once reach max value.
Or if you are in another situation:
task autonomous()
{
while(true)
{
// check whether the flag allows incrementing
if(should_detect && SensorValue[positionSelectButton] == 1)
{
positionSelect = positionSelect + 1;
// no waiting here
should_detect = false;
}
// carry on to other tasks
if(enemy_is_near)
{
if(fight() == LOSING)
should_detect = true;
}
}
}
Try remembering the current position of the button, and only take action when its state changes from off to on.
Depending on the hardware, you might also get a signal as though it flipped back and forth several times in a millisecond. If that's an issue, you might want to also store the timestamp of the last time the button was activated, and then ignore repeat events during a short window after that.
You could connect the button to an interrupt and then make the necessary change in the interrupt handler.
This might not be the best approach, but it will be the simplest.
From The Vex Robotics catalogue :
(12) Fast digital I/O ports which can be used as interrupts
So, most probably which ever micro-controller of Vex you are using will support Interrupts.
Your question is a bit vague
I m not sure why u need this variable to increment and how things exactly work...but i ll make a try.Explain a bit more how things work for the robot to move...and we will be able to help more.
task autonomous()
{
int buttonPressed=0;
while(true)
{
if(SensorValue[positionSelectButton] == 1)
{
positionSelect = positionSelect +1;
buttonPressed=1;
}
else{
buttonPressed = 0;
}
//use your variables here
if( buttonPressed == 1){
//Move robot front a little
}
}
}
The general idea is :
First you detect all buttons pressed and then you do things according to them
All these go in your while loop...that will(and should) run forever(at least as long as your robot is alive :) )
Hope this helps!

Resources