Zdravím, mám tu něco, s čím si nevím rady. V přerušení od časovače (TOVF2) mám úsek programu, co mi bliká LEDkami. Ten úsek programu funguje naprosto bezchybně. POdívejte se do zdrojáku na “mode no 2”. Tam je test blikání těch “blinkrů”. Tam to bez potíží funguje. Ovšem v “mode no. 6” mi to blikat za žádnou cenu nechce. Nepřišel jsem na to, proč. Nechápu to. Dík za vysvětlení/radu.
Druhý můj dotaz se týká tohoto: Co mám napsat v C, aby mi překladač vložil instrukci “nop” ? Třeba potřebuji pozdržet impulz na pinu jen pár desítek nanosekund, a dávat tam kvůli tomu celý “delay…()” se mi nezdá ani trochu vhodné. Nyní tam mám ty “_delay_us(1)”. Raději bych tam viděl cca 3x NOP instrukci. Ale jak donutit překladač?
Zde je zdroják. Pro zvědavce doplním, že je to rozpracovaný software pro moje první robotické vozítko (ehm, pokus o něj).
[code]//************************************************************
//* ROBOT SWARE
//*
//*
//*
//*
//************************************************************
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16000000U
#include <util/delay.h>
//inicializace promennych
char mode; //rezim prace
char light; //aktualni stav svetel
// bit 0 - dalkove
// bit 1, 2 - blinkry
// bit 3 - brzdovky
char blinkr; //bit 0(1) spousti blikani leveho(praveho) bl.
char blincnt; //casovac blinkru (promena softwarove delicky freqence preruseni)
//************************** INTERRUPT **************************
ISR(TIMER2_OVF_vect)
{
//Preruseni 62.5Hz
blincnt++;
if (blincnt == 8) //62.5Hz / 8 = 7.8Hz
{
blincnt = 0; //vynuluj sw delici promennou
light = light ^ (blinkr << 1); //tohle neguje bity podle promenne blinkr
light = light & ((blinkr << 1) | 0b11111001); //zhasnuti blinkru, pokud bylo ukoncene blikani pri rozsvicenem. Proste vymaskovani nulou.
svetla(light);
}
}
//**************************** MAIN ******************************
int main ()
{
//----------- inicializace i/o portu --------------
DDRD = 0xFF;
DDRB = 0b00111111;
DDRC = 0x00;
PORTD = 0x00;
PORTB = 0x00;
PORTC = 0x00;
//----------- inicializace latch registru ------------
light = 0; //zadna svetla nesviti
svetla(light); //odesleme to na latch register
displej(255); //odeslani na jiny latch ktery budi displej
//----------- inicializace timeru, INT, PWM, ---------------
//Nastaveni timeru1:
//Fast PWM mode, prescaler 256, 8bit resolution.
//OCR1A/OCR1B pins active, non-inverting mode
//(0 - zero duty cycle, 255 - max duty cycle)
TCCR1A = (1<<COM1A1)|(1<<COM1B1)|(1<<WGM10);
TCCR1B = (1<<WGM12)|(1<<CS12);
OCR1A = 0;
OCR1B = 0;
//Nastaveni timeru2:
//Prescaler 1024, Fast PWM mode, non-inverting. OVF INT enabled
TCCR2 = (1<<WGM21)|(1<<WGM20)|(1<<COM21)|(1<<CS22)|(1<<CS21)|(1<<CS20);
OCR2 = 22;
blincnt = 0; //vynulovani sw delicky frekvence
//Povoleni preruseni
TIMSK = (1<<TOIE2); //povoleni TCCR2 OVF INT
sei();
//----------------- test veskereho HW -----------------
LED_R_on(); //rozsvitime cervenou LED
LED_Y_on(); //zlutou LED
svetla(0b1111); //Rozsvitime vsechna svetla
displej(0b10000000); //cely displej
_delay_ms(50);
svetla(0); //vsecko pozhasiname
displej(128);
LED_R_off();
LED_Y_off();
//----------------- vyberove menu --------------------
while (1) //zacatek hlavni programove smycky
{
mode = 0; //vychozi mod je c. 0
preved_na_dis(); //aktualni “mode” se zobrazi na displeji, !!nic víc!!!
do { //smycka vyberu podprogramu
if ((PINC & 0b00100000) == 0) //jeli stisknuto tlacitko NEXT, zvys mode o 1
{
mode++;
if (mode == 8) mode = 0;
preved_na_dis(); //mod o 1 vyssi zas zobraz na displej
_delay_ms(200);
}
} while ((PINC & 0b00010000) != 0); //stisknuto OK, delej patricny (pod)program
_delay_ms(200);
switch (mode) //podle aktualne zvoleneho "mode" delej:
{
case 0: //podprogram 0- Mereni napeti baterie
break;
case 1: //podprogram 1- Sviceni svetel
light = light ^ 0b00000001; //neguje stav dalkovych svetel
svetla(light); //posle ven na latch
break;
case 2: //podprogram 2- Test ostatnich svetel
blinkr = 0b00000001; //rozblikame levy blinkr
displej(0b01000111); //na displej zobrazime "L"
while ((PINC & 0b00010000) != 0) ; //pockame na stisk OK
blinkr = 0b00000010; //rozblikame pravy blinkr
displej(0b00001100); //na displej "P"
_delay_ms(200);
while ((PINC & 0b00010000) != 0) ; //cekame na OK
blinkr = 0; //vypneme blinkry
light |= 0b00001000; //rozsvitime brzdova svetla
svetla(light); //odesleme na latch ovladajici budice LED
displej(0b00000011); //na displej zobrazime "b"
_delay_ms(200);
while ((PINC & 0b00010000) != 0) ; //cekame na OK
light &= 0b11110111; //Zhasneme brzdovky
svetla(light); //odesleme na latch
_delay_ms(200);
break;
case 3: //podprogram 3- rucni ovladani PWM motoru
while (1) //slozite na komentovani :-/ Tlacitky je mozne menit otacky pohonneho motru, vcetne reverzace
{
if ((PINC & 0b00100000) == 0) //up
{
if (OCR1A > 0) OCR1A -= 10;
else if (OCR1B < 250) OCR1B += 10;
test_smeru();
_delay_ms(200);
}
if ((PINC & 0b00010000) == 0) //down
{
if (OCR1B >= 10) OCR1B -= 10;
else if (OCR1A < 250) OCR1A += 10;
test_smeru();
_delay_ms(200);
}
}
break;
case 4: //podprogram 4 rozjede robota pár metrů vpřed, a pak zas zpět.
_delay_ms(1000);
OCR1B = 64;
_delay_ms(500);
OCR1B = 128;
_delay_ms(500);
OCR1B = 255;
_delay_ms(2000);
OCR1B = 0;
_delay_ms(2000);
OCR1A = 64;
_delay_ms(500);
OCR1A = 129;
_delay_ms(500);
OCR1A = 255;
_delay_ms(2000);
OCR1A = 0;
break;
case 5: //podprogram 5 otestuje servo - otoceni vpravo, vlevo, stred
LED_Y_on();
OCR2 = 5;
_delay_ms(2000);
OCR2 = 30;
_delay_ms(2000);
OCR2 = 22;
LED_Y_off();
break;
case 6: //podprogram 6 - Jizda do "zakruty S"
displej(0b01100001); //na displej zobrazime "J"
_delay_ms(500);
LED_Y_on();
light |= 0b00001001; //rozsvitime brzdovky, predni svetla
svetla(light);
OCR1B = 64; //rozjedeme vpred
_delay_ms(1000);
OCR2 = 16; //servo vlevo
blinkr = 1; //zapni blikr vlevo
_delay_ms(1000);
OCR2 = 22; //servo stred
blinkr = 0; //vypni blinkry
OCR1B = 128; //pridej rychlost
_delay_ms(1000);
OCR1B = 64; //sniz rychlost
_delay_ms(500);
OCR2 = 27; //servo vpravo
blinkr = 2; //blinkr vpravo
_delay_ms(1000);
OCR2 = 22; //servo stred
blinkr = 0; //vypni blinkr
OCR1B = 128; //rychle vpred
_delay_ms(1000);
OCR1B = 0; //zastavit stat!
_delay_ms(1000);
light &= 0b11110110; //Bliknuti prednimi svetly (zhasnout)
svetla(light); //na latch
_delay_ms(200);
light |= 0b00001001; //rozsvitit
svetla(light); //na latch
_delay_ms(200);
light &= 0b11110110; //zhasnout
svetla(light); //na latch
LED_Y_off(); //zhasnout LED
break;
case 7: // Nedokoncene jezdeni do ctverce, zatim nefunkcni
displej(0b01100001);
_delay_ms(500);
LED_Y_on();
light |= 0b00001001;
svetla(light);
OCR1B = 64;
_delay_ms(1000);
OCR2 = 16;
_delay_ms(1000);
OCR2 = 22;
_delay_ms(1000);
OCR2 = 16;
_delay_ms(1000);
OCR2 = 22;
_delay_ms(1000);
OCR2 = 16;
_delay_ms(1000);
OCR2 = 22;
_delay_ms(1000);
OCR2 = 16;
_delay_ms(1000);
OCR2 = 22;
_delay_ms(1000);
light &= 0b11110110; //bliknuti prednimi na zaver
svetla(light);
_delay_ms(200);
light |= 0b00001001;
svetla(light);
_delay_ms(200);
light &= 0b11110110;
svetla(light);
LED_Y_off();
break;
} //konec switch-e
} //Zpet nazacatek menu
while (1) ; //pro jistotu
}
// ************************* FCE ****************************
//prace s HW:
void svetla(char d) //odeslani na latch svetel
{
PORTD = d;
PORTB |= (1<< PB0);
_delay_us(1); //taj chci ten NOP!
PORTB &= ~(1<< PB0);
_delay_us(1);
}
void displej(char d) //odeslani na displej
{
PORTD = d;
PORTD |= 0b10000000; //nastavit bit 7
_delay_us(1);
PORTD &= 0b01111111; //vynulovat bit 7
_delay_us(1);
}
void LED_R_on() //rozsvitime LED
{
PORTB |= (1<<PB5);
}
void LED_R_off() //zhasneme LED
{
PORTB &= ~(1<<PB5);
}
void LED_Y_on()//rozsvitime LED
{
PORTB |= (1<<PB4);
}
void LED_Y_off() //zhasneme LED
{
PORTB &= ~(1<<PB4);
}
//Prace s vyberovym menu …
void preved_na_dis(void) // obsah cisla promenne mode prevede na cislo na displej
{
char x;
switch (mode)
{
case 0:
x = 0b01000000; //0
break;
case 1:
x = 0b01111001; //1
break;
case 2:
x = 0b00100100; //2
break;
case 3:
x = 0b00110000; //3
break;
case 4:
x = 0b00011001; //4
break;
case 5:
x = 0b00010010; //5
break;
case 6:
x = 0b00000010; //6
break;
case 7:
x = 0b01111000; //7
break;
}
displej(x); //na latch displeje
}
//Pomocne fce …
void test_smeru() //pomocna funkce podprogramu 3
//Podle toho, jestli se motor toci vpred/vzad/stoji zobrazuje paznaky na displej
{
if ((OCR1A | OCR1B) == 0) displej(0b00111111); // “-”
else if (OCR1A > 0) displej(0b01100011); “u”
else if (OCR1B > 0) displej(0b01011100); “n”
}
[/code]
Všem moc dík za veškerou pomoc!
EDIT: doplneny komentare do zdrojaku, vymyzany davno nefunkcni a nepouzivane FCE.