Welcome, Guest
Username: Password: Secret Key Remember me

TOPIC: MPLAB C18 Tutorial - Setting up a new C18 project and creating an application

Re: MPLAB C18 Tutorial - Setting up a new C18 project and creating an application 10 years 3 months ago #15242

Setting up a new C18 project and creating an application

Last updated November 28, 2009 (11.28.09)

This tutorial will show you how to create and configure a new C18 project and then how to create an application within that project. The application is a simple one, well, at least it is at first. Yes, the typical and all-so-popular LED blinking application. What is great about this simple objective is that there are so many ways to do it! At first we will use a simple loop, then we will make use of some basic and specialized software and hardware libraries to add features and special abilities. We will eventually make use of interrupts, timers, even the PWM peripheral to 'enhance' our LED blinking application. Finally, we will conclude by adding RS-232 communication with a PC terminal program so we can control the operation of the LED blinker.

Download the MPLAB IDE installer here: MPLAB IDE

Download the MPLAB C18 Compiler installer here: MPLAB C18 Compiler

The article does not end here! Either view all pages, click next for each sequential page or click on the subject headings on the article index (located on the right) to continue.




Preface

I am not a C18 pro, nor am I a pro in C at all. What I have learned has been based on C18 and my needs to write more complex structured applications more easily than I could in assembly. I am not saying that C is better than Swordfish, or any of the other languages/compilers out there. I'm sure they all have their features and benefits. I do know however that C is widely accepted and supported and it doesn't hurt to learn a thing or two about the language.

With that said, my tutorials WILL work albeit maybe not with the most efficient way. As I learn more I will update my tutorials to include fresher approaches and ideas. I'm always open to suggestions and will include valid input in my tutorials.

Also, please bare with me as I try to find a format that is appealing. I'm pretty new at this sort of thing, and digital-diy has put an amazing amount of support formatting tools at our disposal so I'm trying to get a feel for all of it.

- Hop

 


Project Notes


It is assumed that you know how to install MPLAB with C18 support. A tutorial is forthcoming but there is a lot of instruction out there to follow. Also, this tutorial is written for the 18F452. It will work with any 18xxx series PIC micro controller, but the configuration bits of each individual device vary so if you are using a different device, you will need to make adjustments accordingly.

I prefer to have a separate header file in the project folder to handle the configuration bits, and I reference it in my main code via;



#include "p18f452 ConfigBits.h"



Configuration bits can be set in your main code but I feel this approach is cleaner.

 


Setting up the project folder structure for the application





PLEASE NOTE!

If you would rather handle the configuration bits in your main code instead of a separate header file, you will need to ommit the above line of code from the tutorial main code and include the ...






#pragma config



... lines manually. A quick study of the file p18f452 ConfigBits.h should give you adequate information so you can do them manually. See the datasheet for your particular device for information as to what adjustments need to be made. Later on in the tutorial, I've included my pragma directives for the configuration bits related to the 18F452.




Create a folder somewhere close to the root of whatever drive you select. For my projects, I created a subfolder of one of my Linux system drives called "mcu". You can pick any drive in Windows as well, but again, keep it close to the root, I.E. "C:mcu". The reason for this is that MPLAB use to and may still have a problem with long path names. Keeping your project folder short and sweet and close to the root helps to keep that path name small. To further help that process, keep your individual project folder names small as well. For this project, I advise creating the "mcu" folder, then create a sub-folder in "mcu" called "blink_led". When completed you should have a project folder path like "C:mcublink_test".

 


Files used for a project

You may notice some C18 projects that have a lot of files associated with them. For this project, at least at first, we will keep it fairly simple. Most of any library files you will need will be part of the MPLAB IDE and C18 installation, but there might be a time when you will use one or more custom libraries. You can include them in the project folder, and include them in the C file you write, but the context they are addressed is different. I'll explain further later on in this tutorial.

