void SetParms (){
DDRB |= 0x06; //((1 << LED) | (1 << Siren)); // PB0 LED a Siren as output
TIMSK0 |= (1 << OCIE0A); // Enables the interrupt on Output Compare A Match Interrupt Enable
sei(); // Sets the I-flag in the status register for interrupts
TCCR0B |= ((1 << WGM02) | (1 << CS00) | (1 << CS02)); // Set CTC Bit. Set prescale 1024
OCR0A = 1600; //Set the value 7813 to be compared with TCNT. With Fcu=8MHz and the prescale 1024, 7813 equals 1 second
//PORTB |= 0x01 << LED; //LED starts on
}
ISR(TIM0_COMPA_vect)
{
Flags |= FlTimer;
//if ((Flags & 0x01) == 1) PORTB ^= Siren;
//Flags |= FlTimer; // Ne funguji Set On bit in timer interrupt!!!
}
int main(){
SetParms();
Flags |= FlTimer;
while(1)
{
if ((Flags && FlTimer) == 1)
{
PORTB ^= LED ;
_delay_ms(100);
PORTB ^= LED ;
_delay_ms(1000);
Flags ^= FlTimer;
}
}
}
Ve smyčce Main() změním příznak
Flags |= FlTimer; program jej adekvátně změní a já mohu s tímto příznakem pracovat.
Když se však pokusím změnit tento příznak Flags |= FlTimer; v těle procedury ISR(TIM0_COMPA_vect) - nezmění se.
Analyzoval jsem část assembleru, která je výsledkem kompilace programu. Stejné paměťové místo je adresováno stejnými operacemi.
Flags |= FlTimer;
76: 41 a1 lds r20, 0x41 ; 0x800041
78: 41 60 ori r20, 0x01 ; 1
7a: 41 a9 sts 0x41, r20 ; 0x800041
Od přerušení se bit v bajtu Flags nezmění.
Setkal se někdo s takovými “zázraky”?
A co myslíš tím “chová se nestandartně” ? V programu vidím nějaké chyby, ale když píšeš, že se bits ve Flags nezmění, tak jak jsi na to přišel ? Možná je to tím, že odpočítáváš vteřinu pomocí čítače a v programu máš delaye v délce 1,1 vteřiny…
Při nastavení F_CPU na 12MHz dokonce 1,65 vteřiny a OCR0A je nastaven na cca 0,66 vteřiny…
Díky za komentář - na tomto fóru jsem poprvé. Nejsem na všechno zvyklý.
Změnil jsem program. V této variantě by měla LED dioda spínat čistě pomocí časovače. To se však nestane, protože přerušení nezmění bit v poli Flags. To je pro mě záhadou. Kdysi jsem psal programy v Bascomu. Teď jsem napsal podobný kód pro Attiny13 v Bascomu, abych si to ověřil. Na Attiny13 vše funguje. Zdá se, že Tiny10 není běžný čip - chyby jsou možné. Jak v popisech, tak v rozhraní programu.
// FalseCameraTiny10.c
// Created: 18.04.2024 15:32:47
// Author : Ondra
#define F_CPU 1000000
#include <avr/interrupt.h> //interrupts library
#include <avr/io.h> //input output library
unsigned char TimCount;
unsigned char Flags ;// process status
// 0 0 0 0 0 0 0 0
// 7 6 5 4 3 2 1 0
// | | | | | | | |
// | | | | | | | +-- FlTimer - timer handle flag
// | | | | | | +---- FlSwitch - State of channel
// | | | | | +------
// | | | | +--------
// | | | +----------
// | | +------------
// | +--------------
// +----------------
#define FlTimer 0x01
#define FlSwitch 0x02
#define LED 0x02
#define Siren 0x04
#define Sensor 0x01
void SetParms (){
DDRB |= 0x06; //((1 << LED) | (1 << Siren)); // PB0 LED a Siren as output
TIMSK0 |= (1 << OCIE0A); // Enables the interrupt on Output Compare A Match Interrupt Enable
sei(); // Sets the I-flag in the status register for interrupts
TCCR0B |= ((1 << WGM02) | (1 << CS00) | (1 << CS02)); // Set CTC Bit. Set prescale 1024
OCR0A = 1600; //Set the value 7813 to be compared with TCNT. With Fcu=8MHz and the prescale 1024, 7813 equals 1 second
//PORTB |= 0x01 << LED; //LED starts on
}
ISR(TIM0_COMPA_vect)
{
Flags |= FlTimer;
}
int main(){
SetParms();
Flags |= FlTimer;
while(1)
{ if ((Flags && FlTimer) == 1)
{
Flags ^= FlTimer;
PORTB ^= LED ;
}
}
}
Nevím, jak jsi přišel na to, že Tiny10 není běžný čip. Je to normální procesor s AVR jádrem. I přes chyby, které máš v programu se program v debuggeru AtmelStudia chová správně. V přerušení nastaví bit a na základě toho se splní (špatně napsaná) podmínka. V té podmínce neguješ ve Flags FlTimer (bit 0) a pak bit 1 portu B. Tím smažeš FlTimer bit ve Flags a rozsvítíš/zhasneš LEDku.
Špatné pořadí v nastaveních časovače :
1 - nastavuješ přerušení od časovače (TIMSK0)
2 - povoluješ přerušení jako takové (SEI)
3 - nastavuješ režim a spoustíš časovač (TCCR0B)
4 - teď teprve říkáš, kam až má časovač doběhnout a kdy tedy vyvolávat přerušení (OCR0A)
Správně bych to viděl takhle :
1 - nastavit, kam až má časovač doběhnout a kdy tedy vyvolávat přerušení (OCR0A)
2 - nastavit přerušení od časovače (TIMSK0)
3 - nastavit režim a spustit časovač (TCCR0B)
4 - povolit přerušení jako takové (SEI)
Špatně napsaná podmínka if :
((Flags && FlTimer) == 1)
Když už, tak
((Flags & FlTimer) == FlTimer)
Protože pro jiný bit by podmínka nefungovala.
Když chceš nulovat bit ve Flags, tak by asi bylo lepší napsat to takhle :
Flags &= ~(FlTimer);
Jinak program funguje správně i těmi chybami → Při prescaleru 1024, OCR = 1600 a frekvenci procesoru 1000000 je výsledný kmitočet 1000000/1024/1601 = 0,60997 Hz => 1,64 s
LEDka tedy změní stav každých cca 1,64.
Tohle tvrdí Atmel Studio i reálný HW, na kterým to tu zkouším.
Nastavení rychlosti hodin procesoru se nedělá pomocí #define F_CPU 1000000. Tím jenom říkáš překladači, s jakou rychlostí hodin má počítat, pokud použiješ delay, případně, když počítáš různé prescalery a časování pro použití v programu. Nastavit hodiny musíš podle datasheetu. Po resetu běží procesor na 1MHz.
Jinak překlopení pinu se na tomto procesoru dá udělat takto :
#define LED_bit 1
a
PINB |= (1<<LED_bit);
Zabere to jenom jednu instrukci místo 5 (při nastavení optimalizace překladače na -Os). Ale při této optimalizaci už musí být Flags deklarovaný jako volatile.
Moc Vám děkuji! (Na světě jsou chytří lidé)) Už dlouho jsem nepsal v C++ a ztratil jsem na něj cit. Zmátlo mě, že mi assembler ukázal, že paměť se zpracovává stejně v přerušení i v programu. Logicky měl program reagovat na přerušení. Jak lépe poděkovat? "&& " - Tento operátor mi zničil život na celý den. Ale teď už jde život zase dál a já jsem moc rád, že s vaší pomocí je teď všechno v pořádku))
Mám len malú otázočku.
Prečo píšeš, že programuješ v C++, keď sa jedná o čistý C kód?
Na procesory s tak malou pamäťou by som C++ s jeho fičúrami ani len neskúšal