RPi 4 GPIO 中断上升和下降触发器在 C 中不起作用

RPi 4 GPIO Interrupt on Rising and Falling trigger not working in C

初学者在这里学习编写 linux 内核模块。

我想用 C 语言为我的树莓派 4 编写一个内核模块。

我想在按下按钮时使用中断点亮 LED。只要按下按钮,LED 就会亮起,当我松开按钮时,LED 应该会熄灭。

我使用函数 request_irq() 以便通过指示“IRQF_TRIGGER_FALLING | [=37= 在按钮的上升沿和下降沿调用处理中断的函数]”。我以前使用函数 gpio_to_irq(BUTTON_PIN).

request_irq(button_irq, button_ih, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "button_irq", NULL);

当我按下按钮时调用该函数,但当我释放它时不调用该函数。它的编码如下所示:

static irqreturn_t button_ih(int irq, void *data)
{
    int state;
    
    state = gpio_get_value(BUTTON_PIN);

    printk(KERN_INFO "Actual state of the button : %d", state);
    
    //Debounce condition
    if(jiffies - last_interrupt_time > msecs_to_jiffies(200))
    {
        if(state)
        {
            gpio_set_value(LED_PIN, 1);
        }else
        {
            gpio_set_value(LED_PIN, 0);
        }
    }
    last_interrupt_time = jiffies;

    return IRQ_HANDLED;
}

我检查按钮的值是 1(按下)还是 0(松开),并想相应地打开 on/off LED。

当我尝试不同的 GPIO 时,有时我的按钮的值是 1,即使我还没有按下它(通过从 init 函数打印消息)有时它是 0。所以我不明白如果我做错了什么。我认为 GPIO 尚未使用,因为我可以使用函数 gpio_request_one().

请求它们

因此当按钮已经具有值 1 时,当我释放按钮时 LED 亮起但不会关闭。

并且当值已经是0时,当我进入中断处理函数时按钮值并没有变成1(而且LED显然没有亮)。

你能告诉我它有什么问题吗?

形成简单的C程序,不是内核模块 这个最少看看我是怎么做的。 main.h

typedef struct s_Data {
    int exitFlag;
    struct {int value; int bcmPin;} In01; //<--- Stock actual GPIO Value
    struct {int value; int bcmPin;} In02;
    ....
    struct {int value; int bcmPin;} Out01;
    struct {int value; int bcmPin;} Out02;
    ....
} t_Data;

#define NO_Click 0
#define SimpleClick 1
#define LongClick 2
#define MultiClick 3

typedef struct s_Button {
    pthread_t button_thread;
    int *exitFlag;
    int * input; //Button
    int * output;
    int old_state;
    int new_state;
    struct timeval t0;
    struct timeval t1;
    struct timeval pressedTime;
    struct timeval releasedTime;
    int clickType;
    //float debounce = 0.020; // ms debounce period to prevent flickering when pressing or releasing the button
    // debounce not necessary while thread have time to take a coffee
    float DCgap;            // max ms between clicks for a double click event
    float holdTime;        // ms hold period: how long to wait for press+hold event
} t_Button;

main.c

#include "main.h"
#include <wiringPi.h>
#include <pthread.h>

// initial state
static t_Data data = {
  .exitFlag = 0,
  .In01.value = 0,  .In01.bcmPin = 4,
  .In02.value = 0,  .In02.bcmPin = 17,
  .Out01.value = 0, .Out01.bcmPin = 4,
  .Out02.value = 0, .Out02.bcmPin = 17,
}

static _Data data_prev;

static void *inputRead_threadFn(void *p_Data) {
   pinMode(Data.In01.bcmPin, INPUT);
   pullUpDnControl(Data.In01.bcmPin, PUD_UP);
   pinMode(Data.In02.bcmPin, INPUT);
   pullUpDnControl(Data.In02.bcmPin, PUD_UP);

   while (!Data.exitFlag) {
      Data.In01.value = !digitalRead(Data.In01.bcmPin);
      Data.In02.value = !digitalRead(Data.In02.bcmPin);
      if (Data.In01.value != Data_old.In01.value) {
        Data_old.In01.value = Data.In01.value;
      }
      if (Data.In02.value != Data_old.In02.value) {
        Data_old.In02.value = Data.In02.value;
      }
      usleep(50)
   }
}

