Warning: file_get_contents(https://graph.facebook.com/?ids=http%3A%2F%2Fwww.stsystem.pl%2Findex.php%3Foption%3Dcom_content%26view%3Darticle%26id%3D29) [function.file-get-contents]: failed to open stream: HTTP request failed! HTTP/1.1 403 Forbidden in /domains/stsystem.pl/public_html/plugins/content/fbar/fbar.php on line 210

Warning: file_get_contents(https://graph.facebook.com/?ids=http%3A%2F%2Fwww.stsystem.pl%2Findex.php%3Foption%3Dcom_content%26view%3Darticle%26id%3D29) [function.file-get-contents]: failed to open stream: HTTP request failed! HTTP/1.1 403 Forbidden in /domains/stsystem.pl/public_html/plugins/content/fbar/fbar.php on line 210

Przesiadając się z programowania liniowego na programowanie pseudowielowątkowe, nieodzownym stało się w moim przypadku opracowanie wydajnych i konfigurowalnych funkcji do obsługi wejść cyfrowych. W przykładowym Sterowniku Pneumatycznym Atrakcji użyłem:

- 3 klawiszy nawigacyjnych na panelu czołowym

- 4 wejść ogólnego przeznaczenia

- 1 wejścia 230V (w tej aplikacji nie wykorzystywane)

Musiałem opracować funkcje, które umożliwiłyby mi:

- opóźnienie reakcji na naciśnięcie/puszczenie klawisza (debounce)

- opóźnienie "samopowtarzania" przy utrzymującym się na wejściu stanie pobudzenia

- wybór reakcji na zbocze sygnału (wyzwolenie jednorazowe czy samopowtarzanie)

- wybór poziomu "widzianego" przez dane wejście jako aktywny

- wykonanie funkcji użytkownika wywoływanej przy aktywacji wejścia

Próby trwały dość długo, powstało wiele wersji kodu. Finalna wersja, zoptymalizowana i wyczyszczona jest, moim skromnym zdaniem, niezwykle atrakcyjna z punktu widzenia użytkownika piszącego program. Starałem się, aby biblioteka była prosta i czytelna zarówno w konfiguracji, jak i w późniejszym używaniu wywołań konkretnych wejść. Jako ciekawostkę muszę przedstawić sposób konfiguracji wejść pod kątem reakcji na zbocze sygnału i jego poziom logiczny. Przyjąłem koncepcję, wg której na etapie pisania programu wiem jakim poziomem logicznym pobudzam poszczególne wejścia. Stąd konfiguracja tego parametru zaszyta jest w plikach nagłówkowych jako #define i zostaje przekazana do funkcji obsługujących wejścia już na etapie kompilacji. Inaczej sytuacja przedstawia się z konfiguracją reakcji na zbocze sygnału. Potrzebowałem sposobu, który umożliwiałby mi zmianę tego parametru z poziomu programu użytkownika. Stąd narodziła się ciekawa funkcja realizująca sprawdzanie logicznego ExclusiveNOR (EXNOR). Dzięki temu prostemu zabiegowi daję użytkownikowi możliwość zmiany działania niektórych wejść z poziomu menu (przy czym zmiana poziomu logicznego nie jest tutaj możliwa). Nic nie szkodzi na przeszkodzie, aby bibliotekę przerobić w taki sposób, żeby zmiana poziomu logicznego na wejściu również była możliwa z poziomu programu. 

Biblioteka składa się z kilku plików:

  1. klawisze_libr_conf.h - tutaj określamy, które z wejść jest użyte w programie oraz jakim poziomem logicznym jest aktywowane
  2. klawisze.h - tutaj określamy numery i nazwy portów do których podłączone mamy konkretne wejścia, w pliku tym znajdują się także makra, przyjazne dla użytkownika wywołania funkcji i troszkę innych rzeczy potrzebnych do działania bilbioteki.
  3. klawisze.c - właściwy plik zawierający ciało funkcji obsługującej wejścia

Zdecydowałem, że kod przypisany poszczególnym wejściom kompilowany będzie tylko wtedy, gdy dane wejście zostanie oznaczone jako aktywne w pliku libr_conf - pozwala to zaoszczędzić trochę miejsca w procesorze, gdy np chcemy użyć tylko 2 z dostępnych 8-iu wejść. Oprócz 3 powyższych plików biblioteka korzysta także z nagłówka MACROS.h znanego z artykułu o wyświetlaczu alfanumerycznym.

- zawartość pliku klawisze_libr_conf.h

#ifndef Klawisze_libr_conf_H
#define Klawisze_libr_conf_H
//WYBOR KOMPILOWANYCH PODPROGRAMOW
#define UP_AKTYWNY 1
#define DOWN_AKTYWNY 1
#define OK_AKTYWNY 1
#define WE1_AKTYWNY 1
#define WE2_AKTYWNY 1
#define WE3_AKTYWNY 1
#define WE4_AKTYWNY 1
#define ZEW_AKTYWNY 0
//***************************************************************************
//Opcjonalne makra do uzycia w programie, nie powiazane z funkcjami tej biblioteki
#define pressMacros 1
// 1- reakcja na stan wysoki, 0 reakcja na stan niski
#if UP_AKTYWNY==1
#define UP_Level 0
#endif
#if DOWN_AKTYWNY==1
#define DOWN_Level 0
#endif
#if OK_AKTYWNY==1
#define OK_Level 0
#endif
#if WE1_AKTYWNY==1
#define WE1_Level 1
#endif
#if WE2_AKTYWNY==1
#define WE2_Level 1
#endif
#if WE3_AKTYWNY==1
#define WE3_Level 1
#endif
#if WE4_AKTYWNY==1
#define WE4_Level 0
#endif
#if ZEW_AKTYWNY==1
#define ZEW_Level 0
#endif
//***************************************************************************
//***************************************************************************
//***************************************************************************
//numery bitow po zmapowaniu klawiszy do zmiennych key_status, key_acts i key_rises
//nie nalezy zmieniac!
#if UP_AKTYWNY==1
#define actUPbit 0
#endif
#if DOWN_AKTYWNY==1
#define actDOWNbit 1
#endif
#if OK_AKTYWNY==1
#define actOKbit 2
#endif
#if WE1_AKTYWNY==1
#define actWE1bit 3
#endif
#if WE2_AKTYWNY==1
#define actWE2bit 4
#endif
#if WE3_AKTYWNY==1
#define actWE3bit 5
#endif
#if WE4_AKTYWNY==1
#define actWE4bit 6
#endif
#if ZEW_AKTYWNY==1
#define actZEWbit 7
#endif
#endif

- zawartość pliku klawisze.h

#ifndef Klawisze_H
#define Klawisze_H
#include <avr/io.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <util/delay.h>
#include "klawisze_libr_conf.h"
#include "opoznienie.h"
#include "MACRO_PORT.h"
#include "../TIMERY/tajmer2.h"
//***************************************************************************
//DEFINICJA PORTOW WE / WY
#if UP_AKTYWNY==1 //Klawisz UP
#define KLAW_UP_bit 7
#define KLAW_UP_port PORTC
#endif
//*************************
#if DOWN_AKTYWNY==1 //Klawisz DOWN
#define KLAW_DOWN_bit 6
#define KLAW_DOWN_port PORTC
#endif
//*************************
#if OK_AKTYWNY==1 //Klawisz OK
#define KLAW_OK_bit 5
#define KLAW_OK_port PORTC
#endif
//*************************
#if WE1_AKTYWNY==1 //Wejscie 1
#define WE1_bit 3
#define WE1_port PORTA
#endif
//*************************
#if WE2_AKTYWNY==1 //Wejscie 2
#define WE2_bit 2
#define WE2_port PORTA
#endif
//*************************
#if WE3_AKTYWNY==1 //Wejscie 3
#define WE3_bit 3
#define WE3_port PORTD
#endif
//*************************
#if WE4_AKTYWNY==1 //Wejscie 4
#define WE4_bit 2
#define WE4_port PORTD
#endif
//*************************
#if ZEW_AKTYWNY==1 //Wejscie zewnetrzne 230V
#define ZEW_bit 1
#define ZEW_port PORTB
#endif
//***************************************************************************
#if UP_AKTYWNY==1
#define KLAW_UP_ddrb DDR(KLAW_UP_port)
#define KLAW_UP_pin PIN(KLAW_UP_port)
#endif
#if DOWN_AKTYWNY==1
#define KLAW_DOWN_pin PIN(KLAW_DOWN_port)
#define KLAW_DOWN_ddrb DDR(KLAW_DOWN_port)
#endif
#if OK_AKTYWNY==1
#define KLAW_OK_pin PIN(KLAW_OK_port)
#define KLAW_OK_ddrb DDR(KLAW_OK_port)
#endif
#if WE1_AKTYWNY==1
#define WE1_pin PIN(WE1_port)
#define WE1_ddrb DDR(WE1_port)
#endif
#if WE2_AKTYWNY==1
#define WE2_pin PIN(WE2_port)
#define WE2_ddrb DDR(WE2_port)
#endif
#if WE3_AKTYWNY==1
#define WE3_pin PIN(WE3_port)
#define WE3_ddrb DDR(WE3_port)
#endif
#if WE4_AKTYWNY==1
#define WE4_pin PIN(WE4_port)
#define WE4_ddrb DDR(WE4_port)
#endif
#if ZEW_AKTYWNY==1
#define ZEW_pin PIN(ZEW_port)
#define ZEW_ddrb DDR(ZEW_port)
#endif
//***************************************************************************
//ROZPOZNANIE POBUDZEN WEJSC
#if pressMacros==1
#if UP_AKTYWNY==1
#define keyUPpress (!(KLAW_UP_pin&(1<<KLAW_UP_bit))^UP_Level)
#endif
#if DOWN_AKTYWNY==1
#define keyDOWNpress (!(KLAW_DOWN_pin&(1<<KLAW_DOWN_bit))^DOWN_Level)
#endif
#if OK_AKTYWNY==1
#define keyOKpress (!(KLAW_OK_pin&(1<<KLAW_OK_bit))^OK_Level)
#endif
#if WE1_AKTYWNY==1
#define keyWE1press (!(WE1_pin&(1<<WE1_bit))^WE1_Level)
#endif
#if WE2_AKTYWNY==1
#define keyWE2press (!(WE2_pin&(1<<WE2_bit))^WE2_Level)
#endif
#if WE3_AKTYWNY==1
#define keyWE3press (!(WE3_pin&(1<<WE3_bit))^WE3_Level)
#endif
#if WE4_AKTYWNY==1
#define keyWE4press (!(WE4_pin&(1<<WE4_bit))^WE4_Level)
#endif
#if ZEW_AKTYWNY==1
#define keyZEWpress (!(ZEW_pin&(1<<ZEW_bit))^ZEW_Level)
#endif
#endif
//***************************************************************************
extern volatile uint8_t key_status; //tu zapisane sa stany wcisnietych klawiszy (bez obrobki!!!)
//***************************************************************************
//sprawdzenie stanu pojedynczego klawisza
//Mapuje klawisze do zmiennej key_status a po stwierdzeniu, że dany klawisz jest wcisniety
//wpisuje 1 na danym bicie w key_acts, key_acts obslugiwae jest przez funkcje nadrzedna
//void Butt(uint16_t port, uint8_t pin, uint8_t id,uint8_t debounce,uint8_t level);
//Funkcja nadrzedna nad butt()
//analizuje zawartosc key_acts i wywoluje odpowiednia funkcje przekazana podczas wywolania
//Ponadto sprawdza, czy dany klawisz ma byc powtarzany, czy tez jest inicjowany zboczem.
//void keyf(uint8_t port, uint8_t pin, uint8_t id,void (*f)(void),uint8_t debounce,uint8_t rise);
enum Klawisz_zbocze {Normal,Rise};
enum Klawisz_zbocze Key_trig;
//**********************************************************************************
void keyf(uint8_t port, uint8_t pin, uint8_t id,void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise,uint8_t level);
//**********************************************************************************
#if UP_AKTYWNY==1
#define UpZbocze(a) a?(1<<actUPbit):0
inline void kUP(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise) __attribute__((always_inline));
inline void kUP(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise)
{
 keyf(KLAW_UP_pin, KLAW_UP_bit, actUPbit,*f,debounce,repeat ,UpZbocze(rise),UP_Level);
 return;
}
#endif
//**********************************************************************************
#if DOWN_AKTYWNY==1
#define DownZbocze(a) a?(1<<actDOWNbit):0
inline void kDOWN(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise) __attribute__((always_inline));
inline void kDOWN(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise)
{
 keyf(KLAW_DOWN_pin, KLAW_DOWN_bit, actDOWNbit,*f,debounce,repeat ,DownZbocze(rise),DOWN_Level);
 return;
}
#endif
//**********************************************************************************
#if OK_AKTYWNY==1
#define OkZbocze(a) a?(1<<actOKbit):0
inline void kOK(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise) __attribute__((always_inline));
inline void kOK(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise)
{
 keyf(KLAW_OK_pin, KLAW_OK_bit, actOKbit,*f,debounce,repeat ,OkZbocze(rise), OK_Level);
 return;
}
#endif
//**********************************************************************************
#if WE1_AKTYWNY==1
#define We1Zbocze(a) a?(1<<actWE1bit):0
inline void kWE1(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise) __attribute__((always_inline));
inline void kWE1(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise)
{
 keyf(WE1_pin, WE1_bit, actWE1bit,*f,debounce,repeat ,We1Zbocze(rise), WE1_Level);
 return;
}
#endif
//**********************************************************************************
#if WE2_AKTYWNY==1
#define We2Zbocze(a) a?(1<<actWE2bit):0
inline void kWE2(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise) __attribute__((always_inline));
inline void kWE2(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise)
{
 keyf(WE2_pin, WE2_bit, actWE2bit,*f,debounce,repeat ,We2Zbocze(rise), WE2_Level);
 return;
}
#endif
//**********************************************************************************
#if WE3_AKTYWNY==1
#define We3Zbocze(a) a?(1<<actWE3bit):0
inline void kWE3(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise) __attribute__((always_inline));
inline void kWE3(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise)
{
 keyf(WE3_pin, WE3_bit, actWE3bit,*f,debounce,repeat ,We3Zbocze(rise), WE3_Level);
 return;
}
#endif
//**********************************************************************************
#if WE4_AKTYWNY==1
#define We4Zbocze(a) a?(1<<actWE4bit):0
inline void kWE4(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise) __attribute__((always_inline));
inline void kWE4(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise)
{
 keyf(WE4_pin, WE4_bit, actWE4bit,*f,debounce,repeat ,We4Zbocze(rise), WE4_Level);
 return;
}
#endif
//**********************************************************************************
#if ZEW_AKTYWNY==1
#define ZewZbocze(a) a?(1<<actZEWbit):0
inline void kZEW(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise) __attribute__((always_inline));
inline void kZEW(void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise)
{
 keyf(ZEW_pin, ZEW_bit, actZEWbit,*f,debounce,repeat ,ZewZbocze(rise), ZEW_Level);
 return;
}
#endif
#endif

- zawartość pliku klawisze.c

#include "klawisze.h"
#include "klawisze_libr_conf.h"
//Zmienne mapowania klawiszy
volatile uint8_t key_status = 0; //klawisz wcisniety
volatile uint8_t key_acts = 0; //klawisz obsluzony
volatile uint8_t key_rises = 0; //reakcja na zbocza
//Aktualizuje zmienne mapowania klawiszy
//**********************************************************************************
void keyf(uint8_t port, uint8_t pin, uint8_t id,void (*f)(void),uint8_t debounce,uint8_t repeat,uint8_t rise,uint8_t level)
{
 if(!(key_status&(1<<id)) && (!(port&(1<<pin))^(level)))
 {
 key_status |= (1<<id);//przycisk wciśnięty
 Ltab[id]=debounce;
 }
 if(!Ltab[id])
 {
 if((!(port&(1<<pin))^(level)))
 key_acts |= (1<<id);//przycisk wciśnięty
 }
 if(!(!(port&(1<<pin))^(level)))
 {
 waitus(debounce);
 if(!(!(port&(1<<pin))^(level)))
 key_status &= ~(1<<id);//odznacz w tablicy wciśniętych
 }
 if(((key_acts&(1<<id))||(key_status&(1<<id)))&&(!(key_rises&(1<<id))))
 {
 if(!Ltabr[id])
 {
 Ltabr[id]=repeat;
 f();
 key_rises |= (!((1<<id))^(rise));
 }
 }
 if (!(key_status&(1<<id)))
 {
 key_rises &= ~(1<<id);
 key_acts &= ~(1<<id);
 }
 return;
}

 Gdy już pomyślnie przebrniesz przez dodanie pliku klawisze.h do projektu, możesz zacząć używać maksymalnie uproszczonych wywołań funkcji w swoim programie, np.:

kOK(*menu_next,25,25,Rise);

lub 

kUP(*zwiekszSek,25,15,Normal);

Jak widać pierwszym parametrem przekazywanym do funkcji jest funkcja, która zostanie wywołana po wciśnięciu klawisza. Następne 2 parametry to czas debounce oraz czas autopowtarzania (bez znaczenia jeżeli wybierzemy reakcję na zbocze). Ostatnim parametrem jest typ reakcji na pobudzenie: Rise - zbocze, Normal - autopowtarzanie. Możliwe jest także wywołanie funkcji z pierwszym parametrem równym "0" - wtedy w programie głównym wykorzystamy odpowiedni bit ze zmiennej "key_status".

 

Do pobrania:

Użyj opcji uploadu plików, aby przekazać mi kod do sprawdzenia. Postaram się zajrzeć do niego tak szybko jak będzie to możliwe. Paczkę z poprawionym kodem umieszczę w tym samym miejscu.

 

 

Jeżeli wystąpi sytuacja, w której zostanie wyświetlona zawartość folderu z innego działu - należy wyczyścić cache przeglądarki! Następnie przeładować stronę.


Komentarze  

 
# buy cialisbuy_cialis 2016-12-12 15:41
Hello!
Odpowiedz | Odpowiedz z cytatem | Cytować
 

Licznik odwiedzin

Mapa odwiedzin



 

Copyright © ST WebSite 2017

Stronę hostuje FutureHost. []

Strona korzysta z plików cookie. Dane przechowywane na Twoim komputerze służą wyłą…cznie do poprawienia funkcjonalnoś›ci witryny. Jeżeli tego nie akceptujesz - powinieneś› ją… opuś›cić‡.

Akceptujesz ciasteczka z tej witryny?