forum.mcontrollers.com - hlavní stránka forum.mcontrollers.com - fórum

 

.: fórum - hlavní stránka :.
Technology Stronghold by Rudolf Vesely
How to build Microsoft System Center hosted cloud series
FAQFAQ HledatHledat Seznam uživatelůSeznam uživatelů Uživatelské skupinyUživatelské skupiny RegistraceRegistrace
ProfilProfil StatistikaStatistika Soukromé zprávySoukromé zprávy PřihlášeníPřihlášení

 
Projekt: Stopky na čtyřmístném 7-segmentovém displeji
Jdi na stránku 1, 2  Další
 
Přidat nové téma   Zaslat odpověď    Obsah fóra mcontrollers.com -> AVR
 
Misa
Anonymní





PříspěvekZaslal: 05 leden 2013, 11:05    Předmět: Projekt: Stopky na čtyřmístném 7-segmentovém displeji Citovat

ahoj, chtěla jsem udělat stopky s 4 místnou sedmisegmentovkou, aby mi při stisku tlačítka začali počítat. Při opakovaném stisknutí se zastavili. Vynulování se mi snad podařilo. Dělám to s delay_ms, což nevím jestli je správně...
Našel by se někdo, kdo by mě navedl na nějakou možnost? napadlo mě to dělat přes neznámou a podmínku if. Ale asi je to hloupost
#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>

const unsigned char segs[] =
{0b11000000, 0b11111001, 0b10100100, 0b10110000, 0b10011001, 0b10010010, 0b10000010,
0b11111000, 0b10000000, 0b10011000, 0b01111111};




#define B1() (bit_is_clear(PINA,4))
#define B2() (bit_is_clear(PINA,5))


int main(void)
{
unsigned char set_1=0;
unsigned char set_10=0;
unsigned char sek_1=0;
unsigned char sek_10=0;
unsigned char show_t=0;

DDRD = 0xFF;
DDRA = 0x1F;
DDRB = 0xFF;
PORTB = 0xFF;


while(1)
{
if(B1())
{

_delay_ms(1);
set_1++;

if(set_1>9){set_1=0;set_10++;};
if(set_10>9){set_10=0;sek_1++;};
if(sek_1>9){sek_1=0;sek_10++;};


if(++show_t==4) show_t=0;
switch(show_t)
{
case 0: //show minutes
PORTA = 0b11111110;
PORTB = (segs[set_1]);
break;
case 1: //show 10 minutes
PORTA = 0b11111101;
PORTB = (segs[set_10]);
break;
case 2: //show hours
PORTA = 0b11111011;
PORTB = (segs[sek_1]) & (segs[10]);
break;
case 3: //show 10hours
PORTA = 0b11110111;
PORTB = (segs[sek_10]);
break;
default:
show_t = 0;
break;

}

}
if(B2())
{
set_1=0;
set_10=0;
sek_1=0;
sek_10=0;
}
}
}

Arrow administrator: přejmenováno z "stopky"
Návrat nahoru
 

 
Balů
Profesionál
Profesionál


Založen: 29.10.2012
Příspěvky: 752

PříspěvekZaslal: 05 leden 2013, 11:52    Předmět: Citovat

Teoreticky to přes delay udělat můžeš, ale :

1 - nejsem si jistý, že delay_ms(1) bude trvat přesně 1 ms.
2 - ne každý průběh smyčky bude trvat stejně dlouho v závislosti na splněných/nesplněných podmínkách rozhodování

Načítání impulzů (tedy času) se v těchto případech vždy dělá pomocí čítače a buď procesor běží na krystalu nebo alespoň čítač běží v asynchronním režimu na externí krystal nebo jiný přesný zdroj hodin. Řešil jsem podobnou věc (i když ne stopky) s mcu ATmega8A. Procesor jsem nechal běžet na IntRC 8 MHz, naprogramoval jsem pojistku CKOPT a na piny TOSC1/TOSC2 jsem připojil krystal 32768 Hz jako zdroj hodin pro Timer/Counter2, který jsem přepnul do asynchronního režimu a který zajišťuje co možná nejpřesnější čítání.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

 
Panda38
Profesionál
Profesionál


Založen: 18.9.2012
Příspěvky: 398
Bydliště: Praha, Most

PříspěvekZaslal: 05 leden 2013, 12:14    Předmět: Citovat

Misa: Sice je prodleva 1ms celkem přesná, ale ty ostatní obsluhy ve smyčce udělají přídavné zpoždění, které může udělat chybu (podle rychlosti MCU) i např. 10% (u rychlosti několik MHz). Takže na první pokusy ok, ale pro praktické využití by to chtělo pak přejít na hw čítač (nebo alespoň prodloužit tu prodlevu). I kdyby se měl používat jen interní RC oscilátor a poolování hodnoty čítače, tak by to mohlo být už docela vyhovující pro nenáročná měření.

