Monday, April 7, 2008

Let's C... Dissecting the codes

As a continuation to this blog entry, in this section, will start dissecting the C program to understand the what and why of the codes. The codes shown below for reference...

Okay, lets start.

As mentioned earlier, comments can use the // or /*...*/ format. Thus, line 1-3 are just comments line. It's good to start your program with comments on what the program is all about. After developing million lines of codes, you'll appreciate how short your memory span is...

the main() function
All complete C program MUST have what's call a main() function. When CPU is ready for execution (main CPU clock is stable), it will execute the first line in the main() function. The format of the main() function is as follows:

void main(){
//your codes here

The void means the main() function doesn't return any value when it exit (finish running). In normal PC programming, some software needs to inform the operating system something such as error code when it exit. This doesn't apply to microcontroller.

The curly braces are to signify the block of codes belonging to main().
Do take note that you MUST NOT put a semicolon after the closing brace.

the Setup needed for PIC
Line 6: TRISB = 0b1100000; //Set PortB to all output
As pointed by 9W2GU, the comment is wrong... it should say pin 6 & 7 as inputs, remaining are output.

TRISB is a special function register of PIC used to control the direction of PORTB. If the bit is set (1) then the corresponding pin of PORTB is configured as input otherwise it will be configured as output. By default, all ports pins are configured for input on power up.

As you can see, using binary format make coding easier as you can see which pin is configured for what. In C, binary numbers are preceded by 0b, hexadecimal numbers by 0x, octal numbers by 0. Other numbers (starting with 1 to 9) are considered as decimal. Thus 0b10101010 = 0252 = 170 = 0xAA in binary, octal, decimal and hexadecimal.

Also take note that the line ends with a semicolon (;). This is the syntax of C language. All statement MUST ends with semicolon. Since the compiler ignore white spaces (as well as carriage returns and line feed characters), the semicolon serve to tell the compiler where a statement ends.

the Setup needed for MikroC
Line 7: Sound_Init(&PortB, 0);
This line is needed for us to use the Sound_Play() function later in the program. Open MikroC help and search for Sound in the index. The functions and how to use it are explained there. In this example, we specify that we want sound to be generated on PORTB, pin 0.

This is an example of a library function. The capabilities is provided by MikroC, not PIC directly. MikroC will create the necessary PIC codes to perform the functions thus making our lives a lot easier.

the while(expr) section, line 8 to 15
the while statement is used to execute a block of codes bounded by the opening and closing braces. The codes will execute and loop for as long as the expr expression evaluate to true. In C, anything that is not zero (0) is true. Thus, in this example, since we used while(1), the expr will always be true, thus the codes within the braces will execute indefinitely... infinite loop.

Do take note that the expr is evaluated when the while statement is first encountered and re-evaluated after the last statement in the block is executed. Thus, the while statement can be used to execute a block of code while certain condition is true.

The while statement can also be a one liner such as while(PORTA.F0==1);
In the above example, the while statement will continue until PORTA pin 0 is pulled to the ground. It's normally used to wait for a key to be pressed.

The above example also bring up another very important C syntax...
the = sign is used for assignment. Thus when we write TRISB = 0b11000000; the compiler will assign TRISB the value of 0b11000000
the == sign is used for comparison. Thus when we write PORTA==0xFF we are asking the compiler to check if the value of PORTA is equal to 0xFF or not. If equal then the expression is true otherwise will be set as false.
A very common error is using = instead of == in conditional testing.
Using = alone will result in the expression always evaluating to true...

the Actual codes... finally...
Line 9: PORTB = 0b00000010;
Here we are turning on pin 1 of PORTB. It effectively switching off the LED connected to the pin. Check the development board schematic to confirm this.

Line 10: delay_ms(400);
Another MikroC library function. It causes the PIC to wait for 400 milliseconds.

Line 11: PORTB = 0b00000100;
Let's switch off pin 1 and switch on pin 2 to get the alternating blinking LEDs on pin 1 & 2.

Line 12: delay_ms(400);
Wait for 400 milliseconds again. Without this delays, the LEDs will appear to lit continuously, because the on and off cycle to tooooo fast for the eyes to detect.

the Conditional test
Line 13: if (PORTB.F7==0) Sound_Play(1000,200);
Line 14: if (PORTB.F6==0) Sound_Play(1100,200);
Okay, remember the Sound_Init() line above? If you notice, there's no port or pin information in Sound_Play() function. It uses the information provided via the Sound_Init().

In these two lines, we do what's call conditional testing. We use the if statement... normal format as follows:
//execute if expr evaluate to true
//execute if expr evaluate to false

Just as the while() statement, if statement can also be one liner. Format is
if(expr) statement;

In the example above, we are checking if PORTB pin 6 or 7 are pressed. If pressed (0), then PIC execute the Sound_Play() function otherwise, PIC continue with the next statement.

After execution of line 14, PIC will re-evaluate the while() statement. Since the statement is true, PIC will loop back to line 9 and the process continue until you pull the plug...

How's the first lesson... ready to give up yet? Hang in there... there's more torture in the subsequent lessons... With the few statements already explained above, you're ready to embark on your initial exploration... Look into what library functions provided by MikroC... commonly used functions are there...

Okay, forgot to mention earlier... MikroC already predefines the PIC registers based on the CPU selected when you create new project. The register names are identical to the one used in the datasheet... eg, PORTA, PORTB, TRISA, ADCON1, ANSEL, etc.

Also, to refer to a single pin of any port, you can use the .Fn format. Thus PORTA.F0 refer to PORTA, pin 0 whereas PORTE.F1 refer to PORTE pin 1.

No comments: