RTV forum PL | NewsGroups PL

Jak poprawnie wykorzystać wskaźniki do portów w AT89C51 przy debouncingu przycisków?

sdcc i at89c51 - dostęp do pinu "na około"

NOWY TEMAT

elektroda NewsGroups Forum Index - Elektronika Polska - Jak poprawnie wykorzystać wskaźniki do portów w AT89C51 przy debouncingu przycisków?

Goto page 1, 2  Next

Atlantis
Guest

Tue Mar 14, 2017 7:07 pm   



Ciąg dalszy moich eksperymentów z archaicznymi mikrokontrolerami. ;)

Już kiedyś pytałem, czy da się w jakiś sposób przesłać wygodną
konstrukcję wskazującą bezpośrednio na pin (np. "P0_0") za pomocą
wskaźnika w C. Otrzymałem odpowiedź, że się nie da i muszę to robić w
sposób standardowy.

Natknąłem się jednak na pewne problemy... Próbuję przeportować pewną
bibliotekę do obsługi przycisków (debouncing + wykrywanie długiego
wciśnięcia). Kod podpatrzony w jednej z książek pana Kardasia, z paroma
moimi modyfikacjami.

Generalnie sprowadza się do tego, że mam strukturę opisującą przycisk:

typedef struct key {
unsigned char *port;
unsigned char pin:3;
unsigned char state:4;
unsigned int timer;
void (*push_proc)(void);
void (*long_proc)(void);
} key_t;

Struktura jest inicjowana za pomocą funkcji key_init(), która przypisuje
argumenty do struktury przekazanej przez wskaźnik, czyli wygląda to w
ten sposób:

key_init(&button2, &P0, 0, funkcja, funkcja);

Kolejne argumenty oznaczają: adres struktury, adres portu, numer pinu w
porcie, wskaźnik na funkcję wykonywaną po krótkim wciśnięciu przycisku i
wskaźnik na funkcję wykonywaną po przytrzymaniu przycisku.

Potem stan przycisku jest cały czas sprawdzany wewnątrz funkcji
key_update(), która przyjmuje za argument adres struktury.

Tyle tytułem wprowadzenia.

Sęk w tym, że kod nie chce działać. Drogą eliminacji doszedłem do tego, że:
1) Same wejścia cyfrowe działają - odwołanie się do nich bezpośrednio
daje pozytywny efekt.
2) Działa także konstrukcja key_press = !(P0 & (1<<NUMER_PINU))
3) Program wchodzi do funkcji key_update.

NIE DZIAŁA natomiast następująca konstrukcja:

key_press = !(*(key->port) & (1<<(key->pin)));

Strukturę inicjuję podając dane właściwego portu i pinu, a pomimo tego
wciskanie przycisku nie jest widoczne.

I teraz pytanie: co jest nie tak. Czyżbym w sdcc i/lub at89c51 nie mógł
przesyłać w ten sposób informacji o porcie? A może po prostu coś
przeoczyłem i w powyższej linijce tkwił jakiś banalny błąd, który umyka
mojej uwadze, gdy na nią patrzę?

J.F.
Guest

Tue Mar 14, 2017 7:48 pm   



Użytkownik "Atlantis" napisał w wiadomości grup
dyskusyjnych:oa9bgq$7fd$1@news.icm.edu.pl...
Quote:
Natknąłem się jednak na pewne problemy... Próbuję przeportować pewną
bibliotekę do obsługi przycisków (debouncing + wykrywanie długiego
wciśnięcia). Kod podpatrzony w jednej z książek pana Kardasia, z
paroma
moimi modyfikacjami.

Atlantisie - na moj gust, jak bedziesz takie ambitne struktury robil
.... to ci pamieci zabraknie :-)

Duza ta klawiatura ? Regularnie zrobiona ?
Moze regularne metody lepsze.