Podobný program se řešil tady (obsluhy tlačítek): http://forum.mcontrollers.com/viewtopic.php?t=3140&start=0&postdays=0&postorder=asc&highlight= . Autor tam používá prodlevu 10 ms, což je trochu lepší v tom, že se méně projeví ostatní kód ve smyčce a je to proto přesnější (i bez použití přerušení).

Balů: Nevěděl jsem že ATmega8 umí používat externí krystal a přitom jet z interního RC. Teď na to koukám do datasheetu, to je docela zajímavá možnost.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu Zobrazit autorovy WWW stránky
 

 
Martin
ATmega pouzivatel
ATmega pouzivatel


Založen: 5.1.2008
Příspěvky: 1485

PříspěvekZaslal: 05 leden 2013, 18:40    Předmět: Citovat

Ja by som na to isiel takto. Urcite pouzivaj casovac na urcenie kvanta casu. Netreba hned pouzivat prerusenie. Jednoducho testuj, ci uz dany cas ubehol a ak ano spusti vsetky funkcie ktore potrebujes.
Samozrejme tieto funkcie sa musia stihnut do nastaveneho casu, inak nastane sklz. V dalsom uvadzam priklad z jedneho skolenia, kde je vysvetleny princip prace s casovacom ako s casovou zakladnou pre riadenie celej cinnosti v mcu. V prikade je nastaveny cas na 100us. Co nie je nejaky extra extrem. Pri 8 MHz za ten cas stihne mcu vykonat 400-800 instrukcii. Myslim, ze nebude problem delice a predvolbu nastavit tak, aby vola casova zakladna 1ms, alebo trebars aj 10ms. Vsetko je na prekladac GCC. Header obsahuje nejake nastavenia tykajuce sa vyvojovej dosticky s ATtiny25, viac menej pre to co som chcel ukazat nepodstatne.
Ty si nahrat funkciu "void fn_matematika_1(void)" nejakou, ktora sa stara o o tie tlacitka a stopky. Vyhoda tohto pristuju je, ze mas vzdy v ramci presnosti hodin presne determinonvane vykonavanie cinnosti v mcu. Na tuto cinnost si zvykni, je to uzitocne. Ziadne posahane _delay_ms(). Staci potom pridat par riadkov programu a uz nevies kolko moze v skutocnosti slucka bezat.
V priklade su premenne typu volatile preto, aby ich prekladac nevyhodil z kodu a dalo sa v simulatore prezentovat, ako program funguje. Treba to brat ako edukacny priklad.

subor

program_c02_timebase_100us.c

kód:


// bloky v *.C subore

// dokumentacna cast

/*
   Druhy program.
   Program beží v nekonečnej sľučke.
   Program testuje casovac na dosiahnutie casu 100us.
   Po jeho dosiahnuti vykona dalsiu cinnost.
   V dalsej cinnosti zavola funkciu, ktora spravi prislusne matematicke operacie
   s premennymi typu uint8_t, uint16_t a uint32_t
*/

// vsetky potrebne #include
#include "tiny_kit_zaklad.h"

// deklaracia IMPORTovanych objektov,ale iba ak nieje prislusny *.H subor, takze tu by vlastne nic nemalo byt

// Definicia GLOBALnych premennych

// Definicia lokalnych typov

// Uplne funkcne prototypy LOCALnych funkcii
void fn_matematika_1(void);
void fn_init_cz(void);
uint8_t fn_testuj_cz(void);

// Definicia GLOBALnych funkcii

// Lokalne #define
#define KONST1 7
#define KONST2 547
#define KONST3 856971L

// Definicia LOCALnych premennych
volatile static uint8_t  a;
volatile static uint16_t b;
volatile static uint32_t c;

// main()
int main(void)
{
   
   fn_init_cz();
   // nekonecna slucka
   while(1) {

      if (fn_testuj_cz() == FALSE) continue;

      fn_matematika_1();
   }
}


// Definicia LOCALnych funkcii
void fn_matematika_1(void)
{   
static uint8_t prvy_prechod = 0;

   if (prvy_prechod == 0) {
      prvy_prechod = prvy_prechod + 1;
      a = 0;
      b = 0;
      c = 0;
   }

   a = a + KONST1;
   b = b + KONST2;
   c = c + KONST3;

   return;
}


void fn_init_cz(void)
{

   SET(TCCR0A,WGM01);
   SET(TCCR0B,CS01);
   OCR0A = PREDVOLBA_CZ;

   return;
}

uint8_t fn_testuj_cz(void)
{
   if (TST(TIFR,OCF0A)) {
      // nastala zhoda TCNT0 s obsahom registra OCR0A
      // a casovac pocita od zaciatku
      SET(TIFR,OCF0A);
      return(TRUE);
   }

   return(FALSE);
}



a k tomu este header pre vseobecne nastavenia definicie a pre nastavenia pre konkretny hw obsahujuci nejake tlacitka a nejake ledky.
Subor

tiny_kit_zaklad.h

kód:

#include <stdint.h>

// zakaldne binarne stavy
#define FALSE 0
#define TRUE 255

// Definice makier s parametrami
#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)))


// parametre casovaca vytvarajuceho casovu zakladnu
#define PREDVOLBA_CZ 99

// definicie vstupov a vystupov z hladiska funkcnosti
#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 TL_2 0             // 0, lebo je na pine PB0
#define TL_3 1             // 1, lebo je na pine PB1

#define TRANZISTOR_OC1 2    // 2, lebo je na pine PB2
#define TRANZISTOR_OC2 1    // 1, lebo je na pine PB1
#define REPRO 4              // 4, lebo je na pine PB4

#define IN_OP1 2             // 2, lebo je na pine PB2
#define IN_OP2 1             // 1, lebo je na pine PB1
#define INFRA_PRIJIMAC 0    // 0, lebo je na pine PB0

#define AD1 3                // 3, lebo je na pine PB3
#define AD2 4                // 4, lebo je na pine PB4




skusim napisat funkciu ( z hlavy, nemam cas to skusat tak dufam, ze tam nebudu nejake zasadne chyby Smile ) pre funkciu testujucu tlacitka a pocitanie casu, tu potom nahrad za funkciu "void fn_matematika_1(void)". Ako tlacitko pouzijem TL_2 z demodosky.
Funkciu fn_stopky_ini(void) vloz napr podla vzoru. V nej sa inicializuju stavy a premenne.

kód:

 // ....
      fn_init_cz();
      fn_stopky_ini();
 // ....



kód:


// toto az po ten posledny static vloz na zaciatok programu k ostatnym premenym
#define MAX_TEST_ZAKMITOV_TL 100
#define NULOVANIE_CASU 0
#define ZASTAVENE_CASU 1
#define SPUSTENIE_CASU 2
#define MAX_NAMERANY_CAS 999999 // maximalna hodnota je do 99.9999 sekundy

static uint8_t stav_tlacitka_new, stav_tlacitka_old;
static uint8_t cnt_zakmitov_tl, stav_stopiek = NULOVANIE_CASU;
static uint32_t namerany_cas = 0;
static uint16_t namerany_cas_zobraz, pom16;
static uint8_t znak[3];

void fn_stopky_ini(void)
{
    RES(DDRB,TL_2); // nastavenie pinu na vstup. Po inicializacii sice automaticky je, ale takto je to zrozumitelne a odolne voci EMI
    if (TST(PINB, TL_2))  stav_tlacitka_old = TRUE;
    else  stav_tlacitka_old = FALSE;
    cnt_zakmitov_tl  = MAX_TEST_ZAKMITOV_TL;
    return;
}

