Arduino - problem z kowersja dec -> bin


(fedora24x) #1
void hours_set(int hours)
{
	float edit = hours;
	for (int i = 6; i >=2 ; i--)
	{
		if (edit%2)
		{
			edit = (int)(edit/2);
			digitalWrite(i, HIGH);
		} else {
			edit = (int)edit/2;
			digitalWrite(i, LOW);
		}
	}
}
void minutes_set(int minutes)
{
	float edit = minutes;
	for (int i = 12; i >=7 ; i--)
	{
		if (edit%2)
		{
			edit = (int)(edit/2);
			digitalWrite(i, HIGH);
		} else {
			edit = (int)edit/2;
			digitalWrite(i, LOW);
		}
	}
}
void setup()
{
	for (int i = 2; i <= 13; i++)
	{
		pinMode(i, OUTPUT);
	}
}
int hours = 19;
int minutes = 44;
bool clock = false;
void loop()
{
	if(hours == 24)
	{
		hours = 0;
	} else {
		hours++;
	}
	if (minutes == 59)
	{
		minutes = 0;
		hours++;
	} else {
		minutes++;
	}

	hours_set(hours);
	minutes_set(minutes);

	if (clock)
	{
		digitalWrite(13, LOW);
		clock = false;
	} else {
		digitalWrite(13, HIGH);
		clock = true;
	}
	delay(1000);
}

Montuje zegar binarny, gdzie piny od 2-6 reprezentują godzine binarnie a piny 7-12 minuty, a pin 13 tylko sekundnik. I mam problem z kodem - nie wiem co zrobić aby dobrze wyświetlał czas?


(Drobok) #2

Nie mieszaj typów zmiennych. Do 24 możesz śmiało liczyć na char, nie powtarzaj instrukcji bo zapychasz pamięć procesora.

Nie ustawiaj portów po pinie.

Zakładając, że numerujesz porty zgodnie z tym obrazkiem. http://www.dominicdube.com/wp-content/uploads/Arduino-uno-Pinout.png używasz portd i portb. 

Godzinę możesz wyświetlać tak:

PIND=(hours<<2);

Oczywiście zmienna hours powinna być zmienną typu char. A wprowadzasz do niej wartość zgodnie z ogólnie przyjętą normą.

Jako że ostatnie piny w porcie D używany jest przez minutnik powinieneś do tego użyć również zmiennej dot. minut:

PIND=(hours<<2)|(minutes>>6);//przesuwasz wartość godziny w prawo, bo pierwsze 2piny zawsze są zerami, i dodajesz do tego pierwsze 2piny minut.

Minuty wyświetlasz analogicznie do godzin, z tym że musisz wyświetlić pierwsze 6 pinów i dodać sekundy

PINB=(minutes<<2)|zmienna_sekundowa_typu_bool;


(fedora24x) #3

Wyjścia numeruje wg nadruków na płytce.

a jak je mam ustawiać?

void hours_set(int hours)
{
	PIND=(hours<<1);
}
void minutes_set(int minutes)
{
	PINB=(minutes<<1);
}

tak?

i poprzesuwać piny z (2-12)na:

-dla godz…  (0-4)

-dla minu… (7-12)

 

**to jest to:

https://www.arduino.cc/en/Reference/PortManipulation


(Drobok) #4

portd 0:7

portb nie jest w całości używany w atmegach (masz tam nawet napisane) musiałbyś sobie zmienić fusebity, ale wtedy musiałbyś mieć programator do zmiany softu w tym procesorze.

Potrzebujesz 6bitów do minut i 5bitów do godzin + sekundnik. Więc weź sobie portd jako minuty + sekundy, a portb jako godziny.

Jeśli zrobiłbyś to zgodnie z tym co napisałem, to możesz zrobić tak:

PINB=hours;//ustawisz 5ostatnich pinów portub jako stan godziny więc to z nich powinieneś korzystać