We will be using one file that needs to be in your project folder. The file is a header file. Please be sure to read the note above about using this file. This file will contain the pragma statements for your device's configuration bits. The included file with this tutorial is for a 18F452. At this point, either copy that file to your project folder, create one yourself, or remember to write them into your main code later.

 

It is coming later on. You are not ready for this step yet. All this ruckess is about taking a large block of code out of your main file and putting it in another file to include in your main program. It makes things cleaner but we will address it later on, I promise. I lined out the text related to this so just move forward.

 


Creating a new project


Once you have the IDE installed, run it.

First thing we will do is create a new project.





Figure 1 - MPLAB IDE and its Project Wizard



 






On the Project Wizard, click

Step One.



 

Step One dialog window, select your device. Again please notice in figure 2 that 18F452 is selected for this tutorial.










Figure 2 - Project Wizard Step One: Select a Device




 




Once you selected your device, click

Step Two.



 



Here is where you select your Active Toolsuite. Make sure Microchip C18 Toolsuite is selected in the Active Toolsuite window. For me it was selected by default.










Figure 3 - Project Wizard Step Two: Select an Active Toolsuite



 




Click

Step Three.



 

For now, we will use this step to create a new project file. This is where it gets a bit tricky so please make sure you follow these steps carefully. Make sure the option to Create New Project File is selected. Once that is done, the field under that option will show the project file name. As you can see in Figure 4, there is only a file name with no extension and no path information. This is very important because if the path information is left out, the project file could be created in another location other than where we want it. This is where the folder structure we created earlier becomes important and where we will tell the project that the project file needs to be in that location.

It can be done with either of two ways. You can manually type in the path before the file name OR you can use the browse button to have the wizard help you find that location and build the path for you.










Figure 4 - Project Wizard Step Three: Create a New Project




 




Clicking







Figure 5 - Project Wizard Step Three: Save Project As dialog window




Notice in Figure 5 the folder structure I mentioned earlier. Remember that we are trying to keep the path as short as possible, which is why I created a folder structure close to the root.

Also please note this is on my system where I keep all my projects on a Linux network share. For beginners, or single system users, creating the mcu folder on their Windows install drive is quite alright, I.E. "C:MCU".

 










Figure 6 - Project Wizard Step Three: Save Project As dialog window




 




Once you selected the proper folder, enter the file name as seen in Figure 6 and click






Figure 7 - Project Wizard Step Three: Path is now included




 




Click

Step Four.



 

Since this is our first project, there are not any existing files we need to add to our project. It's worthy to note however that this step is very useful for future projects. For example, if you happen to write a header file that sets your configuration bits and are developing multiple projects for the same device, you can add that file to new projects without rewriting them. I use this technique extensively for all my projects which helps when you want to use special features with a device and have written proven code in the past for those features. Some careful coding of these header files can make them perform like building blocks for future applications and help speed development.










Figure 8 - Project Wizard Step Four: Adding Files




 




Click

Summary.



 










Figure 9 - Project Wizard Summary




 




Review the summary then click

Configuring the project: Build Options - Search Paths


Now that the project is created, we need to configure a few things for the project to allow it to find some C18 included header, library, and linker files. This isn't configured by default, at least it never has been for me. The advantage of that is you can have complete containment of the project and its files, but since we are using some C18 included support files for our project, we need to expand C18's ability to find those files by configuring its search parameters.

At this point, it is important to know where you installed MPLAB and C18. I made it simple for my setup by installing C18 to a sub-folder off of the root of drive C in a sub-folder called MCC18. Three sub-folders inside this sub-folder called h, lib, and lkr are what we will be configuring our project to look at for support files.










Figure 1 - Configure build options for the project




On the MPLAB menu bar, click Project Build Options... Project to bring up the Build Options for Project "blink_led" dialog window.










Figure 2 - Build options dialog window for the project




 

Make sure the Build Directory Policy is set as illustrated in Figure 2, then click on the down arrow for the drop down combo control next to Show directories for: and select Include Search Path.










