问题描述
从这里开始学习编码Linux内核模块的代码。
我想用C语言为RPi 4编写一个内核模块。
我想在按下按钮时使用中断来点亮LED。只要按下按钮,LED就会亮起,而当我松开它时,LED应该会熄灭。
我使用了request_irq()函数,以便通过指示“ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING”在按钮的上升沿和下降沿调用处理中断的函数。我以前使用过函数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(释放),并希望相应地打开/关闭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,.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);
}
,
好的,谢谢所有的评论/答案。
确实是因为我没有正确使用任何上拉或下拉电阻器。
因此,我将电路更改如下: Circuit