AVR, C, Nastavení log hodnot pinů na portu

Všetko čo sa týka mikropočítačov + Sekcia Arduino

Moderátori: psichac, Moderátori

DanielK
Stály člen
Stály člen
Príspevky: 282
Dátum registrácie: 28 Feb 2015, 14:55

AVR, C, Nastavení log hodnot pinů na portu

Príspevok od používateľa DanielK » 21 Feb 2023, 18:50

Ahoj,
Potřebuji ovládat šesnácti segmentový dispaly, na který používám necelé tři porty.
Je mi jasné, jak nastavit celý port, vím jak nastavit konkrétní pin, ale nevím jak v poli nastavit pouze některé piny z portu bez zásahu do ostatních pinů v poli. Na portu D potřebuji nastavovat piny 7,6 a 5 zbytek budou vstupní a výstupní piny do kterých nechci zasahovat. Dokázal bych to udělat v podmínkách, ale určitě existuje i nějaký elegantní způsob jak na to.
Děkuji za pomoc.

Kód: Vybrať všetko

int main(void)
{
	DDRD = 0b11111000;	// Vstupy a výstupy
	DDRB = 0b11111111;	// Vstupy a výstupy
	DDRC = 0b11111111;	// Vstupy a výstupy
	PORTD = 0b00000111;	// Pull UP
	
	uint8_t dispB [] = {0x67, 0x7F};	//0, 1, ...
	uint8_t dispC [] = {0xCC, 0xFF};	//0, 1, ...
	uint8_t dispD [] = {PORTD &= ~(1 << PD7), 0xFF}; //? 
	
	uint8_t hodnota =0; //
	
    while (1) 
    {
		PORTD &= ~(1 << PD3);  // GND 
				
		PORTB = dispB[hodnota];	//nastav port B				
		PORTC = dispC[hodnota];	//nastav port C
		PORTD = dispD[hodnota];	//nastav port D		
    }
}
0

Používateľov profilový obrázok
YellowJacket
Pokročilý člen
Pokročilý člen
Príspevky: 503
Dátum registrácie: 05 Feb 2012, 11:58
Bydlisko: Hrinova
Vek: 33

Re: AVR, C, Nastavení log hodnot pinů na portu

Príspevok od používateľa YellowJacket » 21 Feb 2023, 18:59

Robi sa to pomocou bitovych operatorov.

Nastavenie:

Kód: Vybrať všetko

PORTB |= ( 1 << PB3 );       /* nastavi pin PB3 na log 1 */
Vymazanie:

Kód: Vybrať všetko

PORTB &= ~( 1 << PB3 );       /* nastavi pin PB3 na log 0

Takisto pracujes aj s viacerymi bitmi naraz, napr:

Kód: Vybrať všetko

PORTB |= ( 1 << PB3 ) | ( 1 << PB4 );       /* nastavi pin PB3 a PB4 na log 1, ostatne bity ostanu nezmenene */
Pozri napriklad sem: http://www.rjhcoding.com/avrc-bit-manip.php
0

DanielK
Stály člen
Stály člen
Príspevky: 282
Dátum registrácie: 28 Feb 2015, 14:55

Re: AVR, C, Nastavení log hodnot pinů na portu

Príspevok od používateľa DanielK » 21 Feb 2023, 19:08

To je mi jasné, potřebuji ale nastavovat hodnoty v poli.

uint_8t = pole1 [] {PD7 = log0 PD6 = log1 PD5 = log1, /*další číslo*/ };
PORTD = pole1 [0];
potřebuji měnit pouze piny 5,6 a 7, ale beze změny ostatních pinů na portu D, protože ty budou mít úplně jiné funkce, než ovládat display.
0

Používateľov profilový obrázok
Andy99
Stály člen
Stály člen
Príspevky: 339
Dátum registrácie: 05 Mar 2008, 00:00
Bydlisko: BA
Vek: 35

Re: AVR, C, Nastavení log hodnot pinů na portu

Príspevok od používateľa Andy99 » 21 Feb 2023, 19:28

Nie som sice AVR-ista, ale tipujem, ze hodnoty PD5, PD6... su len bity registra PD. Takze netusim naco je dobre mat ulozeny jeden bit v 8-bitovom poli. Osobne by som to riesil cez bitove pole, maskovanie alebo gulometom pomocou look-up table pointrov.
0

DanielK
Stály člen
Stály člen
Príspevky: 282
Dátum registrácie: 28 Feb 2015, 14:55