void fn_stopky(void)
{

    RES(DDRB,TL_2); // nastavenie pinu na vstup. Po inicializacii sice automaticky je, ale takto je to zrozumitelne a odolne voci EMI
     // test, ci je odpamatana hodnota stavu tlacitka ina ako znovu nacitana hodnota stavu



    if (TST(PINB, TL_2))  stav_tlacitka_new = TRUE;
    else  stav_tlacitka_new = FALSE;
  // na prvy pohlad to vyzera, ze premenna stav_tlacitka_new je zbytocna, ale nie je. Jej pouzitim sa zabrani moznemu chaosu ak tlacitko ma inu hodnotu v case porovnania so starou hodnotou a inu hodnotu v case zmeny starej hodnoty na zaklade novej.

     if (stav_tlacitka_new == TRUE) && (stav_tlacitka == FALSE)) || (stav_tlacitka_new == FALSE) && (stav_tlacitka == TRUE)) ) {
         // ak je odpamatany stav rozny od cerstvo nacitaneho, potom dekrementuj pocitadlo casovo sumovej imunity nacitania tlacitka (pri cz 100us je to pre MAX_TEST_ZAKMITOV_TL = 100 akurat 10ms )
         if (cnt_zakmitov_tl) cnt_zakmitov_tl--;
         // nastavenie novej hodnoty odpamataneho stavu tlacitka
         else {
             // vyhodnotenie stavoveho automatu stopiek.
             stav_tlacitka_old = stav_tlacitka_new;
             // udalost pustenia tlacitka nas nebude zaujimat, budeme vyhodnocovat iba zmenu smerom k "stlaceniu" tlacitka
             if (stav_tlacitka_old == TRUE) {
                 // toto sa samozrejme da spravit aj cez if() a aj cez inkrement premennej. Nie je to vsak tak prehladne ako tento kostrukt a procesoru je to sumafuk, prekladac sa postara o preklad do pouzitelnej rychlej formy. Opat pripominam, ze 100us, nedajboze 1ma je hafo casu.
                 switch (stav_stopiek)  {
                       case NULOVANIE_CASU : {
                            stav_stopiek = SPUSTENIE_CASU;
                            break;
                       }
                       case SPUSTENIE_CASU : {
                            stav_stopiek = ZASTAVENE_CASU;
                            break;
                       }
                       case ZASTAVENE_CASU : {
                            stav_stopiek = NULOVANIE_CASU;
                            break;
                       }
                 }
             }
             // kedze doslo k zmene hodnoty  stav_tlacitka_old, treba znovu prednastavit hodontu cnt_zakmitov_tl, aj ked tato by sa aj tak prednastavila o 100us ked program zisti, ze k zmene stavu nedoslo. Ale takto je to jasnejsie a je vidiet, ze sa na nic nezabudlo :-)
             cnt_zakmitov_tl = MAX_TEST_ZAKMITOV_TL;
 
         } 
    }
    else {
         // ak su hodnoty stav_tlacitka_old a stav_tlacitka_new rovnake, nie je dovod nenastavit premennu cnt_zakmitov_tl. Tym sa eliminuje nespravne vyhodnotenie pri predchadzajucich kratkodobych moznych dekrementoch.
         cnt_zakmitov_tl = MAX_TEST_ZAKMITOV_TL;
    }
       
    // teraz vyhodnotime stavovy automat
    if (stav_stopiek == NULOVANIE_CASU)  namerany_cas = 0;
    if (stav_stopiek == SPUSTENIE_CASU)  {
          // aby nam namerany cas nepretiekol urobime kontrolu
          if(namerany_cas < MAX_NAMERANY_CAS) namerany_cas++;
    }
    // zobrazenie nameraneho casu. NApr, nech nas zaujimaju len desatiny sekundy a cas do hodnoty 99.9s
    namerany_cas_zobraz = uint16_t(namerany_cas/1000);
    // tu sa velmi hodi pouzit funkciu
    // itoa((int16_t)namerany_cas_zobraz, &znak[0]);
    // tymto by v poli znak[] boli ulozne jednotlive asacii znaky cila od 0 do 999
    // ale nepouzijem ju :-)
    // miesto toho zakladny rozklad

    pom16 = namerany_cas_zobraz/10;
    znak[2] = '0' +  uint8_t(namerany_cas_zobraz - pom16*10);
    namerany_cas_zobraz = pom16;
    pom16 = namerany_cas_zobraz/10;
    znak[1] = '0' +  uint8_t(namerany_cas_zobraz - pom16*10);
    namerany_cas_zobraz = pom16;
    // na najnizsom indexe je najvyssia cislica
    znak[0] = '0' +  uint8_t(namerany_cas_zobraz);

    // ak nechces zobrazovat najvyssie nevyznamen nuly, tak potom este test
    if (znak[0] == '0') {
          znak[0] == ' ';
          if (znak[1] == '0') znak[1] == ' ';
          // ak aj znak[2] = '0', ten nechame tak, aby sa na display nieco zobrazovalo.
    }
    // nasledujucu funkciu si napis podla svojich potrieb, nepoznam tvoj hw.
     fn_zobraz_znaky_na_displayi();
   
    return;
}



takze takto nejako by som na to isiel. Urcite si vyber niektory z casovacov pre tvorbu casovej zakladne a dosledne ho pouzivaj. delay pouzi len pre casy tak do 10-20us. Naco zbytocne brzdit cakanim ine casti programu. Drzim palce a daj vediet ako to dopadlo. Smile
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

 
Balů
Profesionál
Profesionál


Založen: 29.10.2012
Příspěvky: 752

PříspěvekZaslal: 05 leden 2013, 23:54    Předmět: Citovat

Panda38: Umí to nejenom ATmega8, ale i ATmega48(88,168,328).
ATmega128, ATmega16(32), ATmega644 umí dokonce i jet na krystal + druhý krystal pro oscilátor.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

 
Misa
Anonymní





PříspěvekZaslal: 06 leden 2013, 11:43    Předmět: Citovat

pro mě jako začátečnici, je to docela složité... ale děkuji. Při dlouhých zimních večerech se na to zkusím podívat Smile
Návrat nahoru
 

 
Panda38
Profesionál
Profesionál


Založen: 18.9.2012
Příspěvky: 398
Bydliště: Praha, Most

PříspěvekZaslal: 06 leden 2013, 12:34    Předmět: Citovat

Tak to už letos nestihneš, když je už skoro jaro. Smile
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu Zobrazit autorovy WWW stránky
 

 
Balů
Profesionál
Profesionál


Založen: 29.10.2012
Příspěvky: 752

PříspěvekZaslal: 06 leden 2013, 12:54    Předmět: Citovat

