|
|
Last updated 23rd February 2010. This FAQ contains the top 68 questions and techniques asked by PIC micro students about Hi-Tech C for the PIC16Fx, PIC18Fx and PIC24Fx micros from the University of Canterbury. View the latest questions and answers on www.MicrochipFault.com, under the tag: HiTechCFAQ
Tips
for using features of C on a PIC micro Watching
the values of variables Quirks
of the PIC micro
Serial Port
with PIC Useful techniques
for using C with PIC Tips for using the PICSTART Plus Programmer Q. What are the most commonly used features of a PIC micro?
Q. So, how do I use the features of the PIC micro listed in the previous question? A. Well, this may sound obvious, but the best way is to follow through the Microchip microprocessor manual. Do it step by step. Dont succumb to the urge to do it now - complete the reading first, then do programming. This way, you avoid missing crucial pieces of information that you will need to get it working. Rule of thumb: When using a new feature of the PIC micro for the first time, read every word in that section of the manual. To skim read it means you will miss out some crucial feature, and waster time inthe long run. For example, to use the A/D port, look up the manual, and follow through it. All the variables like ADCON1, etc have the same name in C. To get a list of all the equivalent names for the registers in C, go to c:\ht-pic\include subdirectory and look at the header files. This is very useful file to have for reference. Q. Tell me how to drive the pins on a PIC micro. View the latest answers to this question on MicrochipFault.com; tags PIC HiTechCcompiler HiTechCFAQ A. Take the PIC16F876,
a 28-pin micro. Then look at port A for example. This is a row of 6 pins,
going down the side of the micro. Each pin can output 5V or 0V, or read whether
the input is 5V or 0V. //(c)Shane Tolmie, http://www.microchipc.com/,
distribute freely for non commercial use on the condition that you include this
web link somewhere in your document. Researching DataQ. How do I find suppliers of Microchip parts? A. Go to the Microchip web site and look up the list of distributors in your country. This technique
works for any company get their info on who distributes for them. Q. How to I do research on a new project? A. Well, there are many places to find information on what you intend to do. 1. Read books and magazines. The advantage of these over the internet are that
the signal-to-noise ratio is extremely high, and the articles are likely to
be more correct. For books, search http://www.amazon.com/ for pic micro then get it out at your local library or buy it.
Good magazines are Circuit Cellar, Electronics Australia, Popular Science
and Popular Mechanics, among others.
6. Ask the experts. You can email Microchip or Hi-Tech with any questions on their products. Tips for using features of C on a PIC micro Q. How do I express numbers in decimal, hexadecimal or binary? A. Use the following code: unsigned char x; //8 bits
on PIC Q.
Whats wrong with the following code? A. Can you figure it out without looking at the answer? Its a simple error, but its easy to glance over and miss. Throughout history, it has caused countless hours of wasted time. 0b1111111=127, not 255, as the last 1 is missing. Binary values always come in groups of 8 bits, and one should always mentally check that 8 bits have been entered. Q.
Whats wrong with the following code? A. A very insidious bug. When it gets to zero, it decrements it and then checks to see whether its still higher than zero. But, of course, since its unsigned it has already rolled over to 255. Thus it will loop until the next blue moon. Change variable i to signed, as below: signed char i; Note that when counting up from 0, chars can be both signed and unsigned as there is no rollover
problem. Q. What datatypes are available on a PIC? A. The following: A. Use the following code for turning single bits on or off in a variable. Remember that the bits in an 8-bit variable are always numbered from right to left, 0 to 7. For example, bit 0 of 0b00000001 is 1. Bit 1 is 0. /*for turning single bits on/off in a variable. Use ~0 instead of 0xFFFF, etc, because this ensures machine independence, if int changes from 16-bit to 32-bit. Remember that the bits in an 8-bit variable are always numbered from right to left, 0 to 7. For example, bit 0 of 0b00000001 is 1. Bit 1 is 0, through to the most significant bit 7 on the left. Example C: unsigned char x=0b0001; /*for turning multiple bits on/off according to mask. Use ~0 instead of 0xFFFF, etc, because this ensures machine independence if int changes from 16-bit to 32-bit. Example C: unsigned char x=0b1010; Q. How do I test bits in a variable? A. Use the following code: /*for testing single bits in a variable. Remember that the bits in an 8-bit variable are always numbered from right to left, 0 to 7. For example, bit 0 of 0b00000001 is 1. Bit 1 is 0, through to the most significant bit 7 on the left. Example C: Q. How do I divide or multiply by two efficiently? A. To multiply by two, use x = x << 1 or x<<=1. The second version is shorthand. If x=2, or 0b10 in binary, shifting left gives 0b100 or 4. To multiply by four, use x<<=2. By eight, x<<=3. To divide by two, use x>>=1. To divide by four, use x>>=2. Having said this, most compilers would optimise a x=x/2 into a shift anyway. A. Use the following
code: Note the use of typecasting when converting any variable to another type, one should typecast it. Read a book on C to explain this further. Note, unions are not necessary and are not recommended because passing variables to functions is made more difficult. The above method is good for looking at any variable in any bank of memory. Unfortunately, it cannot be used to alter a byte in an int. For this, pointers are needed. A different #define is needed to alter variables in each bank. #define lobyte_atbank0(x)
(unsigned char)(*(((unsigned char *)&x)+0)) Q.
Is the following code inefficient? Doesnt x>>=8 have
8 shifts? unsigned int x; Q. Instead of using (unsigned char)(x>>8) as per the previous question, why dont you use pointers? A. It is possible, but because there is 4 banks of memory it needs a different #define for variables in each bank. Its simpler and effectively the same to use (unsigned char)(x>>8), unless youre altering the variable. Q. Whats the difference between the following two lines of code: x++; if (x>=4) x=0; A. Its a very minor point, but the first statement is more robust. If a rogue pointer or a chip brownout corrupts x, it will count all the way up to the max before wrapping around. Of course, one may want such errors to show up, so the second one may be more preferable. Q. Can I use inline code for functions? A. On some compilers, adding the keyword inline before a procedure means that each time the procedure is called, the code inside it is inserted rather than called. This reduces the overhead of jumping to the function, but makes the program larger. There is no inline keyword for the latest version of Hi-Tech C, v7.85. However, one can almost have inline code by using #defines. If one puts a \ character after each line, it treats it like a single large line. The only disadvantage is that there is no way to return a variable. For example, see the following code. unsigned char x,y Q. Whats wrong with the port initialization code below? //these 4 lines are correct //method 2 - set port then
direction (WRONG) Of the two methods above,
method is 1 is correct, method 2 is wrong. Worked Example 1. We wish to set CLOCK=OUTPUT,
and CLOCK to logic level 0 (RA4=0, TRISA4=0). Compare this to step 7. I hope this clarifies
why its a good rule of thumb to use the correct method. Watching the values of variables Q. How do I watch variables in MPLab? A. Bring up the watch
window dialog by clicking on the pair of glasses icon on the right
of the menu bar. Of course, to display variables inside functions, the switch -fakelocal must be added to the linker options. For this switch to work, check that you have the latest version of Hi-Tech C, v7.86pl3 or above. This is explained in the tutorial on how to set up a project.
A. Left click to the left of the Watch_1 title on the title bar, as below. Q. How do I watch an array of variables in MPLab? A. There is no built in way and in MPLab to view arrays of variables. There is a way to get around it, illustrated by the diagram below. To look at the array named array, select main.array from the add watch symbol box. This is address 0x21, and shows array[0]. To look at array[1] enter 0x22 as the symbol. Alternatively, to view an array of integers, increment the address by two each time. Q. I cannot view local variables, only global variables appear in the watch window. A. To display variables inside functions, the switch -fakelocal must be added to the linker options. This is explained in the tutorial on how to set up a project. For this switch to work, check that you have the latest version of Hi-Tech C, v7.85 or above. Q. I get the following errors or line of errors when I compile: ::Can't find 0x64 words for psect rbss_0 in segment BANK0 (error) A. All this gibberish means is that theres not enough ram to fit the variables in. In the 16F876, there are 4 banks of 96 bytes. Move some variables to another bank, by the following method: unsigned char array_char[79];
//goes in bank0, 96 bytes excluding overhead However, there are some issues with passing pointers. For example, a function that accepts a pointer can only accept it from the same bank. This is illustrated by the code below. /* the following C line wouldnt work have to specify bank where pointer comes from, otherwise produces error :Fixup overflow in expression*/ //strcpy(unsigned char *to,unsigned
char *from) project.obj:33:Fixup overflow in expression (loc 0xFD2 (0xFCC+6), size 1, value 0xA1) (error) Q. PORTA doesnt work when reading logic levels. A. Set it to digital mode, by setting ADCON1=7. If its in analogue mode, it will try to do a/d operations on the port. A. Port RA4 requires a 10k pullup. This is because it can be the input for an external timer. A. Check out the sample
files in the c:\ht-pic\samples\ directory for an example. For sample
code for the PIC16F876/77, check out source
code. The best way to check the amount of stack levels used, in Hi-Tech C, is to look at the .map file. Turn on .map files in the linking options. In MPLab, select Project..Edit Project..Node Properties..Map File On.."main.map". Manually check how many levels the function calling is nested. Allow as many stack levels for the interrupts as needed. Another way is to manually
keep a track of the stack levels with a counter. Every time a function is
called, increment the counter. Every time a function is returned from, decrement
the counter. Keep a track of the maximum number this counter gets to, ie: However, this method is not recommended. If your program is big enough to warrant checking for stack levels, it will be a royal pain to add all the calls. A #define makes it easier, also used to switch on/off the debug code, but even still, examining the .map file is much more reliable, quicker, and doesnt make the program larger. Interesting quirks of Hi-Tech C Generally, Hi-Tech C is a very stable, bug free compiler. In two years of using it, I have never encountered any trouble with it. Currently I have an 8k, 5000 line C program that works beautifully. Make sure that you have the latest version, v7.86pl2, as some earlier versions have bugs. For example, v7.84 without the patch level 1 would sometimes branch the wrong way in an if..else statement if the variables were in different banks. Q. Whats wrong with the following program? It gives errors. #define DOMATHS \ <-
invisible space or tabs after \ gives error Symptoms? It will generate multiple errors, with the one below as the last one. c:\pic\main.c: 12: illegal character (0134) (error) A. Here is PIC Hi-Tech
C code, schematic picture and protel 99 files, plus VB 6 example code. Download.
Q. My serial port sometimes dies completely, it wont receive anything more. A. This means you are ignoring framing and overrun error bits. If too many characters are received before they are recorded in software, the overrun bit, OERR, gets set. This shuts off all further transmissions. It a wrong stop bit is received, the framing error bit, FERR, gets set. This shuts off all further transmissions. See the project for serial comms in the sample projects section. Q. I want a routine to do a serial port in software, because Im using a low-end PIC. Go to directory c:\ht-pic\samples and look at files serial.c and iserial.c. The second file receives characters into a buffer in the background, using interrupts. Its almost like the hardware serial port on a high-end PIC. A. Interrupts are very useful. When a certain event happens such as the logic level on a port changing, a timer overflowing or a serial character arriving a flag is set. For example, if the logic level on port RB0 changes, instantly the flag INTF will get set. If the particular interrupt is enabled, the current state of the processor is saved, and execution branches to the interrupt routine. For example, if INTE is enabled, then it will jump to the interrupt routine as soon as INTF is set. When it is finished, the state of the processor is retrieved and execution continues where it left off. Here is sample code to
read the data line if the clock line goes low interrupt isr() Q. My interrupt routine is not working. A. Try the following tips: 1. If you put a breakpoint in the interrupt routine, and it doesnt get there, check that every variable in the interrupt chain is enabled. The diagram below has been reproduced from the PIC16F876 manual, from the section on interrupts. For example, to enable the interrupt on the 16-bit timer 1 overflow, TMR1IE, PEIE and GIE must all be enabled for the interrupt to interrupt to CPU. If PEIE or GIE is disabled, it will never jump to the interrupt routine. 2. You must clear the interrupt flag, and in some cases read the port involved with the interrupt before exiting the interrupt routine. Otherwise, it will keep going back into the interrupt routine continuously for ever. 3. Important: the rule of thumb involving volatile variables: Every variable that is referred to in main() and interrupt must be declared volatile If a variable is not declared volatile, problems will arise if it is changed. This is because the optimiser makes the program store a temporary copy of the variable in a register. If the interrupt comes along and changes it, even though it is changed in ram, it is not changed in the register. Making a variable volatile forces the program to load a fresh copy of the variable every time it wants to check it. It also slows the program down slightly. Here is some sample code to illustrate when to make a variable volatile: //(c)Shane Tolmie, http://www.microchipc.com/,
distribute freely for non commercial use on the condition that you include this
web link somewhere in your document. A. Keep a record of the previous state of the port, and use XOR to work out what pin changed, thus: //(c)Shane Tolmie, http://www.microchipc.com/,
distribute freely for non commercial use on the condition that you include this
web link somewhere in your document. For this example, we will
use the 8-bit timer 0, available on PIC micros. The timer rolls over at 0xFF, or 255. 255 is smaller than 800, so use 4 lots of 200 ticks using a 1:4 prescaler. If we want 200 ticks, and the timer counts up and rolls over at 255, we need to set the timer to 55 each time, so it will count up to 255. Note that the prescaler is not rewritten each time this needs to be only set once initially. The manual seems to indicate that whenever tmr0 is rewritten, it rewrites the prescaler. However, it means that it zeros the internal counter for the prescaler, not the actual prescaler itself. This timing method is used in the simple multitasking technique for a PIC. In the meantime, here are some code examples. Method 1: execute code every 800us by using polling to check the bit in main() //(c)Shane Tolmie, http://www.microchipc.com/,
distribute freely for non commercial use on the condition that you include this
web link somewhere in your document.
//(c)Shane Tolmie, http://www.microchipc.com/,
distribute freely for non commercial use on the condition that you include this
web link somewhere in your document. Q. How do I speed up my interrupts? A. Here is a few tips:
Q. Whats wrong with the following interrupt code? //incorrect code
(if SSPIE or ADIE is being disabled/enabled in main) //correct code (if
SSPIE or ADIE is being disabled/enabled in main) Q. How do I time exact intervals? My favorite way to handle this 'non-commensurate' intervals problem is to steal a concept from the Bresenham line drawing algorithm. Using the current case:
You start with a counter set to 1,000,000 (1 second in microseconds) On each timer interrupt you subtract 16384 from the counter. If the counter goes negative you update the time by one second and then add 1,000,000 back in to the counter. This technique will work
for any interval. It can be made perfect for intervals that have a rational
relationship to the instruction cycle time, and can be abitrary close to perfect
even for irrational ratios, for example a SQRT(2) Mhz crystal. A. Theres a trick to setting breakpoints. See the closing bracket } in the code? It hasnt got 4 dots to the left of it. This means that you cannot right click on that line, and put a breakpoint there. As to making it stop on the right line, sometimes you have to add extra lines of code so it can stop exactly where you want it. Use the #define to set b (for breakpoint) to inline assembly language, asm(nop). Nop stands for No Operation it doesnt do anything. Q. My circuit works with the emulator, but not if I plug in a programmed chip. A. Check the following: 1. The program may be wrong. Usually, the simulator and emulator environment has all variables are set to 0 initially. If a program doesnt initialise its variables, it will work in the simulator and emulator, but not on a standalone chip. Rule of thumb: Initialise every variable to a known value before using it 2.
Is the chip programmed at all? #include <pic.h> A. Add the switch -ICD under the linker options, menu project then edit project then node properties. This reserves the last 256 bytes of memory, and 13 miscellaneous ram bytes that the ICD uses. Check the compiler is v7.85 or above. Then, match the ICD options to the box below. These settings are the default for almost every situation, with the exception of the oscillator. 1. When using an external crystal with speeds of higher than 8Mhz use the settings as shown above. 2. Crystal speeds of lower than 8MHz use XT for the oscillator setting instead HS. 3. When using a RC oscillator for the clock, made up of a resistor and a capacitor, use RC for the oscillator setting instead of HS. Q. What is the watchdog timer and why do I want it? A. The watchdog is a good way to ensure that the microprocessor does not freeze forever from a crash, due to a bad power supply or a rogue program. When the chip is programmed, the watchdog timer bit is enabled. It cannot be turned off in software, in case a rogue program overwrites it. If the timer is not reset regularly with a CLRWDT() instruction, it will reset the micro. This will happen within 18ms to 2 seconds, depending on the prescaler selected.
A. Have you got the watchdog timer bit set? The watchdog is a good way to ensure that the microprocessor does not freeze forever from a crash. When the chip is programmed, the watchdog timer bit is enabled. It cannot be turned off in software, in case a rogue program overwrites it. If the timer is not reset regularly with a CLRWDT() instruction, it will reset the micro. This will happen within 18ms to 2 seconds, depending on the prescaler selected, and on the temperature. It is interesting to note that it is possible to make a PIC into an accurate temperature sensor using the time of the watchdog timeout to sense the temperature. The advantage of using a watchdog timer is that the micro is protected from crashing forever due to a bad power supply or a rogue program. Useful techniques for using C with PIC Q. Have you got any delay routines? A. Its important to
have accurate delay routines. Delay routines written in C arent accurate
depending on optimisations, they can vary. Thats why some of
the routines have inline assembly. Delay routines are available for download. A. If youre using the simulator or the ICEPIC 2000, bring up the stopwatch under menu windows. Put breakpoints before and after the section of code, and measure the time. The MPLAB-ICD doesnt
have a stopwatch. Add a piece of code to read out the value of timer 1 at
the start of the code, then check it again at the finish. The timer increments
at the same frequency as instructions executed. Do some maths and you have
the time in clock cycles that the code takes. A. Do the following code: unsigned char x; A. One way is to reset all variables to their defaults, as listed in the PIC manual. Then, use assembly language to jump to location 0x0000 in the micro. #asm This is quite safe to use, even when called within interrupts or procedures. The PIC 16x series micros have 8 stack levels. Each time a procedure is called, one stack level is used up for the return address. It is a circular buffer, so even if the micro is 7 procedure levels deep and in an interrupt when a reset is called, this is the new start of the stack buffer, and the micro will continue as per normal. Another way is to set watchdog the timer when the chip is programmed, and use CLRWDT() instructions all through the code. When you want the micro to reset, stop clearing the watchdog bit and the micro will reset after around 18ms to 2 seconds depending on the prescaler. Q. Theres a variable in the PIC manual that the compiler doesnt recognise, even though I used the same name. How do I tell what the compilers called it? A. Go to directory c:\ht-pic\include\ and look at the header files. These give the names that the compiler gives to the internal variables. This is extremely useful for finding out exactly what variables are available in C. Heres some example code from the header file, pic1687x.h for the PIC16F87x micro: /* A. Rule of thumb: every time a program waits for an operation that could fail, have a timeout to exit it after too much time. For example, reading in a byte with SPI. There is the clock and data line, and a byte with 8 bits is read into the micro. If the sender of the byte stops halfway through, there is four garbage bits remaining. Later on, after 5 minutes, the sender sends a new byte. Everything is now out of sync, with the first half going into one byte, and the last half going into the next. Use the following code to implement timeouts. //(c)Shane Tolmie, http://www.microchipc.com/,
distribute freely for non commercial use on the condition that you include this
web link somewhere in your document. A. Youve done well. One thing to check is that you havnt got any orphaned functions which are never called. Hi-Tech C includes the code, even though it is redundant. To automatically check for this, set the warning level to 9 (negative nine) under menu Project then Edit Project then node properties. This introduces all sorts of warnings. Most of them can be ignored, except the one: ::function _myfunction is never called (warning) This means that the code
for the function myfunction is included somewhere in your code,
but it is never called. If youre not going to use it, comment it out. Q. Can I use printf() when communicating with a PC computer via the RS232 serial port? A. You can use printf() to write to the USART on a PIC micro if you define your own putch() routine and #include the correct header file. It uses an extra 650 words of program memory. See the sample code here. Q. Why cant I print long (32 bit) variables with printf()? A. Add the switch -lf to the additional command line options, under menu Project then Edit Project then Node Properties. This uses up a additional 1600 words of rom space, but it allows printf to print longs. Q. How do I store large amounts of data? A. Use EEPROM or the Dataflash available from Microchip or Atmel. Capacities range from 1Kbyte to 4Mbyte non-volatile chips. Q. Can I control 2 LEDs from one port? A. Yes. The only catch
is that one has to be on at any time. Connect the 2 LEDs in series, between
the 5V and GND rails. Attach the port to the middle between the LEDs. Connect a current limiting resistor in series between the VCC rail and the
top LED, and between the GND rail and the bottom LED. Different color LEDs
require different voltages acorss their terminals, read the datasheet. Q. I want to protect my circuit from overcurrents and shorts. A. Get a polyswitch, available from, among others, the manufacturer RayChem. See http://www.raychem.com/, search for miniSMDC075. These are tiny autoresetting fuses that limit the current to no more than a certain value. Q. How do I save power in my embedded micro system? A. There are many methods to reduce the power consumption of a circuit with a micro in it. 1.
Use the lowest clock frequency possible. For PIC micros, the power consumption
seems to rise as the square of the frequency. Q. My PIC sometimes resets by itself. A. Bad power? Brownouts? Put a decoupling cap as close to the power supply as possible, so when it switches it doesnt brown itself out. 0.1uF for <8Mhz, 0.01uF for >8Mhz. Q. How do I do a bootloader for the flash based 16F876? A. Although code is available from Hi-Tech, this is a modified and enhanced version that doesnt need RB0 - it uses timeouts, so the code is loaded within 1 second of powerup. It also handles config bits properly, and programs the EEPROM also. See sample code archive here. Simple Multitasking Kernel for PIC under Hi-Tech C Q. How do I handle many things at once on a PIC? I want a simple multitasking system. A. See here for a big explanation of this. Tips for using the PICSTART Plus Programmer Q. The programmer doesnt seem to work it doesnt program A. Sometimes this happens, maybe MPLab has got something wrong with it or the programmer itself has crashed. It can crash its running code just like the computer. Pull the plug out of the programmer, shutdown the computer and restart it, then retry it. This usually fixes the problem. Q.
How do I embed configuration words for the programmer into my C program A. Use the __CONFIG(); macro in your C code, after #include<pic.h> to set these bits. First, look up the appropriate include file for your micro. Then compare this to the include bits in the PIC .pdf manual. For the PIC16C76, <pic.h> includes file pic1677.h, found in c:\ht-pic\include\. At the bottom of the file,these lines appear: //look up datasheet for
explanation of terms #include<pic.h> Some compilers recommend linking the fuse names with logical "OR", the symbol "|". Other compilers recommend linking the fuse names with logical "AND", the symbol "&". Tips on using Libraries with MPLab Q. What is a library, consisting of a ".lib" file, and how do I use it? A. Normally, most people have a library of commonly-used routines that are always included in every project they do. For example, there is
the following files: #include "delay.h" Q. How do I make a library file? View the latest answer to this question on MicrochipFault.com; tags PIC HiTechCcompiler HiTechCFAQ Lets say I have a number of modules, each one an object file, ending in ".obj". I can put these in a library by executing the following at the dos prompt: libr r xx.lib i2c.obj ser_877.obj
delay1.obj Q. I make a library file ending in ".lib" but I cant tell MPLab how to get to it View the latest answers to this question on MicrochipFault.com; tags PIC HiTechCcompiler HiTechCFAQ
Q. How do I add serial numbers to a program coded in Hi-Tech C? View the latest answers to this question on MicrochipFault.com; tags PIC HiTechCcompiler HiTechCFAQ
psect preserve Incremental Compiles with Hi-Tech C Q.
Under Hi-Tech C and MPLab, every time I recompile, it recompiles everything
and then links it. How do I do incremental compiles? View the latest answers to this question on MicrochipFault.com; tags PIC HiTechCcompiler HiTechCFAQ Q.
How do I set the OSCCAL register in Hi-Tech C for the PIC12F672? Looking in the header file, c:\htpic\include\pic1267x.h, we find the following lines, in different parts of the header file static volatile unsigned
char bank1 OSCCAL @ 0x8F; OSCCAL=_READ_OSCCAL_DATA(); If you are using a flash -F- part or a UV-erasable -JW- part, remember to record
the value of the highest ROM address. It will be in the form retfw N where
N=calibration value. For example, if N=0x90, the instruction will be 0x3490. I used seven PIC12C672-JW parts in development. The OSCCAL values that I recorded for them were 0x90, 0x94, 0xB0, 0x84, 0xC8, 0xB0, 0xC0. This illustrates the fact that there is process variation among batches of PIC micros. If you lose the value of OSCCAL for a particular JW part, you can retrieve it, with effort. Write a little routine to output 10kHz pulses. Alter the OSCCAL value until the pulses are indeed 10kHz as viewed on an oscilloscope. |
We welcome any suggesions or comments! Send them to Shane Tolmie on support@microchipc.com. This site is a completely separate site to www.microchip.com, and is maintained independently of Microchip Ltd., manufacturers of the PIC micro. All code on this site is free for non-commercial use, unless stated otherwise. Commercial use normally free, however, it is prohibited without contacting support@microchipc.com for permission. All content on this site created by Shane Tolmie is copyrighted by Shane Tolmie 1999-2009. Click to advertise on this website - $29.90 for a banner ad which will reach 55,000 user sessions per month. One months free trial! |