Quote:
Generalnie sprowadza się do tego, że mam strukturę opisującą
przycisk:
typedef struct key {

unsigned char *port;
unsigned char pin:3;
unsigned char state:4;

* ciekawe czy ten kompilator sobie radzi z tym :3.
Skoro deklaracje przyjmuje, to niby powinien.

unsigned int timer;
void (*push_proc)(void);
void (*long_proc)(void);
} key_t;

Quote:
Struktura jest inicjowana za pomocą funkcji key_init(), która
przypisuje
argumenty do struktury przekazanej przez wskaźnik, czyli wygląda to w
ten sposób:
key_init(&button2, &P0, 0, funkcja, funkcja);

Kolejne argumenty oznaczają: adres struktury, adres portu, numer pinu
w
porcie, wskaźnik na funkcję wykonywaną po krótkim wciśnięciu
przycisku i
wskaźnik na funkcję wykonywaną po przytrzymaniu przycisku.
Potem stan przycisku jest cały czas sprawdzany wewnątrz funkcji
key_update(), która przyjmuje za argument adres struktury.

Ciekawe, na ile to optymalne. Przy kilku przyciskach ... moze ..

Quote:
NIE DZIAŁA natomiast następująca konstrukcja:
key_press = !(*(key->port) & (1<<(key->pin)));

Zlikwiduj testowo te :3, :4. Albo sobie wydrukuj ... albo wrzuc jak
kompilator to na assembler zamienil.

Quote:
Strukturę inicjuję podając dane właściwego portu i pinu, a pomimo
tego
wciskanie przycisku nie jest widoczne.

I teraz pytanie: co jest nie tak. Czyżbym w sdcc i/lub at89c51 nie
mógł
przesyłać w ten sposób informacji o porcie?

89c51 czy 89c52 ?
Bo tu chyba jest pies pogrzebany
http://www.8052.com/tutaddr.phtml

Indirect addressing always refers to Internal RAM; it never refers to
an SFR.

MOV R0,#99h ;Load the address of the serial port
MOV @R0,#01h ;Send 01 to the serial port -- WRONG!!

This is not valid. Since indirect addressing always refers to Internal
RAM these two instructions would write the value 01h to Internal RAM
address 99h on an 8052. On an 8051 these two instructions would
produce an undefined result since the 8051 only has 128 bytes of
Internal RAM.

A aby zaadresowac taka nieokreslona komorke pamieci, kompilator musi
skorzystac z adresowania posredniego.

Swoja droga on tak to napisal, jakby pod 8051 bylo tak samo ... prawde
mowiac nie pamietam, wydaje mi sie, ze mozna bylo adresowac porty @Rn.

Quote:
2) Działa także konstrukcja key_press = !(P0 & (1<<NUMER_PINU))

a ta kompilator moze skompilowac wstawiajac adres na stale.

J.

Janusz
Guest

Tue Mar 14, 2017 7:54 pm   



W dniu 2017-03-14 o 19:07, Atlantis pisze:
Quote:
Ciąg dalszy moich eksperymentów z archaicznymi mikrokontrolerami. ;)

Już kiedyś pytałem, czy da się w jakiś sposób przesłać wygodną
konstrukcję wskazującą bezpośrednio na pin (np. "P0_0") za pomocą
wskaźnika w C. Otrzymałem odpowiedź, że się nie da i muszę to robić w
sposób standardowy.

Natknąłem się jednak na pewne problemy... Próbuję przeportować pewną
bibliotekę do obsługi przycisków (debouncing + wykrywanie długiego
wciśnięcia). Kod podpatrzony w jednej z książek pana Kardasia, z paroma
moimi modyfikacjami.

Generalnie sprowadza się do tego, że mam strukturę opisującą przycisk:

typedef struct key {
unsigned char *port;
unsigned char pin:3;
unsigned char state:4;
unsigned int timer;
void (*push_proc)(void);
void (*long_proc)(void);
} key_t;

Struktura jest inicjowana za pomocą funkcji key_init(), która przypisuje
argumenty do struktury przekazanej przez wskaźnik, czyli wygląda to w
ten sposób:

key_init(&button2, &P0, 0, funkcja, funkcja);