Re: AVR, C, Nastavení log hodnot pinů na portu

Príspevok od používateľa DanielK » 21 Feb 2023, 19:37

Těch bitů bude v tom poli sousta, čísla, písmena, znaky... zatím tam mám jen 0 a 1 další přidám.
port B ovládá část displaye port C ovládá část displaye, ale pouze část portu D ovládá zbývající 3 segmenty dispalye, zbytek pinů z portu D bude využito na tlačítka ledku...
0

Používateľov profilový obrázok
YellowJacket
Pokročilý člen
Pokročilý člen
Príspevky: 503
Dátum registrácie: 05 Feb 2012, 11:58
Bydlisko: Hrinova
Vek: 33

Re: AVR, C, Nastavení log hodnot pinů na portu

Príspevok od používateľa YellowJacket » 21 Feb 2023, 19:48

DanielK napísal:
21 Feb 2023, 19:08
To je mi jasné, potřebuji ale nastavovat hodnoty v poli.
Prepac, zle som pochopil. Tak potrebujes nieco taketo? Pretoze stale je to iba o binarnej uprave daneho bajtu.

Kód: Vybrať všetko

uint_8t pole1 [] = { 0xff, 0x11, 0x44, 0xaa };
uint_8t novaHodnota;

novaHodnota = 0b10100000;   /* P7 = 1; P6 = 0; P5 = 1 */
pole1[0]    = ( pole1[0] & 0b00011111 ) | novaHodnota;

novaHodnota = 0b00100000;   /* P7 = 0; P6 = 0; P5 = 1 */
pole1[1]    = ( pole1[1] & 0b00011111 ) | novaHodnota;
0

peterple
Ultimate člen
Ultimate člen
Príspevky: 2328
Dátum registrácie: 25 Jún 2013, 21:06
Bydlisko: Krajné
Vek: 57
Kontaktovať používateľa:

Re: AVR, C, Nastavení log hodnot pinů na portu

Príspevok od používateľa peterple » 21 Feb 2023, 20:43

Myslím že ideš na to zle. Ako prvé by som začal tým že tie poznámky čo v tom kóde máš môžeš rovno vymazať. Nepriniesli mi žiadnu informáciu.
Za druhé, ako sa dá 16znakový LED riadiť 3 portami a ešte ti zostanú 3 bity. Ja potrebujem všetkých 24.
8 - segmenty A,B,C,D,E,F,G,H(bodka)
16 - spínanie báz tranzistorov.
Ale toto je detail.

A teraz to podstatné. Nie je vôbec vhodné stavať to pole čo tam ideš posielať tak aby to bol obraz tých portov. Práve naopak. Sprav si pole o 16 bytoch a tam daj buď priamo kód znaku sedem segmentovky, alebo len index do generátora znakov.
Na vyslatie údajov na porty si urob funkciu ktorá tie bity pre-ore ako treba a pošle na porty.

Kód: Vybrať všetko

#define SEG_A 0x01
#define SEG_B 0x02
#define SEG_C 0x80
#define SEG_D 0x20
#define SEG_E 0x10
#define SEG_F 0x04
#define SEG_G 0x08
#define SEG_H 0x40


/**
 *          A
 *        -----
 *       |     |
 *     F |     | B
 *       |  G  |
 *        -----
 *       |     |
 *     E |     | C
 *       |     |
 *        -----
 *          D    o H
 *          
 *          
 */

#define ZNAK_0 (SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F)
#define ZNAK_1 (SEG_B | SEG_C)
#define ZNAK_2 (SEG_A | SEG_B | SEG_D | SEG_E | SEG_G)
#define ZNAK_3 (SEG_A | SEG_B | SEG_C | SEG_D | SEG_G)
#define ZNAK_4 (SEG_B | SEG_C | SEG_F | SEG_G)
#define ZNAK_5 (SEG_A | SEG_C | SEG_D | SEG_F | SEG_G)
#define ZNAK_6 (SEG_A | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G)
#define ZNAK_7 (SEG_A | SEG_B | SEG_C)
#define ZNAK_8 (SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G)
#define ZNAK_9 (SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G)

#define ZNAK_A (SEG_A | SEG_B | SEG_C | SEG_G | SEG_E | SEG_F)
#define ZNAK_B (SEG_F | SEG_G| SEG_E| SEG_C| SEG_D)
#define ZNAK_C (SEG_A | SEG_F | SEG_E | SEG_D)
#define ZNAK_D (SEG_G | SEG_E | SEG_C | SEG_D | SEG_B)
#define ZNAK_E (SEG_A | SEG_F | SEG_G | SEG_E| SEG_D)
#define ZNAK_F (SEG_A | SEG_F | SEG_G | SEG_E)
#define ZNAK_TMA (0)

