[Bascom] Proszę o pomoc z programem

To forum jest dla wszystkich pasjonatów mikrokontrolerów AVR Atmela. Wymiana doświadczeń i pomoc dla początkujących w pisaniu programów zarówno w C, Asemblerze jak i BASCOM. Zapraszam znawców tematu, aby pomogli wszystkim początkującym!
ODPOWIEDZ
rozrabiak
-
Posty: 18
Rejestracja: 06 lip 2007, 20:13

[Bascom] Proszę o pomoc z programem

Post autor: rozrabiak » 14 lip 2007, 19:03

W poniższym kodzie mam problem z IDLE, tzn. jednym przyciskiem chcę wprowadzać cpu w stan IDLE oraz go wybudzać (INT1). Problem w tym, że gdy chcę go "ululać" to przechodzi w stan IDLE, po czym wraca "gdzieś". Tzn. pwm startuje ponownie, z załadowaną wartością z eproma. Ale cpu NIE reaguje na żadne przyciski wtedy, totalny zwis?

Kod: Zaznacz cały

$regfile = "2313def.dat"
$crystal = 4000000
Config Portb = &B11111111
Portb = &B11111111
Config Portd = &B1111111
Portd = &B0000000
Config Timer1 = Pwm , Pwm = 10 , Prescale = 1 , Compare A Pwm = Clear Up , Compare B Pwm = Disconnect       'Clear Up
Readeeprom Pwm1a , 0
Stop Timer1
Config Int1 = Falling
Declare Sub Nint
Declare Sub O1nint
Enable Int1
Enable Interrupts
On Int1 Nint
Stop Timer1
Toggle Portb.7
Idle


Do
  If Pind.1 = 1 Then                                        'UP
  If Pwm1a < 500 Then
  Stop Timer1
  Pwm1a = Pwm1a + 5
  Start Timer1
  Waitms 30
  End If
  End If

  If Pind.0 = 1 Then                                        'down
  If Pwm1a > 1 Then
  Stop Timer1
  Pwm1a = Pwm1a - 5
  Start Timer1
  Waitms 30
  End If
  End If

  If Pind.4 = 1 Then                                        '10%
  Stop Timer1
  Pwm1a = 151
  Start Timer1
  End If

  If Pind.6 = 1 Then                                        '100%
  Stop Timer1
  Pwm1a = 701
  Start Timer1
  End If

  If Pind.3 = 1 Then                                        'sleep
  Waitms 250
  If Pind.3 = 1 Then
  Call O1nint
  End If
  End If
Loop

Sub O1nint
      Writeeeprom Pwm1a , 0
      Toggle Portb.7
      Stop Timer1
      Wait 1
      Enable Int1
      Enable Interrupts
      Idle
End Sub

Sub Nint
      Toggle Portb.7
      Waitms 250
      Readeeprom Pwm1a , 0
      Start Timer1
      Disable Int1
      Disable Interrupts
      Waitms 500
End Sub
Ostatnio zmieniony 01 sty 1970, 1:00 przez rozrabiak, łącznie zmieniany 1 raz.

ZbeeGin

Post autor: ZbeeGin » 14 lip 2007, 19:13

Na początek proponuję powiększyć rozmiary stosów: HWStack, SoftStack.

Wątpliwości budzi również fragment:

Kod: Zaznacz cały

  If Pind.3 = 1 Then                                        'sleep
    Waitms 250
    If Pind.3 = 1 Then
      Call O1nint
    End If
  End If
Jakie działanie chciałeś tym uzyskać?
Ostatnio zmieniony 01 sty 1970, 1:00 przez ZbeeGin, łącznie zmieniany 2 razy.

rozrabiak
-
Posty: 18
Rejestracja: 06 lip 2007, 20:13

Post autor: rozrabiak » 14 lip 2007, 19:45

ZbeeGin pisze:Na początek proponuję powiększyć rozmiary stosów: HWStack, SoftStack.
Zwiększać na "oko"? Próbowałem z ustawieniem HWStack 40 i SoftStack 16, nadal to samo.
ZbeeGin pisze: Wątpliwości budzi również fragment:

Kod: Zaznacz cały

  If Pind.3 = 1 Then                                        'sleep
    Waitms 250
    If Pind.3 = 1 Then
      Call O1nint
    End If
  End If
Jakie działanie chciałeś tym uzyskać?
Żeby układ nie reagował na przypadkowe naciśnięcie przycisku "usypiającego".

ZbeeGin

Post autor: ZbeeGin » 14 lip 2007, 19:56

I jeszcze jedno. Konfigurujesz port D jak wyjścia w stanie niskim, a potem chcesz odczytać zmianę ich stanu... :?
rozrabiak pisze:Żeby układ nie reagował na przypadkowe naciśnięcie przycisku "usypiającego".
Ok. Tylko na jaki jego stan chcesz reagować? Przerwanie reaguje przecież na zbocze opadające (z CONFIG INT1=Falling), a ty tutaj oczekujesz stanu wysokiego? Jak w końcu masz podłączone te klawisze?

rozrabiak
-
Posty: 18
Rejestracja: 06 lip 2007, 20:13

Post autor: rozrabiak » 14 lip 2007, 20:05

ZbeeGin pisze:I jeszcze jedno. Konfigurujesz port D jak wyjścia w stanie niskim, a potem chcesz odczytać zmianę ich stanu... :?
Przyciski mam podpięte do plusa zasilania.
ZbeeGin pisze:Ok. Tylko na jaki jego stan chcesz reagować? Przerwanie reaguje przecież na zbocze opadające (z CONFIG INT1=Falling), a ty tutaj oczekujesz stanu wysokiego? Jak w końcu masz podłączone te klawisze?
Mój błąd. Już poprawione. Jednak nadal dzieje się to samo z układem..

