BASCOM: Přerušení přetečením Timer0 začne fungovat při Int0

Zkusil jsem udělat jednoduchý program v bascomu, jenž využívá přerušení. Problém je v tom, že první část (kontrolní zablikání ledkami) proběhne, ale vlastní přerušení nefunguje. Díky přerušení by měl program vyskočit každých 3,5sekundy z hlavní smyčky a 3x bliknout červenou led na portu B.2. Přitom by neustále měla téměř neustále blikat zelená led dioda na portu B1. To se však neděje.

Napadají mě tyto příčiny:
a) Špatné definování a spuštění časovače
b) Špatný dělící poměr v podmínce v podprogramu
Podprogram musí být navštíven 27500x aby se vykompenzovalo přerušení, jenž je 7812,5x za sekundu

Sám si myslím, že by to takto mělo fugovat, avšak evidentně to tak není, jelikož to takto nedělá.

' Preuseni

$regfile = "m48def.dat"
$crystal = 8000000

Dim A As Byte
Dim B As Integer


Config Portb = Output
Config Timer0 = Timer , Prescale = 1024
On Ovf0 Prerus
Enable Timer0

Enable Interrupts
Start Timer0

B = 0

Portb.1 = 1                                                 ' Zelena led
Portb.2 = 1                                                 ' Cervena led


For A = 1 To 5                                              ' Zablikej Ledkami
   Portb.1 = 0
   Portb.2 = 1
      Waitms 300
   Portb.1 = 1
   Portb.2 = 0
      Waitms 300
Next

Portb.1 = 1
Portb.2 = 1

Do                                                          ' Hlavni cyklus
   Portb.1 = 0                                              ' Blikni zelenu led
      Waitms 150
   Portb.1 = 0
      Waitms 300                                            ' Konec hlavniho cyklu
Loop

' Podprogram

Prerus:                                                     ' Podprogram vzkonavany pri preruseni
                                                            ' Zvys B o jednu
   Incr B                                                   ' Pokud uplynuko cca 3.5 sek blikni cervenou led
                                                            ' 8000000/1024 = 7812.5Hz
                                                            ' Kmitocet zakladni / preddelicka               
                                                           ' = vysledny pocet preruseni za sekundu
                                                            ' 27500 / 7812.5 = 3.52 sek
      If B > 27500 Then
         For A = 1 To 3
         Portb.2 = 0
            Waitms 100
          Portb.2 = 1
            Waitms 300
         Next
      Else
         B = 0
   End If
Return

P.S. Doufám, že tento kód na přímé zveřejnění není ještě příliš dlouhý.

:arrow_right: administrator: přejmenováno z "Přerušení nějak funguje, ač to mám špatně napsané"

If B > 27500 Then For A = 1 To 3 Portb.2 = 0 Waitms 100 Portb.2 = 1 Waitms 300 Next Else B = 0 End If Return

Tak jsem zjistil, že příkaz **else **je tam naprosto navíc a tak jsem ho smazal. Bohužel teď po proběhnutí kontrolního blikání na úvod svítí trvale červená dioda (portb.2) a zelená nereaguje.

Upravený kód podprogramu nyní vypadá takto:

If B > 27500 Then For A = 1 To 3 Portb.2 = 0 Waitms 100 Portb.2 = 1 Waitms 300 Next B = 0 End If Return

P.S. Překladač chybu nikde nehlásí. Z tohoto důvodu jsem přesvědčen, že se jedná o chybu spíše logickou, než chybu v příkazu.

Tak jsem to vyřešil. Opět jsem si naběhnul na nesprávný příklad v knize od BENu.

Začátek programu má být:

[code]’ Preuseni

$regfile = “m48def.dat”
$crystal = 8000000
Enable Interrupts
Enable Int0

Dim A As Byte
Dim B As Integer

Config Portb = Output
Config Timer0 = Timer , Prescale = 1024
On Int0 Prerus[/code]

Nechápu co jsi vyřešil tím, že místo přerušení od přetečení čítače0 použiješ externí přerušení.
Podívej se do helpu ENABLE jaké jsou názvy přerušení.
Pro přetečení timer0 můžeš použít OVF0,TIMER0, COUNTER0.

Tvůj původní kód má tyto chyby:

Do ' Hlavni cyklus Portb.1 = 0 ' Blikni zelenu led Waitms 150 Portb.1 = 0 Waitms 300 ' Konec hlavniho cyklu Loop
S tímto ledka blikat nebude.

If B > 27500 Then 

To odpovídá intervalu asi 900 vteřin, ne 3,5.
Zkus hodnotu 100.

Edit:
A samozřejmě vynechat ELSE v obsluze přerušení.

Přerušení jsem se pokusil použít poprvé a tak to podle toho vypadá. :frowning:

Když jsem zkoušel použít přetečení (viz původní kód), tak se nic nedělo. Proto jsem zkusil kód z příkladu z manuálu k bascomu a tofungovalo. Když se člověk zadívá, tak asi ne úplně správně. Spíš to tak na první pohled vypadá. I když, pokud je to externí přerušení, tak nevím, podle čeho funguje. Nejspíš díky neošetřenému pinu, kde se cosi indukuje.

Aha, chyba se vloudila. Tak proto prvni zelena led sviti. Ale ta druhá (červená, ovládaná přerušením) kupodivu bliká.

Aha já sice spočítal, že 8MHz/1024 je 7812.5, ale zapoměl jsem to vydělit 256.

Vnější přerušení INT0 je vyvoláno hranou nebo nízkou úrovní na pinu INT0 (PD2).
Způsob spuštění se nastavuje příkazem CONFIG INT0.

Nezapojený vstupní pin bez pull-up má vysokou vstupní impedanci takže je velmi citlivý na rušení.
Projeví se to tak, že neustále náhodně mění stav.
Proto, pokud za tohoto stavu povolíš přerušení INT0, bude spouštěno neustále jedno za druhým.

Tak jsem trochu poupravil časy původního programu, ale stále se to chová jinak, než bych chtěl. Na začátku má zablikat nastřídačku zelená led na portu B1 nastřídačku s červenou led na portu B.2 Poté má blikat zelená led a zhruba 1x za 3,5sekundy by měla 3x bliknout červená led. První fáze proběhne, ale pak bliká jen zelená led a červená led, jíž by mělo ovládat přerušení jen svítí. A vůbec nevím proč.

[code] ’ Preuseni

$regfile = “m48def.dat”
$crystal = 8000000

Dim A As Byte
Dim B As Integer

Config Portb = Output
Config Timer0 = Timer , Prescale = 1024
On Ovf0 Prerus
Enable Timer0

Enable Interrupts
Start Timer0

B = 0

Portb.1 = 1 ’ Zelena led
Portb.2 = 1 ’ Cervena led

For A = 1 To 10 ’ Zablikej Ledkami
Portb.1 = 0
Portb.2 = 1
Waitms 15
Portb.1 = 1
Portb.2 = 0
Waitms 15
Next

Portb.1 = 1
Portb.2 = 1

Do ’ Hlavni cyklus
Portb.1 = 0 ’ Blikni zelenu led
Waitms 20
Portb.1 = 1
Waitms 20 ’ Konec hlavniho cyklu
Loop

’ Podprogram

Prerus: ’ Podprogram vzkonavany pri preruseni
’ Zvys B o jednu
Incr B ’ Pokud uplynuko cca 3.5 sek blikni cervenou led
’ 8000000/1024 = 7812.5Hz
’ Kmitocet zakladni / preddelicka
’ = vysledny pocet preruseni za sekundu
’ 27500 / 7812.5 = 3.52 sek
If B > 50 Then
For A = 1 To 3
Portb.2 = 0
Waitms 20
Portb.2 = 1
Waitms 30
Next
Else
B = 0
End If
Return[/code]

Protože proměnná “B” v přerušení nebude nikdy větší než 50.

Měl bys laborovat trochu systematičtěji.
Tuto chybu už jsi jednou odstranil a teď je tam znovu.

Je pravda, že jsem snížil čas na 1/2, takže místo 1x za 3,5sek by mělo blikání červené led proběhnout 2x. Celý cyklus blikání trvá 150ms a to by i při čase pro přerušení 612,5ms nemělo vadit. Nebo se pletu? Čemu vadí, že b bude maximálně 50? Kromě toho, že čas bude poloviční, než u hodnoty 100?

Asi si sedím na vedení, jelikož nevím, co jsem měl špatně, opravil jsem to na správně a pak zas opravil na špatně.

Máš v kódu napsáno, že když B je větší než 50 tak ledka zabliká.
Tudíž když B bude maximálně 50, tak ledka nezabliká nikdy.
Ostatně v tvém kódu dokonce B nebude nikdy větší než 1.

Ještě polopatické vysvětlení, jestli pomůže

[code]Prerus: ’ Podprogram vzkonavany pri preruseni
Incr B

  If B > 50 Then          'jestliže B je větší než 50, proveď smyčku "for-next" (tj. zablikej ledkou)
       For A = 1 To 3
          Portb.2 = 0
          Waitms 20
          Portb.2 = 1
          Waitms 30
       Next

 Else                      'jinak (tj. jestliže B není větší než 50)
     B = 0                 'vynuluj B (a smyčku for-next samozřejmě vynech)

End If
Return[/code]

Už to vidím. Zas jsem tam nacpal to else. Díky za trpělivost.