//vytvor pole ktore obsahuje obrazovu reprezentáciu jednotlivych cislic
unsigned char generatorCislic[]={ZNAK_0,ZNAK_1,ZNAK_2,ZNAK_3,ZNAK_4,ZNAK_5,ZNAK_6,ZNAK_7,ZNAK_8,ZNAK_9,ZNAK_A,ZNAK_B,ZNAK_C,ZNAK_D,ZNAK_E,ZNAK_F};

/**
 * Funkcia ktora pre cislo v rozsahu 0 az 15 vrati obrazovu reprezentaciu cislice na sedemsegmentovke
 * vstup cislo - cislo od 0 po 15
 * vystup 8bitova hodnota ktora zobrazi cislicu na sedemsegmentovke
 * ak vstupna hodnota bude viac ako 15 tak sa zobrazi prazdny znak
 */
unsigned char dajCislicu(unsigned char cislo){
  if (cislo<=15){ //ak je cislo od 0 do 15
    return generatorCislic[cislo];  //vytiahni z pola obrazovu podobu cislice
  }
  return ZNAK_TMA;  //inak zobraz prazdny znak (zhasnute všetky segmenty)
}

unsigned char displej[16];
char pozicia = 0;
unsigned int bazy = 0xFFFE;

void zobrazZnak(){
//napr tie segmenty budú 7 - 3 PORTD a 7 - 5 PORTB
unsigned char znak=displej[pozicia];
PORTD=(znak & 0xF8) | 0x07; //necham hornych 5 bitov a dole doplnim 111 
PORTB=(bazy & 0x1F) | (znak & 0x07) << 5); // bázam odrežem horné 3bity a pridám tam dolné tri zo znaku
                                                                             // pričom zo znaku najprv odrežem horných 5 bitov  a potom to 5x posuniem doľava
PORTC=(bazy >> 8) & 0xFF; //tuto len vezmem horný byte a naposuniem ho do dolného;
}


main(){
//vypisovanie znakov do pola
displej[0]=ZNAK_0;  //na tvrdo
displej[1]=ZNAK_1;
displej[2]=dajCislicu(2);  //podľa indexu v tabuľke znakov

zobrazZnak();


}
Výhodu to má takú že kedykopľvek čokolvek na dps zmeníš tak len upravíš pár konštant a ten šrotovací výpočet a všetok ostatný kód zostáva rovnaký. Vystačís si len s operáciami logický sučin, súčet a rotácie.
Samozrejme ešte tam chýba kód čo po nejakej chvíli zmení premennú bázy a pozicia a potom znova zavolá zobrazZnak() aby sa zobrazil nový znak na novej pozícii.

Polovica toho kódu bola písaná priamo do príspevku, takže neručím za prípadné preklepy. Išlo mi len o to nahodiť princíp ako jednoducho a univerzálne napísať obsluhu multiplexneho LED displeja.
Samozrejme miesto hexa konštant môžeš použiť binárne ak je to pre teba prehladnejšie. Ja som stará škola čo odrástla na hexa sústave.

A je tam ešte miesto pre optimalizáciu, nakoľko ten generátor znakov obsahuje iba konštanty takže sa dá presunúť do programovej pamäte a ušetiť si tak zopár byte SRAM.
0
Ukáž múdremu chybu a on sa ti poďakuje. Ukáž chybu hlupákovi a on sa urazí.

DanielK
Stály člen
Stály člen
Príspevky: 282
Dátum registrácie: 28 Feb 2015, 14:55

Re: AVR, C, Nastavení log hodnot pinů na portu

Príspevok od používateľa DanielK » 21 Feb 2023, 21:04

Nechci řídit 7 segmentový display o 16 digitech, ale 16 segmentový resp 17 i s tečkou 1 digit :D alfanumerický display LTP-587Y proto potřebuji 17 pinů. Port C jich má ale pouze 6, B 8 a 3 piny si vypůjčím od portu D Attiny48.
0

peterple
Ultimate člen
Ultimate člen
Príspevky: 2328
Dátum registrácie: 25 Jún 2013, 21:06
Bydlisko: Krajné
Vek: 57
Kontaktovať používateľa:

Re: AVR, C, Nastavení log hodnot pinů na portu

