Knappar fungerar inte.

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Knappar fungerar inte.

Inlägg av Kalf »

Hej. Det var ett himla tjat ifrån mig det sista men jag lär mig mer och mer för varje gång.

Nu har jag problem med att få två knappar att fungera. Till och börja med här är förutsättningarna:

uC: PIC16F886
Kompilator: MikroC
Koppling: Porta: 7 segments display segment A-DP
Portb: RB0 en fototransistor via en vanlig transistor för att invertera signalen.
RB1 utgång till blixt via optokopplare
RB2-3 Knappar för att styra displayen
Portc:RC0-3 transistorer för att välja rätt display
Knapparna är kopplade enl. mellan RB2 och +5v 100k motstånd och mellan RB2 och GND är knappen. Likaså för RB3

config:

Kod: Markera allt

__CONFIG _CONFIG1, _DEBUG_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_OFF &
_CPD_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT

__CONFIG _CONFIG2, _WRT_OFF & _BOR21V
Kod:

Kod: Markera allt

/************************************************************/
//                                                          //
//   Flash delay timer V1.0                                 //
//   Developer: Karl-Fredrik Johansson                      //
//                                                          //
//   Decription:                                            //
//   A delay timer for a flash for taking highspeed photos. //
//   Using a IR-diode and a phototransistor to sense when   //
//   a BB-gun is fired. A PIC16F886 processes this          //
//   information and triggers a flash after a deired time.  //
//   To display and choose the delay time I'm using a       //
//   4*7 segments display and two buttons.                  //
//                                                          //
//   Copyright Karl-Fredrik Johansson                       //
//   Mail: kalf89@gmail.com                                 //
/************************************************************/

//Functions
void display(void);

//variables
unsigned short shifter;
unsigned short digit;
unsigned short porta_index;
unsigned int   number;
unsigned short porta_array[4];
unsigned short digit1 = 0;
unsigned short digit2 = 0;
unsigned short digit3 = 0;
unsigned short digit4 = 0;
unsigned short last_digit1 = 0;
unsigned short last_digit2 = 0;
unsigned short last_digit3 = 0;
unsigned short last_digit4 = 0;
unsigned short cnt_value = 0;
unsigned short real_cnt_value = 0;
unsigned short oldstate = 0;

//Mask values to display the correct values on the display
unsigned short mask(unsigned short num) {
  switch (num) {
    case 0 : return 0x3F;
    case 1 : return 0x06;
    case 2 : return 0x5B;
    case 3 : return 0x4F;
    case 4 : return 0x66;
    case 5 : return 0x6D;
    case 6 : return 0x7D;
    case 7 : return 0x07;
    case 8 : return 0x7F;
    case 9 : return 0x6F;
    default: return 0x40;
  }
}

//interrupt
void interrupt()
{
     if(INTCON.T0IF == 1) //If TMR0 generats interrupt
     {
                    PORTC = 0;                        //Turns the segments off
                    PORTA = porta_array[porta_index]; //Assaign the correct value of the correct digit
                    PORTC = shifter;                  //Turn on the correct digit
                    
                    //Shift display
                    shifter <<= 1;
                    if (shifter > 8u) shifter = 1;
                    
                    //move on to next display
                    porta_index++;
                    if (porta_index > 3u) porta_index = 0;   // turn on 1st, turn off 2nd 7seg.
                    
                    TMR0   =   0;                          // reset TIMER0 value
                    INTCON = 0x20;                         // Clear T0IF
     }
}

//Display function
void display(void)
{
     //Display 0000 for a start value
     porta_array[0] = mask(0);
     porta_array[1] = mask(0);
     porta_array[2] = mask(0);
     porta_array[3] = mask(0);

     while(1)
     {
             //Display the current digits
             porta_array[0] = mask(digit1);
             porta_array[1] = mask(digit2);
             porta_array[2] = mask(digit3);
             porta_array[3] = mask(digit4);

             //Get digits from value
             real_cnt_value = cnt_value;
             digit1 = cnt_value % 10;
             cnt_value = cnt_value / 10;
             digit2 = cnt_value % 10;
             cnt_value = cnt_value / 10;
             digit3 = cnt_value % 10;
             cnt_value = cnt_value / 10;
             digit4 = cnt_value % 10;
             cnt_value = real_cnt_value;

             //increase value on display
             if (button(&PORTB, 2, 50, 1)) oldstate = 1;
             if (button(&PORTB, 2, 50, 0))
             {
                cnt_value++;
                if (cnt_value > 9999) cnt_value = 0;
                oldstate = 0;
             }

             //decrease value on display
             if (button(&PORTB, 3, 50, 1)) oldstate = 1;
             if (button(&PORTB, 3, 50, 0))
             {
                cnt_value--;
                if (cnt_value > 9999) cnt_value = 9999;
                oldstate = 0;
             }
     }
}