Kolejne argumenty oznaczają: adres struktury, adres portu, numer pinu w
porcie, wskaźnik na funkcję wykonywaną po krótkim wciśnięciu przycisku i
wskaźnik na funkcję wykonywaną po przytrzymaniu przycisku.

Potem stan przycisku jest cały czas sprawdzany wewnątrz funkcji
key_update(), która przyjmuje za argument adres struktury.

Tyle tytułem wprowadzenia.

Sęk w tym, że kod nie chce działać. Drogą eliminacji doszedłem do tego, że:
1) Same wejścia cyfrowe działają - odwołanie się do nich bezpośrednio
daje pozytywny efekt.
2) Działa także konstrukcja key_press = !(P0 & (1<<NUMER_PINU))
3) Program wchodzi do funkcji key_update.

NIE DZIAŁA natomiast następująca konstrukcja:

key_press = !(*(key->port) & (1<<(key->pin)));

Strukturę inicjuję podając dane właściwego portu i pinu, a pomimo tego
wciskanie przycisku nie jest widoczne.

I teraz pytanie: co jest nie tak. Czyżbym w sdcc i/lub at89c51 nie mógł
przesyłać w ten sposób informacji o porcie? A może po prostu coś
przeoczyłem i w powyższej linijce tkwił jakiś banalny błąd, który umyka
mojej uwadze, gdy na nią patrzę?

Zobacz w asemblerze jak to kompilator przetłumaczył, może się okazać że

poszedł w maliny.

--
Pozdr
Janusz

Atlantis
Guest

Tue Mar 14, 2017 9:03 pm   



W dniu 2017-03-14 o 19:48, J.F. pisze:

Quote:
Atlantisie - na moj gust, jak bedziesz takie ambitne struktury robil ...
to ci pamieci zabraknie Smile

Pilnuję zawartości pliku .mem i na razie mieszczę się w wyznaczonej
normie. Przycisków jest kilka i tylko niektóre z nich wymagają podwójnej
funkcjonalności przyciśnięcie/przytrzymanie. Pozostałym zrobię prostszy
debouncing. ;)


Quote:
* ciekawe czy ten kompilator sobie radzi z tym :3.
Skoro deklaracje przyjmuje, to niby powinien.

Wygląda na to, że sobie radzi. Po dodaniu pól bitowych do definicji typu
struktury zużycie pamięci zmniejszyło się o kilka bajtów. I z całą
pewnością pola bitowe nie są przyczyną, bo na początku ich nie było, a
problem występował. ;)



Quote:
89c51 czy 89c52 ?
Bo tu chyba jest pies pogrzebany
http://www.8052.com/tutaddr.phtml

89c51


Quote:
Swoja droga on tak to napisal, jakby pod 8051 bylo tak samo ... prawde
mowiac nie pamietam, wydaje mi sie, ze mozna bylo adresowac porty @Rn.

Innymi słowy: da się jakoś dostać do tego portu z poziomu C? Wink

Zbych
Guest

Tue Mar 14, 2017 9:09 pm   



W dniu 14.03.2017 o 19:07, Atlantis pisze:

Quote:
NIE DZIAŁA natomiast następująca konstrukcja:

key_press = !(*(key->port) & (1<<(key->pin)));

Strukturę inicjuję podając dane właściwego portu i pinu, a pomimo tego
wciskanie przycisku nie jest widoczne.

Używasz 51 czy 52? Bo w 52 odwołanie pośrednie do adresu 80h (port P0),
spowoduje odwołanie do pamięci idata pod adres 80h.

Atlantis
Guest

Tue Mar 14, 2017 9:34 pm   



W dniu 2017-03-14 o 19:54, Janusz pisze:

Quote:
Zobacz w asemblerze jak to kompilator przetłumaczył, może się okazać że
poszedł w maliny.