Figure 3 - Build options dialog window - Include Search Path







Once Include Search Path is selected, click


Figure 4.










Figure 4 - Build options dialog window - Adding a Include Search Path




 




Clicking on







Figure 5 - Browse for Include Search Path




 

Here is where you need to navigate to your C18 installation folder. For the include path, C18 assumes that you want the topmost folder of its installation. As we set the next two search paths for libraries and linker files, C18 will target those specific sub-folders. I am not sure why C18 prefers this, but I just went with it. Maybe because some include files are located in the example sub-folder and might need to be exposed to a search later.




Once you have MCC18h sub-folder targeted, click







Figure 6 - Build options dialog window - New Include Search Path added




 

As you did before (see Figure 3), click on the down arrow for the drop down combo control next to Show directories for: and select Library Search Path.

Follow the same process as you did to set the Include Search Path to set the Library Search Path. The sub-folder for this and the next step are located inside MCC18 and C18 should help you by automatically pointing to the proper sub-folder when you browse for it as instructed earlier.










Figure 7 - Browse for Library Search Path




 

As stated earlier, C18 SHOULD have lib already targeted for you.




Make sure lib is targeted and click







Figure 8 - Build options dialog window - New Library Search Path added




 

And finally, again as you did before (see Figure 3), click on the down arrow for the drop down combo control next to Show directories for: and select Linker-Script Search Path.

Follow the same process as you did to set the Include Search Path to set the Linker-Script Search Path. The sub-folder for this final step is located inside MCC18 and C18 should help you by automatically pointing to the proper sub-folder when you browse for it as instructed earlier.










Figure 9 - Browse for Linker Search Path




 

As stated earlier, C18 SHOULD have lkr already targeted for you.




Make sure lkr is targeted and click


lkr sub-folder.










Figure 10 - Build options dialog window - New Linker Search Path added




 

That concludes the build options configuration at this time.




On the main Build Options Project dialog window, click


Configuring your project: Selecting your programmer




WARNING! PLEASE READ!!! If you have your PICkit 2 connected to your computer AND you have it connected to your project on a breadboard, etc., and you DON'T want power supplied to it yet, make sure you disconnect the VDD output from the programmer prior to taking these next steps. The problem is, MPLAB has the PICkit 2 configured to connect automatically and apply power to the VDD line. This option can be turned off, but not prior to selecting it in MPLAB. This can be disastrous if your circuit isn't ready for power to be applied.

NOTE ABOUT SPECIFIC PROGRAMMER USAGE: As stated at the beginning of this tutorial, we are using the PICkit 2 programmer. Since that is the only MPLAB supported programmer I have ever used with this software, I cannot offer any additional information on other programmers used. To that end, the following images and instructions are for the PICkit 2.

After reading the above warning and note, we are ready to tell MPLAB what programmer we wish to use.

 

Before we do this, please note that there will be no other options for Programmer except Select Programmer until a programmer is selected. After a programmer is selected, the options for Programmer expand to allow many more options. Some of these will be disabled until the programmer is actually connected. With that said, let us get started.

On the MPLAB main menu, click Programmer / Select Programmer / PICkit 2 as seen in Figure 1.










Figure 1 - Select Programmer




 

Once you select a programmer (as in PICkit 2 for this tutorial) the options for Programmer expand. Chances are the programmer connected the moment you selected a programmer so you shouldn't see any disabled options. We'll change that in a moment, but for now you should see some more options as shown in Figure 2. Remember that the image assumes the programmer is NOT connected.










Figure 2 - Programmer Options




 

Click on Settings to set how the IDE handles your programmer. Set your settings to match this. Many of these settings are unclear as to their use. A search of official Microchip documents related to the PICkit 2, MPLAB IDE, and C18 turned up nothing to most of these settings. I have posts posted out there asking for information concerning these settings. I'll update this tutorial as that information comes in. For now, this is what I use and it works just fine. It also allows for manual connection to the programmer on MPLAB start up which in my opinion is a nice safe practice.

