Problem med TMR1/TMR0 och meny... (C/MikroC)

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
jonte_s
Inlägg: 88
Blev medlem: 11 februari 2006, 17:13:48
Ort: Stockholm

Problem med TMR1/TMR0 och meny... (C/MikroC)

Inlägg av jonte_s »

Tja.

Försöker knåpa ihop en meny på LCD, men jag har problem med koden, närmare bestämmt TMR1 och TMR0.

Jag kan inte få TMR1 att fungera utan TMR0. Så som koden ser ut nu så fungerar allt, men så fort jag tar bort något som har med TMR0 att göra så fungerar det inte längre. Grejen är att jag använder inte TMR0 i koden (har tagit bort det som använde TMR0). Förstår inte vad det beror på!?
TMR1 använder jag i "void debounceStateMachine(void)".

Ge gärna förslag på hur jag skall förbättra koden! Är mitt första C-program.

PIC:en är en 628A @ 10MHz.

Kod: Markera allt

#define TRUE 1
#define FALSE 0

void interrupt(void);
void TMRInit(void);
void LCDInit(void);
void menuStateMachine(void);
void debounceStateMachine(void);

char weGotTMR1Interrupt = 0;        // glbal var which tells the program (main) if we got TMR1 interrupt.
char PushbuttonUpPushed = FALSE;

enum state1 {bootsState, dustState, invulnState, mercState};
enum state1 menuStateVar = bootsState;
enum state2 {idleState, pressingState, pressedState};
enum state2 debounceStateVar = idleState;
//------------------MAIN--------------------------------------------------------
void main()
{
    CMCON = 0b00000111;     //Turn comparators off --> pins becomes I/O
    TRISA = 0x1f;           // inputs
    TRISB = 0;              // outputs
    LCDInit();
    TMRInit();
    while (1)
    {
          debounceStateMachine();      // polls button
          menuStateMachine();
          PushbuttonUpPushed = FALSE;
    }
}
//------------------------------------------------------------------------------

void menuStateMachine(void)
{
     switch(menuStateVar)
     {
          case bootsState:
              LCD_Out(2,1,"boots");
              if(PushbuttonUpPushed == TRUE)
              {
                  menuStateVar = dustState;
              }
              break;

          case dustState:
              LCD_Out(2,1,"dust");
              if(PushbuttonUpPushed == TRUE)
              {
                  menuStateVar = invulnState;
              }
              break;

          case invulnState:
              LCD_Out(2,1,"invuln");
              if(PushbuttonUpPushed == TRUE)
              {
                  menuStateVar = mercState;
              }
              break;

          case mercState:
              LCD_Out(2,1,"merc");
              if(PushbuttonUpPushed == TRUE)
              {
                  menuStateVar = bootsState;
              }
              break;
       }
}

void debounceStateMachine(void)
{
     switch(debounceStateVar)
     {
          case idleState:
              if(PORTA.F0 == 1)
              {
                    T1CON.TMR1ON = 1;        // start TMR1.
                    debounceStateVar = pressingState;
              }
              break;

          case pressingState:
              if(weGotTMR1Interrupt == 1)
              {
                  T1CON.TMR1ON = 0;          // stop TMR1.
                  if(PORTA.F0 == 1)
                  {
                     debounceStateVar = pressedState;   //om fortfarande en 1:a
                                                        //så registrerar vi ett
                  }                                     //knapptryck.
                  else
                     debounceStateVar = idleState;      // om inte en 1:a hoppa
              }                                         // tillbaka till början

              weGotTMR1Interrupt = 0;        // reset variable
              break;

          case pressedState:
              PushbuttonUpPushed = TRUE;
              debounceStateVar = idleState;
              break;
       }
}

void LCDInit(void)
{
    LCD_Init(&PORTB);         // Initialize LCD connected to PORTB
    LCD_Config(&PORTB, 1, 3, 2, 7, 6, 5, 4);
    LCD_Cmd(LCD_CLEAR);       // Clear display
    LCD_Cmd(LCD_CURSOR_OFF);  // Turn cursor off
}

void TMRInit(void)
{
// interuppt from TMR0
     INTCON.T0IE = 1;         // eneble intrrupt on overflow.
     OPTION_REG.T0CS = 0;     // timer-mode.

// interrupt from TMR1 is init to interrupt after xxms.
   PIE1.TMR1IE = 1;           // enebles timer1 interrupts
   T1CON.TMR1CS = 0;          // timer mode
   TMR1L = 0b00000000;        // räknar upp till 20000-->26ms innan overflow...
   TMR1H = 0b00000000;        // ... med o.4us per instruktion (10MHz).
   T1CON.T1CKPS1 = 1;         // prescaler 8 --> 200ms before overflow.
   T1CON.T1CKPS1 = 1;

   INTCON.GIE = 1;            // eneble global interrupt.
}

