1. ActivePower

    Thread Starter Member

    Mar 15, 2012
    155
    23
    I have recently started reading on interrupts properly to optimize my code and to prepare for my next project on DC motor control.

    To start with, I thought I'd write a small piece of code which increments a counter by 1 every time the motor completes a revolution. I am using the INT interrupt feature of the PIC16F877A and while the interrupt works correctly (I assume. I had an LED glow ON and OFF on each call), it would be nice if I could display the value of the counter on an LCD for debugging/measurement.

    I had written a LCD module for a previous project and it worked fine then. However, in conjugation with the interrupt the LCD doesn't seem to be able to display anything yet (in Proteus).

    As the LCD routines are working fine (I checked again) and so does the interrupt, could there be any speed issues (is the interrupt occuring too fast to allow the LCD to display/update any values?

    Here's the code:


    Code ( (Unknown Language)):
    1. //main.c
    2. //Measure speed of a DC motor using a position encoder
    3.  
    4. #include <htc.h>
    5. #include "lcd.h"
    6.  
    7. #define _XTAL_FREQ 200000
    8.  
    9. __CONFIG (FOSC_HS & WDTE_OFF & PWRTE_OFF & BOREN_OFF & LVP_OFF & CPD_OFF & CP_OFF & WRT_OFF);
    10.  
    11. #define MOTOR_POS RD3
    12. #define MOTOR_NEG RD4
    13. #define LED RD5
    14.  
    15. #define COMPLEMENT(x) x=~x
    16.  
    17. volatile double counter;
    18.  
    19. void interrupt ISR()
    20. {
    21.     if(INTF)
    22.     {
    23.         __delay_us(500);
    24.         COMPLEMENT(LED);
    25.         counter++;
    26.         INTF=0;
    27.     }  
    28. }
    29.  
    30.  
    31.  
    32. void init()
    33. {
    34.     LCD_Init();
    35.     INTCON=0x10;            //set INT interrupt enable bit
    36.     OPTION_REG=0x80;                //Pullups enabled and rising edge triggering
    37.     TRISB=0xFF;         //configure as inputs
    38.     TRISD=0x00;
    39.     TRISC=0x00;
    40. }
    41.  
    42. void move_forward()
    43. {
    44.     MOTOR_POS=1;
    45.     MOTOR_NEG=0;
    46. }
    47.  
    48. void main()
    49. {
    50.     counter=0;
    51.     init();
    52.     ei();                   //Global interrupt enable macro
    53.     while(1)
    54.     {
    55.         move_forward();
    56.         LCD_Write((char)counter+48);            //For debug only; write a proper integer to ascii routine later
    57.         __delay_ms(300);
    58.     }
    59. }
    Thanks!
     
  2. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    you really shouldn't use a delay in an interrupt... during this time, your uC can't do anything.... especially since the 16F doesn't have different priority interrupts... my bet is the delay...
     
  3. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,887
    1,016
    You should NOT be delaying inside the ISR. That is a huge amount of time. Remember everything else stops while the ISR is being processed.

    It is what is messing up your timing for your LCD.

    Take out the delay and either change the frequency of your timer and/or put in a counter and only process when the counter reaches X.
     
  4. ActivePower

    Thread Starter Member

    Mar 15, 2012
    155
    23
    I added the delay later to avoid any unwanted updates. Now that I think of it, it was a very stupid thing to do (its not a switch to debounce, after all). I tried removing the delay though and nothing has shown up on the LCD yet.
     
  5. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    you have your crystal frequency set to 200kHz, is this correct?

    ..though I don't think you could run this low in FOSC_HS mode....
     
  6. ActivePower

    Thread Starter Member

    Mar 15, 2012
    155
    23
    I am sorry that was a typing mistake. The crystal frequency is 20 MHz, I have edited it now.

    Here's the final code:

    Code ( (Unknown Language)):
    1. //main.c
    2. //Measure speed of a DC motor using a position encoder
    3.  
    4. #include <htc.h>
    5. #include "lcd.h"
    6.  
    7. #define _XTAL_FREQ 20000000
    8.  
    9. __CONFIG (FOSC_HS & WDTE_OFF & PWRTE_OFF & BOREN_OFF & LVP_OFF & CPD_OFF & CP_OFF & WRT_OFF);
    10.  
    11. #define MOTOR_POS RD3
    12. #define MOTOR_NEG RD4
    13. #define LED RD5
    14.  
    15. #define COMPLEMENT(x) x=~x
    16.  
    17. volatile double counter;
    18.  
    19. void interrupt ISR()
    20. {
    21.     if(INTF)
    22.     {
    23.         COMPLEMENT(LED);
    24.         counter++;
    25.         INTF=0;
    26.     }  
    27. }
    28.  
    29.  
    30.  
    31. void init()
    32. {
    33.     LCD_Init();
    34.     INTCON=0x10;            //set INT interrupt enable bit
    35.     OPTION_REG=0x80;                //Pullups enabled and rising edge triggering
    36.     TRISB=0xFF;         //configure as inputs
    37.     TRISD=0x00;
    38.     TRISC=0x00;
    39. }
    40.  
    41. void move_forward()
    42. {
    43.     MOTOR_POS=1;
    44.     MOTOR_NEG=0;
    45. }
    46.  
    47. void main()
    48. {
    49.     counter=0;
    50.     init();
    51.     ei();                   //Global interrupt enable macro
    52.     while(1)
    53.     {
    54.         move_forward();
    55.         LCD_Write(((char)counter+48));          //For debug only; write a proper integer to ascii routine later
    56.         __delay_ms(500);
    57.     }
    58. }
    Nothing yet though! :(
     
  7. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    You should try to remove the interrupt portion and ensure the LCD module works, since, you said you compiled it for a different project...
     
  8. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,394
    1,606
    Unless your motor is turning less then 300 RPM (or 5 Revs Per Second) you stand the chance of updating the display so frequently nothing gets seen. It may seem to work in a simulator but NOT in the real world.

    Somewhere in your main loop of code (ie, not inside the ISR) check the revs once or twice a second, and if a new value then update the LCD. Anything much quicker and you may just see a blur on the display.
     
  9. spinnaker

    AAC Fanatic!

    Oct 29, 2009
    4,887
    1,016

    Have you tried debugging the code? Is it ever reaching the code that writes to the LCD?
     
  10. ActivePower

    Thread Starter Member

    Mar 15, 2012
    155
    23
    I am sorry I could not follow up on this thread sooner. Finals are indeed a tough time for any productive work. :)

    I am trying to go through my LCD routine again and see if there is anything I might have missed. I'll get back as soon as I am done combing through it.

    Thanks for the replies.
     
  11. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    I would also have made it simple. By just writing a hello world message on the display. Just to be sure that part of the program works. In your current setting
     
    Last edited: Dec 11, 2012
  12. ActivePower

    Thread Starter Member

    Mar 15, 2012
    155
    23
    I got the program working! It was a very stupid mistake of not having enabled the TRIS registers before I initialized the LCD in my main program. Working on the ASCII conversion now.

    Thanks everyone for the useful help :)
     
  13. tshuck

    Well-Known Member

    Oct 18, 2012
    3,531
    675
    Glad to hear it, though we probably could have gotten there sooner if you had posted what LCD_Init(); did.:p

    I had assumed that it simply set up ports, obviously I, instead, managed to make a donkey out of us....
     
  14. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,394
    1,606
    You should have those in your libraries. Look for atoi() (ASCII to int) or itoa() (int to ASCII). atoi() lives inside stdlib.h, and in some versions so does itoa(), but that is so simplemany people just make their own (or copy code off the web).
     
Loading...