brzdové svetlo na RC auto cez Atmega8

Zdravím Vás chcel by som si naprogramovať na atmega8 spínanie brzdových svetiel na autíčku.
Princíp by mal byť jednoduchý keď mám páku nad 50% tak auto ide do predu, keď mám páku pod 50% tak cúva resp. brzdí a svetlo sa rozsvieti. Upravil som si nejaké programy čo som našiel na internete ale nefunguje mi to a neviem prečo, pritom codevisionavr neukázalo žiadnu chybu.
Môžte mi poradiť prosím?

Upozorňujem že som úplný začiatočník v programovaní a zatiaľ som zvládol akurát tak blikanie LED.

prikladám program:

Chip type : ATmega8L
Program type : Application
Clock frequency : 16,000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 256
*****************************************************/

#include <mega8.h>
#include <delay.h>

unsigned char ServoValue;
unsigned char i;
unsigned long TickCount;
unsigned char adc_input;

#define ADC_VREF_TYPE 0x40

interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
#asm(“cli”);
TCNT0=0x83;
TickCount++; // Inkrement pocitadla milisekund
#asm(“sei”);
}

    interrupt [EXT_INT0] void ext_int0_isr(void)
            {      
            
            #define SIGNAL PORTD.2 
                    #asm("cli");         
                            if (!SIGNAL)
                                    {
                                    TCCR1B=0x03;   
                                    }
                             else
                                    {
                                    TCCR1B=0x00;
                                    ServoValue = (TCNT1L - 125) * 2;   
                                    TCNT1H=0x00;
                                    TCNT1L=0x00;
                                    }
                    #asm("sei");         
            }

#define BRZDA PORTC.0
void main(void)
{

ADMUX=adc_input|ADC_VREF_TYPE;
ADCSRA|=0x40;
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;

while (1)
{

   i=ServoValue;
   
   if (ServoValue < 50)   BRZDA = 1;  //ovládanie BRZD
    else BRZDA = 0;
       

  }

}

Mega8L nepojede na 16MHz (možný je ledasco, ale dovolené maximum je 8MHz). Ostatně na tento program bude stačit interní RC oscilátor v továrním nastavení (1MHz).
Ledka je dobrá věc a je vhodné ji do programu zakomponovat abys věděl, že mcu pracuje.
Funkce VOID main(void) nemůže nic vracet (return…). Ikdyby byla definována správně, příkazem “return” program skončí.
Jakým způsobem na modelu zjistíš nastavení polohy ovladače? Jesli je to z nějakého signálu pro servo, tak stačí změřit šířku pulzu v “1” (o což se možná snažíš). AD převodník k tomu není potřeba, leda že by sis nastavoval nějakým trimrem, kdy je oněch 50% kterým odpovídá 1.5ms.
Kódy vkládej patřičně formátované do “code”. Takhle se to blbě luští.

No vlastne som to chcel dať na 16 khz ale wizard mi to vždy doplní na Mhz - neviem jak to zmeniť.
Čo sa týka polohy ovládača som zabudol napísať, cez Y kábel chcem do atmegy získať rovnaký signál ako má servo. A áno snažím sa zmerať dĺžku pulzu aby som vedel vyhodnotiť v akej polohe je páka, ale neviem či to robím dobre a kde je chyba a podľa knižiek čo som zohnal na programovanie to nejak neviem vyriešiť.
Ten AD prevodník som odstránil a zaradil som aj kontrolnú LED ale spínanie stále nefunguje.
brzda.c (1.82 KB)

Když pominu, že to ani CV nepřeloží (přerušení nemůže přijímat parametry ani mít návratovou hodnotu), tak nejspíš ani dioda nesvítí (není nastaven příslušný DDR registr).
Mimochodem - frekvence, kterou si zadáš do wizarda, nemá nic společného s tím, na jaké frekvenci mcu skutečně běží. Pokud jsi se nevrtal ve fuses, tak pracuje na 1MHz z interního RC oscilátoru (není třeba krystal). Rozhodně nelze nastavit libovolnou frekvenci. To číslo ve wizardu je pouze informace pro překlač.
S kódem ti nepomůžu, protože nepíšu v CV nýbrž v AVRStudiu 4.19 (+ AVR Toolchain).

Kto by mi vedel poradiť literatúru aby som sa mohol naučiť princíp funkcie interrupt a časovača?

Piityy:
Tvoje snaha je chvályhodná, ale asi zbytečná.
Pochybuji, že tento začátečník ti porozumí.