Keep in mind that this image and part of the tutorial will change often in the near future so revisit this tutorial for updates. I'll post an update DATE at the top of the tutorial so it will be easier to see if you have seen the latest updates.










Figure 3 - PICkit 2 Settings




 




Once you have your settings looking like Figure 3, click

Creating the main code file


Finally, after all that setup, we are ready to start writing some code. At first, we need to cover some basics and write a shell of a program that really does nothing except build without errors. Once that is accomplished, we can expand our application to do some things but we need to know the basics are covered and the application builds without errors.

NOTE: Up to this point, I've held your hand a bit by showing images of some menu commands in the MPLAB IDE. At this point, it is assumed that you know how to navigate the menu commands so I'll simply say "File / New" when I want you to navigate to that command.

It just so happens that is exactly what I want you to do, but fortunately there is a shortcut for that. You can click on File / New or simply press CONTROL-N to bring up a blank document within the MPLAB IDE. Once it is displayed, I want you to immediately save it. No, CONTROL-S doesn't work yet, not sure why Microchip left that out. I have suggestions posted to their site. Anyway, you have to go to File / Save As to save it.

One annoying issue with MPLAB is that it remembers the last folder you were at, even if it wasn't in the IDE. In my opinion, the MPLAB IDE should start at the project's folder first and make you navigate out of it. Since that isn't done, MAKE ABSOLUTELY SURE you are saving this file in your project folder.

Name the file main.c and save it. Once you have saved it, you need to add a reference to it in your SOURCE FILES folder in the IDE.

In the IDE, if you do not see a project window, open it up for viewing by clicking View on the menu and making sure Project is checked.










Figure 1 - PICkit 2 Settings




 

Now that it is visible, right click on 'Source Files' and select 'add files...'. When the browsing dialog window appears, click your new file 'main.c' and then click ok. If you did it right, you will see what is shown if Figure 2.










Figure 2 - Project View: main.c is added




Now we are ready to add some setup code to main.c and it's about time isn't it? =)

 


Writing the setup code into main.c


I'm sure you are wondering at this point... When am I going to be able to write code? I hear ya. My first C18 project took a week and that was before I even wrote anything worthwhile. The reason for that of course was all this set up, but once you do it a few times it goes a lot faster. Again, as I said before, I'll try to find a way to template all this so you don't have to go through the arduous task of the setup each time, but that is for another day. Even with all this setup work, there are things we haven't explored yet, like setting up the linker for custom ram banking, etc. Thankfully, we don't need to do that with this application so we will save that for another tutorial as well.

If you remember some years back (joking) I mentioned using a file for some of the code you will see here. Since we are going to place it in the main.c file, we will not need that extra file. I still want you to think about this though as we move forward. When you have a proven and tested set of configuration bit settings written, it's good to have that code isolated into a separate file that you can use for other projects. With that said, double click 'main.c' in your project view (under Source Files). When it opens up, place this code into that window via copy and paste.



#include <p18f452.h>
 