Když se s časovačema a přerušením naučíš pracovat, tak Ti to ušetří do budoucna obrovské množství práce. Například právě zobrazení na multiplexovaném 7-segmentovém displeji většinou řeším právě přes časovač a přerušení. Ve vlastním programu pak jenom zapisuju hodnoty do RAM a nestarám se o to, kdy se má která část zobrazit. Když to pak zkombinuju s OCR registrem a AD převodníkem na kterém je fotoodpor, tak mám k dispozici dokonce i třeba řízení jasu těch 7-segmentovek.

Principiálně to udělám takto :

Hlavní program
kód:

Inicializace -

    Spustit AD převodník do freerunning režimu (tzn., že provádí převod pořád dokola) se zarovnáním doleva a pak číst jen horních 8 bitů - ten se použije ke snímání okolního světla a následné regulaci jasu displeje. Ve dne pak displej svítí více a je tak dobře vidět, za tmy pak displej sníží jas a nezáří do okolí jako reflektor. Používám to ve většině zařízení, kde používám LED 7-segmentové zobrazovače, podsvícení displejů, LED jako kontrolky apod.
    Do RAM nastavit "výchozí hodnoty" pro displej
    Pokud už je alespoň jeden AD převod hotový, načíst hodnotu AD převodníku
    Časovač :
              Povolit přeručení TOV a OCR
              Nastavit OCR = do OCR uložit hodnotu z AD převodníku
              Nastavit časovač = spustit časovač s takovým prescalerem, aby vycházel refresh celého displeje alespoň na 80Hz (kvůli blikání).
Příklad : MCU běží na IntRC 8 MHz, mám 4-místný 7-segmentový displej.
8000000(rychlost mcu)/256(rozlišení časovače)/4(počet míst displeje)/prescaler<80 =>
8000000(rychlost mcu)/256(rozlišení časovače)/4(počet míst displeje)/80(požadovaný refresh)>prescaler =>
8000000/256/4/80=97,65625 =>
Prescaler časovače vyberu tak, aby byl menší, než 97,65625 - tedy 64.
Refresh pak mám 8000000/256/4/64=122 Hz

Plus samozřejmě další inicializace, kterou bude vyžadovat program

    Povolit přerušení

Tady už bude hlavní smyčka programu


V hlavní smyčce programu pak jenom vypočítám, co na který pozici má být - v případě 7-segmentového displeje dělám rovnou "překlad" na hodnotu posílanou na port - a uložím na svá místa v RAM. O vlastní zobrazení se starají přerušení od časovače.

Podprogramy pro přerušení
kód:

Přerušení TOV :
    Vyberu hodnotu pro další znak
    Na port pošlu hodnotu
    Vyberu a zapnu správnou anodu/katodu
    Přečtu hodnotu z AD převodníku
    Uložím ji do OCR
    Konec

Přerušení OCR :
    Vypnu všechny anody/katody
    Konec



Pokud nebudu komplikovat situaci s AD převodníkem a řízením jasu displeje, pak z inicializace vynecháš nastavení AD převodníku, OCR a povolení přerušení pro OCR.

Podprogram pro přerušení vypadal nějak takto
kód:

Přerušení TOV :
    Vypnu všechny anody/katody
    Vyberu hodnotu pro další znak
    Na port pošlu hodnotu
    Vyberu a zapnu správnou anodu/katodu
    Konec



Ve Tvém případě pro stopky bych nastavil časovač do asynchronního režimu s krystalem 32768 Hz a přerušení by vypadalo nějak takhle :
kód:

Přerušení TOV:
    Pokud jsou spuštěny stopky, přičíst 1/128 sekundy
    konec



Vlastní program by vypadal takto :
kód:

Inicializace -
    Nastavit časovač do asynchronního režimu s prescalerem 1 - perioda pak vychází 32768(frekvence krystalu)/256(rozlišení časovače)/1(prescaler)=128 Hz (počet přerušení za sekundu)

Hlavní smyčka -
    Zpracování tlačítek a spuštění/zastavení/nulování stopek.



Na první pohled to možná vypadá složitě, ale jakmile se s přerušeníma a časovačema naučíš pracovat, tak Ti to následné ušetří spoustu práce a výrazně to zjednoduší programování. Hlavně odpadne "starost" s tím, co se volá pravidelně a co může v podstatě běžet autonomně "na pozadí" vlastního programu...

Neber to, prosím, jako nějaké vytahování se apod. Každý začátek je těžký a všichni jsme si tím prošli. Zkus to vzít jako inspiraci a náznak možností, které Ti použití časovačů, přerušení a vůbec splupráce s integrovanými periferiemi přímo v mcu přináší. Pro začátek si zkus třeba jenom blikání LEDkou pomocí přerušení, vyzkoušej si co a jak.