void interrupt(void)
{
//  TMR0 overflow interrupt. on TMR0 interrupt TOIF is set.
    if(INTCON.T0IF == 1)
    {
        INTCON.T0IF = 0;  // reset flag
    }
    
// TMR1 overflow interrupt.
    if(PIR1.TMR1IF == 1)
    {
        weGotTMR1Interrupt = 1;
        TMR1L = 0b00000000;      // reloed TMR1.
        TMR1H = 0b00000000;      //
        T1CON.T1CKPS1 = 1;       // prescaler is reset when writing to TMR1L/H
        T1CON.T1CKPS1 = 1;
        PIR1.TMR1IF = 0;         // reset flag
    }
    //INTCON.GIE = 1;        // Global interrupt is reset after return?
}
mvh Jonas
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

*Vad* är det du "tar bort" ??

> //INTCON.GIE = 1;

Sker automatiskt vid RETFIE (vilket interrupt funktionen borde göra).
jonte_s
Inlägg: 88
Blev medlem: 11 februari 2006, 17:13:48
Ort: Stockholm

Inlägg av jonte_s »

Tack för svaret.
Ok. Va lite otydlig kanske. Exakt så som koden är i mitt inlägg, så fungerar det.
Men tar jag bort

Kod: Markera allt

// interuppt from TMR0 
     INTCON.T0IE = 1;         // eneble intrrupt on overflow. 
     OPTION_REG.T0CS = 0;     // timer-mode. 
eller

Kod: Markera allt

//  TMR0 overflow interrupt. on TMR0 interrupt TOIF is set. 
    if(INTCON.T0IF == 1) 
    { 
        INTCON.T0IF = 0;  // reset flag 
    } 
    
eller båda delarna så fungerar det inte.

Jag tror också att det där med INTCON.GIE = 1 är som du säger (eftersom det fungerar som det är nu), men tror inte det stod något excplicit om det i MikroC-maualen...
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Jag tror dessutom att du har en bugg i koden *om* du själv
sätter GIE *innan* interrupt rutinen gör return...
(Jag såg inte att det var bortkommenterat...)

Men för övrigt, vad händer när du plockar bort timer0-delarna ?
Vart tar koden "vägen" ?
jonte_s
Inlägg: 88
Blev medlem: 11 februari 2006, 17:13:48
Ort: Stockholm

Inlägg av jonte_s »

Första meny "State" skrivs ut på LCD:n (dvs. "boots") när jag tar bort TMR0 delarna, men knappen fungerar inte, dvs man kan inte stega genom menyn.

Jag försöker simulera i MikroC, men det verkar som att inte TMR1L och TMR1H uppdateras när man stegar sig igenom. Testade att kolla TMR0-registret också i en annan kod, men det verkar som att dem inte uppdateras. Hmm...


(Edit: första meningen löd tidigare: Ja alltså ingenting skrivs ut på LCD:n när jag tar bort TMR0 delarna.)
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

OK, ser inget uppenbart, men ett par andra småsaker...

> ... // prescaler is reset when writing to TMR1L/H

Ja, men *inte* bitarna i T1CON. Och varför sätter du
samma bit två gånger (även i init) ?

Varför inte lägga "case pressedState" direkt där "debounceStateVar = pressedState" görs ?
Det verkar bli ett extra "varm" i rutinen i onödan...
Å så behövs väl inte "else" direkt därefter...

Mina tanke är att något gör att du aldrig startar TMR1 igen...
jonte_s
Inlägg: 88
Blev medlem: 11 februari 2006, 17:13:48
Ort: Stockholm

Inlägg av jonte_s »

Jo jag missade det där att jag satte samma bit två ggr, så ska det ju inte vara. Tack för det.

Såhär står det i 628A-manualen: "The prescaler counter is cleared on writes to the TMR1H or TMR1L registers."
Betyder inte det att Prescaler-bitarna sätts till 0 efter att man skrivit till TMR1H eller TMR1L ?

Det blir nog ett varv extra så som jag har det, ändrar nog på det senare, men känns skönt att ha väldefinierade "states". Så som jag har det nu tror jag att else behövs...

Blir helt tokig på det här med TMR1 och TMR0, har fan suttit många timmar med det nu. Jag kan ju ha det som jag har det nu. Det funkar ju, men det känns inte ok när man inte fattar.

> Mina tanke är att något gör att du aldrig startar TMR1 igen...

Det borde den göra, för när jag ändrar TMR1H, TMR1L och prescaler så ändras känsligheten på knappen.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Betyder inte det att Prescaler-bitarna sätts till 0 efter att man skrivit till TMR1H eller TMR1L ?

Nej, sa jag ju...

> ...så ändras känsligheten på knappen.