// HS-PLL Enabled, Internal External Osc. Switch Over OFF Disabled
#pragma config OSC = HSPLL, OSCS = OFF 
// Power Up Timer: OFF Disabled
#pragma config PWRT = OFF 
// Brown Out Reset: OFF, Brown Out Voltage: OFF Disabled
#pragma config BOR = OFF, BORV = 25 
// Watchdog Timer: OFF Disabled, Watchdog Postscaler: 1:128
#pragma config WDT = OFF, WDTPS = 128 
// CCP2 Mux: OFF Disabled (RB3)
#pragma config CCP2MUX = OFF 
// Stack Overflow Reset: OFF Disabled
#pragma config STVR = OFF 
// Low Voltage ICSP:OFF Disabled
#pragma config LVP = OFF 
// Background Debugger Enable: OFF Disabled
#pragma config DEBUG = OFF 
// Code Protection Block 0-3: OFF Disabled
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF 
// Boot Block Code Protection: OFF Disabled
#pragma config CPB = OFF 
// Data EEPROM Code Protection: OFF Disabled
#pragma config CPD = OFF 
// Write Protection Block 0-3: OFF Disabled
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF 
// Boot Block Write Protection: OFF Disabled
#pragma config WRTB = OFF 
// Configuration Register Write Protection: OFF Disabled
#pragma config WRTC = ON 
// Data EEPROM Write Protection: OFF Disabled
#pragma config WRTD = OFF 
// Table Read Protection Block 0-3: OFF Disabled
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF 
// Boot Block Table Read Protection: OFF Disabled
#pragma config EBTRB = OFF 
 
void main(void){
}












Notice the first line of code containing the #include

. This instructs the compiler to include an important header file specific to the device you are planning to use. This header file allows you to address various features of the device by using predefined structures which makes life a LOT easier in code. Microchip includes make device specific header files with your C18 installation, and they are included in the C18 installation at "..MCC18h". When looking at this file, great care must be taken not to change anything in that file, whether deliberately or inadvertently.

In the future you may want to 'enhance' your device header file to add structures or modify existing ones. If that is ever the case, it is always a good idea to copy that file to your project folder and make changes to the copy. You should ALWAYS leave the factory header file unchanged. These kind of modifications are beyond the scope of this tutorial and will be addressed in another tutorial.

Also notice the brackets < > around the file name. Presenting the file name to the compiler in this format instructs the compiler to find the file using the search paths we customized earlier in this tutorial. If you should want to include a file that exists in the project root folder and bypass the search feature, simply enclose the file name in double quotes, as in #include "p18f452.h". If the file isn't located in the project root folder, an error will occur during the build process.

The #pramga lines make the setup code fairly large because we include the configuration bits via individual pragma directives. There are other ways to do this that leave a smaller code footprint. I prefer to use this format as it is easier to read and understand. The comments I added should enlighten you to what each line deals with. Make changes accordingly, like the clock settings, etc.

Save the file (CTRL+S). Now we will build the project even though the application doesn't do anything yet. The application should build fine without any errors. Click Project / Build All on the menu bar or use its shortcut (CTRL+F10).

Quite a bit happens in your OUTPUT window in the BUILD tab. This is where you will look for any errors during the build like syntax errors, undeclared prototypes, type mismatches, or any other wonderful coding snags you need to diagnose and fix.

Since the code is pretty simple, the build should succeed just fine, and your OUTPUT / BUILD results should look something like this...



----------------------------------------------------------------------
Debug build of project `S:mcublink_ledblink_led.mcp' started.
Language tool versions: mpasmwin.exe v5.30.01, mplink.exe v4.30.01, mcc18.exe v3.30
Preprocessor symbol `__DEBUG' is defined.
Wed May 13 10:09:42 2009
----------------------------------------------------------------------
Clean: Deleting intermediary and output files.
Clean: Deleted file "S:mcublink_ledmain.o".
Clean: Deleted file "S:mcublink_ledblink_led.cof".
Clean: Deleted file "S:mcublink_ledblink_led.hex".
Clean: Done.
Executing: "C:MCC18binmcc18.exe" -p=18F452 "main.c" -fo="main.o" -D__DEBUG -Ou- -Ot- -Ob- -Op- -Or- -Od- -Opa-
Executing: "C:MCC18binmplink.exe" /p18F452 /l"C:MCC18lib" /k"C:MCC18lkr" "main.o" /u_CRUNTIME /u_DEBUG /z__MPLAB_BUILD=1 /z__MPLAB_DEBUG=1 /o"blink_led.cof" /M"blink_led.map" /W
MPLINK 4.30.01, Linker
Copyright (c) 2009 Microchip Technology Inc.
Errors    : 0

