Stránka 1 z 1

"Rozsekání" čísla po desítkách

Napsal: 19 lis 2014, 13:27
od pirat077
Ahoj, potřeboval bych rozsekat číslo po desítkách (na čtyřcifernou sedmisegmentovku), jak to udělat?

Řešení s dělením mi vždycky nějak selhalo,

Počítání od 0 do 9 podle pulzů mi funguje dobře, rozšíření je problém.

Jinak používám Atmega8, TIMER2 (Nejsou v něm snad žádné záludnosti narozdíl od TIMER0??)


Napadlo mě i klasitké řešení vytvořit si proměnnou pro jednotky, desítky, stovky....ale vzhledem k tomu, že potřebuju jedním signálem přičítat a druhým odečítat (čísla, ne jedničky), tak to nepřichází v úvahu.

Díky

Napsal: 19 lis 2014, 14:34
od forbidden
Já v assembleru vždycky pracuju se samostatnýma proměnnýma pro stovky, desítky, jednotky... když jde o zobrazování na display. Algoritmus mám, že nejdřív odečítám nejvyšší řád, třeba stovky a počítám, kolikrát odečtu, než je výsledek zápornej, pak ten poslední odečet vrátím a odečítám nižší řád, atd...
Původní číslo ale mám samozřejmě uložený ve zvláštní proměnné, abych s ním kdyžtak mohl dělat běžný operace. Ten rozklad je jen kvůli zobrazování.

Napsal: 19 lis 2014, 15:32
od termit256
Nevim co presne si predstavujes pod pojmem rozsekat na desitky, ale pokud jde o prevod do BCD, deleni by melo fungovat. Pricitej a odecitej si cisla jak chces, ale to co se ma zobrazit preved na BCD. Vydel cislo k zobrazeni 1000 -dostanes tak tisicovky a ty posli na displej, celociselny zbytek vydel 100 (stovky), pak 10 a nakonec ti zbudou jednotky.

Napsal: 19 lis 2014, 16:08
od pirat077
termit256 píše:Nevim co presne si predstavujes pod pojmem rozsekat na desitky, ale pokud jde o prevod do BCD, deleni by melo fungovat. Pricitej a odecitej si cisla jak chces, ale to co se ma zobrazit preved na BCD. Vydel cislo k zobrazeni 1000 -dostanes tak tisicovky a ty posli na displej, celociselny zbytek vydel 100 (stovky), pak 10 a nakonec ti zbudou jednotky.


Možná 🤐 dotaz: Ale vždycky to počítá celočíselně? není v tom nějaká zrada? nebo existuje fce pro zaokrouhlení na jednotky?

Napsal: 19 lis 2014, 16:54
od AB1

Kód: Vybrat vše

unsigned int number = 1234;

jed = number % 10            // 4
des = (number / 10) % 10     // 3
sto = (number / 100) % 10    // 2
tis = (number / 1000) % 10   // 1


Ale vždycky to počítá celočíselně? není v tom nějaká zrada? nebo existuje fce pro zaokrouhlení na jednotky?

Dělení celočíselných typů probíhá celočíselně.

int a,b,c;
a=7;
b=2;
c=a/b; // c = 3

Asi by bylo dobré přečíst nějakou knihu o C.

Napsal: 19 lis 2014, 17:24
od pirat077
Díky, nefunguje mi tenhle program: (snad mě neukamenujete za tak dlouhej kus)

Displej bliká, něco se tam děje....
Budu fakt moc vděčnej za radu ;)

#define F_CPU 4000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <math.h>

volatile unsigned int cislice;
volatile unsigned int cislo;
volatile unsigned char T1;
volatile unsigned char T2;
volatile unsigned char T3;

