Stránka 1 z 2

Pomoc s programem

Napsal: 27 led 2020, 17:30
od reher64
Zdravím Vás tu,
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ů.

Napsal: 27 led 2020, 17:45
od passion
V čom to programuješ? Napríklad Arduino IDE pozná funkciu pulseIn

Kód: Vybrat vše

https://www.arduino.cc/reference/en/language/functions/advanced-io/pulsein/

Napsal: 27 led 2020, 17:55
od reher64
Jo pardon zapomněl jsem. Píši to v atmel studiu v Céčku

Napsal: 27 led 2020, 18:25
od FHonza
Použij přerušení INT0, nastavené tak aby se vyvolalo při změně na vstupu. Vzestupná hrana nuluje počítadlo a spouští časovač , sestupná hrana ho vypíná. Každý "průchod" časovačem inkrementuje počítadlo. Přesnost je dána rychlostí časovače.

Napsal: 27 led 2020, 19:37
od reher64
Přesnost mě až tak moc netrápí, kdyby to bylo v rozmezí 500ms tak se nic neděje. Použít časovač mě napadlo jako první, ale připadalo mi to složité k funkci co potřebuji. Setování se provede možná jednou za celou dobu používání zařízení, možná víckrát, ale minimálně. Pak bych musel při každém sepnutí výstupu pouštět časovač který mi bude držet výstup v log 1 cca 5-15s dle nasetování při oživení. Myslel jsem jestli není nějaká jednodušší funkce, co by mi změřila čas při nasetování při oživení a pak ho to používalo.
Zkusím si tedy asi pohrát s tím časovačem a uvidím, jestli to půjde.

Napsal: 27 led 2020, 20:54
od FHonza
S výhodou použiješ stejný časovač i pro generování výstupního impulzu. Budeš vědět kolik napočítal časovač při měření. Stejnou hodnotu použiješ i při generování. Nemusíš pak nic přepočítávat. Prostě pro generování nastavíš log1 na výstup, spustíš časovač. Každý "průchod" časovačem odečte jedničku, při nule nastavíš log0 a vypneš časovač.

Napsal: 28 led 2020, 11:04
od reher64
Tak sedím na datasheetem, ale nedokážu se hnout z místa. Neporadili by jste jak nastavit ten čítač ? Posílám zde i schéma jak by měl být attiny připojen.
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.

Napsal: 28 led 2020, 20:26
od Zmije
A máš už nějaký kus kódu?
přečti si tohle
http://www.tajned.cz/2017/01/citaccasovac-0-nejen-na-attiny-1-dil/

Napsal: 29 led 2020, 18:08
od reher64
Z kódu mám zatím toto. Je to bez čítače, nesmysl co jsem měl jsem smázl, nedělalo to nic. Je tam zatím sekvence pro nastavení času. Spínání těch dvou výstupů za normálního provozu tam ještě nemám.
Č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;
}
}



}
}

Napsal: 29 led 2020, 20:45
od petula
má to arduino dělat ještě něco jiného, než jen tpo co bylo shora napsáno, tedy na vstupní impuls spustit časovač a počítat čas? Ten čas v časovači má být jak dlouhý? Bude vždy stejný, nebo se bude nějkak nastavovat, třeba rotačním enkodérem?

Napsal: 29 led 2020, 21:02
od Zmije
On to nedělá s arduinem, ale klasicky v C, vleze se vůbec arduino do atiny?

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.

Napsal: 29 led 2020, 22:24
od Zmije
Možná takhle
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);
}

Napsal: 02 úno 2020, 18:44
od reher64
Páni, neměl jsem teď vůbec čas se sem dostat, až teď.
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í ?

Napsal: 03 úno 2020, 01:02
od Zmije
Bod č. 1 je jednoduchý, to bys mohl zvládnout sám

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.

Napsal: 05 úno 2020, 23:17
od reher64
Super děkuji funguje. Ještě jsem si to trochu upravil aby při rychlém přepínání směrů to reagovalo ihned a povedlo se také.
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);
}