//Main
void main()
{
      //input output assignment
      TRISA = 0b00000000;      //7-segment display Segment A-DP
      TRISB = 0b00001101;      //RB0 sensor input RB1 Flash trigger output RB2-3 Input button RB4-7 N-A
      TRISC = 0b00000000;      //RC0-3 Digit selection RC4-7 N-A

      //Timer and other settings
      OPTION_REG = 0b10000000;  //PORTB Pull-ups are dissabled
      INTCON = 0b10100000;      //enable GIE and T0IE
      
      //Clearing and setting regs, bits and varibles
      PORTA = 0;                //Clears PORTA
      PORTB = 0;                //Clears PORTB
      PORTC = 0;                //Clears PORTC
      TMR0 = 0;                 //Clears TMR0
      shifter = 1;
      porta_index = 0;

      //Write to display Startup sequence
      porta_array[0] = 0x40;
      porta_array[1] = 0x40;
      porta_array[2] = 0x40;
      porta_array[3] = 0x40;
              
      delay_ms(1000); // Create a delay to fake a loading sequence
              
      display();      //Go to display()
}
För er som undrar, funktionen button() är en inbyggd funktion för att hantera kontaktstuds. Mer info, saxat ifrån MikroC manualen, nedan:
Button
Prototype unsigned short Button(unsigned short *port, unsigned short pin, unsigned short time, unsigned short active_state);

Returns Returns 0 or 255.

Description Function eliminates the influence of contact flickering upon pressing a button (debouncing).

Parameter port specifies the location of the button; parameter pin is the pin number on designated port and goes from 0..7; parameter time is a debounce period in milliseconds; parameter active_state can be either 0 or 1, and it determines if the button is active upon logical zero or logical one.

Requires Button pin must be configured as input.

Example Example reads RB0, to which the button is connected; on transition from 1 to 0 (release of button), PORTD is inverted:

do {
if (Button(&PORTB, 0, 1, 1)) oldstate = 1;
if (oldstate && Button(&PORTB, 0, 1, 0)) {
PORTD = ~PORTD;
oldstate = 0;
}
} while(1);
Nu till det resultatet jag får:
Displayen lyser upp med: ---- detta lyser i 1s som den skall. Sedan visas 0000. Också detta som planerat. Men det händer ingenting när jag trycker på knapparna. Det förväntade resultatet skall vara att displayen räknar upp respektive ner beroende på vilken knapp som trycks ner.

Fråga
Vad är fel? Jag kan inte hitta något direkt fel med koden eller inkopplingen. Några idéer på hur jag skall fortsätta i min felsökning?

MVH
Kalf
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Knappar fungerar inte.

Inlägg av sodjan »

Jag ser inte att du stänger av de analoga funktionerna.
Kolla databladet för PORTB, speciellt noten på sidan 47 som säger :
Note: The ANSELH register must be initialized to configure an analog
channel as a digital input. Pins configured as analog inputs will read ‘0’.
(Föredömligt förstainlägg, för övrigt. Inget saknas och det kommer sannolikt
att lösas utan en massa extrabollande av kompletteringsfrågor. Sparar tid
till alla... :-) )

EDIT:

En annan intressant fråga är ju, hur skulle du ha löst detta själv ?
Tja, några förslag skulle kunna vara :

- Fixa en testkod som enbart läser knapparna på PORTB och felsök det separat.
D.v.s skala bort allt annat ur koden som förvillar tills knapparna fungerar.
Det räcker med 5-10 C-rader för att t.ex läsa en knapp och tända en LED.

- Noggrannare läsning av kapitlet om PORT'ar i databladet. Svaret finns
ju speciellt utpekat i en "Note:" i en egen liten grå ruta, så det måste ju
vara viktigt, eller hur ?
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Knappar fungerar inte.

Inlägg av blueint »

Kanske en liten kondensator parallellt med knappen kunde göra nytta?
Användarvisningsbild
TomasL
EF Sponsor
Inlägg: 47009
Blev medlem: 23 september 2006, 23:54:55
Ort: Borås
Kontakt:

Re: Knappar fungerar inte.

Inlägg av TomasL »

Eller ännu bättre, knappen mot jord i stället, 10k mellan pinnen och matningen.
Sedan kan man för att förbättra det ytterligare, lägga en konding på säg 1 u mellan porten och jord, samt ett motstånd på säg 10 k mellan knapp och jord
Typ så här:
Bild