//////////////////////////////////////////////////////////////////////////
// TIMER 0
//////////////////////////////////////////////////////////////////////////
ISR (TIMER0_OVF_vect)
{
TCNT0 = 180; // preruseni po 19,2ms
T1++;
T2++;
//////////////////////////////////////////////////////////////////////////
// FCE PRICITANI PULZU - (PB3)
//////////////////////////////////////////////////////////////////////////
switch (T1)//kazdejch 19,2s scannuje pulz
{
case 1:
if ((!(PINB&0b00001000))==1){ //pokud neprisel pulz
T1=0;
}
break;

case 4:
if ((!(PINB&0b00001000))==0){
cislo=cislo+5;
}
else{
T1=0;
}
break;

case 8:
T1=0;
break;
}
//////////////////////////////////////////////////////////////////////////
// ODECITANI PULZU -(PB2)
//////////////////////////////////////////////////////////////////////////
switch (T2)//kazdejch 19,2s scannuje pulz
{
case 1:
if ((!(PINB&0b00000100))==1){
T2=0;
}
break;

case 2:
if ((!(PINB&0b00000100))==0){ //pokud prisel pulz if ((!(PINB&0b00000100))==0)
cislo--;
}
else { //pokud tady neni pulz, tak neceka do konce, ale jde na zacatek cekani
T2=0;
}
break;

case 3:
T2=0;
break;
}
}
//////////////////////////////////////////////////////////////////////////
// TIMER 2
//////////////////////////////////////////////////////////////////////////
ISR (TIMER2_OVF_vect)
{
TCNT0 = 205; //preruseni po 12,8ms
T3++;
switch (T3)
{
case 1:
PORTC|= (0 << PC2); PORTC|= (1 << PC5);//PC5 -ANODA TISICE
if (cislo>=1000){
cislice=cislo/1000;
cislo=cislo-(cislice*1000);
}
else{
cislice=10; //zobrazi se -
}
break;

case 2:
PORTC|= (0 << PC5);PORTC|= (1 << PC4);//PC4 -ANODA STOVKY
if (cislo>=100){
cislice=cislo/100;
cislo=cislo-(cislice*100);
}
else{
cislice=10; //zobrazi se -
}
break;

case 3:
cislice=cislo/100;
PORTC|= (0 << PC4);PORTC|= (1 << PC3);//PC3 -ANODA DESITKY
if (cislo>=10){
cislice=cislo/10;
cislo=cislo-(cislice*10);
}
else{
cislice=10; //zobrazi se -
}
break;

case 4:
PORTC|= (0 << PC3);PORTC|= (1 << PC2); //PC2 -ANODA JEDNOTKY
cislice=cislo;
T3=0;//vymaze casovaci promennou
break;
}
ukazC(cislice);
}
//////////////////////////////////////////////////////////////////////////
// ZOBRAZOVANI CISEL
//////////////////////////////////////////////////////////////////////////
void ukazC (char cislice)
{
switch (cislice)
{
case 0: PORTD = 0b11000000; break;
case 1: PORTD = 0b11111001; break;
case 2: PORTD = 0b10100100; break;
case 3: PORTD = 0b10110000; break;
case 4: PORTD = 0b10011001; break;
case 5: PORTD = 0b10010010; break;
case 6: PORTD = 0b10000010; break;
case 7: PORTD = 0b11011000; break;
case 8: PORTD = 0b10000000; break;
case 9: PORTD = 0b10010000; break;
default: PORTD = 0b10111111; break; //prostredni vodorovna cara
//0b01111111, //tecka
//0b11111111 //nic
}
}
//////////////////////////////////////////////////////////////////////////
// HLAVNI FUNKCE
//////////////////////////////////////////////////////////////////////////
int main (void)
{
DDRB=0b00110010; //1=vystup, 0=vstup ///F7=>preklad programu
DDRC=0b00111100; //C2-C5 jsou spolecny anody
DDRD=0xff; //sedmisegment-vse vystupy
//PORTB|= (1 << PB1); //zapnuti proudu nafurt
PORTD = 0b11111111;
while(1)
{
TCCR0 |= (1 << CS02) | (1 << CS00); // preddelicka /1024 //TCCR0 = 0b00000101;TIMSK = 0b00000011;
TIMSK|= (1 << TOIE0);// prerušenie pri pretečení TCNT0

//TIMER2
TCCR2 |= (1 << CS22) | (1 << CS21)| (1 << CS20); // preddelicka /1024 //TCCR0 = 0b00000101;TIMSK = 0b00000011;
TIMSK|= (1 << TOIE2);// prerušenie pri pretečení TCNT2

sei(); //povol globálne prerušenia

PORTB=0b00110000;
_delay_ms(40);
PORTB ^= (1 << PB5);
_delay_ms(100);
}
}

Napsal: 19 lis 2014, 19:46
od mtajovsky
Nejspíš tam budete mít nějakou chybu.

Napsal: 19 lis 2014, 19:50
od pirat077
mtajovsky píše:Nejspíš tam budete mít nějakou chybu.

Ale kde? :D
Já už nevím :(

Napsal: 19 lis 2014, 20:46
od mtajovsky
Vážně ... to vám takhle asi nikdo neřekne. To je pro ATMega 8? Blbě se ladí, nemá debug režim. Zkuste najít chybu krokováním programu v simulátoru a kontrolou dat a výstupů. Pokud máte skutečný HW debugger (Dragon, JTAG ICE apod. a to pro važnější práci fakt doporučuju), tak bych to odladil pro ATMega 88, která má DebugWire a pak odladěné portoval na ATMega 8.

Napsal: 19 lis 2014, 21:44
od Zaky
Asi tak, dělat něco dnes na MCU bez debugu si nějak radši ani nechci představovat. Když si vzpomenu na doby, kdy jsem kódoval v ASM 51čku a to naštěstí již flashový paralelně programovaný klon od Atmelu a bylo to pořád programátor - patice v zařízení, přičemž vrcholem ladění bylo někam přidat rozsvícení ledky, no nechybí mi to :-) Oblíbil jsem si Cypress PSOC, řada 4 je narozdíl od 5 i za velmi přijatelné peníze a s osmibity zcela nesrovnatelná.

