Definiowane portów/flag w C

Oct 19, 2017 17 Replies

Cześć,



Może nie do końca ta grupa ale wielu z Was pisze w C i może mi podpowie :)



Korzystam z takich makr, które pracują na bitach, np.:



#define setbit(VAR,Place) ( (VAR) |= (uint8_t)((uint8_t)1<<(uint8_t)(Place)) )



w programie mam zdefiniowane np.:



#define PORT_LED GPIOA #define LED_R 0



uint8_t main_flags1, main_flags2, main_flags3; #define FLAGA1 0 #define FLAGA2 0


i później takie wykorzystanie np.:



setbit(PORT_LED, LED_R); setbit(main_flags, FLAGA1); setbit(main_flags2, FLAGA2);



Przy portach to jeszcze nie jest problemu ale przy flagach trzeba ręcznie panować nad tym w której zmiennej leży jaka flaga. Już kilka razy szukałem przez to błędów.



Jak zrobić, żeby odwołanie do flagi było jednoznaczne, chodziło by mi o coś takiego (co nie działa przez ten przecinek):



#define F_LED_R PORT_LED,LED_R



setbit(F_LED_R);



Wtedy w programie nie muszę się już zastanawiać gdzie leży jaki bit.



Zawsze tak pisałem w asm, a teraz mi tego brakuje :)


Pozdrawiam,


#define led_set() set_bit(PORT_LED, LED_R)

Ja tych makr mam więcej, to był tylko przykład z 'setbit'. Chodzi o to, żeby w dowolnym makrze można było podstawić port lub flagę nie generując przy tym osobnego makra dla każdego przypadku, np.:

setbit(F_LED_R); clrbit(F_LED_R); chgbit(F_LED_R); if (valbit(F_LED_R))

a czemu upierasz się przy makrach? Nie możesz dać inline function?

Waldek

Nie musisz jesli użyjesz C++. Nie mam stosownego przykładu pod reką w tej chwili ale kilka lat temu mając ochote ukręcić leb idiotom od definicji rejestrow SAM7 narzeźbilem coś takiego i "sprzedałem" kod. Napisanie tego na nowo jest w zasadzie osiągalne.

Oczywiście od razu informacja dla wszystkich co podskoczyli na hasło C++

- ten mechanizm nie genaruje ani bajta więcej w kodzie. To metaprogramowanie na szablonach, operatorach itd, na końcu wychodzi to samo tylko pewne i bez głupich pomyłek i wygląda prawie identycznie.

Hmm, mogę dać inline ale wydaje mi się, że jestem w tym samym punkcie co z makrami.

static inline void setbit (u8 port, u8 pin) { port |= 1<<pin; }

No i co dalej? Chciałbym ją tak samo wywołać, np.:

setbit(F_LED)

Ja mam C na sztywno w tym projekcie i nie dam rady przeskoczyć na C++.

Z powodu jakiego? Technicznego czy białkowego?

sword snipped-for-privacy@poczta.onet.pl> napisał(a):

Musisz stworzyć coś, co oprócz bitu będzie nisło też informację o porcie, np.

#include <stdio.h>

#define PINA1 0x01 #define PINA2 0x02 #define PINB2 0x02 #define PINB3 0x03

#define F_PINA1 (0x0000 | PINA1) #define F_PINA2 (0x0000 | PINA2) #define F_PINB2 (0x0100 | PINB2) #define F_PINB3 (0x0100 | PINB3)

int porta = 0, portb = 0;

void setpin(unsigned int fpin);

int main() { setpin(F_PINA1); setpin(F_PINA2); setpin(F_PINB2); setpin(F_PINB3); printf("%x %x\n", porta, portb); return 0; }

void setpin(unsigned int fpin){ int port = fpin >> 8; int pin = 0x00ff & fpin; switch(port) { case 0x00: porta |= 1 << pin; break; case 0x01: portb |= 1 << pin; break; } }