K multiplexovanému 7-segmentovému LED displeji : Spousta začátečníků dělá tu chybu, že při přepínání znaků přepne segmentovku a pak změní data pro segmenty nebo opačně nejdřív změní data pro segmenty a pak přepne segmentovku. Pak do segmentovky "prosvítá" znak z vedlejší číslice. Vtip je právě v tom, že musíš nejdřív segmentovku zhasnout (vypnout společnou anodu/katodu), pak změnit data pro segmenty a pak teprve segmentovku rozsvítit (zapnout společnou anodu/katodu) - prostě přepnutí společnou anody/katody udělat ve dvou krocích. Druhá varianta je zhasnout segmenty (poslat "zhasnuté" segmenty), přepnout společnou anodu/katodu a pak teprve vyslat vlastní znak.

Ale to už jsem se nějak moc rozepsal, tak držím palce a přeju spoustu objevů při bádání.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

 
Anonymní






PříspěvekZaslal: 06 leden 2013, 13:02    Předmět: Citovat

Panda38 napsal:
Tak to už letos nestihneš, když je už skoro jaro. Smile


Ti, kteří si nestihli dobastlit venkovní teploměry, mají stále ještě kalendářní zimu Wink
Návrat nahoru
 

 
Martin
ATmega pouzivatel
ATmega pouzivatel


Založen: 5.1.2008
Příspěvky: 1485

PříspěvekZaslal: 06 leden 2013, 15:02    Předmět: Citovat

To ma mrzi, ze to vyzera zlozito. Preto posielam odskusany kod obsahujuci iba tu cast s vyuzitim casovaca.

kód:

// projekt pre demonstrovanie pouzitia citaca ako casovej zakladne vsektych dejov v mcu
// ATmega8, CLK 8MHz, prekladac GCC, AVRstudio 4.18, -Os

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

#define SET(BAJT,BIT) ((BAJT) |= (1<<(BIT)))
#define TST(BAJT,BIT) ((BAJT) & (1<<(BIT)))

// parametre casovaca vytvarajuceho casovu zakladnu
// 124 = 125 - 1, do registra je potrebne nastavit hodnotu o jednu mensiu ako je skutocna hodnota.
// je to preto, lebo aj 0 je pre casovac stav cez ktory musi prejst
#define PREDVOLBA_CZ 124


int main(void)
{
   // pre generovanie casovej zakladne bude pouzity casovac 2, lebo ma mod PWM.
   // To znamena, ze vie pocitat do hodnoty nastavenej predvolby,
   // po jej dosiahnuti nastavi prislusny bit ktory sa da testovat
   // hodnota citaca sa po diosiahnuti predvolby automaticky vynuluje a pocita od zaciatku.
   // To znamena, ze cas medzi dvoma nastaveniami bitu nezavisi od casu,
   // kedy sa program v hlavnej slucke dostane k jeho vynulovaniu

   // nastavenie citaca do modu pocitania len do hodnoty v predvolbe.
   // Predvolba je v registri

   OCR2 = PREDVOLBA_CZ;
   SET(TCCR2,WGM21);

   // predvolba pre spustenie pocitadla a pre delenie vstupnej frekvencie 64.
   // to znamena, ze pocitadlo sa zmenni o jednotku 1x za 1/125000 sekundy.
   // Zdroj je frekvencia mcu (8MHz, tak som to nastavil cez fuse a uviedol v projekte)

   SET(TCCR2,CS22);

   //...  // tu si daj vsetky potrebne inicializacie

   // nekonecna slucka
   while(1) {
     // test, ci uz casovac dosiahol hodnotu v OCR2
     if (TST(TIFR,OCF2)) {
        // priznak treba rucne vynulovat, kedze sa automaticky nenuluje.
        // To robi iba v pripade pouzitia prerusenie, ale to teraz neriesime.
        // Vsimni si, ze sa bit nuluje zapisom jednicky na jeho poziciu. Je to v manuali.
        SET(TIFR,OCF2);

        // ... tu si daj kod, ktory sa ma vykonat 1x za 1ms
        
     }
   }

   // sem sa program nikdy nedostane
   return;
}


Ak by to vyzeralo stale rozsiahle, tak s vymazanymi edukacnymi komentarmi je zdrojak nasledovny:

kód:

// projekt pre demonstrovanie pouzitia citaca ako casovej zakladne vsektych dejov v mcu
// ATmega8, CLK 8MHz, prekladac GCC, AVRstudio 4.18, -Os

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

// Definice makier s parametrami
#define SET(BAJT,BIT) ((BAJT) |= (1<<(BIT)))
#define TST(BAJT,BIT) ((BAJT) & (1<<(BIT)))

#define PREDVOLBA_CZ 124

int main(void)
{
   OCR2 = PREDVOLBA_CZ;
   SET(TCCR2,WGM21);
   SET(TCCR2,CS22);

   //...  // tu si daj vsetky potrebne inicializacie

   // nekonecna slucka
   while(1) {
     if (TST(TIFR,OCF2)) {
        SET(TIFR,OCF2);

        // ... tu si daj kod, ktory sa ma vykonat 1x za 1ms
        
     }
   }
   return;
}