PIND=(minutes1)|sekundy;//(przesuwasz minuty 1bit w lewo, a na ostatni bit dodajesz sekundy), używasz wtedy ostatnich 7bitów portud, możesz przesunąć całość o 2bity i wtedy będziesz używał pierwszych pinów (ostatni pin będzie wolny)

A co do pytania w tytule, to kompilator zmieni liczbę dziesiętną na binarną. Więc jeśli nie wpisujesz niczego z zewnątrz to nie musisz nic konwertować.


(fedora24x) #5
void hours_set(int hours)
{
	PIND=(hours<<1);
}
void minutes_set(int minutes)
{
	PINB=(minutes<<1);
}
void setup()
{
	for (int i = 0; i <= 13; i++)
	{
		pinMode(i, OUTPUT);
	}
}
int hours = 19;
int minutes = 44;
bool clock = false;
void loop()
{
	if(hours == 24)
	{
		hours = 0;
	}
	if (minutes == 59)
	{
		minutes = 0;
		hours++;
	} else {
		delay(1000);
		minutes++;
	}
	hours_set(hours);
	minutes_set(minutes);
}

Aktualnie mam:

piny 0-4 dla godz (5bit)

a piny 7-12 dla minut (6bit)

 

i teraz jak mam to wyprowadzic na prostą?


(Drobok) #6

Jeśli używasz starszych pinów musisz przesunąć wartość bardziej w ich kierunku, jednak zgodnie z linkiem który podałeś nie powinieneś używać dwóch najstarszych pinów portub (a ty używasz jednego z nich). Używanie funkcji dla jednej instrukcji mija się z celem.

void setup()
{
    DDRD=0xFF;//portd jako wyjście
    DDRB=0xFF;//portb jako wyjście
}
char hours = 19;
char minutes = 44;
bool clock = false;
void loop()
{
	if(hours == 24)
	{
		hours = 0;
	}
	if (minutes == 59)
	{
		minutes = 0;
		hours++;
	} else {
		minutes++;
		clock=~clock;//zmiana stanu clock co sekundę
	}
	delay(1000);//zajęcie procesora poza warunkiem (bo ci będzie przeskakiwał o sekundę co 24h i co godzinę)
	//weź poprawkę że delay działa względem ustawionej w kompilatorze częstotliwości pracy procesora
	PORTB=(hours<<2);
	PORTD=(minutes<<1)||sekundy;
}

piny 9:13 to godzina, a piny 1:6minuty, a 7pin to sekundnik. Pisane z palca, ale powinno działać.

Weź też pod uwagę, że użycie delay spowoduje że nie zrobisz z procesorem nic innego. Powinieneś zacząć korzystać z przerwań.


(fedora24x) #7
void setup()
{
    DDRD=0xFF;//portd jako wyjście
    DDRB=0xFF;//portb jako wyjście
}
int hours = 22;
int minutes = 14;
int seconds = 0;
bool clock = false;
void loop()
{
	if(hours == 24)
	{
		hours = 0;
	}
	if (minutes == 59)
	{
		minutes = 0;
		hours++;
	}
	if(seconds == 59)
	{
		seconds = 0;
		minutes++;
	} else {
		seconds++;
		delay(910);
	}
	
	PORTB=(hours<<2);
	PIND=(minutes<<1)||seconds;
}

Porty 9:13 to godzina, a porty 1:6minuty, a 7port to sekundnik

 

tak?


(Drobok) #8

Wszystko ma mieć typ char, a co do sekund nie. Musiałbyś usunąć wszystkie bity poza ostatnim.

=(minutes<<1)|(seconds&1);

Poza tym delay musisz mieć poza if, bo ci będą przeskakiwać stany po wykonaniu if’a będziesz miał 2 przejścia a nie jedno. W sumie jeden kij.


(fedora24x) #9
void setup()
{
    DDRD=0xFF;//portd jako wyjście
    DDRB=0xFF;//portb jako wyjście
}
char hours = 22;
char minutes = 27;
int seconds = 0;
bool clock = false;
void loop()
{
	if(hours == 24)
	{
		hours = 0;
	}
	if (minutes == 59)
	{
		minutes = 0;
		hours++;
	}
	if(seconds == 59)
	{
		seconds = 0;
		minutes++;
	} else {
		seconds++;
		delay(980);
	}
	
	PORTB=(hours<<2);
	PIND=(minutes<<1)||(seconds&&1);
}