MP2HEX 4.30.01, COFF to HEX File Converter
Copyright (c) 2009 Microchip Technology Inc.
Errors    : 0

Loaded S:mcublink_ledblink_led.cof.
----------------------------------------------------------------------
Debug build of project `S:mcublink_ledblink_led.mcp' succeeded.
Language tool versions: mpasmwin.exe v5.30.01, mplink.exe v4.30.01, mcc18.exe v3.30
Preprocessor symbol `__DEBUG' is defined.
Wed May 13 10:09:43 2009
----------------------------------------------------------------------
BUILD SUCCEEDED 



 

If you get BUILD FAILED, recheck your work and make sure you do not have any typos. To illustrate what you might see in such a scenario, I removed the pound symbol from the first pragma and then rebuilt the project (CTRL+F10). Of course, the build failed and the output looked like this...

You can try this or just read on to familiarize yourself with debugging build errors.



----------------------------------------------------------------------
Debug build of project `S:mcublink_ledblink_led.mcp' started.
Language tool versions: mpasmwin.exe v5.30.01, mplink.exe v4.30.01, mcc18.exe v3.30
Preprocessor symbol `__DEBUG' is defined.
Wed May 13 11:03:47 2009
----------------------------------------------------------------------
Clean: Deleting intermediary and output files.
Clean: Deleted file "S:mcublink_ledmain.o".
Clean: Deleted file "S:mcublink_ledblink_led.cof".
Clean: Deleted file "S:mcublink_ledblink_led.hex".
Clean: Done.
Executing: "C:MCC18binmcc18.exe" -p=18F452 "main.c" -fo="main.o" -D__DEBUG -Ou- -Ot- -Ob- -Op- -Or- -Od- -Opa-
S:mcublink_ledmain.c:3:Error: syntax error
Halting build on first failure as requested.
----------------------------------------------------------------------
Debug build of project `S:mcublink_ledblink_led.mcp' failed.
Language tool versions: mpasmwin.exe v5.30.01, mplink.exe v4.30.01, mcc18.exe v3.30
Preprocessor symbol `__DEBUG' is defined.
Wed May 13 11:03:47 2009
----------------------------------------------------------------------
BUILD FAILED  



 

Double clicking on the blue error line will take you right to that line of code so you can fix the syntax error. A little blue horizontal line will appear before the line containing the error. After fixing the error, rebuild the project to confirm you fixed the error.

 


Functions and prototypes


We are almost ready to add some useful code to our project but first I want to cover a couple of basics about functions and prototypes. We will be making frequent use of functions as we move forward so I feel it is important that you know some best practices for their use, how bypassing these best practices can cause build errors, and why some dirty code only throws a warning and not an error.

A function prototype is a way of informing the compiler that somewhere in the program there will be this specific function, what type of data it will expect (if any) and what type of data it will return (if any). The first instance of a function, whether it be a prototype, it's use, or the actual function determines its logic (as mentioned above). In some instances where you have a function that doesn't expect anything and doesn't return anything, using it somewhere in the program will probably cause the compiler to throw a warning during the build. If the function returns something and/or expects something, a serious type mismatch can occur and the build will fail. So pay attention to prototype warnings that may appear in your build output and address them right away. Creating a prototype insures that the compiler knows what the function is all about before any code is encountered so occurrences of the function call throughout your code can be properly validated by the compiler, giving you an error-free build.

Here are some examples of this behavior. Hopefully, these examples will help you debug some of these common build errors and shed some light on why they occur. I'll leave out the pragma directives included in our main.c file to shorten and simplify the examples.

This first example shows why a build warning occurs. A prototype isn't used and the function doesn't expect or return anything.






1
2
3
4
5
6
7
8

#include <p18f452.h>
 
void main(void){
	testfunction();
}
 
int testfunction(void){
}






