Skocz do zawartości

Jawne rzutowanie w AVR GCC


Krawi92

Pomocna odpowiedź

Witam, mam taki problem. Stworzyłem tablice na potrzebę wyswietlacza multipleksowanego LED, żeby wygodnie wyświetlać cyfry. Tablica jest typu uint8_t. Wszystko było ok dopóki do tablicy nie dodałem kropki DP. Wtedy kompilator wywala warnign, że używam nie odpowiedniego typu. Gdy zmienie typ na uint16_t jest ok. Przeczytałem, że zamiast takiej operacji, żeby nie tracić dodatkowo pamięci zastosować jawne rzutowanie. Dostałem odpowiedz "Wszystkie stałe zdefiniowane za pomocą #define, albo stałe dosłowne czyli właśnie (1<<7) kompilator rzutuje sobie domyślnie ale niejawnie do typu int (2 bajty)". I tu problem mam ze zrozumieniem tego. Wrzucę kod 2 plików 

// d_led.c//
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "d_led.h"

volatile uint8_t cy1;
volatile uint8_t cy2;
volatile uint8_t cy3;
volatile uint8_t cy4;

const uint8_t cyfry[] PROGMEM = {
		~(SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_F), // 0
		~(SEG_B|SEG_C), // 1
		~(SEG_A|SEG_B|SEG_D|SEG_E|SEG_G), // 2
		~(SEG_A|SEG_B|SEG_C|SEG_D|SEG_G), //3
		~(SEG_B|SEG_C|SEG_F|SEG_G), // 4
		~(SEG_A|SEG_C|SEG_D|SEG_F|SEG_G), // 5
		~(SEG_A|SEG_C|SEG_D|SEG_E|SEG_F|SEG_G), // 6
		~(SEG_A|SEG_B|SEG_C|SEG_F), // 7
		~(SEG_A|SEG_B|SEG_C|SEG_D|SEG_E|SEG_F|SEG_G), // 8
		~(SEG_A|SEG_B|SEG_C|SEG_D|SEG_F|SEG_G), //9
		~(SEG_D|SEG_E|SEG_F), // litera L
		~(SEG_A|SEG_B|SEG_C|SEG_G|SEG_E|SEG_F), // litera A
		~(SEG_DP), // kropka
};

void d_led_init(void) { // inicjacja wyswietlacza i timera

	LED_DATA_DIR = 0xFF; // wszystkie piny portu D jako wyjscia segmentow
	LED_DATA = 0xFF; // wygaszenie segmentów
	ANODY_DIR |= CA1|CA2|CA3|CA4; // Anody jako wyjscia
	ANODY_PORT |= CA1|CA2|CA3|CA4; // wylaczenie anod - stan wysoki

	TCCR0A |= (1<<WGM01); // tryb ctc timer8bit
	TCCR0B |= (1<<CS00)|(1<<CS02); // prescaler 1024
	OCR0A = 38;
	TIMSK0 |= (1<<OCIE0A); // zezwolenie na przerwanie compare match
}
ISR(TIMER0_COMPA_vect) { // procedura obslugi przerwania
static uint8_t licznik = 1;

	ANODY_PORT = ( ANODY_PORT & 0xF0) | (~licznik & 0x0F); // zamaskowanie ANOD PC0-PC3
	if (licznik == 1 ) LED_DATA = pgm_read_byte(&cyfry[cy1]);
	else if (licznik == 2) LED_DATA = pgm_read_byte(&cyfry[cy2]);
	else if (licznik == 4) LED_DATA = pgm_read_byte(&cyfry[cy3]);
	else if (licznik == 8) LED_DATA = pgm_read_byte(&cyfry[cy4]);

	licznik <<= 1;
	if (licznik>8) licznik = 1;

}
/*
 * d_led.h
 *
 *  Created on: 10 wrz 2021
 *      Author: User
 */

#ifndef D_LED_H_
#define D_LED_H_

#define LED_DATA_DIR DDRD // kierunek wyjsciowy segmentow
#define LED_DATA PORTD // stan segmentow
#define ANODY_PORT PORTC // stan anod
#define ANODY_DIR DDRC // kierunek wyjsciowy anod

#define CA1 (1<<PC3) // anoda 1
#define CA2 (1<<PC2) // anoda 2
#define CA3 (1<<PC1) // anoda 3
#define CA4 (1<<PC0) // anoda 4

// ========Makra segmentow ============ //
#define SEG_A (1<<0)
#define SEG_B (1<<1)
#define SEG_C (1<<2)
#define SEG_D (1<<3)
#define SEG_E (1<<4)
#define SEG_F (1<<5)
#define SEG_G (1<<6)
#define SEG_DP (1<<7)


extern volatile uint8_t cy1; // zmienne dostepne w innych plikach projektu
extern volatile uint8_t cy2;
extern volatile uint8_t cy3;
extern volatile uint8_t cy4;

void d_led_init(void); // deklaracja funkcji

#endif /* D_LED_H_ */

Nie mogę zrozumieć, czemu gdy korzystam z makr od (1<<0) do (1<<6) to nie mam warningów, a gdy użyje w tablicy (1<<7) to już jest. Nie bardzo też wiem, jak w tym kodzie zastosować to jawne rzutowanie. 

Link do komentarza
Share on other sites

Oo, problem rozwiązało. Próbowałem w różnych miejscach robić to rzutowanie, a nie wpadłem, że trzeba zrobić to przed.. Tylko właśnie teraz chodzi o zrozumienie tego, czemu akurat przy operacji bitowej 1<<7 wywala błąd. 😕

Link do komentarza
Share on other sites

3 minuty temu, Krawi92 napisał:

