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

Thread Starter

friskyy

Joined Mar 27, 2011
13
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;
}
}
 

DumboFixer

Joined Feb 10, 2009
217
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 ?
 

RiJoRI

Joined Aug 15, 2007
536
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.
Rich (BB code):
while (1)
{ 
	while(RA0) //Wait while switch off
	{ 
		__delay_ms(1); 
	} //Debounce switch
	while(!RA0) //Wait while switch on
	{ 
		__delay_ms(1); 
	} //Debounce switch 
// more code
}
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.

Rich (BB code):
#define LEDS_ON 0b10101010  // Turn on ODD LEDs
                     :
                     :
                     :
PORTD = LEDS_ON;
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
 

t06afre

Joined May 11, 2009
5,934

Thread Starter

friskyy

Joined Mar 27, 2011
13
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.
Rich (BB code):
while (1)
{ 
	while(RA0) //Wait while switch off
	{ 
		__delay_ms(1); 
	} //Debounce switch
	while(!RA0) //Wait while switch on
	{ 
		__delay_ms(1); 
	} //Debounce switch 
// more code
}
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.

Rich (BB code):
#define LEDS_ON 0b10101010  // Turn on ODD LEDs
                     :
                     :
                     :
PORTD = LEDS_ON;
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
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.
 

RiJoRI

Joined Aug 15, 2007
536
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.
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
 

Thread Starter

friskyy

Joined Mar 27, 2011
13
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
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
}
 

DumboFixer

Joined Feb 10, 2009
217
No operator as such is needed. All you need to do is replicate
Rich (BB code):
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
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

Rich (BB code):
show(119);
show(76);
show(14);
// 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
 

Thread Starter

friskyy

Joined Mar 27, 2011
13
No operator as such is needed. All you need to do is replicate
Rich (BB code):
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
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

Rich (BB code):
show(119);
show(76);
show(14);
// 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
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);

}
}
 

DumboFixer

Joined Feb 10, 2009
217
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
Rich (BB code):
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.

Rich (BB code):
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);

    }
}
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:

RiJoRI

Joined Aug 15, 2007
536
Green tells what's happening, Red is my comments.
Rich (BB code):
01	while (1) // LOOP forever
02	{ 
03		while(RA0) // WHILE RA0 is HI
04		{
05			__delay_ms(1); // Wait
06		} 
07		/* RA0 has gone low. */
08		{ 
09			__delay_ms(1); // Wait 1 mSec
10		}
11      /* Clearing the counter should be just before the while() loop. */
12		counter = 0;
13		/* What is this supposed to do? */
14		PORTD = 0xF0; // Send b'111000 out Port D
15		/* This could be done with a for() loop */
16		while (counter < 10) // Wait 980 mSec.
17		{
18			__delay_ms(98);
19			counter = counter + 1;
20		}
21		/* counter is now == 10 */
22		__delay_ms(20); // Wait another 20 mSec.
23
24		/* What is this supposed to do? It does NOT change anything from Line 14 */
25		PORTD = 0xF0;	 // Send b'111000 out Port D
26		/* counter == 10. This loop will never execute */
27		while (counter < 10)	// Wait 980 mSec.
28		{
29			__delay_ms(98);
30			counter = counter + 1;
31		}
32		__delay_ms(20); // Wait another 20 mSec.
33
34	}
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
 

Thread Starter

friskyy

Joined Mar 27, 2011
13
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
Rich (BB code):
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.

Rich (BB code):
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);

    }
}
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.
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?

Rich (BB code):
char counter;
void main(void)
{

init();
        
while (1)

{while(RA0)                           
{  __delay_ms(1);  }              
{  __delay_ms(1);  }        

        counter = 0;

        PORTD = 0x55;         

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

                // Clear PortD

// Switch OFF PORTD

                PORTD = 0x00;

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

        }
}
 

Thread Starter

friskyy

Joined Mar 27, 2011
13
Green tells what's happening, Red is my comments.
Rich (BB code):
01	while (1) // LOOP forever
02	{ 
03		while(RA0) // WHILE RA0 is HI
04		{
05			__delay_ms(1); // Wait
06		} 
07		/* RA0 has gone low. */
08		{ 
09			__delay_ms(1); // Wait 1 mSec
10		}
11      /* Clearing the counter should be just before the while() loop. */
12		counter = 0;
13		/* What is this supposed to do? */
14		PORTD = 0xF0; // Send b'111000 out Port D
15		/* This could be done with a for() loop */
16		while (counter < 10) // Wait 980 mSec.
17		{
18			__delay_ms(98);
19			counter = counter + 1;
20		}
21		/* counter is now == 10 */
22		__delay_ms(20); // Wait another 20 mSec.
23
24		/* What is this supposed to do? It does NOT change anything from Line 14 */
25		PORTD = 0xF0;	 // Send b'111000 out Port D
26		/* counter == 10. This loop will never execute */
27		while (counter < 10)	// Wait 980 mSec.
28		{
29			__delay_ms(98);
30			counter = counter + 1;
31		}
32		__delay_ms(20); // Wait another 20 mSec.
33
34	}
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
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.
 
Top