static void *outputWrite_threadFn(void *p_Data) {
   pinMode(Data.In01.bcmPin, OUTPUT);
   pinMode(Data.In02.bcmPin, OUTPUT);

   while (!Data.exitFlag) {
      digitalWrite(Data.Out01.bcmPin, !Data.Out01.value);
      digitalWrite(Data.Out02.bcmPin, !Data.Out02.value);
   }
   usleep(50)
}

static void *button_threadFn(void *p_Data) {
  t_Button *button = (t_Button *)p_data;

  LOG("Button[%s] thread initialized\r\n", button->name);

  button->old_state = 0;
  button->new_state = 0;
  button->clickType = NO_Click;


  int clickCount = 0;
    
  while(*(button->exitFlag) == 0) {
    
    button->new_state = *(button->input) || *(button->web_input); //*((int *)

    if( button->old_state == 0 && button->new_state == 1 ) {
       //printf("front montant\r\n"); fflush(stdout);
        // *****************************   
        // traitement sur front montant
        // rising edge
        // ***************************** 

        button->old_state = 1;
        
        gettimeofday(&button->pressedTime, 0);
        
        //Button pressed
  

    } else if( (button->old_state == 1) && (button->new_state == 0) ) {
        //printf("front descendant\r\n"); fflush(stdout);
        // ***************************** 
        // traitement sur front descendant
        // falling edge
        // ***************************** 
        button->old_state = 0;
        gettimeofday(&button->releasedTime, 0);
        
        if (my_timedifference_msec(button->releasedTime, button->pressedTime ) < button->DCgap) {
            clickCount++;
            button->clickType = MultiClick;
        }
        
        
        //Button released
        
        
    } else if( (button->old_state == 0) && (button->new_state == 0) ) {
       // printf("front bas\r\n"); fflush(stdout);
        // ***************************** 
        // pas de changement d'état : front bas
        // no state change : edge down
        // ***************************** 
        gettimeofday(&button->t0, 0);
        

        *(button->output) = 0; //<--- here in your case

        //Attendre DC_Gap pour connaitre le nombre de click
        // Wait for DC_Gap to know click count
        if (my_timedifference_msec(button->t0, button->releasedTime) > button->DCgap) {
            if (clickCount == 1) {
                LOG("SimpleClick");
                //Simple Click

            } else if ( clickCount > 1 ) {
                //Multiclicks
            }
            button->clickType = NO_Click;
            clickCount = 0;
        }
        
    } else if( (button->old_state == 1) && (button->new_state == 1) ) {
       // printf("front haut\r\n"); fflush(stdout);
        // ***************************** 
        // pas de changement d'état : front haut
        // no state change : edge up
        // ***************************** 
        gettimeofday(&button->t1, 0);
        
        *(button->output) = 1; //<--- here in your case
       
        //long click
        if (my_timedifference_msec(button->t1, button->pressedTime) >= button->holdTime) {
            LOG("LongClick");
            button->clickType = LongClick;

            //do what you want while not released

            usleep(30*1000);
        }
    }
    usleep(100);   
  }
  printf("Light Loop::exiting...\r\n"); fflush(stdout);
}

int main(int argc, char** argv) {
   wiringPiSetup();
   wiringPiSetupGpio();

   data_prev = data;

   //start input thread
   //start output thread

   int DCGap = 250; //ms
   int HoldTime = 600;
   t_Button Buttons[] = {
    { //WC
        .exitFlag = &Data.exitFlag,
        .DCgap = DCGap,
        .holdTime = HoldTime,
        .input = &Data.In01.value,
        .output = &Data.Out01.value,
    },
    { //chambre
        .exitFlag = &Data.exitFlag,
        .DCgap = DCGap,
        .holdTime = HoldTime,
        .input = &Data.In02.value,
        .output= &Data.Out02.value,
    }
   }
   //start buttons threads
   for (i = 0; i < (sizeof(Buttons) / sizeof(t_Button)) ; i++) {
     ret = pthread_create (&Buttons[i].button_threadFn, NULL, fn_Button, &Buttons[i]); 
     if (ret) {
         fprintf (stderr, "%s", strerror (ret));
     }
   }


   //threads join

   return (EXIT_SUCCESS);
}

好的,谢谢大家 comments/answers。

确实是因为我没有正确使用任何 pull-up 或 pull-down 电阻。

所以我改变了我的电路如下: Circuit