Príspevok od používateľa peterple » 21 Feb 2023, 21:13

Aha zle som to pochopil. Nevadí - princíp zostáva. Len ten generátor znakov bude máličko inak a tie výpočty budú podobné.
0
Ukáž múdremu chybu a on sa ti poďakuje. Ukáž chybu hlupákovi a on sa urazí.

DanielK
Stály člen
Stály člen
Príspevky: 282
Dátum registrácie: 28 Feb 2015, 14:55

Re: AVR, C, Nastavení log hodnot pinů na portu

Príspevok od používateľa DanielK » 22 Feb 2023, 21:59

V jednoduchosti je krása.
Původně jsem chtěl psát ty znaky do pole pro část portu D podobně jako jsem to udělal i s portem B a C, ale zda to lze to nevím.

Kód: Vybrať všetko

int main(void)
{
	DDRD = 0b11111000;	// Vstupy a výstupy
	DDRB = 0b11111111;	// Vstupy a výstupy
	DDRC = 0b11111111;	// Vstupy a výstupy
	PORTD = 0b11111111;	// Pull UP
	uint8_t hodnota =0; //
	
	uint8_t dispB [] = {0x67, 0x7F, 0x67, 0x67, 0x7F, 0xE7, 0xE7, 0x7F, 0x67, 0x67, 0x7F, 0x65, 0xE7, 0x65, 0XE7, 0xFF, 0xE7, 0x7F, 0xE5, 0xED, 0xBE, 0xE7, 0x3F, 0x7E, 0x67, 0x7F, 0x66, 0x7E, 0xE7, 0xFD, 0x67, 0x9F, 0x5E, 0x9E, 0xBD, 0x87};	//0, 1, ...
	uint8_t dispC [] = {0xCC, 0xFF, 0xCE, 0xCF, 0xFD, 0xCD, 0xCC, 0xCF, 0xCC, 0xCD, 0xCC, 0xC7, 0xCC, 0xC7, 0xCC, 0xCC, 0xCC, 0xFC, 0xC7, 0xC6, 0xFC, 0xFC, 0xF8, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0xCD, 0xC7, 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xCF};	//0, 1, ...
	
	int vypisznak(){
		
		PORTB = dispB[hodnota];	//nastav port B
		PORTC = dispC[hodnota];	//nastav port C
		
		if(hodnota == 0 || hodnota == 1 || hodnota == 7 || hodnota == 13 || hodnota == 22 || hodnota == 23 || hodnota == 24 || hodnota == 26 || hodnota == 30 || hodnota == 32){
			PORTD &= ~(1 << PD7);  // GND
			PORTD |= (1 << PD6);  // VCC
			PORTD |= (1 << PD5);  // VCC
		}

		else if(hodnota == 20){
			PORTD |= (1 << PD7);  // VCC
			PORTD &= ~(1 << PD6);  // GND
			PORTD |= (1 << PD5);  // VCC
		}
		else if(hodnota == 11 || hodnota == 16){
			PORTD &= ~(1 << PD7);  // GND
			PORTD |= (1 << PD6);  // VCC
			PORTD &= ~(1 << PD5);  // GND
		}
		else if(hodnota == 2 || hodnota == 14 || hodnota == 15 ||hodnota == 25 || hodnota == 27){
			PORTD |= (1 << PD7);  // VCC
			PORTD &= ~(1 << PD6);  // GND
			PORTD &= ~(1 << PD5);  // VCC
		}
		else if(hodnota == 3 || hodnota == 4 || hodnota == 5 || hodnota == 6 || hodnota == 8 || hodnota == 9 || hodnota == 10 || hodnota == 17 || hodnota == 28){
			PORTD &= ~(1 << PD7);  // GND
			PORTD &= ~(1 << PD6);  // GND
			PORTD &= ~(1 << PD5);  // GND
		}
		else/*(hodnota == 12 || hodnota == 18 || hodnota == 19 || hodnota == 21 || hodnota == 29 || hodnota == 31 || hodnota == 33 || hodnota == 34 || hodnota == 35)*/{
			PORTD |= (1 << PD7);  // VCC
			PORTD |= (1 << PD6);  // VCC
			PORTD |= (1 << PD5);  // VCC
		}	
	}
	
    while (1) 
    {
		PORTD &= ~(1 << PD3);  // GND je noc a piezo je moc hlasité
		
		vypisznak();
		hodnota ++;
		if(hodnota > 35)
		hodnota =0;
		_delay_ms(2000);
		
	}		
}
0

Napísať odpoveď