Dufam, ze toto uz snad nevyzera na dlhe zimne vecery. Smile

Ked si kod vlozis do AVRstudia a prelozis v simulatore, daj si break point na riadok
kód:

        SET(TIFR,OCF2);



Pri nastaveni frekvencie v simulatore na 8MHz zistis, ze sem program pride priemerne vzdy za 1000us. dalsia cinnost moze trvat lubovolny cas medzi od 0us do 990us, ale vzdy sa spusti az zaciatkom dalsej milisekundy.

za tento riadok vloz svoj kod, ale prehladnejsie je vlozit volanie funkcie v ktorej sa az bude ten kod nachadzat. To ti umozni casom vyrobit si funkcie a pouzivat ich v roznych projektoch bez potreby zasahovat do nich (teda ak su v poriadku Smile ) a tym sa vyhnut hladanim chyb sposobenych kopirovanim neuplneho alebo inak zavisleho kodu. Kazda funkcia ma byt napisana tak, aby mala jasne definovany vstup a vystup. Najlepsie, ked pracuje v maximalne moznej miere s lokalnymi premennymi a interakciu s okolim budes mat slusne popisanu.

Snaz sa na kazdu logicku cinnost pouzit zvlast funkciu. Vedie to prehladnosti, lahsie sa hladaju chyby a jednoduchsie vyuzijes kusy kodu v buducnosti.
Takze potom by to vyzeralo nejako takto.



kód:

// projekt pre demonstrovanie pouzitia citaca ako casovej zakladne vsektych dejov v mcu
// ATmega8, CLK 8MHz, prekladac GCC, AVRstudio 4.18, -Os

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

// Definice makier s parametrami
#define SET(BAJT,BIT) ((BAJT) |= (1<<(BIT)))
#define TST(BAJT,BIT) ((BAJT) & (1<<(BIT)))

#define PREDVOLBA_CZ 124


// deklaracie funkcii
   void fn_inicializuj_casovu_zakladnu(void);
   void meraj_cas(void);
   void fn_testuj_tlacitko(void);
   void fn_zobraz_dalsiu_sedemsegmentovu(void);
   void fn_inic_sedemsegment(void);
// ... tu si vloz premenne spolocne pre viac funkcii

int main(void)
{
   fn_inicializuj_casovu_zakladnu();
   fn_inic_sedemsegment();
   //...  // tu si daj vsetky potrebne inicializacie

   // nekonecna slucka
   while(1) {
      if (TST(TIFR,OCF2)) {
         SET(TIFR,OCF2);

         fn_meraj_cas();
         fn_testuj_tlacitko();
         fn_zobraz_dalsiu_sedemsegmentovu();
      }
   }


   return;
}

void fn_inicializuj_casovu_zakladnu(void)
{
      OCR2 = PREDVOLBA_CZ;
      SET(TCCR2,WGM21);
      SET(TCCR2,CS22);
      return;
}

void meraj_cas(void)
{
   //...
   return;
}

void fn_testuj_tlacitko(void)
{
   //...
   return;
}

void fn_zobraz_dalsiu_sedemsegmentovu(void)
{
   //...
   return;
}

void fn_inic_sedemsegment(void)
{
   //...
   return;
}



Este Ti chcem poradit, aby si si zvykla pouzivat #define

napriklad

kód:

//...

// definovanie pinu pre ten ktory segment v sedem segmentovke
// piny som vybral nahodne
#define SEG_A 0
#define SEG_B 5
#define SEG_C 3
#define SEG_D 2
#define SEG_E 1
#define SEG_F 4
#define SEG_G 6
#define SEG_P 7

// definovanie pinu pre ten ktory sedem segmentovky
// piny som vybral nahodne
#define CISL_1 0
#define CISL_2 2
#define CISL_3 3
#define CISL_4 1

//...


uint8_t segs[10];

//...

segs[0] = (1<<SEG_A) | (1<<SEG_B) | (1<<SEG_C) | (1<<SEG_D) | (1<<SEG_E) | (1<<SEG_F);
segs[1] = (1<<SEG_B) | (1<<SEG_C);
segs[2] = (1<<SEG_A) | (1<<SEG_B) | (1<<SEG_G) | (1<<SEG_D) | (1<<SEG_E);

// ak to potrebujes invertovane tak potom
segs[0] = ~((1<<SEG_A) | (1<<SEG_B) | (1<<SEG_C) | (1<<SEG_D) | (1<<SEG_E) | (1<<SEG_F));


Kod ma prakticky rovnaku dlzku .
Vedie to k daleko prehladnejsiemu kodu a to aj v pripade ked si pytas radu od niekoho ineho. Zaroven ak zmenis hw a segment A bude na inom pine, upravu v cislach pinov robis iba na jedinom mieste a nemoze sa stat ze ju v nejakej casti zabudnes.