Niestety, nie znam asemblera, więc kod niewiele mi mówi... :(

; src/SuperDebounce.c:18: key_press = !(*(key->port) & (1<<(key->pin)));
mov _key_update_key_1_13,dpl
mov (_key_update_key_1_13 + 1),dph
mov (_key_update_key_1_13 + 2),b
lcall __gptrget
mov r2,a
inc dptr
lcall __gptrget
mov r3,a
inc dptr
lcall __gptrget
mov r4,a
mov dpl,r2
mov dph,r3
mov b,r4
lcall __gptrget
mov r2,a
mov a,#0x03
add a,_key_update_key_1_13
mov r1,a
clr a
addc a,(_key_update_key_1_13 + 1)
mov r3,a
mov r4,(_key_update_key_1_13 + 2)
mov dpl,r1
mov dph,r3
mov b,r4
lcall __gptrget
anl a,#0x07
mov r1,a
mov b,r1
inc b
mov a,#0x01
sjmp 00176$
00174$:
add a,acc
00176$:
djnz b,00174$
mov r1,a
anl ar2,a
mov a,r2
cjne a,#0x01,00177$
00177$:
clr a
rlc a

Atlantis
Guest

Tue Mar 14, 2017 10:02 pm   



W dniu 2017-03-14 o 21:21, antispam@math.uni.wroc.pl pisze:

Quote:
Twoj problem jest prawdopodobnie zwiazany z at89c51, ale
bez 'volatile' mozesz miec problem na dowolnym procku.

Dodałem "volatile", ale nie ma żadnej zmiany. Więc jednak nie o to
chodziło...

Powinienem przyjąć, że w przypadku tych MCU nie da się odwołać do portu
przez wskaźnik? Mogę to obejść w inny sposób - najprościej będzie chyba
przekazywać normalną liczbę i w zależności od jej wartości, odwoływać
się do konkretnego portu, określonego twardo w kodzie. Sądziłem tylko,
że może będzie się to dało zrobić bardziej elegancko. Wink

Guest

Tue Mar 14, 2017 10:21 pm   



Atlantis <marekw1986NOSPAM@wp.pl> wrote:
Quote:
Ci?g dalszy moich eksperyment?w z archaicznymi mikrokontrolerami. ;)

Ju? kiedy? pyta?em, czy da si? w jaki? spos?b przes?a? wygodn?
konstrukcj? wskazuj?c? bezpo?rednio na pin (np. "P0_0") za pomoc?
wska?nika w C. Otrzyma?em odpowied?, ?e si? nie da i musz? to robi? w
spos?b standardowy.

Natkn??em si? jednak na pewne problemy... Pr?buj? przeportowa? pewn?
bibliotek? do obs?ugi przycisk?w (debouncing + wykrywanie d?ugiego
wci?ni?cia). Kod podpatrzony w jednej z ksi??ek pana Kardasia, z paroma
moimi modyfikacjami.

Generalnie sprowadza si? do tego, ?e mam struktur? opisuj?c? przycisk:

typedef struct key {
unsigned char *port;
unsigned char pin:3;
unsigned char state:4;
unsigned int timer;
void (*push_proc)(void);
void (*long_proc)(void);
} key_t;
snip
NIE DZIA?A natomiast nast?puj?ca konstrukcja:

key_press = !(*(key->port) & (1<<(key->pin)));

Przy dostepie do portow powinno byc 'volatile', np:

typedef struct key {
volatile unsigned char *port;
....

Twoj problem jest prawdopodobnie zwiazany z at89c51, ale
bez 'volatile' mozesz miec problem na dowolnym procku.

--
Waldek Hebisch

Atlantis
Guest

Tue Mar 14, 2017 10:29 pm   



Ok, zrobiłem banalny "workaround" rezygnując z przekazywania adresu
portu przez wskaźnik. Zamiast tego przekazuje jego numer i na jego
podstawie, za pomocą sekwencji if-ów wykonuję operację na właściwym
porcie. Wink Dodatkowo za pomocą pól bitowych udało mi się zmieścić
identyfikator portu razem z identyfikatorem pinu i stanem maszyny stanów
w jednej ośmiobitowej zmiennej. :)

