Atmega8 - nezávislá sekvence pípání
Moderátor: Moderátoři
Atmega8 - nezávislá sekvence pípání
Zkoušel jsem vytvořit funkci a tu poté volat v přetečení časovače s podmínkou stisknuteho tlačítka, bohužel během doby kdy bylo tlačítko zmacknuto tak hlavní smyčka byla ve stopu, dále jsem zkusil vytvořit sekvenci pipani přímo v přerušení od časovače a pomocí externího přerušení zapnout časovač a tím i pipani, ale nepodařilo se mi časovač ukončit a když jo tak v nejistém stavu (log výstup 1 nebo 0).
Jinak sekvenci pipani mám na mysli cyklus:
Zapni
Počkej 100ms
Vypni
Počkej 100ms
Výstup je přes tranzistor na 12v sirénku.
A musí být vyvolaná okamžitě a zároveň okamžitě ukončena (nejpozději do cca 50ms od stisknutí nebo puštění tlačítka).
Nemohl by mě někdo nakopnout jak to zrealizovat?
Ale jak jsem psal, tlačítka a výstupy musí být v provozu, pokud bude v činosti zvuková sekvence a ta bude v provozu jen tehdy, pokud bude zmáčknuto tlačítko.
Jinak těch 50ms je maximum, které se dá tolerovat, samozřejmě čím rychleji to bude tím lépe.
Je třeba určit, které události a stavy jsou důležité. Ve vašem případě na první pohled vidím události:
- stisk tlačítka
- uvolnění tlačítka
- vypršení časovače 100 ms
a stavy:
- pípnutí zapnuto
- pípnutí vypnuto
V hlavní smyčce je nutno detekovat uvedené události a správně reagovat. Například:
- stisk tlačítka -> pípání se zapne, stav se nastaví do "pípání zapnuto", odstartuje se časovač 100 ms a poznačí se stav tlačítka
- časovač 100 ms vypršel -> je-li stav "pípání zapnuto", pak jej vypni, jinak jej zapni. Poznač nový stav a restartuj časovač.
- tlačítko uvolněno -> vypnout pípání, zastavit časovač, poznačit stav tlačítka
V ideálním případě je třeba vyřešit všechny kombinace možných událostí a možných stavů. Některé kombinace nebudou mít smysl - pak se nic nedělá, některé kombinace jsou chybové a značí chybu v naprogramování, například kdyby se zjistila událost vypršení časovače při uvolněném tlačítku, protože při jeho uvolnění časovač zastavujeme.
Základní zásadou je odstranit veškeré čekací smyčky vyjma těch mikrosekundových, které se používají třeba při řízení LCD. Čekací smyčky jsou povolené jen v inicializační fázi programu, ale po odstartování hlavní smyčky, která detekuje události, už se nesmí používat.
Kód: Vybrat vše
/*
* Relay_power_system.c
*
* Created: 07.01.2016 11:13:24
* Author: Patrik
*/
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
#define F_CPU 1000000
#define rel1 1 //+5V
#define rel2 2 //+12V
#define rel3 4 //zdroj A
#define rel4 8 //zdroj B
#define rel5 16 //A+B
#define BUZZ 32 //piezo
volatile unsigned int rezim=0;
volatile unsigned int i;
volatile unsigned int tl; //promněnná tlačítko
ISR (TIMER0_OVF_vect) //přerušení od časovače každou 1ms
{
TCNT0 = 131; //začátek počítání
i++;
if (tl==1 && i==100) //pokud bylo tlačítko stisknuto a uběhlo 100ms
{
PORTC ^= (BUZZ);
i=0;
}
if (tl==0 || tl==2) //pokud je tlačítko puštěno, nebo ješte nebylo stiknuto
{
tl=0;
i=0;
PORTC &= ~ (BUZZ); //vypni sirenu
TIMSK &= ~(1 << TOIE0); //zakaž povolení pro časovač
}
}
ISR (INT0_vect) //externí přerušení od INT0
{
if (tl==0)
{
tl++;
TIMSK |= (1 << TOIE0); //povol časovač
}
else
{
tl=0;
}
}
void test (void)
{
PORTC |= rel1; // zapni relé 1
_delay_ms(500);
PORTC |= rel2; // zapni relé 2
_delay_ms(500);
PORTC |= rel3; // zapni relé 3
_delay_ms(500);
PORTC |= rel4; // zapni relé 4
_delay_ms(500);
PORTC |= rel5; // zapni relé 5
_delay_ms(500);
PORTC &= ~ ((rel1) | (rel2) | (rel3) | (rel4) | (rel5)); // vypni relé 1 až 5
_delay_ms(500);
int main(void)
{
DDRC |= (1 << PC0) | (1 << PC1) | (1 << PC2) | (1 << PC3) | (1 << PC4) | (1 << PC5); //Piny PC0 až PC5 jako výstupní (log 1)
DDRD &= ~(1 << PD2) | (1 << PD3); //piny PD0 až PD4 jako vstupní (log 0)
DDRB &= ~(1 << PB4) | (1 << PB5); //PB jako vstupní (log 0)
PORTD |= (1 << PD2) | (1 << PD3); //pull-up na PD2,3 jako vstupní (log 1)
PORTB |= (1 << PB4) | (1 << PB5); //pull-up na PB5 jako vstupní (log 1)
GICR |= (1 << INT0); // povolení od přerušení od INT0
MCUCR |= (1 << ISC00) ;
TCCR0 |= (1 << CS01); // preddelicka /8
//TIMSK |= (1 << TOIE0); // přerušení po přetečení TCNT0
TIMSK &= ~(1 << TOIE0); //zakazani přerušení
sei(); //povol globální přerušení
while(1)
{
test();
}
}
V ISR pak počítáš přerušení a testuješ tlačítko. Pokud je sepnuté,
tak při každém desátém přerušení invertuješ výstup.
Edit:
Kód: Vybrat vše
DDRD &= ~(1 << PD2) | (1 << PD3);Správné je
Kód: Vybrat vše
DDRD &= ~((1 << PD2) | (1 << PD3));Kód: Vybrat vše
ISR (TIMER0_OVF_vect) //přerušení od časovače každou 1ms
{
TCNT0 = 131; //začátek počítání
i++;
if (bit_is_clear(PIND,2)) //pokud bylo tlačítko stisknuto
{
if (i==100) //uběhlo 100ms
{
PORTC ^= (BUZZ);
i=0;
}
}
else
{
PORTC &= ~ (BUZZ);
}
if (i==101)
{
PORTC &= ~ (BUZZ);
i=0;
}
}
Kód: Vybrat vše
ISR (TIMER0_OVF_vect)
{
tictac++;
}
loop()
{
//
time = tictac;
time_ip = ~time & time_hf; // zde jsou jehlove impulsy
time_hf = time; // pomocna promenna
if (bit_is_set(time_ip,0))
{
// tato akce se provede jednou za 1ms
}
if (bit_is_set(time_ip,1))
{
// tato akce se provede jednou za 2ms
}
if (bit_is_set(time_ip,2))
{
// tato akce se provede jednou za 4ms
}
}
V takto jednoduchém případě to jde, ale pokud by bylo více událostí, které je třeba zpracovat, bude potřeba zvolit obecnější přístup, který jsem popsal výše. To znamená například v přerušení od časovače jen vygenerovat událost a časovač restartovat. V přerušovací rutině se ze zásady má vykonat jen to nejnutnější a složitější zpracování dělat v hlavní smyčce, protože přerušovací rutina má defaultně zamaskované přerušení. Povolování přerušení v přerušovací rutině je obecně choulostivé a je třeba dávat dobrý pozor na integritu dat.Nikeed12 píše:Tak jsem tedy uplně vynechal externí přerušení a vše obsluhuji jen v přerušení časovače ...[/code]