Hur vet du det, om inget ändras i LCD'n ??
jonte_s
Inlägg: 88
Blev medlem: 11 februari 2006, 17:13:48
Ort: Stockholm

Inlägg av jonte_s »

Jo, eftersom TMR1 bestämmer känsligheten på knappen (eller "debouncetiden"), så när jag ändrar tiden tills TMR1 får overflow så ändras "känsligheten" på knappen --->>> menyerna på LCD:n bläddras olika snabbt.
Användarvisningsbild
Abra Hana
Inlägg: 94
Blev medlem: 12 maj 2005, 13:20:58

Inlägg av Abra Hana »

Kod: Markera allt

void TMRInit(void) 
{ 
// interuppt from TMR0 
     INTCON.T0IE = 1;         // eneble intrrupt on overflow. 
     OPTION_REG.T0CS = 0;     // timer-mode. 

// interrupt from TMR1 is init to interrupt after xxms. 
   PIE1.TMR1IE = 1;           // enebles timer1 interrupts 
   T1CON.TMR1CS = 0;          // timer mode 
   TMR1L = 0b00000000;        // räknar upp till 20000-->26ms innan overflow... 
   TMR1H = 0b00000000;        // ... med o.4us per instruktion (10MHz). 
   T1CON.T1CKPS1 = 1;         // prescaler 8 --> 200ms before overflow. 
   T1CON.T1CKPS1 = 1; 

   INTCON.GIE = 1;            // eneble global interrupt. 
}
----------------------------------------------------------------------------
:shock:
INTE KONSTIG ATT DU INTE FÅR TIMER1 ATT FUNGERA
TIMER1 ÄR UR LEKEN , DÄRFÖR FUNGERAR INTE TIMER1:s INTERRUPT .

DU MÅSTE TILLÅTA TIMER1 GENOM ATT SÄTTA BITEN TMR1ON I REGISTRET T1CON
jonte_s
Inlägg: 88
Blev medlem: 11 februari 2006, 17:13:48
Ort: Stockholm

Inlägg av jonte_s »

Abra Hana: Mitt problem är inte riktigt att TMR1 inte fungerar, för det gör den (men bara "tillsammans" med TMR0).
Jag sätter TMR1ON=1, i rutinen "void debounceStateMachine(void)"

Kod: Markera allt

void debounceStateMachine(void) 
{ 
     switch(debounceStateVar) 
     { 
          case idleState: 
              if(PORTA.F0 == 1) 
              { 
                    T1CON.TMR1ON = 1;        // start TMR1. 
                    debounceStateVar = pressingState; 
              } 
              break; 

          case pressingState: 
              if(weGotTMR1Interrupt == 1) 
              { 
                  T1CON.TMR1ON = 0;          // stop TMR1. 
                  if(PORTA.F0 == 1) 
                  { 
                     debounceStateVar = pressedState;   //om fortfarande en 1:a 
                                                        //så registrerar vi ett 
                  }                                     //knapptryck. 
                  else 
                     debounceStateVar = idleState;      // om inte en 1:a hoppa 
              }                                         // tillbaka till början 

              weGotTMR1Interrupt = 0;        // reset variable 
              break; 

          case pressedState: 
              PushbuttonUpPushed = TRUE; 
              debounceStateVar = idleState; 
              break; 
       } 
} 
Användarvisningsbild
Abra Hana
Inlägg: 94
Blev medlem: 12 maj 2005, 13:20:58

Inlägg av Abra Hana »

:shock:
oj då det var en miss av mig .
Användarvisningsbild
Abra Hana
Inlägg: 94
Blev medlem: 12 maj 2005, 13:20:58

Inlägg av Abra Hana »

*
kan int få timer1 att fungerar utan timer0


inaktivera TIMER1 och sedan se om TIMER0 kan fungera utan TIMER1 .

flytta "weGotTMR1Interrupt == 1" till

if(INTCON.T0IF == 1)
{
INTCON.T0IF = 0; // reset flag
weGotTMR1Interrupt == 1 ; <<--
}

Ställ in önskad TIMER0 prescaler .
Om samma problem kvarstår , så kan det vara att det är något som inte stämmer med en eller flera av CASE sates .

*
jonte_s
Inlägg: 88
Blev medlem: 11 februari 2006, 17:13:48
Ort: Stockholm

Inlägg av jonte_s »

Det fungerar att bara använda TMR0. Har tagit bort allt som har med TMR1 att göra.
Men jag vill använda TMR1 till detta. TMR0 skall jag använda till något annat...
Hmmmm...
Användarvisningsbild
Abra Hana
Inlägg: 94
Blev medlem: 12 maj 2005, 13:20:58

Inlägg av Abra Hana »

*
det är svårt att få en överblick över din kod !
Kan du göra en CHAR FLOW över programmet .

*
Skriv svar