To może zapytam jeszcze o jedną rzecz, z którą obecnie walczę i chwilowo
wygrać nie mogę. Projekt wykorzystuje RTC na DS1307. Sam układ działa
(przetestowałem go za pomocą Arduino). Nie mogę jednak za nic
skomunikować go z at89c51.

Korzystam z tej biblioteki:
http://saeedsolutions.blogspot.com/2012/11/interfacing-of-8051-with-ds1307-rtc.html

Czy winę może ponosić fakt, iż mój projekt dość intensywnie korzysta z
przerwań? Powinienem je wyłączać na czas każdej transmisji I2C, czy
raczej nie tutaj szukać przyczyny?

J.F.
Guest

Wed Mar 15, 2017 1:42 am   



Dnia Tue, 14 Mar 2017 22:29:02 +0100, Atlantis napisał(a):
Quote:
To może zapytam jeszcze o jedną rzecz, z którą obecnie walczę i chwilowo
wygrać nie mogę. Projekt wykorzystuje RTC na DS1307. Sam układ działa
(przetestowałem go za pomocą Arduino). Nie mogę jednak za nic
skomunikować go z at89c51.

Korzystam z tej biblioteki:
http://saeedsolutions.blogspot.com/2012/11/interfacing-of-8051-with-ds1307-rtc.html

Czy winę może ponosić fakt, iż mój projekt dość intensywnie korzysta z
przerwań? Powinienem je wyłączać na czas każdej transmisji I2C, czy
raczej nie tutaj szukać przyczyny?

Raczej nie tutaj.
Ogolnie - predkosc w I2C moze byc dosc dowolna.
Za szybko nie wolno ... ale 100kHz chyba nie przekraczasz,
za wolno ... tylko niektore uklady maja jakies timeouty,
ale az tak bardzo przerwania Ci chyba nie spowalniaja.

Za to oczywiscie w przerwaniu mozna duzo sp* - wiec moze wylacz i
zobacz czy lepiej dziala.

J.

J.F.
Guest

Wed Mar 15, 2017 1:46 am   



Dnia Tue, 14 Mar 2017 21:03:03 +0100, Atlantis napisał(a):
Quote:
W dniu 2017-03-14 o 19:48, J.F. pisze:
Atlantisie - na moj gust, jak bedziesz takie ambitne struktury robil ...
to ci pamieci zabraknie Smile
Pilnuję zawartości pliku .mem i na razie mieszczę się w wyznaczonej
normie.

A tam masz program czy RAM ?
Ja sie o (I)RAM martwie - 128 bajtow to tyle co nic :-)

Quote:
89c51 czy 89c52 ?
Bo tu chyba jest pies pogrzebany
http://www.8052.com/tutaddr.phtml

89c51

Swoja droga on tak to napisal, jakby pod 8051 bylo tak samo ... prawde
mowiac nie pamietam, wydaje mi sie, ze mozna bylo adresowac porty @Rn.

Innymi słowy: da się jakoś dostać do tego portu z poziomu C? Wink

Dajac staly adres.

J.

Atlantis
Guest

Wed Mar 15, 2017 7:51 am   



On 15.03.2017 01:42, J.F. wrote:

Quote:
Za to oczywiscie w przerwaniu mozna duzo sp* - wiec moze wylacz i
zobacz czy lepiej dziala.

Właśnie uświadomiłem sobie, że przyczyna nie może tutaj leżeć.
Jeszcze przed ustawieniem flagi globalnego zezwolenia na przerwania
(EA=1) próbuję skonfigurować DS1307 tak, aby na pinie SQW pojawił się
sygnał 1Hz.

Write_Byte_To_DS1307_RTC(0x07, 0x10);

Nie przynosi to jednak żadnego efektu.

Atlantis
Guest

Wed Mar 15, 2017 8:57 am   



On 15.03.2017 01:46, J.F. wrote:

Quote:
A tam masz program czy RAM ?

Jedno i drugie.


Quote:
Ja sie o (I)RAM martwie - 128 bajtow to tyle co nic Smile