Tylko właśnie teraz chodzi o zrozumienie tego, czemu akurat przy operacji bitowej 1<<7 wywala błąd. 😕

Nie pomoge bo nie wiem...😢 ale...rzutowanie to bardzo wazna kwestia i radze Ci sie za nia wziasc, bo szybko zderzysz sie z problemem poprawnego rownania ktore daje "zly" wynik...w skrocie wynik zostaje niejawnie rzutowany do typu int, chyba ze w rownaniu wystepuje wiekszy typ...poprostu rzutuje do najwiekszego typu...np. takie cos...

int a = 50000
int b = 50000
uint32_t x
  
x = a + b

bedzie zawierac blad...bo obie zmienne sa typu int i na taki typ zostanie wykonane rzutowanie, a liczba 100tys. juz sie nie miesci w 16bitach i bedziesz mial blad...poprostu otrzymasz tylko 16 bitow zamiast pelnej liczby...to samo jesli chodzi o floaty czy dlugie rownania ktore sa "podzielone" nawiasami...tam tez czesto trzeba zwracac uwage na rzutowanie zeby wszystko bylo ok...

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

20 godzin temu, Krawi92 napisał:

Oo, problem rozwiązało. Próbowałem w różnych miejscach robić to rzutowanie, a nie wpadłem, że trzeba zrobić to przed.. Tylko właśnie teraz chodzi o zrozumienie tego, czemu akurat przy operacji bitowej 1<<7 wywala błąd. 😕

Kompilator uznaje twój #define jako liczbę ze znakiem, a ~(1 << 7) w "trybie znakowym" to -129, czyli wypadasz poza zakres liczb 8-bitowych, stąd kompilator ma problemy z konwersją, bo musi wykonać overflow przez zakres by tę liczbę skonwertować do 8-bitowej, czego zazwyczaj się unika, bo jak się człowiek zapomni to może tworzyć dziwne artefakty po zmianie platformy na np. 64-bitową.

Edytowano przez H1M4W4R1
Link do komentarza
Share on other sites

58 minut temu, H1M4W4R1 napisał:

 a ~(1 << 7) w "trybie znakowym" to -129

No jak? Mi wychodzi 127...czyli przesuniecie..

0b10000000

a po negacji...

0b01111111

Czyli 127...🤔 (odrazu mowie ze sie nie wymadrzam tylko probuje zrozumiec, bo byc moze czegos nie kumam...)

Edytowano przez farmaceuta
Link do komentarza
Share on other sites

image.thumb.png.039fc75f12c2b235fac4799c2add9d97.png

Nie ważne co wychodzi na kartce, ważne co liczy kompilator 😛 Przyzwyczaj się, bo to często spotykane błędy są.

A tutaj skąd:

(1 << 7) =  0b010000000 // (128)
~(1 << 7) = 0b101111111 // (-129)

Matematyka w programowaniu to trudny temat... Mnie nawet kiedyś się zdarzyło, że kompilator twierdził, że 1 > 12.

Edytowano przez H1M4W4R1
  • Lubię! 1
Link do komentarza
Share on other sites

nie moge gdzies zalapac...bitem znaku jest najstarszy bit tak? A skoro wyniki sa nie jawnie rzutowane do int to we wszystkich makrach powinien byc blad...🤔(?) bez znaczenia ile bitow przesunal...

edit...faktycznie to jeszcze troszke inaczej idzie i tylko w tym makrze bedzie blad...trzeba sie wczytac w ten temat, bo juz mi sie to chyba o oczy obilo, ale guzik pamietam...

Edytowano przez farmaceuta
Link do komentarza
Share on other sites

2 godziny temu, farmaceuta napisał:

nie moge gdzies zalapac...bitem znaku jest najstarszy bit tak? A skoro wyniki sa nie jawnie rzutowane do int to we wszystkich makrach powinien byc blad...🤔(?) bez znaczenia ile bitow przesunal...

Ja to trochę uprościłem 😛 Tak dość mocno...

Powiedzmy, że matematykę zostawiamy w spokoju. Po prostu w jednym z momentów obliczenia wychodzi poza oczekiwany zakres, co kompilatorowi się nie podoba. 😉 

Pamiętaj, że każda liczba "signed" ma na początku "znak" (dobra, trochę źle się wysławiam... to -2^n, które przesuwa nam zakres liczb, stąd też bierze się szerszy zakres na minusach niż na plusach). Wynika to z metody zapisu (pierwszy bit to -2^n, a reszta to 2^n). Nawet jeżeli masz liczbę dodatnią, to na początku jest bit 0, który też jest uwzględniany przy negacji. A reszta to magia kompilatora, nad którą lepiej się nie rozwodzić, bo można by o tym stworzyć cały kierunek studiów.

P.S.

128(signed) = 0b010000000

Edytowano przez H1M4W4R1
  • Lubię! 1
Link do komentarza
Share on other sites

Ja tylko tak...

const uint8_t zmienna = (cośtam) & 0xff;

To raczej poza 8 bitów nie wylezie 🙂

Można np. tak:
 

#define B8(a) ((a) & 0xff)
#define N8(a) ((~(a)) & 0xff)

 

i dalej w stylu:

const uint8_t zmienna = N8((1<<7) | (1<<6));

Można i tak...

 

 

 

  • Lubię! 1
Link do komentarza
Share on other sites

Chodzi o to ze twoj wynik zostaje skrocony/uciety do 8-bitow

#define N8(a) ((~(a)) & 0xff)

zapis 0xff oznacza binarnie 0b11111111...i teraz cala reszta poza tymi osmioma jedynkami zostaje jaky usunieta i zostaje tylko liczba 8- bitowa, czyli taka jaka Cie interesuje..

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.