Zjištění logické hodnoty pinu

Nefunguje mi načtení logické hodnoty na PINB4, jako by tem bylo furt log 1
Část kódu kterého se to týká:

ISR (TIMER0_OVF_vect){
	
	if (!PINB4) {
		PORTD = 0x00;
		} else {
		PORTD = 0x80;
	}
	
}

Celý kód:

#define F_CPU 8000000UL
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <util/delay.h>

unsigned char linka;
unsigned char cisloPrikazu;
unsigned char id;
unsigned char ks;
unsigned char p = 7;
unsigned char podminka;
unsigned char pocitadlo;
unsigned char poziceMotoru1;
unsigned char poziceMotoru2;
unsigned char reletivniPozicePocatkuX;
unsigned char relativniPozicePocatkuY;
unsigned short x;
unsigned short y;
unsigned char pole[4] = {0b00000011, 0b00000110, 0b00001100, 0b00001001};
// send char
void uart_putc(unsigned char data )
{
	while ( !( UCSRA & (1<<UDRE)) )
	;
	UDR = data;
	
}
// get char
unsigned char uart_getc( void )
{
	/* Wait for data to be received */
	while ( !(UCSRA & (1<<RXC)) )
	;
	/* Get and return received data from buffer */
	return UDR;
}

ISR (TIMER0_OVF_vect){
	
	if (!PINB4) {
		PORTD = 0x00;
		} else {
		PORTD = 0x80;
	}
	
	//PORTD ^= 0x80;
}
ISR (TIMER1_COMPA_vect){
	
	
}
void pozice (void) {
	while ((!PINB4) || (!PINB5)) {
		_delay_ms(10);
		if (!PINB4)
		{
			poziceMotoru1 -= 1;
			poziceMotoru1 = (poziceMotoru1 + 4) % 4;
			PORTB = pole[poziceMotoru1 + 1];
		}
		if (!PINB5)
		{
			poziceMotoru2 -= 1;
			poziceMotoru2 = (poziceMotoru2 + 4) % 4;
			PORTB = pole[poziceMotoru2 + 1];
		}
	}
	x = 0;
	y = 0;
	
	while ((x < reletivniPozicePocatkuX) || (y < relativniPozicePocatkuY)) {
		_delay_ms(10);
		if (x < reletivniPozicePocatkuX)
		{
			poziceMotoru1 += 1;
			poziceMotoru1 = (poziceMotoru1 + 4) % 4;
			PORTB = pole[poziceMotoru1 + 1];
			x += 1;
		}
		if (y < relativniPozicePocatkuY)
		{
			poziceMotoru2 += 1;
			poziceMotoru2 = (poziceMotoru2 + 4) % 4;
			PORTB = pole[poziceMotoru2 + 1];
			y += 1;
		}
	}
	x = 0;
	y = 0;
	
}
int main(void)
{
	
	
	/***** inicializace uart  *****/
	DDRD = 0x80;
	PORTD = 0x00;
	DDRB = (1<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3);
	DDRC = 0xFF;
	
	
	UCSRA = 0x00;
	UBRRH = 0x00;  // nastaveni rychlosti pro krystal  1 MHz
	UBRRL = 51;   // 9600 baud
	UCSRB |= (1<<TXEN) | (1<<RXEN);
	UCSRC = 0x86;  // ramec dat:  8 datovych, 1 stop bit, bez parity
	
	TIMSK = 0b00010001; //bit 0 - povolení přerušení při přetečení od timeru 0, bit 4 - povolení přerušení timer 1
	TCCR0 = 5; //předdělička na 1024, timer 0
	TCCR1B = 0b00001010; //předdělička na 8(bit 1); (bit 3) nastavení CTC modu
	OCR1A = 199; // 460 při 18,xx MHz, 199 při 8 MHz
	
	
	PORTD = 0x80;
	
	_delay_ms(1000);
	_delay_ms(1000);
		
	sei();
	while(1)
	{
		linka = uart_getc();
		switch (linka) {
		case 237:
			uart_putc(237);
			break;
		case 239:
			cisloPrikazu = uart_getc();
			id = uart_getc();
			switch (id) {
			case 1:
				ks = uart_getc();
				podminka = 239 ^ cisloPrikazu ^ id ^ ks;
				if (podminka == 0) {
					ks = 239 ^ cisloPrikazu ^ 10;
					uart_putc(239);
					uart_putc(cisloPrikazu);
					uart_putc(10);
					uart_putc(ks);
					
					pozice();
					
					ks = 239 ^ cisloPrikazu ^ 11;
					uart_putc(239);
					uart_putc(cisloPrikazu);
					uart_putc(11);
					uart_putc(ks);
					
				}
				break;	
			}
			break;
		}
		
	}
	return 0;
}

avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=308279

zapis

 if (!PINB4) { 
}

je nezmyselny, lebo hodnota PINB4 je vzdy rovna 4.
No a 4 sa nikdy nebude rovnat nule. Zvycajne :slight_smile:

PINB4 iba urcuje, na ktorej pozicii sa PINB4 v registri PINB nachadza.

Preto je spravny zapis ako uz bolo uvedene v odkaze

if (PINB & (1<<PINB4)) { 
}

tento zapis spravi logicky AND obsahu vstupu portu B s hodnotou log.1 posunutou o PINB4 pozicie do lava, cize je to to iste ako

if (PINB & 0b00010000) { 
}

alebo to iste ako

if (PINB & 0x10) { 
}

Ale len ten prvy zapis je prehladny a cloveku zrozumitelny.
A ti aj ked sa Ti to mozno na pry pohlad nezda. Mozes si ho vylepsit pomocou nasledovnych #define:

#define SET(BAJT,BIT) ((BAJT) |= (1<<(BIT)))
#define RES(BAJT,BIT) ((BAJT) &= ~(1<<(BIT)))
#define NEG(BAJT,BIT) ((BAJT) ^= (1<<(BIT)))
#define TST(BAJT,BIT) ((BAJT) & (1<<(BIT)))

if TST(PINB,PINB4) { 

}

// alebo pre opacnu podmienku
if (!TST(PINB,PINB4)) { 

}

Takyto zapis sa pouziva aj preto, ze ak by vyrobca v nejakom registri pomenil poradie bitov, tak prekladac vzdy prelozi kod spravne (pokial teda ten bit ostane v tom istom registri),lebo spravnu polohu bitu si nacita z prislusnych headrov, ktore sa napr v AVRStudiu v ramci nastavenia parametrov projektu nacitaju pre dany procesor automaticky. Ak by dany bit v nanom procesore neexistoval, prekladac ta na to upozorni. Priklad zapis:

SET(ADCSRA,ADFR);

napisany pre ATmega8 sa prelozi v poriadku, ale ten isty zapis sa pre ATmaga88 uz v poriadku neprelozi, lebo ATmega88 nema bit ADFR. Na jeho mieste je bit s nazvom ADATE a jeho nastavenie ma trochu iny vyznam. Ak by si mal v kode prasacky zapisane

   ADCSRA = ADCSRA | 0b00100000;

alebo ten isty vysedok pri inom zapise

   ADCSRA |= 0x20;

Program by pre ATmega8 robil to co ma, ale pre ATmega88 uz ani nie a prekladac by Ta na nic neupozornil, kedze by nemal na zaklade coho. Zaroven takto zapisany program je velmi tazko citatelny a osobne “milujem” otazky v diskusii s kusmi takehoto kodu, ktore automaticky prehliadam. Ved kto ma cas lustit, ktore bity sa to vlastne nastavuju.
Prekladac vsak vestky horeuvedene zapisi prelozi rovnako, takze prasackym zapisom sa v ramci vysledneho kodu aj tak nic neusetri.

Fakt mě překvapuje že se chce lidem používat makra SET ,RES, NEG, TST když jde zařídit aby když chceš znát hodnotu pinu nebo ji změnit tak prostě napíšeš PIN= nebo if (PIN)

Ako?

Uved prosim kod ako to myslis. Vacsina setupovacich bitov nema s portami nic spolocne.

Je to otestovaný s AVR GCC…


typedef struct
	{
    unsigned B0: 1;
    unsigned B1: 1;
    unsigned B2: 1;
    unsigned B3: 1;
    unsigned B4: 1;
    unsigned B5: 1;
    unsigned B6: 1;
    unsigned B7: 1;
    } bits;


#define BITS(p) (*(volatile bits*)&p)

#define INPUT  0
#define OUTPUT 1

#define LEDKA BITS(PORTB).B7
#define DIR_LEDKA BITS(DDRB).B7


DIR_LEDKA=OUTPUT;

LEDKA=1;
LEDKA=0;

Proti gustu ziaden disputat. :slight_smile:
Mne to pride komplikovanejsie a mozno pre zaciatocnika pouzivanie smernikov este zahadnejsie.

