Attiny10 C++

Dobrý den, nechápu, proč program v C++ nefunguje standardním způsobem. (Windows 7, Atmel Studio 7, Avrdude - Usbasp).

/*

  • FalseCameraTiny10.c
  • Created: 18.04.2024 15:32:47
  • Author : Ondra
    */
    #define F_CPU 12000000
    #include <avr/interrupt.h> //interrupts library
    #include <avr/io.h> //input output library
    #include <util/delay.h>

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;
//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”?

Další, co neumí dát CELÝ KÓD do <code>, </code> … :exploding_head:

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.

  1. Š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)

  1. Š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))

  62:	41 a1       	lds	r20, 0x41	; 0x800041 <Flags>
  64:	41 60       	ori	r20, 0x01	; 1
  66:	41 a9       	sts	0x41, r20	; 0x800041 <Flags>

Nejlépe mi poděkuješ, když se něco naučíš a bude Ti program fungovat. :+1: :grinning:

I tak vám velmi děkuji.:+1::slightly_smiling_face: