PIC Micro-controller (S.O.S.)

Discussion in 'Programmer's Corner' started by friskyy, May 5, 2011.

  1. friskyy

    Thread Starter New Member

    Mar 27, 2011
    13
    0
    I'm just starting with micro-controllers, so I would like to ask someone more advanced if the code that I've written for these 2 tasks is feasible. It is for the PIC16F917 MICROCONTROLLER
    Thank you for your time :)


    Task 1
    Use port D of the PIC16F917A as an output port, write a simple program to control 8 LEDS to generate the binary-equivalent of the following decimal numbers:

    119, 76, 14, 55 & 99


    CODE:

    #include <htc.h>

    __CONFIG(UNPROTECT & BORDIS & PWRTEN & WDTDIS & INTIO & MCLREN & FCMDIS & IESODIS);

    #define _XTAL_FREQ 8000000

    void init(void)
    {
    // port directions: 1=input, 0=output
    TRISD = 0x00;


    // 8Mhz Internal Clock
    OSCCON = 0b01110000;

    // Clear PORTD
    PORTD = 0x00;

    }

    void main(void)
    {
    init();
    start:

    RD0=1;
    RD1=1;
    RD2=1;
    RD5=1;
    RD6=1;
    RD7=1;


    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(20);

    PORTD = 0x00;
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(20);

    RD2=1;
    RD3=1;
    RD6=1;

    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(20);

    PORTD = 0x00;
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(20);

    RD1=1;
    RD2=1;
    RD3=1;

    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(20);

    PORTD = 0x00;
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(20);

    RD1=1;
    RD2=1;
    RD4=1;
    RD5=1;

    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(20);

    PORTD = 0x00;
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(20);


    RD0=1;
    RD1=1;
    RD5=1;
    RD6=1;


    goto start;
    }




    Taks 2

    Use a switch as an input to read the status of bit 0 of port A, write a program to switch all odd numbered LEDs (the most right hand LED is number 0) connected to port D, upon detecting the switch closure.
    #include <htc.h>

    __CONFIG(UNPROTECT & BORDIS & PWRTEN & WDTDIS & INTIO & MCLREN & FCMDIS & IESODIS);

    #define _XTAL_FREQ 8000000

    void init(void)
    {
    // port directions: 1=input, 0=output
    TRISD = 0x00;
    TRISA = 0xFF;

    // 8Mhz Internal Clock
    OSCCON = 0b01110000;


    // Clear PortD
    PORTD = 0x00;

    // Turn off comparators
    CMCON0 = 0x07;

    //Turn off ADC
    ANSEL = 0x00;


    }
    void main(void)
    {

    init();
    start:

    while (1){ while(RA0) //Wait while switch off
    { __delay_ms(1); } //Debounce switch
    while(!RA0) //Wait while switch on
    { __delay_ms(1); } //Debounce switch


    // Switch ON PORTD

    PORTD = 0b010101010;

    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(20);

    PORTD = 0x00; // XOR (Flip) PORTD


    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(98);
    __delay_ms(20);

    goto start;
    }
    }
     
  2. DumboFixer

    Active Member

    Feb 10, 2009
    219
    34
    To avoid all those sequences of delay statements, either make ir one longer statement or put them all into their own function/procedure and call that instead - it'll make the code much more readable.

    Get rid of that "goto", use a while loop instead - much neater :)

    Did you mean to have a blank display between each sequence ?

    Would it be more readable if you did something like PORTD = 55 instead of setting individual bits ?
     
  3. RiJoRI

    Well-Known Member

    Aug 15, 2007
    536
    26
    As DumboFixer implied, let the compiler do the hard work.

    Task 1:
    Instead of diddling each bit of Port D, just load the port with the desired decimal number. The compiler will fix it for you.

    Also, you should be able to call __delay_ms with a parameter of 1000:
    __delay_ms(1000);

    And before writing code, write your comments. You MUST have comments! Your teacher may not insist on them (Shame!) but if you get into the habit now, you'll be grateful later. And do NOT have comments like:
    PORTD = 0x00; // Clear PortD

    Yeah, why are you telling me what the code has told me? Tell me WHY you are clearing PortD:
    PORTD = 0x00; // Turn LEDs OFF.

    Task 2:
    At the top of the editing window there is a '#' icon. Use it to enter your code.
    Code ( (Unknown Language)):
    1.  
    2. while (1)
    3. {
    4.     while(RA0) //Wait while switch off
    5.     {
    6.         __delay_ms(1);
    7.     } //Debounce switch
    8.     while(!RA0) //Wait while switch on
    9.     {
    10.         __delay_ms(1);
    11.     } //Debounce switch
    12. // more code
    13. }
    14.  
    Also note how indenting the code makes it easier to understand. Again, the "goto" is not needed, and will probably cost you points!

    Look up "switch debouncing." Your algorithm shows you are a little hazy on the basics of switch bouncing and how to correct for it.

    I really cannot say what the compiler will do with this:
    PORTD = 0b010101010;

    At best, it will complain; at worst it will truncate the last zero. I find doing something like this to help:
    // 76543210
    PORTD = 0b10101010;

    Also try to avoid "magic numbers" such as "0b010101010" -- once you get into the real world, you'll come across things like, "Sorry, the specs have changed; instead of all ODD bits turned on, all EVEN bits will need to be turned on." Now try looking for that pattern through 60 files, making sure it's what you want, and changing it.

    Code ( (Unknown Language)):
    1.  
    2. #define LEDS_ON 0b10101010  // Turn on ODD LEDs
    3.                      :
    4.                      :
    5.                      :
    6. PORTD = LEDS_ON;
    7.  
    will make your life a LOT easier!


    Good luck! Keep plugging away -- someday it will all gel, and you'll find yourself helping another newcomer to microcontroller programming!

    --Rich
     
  4. t06afre

    AAC Fanatic!

    May 11, 2009
    5,939
    1,222
    Just a lilitle warning about this. If you use an older version of the HI-Tech C compiler. This will not work. It was fixed in version 9.70 or 9.71 (not sure)
    The current version is 9.81 I think.
    You can download the latest version for free (lite mode) here
    http://www.microchip.com/stellent/i...deId=1406&dDocName=en534868&page=wwwCompilers
     
  5. friskyy

    Thread Starter New Member

    Mar 27, 2011
    13
    0
    Thank you for the response. Obviously you know what you are doing. Could you write me the whole code for these two tasks. That would be hugely appreciated.
     
  6. RiJoRI

    Well-Known Member

    Aug 15, 2007
    536
    26
    Sure I could. But, (1) you will learn nothing, except how to read my code, and, (2) I charge US$150 per hour for coding. (TANSTAAFL!)

    I -- and others here -- can check your code, and make suggestions, but the only way to learn is to do it yourself. Just like learning to walk.

    --Rich
     
  7. friskyy

    Thread Starter New Member

    Mar 27, 2011
    13
    0
    Ok then. I don't really have the passion for microcontrollers and programming at this stage, its a tiny bit from my degree( mech. eng) but I'll do my best.

    I started again using microC Pro and PIC Simulator IDE to test the code.
    Task 1 is asking me to generate the binary-equivalent of the following decimal numbers:

    119, 76, 14, 55 & 99

    So, by writing the code below I can generate the output of 119-several leds blink continuosly. Now, if I want to generate the same effect for the other decimal numbers and add all that in the same program what operator should I use?

    void main() {
    TRISB=0; //MAKING PORT B OUTPUT
    while (1) {
    PORTB = 0x77; //Make port B high
    delay_100ms; //maintain portb as high for 100ms
    PORTB = 0x00; //Make port b low
    delay_100ms; //maintain port b as low for 100ms
    }
     
  8. DumboFixer

    Active Member

    Feb 10, 2009
    219
    34
    No operator as such is needed. All you need to do is replicate
    Code ( (Unknown Language)):
    1. PORTB = 0x77; //Make port B high
    2. delay_100ms;   //maintain portb as high for 100ms
    3. PORTB = 0x00; //Make port b low
    4. delay_100ms;  //maintain port b as low for 100ms
    for the other numbers as well.

    If you wanted to go one stage further you could write a small procedure called something like show that will display your number, pause, blank the LEDs and pause again, giving you something like

    Code ( (Unknown Language)):
    1.  
    2. show(119);
    3. show(76);
    4. show(14);
    5. // etc
    This way if you decide to change the delay you only need to do it inside "show".

    Another way is to declare an array and put the numbers in the array and have a for loop go through the array.

    Just a few thoughts for you to consider
     
  9. friskyy

    Thread Starter New Member

    Mar 27, 2011
    13
    0
    Thx for the suggestion.
    Would you that this is correct for task 2 :

    void init(void)
    {
    // port directions: 1=input, 0=output
    TRISD = 0x00;
    TRISA = 0xFF;

    // 8Mhz Internal Clock
    OSCCON = 0b01110000;


    // Clear PortD
    PORTD = 0x00;


    // Turn off comparators
    CMCON0 = 0x07;

    //Turn off ADC
    ANSEL = 0x00;




    }

    char counter;
    void main(void)
    {

    init();

    while (1){ while(RA0) //Wait while switch off
    { __delay_ms(1); } //Debounce switch while(!RA0) //Wait while switch on
    { __delay_ms(1); } //Debounce switch

    counter = 0;

    // Switch ON PORTD

    PORTD = 0xF0; // XOR (Flip) PORTD

    //1 second delay rotuine
    while (counter < 10) {
    __delay_ms(98);
    counter = counter + 1;
    }
    __delay_ms(20);

    // Clear PortD

    // Switch OFF PORTD

    PORTD = 0xF0;

    //1 second delay rotuine
    while (counter < 10) {
    __delay_ms(98);
    counter = counter + 1;
    }
    __delay_ms(20);

    }
    }
     
  10. DumboFixer

    Active Member

    Feb 10, 2009
    219
    34
    Firstly, please put your code in code tags (it's the # just about the text input box - it makes reading code easier. thanks

    The line
    Code ( (Unknown Language)):
    1. PORTD = 0xF0;     // XOR (Flip) PORTD
    does not flip Port D. It sets the upper 4 bits to 1 and the lower 4 bits to 0.

    Code ( (Unknown Language)):
    1. void init(void)
    2. {
    3.     // port directions: 1=input, 0=output
    4.     TRISD = 0x00;
    5.     TRISA = 0xFF;
    6.    
    7.     // 8Mhz Internal Clock
    8.     OSCCON = 0b01110000;
    9.    
    10.    
    11.     // Clear PortD
    12.     PORTD = 0x00;
    13.  
    14.  
    15.     // Turn off comparators
    16.     CMCON0 = 0x07;
    17.  
    18.     //Turn off ADC
    19.     ANSEL = 0x00;
    20.  
    21.  
    22.  
    23.  
    24. }
    25.    
    26. char counter;
    27. void main(void)
    28. {
    29.  
    30.     init();
    31.    
    32.     while (1){    
    33.          while(RA0)      //Wait while switch off
    34.                          {  __delay_ms(1);  }     //Debounce switch    
    35.       while(!RA0)  //Wait while switch on
    36.            {  __delay_ms(1);  }     //Debounce switch
    37.  
    38.      counter = 0;
    39.  
    40.       // Switch ON PORTD
    41.  
    42.      PORTD = 0xF0;     // XOR (Flip) PORTD
    43.  
    44.      //1 second delay rotuine
    45.                  while (counter < 10) {
    46.          __delay_ms(98);
    47.          counter = counter + 1;
    48.               }
    49.       __delay_ms(20);
    50.  
    51.       // Clear PortD
    52.  
    53.       // Switch OFF PORTD
    54.  
    55.       PORTD = 0xF0;
    56.  
    57.        //1 second delay rotuine
    58.                    while (counter < 10) {
    59.                             __delay_ms(98);
    60.                         counter = counter + 1;
    61.                }
    62.        __delay_ms(20);
    63.  
    64.     }
    65. }    
    66.  
    The switch debounce won't work properly. I'd be tempted to use a bigger delay once the switch leading edge is detected and ignore any bounces.

    To turn on all the odd LED's you may want to have a look at the binary patterns for 0x55 and 0xAA.
     
    Last edited: May 12, 2011
  11. RiJoRI

    Well-Known Member

    Aug 15, 2007
    536
    26
    Green tells what's happening, Red is my comments.
    Code ( (Unknown Language)):
    1.  
    2. 01  while (1) [COLOR="SeaGreen"]// LOOP forever[/COLOR]
    3. 02  {
    4. 03      while(RA0) [COLOR="SeaGreen"]// WHILE RA0 is HI[/COLOR]
    5. 04      {
    6. 05          __delay_ms(1); [COLOR="SeaGreen"]// Wait[/COLOR]
    7. 06      }
    8. 07      [COLOR="Red"]/* RA0 has gone low. */[/COLOR]
    9. 08      {
    10. 09          __delay_ms(1); [COLOR="SeaGreen"]// Wait 1 mSec[/COLOR]
    11. 10      }
    12. 11      [COLOR="Red"]/* Clearing the counter should be just before the while() loop. */[/COLOR]
    13. 12      counter = 0;
    14. 13      [COLOR="Red"]/* What is this supposed to do? */[/COLOR]
    15. 14      PORTD = 0xF0; [COLOR="SeaGreen"]// Send b'111000 out Port D[/COLOR]
    16. 15      [COLOR="Red"]/* This could be done with a for() loop */[/COLOR]
    17. 16      while (counter < 10) [COLOR="SeaGreen"]// Wait 980 mSec[/COLOR].
    18. 17      {
    19. 18          __delay_ms(98);
    20. 19          counter = counter + 1;
    21. 20      }
    22. 21      [COLOR="Red"]/* counter is now == 10 */[/COLOR]
    23. 22      __delay_ms(20); [COLOR="SeaGreen"]// Wait another 20 mSec.[/COLOR]
    24. 23
    25. 24      [COLOR="Red"]/* What is this supposed to do? It does NOT change anything from Line 14 */[/COLOR]
    26. 25      PORTD = 0xF0;    [COLOR="SeaGreen"]// Send b'111000 out Port D[/COLOR]
    27. 26      [COLOR="Red"]/* counter == 10. This loop will never execute */[/COLOR]
    28. 27      while (counter < 10)    [COLOR="SeaGreen"]// Wait 980 mSec.[/COLOR]
    29. 28      {
    30. 29          __delay_ms(98);
    31. 30          counter = counter + 1;
    32. 31      }
    33. 32      __delay_ms(20); [COLOR="SeaGreen"]// Wait another 20 mSec.[/COLOR]
    34. 33
    35. 34  }
    36.  
    If you stick a scope on a mechanical switch (with current applied to the switch, of course!) and open or close the switch, you will see the switch bouncing -- it closes and opens repeatedly. Lines 3 through 6 wait for the input signal to go HI; Lines 8-10 just delay one millisecond. But if the bouncing up and down goes on, you will be in trouble. Maybe not with this code, but definitely later on.

    Lines 27-31 will never execute -- You need to re-initialize counter!

    Finally, when you loop back to while(1), the switch input is still LO! You may want to add code to wait for the switch to go back HI.

    --Rich
     
  12. friskyy

    Thread Starter New Member

    Mar 27, 2011
    13
    0
    Thx for the suggestion I used 0x55 to flash the odd LEDs only.
    Could you explain what is switch leading edge and how to ignore bounces. Why isn't one second enough for the delay?

    Code ( (Unknown Language)):
    1.  
    2. char counter;
    3. void main(void)
    4. {
    5.  
    6. init();
    7.        
    8. while (1)
    9.  
    10. {while(RA0)                          
    11. {  __delay_ms(1);  }              
    12. {  __delay_ms(1);  }        
    13.  
    14.         counter = 0;
    15.  
    16.         PORTD = 0x55;        
    17.  
    18.            //1 second delay routine
    19.                         while (counter < 10) {
    20.                                 __delay_ms(98);
    21.                         counter = counter + 1;
    22.                 }
    23.                                 __delay_ms(20);
    24.  
    25.                 // Clear PortD
    26.  
    27. // Switch OFF PORTD
    28.  
    29.                 PORTD = 0x00;
    30.  
    31.                 //1 second delay rotuine
    32.                         while (counter < 10) {
    33.                                 __delay_ms(98);
    34.                         counter = counter + 1;
    35.                 }
    36.                                 __delay_ms(20);
    37.  
    38.         }
    39. }            
     
  13. friskyy

    Thread Starter New Member

    Mar 27, 2011
    13
    0
    How to re-initialize counter? I don't understand why does the switch have to go high at the end? The task is asking to switch the LEDs upon detecting the switch closure.
     
Loading...