To mniej-więcej tyle, co we współczesnych ATTiny. :)

Zawartość pliku poniżej. Nie wygląda to źle zważywszy na fakt, że
program jest prawie gotowy. Pewnie dałoby się odzyskać jeszcze parę
bajtów. :)

Jedyne co mnie zastanawia, to te "PAGED EXT. RAM" i "EXTERNAL RAM".
Powinienem to jakoś wyłączyć, skoro nie korzystam z zewnętrznej pamięci?
Jeśli tak, to gdzie?


Internal RAM layout:
0 1 2 3 4 5 6 7 8 9 A B C D E F
0x00:|0|0|0|0|0|0|0|0|a|a|b|b|b|b|b|b|
0x10:|b|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|
0x20:|c|c|c|c|c|c|c|d|d|d|d|e|e|e|e|e|
0x30:|e|e|e|e|e|e|e|e|e|e|e|e|e|e|e|e|
0x40:|e|e|Q|Q|Q|Q|Q|Q|S|S|S|S|S|S|S|S|
0x50:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x60:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x70:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|
0x80:| | | | | | | | | | | | | | | | |
0x90:| | | | | | | | | | | | | | | | |
0xa0:| | | | | | | | | | | | | | | | |
0xb0:| | | | | | | | | | | | | | | | |
0xc0:| | | | | | | | | | | | | | | | |
0xd0:| | | | | | | | | | | | | | | | |
0xe0:| | | | | | | | | | | | | | | | |
0xf0:| | | | | | | | | | | | | | | | |
0-3:Reg Banks, T:Bit regs, a-z:Data, B:Bits, Q:Overlay, I:iData,
S:Stack, A:Absolute

Stack starts at: 0x48 (sp set to 0x47) with 56 bytes available.

Other memory:
Name Start End Size Max
---------------- -------- -------- -------- --------
PAGED EXT. RAM 0 256
EXTERNAL RAM 0 1024
ROM/EPROM/FLASH 0x0000 0x0b4a 2891 4096

Piotr Gałka
Guest

Wed Mar 15, 2017 9:57 am   



W dniu 2017-03-15 o 01:46, J.F. pisze:

Quote:
A tam masz program czy RAM ?
Ja sie o (I)RAM martwie - 128 bajtow to tyle co nic :-)

Obecnie nic, ale kiedyś to było bardzo dużo Smile

W PiccoGALu w tych 128 bajtach mieściły nam się:
- stos procesora,
- stos danych FORTH,
- bufor danych programowania/odczytywania EEPROMów / GALi
- cały program w FORTH konkretnej (odczyt, zapis, weryfikacja...)
obsługi danej kostki.

Może mieściły to nie dokładne określenie, bo bufor danych zachodził
zazwyczaj na początek programu, ale był używany już po wykonaniu tego
początku programu i dojściu do głównej pętli.
P.G.

J.F.
Guest

Wed Mar 15, 2017 10:21 am   



Użytkownik "Piotr Gałka" napisał w wiadomości grup
dyskusyjnych:oaavl5$ilc$1@news.chmurka.net...
W dniu 2017-03-15 o 01:46, J.F. pisze:
Quote:
A tam masz program czy RAM ?
Ja sie o (I)RAM martwie - 128 bajtow to tyle co nic :-)

Obecnie nic, ale kiedyś to było bardzo dużo Smile
W PiccoGALu w tych 128 bajtach mieściły nam się:
- stos procesora,
- stos danych FORTH,

Ale w Forth nie miales takich ambitnych struktur danych :-)

Quote:
- bufor danych programowania/odczytywania EEPROMów / GALi

Dobrze ze z RS czy Centronicsa, bo juz z dyskietka mialbys problem :-)

J.

Goto page 1, 2  Next

elektroda NewsGroups Forum Index - Elektronika Polska - Jak poprawnie wykorzystać wskaźniki do portów w AT89C51 przy debouncingu przycisków?

NOWY TEMAT

Regulamin - Zasady uzytkowania Polityka prywatnosci Kontakt RTV map News map