Skocz do zawartości

Jawne rzutowanie w AVR GCC


Pomocna odpowiedź

Napisano

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. 

Moge sie mylic, bo szczerze to strzelam, ale jawne rzutowanie wyglada tak..

(uint8_t)~(SEG_DP),

Choc dziwne by bylo ze reszta bez rzutowania dziala a to akurat nie, wiec nie wiem czy to rozwiaze twoj problem...cza na mondzejszych poczekac..😅

  • Pomogłeś! 1

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. 😕

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...

(edytowany)
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
(edytowany)
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
(edytowany)

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
(edytowany)

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
(edytowany)
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

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

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..

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...