The first occurrence of the function is encountered in the form of a call within main on line 4 instead of the actual function on line 7 or a prototype, so the function is assumed to be of the type INTEGER even though the compiler isn't sure, thus the warning. These are usually non-lethal to code execution but it leaves a possible problem that can alter the program's results later on.

The build output...



S:mcublink_ledmain.c:4:Warning [2058] call of function without prototype
.
.
.
BUILD SUCCEEDED



Since the function is indeed of type INTEGER, the build is allowed to succeed.

But say we change the testfunction to be of type CHAR, as in...






1
2
3
4
5
6
7
8

#include <p18f452.h>
 
void main(void){
	testfunction();
}
 
char testfunction(void){
}






'testfunction' is first encountered in main on line 4 and assumed to be of type INTEGER, but when the compiler encounters the actual function on line 7, it is of type CHAR instead so there will be a type mismatch and the build will fail.

The build output...



S:mcublink_ledmain.c:4:Warning [2058] call of function without prototype
S] type mismatch in redeclaration of 'testfunction'
Halting build on first failure as requested.
.
.
.
BUILD FAILED





To fix this, we simply prototype the function early on, usually before main, so the compliler knows what the function type is before it is encountered in code.




1
2
3
4
5
6
7
8
9
10

#include <p18f452.h>
 
char testfunction(void);
 
void main(void){
	testfunction();
}
 
char testfunction(void){
}






The function is revealed to the compiler in the form of a prototype on line 3 so when it is encountered later on, on lines 6 and 9, the compiler knows that the function is of type CHAR and no mismatches will occur.

The build output...



.
.
.
BUILD SUCCEEDED




As you can see, function prototypes are very important to writing safe and succesful code. They are very simple to do as well. When I write a function, I make a habit of prototyping it before I leave it to work elsewhere. You can prototype it first, but if you change the arguments it expects, or decide on another data type for it, you will have to make sure you change that prototype to reflect the changes. The prototype is exactly like the function header except the line is ended with a semicolon instead of an open curly brace.

So why doesn't main need a prototype? I'm not really sure, but it seems logical that since it is the first function header encountered and isn't called that no errors are thrown when main isn't prototyped. Advanced programming techniques I haven't yet encountered might require main to be prototyped so prototyping main is probably a good idea and certainly doesn't hurt anything. I never have though and have yet to encounter an error because of it.

 


Blinking LED application


Now that we have ALL THAT STUFF out of the way, we are finally ready to write some meaningful code. As promised, we will blink an LED in a 50% duty cycle on / off style. We will do this using a simple loop in main, which as you might have guessed is where our application starts execution.

Since we are not using any timer or delay libraries yet, we will need to create a delay loop to slow things down a bit. We will place this loop into a function so we can call it when needed.

Copy and paste the code below into main.c and please remember to overwrite the previous code in there since the code below is the entire file. You can also download the file here and then place it in your project folder overwriting the old main.c in there.



/*
  Setting up a new C18 project and creating an application Tutorial
  Super simple LED blinker in C using Microchip C18 and MPLAB
  Written by Hop for digital-diy.com tutorials - May 13, 2009
  Written for the 18F452 running at 40mhz specifically. Make changes as needed for other devices
*/
 
// Include the necessary device header file
#include <p18f452.h>
 