Czyli białkowy. Nadzieja w tym że problemy białkowe czasami rozwiązują się szybciej niż komercyjne kompilatory dostają wsparcie C++, ale to rodzaj czarnego humoru.

To nie pomogę bo każde rozwiązanie w C będzie gówniane.

W dniu 19.10.2017 o 13:01, sword pisze:

Problem moim zdaniem nie leży ani w wybranym w języku programowania, ani w sposobie implementacji tylko "wyżej" - zagadnienie nazywa się semantyka.

Rozwiązanie banalne - stosuj nazwy zmiennych, funkcji, makr i definicji, które będą JEDNOZNACZNE i SAMOKOMENTUJĄCE SIĘ. Dobrym przykładem mogą być biblioteki dostarczane przez ST do ich procków, bo tam przyjęto regułę, że jeśli rejestr nazywa się REG_BLA_BLA to bity w nim nazywają się REG_BLA_BLA_ENABLE_COŚTAM, REG_BLA_BLA_DISABLE_INNE_COŚTAM itd.

Dnia Thu, 19 Oct 2017 21:38:58 +0200, Grzegorz Niemirowski napisał(a):

[...]

A na bezczelnego ?

#define F_LED GPIO,7

... setbit(F_LED) ...

formatting link

J.

Do takiego zadzialania potrzeba "podwojnego makra":

#define _test_set_bit(port,pin) do{ (port)->PDOR |=(1<<(pin)); }while(0) #define test_set_bit(x) _test_set_bit(x) #define LEG_G_7 GPIOB,7

i wtedy test_set_bit(LEG_G_7); preprocesor rozwinie poprawnie: do{ (((GPIO_Type *)(0x400FF040u)))->PDOR |=(1<<(7)); }while(0);

Przy pojedynczym makro (jak pierwsze) arm-none-eabi-gcc zglasza blad ze makro ma miec 2 parametry a przekazany jest tylko 1.

$ arm-none-eabi-gcc -E -mcpu=cortex-m0plus makro.c -o makro2.lst makro.c:14:23: error: macro "test_set_bit" requires 2 arguments, but only 1 given test_set_bit(LEG_G_7);

Marcin

W dniu 2017-10-19 o 13:01, sword pisze:

Ja to robię tak wpierw definicje makr #define SET_(p, m) (p |= (1 << (m))) #define CLR_(p, m) (p &= ~(1 << (m))) #define TEST_(p,m) (p & (1 << (m))) #define TOGGLE_(p, m) (p ^= (1 << (m)))

#define SET(x) SET_(x) #define CLR(x) CLR_(x) #define TEST(x) TEST_(x) #define TOGGLE(x) TOGGLE_(x)

potem właściwa konfiguracja

#define ZIELONA PORTB,1

i potem w programie

SET(ZIELONA);

Fajny przykład ale do pracy z bitami to za dużo kodu.

Niekoniecznie.

Nie wiem na jaką platformę piszesz, ale na AVR port nie ma typu u8 (uint8).

Spróbuj tak:

[gof@pi /tmp]$ cat test.c #include <inttypes.h>

#include <avr/io.h>

// bez nawiasów, żeby nie rozwinęło się tylko do jednego argumentu #define MAKE(port, bit) &port, _BV(bit)

// podejście z MAKE #define LED1 MAKE(PORTB, 3) #define BUZZER1 MAKE(PORTC, 0)

// podejście bez MAKE - bez nawiasów! #define LED2 &PORTB, _BV(3) #define BUZZER2 &PORTC, _BV(0)

static inline void setbit(volatile uint8_t *port, uint8_t mask) { *port |= mask; }

int main(void) { setbit(LED1); setbit(BUZZER1); setbit(LED2); setbit(BUZZER2);

return 0; } [gof@pi /tmp]$ avr-gcc -mmcu=atmega8 -Wall -Wextra test.c [gof@pi /tmp]$

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required