ZbeeGin

Post autor: ZbeeGin » 14 lip 2007, 20:17

Ja bym jednak zmienił koncepcję. Przyciski zwierane do masy. PortD skonfiguruj jako wejście z podciąganiem. Przerwanie wywoływane zboczem opadającym (Falling).

No i nie musisz zatrzymywać licznika by wpisać nową wartość do rejestru PWM1A. Konstruktorzy Atmela zadbali by PWM nie generował przypadkowych impulsów podczas zmiany jego stanu.

rozrabiak
-
Posty: 18
Rejestracja: 06 lip 2007, 20:13

Post autor: rozrabiak » 14 lip 2007, 20:31

ZbeeGin pisze:Ja bym jednak zmienił koncepcję. Przyciski zwierane do masy. PortD skonfiguruj jako wejście z podciąganiem. Przerwanie wywoływane zboczem opadającym (Falling).
Będzie tak zrobione. Wiem o tym:) Jednak ta płytka musi mi posłużyć do końca pisania programu, później zmienię co trzeba i będzie nowa płytka (prawdopodobnie elementy SMD).
No i nie musisz zatrzymywać licznika by wpisać nową wartość do rejestru PWM1A. Konstruktorzy Atmela zadbali by PWM nie generował przypadkowych impulsów podczas zmiany jego stanu.
Dziękuję za informację.

Znalazłem BŁĄD! Jednak nie wiem czy to moja wina, programistów BASCOMA czy CPU felerne.

Kod: Zaznacz cały

Sub O1nint
   Writeeeprom Pwm1a , 0
   Toggle Portb.7
   Stop Timer1
   Wait 1
   'Enable Int1
   'Enable Interrupts
   Idle
End Sub
Po wyremowaniu tych dwóch poleceń:

'Enable Int1
'Enable Interrupts

w powyższej procedurce program "nie resetuje się" i cpu się nie zawiesza. Tylko nie rozumiem jaki wpływ to ma na stabilność? Coś trzeba dodatkowo załączyć/wyłączyć w ustawieniach może?

ZbeeGin

Post autor: ZbeeGin » 14 lip 2007, 22:11

A ja widzę inny poważniejszy błąd. Deklarujesz procedurę obsługi przerwania On Int1 Nint . A tym czasem Nint to procedura programowa użytkownika Declare Sub Nint!

Jako procedura obsługi przerwania musi być stworzona specjalna procedura. Rozpoczyna się ona od etykiety, a kończy słowem kluczowym Return. Co więcej, procesor AVR podczas trwania tej procedury wyłącza przyjmowanie przerwań, a później odtwarza stan znacznika. Zatem samo przepisanie Nint do postaci:

Kod: Zaznacz cały

Nint:
  Toggle Portb.7
  Waitms 250
  Readeeprom Pwm1a , 0
  Start Timer1
  Disable Int1
  Disable Interrupts
  Waitms 500
Return
Nic tutaj nie da. Instrukcja Disable Interrupts zostanie "przykryta". Ponadto tych instrukcji się nie stosuje w przerwaniu: Readeeprom, Waitms.
Najlepiej stworzyć znacznik typu Bit, zmieniać go w procedurze obsługi przerwania i na podstawie jego stanu wywoływać Sub Nint w obecnej postaci.

Jest już dość późno więc nie przedstawię tutaj jakiegoś sensownego i kompletnego przykładu. :sad:

[ Dodano: 2007-07-15, 13:04 ]
Obiecany konkret (tylko istotne fragmenty):

Kod: Zaznacz cały

$regfile = "2313def.dat"
$crystal = 4000000

(...)

Dim Iff As Bit    'flaga zgloszenia przerwania

(...)

On Int1 Int_isr
Enable Int1
Enable Interrupts

Iff = 0
Readeeprom Pwm1a , 0
Toggle Portb.7
Idle

Do
  If Iff = 1 Then
    Iff = 0   'lub Reset Iff
    Call Nint
  End If

  (...)

Loop

Int_isr:
  Set Iff
Return

(...)
Nie zapomnij sprzętowo wyeliminować drgań styków na końcówce INT1.

rozrabiak
-
Posty: 18
Rejestracja: 06 lip 2007, 20:13

Post autor: rozrabiak » 15 lip 2007, 18:08

[ Dodano: 2007-07-15, 13:04 ]
Obiecany konkret (tylko istotne fragmenty):

Kod: Zaznacz cały

$regfile = "2313def.dat"
$crystal = 4000000

(...)

Dim Iff As Bit    'flaga zgloszenia przerwania

(...)

On Int1 Int_isr
Enable Int1
Enable Interrupts

Iff = 0
Readeeprom Pwm1a , 0
Toggle Portb.7
Idle

Do
  If Iff = 1 Then
    Iff = 0   'lub Reset Iff
    Call Nint
  End If

  (...)

Loop

Int_isr:
  Set Iff
Return

(...)
Nie zapomnij sprzętowo wyeliminować drgań styków na końcówce INT1.
Dziękuję BARDZO za pomoc. Jednak dopiero teraz spojrzałem na forum i już było za późno, gdyż napisałem od zera nowy kod, zrobiłem symulację w bascomie. Kod jest krótszy i nie ma już problemów z zwisami.

Pracuję teraz nad PWM i detekcją przez zero.

Układ detekcji przejścia przez zero mam podłączony do wejścia INT0. W obsłudze przerwania wpisałem "Start Timer1". Tylko, że przeglądając różne projekty (bardzo rozbudowane) nie potrafię wywnioskować KIEDY mam zatrzymać timer1 :/
Bazuję tylko na pomocy z bascoma oraz nocie katalogowej ze strony Atmel'a.

ODPOWIEDZ