- 12V Akku mit 280 Ah bauen         
Seite 4 von 14 ErsteErste ... 23456 ... LetzteLetzte
Ergebnis 31 bis 40 von 136

Thema: Anfänger mit STK500 und Assembler

  1. #31
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.12.2005
    Beiträge
    535
    Anzeige

    LiFePo4 Akku selber bauen - Video
    robo_wolf,

    an Deiner Grafik kann man gut die Struktur erkennen, die Dir vorschwebt - dafür sind diese grafischen Darstellungen sehr praktisch.

    Ich lese Dein Bild so:
    Du hast vor, zwei von einander unabhängige Programmteile aufzubauen:
    1. einer liest den Tastenzustand aus
    2. der andere wertet den Tastenzustand aus und führt abhängig davon eine Aktion aus
    (LEDs ein und aus).

    Der 1. Teil, der vom Timerinterrupt angestossen wird, ist für die Entprellung zuständig. Dazu gibt's im Anhang noch etwas Ausführlicheres . Der 2. Teil reagiert auf die Tastenzustände, wie er sie vom 1. Teil "vorgekaut" vorfindet. Diese Einteilung gefällt mir sehr gut, weil sie voneinander unabhängige Aufgaben getrennten Programmteilen zuordnet.

    Zum 1. Teil fallen mir noch folgende Gesichtspunkte ein: Jeder Taster hat die beiden Zustände “betätigt“/“nicht betätigt“. Welche Pegel dabei am Portpin anstehen, hängt von der Art des Tasters („Öffner“ oder „Schliesser“) und von der Beschaltung ab. Ein Öffner zwischen Portpin (mit aktiviertem pull-up-Widerstand)und Masse liefert im betätigten Zustand eine logische Eins, ein Schliesser eine logische Null. Um aller möglichen Verwirrung vorzubeugen, ist es gute Praxis, wenn der 1. Programmteil immer denselben logischen Zustand liefert, wenn der Taster betätigt wird, z.B. den Zustand „hoch“ (= logisch Eins), ganz unabhängig davon, ob das jetzt 5V oder 0V am Pin entspricht.

    Wenn man's nicht so macht, muss man sich später im 2. Programmteil immer wieder daran erinnern, wie die Hardware aussieht. Als ich noch mit sehr umfangreichen, mit Relais aufgebauten Steuerungen (naja, das war in den 1980ern ) zu tun hatte, habe ich mich mir mit sowas mehr als einmal fast das Gehirn verstaucht.

    Der erste Programmteil ist ein „Treiber“, der die Hardware kapselt. D.h. alle Programmteile, die die Tasterzustände verarbeiten, die der Treiber liefert, brauchen nichts über die Hardware zu wissen. Wird irgendwann mal ein Taster von Öffner auf Schliesser getauscht, dann braucht man nur den 1. Programmteil anzupassen. Alle anderen Teile können so bleiben, wie sie sind.

    Im 2. Teil hast Du die möglichen Tastenzustände, die er vorfindet, in den drei hellbraunen Kästchen aufgezählt. Da fehlt aber einer, nämlich der „Taste losgelassen“. Es ist sehr wichtig, sich immer eine vollständige Liste aller möglichen Zustände aufzuschreiben, damit man ja nicht vergisst, für alle Zustände die Reaktion festzulegen. Und wenn man einen Zustand ausser Acht lassen will, dann ist ganz besonders wichtig, genau dafür die Begründung aufzuschreiben. Man glaubt gar nicht, wie schnell man die Gründe für das Weglassen vergessen hat. Liest man dann später das Programm, hält man das Weglassen erstmal für einen Fehler. Es kostet erfahrungsgemäss sehr viel Zeit, bis man schliesslich wieder dahinterkommt, dass man schon damals so ein schlaues Kerlchen gewesen war...

    In Deinem Fall hast Du festgelegt, dass nichts passieren soll, wenn der Taster gedrückt gehalten wird oder wenn er dauernd nicht gedrückt ist. Nur, wenn der Taster gerade gedrückt worden ist, soll das LED umgeschaltet werden. Für das Loslassen hast Du keine Reaktion vorgesehen. Das führt dazu, dass die LED bei jedem zweiten Tastendruck wieder ausgeht. Es gibt also keine ein-eindeutige Zuordnung von Taster- und LED-Zustand. Aber - vielleicht wolltest Du's ja so haben .

    Noch ein Vorschlag: Lass' uns diese Version erstmal für eine einzige Taste zum Laufen bringen, danach kümmern wir uns um die Behandlung von mehreren Tasten. Da können wir dann man gucken, wie man vorgeht, wenn man mehr Variablen als Register verfügbar hat...

    Ciao,

    mare_crisium

    Edit: Im Anhang den Fehler korrigiert, auf den robo_wolf in seinem Posting vom 01.02.2010 hinweist.
    Angehängte Dateien Angehängte Dateien

  2. #32
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.693
    Hallo mare_crisium,

    herrlich - eine ZAK (ZustandsAutomatenKanone), made by mare_crisium. Einfach perfekt. Und ein schönes Lehrstück zur Tastenverwaltung. Ich muss mal sehen, was davon ich abkupfern kann (ich nehme mir einfach diese Freiheit *ggg* - und danke schon mal dafür).

    Das Thema interessiert mich, weil ich derzeit seit vielen Tagen (wieder mal) an einem Pacer arbeite - das ist ein Blinker (vllt. mit Piepsmöglichkeit), der mit zwei LEDs und zwei Tastern ausgestattet ist und mir für Lauftraining eine Schrittfrequenz vorgibt. Also eine Art Metronom. Kein Display - ausser den beiden LEDs.

    Die Tasten dienen zum Einschalten des aktiven Modus, zum Ausschalten, zum Ändern der Frequenz rauf und runter, zum Ein-/Ausschalten des Piepsers, zum Ändern eines Zeit-Mess-Taktes - weil das Dings ohne Quarz läuft und daher nicht wirklich stabil in der Frequenz ist. Dieses Gimmik ist auch ne Kanone - aber es soll halt alles den Anschein von Perfektion haben. Vielleicht noch mehr Gimmiks.

    Nun habe ich meine Tasten nicht nur zu entprellen gehabt, sondern wollte auch in einem Horizont von etwa 2,5 sec wissen, wie lange die Taste schon gedrückt bzw. gelöst wurde. Damit kann/will ich im Menue herumtoben, je nachdem welche Taste in welcher Reihenfolge wie lange gedrückt wurde. Kennen wir von mancher alten Digital-Armbanduhr, von Fahrradcomputern etc. Also stelle ich den Tastenstatus der beiden Tasten TAB und TAU (Taste ABwärts und Taste AUfwärts) im 100 Hz Rhythmus in einer ISR fest - und zähle die jeweiligen Zeitabschnitte (in 10 ms-Schnitten) "gelöst" oder "gedrückt" ab dem letzen Wechsel. Damit kann ich dann recht gut spielen.

    Das Ganze läuft dann so auf (m)einem tiny85:

    Code:
    /* >>   Sicherung 22Jan10 0930   ...C2..\PCR_80\PCR_80_tmr_x51.c
     Es folgt ein Auszug aus einem funktionierenden Teilprogramm
     ===================================================================================
     Target MCU        : ATtiny85
     Target Hardware   : Pacer ...
     Target cpu-frequ. : In der Quelle wählbar
     ===================================================================================
            Enthaltene Routinen:        Nur Timer
     ...
     void TC1TMR_init(void)         // Init Tmr/Cntr1, 8-Bit auf ca. 100 Hz = 0,01 s 50
     ...
     ISR(TIM1_COMPA_vect)           // Vektor 4 (1 ... 4 !!!)                 doc S  50
     ...
     ===================================================================================
      *** Versionsgeschichte:
     ====================
     x51 22Jan10 0930 Weiter in der Blink-organisation
     ...
     x00 07Dez09 2220 Übernahme vom Original, s.u., 
     ===================================================================================
      *** Aufgabenstellung : Timer für pacer80
      Original:  ...C2..\pacer_61\pcr61_tmr_x21.c       x21 11feb09
           war:  ...C2..\wallr_20\WR3_tmr_x03.c   30Nov08
     ================================================================================ */
    // ================================================================================
    
    
    // ================================================================================
    // ===  Initialisierung fuer Timer1 tiny85 ========================================
     void TC1TMR_init(void)         // Init Tmr/Cntr1, 8-Bit auf ca. 100 Hz = 10 ms
     {	                          
      TCCR1  |=  (1<<CTC1);         // Timer im CTC-Mode, Top=OCRA            doc S  92
      TCCR1  |=  (1<<CS12)|(1<<CS11)|(1<<CS10);
                                    // Prescaler Clock1/64                    doc S  93
      OCR1C   =   152;      // Preset/Preload = 152 => getestet ca. 0,010s @ 1,0Mhz
      TIMSK  |=  (1<<OCIE1A);       // Tmr/Cntr1 CompareA interrupt enabled
    //SetBit (PB, rLED);            // Testphase: Zeitanzeige durch rLED 
     }                                
    // ================================================================================
    
    
    // ================================================================================
    // ===  Nicht unterbrechbare ISR für timer1 =======================================
    // Interrupt mit ca. 100 Hz/10 ms. Diese ISR wird benutzt
    //   A  zum Auslesen der Tasten
    //      Nach Ende der Routine sind die Tastenstati in den Statusbytes
    //   B  Zum Setzen der LEDs 
    //      Es werden beide LEDs durch das vorgegebene Bitmuster bedient ( 0 / 1 )
    //      AUSNAHME : Wenn 
    //
     ISR(TIM1_COMPA_vect)           // Vektor 4 (1 ... 4 !!!)                 doc S  50
     {                                
                    // Ab hier mal ähnlicher Aufbau wie bei Timer0
     Izeit_1 ++;                    //  
     if (Izeit_1 >= 100)            //Interrupt-Timer = "Zeithorizont" begrenzen auf 
                                    // 100 = Zeit für EINE Sekunde
     {                                
       Izeit_1   =  1;              // Rückstellen auf Eins
       Isecflag  = 55;              // .. und Sekundenflag setzen
     }                                
                                      
    // - -  Tastenstatistik    - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // - -  Es wird geprüft ob eine Taste gedrückt ist - - - - - - - - - - - - - - - -
    //   WENN diese Taste gedrückt ist, wird einfach bis 254 hochgezählt
    //   WENN diese Taste NICHT gedrückt ist, wird schnell (z.B.20) runtergezählt
    // Änderung 01Jan10  WENN Taste NICHT gedrückt ist, wird *cnt auf Null gesetzt
                                      
    // - -  Zuerst für TAB   - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                      
     TABsts = (!(PINB & (1<<TAB))); // GENAU so *ggg* -- Status von Taste TAB holen
                                      
     if (TABsts)                    // Taste TAB gedrückt?
     {                                
       if (TABcnt < 254)            // Wenn counter < 250
       {                              
         TABcnt     ++;             //   dann hochtackern
         nTABcnt    = 0;            //   und Not-TABcount auf Null setzen
       }                              
     }                                
     else                           // Taste TAB ist nicht gedrückt
     {                                
       if (nTABcnt < 254)           // Wenn not-counter < 250
       {                              
         nTABcnt    ++;             //   dann hochtackern
         TABcnt     = 0;            //   und TABcount auf Null setzen
       }                              
     }                                
    // - -  .. und auch für TAU  - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                      
    //  . . . .                       
                                      
    // - -  Die Tastenstati sind ausgelesen  - - - - - - - - - - - - - - - - - - - - -
                                                
    // . . . .                        
     return;                          
    }                                 
    // ================================================================================
    
    
    // ================================================================================
    // . . . .                        
    // ================================================================================
    
    
    // ================================================================================
    // =====  ENDE    Subroutinen  ====================================================
    // ================================================================================
    
    
    // ================================================================================
    // =====  Sonstige Angaben     ====================================================
    // ================================================================================
                                      
    
     #define TAU     1              // Taster "Aufwärts", PB1
     #define TAB     2              // Taster "Abwärts",  PB2 = "Start"Taste
                                      
     #define PB     PORTB           // Kurzwort für PORTB
     #define gLED    4              // Grüne LED      PB4
                                    // Typ LITEON-LTL1CHKGKNN = CSD-25-3020320
                                    //      572 nm, 45°,    IF 20 mA bei UF 2,4 V
                                    //      Peak FW 60 mA, DC FW 30 mA
     #define rLED    3              // Rote LED       auf PB3
                                      
     #define IsBitSet(ADDR,BIT)     (((ADDR)&(1<<BIT))?1:0) // Fragt Bit = 1?
     #define IsBitClr(ADDR,BIT)     (!((ADDR) & (1<<BIT)))  // Fragt Bit = 0?
                                      
    volatile uint16_t Izeit_1;      // Timer1, ähnlich ~0
                                      
    volatile uint8_t  Isecflag;     // Sekundenflag...55 = Sekunde in ISR erreicht
                                    //                 0 = Sekunde in main übernommen
                                      
      volatile uint8_t TABsts;      // Status derTaste TAB
                                    //   = 0 <=> nicht gedrückt, =1 <=> gedrückt
      volatile uint8_t TABcnt;      // Counter für Taste TAB, 0 ... 255
      volatile uint8_t nTABcnt;     // Counter für Taste notTAB, 0 ... 255
    Dies vielleicht als Anhaltspunkt.
    Ciao sagt der JoeamBerg

  3. #33
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.11.2005
    Ort
    Bayern
    Alter
    55
    Beiträge
    310
    Hallo mare_crisium,
    erst einmal vielen Dank fuer Deine Auswertung und den sehr ausfuehrlichen "endlichen Zustandsautomaten".
    (kann es sein, dass sich ein kleiner Fehler eingeschlichen hat?

    "Die Entscheidung, ob der aktuelle Tasterzustand „hoch“ oder „tief“ ist, kann als
    Mehrheitsentscheidung betrachtet werden: Beim Z=3 war die Mehrheit der Messwerte „hoch“, bei Z=0 war
    sie „tief“. Also werden dem Z-Wert 0 der Tasterzustand „hoch“ und dem Z-Wert 3 der „tief“
    ### muss es hier nicht umegkehrt lauten? ..oder ich habe es doch nicht begriffen..###
    zugeordnet. In den Zuständen 1 und 2 herrscht Stimmengleichheit. Deshalb wird festgelegt, dass der
    vorhergehende Tasterzustand unverändert bleibt, bis entweder Z=0 oder Z=3 erreicht wird."

    Die Ausfuehrungen dazu habe ich in den Grundzuegen begriffen.
    Wobei ich zugeben muss, manches mehrmals durchgelesen und durchdacht zuhaben, bis es so weit war.

    Meine Vorstellungen des Schaltens eines Tasters hat nicht so viele Zustaende umfasst.
    Bei mir gab es nur die Zustaende und deren Aktionen:
    1. Taste gedrueckt (Kein Zustandswechsel an den Tasten)
    1a. Taste nicht gedrueckt bei LED-Zustand AUS -> LED AUS (keine Aktion)
    1b. Taste nicht gedrueckt bei LED-Zustand AN -> LED AN (keine Aktion)

    2. Taste nicht gedrueckt "Wechsel auf" Taste gedrueckt -> Umschalten der LED (Zustandswechsel an den Tasten)
    2a. Taste nicht gedrueckt auf Taste gedrueckt bei LED-Zustand AUS -> LED AN (Aktion von AUS auf AN)
    2b. Taste nicht gedrueckt auf Taste gedrueckt bei LED-Zustand AN -> LED AUS (Aktion von AN auf AUS)

    3. Taste nicht gedrueckt "Wechsel auf" Taste gedrueckt und gehalten -> Umschalten der LED (Zustandswechsel an den Tasten)
    3a. Taste gedrueckt gehalten bei LED-Zustand AUS -> LED AN (Aktion von AUS auf AN)
    3b. Taste gedrueckt gehalten bei LED-Zustand AN -> LED AUS (Aktion von AN auf AUS)

    Die abfallende Taste(gedrueckte Taste Wechsel auf Taste nicht gedrueckt) habe ich nicht betrachten und ihr auch keine Aktion angedacht.
    Wenn ich meine Zeile aber nun so lese, stimmt das nicht wirklich... und ich muss Dir Recht geben.
    " ..und ihr auch keine Aktion angedacht" - ist falsch, es sollte sich "nur" nichts am LED-Zustand aendern.
    somit ergaenze ich hier:
    4. Taste gedrueckt gehalten und Taste los gelassen (Zustandswechsel an den Tasten)
    4a. bei LED-Zustand AUS -> LED AUS (keine Aktion)
    4b. bei LED-Zustand AN -> LED AN (keine Aktion)

    Beim Thema "Timer_Routine"- (Teil1) sprichst Du von einem Treiber bzw. Kapselung.
    Die Idee bzw. den Hinweis, so an die Sache heran zu gehen, finde ich sehr gut.
    In meinen Fall waere es eine Art "Eingangstreiber".
    Wobei es sich dann foermlich aufdraengt gleiches an Ausgangsseite zu tun.
    Zusammen gesagt einen IO-Treiber fuer das STK500...
    Leicht gesagt bzw. geschrieben ich weis.
    Aber dieses Thema einmal komplett durchdacht und abgearbeiten - kann mann diesen Treiber immer wieder verwenden, in andere Projecte includen.
    Der "IO-Treiber" braeuchte dann nur die Informatioen
    -- Input oder Output
    - Tastenzustaende in eine Inputvariable zu schreiben
    - aus einer Outputvariable in den LED-Port zu schreiben.

    Den Vorschlag "Lass' uns diese Version erstmal für eine einzige Taste zum Laufen bringen.." stimme ich,
    nach dem was ich nun alles gelesen habe, vollkommen zu.

    Nach dem Motto kleine Schritte machen, die aber richtig, soll erst einmal nur das Einlesen funktionieren.

    -> Nehmen wir also die Taste, welche am PinD0 gekoppelt ist, als einzulesene Taste.
    Als Ausgabe die LED an PortB0.
    Ferner sind die Besonderheiten des STK500 bekannt.
    Tasten sind mit PullUp-Winderstaende versehen:
    Taste nicht betaetigt: liefert beim Einlesen eine log 1
    Taste betaetigt: liefert beim Einlesen eine log 0
    Der LED-Port schaltet LED AUS bei einer log 1
    LED AN bei einer log 0.

    Die Timer_Routine liest den Zustand von PinD0 und bereitet ihn so auf, dass
    Taste nicht betaetigt eine log 0
    Taste betaetigt eine log 1
    in die Zustandsvariable schreibt.
    ??? (Bleibt erst einmal zu klaeren, in welcher Zeit die Timer_Routine aufgerufen werden soll? Was ist ein guter Wert?) ???

    Die Zustandsvariable wird entsprechend Deiner Ausfuehrungen getestet:
    Um eine gedrueckte Taste(log 1) zu erkennen, muss die Timer_Routine 3 mal nacheinander eine log 1 uebergeben.
    Um eine nicht gedrueckte Taste(log 0) zu erkennen, muss die Timer_Routine 3 mal nacheinander eine log 0 uebergeben.

    so erst einmal die Theorie. Die Praxis folgt....
    ### Silvio ###

  4. #34
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.12.2005
    Beiträge
    535
    robo_wolf,

    jau, danke für den Hinweis auf den Fehler - ist schon korrigiert!

    Es macht richtig Spass, mitzulesen, wie Du Dich in das Thema hineinwühlst ! Am Besten gefällt mir Deine Schlussfolgerung:

    Zitat Zitat von robo_wolf
    Aber dieses Thema einmal komplett durchdacht und abgearbeiten - kann mann diesen Treiber immer wieder verwenden, in andere Projecte includen.
    Zu genau demselben Schluss bin ich nach ein paar Monaten auch gekommen und bin damit seither gut gefahren. Ein Programm-Modul deckt bei mir jeweils eine Funktion komplett ab (im Sinne von Kapselung, wie man sie von objektorientiertem Programmieren her kennt). Z.B. steckt die Handhabung des TWI-Busses und meines eigenen TWI-Protokolls in einem Modul. Wenn ich Daten über den Bus versenden will, schreibe ich sie byteweise in die Ausgangs-FIFO, rufe im TWI-Modul die Prozedur TWI_SEND auf und weiter geht's. Über die ganze interne Abwicklung im Modul brauche ich nie mehr ( ) Gedanken zu machen.

    Die Module werden einfach per "include"-Anweisung eingebunden. Z.B. sieht der "include"-Block in meinem 13kB-Programm so aus:

    Code:
    .include "ASTWI16_V01.asm"                  ; Modul zur TWI-Abwicklung
    .include "ASTWIIF16_V04.asm"               ; Interface zwischen Hauptprogramm und TWI-Modul, enthält die Dialogstruktur
    .include "FIFOk16_V01.asm"                   ; Ein- und Ausgangs-Datenpuffer für TWI-Bus
    .include "System16_V02.asm"                 ; div. Utilities, z.B. ASCII_to_hex u.ä.
    .include "MathLibSF24_16_V07.asm"      ; 32-Bit Fliesskomma Bibliothek
    .include "M2KNavigation_16_V08.asm"   ; Koppelnavigations-Algorithmus 
    .include "ADNS2610SPI16_V05.asm"       ; SPI-Kommunikation mit dem Maussensor 
    .include "ASADNS2610IF16_V04.asm"     ; Interface zwischen Hauptprogramm und Maussensoren
    .include "ZstAutomat16_V04.asm"          ; der Zustandsautomat zum Hochfahren und Überwachen der Maussensoren usw.
    Dieses Vorgehen führt zu etwas erhöhtem Zeitbedarf, weil man sich bestimmte Vorschriften setzen und sie einhalten muss. Z.B. werden bei mir alle verwendeten Register mit "push"- und "pop"-Anweisungen gesichert, damit ich nicht jedesmal nachgucken muss, welche Register verändert werden. Trotzdem hat das Verfahren sich sehr bewährt, weil es mir erlaubt, mit Assembler fast wie in einer Hochsprache Programme zu schreiben. -

    Der Vollständigkeit halber habe ich im Anhang noch die Geschichte mit dem Zustandsautomaten zuendegeführt. Bin gespannt auf Dein nächstes "Lernprogramm". Als Takt für den Timer-Interrupt schlage ich vor, zunächst mit so 2 bis 5 Hz anzufangen; da kann man das Flackern noch sehen. Wenn dann alles fehlerfrei läuft, kannst Du's immer noch schneller machen.

    Ciao,

    mare_crisium

    @oberallgeier,

    ja, für diese Anwendung könnte ein endlicher Zustandsautomat ein gangbarer Weg sein. Natürlich nur, wenn er in Assembler programmiert ist, nicht in cäh !

    mare_crisium
    Angehängte Dateien Angehängte Dateien

  5. #35
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.11.2005
    Ort
    Bayern
    Alter
    55
    Beiträge
    310
    Habe den Code zum Einlesen und Auswerten des an PinD0 befindenlicher Taste.
    Einige Zeilen sind stark an mare_crisium´s "endlichen Zustandsautomaten" angelehnt.
    Das Schalten der LED habe ich vorerst weggelassen.
    Code:
    ;***** STK500 Lernprogramm Nr.4d
    ;*** Aufgabe: die Taste an PinD0 schaltet die zugeordnete LED auf dem STK500
    ;*** 1. Tastendruck: LEDs einschalten
    ;*** 2. Tastendruck: LEDs ausschalten
    ;*** eine Timerroutine liest den TastenStatus ein
    ;*** zum Entprellen - muss die TimerRoutine 3mal hintereinander den gleichen Wert
    ;*** einlesen um einen Tastzustand zu erkennen, Zst_Var 0x03(log 1) bzw. 0x00(log 0)
    ;*** Taste nicht gedrueckt >>> log 0 in Tast_Stat(r17)
    ;*** Taste gedrueckt       >>> log 1 in Tast_Stat(r17)
    ;
    ;
    .include "m8515def.inc" 
    .def Temp        = r16			; Temporary Register 
    .def Tast_Stat   = r17			; Tasten Status
    .def Tast_Stat0	 = r18
    .def LED_Stat    = r19			; LED Status
    .def Zst_Var     = r20			; Zustandsvariable - beinhaltet eine 2Bit-Zahl zur Tastzustandserkennung
    .def TOGGLE_SPRR = r21			; Sperrt die Ausfuehrung von TastenTest wenn, keine neuer TIMER1_OVL voran gegangen	
    
    ;
    ;	TimerWerte(bei 8MHz - ca. 0,2sec)
    .equ Timerwert   = -60 			; Timerschritte bis zum Überlauf(fuer Simulatortest)
    ;.equ Timerwert   = -1562     	; Timerschritte bis zum Überlauf
    ;
    ;
    .equ LED_PORT = PORTB			; LEDs
    .equ LED_DDR  = PORTB-1			; DataDirectory fuer LEDs
    .equ TAST_PORT= PORTD			; Tasten
    .equ TAST_DDR = PORTD-1			; DataDirectory fuer TastenEingang
    .equ TAST_PIN = PORTD-2			; TastenEingang
    ;
    ;***** 
    ;Reset and Interrupt vector    ;VNr.  Beschreibung 
       rjmp   RESET                ;1   POWER ON RESET 
       reti						   ;2   Int0-Interrupt 
       reti                        ;3   Int1-Interrupt 
       reti                        ;4   TC1 Capture 
       reti                        ;5   TC1 Compare Match A TC2 Overflow 
       reti                        ;6   TC1 Compare Match B TC1 Capture 
       rjmp  TIMER1_OVF            ;7   TC1 Overflow TC1 Compare Match A 
       reti	                       ;8   TC0 Overflow TC1 Compare Match B 
       reti                        ;9   SPI, STC Serial Transfer Complete TC1 Overflow 
       reti                        ;10  UART Rx Complete TC0 Overflow 
       reti                        ;11  UART Data Register Empty SPI, STC Serial Transfer Complete 
       reti                        ;12  UART Tx Complete UART Rx Complete 
       reti                        ;13  Analog Comparator 
       reti                        ;14  Int2-Interrupt 
       reti                        ;15  Timer 0 Compare Match 
       reti                        ;16  EEPROM Ready 
       reti                        ;17  Store Program Memory Ready 
    ;*****
    
    RESET: 
    	
    
    
    	ldi temp,(1<<CS10)				; Taktfrequenz Vorteiler 1 gewaehlt (fuer Simaulatortest)          
    ;	ldi temp,(1<<CS10)|(1<<CS12)	; Taktfrequenz mit Vorteiler 1024 gewaehlt           
     	out TCCR1B,temp
    									; Timer1 vorladen 
     	ldi temp,HIGH(Timerwert) 
    	out TCNT1H,temp
     	ldi temp,LOW(Timerwert) 
    	out TCNT1L,temp	
    	ldi temp,(1<<TOIE1)				; Timer1 Overflow aktivieren
    
    	out TIMSK,temp          
    
    
    
    
    
    	ldi r16, LOW(RAMEND)        	;Stack initialisieren 
    	out SPL, r16 
    	ldi r16, HIGH(RAMEND) 
    	out SPH, r16 
    
    	clr Temp                    	;Temp mit 0b00000000 bzw. 0x00 laden 
    	out TAST_DDR, Temp         		;PORTD als Eingang 
    	ser Temp                    	;Temp mit 0b11111111 bzw. 0xFF laden 
    	out TAST_PIN, temp				;STK500 schaltet gegen GND - Taste gedreuckt (Pin==0)
    	out TAST_PORT, temp        		;PullUp an PortD einschalten 
    	out LED_DDR,Temp           		;PORTB als Ausgang 
    	out LED_PORT, temp         		;PORTB (LEDs) aus 
    	clr Tast_Stat					;Tast_Stat auf def. Zustand
    	clr Zst_Var
    	sei								; globale Interruptfreigabe
    MAIN:
    	sbrc TOGGLE_SPRR,0				; kein TOGGLE, wenn Bit0 ==0
    	rcall TOGGLE
    	rjmp MAIN
    
    
    TIMER1_OVF:
    	push	TEMP					; TEMP auf Stack sichern
    	in	TEMP,SREG					; SREG auf Stack sichern 
    	push	TEMP					;
    	
    	in Tast_Stat0, PIND				; Tasten werden komplett eingelesen
    	com Tast_Stat0					; invertiere
    	clt								; loesche T-Flag
    	SBRC Tast_Stat0,0				; RegisterBit0 von TastStat ==0 ueberspringe / T-Flag wird nicht gesetzt	
    	set								; ==1 setze T-Flag
    ;	
    ;	default wird -1 in temp eingetragen | springt bei nicht gesetzten T-Flag zu TastZst0 
    ;	bei gesetzten T-Flag wird +1 in temp eingetragen
    ;
    	ldi temp, 0x03					; temp == "-1"
    	brtc TastZst0
    	ldi temp, 0x01					; temp == "+1"
    ;
    ;	TastZustand0
    ;
    	TastZst0:
    	cpi Zst_Var,0x00				; vergleiche ob Zst_Var ==0
    	brne TastZst1					; springe wenn ungleich
    	sbrs temp, 0x01					; ueberspringe naechsten Befehl, wenn temp negativ(0x03) ist
    	add Zst_Var, temp				; addieren temp in Zst_Var
    	rjmp TastZst_Exit
    ;
    ;	TastZustand1
    ;
    	TastZst1:
    	cpi Zst_Var, 0x01				; vergleiche ob Zst_Var ==1
    	brne TastZst2
    	add Zst_Var, temp
    	rjmp TastZst_Exit
    ;
    ;	TastZustand2
    ;
    	TastZst2:
    	cpi Zst_Var, 0x02				; vergleiche ob Zst_Var ==2
    	brne TastZst3
    	add Zst_Var, temp
    	rjmp TastZst_Exit
    ;
    ;	TastZustand3					; Fehler abfangen Zst_Var darf nur Werte zwischen 0x00 und 0x03 haben
    ;
    	TastZst3:
    	cpi Zst_Var, 0x03				; vergleiche ob Zst_Var ==3
    	brne TastZst_Error
    	sbrc temp, 0x01
    	add Zst_Var, temp
    ;
    	TastZst_Error:
    	;
    	TastZst_Exit:
    	andi Zst_Var, 0xFB				; eventuellen Uebertrag loeschen
    ;
    	cpi Zst_Var, 0x00				; ueberspringe naechsten Befehl
    	brne Test2
    	cbr Tast_Stat,0x01				; >>>>>Taste nicht gedrueckt
    ;
    	Test2:
    	cpi Zst_Var,0x03				; ueberspringe naechsten Befehl 
    	brne T0_OVL_Exit
    	sbr Tast_Stat,0x01				; >>>>>Taste gedrueckt
    ;
    	T0_OVL_Exit:
    									; Timer1 vorladen 
     	ldi temp,HIGH(Timerwert) 
    	out TCNT1H,temp
     	ldi temp,LOW(Timerwert) 
    	out TCNT1L,temp	
    ;
    	sbr TOGGLE_SPRR,0				; Status fuer TOGGLE 1 - TOGGLE / 0 - kein TOGGLE
    	pop	TEMP						; 
    	out	SREG,TEMP					; SREG zurueckschreiben
    	pop	TEMP						; TEMP zurueckschreiben 
    	reti
    
    
    TOGGLE:
    	cbr TOGGLE_SPRR,0				; loesche Bit0, um TOGGLE bis zum naechsten TIMER1_OVF zu sperren
    	nop								; kommt spaeter
    	ret
    Ganz zufrieden bin ich damit nicht..
    Es tut zwar was es soll, ABER:
    - es wurden 5 Register dafuer benoetigt (schaem)
    - ich bin mir nicht sicher, ob alles in der TimerServiceRoutine drin sein sollte ???
    (hatte mal gelesen, das die Programmunterbrechungen so kurz wie moeglich sein sollten) bei mir spielt sich da fast alles ab.
    - gern haette ich die von mare_crisium aufgestellte Zustandstabelle benutzt, nur leider verstehe ich deren Funktion nicht richtig (wieder schaem)
    (Da braeuchte ich noch mal ein bischen Starthilfe...generell das Benutzen von arrays und deren Auswertung)
    - mit dem Konzentrieren auf eine Taste PinD0 in diesem Beispiel, seh ich momentan kein einfaches Einbinden der restlichen 7 Tasten
    - vom eigendlichen Ziel "IO-Treiber" bin ich noch sehr weit weg
    ### Silvio ###

  6. #36
    Erfahrener Benutzer Robotik Visionär
    Registriert seit
    26.11.2005
    Ort
    bei Uelzen (Niedersachsen)
    Beiträge
    7.942
    Solange man nur eine ISR hat, und sonst nichts zeitkritisches läuft, macht es nicht wenn die ISR etwas länger ist. Wenn man weiss was man macht, kann man da auch längere Sachen machen, wie einen String per UART verschicken. Meine längste ISR braucht etwa 2 Sekunden - das Hauptprogramm macht dafür nichts außer sleep.

    So lang ist die ISR auch noch gar nicht. da ist schließlich keine Schleife drin. An einigen Stellen läßt sich noch was feilen, aber das lernt man auch noch. Ein Beispiel was mit sehr umständlich vorkommt ist die Art wie das Bit0 vonder Taste in T flag verschoben wird. Dafür gibt es direkt den Befehl BST, den ich allerdings auch noch nie richtig benutzt habe.


    Es ist auch keine Schande die Register auch zu benutzen. Solange die Register da sind kann man das machen, und kommt so ohne RAM aus. geht schließlich schneller und wird kürzer.
    Man kann sogar soweit gehen, für die Interrupts eigene Register zu reservieren, so daß man keine Register mehr auf den Stack retten muß.

  7. #37
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.12.2005
    Beiträge
    535
    robo_wolf,

    wenn sich einer zu schämen hat, dann wohl ich, weil ich's nicht gut genug erklärt habe . Wenn's Dir nichts ausmacht, dann lass' uns die Sache in kleineren Schritten angehen (siehe Anhang).

    Ciao,

    mare_crisium

    Edit 1:
    im .pdf haben sich folgende Fehler eingeschlichen:
    1. "...mit der „ldi2-Anweisung setzen kann." Gemeint ist die "ldi"-Anweisung.
    2. Im Programm-Ausschnitt "; LEDs von Tasten 1 und 2 steuern" müssen die Skip-Anweisungen nicht "sbrs r19,bFLANKE0" und "sbrs r19,bFLANKE1" sondern "sbrc r19,bFLANKE0" und "sbrc r19,bFLANKE1" heissen.
    Angehängte Dateien Angehängte Dateien

  8. #38
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.11.2005
    Ort
    Bayern
    Alter
    55
    Beiträge
    310
    Hallo mare_crisium,
    vielen Dank fuer die Erlaerungen.
    Die fehlerhafte Vektortabelle hatte ich bisher nicht bemerkt.(Asche ueber mein Haupt)
    Bis jetzt war bei Timer0 Schluss...und mit Timer1 ist es das erste Programm.
    Aus diesem Grund sind mir die CTC-, Compare-Funktionen zwar bekannt, aber es fehlte die praktische Anwendung.
    Du hast geschrieben, das die CTC-Funktion besser geignet sei.
    Da habe ich nun einen praktischen Anwendungsfall

    CTC bedeutet also, dass er nach dem Erreichen des voreingestellten OCR1A und, oder OCR1B den Interrupt ausloest und die Serviceroutine durchlaeuft.
    Es ist dann aber so, dass er beim Verlassen der Serviceroutine keinen definierten Zaehlerstand, je nach Verzweigung, hat? Oder liege ich da falsch?
    Das spielt bei mir aber eine untergeordnete Rolle. Man kann auch sagen 100 Takte hin oder her sind bei der gewuenschten Funktion egal,
    da keine Timings eingehalten werden muessen.
    Es vereinfacht aber Programm an dieser Stelle, da das Nachladen entfaellt.

    Die Funktionen des AVR-Studios hinsichtlich des Manipulieren(Setzen und Ruecksetzen von verschiedener PortBits oder Registerwerte)
    sind mir schon bekannt und ich nutze sie.
    Das zusaetzliche Anlegen der Daten fuer die Simulation hatte einen anderen Zweck.
    Wenn ich bestimme wann die Programmunterbrechnung und Ausfuehrungen der ISR passieren, dann habe ich keine Willkuer vom Programm.
    ...will sagen, die Unterbrechungen passieren dann dort, wo ich sie nicht erwarte...
    So hatte ich schon "kleine Anfaengerfehler" gefunden. War fuer mich eine zusaetzliche Ueberpruefung.
    Trotzdem Danke fuer die Erlaeuterungen.

    „BST“-Anweisung kannte ich bis jetzt nicht wirklich.
    Du musst dir vorstellen, wenn ich ein programmtechnisches Problem loesen moechte,
    dann nehme ich mir das Datasheet oder die AVR-Instuktionsliste zur Hand und probiere...
    Auch muss ich wieder sagen, ... super habe nun eine praktische Anwendung dafuer

    */Ach, ich glaube, ich habe Dich auf zu komplizierte Gedanken gebracht. Tut mir leid, ich bin halt kein Pädagoge /*
    Das ist schon OK so und bitte weiter so. Es schadet mir gewiss nicht, ueber das Geschriebene laenger nach zu denken.
    Wenn es zu kompliziert wird, melde ich mich schon

    Nun habe ich leider nicht konkret geschrieben, was mir schwer faellt zu begreifen.. sorry
    So kam es, wie es kommen musste.
    Du hast genau, dass was mir klar war, noch einmal schoen beschrieben. - geschadet hat es mir ganz sicher nicht
    - Du hattest nur Arbeit damit -

    Den eigentlichen Ablauf habe ich schon verstanden und kann ihn nachvollziehen.
    ABER
    >>> Die Sache mit den .dw-Anweisungen... da habert es ...
    Die Werte die Du angegeben hast, sind von Dir (willkuerlich)festgelegt und beschreiben die Zustaende und belegen praktischer Weise 4Bit,
    also ein Nibble eines Registers.
    Da glaubte ich erst einen bestimmten Algoritmus, der dahinter steht, finden zu muessen.
    - es sind leicht zu erkennende Zustaende, die nur irgendwie sinnvoll angeordnet sein muessen -

    Dadurch lassen sich 2 Tasten in ein Register speichern.
    Nun sind die Werte mit den .dw-Anweisungen festgelegt... und wo kommen die hin, sind sie abgelegt.?

    >>> Danach hast Du Zeiger verwendet. ist ebenfalls Neuland fuer mich.(Hier liegt glaube ich mein groesstes Manko)
    Wie der Name schon sagt, zeigen bzw. verweisen sie auf etwas. In dem Fall Speicher stellen.

    >>> add und adc -Addieren mit und ohne Carry-Flag

    >>> dann waere da noch "lpm" lesen aus dem Programmspeicher

    Wahrscheinlich, dessen bin ich mir sicher, sind das ganz banale Dinge... die ich mir komplizierter denke, als sie in Wirklichkeit sind.

    Das sind bei weitem nicht alle Fragen, die ich gern los werden moechte
    Aber mit den Antworten, kaeme ich erst einmal wieder ein Schritt weiter.

    Ich hoffe, dass ich Dich nicht zu sehr damit quaele?
    Du hast auf jeden Fall einen dankbaren Schueler... auch wenn Du kein Paedagoge bist.
    Es ist eben nicht so einfach, etwas zu erklaeren, wenn man nicht genau weis, wie der andere(ich) es versteht.
    ### Silvio ###

  9. #39
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    08.12.2005
    Beiträge
    535
    robo_wolf,

    nur immer zu mit Fragen . Dafür ist dieser Fred ja da.

    ".dw"-Anweisung:
    Mit der „.dw“-Anweisung wird ein Wort, also ein 16-Bit-Wert, in den Programmspeicher geschrieben. Die Syntax des AVR-Assemblers erlaubt es, auch gleich mehrere Worte auf einmal zu schreiben. Z.B. ist

    ...
    TABELLE:
    .dw 0xABCD,0x1234,0x5678
    ...

    ebenfalls erlaubt. Man kann die Einträge 0xABCD usw. wiederfinden, wenn man das Memory-Fenster des Simulator auf „Program“ einstellt und sich die Speicherinhalte ansieht, die auf die Adresse des Labels „TABELLE“ folgen (die Adresse von „TABELLE“ sieht man, wenn man im Simulator im Quelltext den Mauszeiger auf das Label stellt). Angenommen, die Adresse von „TABELLE“ sei 0x0046. Dann sieht es im Programmspeicher so aus

    0046 CD AB 34 12
    004A 78 56 ...

    Das LSB wird also immer in der niedrigeren, geradzahligen Adresse abgelegt, danach erst das MSB. Man nennt diese Speichermethode auch „little endian“, im Gegensatz zum „big endian“, wo das MSB an der niedrigeren Adresse steht.

    Die Daten, die auf die Adresse „TABELLE“ folgen, kann man mit der „lpm“-Anweisung auslesen. Die Einzelheiten des Befehls sind in der Assembler-Hilfe des AVR-Studios gut beschrieben.

    Die Tastenzustände ändern sich laufend und müssen deshalb in den Registern oder im RAM-Speicher gehalten werden; der Programmspeicher soll zur Laufzeit des Entprellprogramms nicht mehr geändert werden. Deshalb dienen die „.dw“-Anweisungen ausschliesslich dazu, im Programmspeicher die Übergangstabelle zu erzeugen. Mit den aktuellen Tastenzuständen haben sie nichts zu tun.

    Timer/Counter1:
    In der Betriebsart CTC springt der Timer wieder auf Null zurück, nachdem er den Wert von OCR1A bzw. OCR1B erreicht hat, und zählt dann munter weiter. Dadurch bleibt das Zeitintervall zwischen zwei Interrupts immer dasselbe. Wo wie Du es gemacht hattest, beginnt die Zählung vom Rücksetzen des Zählerstandes neu. Er ist also von der Ausführungsdauer des Interrupt-Dienstprogramms abhängig.

    Ich nehme an, Du hast das so gemacht, weil Du befürchtetest, der nächste Interrupt könnte eintreten, bevor das Dienstprogramm beendet ist. Probier' mal im Simulator, was passiert, wenn Du den CTC-Interrupt von TC1 manuell auslöst, während das Dienstprogramm noch läuft... Wenn Du solche Ereignisse partout vermeiden willst, dann hilft der Vergleich von PreScaler*OCR1A_Wert mit der maximalen Anzahl Taktzyklen im Dienstprogramm. Solange PreScaler*OCR1A > max.TaktZyklen ist, fällt der Interrupt immer in die Zeit nach dem Ende des Dienstprogramms.

    Ciao,

    mare_crisium

  10. #40
    Erfahrener Benutzer Begeisterter Techniker
    Registriert seit
    02.11.2005
    Ort
    Bayern
    Alter
    55
    Beiträge
    310
    Hallo mare crisium,
    schnelle und praezise Erklaerung.
    Das bringt doch gleich etwas LICHT ins dunkel.
    versteh ich das richtig?
    von 0xABCD
    LSB ist "CD"
    und
    MSB ist "AB"
    Habe mal bei mir den Quellcode eingefuegt und mir den Programmspeicher angeschaut:

    TABELLE:
    .dw 0xABCD,0x1234,0x5678

    Label Tabelle: zeigt auf die Speicherzelle 0x0019(16Bit breit) und
    .dw 0xABCD,0x1234,0x5678 sind bei
    0x0019 CD AB
    0x001A 34 12
    0x001B 78 56 abgelegt

    also zuerst LSB und dann MSB in der Adresse

    Nun hast Du geschrieben:
    "Das LSB wird also immer in der niedrigeren, geradzahligen Adresse abgelegt, danach erst das MSB. "
    ??? 0x0019 und 0x001B sind doch keine geradzahligen Adressen ???

    Ich glaub, ich steh hier schon wieder auf der Leitung.
    ### Silvio ###

Seite 4 von 14 ErsteErste ... 23456 ... LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

fchao-Sinus-Wechselrichter AliExpress