wszystko char, poza sekundami

 

minuty wogole sie nie świeca a sa dobrze polaczone


(Drobok) #10

Już zdążyłem poprawić, ma być & a nie && (ten drugi daje stan logiczny a nie and) or analogicznie 

A sekundy też mają być char.


(fedora24x) #11
void setup()
{
    DDRD=0xFF;
    DDRB=0xFF;
}
char hours = 10;
char minutes = 0;
char seconds = 0;
void loop()
{
    if(seconds == 59)
    {
        seconds = 0;
        minutes++;
    } else {
        seconds++;
        delay(980);
    }
    if (minutes == 59)
    {
        minutes = 0;
        hours++;
    }
    if(hours == 24)
    {
        hours = 0;
    }
    PORTB=(hours<<2);
    PIND=(minutes<<1)|(seconds&1);
}

stan wyjsc dla godziny sie zgadza 9 = 01001, ale minuty nie koniecznie bo przeskaują po miedzy stanami: 100000 a 001101 suma obydwóch to 45 sie zgadza, ale nie da się w jednym cyklu?

a dla 10.00 juz sie nie zgadza bo 00101 a minuty 100000

zegar dziala nie prawidlowo?


(Drobok) #12

delay(980) nie da ci jednej sekundy

przeskakiwanie tej sumy to raczej wina optymalizacji kompilatora - dołóż nawias albo zmienną tymczasową.

PORTD=((minutes<<1)|(seconds&1));

Albo (jeśli pierwsze nie zadziała):

char tmp=((minutes<<1)|(seconds&1));
PORTD=tmp;

a co do złego stanu ma być portb a nie pinb, zdebugowałem ten kod i działa tak jak powinien.


(fedora24x) #13

Kod do Arduino:

void setup()
{
    DDRD=0xFF;
    DDRB=0xFF;
}
char hours = 12;
char minutes = 33;
char seconds = 0;
void loop()
{
	if(seconds == 59)
	{
		seconds = 0;
		minutes++;
	} else {
		seconds++;
		delay(1000);
	}
	if (minutes == 59)
	{
		minutes = 0;
		hours++;
	}
	if(hours == 24)
	{
		hours = 0;
	}
	PORTB = (hours<<2);
	PORTD = ((minutes<<1)|(seconds&1));
}

Używane PINy:

godzina: 8-13

minuty: 1-6

 

Zamiast 12:30, pokazuje 00011(H) i 110001(M), metoda z PORTD/B nie działa?

 

Nie było by łatwiej wykorzystać bit po bicie?

void hours_set(int hours)
{
	float edit = hours;
	for (int i = 6; i >=2 ; i--)
	{
		if (edit%2)
		{
			edit = (int)(edit/2);
			digitalWrite(i, HIGH);
		} else {
			edit = (int)edit/2;
			digitalWrite(i, LOW);
		}
	}
}
void minutes_set(int minutes)
{
	float edit = minutes;
	for (int i = 12; i >=7 ; i--)
	{
		if (edit%2)
		{
			edit = (int)(edit/2);
			digitalWrite(i, HIGH);
		} else {
			edit = (int)edit/2;
			digitalWrite(i, LOW);
		}
	}
}

 


(Drobok) #14

Spróbuj tak (zadeklaruj wcześniej zmienne):

tam gdzie masz sekundy itd zadeklarowane daj:


(fedora24x) #15
void setup()
{
    DDRD=0xFF;
    DDRB=0xFF;
    pinMode(7, OUTPUT);
}
char hours = 13;
char minutes = 14;
char seconds = 6;
bool clock = false;
volatile char TMPB;
volatile char TMPD
void loop()
{
	if(seconds == 59)
	{
		seconds = 0;
		minutes++;
	} else {
		seconds++;
		delay(1000);
	}
	if (minutes == 59)
	{
		minutes = 0;
		hours++;
	}
	if(hours == 24)
	{
		hours = 0;
	}
	TMPB = (hours<<2);
    PORTB = TMPB;
    TMPD = (minutes<<1)|(seconds&1);
    PORTD = TMPD;
	if (clock)
	{
		digitalWrite(7, LOW);
		clock = false;
	} else {
		digitalWrite(7, HIGH);
		clock = true;
	}
}

i mam:

sketch_dec13a.ino:4:1: error: expected initializer before ‘void’
sketch_dec13a.ino:13:1: error: expected initializer before ‘void’

 


(Drobok) #16

ta migająca dioda jest najmłodszym pinem z minut więc ten  if na końcu jest zbędny. Wartości zmiennych powinieneś przypisywać w setup. A jeśli przeniesienie tego do tej funkcji nie zadziała to powinieneś wywalić to volatile, widać kompilator do arduino nie wie co to.

btw połknąłeś linie kopiując


(fedora24x) #17

Jak dałem do setupa:

void setup()
{
    DDRD=0xFF;
    DDRB=0xFF;
    pinMode(7, OUTPUT);
    char hours = 13;
	char minutes = 14;
	char seconds = 6;
	bool clock = false;
	volatile char TMPB;
	volatile char TMPD;
}
void loop()
{
	if(seconds == 59)
	{
		seconds = 0;
		minutes++;
	} else {
		seconds++;
		delay(1000);
	}
	if (minutes == 59)
	{
		minutes = 0;
		hours++;
	}
	if(hours == 24)
	{
		hours = 0;
	}
	TMPB = (hours<<2);
    PORTB = TMPB;
    TMPD = (minutes<<1)|(seconds&1);
    PORTD = TMPD;
	if (clock)
	{
		digitalWrite(7, LOW);
		clock = false;
	} else {
		digitalWrite(7, HIGH);
		clock = true;
	}
}

To wywaliło:

sketch_dec13a.ino: In function ‘void loop()’:
sketch_dec13a.ino:15:5: error: ‘seconds’ was not declared in this scope
sketch_dec13a.ino:18:3: error: ‘minutes’ was not declared in this scope
sketch_dec13a.ino:23:6: error: ‘minutes’ was not declared in this scope
sketch_dec13a.ino:26:3: error: ‘hours’ was not declared in this scope
sketch_dec13a.ino:28:5: error: ‘hours’ was not declared in this scope
sketch_dec13a.ino:32:2: error: ‘TMPB’ was not declared in this scope
sketch_dec13a.ino:32:10: error: ‘hours’ was not declared in this scope
sketch_dec13a.ino:34:5: error: ‘TMPD’ was not declared in this scope
sketch_dec13a.ino:34:13: error: ‘minutes’ was not declared in this scope
sketch_dec13a.ino:34:26: error: ‘seconds’ was not declared in this scope
sketch_dec13a.ino:36:6: error: ‘clock’ was not declared in this scope

a jak wyjąłem z setupa:

void setup()
{
    DDRD=0xFF;
    DDRB=0xFF;
    pinMode(7, OUTPUT);
}
char hours = 13;
char minutes = 14;
char seconds = 6;
bool clock = false;
volatile char TMPB;
volatile char TMPD;
void loop()
{
	if(seconds == 59)
	{
		seconds = 0;
		minutes++;
	} else {
		seconds++;
		delay(1000);
	}
	if (minutes == 59)
	{
		minutes = 0;
		hours++;
	}
	if(hours == 24)
	{
		hours = 0;
	}
	TMPB = (hours<<2);
    PORTB = TMPB;
    TMPD = (minutes<<1)|(seconds&1);
    PORTD = TMPD;
	if (clock)
	{
		digitalWrite(7, LOW);
		clock = false;
	} else {
		digitalWrite(7, HIGH);
		clock = true;
	}
}

to nie wywala żadnych błedów, lecz diody pokazują błedny czas…