googla på "debouncing" så hittar du en del skojj
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Knappar fungerar inte.

Inlägg av Icecap »

När knapparna INTE räknar kan det knappast vara ett debounce-problem...

Dessutom är det bättre att lösa debounce i mjukvaran, ger färre komponenter. Men jag håller med om att det ger bäst resultat att ha knapparna mellan GND och portpinne med en pull-up, det ger färre störningar.

Men jag ser ett stort problem i det hela:
do {
if (Button(&PORTB, 0, 1, 1)) oldstate = 1;
if (oldstate && Button(&PORTB, 0, 1, 0)) {
PORTD = ~PORTD;
oldstate = 0;
}

Det finns en sak i detta som jag undrar starkt över: Varför tusan använda "Button()" funktionen?

Om vi antar att knapp 1 är PORTB.0 och knapp 2 är PORTB.1 är det hela ganska enkelt:
En knappläsningsrutin kallas regelbundet, t.ex. via en timer-interrupt eller via main-loop.

Man ska ha en variabel som inte används till annat, den sparar status, här kallar vi den "Previous"
Steg 1: Läs porten och maska ut de viktiga data.
- Port_Data = PORTB & 0x03; // 0x03 motsvarar de bits som knapparna sitter på
Steg 2: Kolla att knappen är påverkat minst 2 avläsningar, debounce helt enkelt.
- Keys = Port_Data & Previous;
Steg 3: Spara "nu-värde" till nästa gång.
- Previous = Port_Data;
Steg 4: Nu innehåller "Keys" en '1' för varje knapp som är intryckt, sedan gör man med detta vad man vill.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Knappar fungerar inte.

Inlägg av sodjan »

> Varför tusan använda "Button()" funktionen?

Svaret är naturligtsvis "därför att den finns".

> Dessutom är det bättre att lösa debounce i mjukvaran,...

Och det gör också Button() redan, så det är sannolikt inte problemet.

Men det är en helt annan fråga. Det finns ingen anledning att
just nu misstänka att Buttom() funktionen inte fungerar alls.
Just *nu* ser det ut att vara ett enkelt fall där man inte
har slagit av analoga funktioner, och alltså läses knapparna
hela tiden som "0", och det kan inte Buttom() göra mycket åt...

I just detta fall fungerar sannolikt Button() helt utmärkt, om den sedan
i någon annat hypotetiskt fall inte passar är en helt annan fråga...
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Re: Knappar fungerar inte.

Inlägg av Kalf »

Sodjan du hade helt rätt. Det räckte att slå av de analoga funktionerna. Men jag har stött på ett nytt problem nu. Jag har försökt att tackla det hela morgonen utan resultat. Nu försöker jag få en interrupt ifrån min sensor. Alltså när RB0 får en "rising edge" skall interrupten "triggas". Det finns ju (som bekant?) en funktion i processorn för detta redan. Det är också denna jag försöker få att fungera.

Förutsättningarna är som tidigare. 16f886MikroC config enl. tidigare etc.

Jag har även tagit råd ifrån Sodjan och pluggat på databladet ännu mer och läst allt jag kan hitta om RB0/INT. Jag har även skrivit en egen kod enbart för just denna interrupten.

I kopplingen har jag även uteslutit sensorn genom att enbart ha en sladd från +5v att "dutta" på RB0 för att simulera en rising edge.

Vad jag har fått fram ifrån databladet krävs följande saker för att få en interrupt:

*OPTION_REG - pull-ups av och interrupt on rising edge
*INTCON - GIE på INTE På töm INTF
*vänta på interrupt
*Interrupt kommer
*Töm GIE för att inga andra interrupts skall kunna inträffa
*Töm INTF för att nollställa interrupt flaggan
*gör det interrupten skall göra.

Såhär har jag kodat:

Kod: Markera allt

//interrupt
void interrupt()
{
     if(INTCON.INTF == 1)
     {
                    INTCON.GIE = 0;                //Clear GIE
                    INTCON.INTF = 0;               //clear intrerrupt
                    PORTB = 0b11111111;            //Trigger the flash
                    delay_ms(20);                  //wait to be shure that the flash has triggerd
                    PORTB = 0;                     //release flash circut
     }
}



//Main
void main()
{
     while(1)
     {
        //input output assignment
        TRISB = 0b00001101;      //RB0 sensor input RB1 Flash trigger output RB2-3 Input button RB4-7 N-A

        //Timer and other settings
        OPTION_REG = 0b11000000;  //PORTB Pull-ups are dissabled, interrupt on rising edge
        INTCON = 0b10010000;      //enable GIE, and INTE
        ANSEL  = 0;               // Configure AN pins as digital I/O
        ANSELH = 0;
        IOCB = 0;

        //Clearing and setting regs, bits and varibles
        PORTB = 0;                //Clears PORTB
     }
}
Nerre
Inlägg: 27257
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Knappar fungerar inte.

Inlägg av Nerre »

Varför har du all initialisering i while-loopen??

Sen undrar jag om det där är hela koden? Nånstans måste man väl tala om för kompilatorn att interrupt() är en interrupt-hanterare?
ToPNoTCH
Inlägg: 5158
Blev medlem: 21 december 2009, 17:59:48

Re: Knappar fungerar inte.

Inlägg av ToPNoTCH »

Jag är totalt obegåvad på C, men borde du inte spara undan status registret i samband med interruptrutinen ??
Användarvisningsbild
Kalf
Inlägg: 249
Blev medlem: 5 november 2005, 09:59:45

Re: Knappar fungerar inte.

Inlägg av Kalf »

Nerre: Inte för att jag ser några problem med att ha initieringen i en while-loop. Men för att det skall se snyggare ut så har jag nu flyttat ut det. Sedan vet min kompilator MikroC om från början att interrupt() är en interrupt hanterare.

ToPNoTCH: Jag har aldrig använt mig utav STATUS registret när jag kodat i C.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Knappar fungerar inte.

Inlägg av sodjan »

> *Töm GIE för att inga andra interrupts skall kunna inträffa

Behövs inte. Interruptet självt stänger av GIE och när interruptet
gör RETFIE (alltså när din interrupt funktion i C avslutas) så sätts
GIE igen automatiskt. Du behöver aldrig röra GIE om du inte vill
stänga av interrupt från att inträffa *utanför* interrupt funktionen.

> INTCON = 0b10010000;

För att lättare att läsa koden (och man slipper att öppna databladet hela
tiden för att kolla vilken bit som är vad i INTCON) om du skriver :

INTCON.GIE = 1;
INTCON.INTE = 1;

Detta gäller generellt för *alla* register där de olika bitarna har
olika funktion och olika/egna namn.

Sen så räcker det väl med en while(1) loop på slutet av main, finns
ingen anledning att köra om all initiering hela tiden (och det *kan* vara
ett problem i sig, jag har inte funderat på det).

> Nånstans måste man väl tala om för kompilatorn att interrupt() är en interrupt-hanterare?

Namnet "interrupt()" är just det.

> men borde du inte spara undan status registret i samband med interruptrutinen ??

MikroC gör det när man använder funktions namnet "interrupt()".

> Inte för att jag ser några problem med att ha initieringen i en while-loop.

Problem och problem... Det är bara korkat. Så fixa det.
Nerre
Inlägg: 27257
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Knappar fungerar inte.

Inlägg av Nerre »

Den aktuella PICen har alltså bara EN interrupt?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Knappar fungerar inte.

Inlägg av sodjan »

Om du menar interrupt *vector*, så ja.
Om du menar interrupt *source*, så nej.

Inget problem alls, även om vektoriserade interrupt beroende
på interruptkällan också kan vara trevligt...
Nerre
Inlägg: 27257
Blev medlem: 19 maj 2008, 07:51:04
Ort: Upplands väsby

Re: Knappar fungerar inte.

Inlägg av Nerre »

Ah, jag har aldrig pysslar med annat än vektoriserad interrupt. Blir det inte väldigt omständligt med bara en vektor? Man skriver ett program som använder en interrupt. Sen ska man utöka med en till, då räcker det inte med att skriva en ny interrupt-hanterare utan man måste in i den första hanteraren och göra tillägg?

Och det måste bli svårt att hooka befintliga interrupt-hanterare också?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Knappar fungerar inte.

Inlägg av sodjan »

> Blir det inte väldigt omständligt med bara en vektor?

Nej.

> Sen ska man utöka med en till, då räcker det inte med att skriva en ny interrupt-hanterare
> utan man måste in i den första hanteraren och göra tillägg?

Eftersom det inte finns någon "första" hanterare så är frågan inte riktigt rellevant... :-)

> Och det måste bli svårt att hooka befintliga interrupt-hanterare också?

Jag vet inte vad "befintlig" syftar på här. Det finns som sagt bara en.

Det man gör är något i stil med :

Kod: Markera allt

void interrupt()
{
     if(INTCON.INTF == 1)
     {
           call int_interrupt_manager()
     }

     if(INTCON.RXIF == 1)
     {
           call USART_RX_interrupt_manager()
     }

     if(INTCON.T0IF == 1)
     {
           call Timer0_interrupt_manager()
     }
}
Eller något i den stilen...
Skriv svar