// Configuration Bit pragma directives (see device data sheet)
#pragma config OSC = HSPLL, OSCS = OFF // HS-PLL Enabled, Internal External Osc. Switch Over OFF Disabled
#pragma config PWRT = OFF //	Power Up Timer: OFF Disabled
#pragma config BOR = OFF, BORV = 25 // Brown Out Reset: OFF, Brown Out Voltage: OFF Disabled
#pragma config WDT = OFF, WDTPS = 128 //	Watchdog Timer: OFF Disabled, Watchdog Postscaler: 1:128
#pragma config CCP2MUX = OFF // CCP2 Mux: OFF Disabled (RB3)
#pragma config STVR = OFF //	Stack Overflow Reset: OFF Disabled
#pragma config LVP = OFF //	Low Voltage ICSP:OFF Disabled
#pragma config DEBUG = OFF //	Background Debugger Enable: OFF Disabled
#pragma config CP0 = OFF, CP1 = OFF, CP2 = OFF, CP3 = OFF //	Code Protection Block 0-3: OFF Disabled
#pragma config CPB = OFF //	Boot Block Code Protection: OFF Disabled
#pragma config CPD = OFF //	Data EEPROM Code Protection: OFF Disabled
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF //	Write Protection Block 0-3: OFF Disabled
#pragma config WRTB = OFF //	Boot Block Write Protection: OFF Disabled
#pragma config WRTC = ON //	Configuration Register Write Protection: OFF Disabled
#pragma config WRTD = OFF //	Data EEPROM Write Protection: OFF Disabled
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF //	Table Read Protection Block 0-3: OFF Disabled
#pragma config EBTRB = OFF //	Boot Block Table Read Protection: OFF Disabled
 
// Function prototypes
void delay1(void);
 
// Main code section. Execution starts here.
void main(void){
  // First some setup code for the LED
  // The LED will be driven by port D, bit 0, driving the anode, cathode to ground
 
  // First we should clear the port D, bit 0 data latch
  LATDbits.LATD0=0;
 
  // We need to set port D, bit 0 as an output
  // Using TRISDbits instead of TRISD allows isolating a single bit leaving the other bits unchanged
  TRISDbits.TRISD0=0; // 0 = output, 1 = input
 
  // Set port D, bit 0 to off (driving the LED anode, cathode to ground)
  PORTDbits.RD0=0;
 
  // LED blinking loop that never ends since '1' never changes
  while(1){
    PORTDbits.RD0=1; // turn the LED on
    delay1(); // call the delay function
    PORTDbits.RD0=0; // turn the LED off
    delay1(); // call the delay function
  }
  // end of main, but we will never get this far (endless loop)
}
 
// Start of our functions
void delay1(void){
  /*
    It is important to note that all variable declarations need to be placed before any code in
    a function or the build will fail. 
  */
  // declare a long integer and set it to zero
  long int loop1=0;
 
  // count from zero to 30,000 then continue on
  // Lower than 30000 for a faster blink, higher for a slower blink.
  for(loop1=0;loop1<=30000;loop1++){
    /*
      FOR loops are pretty simple in C. There are three parameters in a FOR loop seperated by
      semicolons. The first parameter is what variable we want to use and what value to assign
      to it initially. The second parameter is the condition for the loop to continue looping. In
      this case, as long as loop1 is less than or equal to 30000 the loop will continue looping.
      The third parameter is what to do at each iteration of the loop. In this case, increment
      loop1 by 1 each iteration. Everything in between the curly braces is executed on each
      pass of the loop. When the test condition fails, IE: loop1 = 30001, then execution passes
      to the next statement after the close curly brace.
    */
    }
    // The loop is done and execution has moved past the loop
}



 

This simple application does one thing, turn a LED on and off repeatedly. I included some comments to help explain each line and to give you a little exposure to the C version of FOR loops. I plan to write a ton of tutorials on the various little C tricks that are out there.

We have so much revision to do with this simple application. PWM, interrupts, multiplexing, using RS232 and USB to control the LED flashing element, and using the Microchip C18 libraries. Together, we will take this simple task to the absolute LIMIT using peripheral hardware and software support. Through these adventures, we will learn how to take these skills and apply them to more complex tasks using C18. Tasks that will allow us to interface and interact with other devices, bringing our PIC MCU to a point where we are comfortable having it handle almost anything we can think of.

Please revisit this tutorial in the future and check for updates and revisions. We have laid out a great foundation to build on, and there is much more work to be done.

Have fun! I know I have.

Hop

 

 
Read full article...
Time to create page: 0.757 seconds