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
// 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
#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 ) 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.
// ....
fn_init_cz();
fn_stopky_ini();
// ....
// 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.