Zrobiłem to, sprawdzając migawki zamiast czasu. Myślę, że w ten sposób jest mniej narzutów. Jednak nadal staram się ulepszyć algorytm odbijania, ponieważ nie jestem z niego w pełni zadowolony: nadal istnieją odbijania, chociaż są one rzadsze niż wcześniej.
#include <linux / jiffies.h>extern unsigned long volatile jiffies; static irqreturn_t irq_handler (int irq, void * dev_id, struct pt_regs * regs) {static unsigned long old_jiffie = 0; unsigned long diff = jiffies - old_jiffie; if (diff < 20) {return IRQ_HANDLED; } printk (KERN_NOTICE "Przerwanie [% d] dla urządzenia% s zostało wywołane, jiffies =% lu, diff =% lu, direction:% d \ n", irq, (char *) dev_id, jiffies, diff, gpio_get_value (GPIO_BUTTON1 )); old_jiffie = jiffies; return IRQ_HANDLED;}
Udało mi się jeszcze bardziej udoskonalić algorytm odbijania. Teraz wyzwalam przerwanie, gdy linia osiągnie LOW zamiast opadającej krawędzi. Następnie w obsłudze przerwań zmieniam przerwanie, aby następnym razem było wyzwalane na WYSOKIE, potem na NISKIE i tak dalej. To w połączeniu z metodą jiffies z góry znacznie zmniejsza odbicia.
Myślę, że to najlepsze, co można osiągnąć w oprogramowaniu. Dla dalszych ulepszeń myślę, że rzeczywiście trzeba to zrobić w sprzęcie. Kiedy będę miał czas, spróbuję z kondensatorem i tym podobnymi rzeczami.
Pełny kod poniżej:
#include <linux / module.h> #include <linux / kernel .h> #include <linux / init.h> # include <linux / interrupt.h> # include <linux / gpio.h> # obejmują <linux / irq.h> # include <linux / jiffies.h> #define DRIVER_AUTHOR "" #define DRIVER_DESC "pad Przycisk" extern unsigned long volatile jiffies; struct _Button {unsigned gpio; int irq; const char * opis; char last_value;}; typedef struct _Button Button;
// chcemy, aby GPIO 17,27,22 (pin 11,13,15 na płytce pinout raspberry pi rev. 2 P5) generowało przerwanieButton button1 = {17, 0, "Gpio dla przycisku 1", 1}; Button button2 = {27, 0, "Gpio dla przycisku 2", 1}; Button button3 = {22, 0, "Gpio dla przycisku 3", 1}; / **************** ************************************************ ********** // * Obsługa IRQ - uruchamiana przy przerwaniu * // **************************** ************************************************/statyczny irqreturn_t irq_handler (int irq, void * dev_id, struct pt_regs * regs) {Button * button = (Button *) dev_id; wartość znaku = gpio_get_value (przycisk->gpio); if (wartość == button->last_value) return IRQ_HANDLED; if (0 == wartość) {static unsigned long old_jiffie = 0; unsigned long diff = jiffies - old_jiffie; if (diff < 23) {button->last_value = wartość; irq_set_irq_type (irq, IRQ_TYPE_LEVEL_HIGH); // old_jiffie = jiffies; return IRQ_HANDLED; } printk (KERN_NOTICE "Przerwanie [% d] dla urządzenia% s zostało wywołane, jiffies =% lu, diff =% lu, direction:% d \ n", irq, button->description, jiffies, diff, value); irq_set_irq_type (irq, IRQ_TYPE_LEVEL_HIGH); old_jiffie = jiffies; } else {irq_set_irq_type (irq, IRQ_TYPE_LEVEL_LOW); } button->last_value = wartość; return IRQ_HANDLED;} / ******************************************* ******************************* // * Ta funkcja konfiguruje przerwania. * // *********************************************** ***************************** / void int_config (przycisk * przycisk) {if (! przycisk || gpio_request (przycisk->gpio, button->description)) {printk ("Błąd żądania GPIO:% s \ n", button->description); powrót; } gpio_direction_input (button->gpio);
if ((button->irq = gpio_to_irq (button->gpio)) < 0) {printk ("Faiure mapowania GPIO na IRQ% s \ n", button->description); powrót; } printk (KERN_NOTICE "Mapowany int% d \ n", przycisk->irq); if (request_irq (button->irq, (irq_handler_t) irq_handler, IRQF_TRIGGER_LOW, button->description, button)) {printk ("Błąd żądania Irq \ n"); powrót; } powrót;}/********************************************* ******************************* // * Ta funkcja zwalnia przerwania. * // *********************************************** ***************************** / void int_release (przycisk * przycisk) {free_irq (przycisk->irq, przycisk); gpio_free (button->gpio); return;} int init_module (void) {printk (KERN_INFO "init_module () o nazwie \ n"); int_config (&button1); int_config (&button2); int_config (&button3); return 0;} void cleanup_module (void) {printk (KERN_INFO "cleanup_module () o nazwie \ n"); int_release (&button1); int_release (&button2); int_release (&button3);} / ***************************************** ********************************* // * Blok licencji / opisu modułu. * // *********************************************** ***************************** / MODULE_LICENSE ("GPL"); MODULE_AUTHOR (""); MODULE_DESCRIPTION ("Sterownik GPIO RaspeberryPi ");