Napsal: 19 lis 2014, 22:22
od WLAB
Ten program je bohuzel asi hodne spatny... Jednak se mi zda, ze tam vidim nekolik "race condition"... Operace, ktere maji byt atomicke atomicke nejsou, cislo se rozpocitava na digity rozlozene v case, do toho to rozebirane "cislo" muze menit to druhe preruseni... tohle spatne odhaluje i pri krokovani....

Tohle predpokladam, ze je preklep a ma byt TCNT2:

TCNT0 = 205; //preruseni po 12,8ms

Takhle tou operaci OR opravdu puvodne nahozenou anodu neodbudis...

PORTC|= (0 << PC3);PORTC|= (1 << PC2); //PC2 -ANODA JEDNOTKY

PORTC|= (0 << PC3); oprav na PORTC&= ~(1 << PC3);

a vsechno dalsi taky...

Takhle reseny program je zrejme velke sousto....
Ono i ty intervaly by to chtelo resit zpusobem, kdy se o to clovek nemusi starat a nastavovat TCNTx na neco v ISR, protoze se tim zanasi systematicka odchylka....

Napsal: 19 lis 2014, 22:53
od pirat077
Díky, ty negace portu už jsem opravil,
...a ten komentář v ms je špatněj, zkoušel jsem jinej interval... Ale postřeh dobrej

hlavní chyba je v tom, že se ta hlavní suma pořád jen dělila časovačem2, za chvilku ukážu lepší řešení ;)

Napsal: 19 lis 2014, 23:24
od WLAB
jsi si jistej, ze v ISR u TIM2 misto

Kód: Vybrat vše

TCNT0 = 205;

nema byt

Kód: Vybrat vše

TCNT2 = 205;


Takhle na pohled mi to prijde divny....

Ten kod ma, obavam se, zasadni koncepcni vady... no uvidis...

A vkladej sem ten zdrojak jako "code", at to neni tak necitelna hruza...

Napsal: 19 lis 2014, 23:57
od pirat077
WLAB píše:jsi si jistej, ze v ISR u TIM2 misto

Kód: Vybrat vše

TCNT0 = 205;

nema byt

Kód: Vybrat vše

TCNT2 = 205;


Takhle na pohled mi to prijde divny....

Ten kod ma, obavam se, zasadni koncepcni vady... no uvidis...

A vkladej sem ten zdrojak jako "code", at to neni tak necitelna hruza...


DÍKY MOC ZA TEN TCNT2 !!
To jsem úplně přehlídl, fakt mi to pomohlo!!
Už mi to funguje,
Pokud se ti chce, tak mi prosím (třeba i v bodech) napiš, co se ti na tom koncepčně nezdá...
Jsem začátečník a rád se přiučím ;)

Díky!

Napsal: 20 lis 2014, 00:32
od WLAB
Uz jsem to psal nahor, zas ale ten zdrojak nechi prolejzat do detailu, takze pokud to mas ostreno, napis jak...

Napr. ten multiplex mas rizeny prerusenim a soucasne s kazdym digitem pocitas, co zobrazit a upravujes pri tom hodnotu promenne "cislo", behem te doby ale "cislo" obsahuje nejaky mezivysledek pro zobrazovani, ovsem TIM0, se zda, ze ti ho muze kdykoliv zmenit - ten mezivysledek.... Proste, kdyz nejakou promennou zpracovavas (a tady "cislo" zpracovavas vlastne po celou dobu multiplexu, vyjma jeho navratu na prvni digit), musis mit zajisteno, ze ti do ni nikdo jiny nesahne (TIM 0 ISR) a opacne nesmis (TIM2 ISR) ji menit nekomu, kdo s ni pracuje (TIM0 ISR)... pomohou tomu pomocne promenne a atomicke predavani hodnot (tj. rekneme "neprerusitelne").

Moc nevim, jak to muze fungovat (ale mohl jsem v tom neco prehlednout), protoze ten zobrazovaci multiplex ti vzdycky znici obsah "cislo"...

Taky nechapu, proc jsou v mainu uvnitr while(1) ty incicializace timeru a to povoleni preruseni....