P.S. Este Ta chcem upozornit, ze ak budes experimentovat s nejakymi kusmi pokusneho kodu, moze sa lahko stat, ze pri nastaveni oprimalizacie vyssej ako -O0 ti prekladac kde co vyhodi, lebo to na celkovu funkciu nema vplyv. On je mudry a rozozna to. Tak pred take pokusne premenne vloz "volatile". To je info pre neho, aby tuto premennu neoptimalizoval. Ano, optimalizovat sa da az na ultimum, t.j. dana premenna sa z programu uplne vyhodi Smile. Ale on to robi spravne. To na zaciatku moej programovacej kariery som si cas od casu namyslal, ze som v prekladaci objavil chybu. Vzdy to vsak bola chyba medzi klavesnicou a stolickou. Tak drzim palce. Smile


Naposledy upravil Martin dne 06 leden 2013, 16:03, celkově upraveno 1 krát.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

 
Panda38
Profesionál
Profesionál


Založen: 18.9.2012
Příspěvky: 398
Bydliště: Praha, Most

PříspěvekZaslal: 06 leden 2013, 15:46    Předmět: Citovat

Martine myslím že jsi tu chybu udělal znovu. Smile Tvé texty jsou moc dlouhé (přestože hodnotné a kvalitní). Lidé neumí číst rozsáhlé návody, raději mají co nejjednodušší příklad na pár řádků. Obzvláště začátečníkům by více pomohlo zkrátit Tvůj text asi tak na 1/10.

Kdyby dokázali přečíst takový delší text, to by pak četli i datasheety a nechodili by se ptát na fóra.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu Zobrazit autorovy WWW stránky
 

 
Martin
ATmega pouzivatel
ATmega pouzivatel


Založen: 5.1.2008
Příspěvky: 1485

PříspěvekZaslal: 06 leden 2013, 16:02    Předmět: Citovat

OK Smile

hlavny je ten kod v strede (spolu 25 riadkov).

kód:

// projekt pre demonstrovanie pouzitia citaca ako casovej zakladne vsektych dejov v mcu
// ATmega8, CLK 8MHz, prekladac GCC, AVRstudio 4.18, -Os

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

// Definice makier s parametrami
#define SET(BAJT,BIT) ((BAJT) |= (1<<(BIT)))
#define TST(BAJT,BIT) ((BAJT) & (1<<(BIT)))

#define PREDVOLBA_CZ 124

int main(void)
{
   OCR2 = PREDVOLBA_CZ;
   SET(TCCR2,WGM21);
   SET(TCCR2,CS22);
   while(1) {
     if (TST(TIFR,OCF2)) {
        SET(TIFR,OCF2);
        // ... tu si daj kod, ktory sa ma vykonat 1x za 1ms
     }
   }
   return;
}


Inak to uz vzdavam. Smile
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

 
Misa
Anonymní





PříspěvekZaslal: 06 leden 2013, 16:22    Předmět: Citovat

ted už je to super, mnoho si mi toho vysvětlil. I když je to dlouhé, ale zajímavé. Ale ještě se chci zeptat kolik bude předvolba, když mám oscilátor 16 MHz?
Návrat nahoru
 

 
Martin
ATmega pouzivatel
ATmega pouzivatel


Založen: 5.1.2008
Příspěvky: 1485

PříspěvekZaslal: 06 leden 2013, 16:39    Předmět: Citovat

16000000/64=250000

Ak chces nastavenie 1x za 1ms, tak predvolba musi byt 250-1=249.
Vacsie cislo ako 255 tam nevopchas, potom musis zvysit deliaci pomer zo 64 na nejaky vyssi.
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
 

 
Misa
Anonymní





PříspěvekZaslal: 06 leden 2013, 16:58    Předmět: Citovat

díky Wink
Návrat nahoru
 

Zobrazit příspěvky z předchozích:   
Zobrazit předchozí téma :: Zobrazit následující téma  
Přidat nové téma   Zaslat odpověď    Obsah fóra mcontrollers.com -> AVR Časy uváděny v GMT + 2 hodiny
Jdi na stránku 1, 2  Další
 
Strana 1 z 2
Přejdi na:  
Můžete přidat nové téma do tohoto fóra.
Můžete odpovídat na témata v tomto fóru.
Nemůžete upravovat své příspěvky v tomto fóru.
Nemůžete mazat své příspěvky v tomto fóru.
Nemůžete hlasovat v tomto fóru.
Můžete k příspěvkům připojovat soubory
Můžete stahovat a prohlížet přiložené soubory
 



Num Lock Holder - app to hold Numlock
Copyright © 2018 Rudolf Veselý, mcontrollers.com.
Je zakázáno používat části tohoto webu bez souhlasu autora. || Powered by phpBB © 2001, 2002 phpBB Group - with RedSquare DoubleJ(Jan Jaap)