Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
307 views
in Technique[技术] by (71.8m points)

c - Slight Delay After Returning from Interrupt

I've written a small program that uses a button on an STM32 Discovery board to act as a counter in either Binary/Decimal/Hexadecimal mode (screen cycles through the 3 options and once pressed, counts up to 16 for each press before resetting to cycling through options).

I'm encountering one small "bug" (read, not really) that has me a little confused. If I count up in Decimal/Hexadecimal, it returns to cycling through the options immediately but if I have counted up in Binary it takes ~1sec or so before doing so (a noticeable delay).

int main(void)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
    lcd_init();
    button_init();

    while (1)
    {
        while (!counting) {
            standard_output();
        }
    }

}

void standard_output(void) {
    state = 0;
    lcd_command(0x01);
    delay_microsec(2000);
    lcd_putstring("Binary");
    for (i=0; i<40; i++) delay_microsec(50000);     // keep display for 2 secs
    if (counting) return;                           // if we have pressed the button, want to exit this loop
    state = 1;
    lcd_command(0x01);
    delay_microsec(2000);
    lcd_putstring("Decimal");
    for (i=0; i<40; i++) delay_microsec(50000);     // keep display for 2 secs
    if (counting) return;                           // if we have pressed the button, want to exit this loop
    state = 2;
    lcd_command(0x01);
    delay_microsec(2000);
    lcd_putstring("Hexadecimal");
    for (i=0; i<40; i++) delay_microsec(50000);     // keep display for 2 secs
    if (counting) return;                           // if we have pressed the button, want to exit this loop

}

void EXTI0_IRQHandler(void) {
    if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
        if (!stillBouncing) {                               // a button press is only registered if stillBouncing == 0
            if (!counting) {                                // if we weren't already counting, a valid button press means we are now
                counting = 1;
                count = 0;                                  // starting count from 0
            }
            else {
                count++;
            }
            if (count < 16) {
                lcd_command(0x01);
                delay_microsec(2000);
                format_int(count);
            }
            else {
                counting = 0;                               // we are no longer counting if count >= 16
            }
        }
        stillBouncing = 10;                                 // every time a button press is registered, we set this to 10
        while (stillBouncing > 0) {                         // and check that it hasn't been pressed for 10 consecutive 1000microsec intervals
            if (!delay_millisec_or_user_pushed(1000)) {
                stillBouncing--;
            }
        }
    }
    EXTI_ClearITPendingBit(EXTI_Line0);
}

void format_int(unsigned int n) {
    if (state == 0) {                                       // if we selected binary
        for (i=0;i<4;++i) {
            num[i] = (n >> i) & 1;                          // generate array of bit values for the 4 least significant bits
        }
        i = 4;
        while (i>0) {
            i--;
            lcd_putint(num[i]);                             // put ints from array to lcd in reverse order to display correctly
        }
    }
    else if (state == 1) {                                  // if we selected decimal
        lcd_putint(n);                                      // lcd_putint is enough for decimal
    }
    else {                                                  // if we selected hex
        snprintf(hex, 4, "%x", n);                          // format string such that integer is represented as hex in string
        lcd_putstring(hex);                                 // put string to lcd
    }
}

int delay_millisec_or_user_pushed(unsigned int n)
{
    delay_microsec(n);
    if (!GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) {
        return 0;
    }
    return 1;
}

I really have no idea why it is doing this and have played around with it now but still unable to figure it out. It's fine as is but I would like to know why it is doing this.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Probably lcd_putint takes a lot of time to refresh the display. It probably convert each number to string and then put it to the screen. format_int() In binary case it loops 4 times, then 4 times more than Hex and Dec cases.

If you change the code as below, It will, I guess, be faster:

char bin[5];
sprintf(bin, "%d%d%d%d", ((n&0x08)>>3), ((n&0x04)>>2), ((n&0x02)>>1), (n&0x01));
lcd_putstring(bin);

I know there are a lot of solutions to convert number to binary string, but the key point is to use lcd_putstring that is surely faster then call 4 times lcd_putint


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...