Pomoc s programem
Moderátor: Moderátoři
Pomoc s programem
potřeboval bych malou pomoc. Chci sestavit jednoduché zařízení s attiny13. Vše bude naprosto jednoduché. 2 vstupní piny a 2 výstupní. Na signál 1 vstupu který bude impulz o délce cca 200 až 350 ms se sepne výstup. Ale potřebuji aby ten výstup byl seplý určitý čas. (to si vše napíšu, neměl by být problém) Potřebuji ale ten čas změřit. Na zařízení bude jumper kterým se uvede do režimu set, pokud bude v tomto režimu a objeví se mi na některém definovaném vstupu log 1 tak tento čas potřebuji změřit a uložit do nějaké proměné. Tento čas z proměné, chci pak používat.
Napadá vás funkce kterou změřím ten čas (délku sepnutí pinu při režimu set) a můžu ho pak používat pro držení sepnutí výstupů.
Kód: Vybrat vše
https://www.arduino.cc/reference/en/language/functions/advanced-io/pulsein/Zkusím si tedy asi pohrát s tím časovačem a uvidím, jestli to půjde.
na pb3 a 4 jsou vstupy . PB0 a 1 jsou výstupy. Pb2 je pro set, nastavení času délky pulzu.
Ještě jednou popis činnosti. Na vstup pb3,nebo 4 přijde pulz cca 200-350ms na výstupu pb0 nebo 1 se musí objevit log 1 v délce cca 5-15s - tuto délku potřebuji nastavit v režimu set kdy bude log 1 respektive 0 vstup bude uzemňován vstup pb2. Délku vstupu pb2 potřebuji změřit a tuto délku pulzu pak používat pro výstup pb 0 a 1.
přečti si tohle
http://www.tajned.cz/2017/01/citaccasovac-0-nejen-na-attiny-1-dil/
Články na tomto portálů znám snad již nazpaměť. S časovačem jsem si dělal i pwm pro řízení motoru s pomocí adc atd.. ale toho jak to nastavit aby to udělalo jen 1 pulz o určité délce kterou tam nastavím v režimu set nevím.
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
int main(void)
{
DDRB &= ~ (1<<PB2); // vstup set času
DDRB &= ~ (1<<PB3); //vstup pravý blinkr
DDRB &= ~ (1<<PB4); //vstup levý blinkr
PORTB |= (1<<PB2)|(1<<PB3)|(1<<PB4); //zapnutí pull up rezistorů
DDRB |= (1<<PB0); // výstup levý blinkr
DDRB |= (1<<PB1); //výstup pravý blinkr
char set_cas;
char blinkr_levy;
char blinkr_pravy;
set_cas = 0;
blinkr_levy = 0;
blinkr_pravy = 0;
while (1)
{
if (!(PINB & (1<<PB2)) && !set_cas)
{
_delay_ms(50);
if (!(PINB & (1<<PB2)))
{
PORTB |= (1<<PB0);
set_cas = 1;
}
}
if ((PINB & (1<<PB2)) && set_cas)
{
_delay_ms(50);
if (PINB & (1<<PB2))
{
PORTB &= ~ (1<<PB0);
set_cas = 0;
}
}
}
}
Trochu mě to příde jako blinkr zkřířený s nastaitelným cyklovačem stěračů.
Ten čas má být 5-15s takže trochu moc na to aby se to dalo jednoduše generovat časovašem v CTC módu, jak se ho asi snažil nasměrovat FHonza.
Spouštět to chce pulzem délky 200 až 350 ms, není to sice zmíněno, ale předpokládám, že chce detekovat hranu, tak by se mohl udělat i jednoduchý debouncing.
Já bych nastavil jen přerušení na přetečení časovače (cca na 50ms). V obsluze detekoval stav vstupních pinů a generoval výstupní pulz. Předpokládám že nepřesnost ±50ms by nemusela v tomto případě vadit.
https://blog.podkalicki.com/attiny13-blinky-with-timer-ovf-overflow/
https://ww1.microchip.com/downloads/en/devicedoc/doc2535.pdf
Kód: Vybrat vše
#include <avr/io.h>
#include <avr/interrupt.h>
#define BULHAR_CONST 10
volatile unsigned int set_cas, set_cas_docas;
volatile unsigned int blinkr_levy, blinkr_pravy;
// obsluha preruseni
ISR(TIM0_OVF_vect)
{
// test vstupu set
if (!(PINB & (1<<PB2))) {
set_cas_docas++;
} else {
if (set_cas_docas > BULHAR_CONST) {
set_cas = set_cas_docas;
}
set_cas_docas = 0;
}
// set_cas neni dostatecne velky
if (set_cas < BULHAR_CONST) {
return;
}
// test vstupu pravy blinkr (pokud je logika negativni jako u set)
if (!(PINB & (1<<PB3))) {
if (blinkr_pravy++ > BULHAR_CONST) {
blinkr_pravy = set_cas;
}
} else {
if (blinkr_pravy > 0) {
blinkr_pravy--;
if (blinkr_pravy > BULHAR_CONST) {
PORTB |= (1<<PB1);
}
} else {
PORTB &= ~(1<<PB1);
}
}
// test vstupu levy blinkr (pokud je logika negativni jako u set)
if (!(PINB & (1<<PB4))) {
if (blinkr_levy++ > BULHAR_CONST) {
blinkr_levy = set_cas;
}
} else {
if (blinkr_levy > 0) {
blinkr_levy--;
if (blinkr_levy > BULHAR_CONST) {
PORTB |= (1<<PB0);
}
} else {
PORTB &= ~(1<<PB0);
}
}
}
int main(void)
{
DDRB &= ~(1<<PB2); // vstup set času
DDRB &= ~(1<<PB3); // vstup pravý blinkr
DDRB &= ~(1<<PB4); // vstup levý blinkr
PORTB |= (1<<PB2)|(1<<PB3)|(1<<PB4); //zapnutí pull up rezistorů
DDRB |= (1<<PB0); // výstup levý blinkr
DDRB |= (1<<PB1); // výstup pravý blinkr
// nastaveni preddelicky na 1024 (CLK=fosc/1024/256 = [Hz], 1 / CLK = [s])
TCCR0B |= _BV(CS02)|_BV(CS00);
// zapni preruseni: Timer Overflow interrupt
TIMSK0 |= _BV(TOIE0);
// nastaveni globalnich promenych
set_cas_docas = 0;
set_cas = 0;
blinkr_levy = 0;
blinkr_pravy = 0;
// globalni povoleni preruseni
sei();
while (1);
}
V první řadě moc děkuji ! Když na to koukám mám se ještě hodně co učit.
Vyzkoušel jsem jak to funguje.
Šlo by udělat aby pro nastavení toho času bylo potřeba negovat dva vstupy, jak pb2 tak pb4 Aby to začalo počítat až když budou oba negovaný.
Pak jestli by bylo možné funkci spustit ihned jak je vstup buď pb4, nebo pb3 negován. Teď to jde až když to jakoby vypnu, když je vstup stále uzeměn, tak se nic neděje a až když naběhne zpět do log. 1 se aktivuje výstup.
Je možné docílit toho aby hodnota která se nastaví byla uložené aby si jí to pamatovalo i při odpojení napájení ?
Kód: Vybrat vše
// test vstupu set
if (!(PINB & ((1<<PB2) | (1<<PB4)))) {
set_cas_docas++;
Bod č. 2 není přesně specifikovaný. Není uvedeno, co se má stát v případě, že vstup PB3 nebo PB4 zůstane přizeměný déle než je nastavený interval.
Můžeš zkusit tuto úpravu. Za to, že to bude podle tvých nejtajnějších přání neručím.
Kód: Vybrat vše
volatile unsigned int set_cas, set_cas_docas;
volatile unsigned int blinkr_levy, blinkr_pravy;
volatile char blinkr_levy_spusten, blinkr_pravy_spusten;
.......................
Kód: Vybrat vše
// test vstupu pravy blinkr (pokud je logika negativni jako u set)
if (!(PINB & (1<<PB3))) {
if (!blinkr_pravy_spusten) {
if (blinkr_pravy++ > BULHAR_CONST) {
blinkr_pravy = set_cas;
blinkr_pravy_spusten = 1;
PORTB |= (1<<PB1);
}
}
} else if (!blinkr_pravy) {
blinkr_pravy_spusten = 0;
}
if (blinkr_pravy > 0 && blinkr_pravy_spusten) {
blinkr_pravy--;
} else {
PORTB &= ~(1<<PB1);
}
Levý blinkr stejným způsobem.
Bod č. 3 vyžaduje EEPROM, attiny13 ho podle katalogu má, tak by to mělo jít.
Na eeprom jsem přišel, zápis funguje dobře dle čtení hodnot z eeprom programátorem, ale nejde mi přečtení hodnot. Nevídíte tam někde problém ? Ten proces by měl být správně, ale ani když napíšu hodnotu do eeprom ručně tak nic, prostě jí to nenačte z eeprom.
Kód: Vybrat vše
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#define BULHAR_CONST 5
volatile unsigned int set_cas, set_cas_docas, eeprom_cas;
volatile unsigned int blinkr_levy, blinkr_pravy;
volatile char blinkr_levy_spusten, blinkr_pravy_spusten;
// podprogram pro cteni dat z EEPROM
unsigned char eeprom_read (unsigned char adress)
{
while (EECR & 0b00000010); // cekani na dokonceni predchozi operace (nez bit EEPE v registru EECR padne do '0')
EEARL = adress; // do registru EEARL ulozit adresu (0 az 63)
EECR = 0b00000001; // bit EERE (Read Enable) nastavit na '1'
return EEDR;
} // v registru EEDR se nachazi obsah pametove bunky ze zadane adresy
// podprogram pro zapis dat do EEPROM
void eeprom_write(unsigned char adress,unsigned char data)
{
while (EECR & 0b00000010); // cekani na dokonceni predchozi operace (nez bit EEPE v registru EECR padne do '0')
EECR = 0b00000000; // nastavit rezim zapisu na 'atomic' (smazat a zapsat)
EEARL = adress; // do registru EEARL ulozit adresu (0 az 63)
EEDR = data; // do registru EEDR ulozit jednobajtovou hodnotu
EECR = 0b00000100; // bit EEMPE (Master Program Enable) nastavit do '1' (povoleni zapisu)
EECR |= 0b00000010; // k tomu jeste bit EEPE nastavit do '1' - tim zacne zapis.
// (je treba ty dva bity EEMPE a EEPE nastavovat postupne)
}
ISR(TIM0_OVF_vect) // obsluha preruseni
{
if (!(PINB & ((1<<PB2) | (1<<PB4))))
{
set_cas_docas++;
}
else
{
if (set_cas_docas > BULHAR_CONST)
{
set_cas = set_cas_docas;
eeprom_cas = set_cas_docas;
eeprom_write(0,set_cas_docas );
}
set_cas_docas = 0;
}
eeprom_cas = set_cas;
eeprom_cas = eeprom_read(0); // nacteni hodnoty z eeprom
if (set_cas < BULHAR_CONST) // set_cas neni dostatecne velky
{
return;
}
// test vstupu pravy blinkr (pokud je logika negativni jako u set)
if (!(PINB & (1<<PB3)))
{
if (!blinkr_pravy_spusten)
{
if (blinkr_pravy++ > BULHAR_CONST)
{
blinkr_pravy = set_cas;
blinkr_pravy_spusten = 1;
PORTB |= (1<<PB1);
blinkr_levy_spusten = 0;
}
}
} else if (!blinkr_pravy)
{
blinkr_pravy_spusten = 0;
}
if (blinkr_pravy > 0 && blinkr_pravy_spusten)
{
blinkr_pravy--;
}
else
{
PORTB &= ~(1<<PB1);
}
// test vstupu levy blinkr (pokud je logika negativni jako u set)
if (!(PINB & (1<<PB4)))
{
if (!blinkr_levy_spusten)
{
if (blinkr_levy++ > BULHAR_CONST)
{
blinkr_levy = set_cas;
blinkr_levy_spusten = 1;
PORTB |= (1<<PB0);
blinkr_pravy_spusten = 0;
}
}
}
else if (!blinkr_levy)
{
blinkr_levy_spusten = 0;
}
if (blinkr_levy > 0 && blinkr_levy_spusten)
{
blinkr_levy--;
}
else
{
PORTB &= ~(1<<PB0);
}
}
int main(void)
{
DDRB &= ~(1<<PB2); // vstup set času
DDRB &= ~(1<<PB3); // vstup pravý blinkr
DDRB &= ~(1<<PB4); // vstup levý blinkr
PORTB |= (1<<PB2)|(1<<PB3)|(1<<PB4); //zapnutí pull up rezistorů
DDRB |= (1<<PB0); // výstup levý blinkr
DDRB |= (1<<PB1); // výstup pravý blinkr
TCCR0B |= _BV(CS01) |_BV(CS00); // nastaveni preddelicky na 1024 (CLK=fosc/1024/256 = [Hz], 1 / CLK = [s])
TIMSK0 |= _BV(TOIE0); // zapni preruseni: Timer Overflow interrupt
set_cas_docas = 0; // nastaveni globalnich promenych
set_cas = 0;
blinkr_levy = 0;
blinkr_pravy = 0;
sei(); // globalni povoleni preruseni
while (1);
}