Velký problém, podle mne, je v tom, že v češtině neexistuje kniha určená opravdovým začátečníkům,
která by popsala (pro začátečníky srozumitelně) mikroprocesor, jeho části, názvy, funkce jednotlivých částí atd.
Aspoň já o takové nevím.

Taky o žádný knize pro úplný žačátečníky s AVR v C nevím.

Na tohle ani přerušení nepotřebuješ. Stačí počkat na vzestupnou hranu, pak spustit timer, počkat na sestupnou a timer zastavit. Přečíst hodnotu, vynulovat, rozhodnout o diodě a repete :slight_smile:. Kdybys používal AVRStudio, tak jsem ti to už dávno napsal (viděl bych to od oka tak na 20 řádků).

Tenhle kód bude jednoduchej, to by možná CV skouslo ikdyž to pro to nebude napsaný. Jesli se nepletu, AB CV použivá, tak ti s portováním třeba píchne.[code]#include <avr/io.h>
#define F_CPU 1000000UL
#include <util/delay.h>

#define VSTUP (PIND & (1<<PD2))
#define DIODA_ON (PORTC &= ~(1<<PC0)) // dioda mezi Vcc a PC0
#define DIODA_OFF (PORTC |= (1<<PC0))

void main(void)
{
DDRC |= 1<<PC0; // PC0 = výstup

for (;;)
{
	while(!VSTUP);		// počkej než přijde 1
	TCCR0 |= 1<<CS01 | 1<<CS00;		// timer start, Tclk = F_CPU/64
	_delay_us(500);		// ignoruje nulu příchozí dříve než za 500us
	while(VSTUP);		// počkej na nulu
	TCCR0 = 0;			// timer stop
	// Při 1 MHz a děličce 64 trvá 1 tik timeru 64us.
	// Pro 1.5ms (střed serva) musí timer napočítat 23.4375 tiků.
	if(TCNT0 < 23) DIODA_ON;
	else DIODA_OFF;
	// nyní bude 18-19ms pauza než zase přijde 1
	// chvíli počkáme
	_delay_ms(10);
	// a pokračujeme na začátku cyklu
}

}[/code]

kniha shop.ben.cz/cz/121139-atmel-avr- … yce-c.aspx je myslím pro začátečníky dobrá - navíc je to vlastně do češtiny přeložený manuál a příklady CodeVisionu

Knihy su, len treba hladat :slight_smile:

pre CodeVision
Vladimir Vana: Programovani c jazyce C, BEN

a na koniec jedna z najlepsich pre GCC

Vladimir Subrt:ATMEL AVR vyvojove prostredi, BEN

takze “keine panik”.
Ci uz nieco pre C-cko napisal aj Matousek netusim, mam od neho nejake knihy zaoberajuce sa asemnlerom. Jeho znalost, nedajboze programovanie v nom osobne nepovazujem za dobru volbu. Ale o tom sa tu uz pisalo viac ako dost. :slight_smile:

P.S. Lou tasil rychlejsie :slight_smile:

lou:
martin:
Přátelé, knihy které uvádíte jsou výborné.

Ale já jsem měl na mysli úplného začátečníka,
člověka který sice zná elektroniku ale který neví co je registr, adresa, program counter atd.
Ten se v těchto knihách základy nedozví.

tady je piityyho kód pro CV - na simulátoru to funguje
frekvenci nastavíš v Configure project->C Compiler

[code]#include <mega8.h>

#include <delay.h>

#define VSTUP PIND.2//(PIND & (1<<PD2))
#define DIODA_ON PORTC.0=1//(PORTC &= ~(1<<PC0)) // dioda mezi Vcc a PC0
#define DIODA_OFF PORTC.0=0//(PORTC |= (1<<PC0))

void main(void)
{
DDRC = 1; ///<<PC0; // PC0 = výstup
ACSR=0x80;
for (;:wink:
{
while(!VSTUP); // počkej než přijde 1
TCCR0 |= 1<<CS01 | 1<<CS00; // timer start, Tclk = F_CPU/64
delay_us(500); // ignoruje nulu příchozí dříve než za 500us
while(VSTUP); // počkej na nulu
TCCR0 = 0; // timer stop
// Při 1 MHz a děličce 64 trvá 1 tik timeru 64us.
// Pro 1.5ms (střed serva) musí timer napočítat 23.4375 tiků.
if(TCNT0 < 23) DIODA_ON;
else DIODA_OFF;
// nyní bude 18-19ms pauza než zase přijde 1
// chvíli počkáme
delay_ms(10);
// a pokračujeme na začátku cyklu
}
}

[/code]

pak jedině shop.ben.cz/cz/121251-prace-s-mi … ega16.aspx - i když příklady jsou v asembleru - ale pro pochopení, co je registr, PC(program counter), timer atd… myslím dobrá

Lou: máš prohozeny definice diody :slight_smile:.

Ahojte ďakujem všetkým za rady.
Čo sa týka kníh tak Váňu som už mal ale v ňom ten základ ktorý mi chýba nieje popísaný skúsim si zohnať tú knihu čo mi poradil Lou.
Čo sa týka samotného programu tak ďakujem Piityy za vypracovanie, začal som ho včera vypracúvať ale prácu mi ešte viac uľahčil lou. Bohužial CV mi vyhadzuje chybu nedefinovaný simbol CS01 tak som celý riadok nahradil TCCR0 = 1; a už to bere.
Ale po odskúšaní programu už s riadením z RC vysielača tak ledka blika pri pohybe páčky sa intenzita takmer nemení. po vymazaní riadka delay_ms(10); začala v jednej polohe páky blikať pomalšie a v druhej polohe bliká rýchlo ale neviem ju zatiaľ donútiť svietiť resp zhasnúť. :frowning:

Páni tak nakoniec som to rozbehal. V kóde je malá chyba, chýba tam totiž vynulovanie časovača.
dovolím si pripojiť funkčný kód.
Ďakujem všetkým za spoluprácu a trpezlivosť :slight_smile:

[code]
Chip type : ATmega8L
Program type : Application
Clock frequency : 1,000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 256
*****************************************************/
#include <mega8.h>
#include <delay.h>

#define VSTUP PIND.2
#define DIODA_ON PORTC.0=1 // dioda mezi Vcc a PC0
#define DIODA_OFF PORTC.0=0

void main(void)
{
PORTC=0x00;
PORTC.1=1; //kotrola funkcie CPU

DDRC=0x3F;   ///<<PC0;               // PC0 = výstup     
ACSR=0x80; 

while (1) //nekonečná slučka
{
TCNT0=0;
while(!VSTUP); // počkej než přijde 1
TCCR0 |= 3; // timer start, Tclk = F_CPU/64
delay_us(500); // ignoruje nulu příchozí dříve než za 500us
while(VSTUP); // počkej na nulu
TCCR0 = 0; // timer stop
// Při 1 MHz a děličce 64 trvá 1 tik timeru 64us.
// Pro 1.5ms (střed serva) musí timer napočítat 23.4375 tiků.
if(TCNT0 < 23) DIODA_ON;
else DIODA_OFF;
// nyní bude 18-19ms pauza než zase přijde 1
// chvíli počkáme
// a pokračujeme na začátku cyklu

} 

}[/code]

  • opravený

“TCCR0 |= 1<<CS01 | 1<<CS00;” je nastavení bitů CS01 a CS00 do 1. To zápisem 1 do téhož registru nedocílíš. Nastavil jsi timer na práci bez děličky(CS00 = 1, viz. datasheet), tedy počítá mnohem rychleji a program nefunguje správně. Když už, tak “TCCR0 |= 3;” //(3 = 0b00000011).

“DDRC=0x3F; ///<<PC0; // PC0 = výstup” nastaví jako výstupy piny PC0 až PC5
Diodu máš mezi Vcc a pinem nebo mezi pinem a GND?
V prvním případě by byla na řádku “#define DIODA_ON PORTC.0=1 // dioda mezi Vcc a PC0” špatně jednička (a nula na následujícím řádku), ve drhém případě by nesouhlasil komentář (to už lou nepřepsal správně).

Dávej zdrojáky mezi CODE tagy.

aha ja som si myslel, že to že mi LED vypne len v minimálnej polohe je už len problém časovania… moja chyba ďakujem za opravu teraz to už spína cca presne v 50%.

Čo sa týka výstupu tak PC0 spína tranzistor (čiže druhá možnosť ), a tranzistor spína GND => pre môj prípad popis v podstate sedí :slight_smile:

Ahojte
Tak po čase sa tu opäť vraciam s prosbou o radu. Nezakladám novú tému lebo nadväzujem na predošlú tému.
Snažím sa spraviť svetlá na autíčko. Zakladám to vlastne na predošlom programe s tým že osobitný kanál mi bude zapínať a vypínať osvetlenie. Samotné spínanie fungovalo aj pomocou predošlého programu, ktorý som tu už uvádzal ako funkčný ale problém nastáva v prípade že prijímač nedostáva riadiaci signál z vysielača (prípadne keď vôbec nezapojím signálový kábel) a to v tom že svetlá sa nerozsvietia.
Preto som spínanie svetiel spravil cez prerušenie (ktoré funguje) a pomocou kontroly pretečenia sa snažím spraviť aby sa svetlá rozsvietili aj keď nemá signál.
prikladám kód:

[code]
#include <mega8.h>
#include <delay.h>

unsigned char Servo;
unsigned char off;

#define LED1 PORTC.5 // LED na porte C5 a C4
#define LED2 PORTC.4
#define SWITCH off //spínanie funkcií na SWITCH podľa hodnoty off

interrupt [EXT_INT0] void ext_int0_isr(void) // Externé prerušenie 0
{

#define SIGNAL  PIND.2        //riadiaci signál z prijímača - vstup     

#asm("cli");     //zakázať prerušenie

if (!SIGNAL)
{
TCNT0=0; //vynulovanie časovača 0
}
else
{

    Servo = (TCNT0); //servo = hodnota časovača 
    
 }

#asm(“sei”); //povoliť prerušenie

}

interrupt [TIM0_OVF] void timer0_ovf_isr(void) // Pretečenie časovača 0
{
off=1; //keď pretečie zapne na SWITCH funkciu 1
}

void main(void)
{

PORTC=0x00;     //PC0 az PC5 = výstup     //PC6 = vstup
DDRC=0x3F;
      
TCCR0 |= 3;     //spustenie časovača 0
TIMSK |= 0x01;  //povolenie prerušenia 

GICR|=0xC0;     // External Interrupt(s) initialization
MCUCR=0x05;     // INT0: On  // INT0 Mode: Any change   // INT1: On   // INT1 Mode: Any change
GIFR=0xC0;

ACSR=0x80;      // Analog Comparator initialization
SFIOR=0x00;

#asm(“sei”)

//test HW
LED1 =1; //LED ON
LED2 =1;

delay_ms(100);
LED1 =0; //LED OFF
LED2 =0;

//koniec testu

while (1) // nekonečná slučka
{
switch (SWITCH) // voľba či má prijímač signál alebo nie
{
case 0: // prijímač signál má
LED2 = 0; //LED2 OFF

            if (Servo > 190)  
            {
            LED1=1;   //LED1 ON
            }
            else  
            {
            LED1=0;   //LED1 OFF
            } 
            break; 
            
            case 1:  // prijímač signál nemá (spustenie pretečenia)
            LED2 =1;  //LED2 ON
            
            break; 
           }
 }  

}[/code]

Problém je, že signál pretečenie vždy. Čiže zvyšok programu aj keď je funkčný tak nefunguje správne.
Viete mi poradiť, kde mám chybu prípadne čo v tom pretečení musím doplniť aby mi to fungovalo?
Prípadne iné riešenie ako by sa dala ošetriť kontrola vstupného signálu?

  1. V obsluze přerušení nezakazujeme přerušení (#asm(“cli”)), to dělá mproc automaticky.

  2. Proměnné, které používáme v hlavním programu i v přerušení musí být deklarovány jako “volatile” (volatile unsigned char off;).

  3. Povolit přerušení a nenapsat k němu obsluhu se nesmí (INT1).

  4. V přerušení INT0 měříš dobu úrovně 0, ale impulsy pro servo jsou běžně kladné. Takže měříš dobu mezery, ne impulsu.

atd.

Edit:
K bodu 2. - V CodeVision to funguje i bez “volatile”, ale je lépe zvyknout si tento kvalifikátor používat.

Vďaka za pripomienky, teraz sa k nim vyjadrím. (som začiatočník tak ak sa mýlim, prosím o strpenie a o opravu.)
K bodu 1 a 2. videl som že to takto používajú aj iný tak som to používal aj ja ale poučím sa a už to budem používať správne.
k bodu 3. - INT1 som povolil lebo som ho mal v pláne použiť pri rozširovaní funkcií ale po tvojom upozornení som si ho zakázal ale zmena nenastala.

k bodu 4. - nemerám dobu úrovne 0 ale hocijakú logickú zmenu a keďže kladná zmena sa vojde do rozsahu 0-256 a nulová úroveň sa do tohto rozsahu nezmestí tak vlastne merám len kladný impulz. Ale ak sa mýlim alebo vieš ako to spraviť presnejšie veľmi rád si nechám poradiť, lebo je mi jasné že tento spôsob je síce funkčný ale nekorektný.
Skúšal som to aj inak aleto toto je jediné čo mi ako tak fungovalo. :frowning:
Poprosím keby ste mi napísali aj ďalšie pripomienky, najlepšie aj s iným možným riešením.
Vopred ďakujem.

PS: asi som zabudol udať frekvenciu, ktorú používam je 8MHz