Osobne robim hodne s definicnymi hlavickovymi subormi, ktore sa linkuju jednak podla pouziteho MCU a jednak podla pouziteho HW tak, aby bol kod v C-cku rovnaky.

vyskusal som Tvoj kod a doplnil na porovnanie s mojim pristupom



#include <avr/io.h>
#include <stdint.h>

typedef struct
   {
    unsigned B0: 1;
    unsigned B1: 1;
    unsigned B2: 1;
    unsigned B3: 1;
    unsigned B4: 1;
    unsigned B5: 1;
    unsigned B6: 1;
    unsigned B7: 1;
    } bits;


#define BITS(p) (*(volatile bits*)&p)

#define INPUT  0
#define OUTPUT 1

#define LEDKA BITS(PORTB).B7
#define DIR_LEDKA BITS(DDRB).B7


#define SET(BAJT,BIT) ((BAJT) |= (1<<(BIT)))
#define RES(BAJT,BIT) ((BAJT) &= ~(1<<(BIT)))
#define NEG(BAJT,BIT) ((BAJT) ^= (1<<(BIT)))
#define TST(BAJT,BIT) ((BAJT) & (1<<(BIT)))

#define LED_BLUE  0 			// 0, lebo je na pine PB0
#define LED_GREEN 1 			// 1, lebo je na pine PB1
#define LED_WHITE 2 			// 2, lebo je na pine PB2

#define LED_BLUE_OUT SET(DDRB,LED_BLUE)
#define LED_BLUE_IN RES(DDRB,LED_BLUE)
#define LED_BLUE_ON RES(PORTB,LED_BLUE)
#define LED_BLUE_OFF SET(PORTB,LED_BLUE)


int main(void)
{

DIR_LEDKA=OUTPUT;

LEDKA=1;
LEDKA=0;

LED_BLUE_OUT; 
LED_BLUE_ON;
LED_BLUE_OFF; 

}

Po pozreti v ASM kodu v simulatore je uplne jasne, ze obe verzie vedu k uplne rovnakemu vygenerovaneho kodu.

Osobne pouzivam makra hlavne z nasledujuceho dovodu. Pri Tvojom pristupe, by som sa bez makra nakoniec aj tak nezaobisiel.

Priklad nastavenia casovaca

// v headri pre ATmega328, napr. "header_basic_328.h"
#define TB_NASTAV_CASOVAC	TCCR2A = (1<<WGM21) | (1<<WGM20);\
                            TCCR2B = ((1<<WGM22) | (1<<CS22) | (1<<CS20)) // mod 7, CTC update TOP a preddelic 128
// v headri pre ATmega8, napr. "header_basic_8.h"
define TB_NASTAV_CASOVAC	(TCCR2 = (1<<WGM21) +(1<<CS22)) // mod CTC a preddelic 64, CS22 = H, CS21 = L, CS20 = L

a potom v nejakom C-cku


#define MCU ATmega328
//#define MCU ATmega8

#ifdef MCU == ATmega328
   #include "header_basic_328.h"
#elif MCU == ATmega8
   #include "header_basic_8.h"
#else
   #error NIE JE SPRAVNE DEFINOVANY PROCESOR
#endif

#ifndef MCU
   #error NIE JE VOBEC DEFINOVANY PROCESOR
#endif


int main(void)
{
// ....

TB_NASTAV_CASOVAC;

// ....

}

Jasný.
Chápu, že když někdo neumí s pointrama a struktůrama, tak to řešení vypadá dost krypticky :wink:
Celá věc se má tak že pokud chci vyjít z toho co už je nadefinováno, tak se to co jsem napsal hodí tak maximálně pro ty vstupy a výstupy (já to používám právě jen takhle), ty si člověk stejně definuje podle aplikace , takže to nevadí.
Setkal jsem se dost často s tím že lidi co přešli z 51 a PIC se ptali jak to že u AVR se na I/O zapisuje a čte jinak (pro ně nezvykle) a nejde udělat OUT=IN;
V IAR a CODE VISION na to už mají definice udělaný.
Co se týče nastavování registrů pro periférie - tam jsou pouze dvě možnosti , dělat s tím co je a nebo si napsat svoje hlavičky.
Pokud bych se rozhodl pro to druhé, byla by to kombinace ukazatelů na struktury/unie + #define SFR_BIT (1<N) nebo #define SFR_BITS(b) (b<<n)

Ale když se vrátím k tomu na co se ptal zakladatel vlákna, tak mu to moje makro problém řeší - může používat konstrukci která mu nechodila.