Sei sulla pagina 1di 28

Fundamentals of PIC with Hi-Tech C Q. What are the most commonly used features of a PIC micro?

A In my experience, the following: Output ports for driving LEDs, etc. Input ports for reading logic levels. Timers that count in the background External interrupts that trigger the interrupt routine if a port changes. Internal interrupts that trigger the interrupt routine if a timer overflows Serial port USART for communicating with a PC A/D ports for reading voltages Capture ports that can precisely capture the exact time of a port logic change. I2C, a standard by Philips that allows comms to multiple devices on a 2-wire bus SPI, transferring data using a CLK and DATA line Counters, can count external pulses in hardware and give the result a register SLEEP mode, to reduce power consumption. Watchdog timer, to increase reliability by resetting micro if it crashes. 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 micropro step by step. Dont succumb to the urge to do it now - complete the reading first, then do programming. This way, you avoid missing cruc 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 i manual. To skim read it means you will miss out some crucial feature, and waster time inthe l

For example, to use the A/D port, look up the manual, and follow through it. All the variables li the same name in C. To get a list of all the equivalent names for the registers in C, go to c:\htand 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 HiTechCcompile

A. Take the PIC16F876, a 28-pin micro. Then look at port A for example. This is a row of 6 p of the micro. Each pin can output 5V or 0V, or read whether the input is 5V or 0V.

Here is sample C code to write a logic level to a port. A value of 1 will product 5V, a 0 will prod //(c)Shane Tolmie, http://www.microchipc.com/, distribute freely for non commercial use on the include this web link somewhere in your document. #include <pic.h> //designed for PIC16F876 main() {

#define OUTPUT 0 #define INPUT 1 ADCON1=7; //switch all pins in port A to digital (otherwise it tries to do A/D) TRISA0=OUTPUT; //change port RA0 direction to output RA0=1; //produce 5V on RA0, pin 2 of micro RA0=0; //produce 0V on RA0, pin 2 of micro }

Alternatively, you can read the value of the logic level on a port. If it is 0V, it will return a 0, it i Here is sample C code.

//(c)Shane Tolmie, http://www.microchipc.com/, distribute freely for non commercial use on the include this web link somewhere in your document. #include <pic.h> //designed for PIC16F876 main() { unsigned char x; #define OUTPUT 0 #define INPUT 1 ADCON1=7; //switch port A to digital (otherwise it tries to do A/D) TRISA0=INPUT; //change the port direction to input x=RA0; //now x=0 if RA0=0 volts, and x=1 if RA0=5V. } Researching Data Q. 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 techn company get their info on who distributes for them.

Also, try http://www.findchips.com/ or http://www.freetradezone.com/. I have found this site to comparisons between companies/products and within the microchip line itself. It has been ver the beginning that the chips are so easy to get, cheap, and varied. 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-t high, and the articles are likely to be more correct. For books, search http://www.amazon.com out at your local library or buy it. Good magazines are Circuit Cellar, Electronics Australia, Po Popular Mechanics, among others. 2. Look up previous years projects for other students that have completed 3rd pro design. By can gain sample code and ideas from their writeup. 3.Collect application notes. All the major manufacturers like Philips, Motorola, Atmel, Microch Semiconductor, TI and Zilog have sample projects to illustrate the use of their devices. Look Application Notes, or do a search for 'application notes'.

4. Find the official standards. It may be nice to download information off the web compiled by person, but in my experience dont be satisfied until you have the official documentation. Info private individual may be only mostly correct. 5. Put out a request for information on the web. For the best results, go to http://www.copernic.com/ and download their search program. It is searches and extremely fast. I use it exclusively now, as it gets the best results, culled and so engines. You can use newsgroups on the internet such as comp.arch.embedded.

The Hi-Tech site, http://www.htsoft.com/ has an inhouse newsgroup devoted to PIC questions Search the piclist archive, from http://www.piclist.com/ to look at previous postings.

Subscribe to piclist, http://www.piclist.com/ to ask any question of thousands of PIC enthusias

Look at the PIC webring http://nav.webring.com/cgi-bin/navcgi?ring=picmicro;list which is a co the PIC micro. Search for pic micro on http://www.google.com/, one of the best web-based search engines o 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:

6. Ask the experts. You can email Microchip or Hi-Tech with any questions on their products.

unsigned char x; //8 bits on PIC x=255; x=0xFF; //give hex number, x=255 x=0b11111111; //give binary number, x=255 Q. Whats wrong with the following code? unsigned char x; x=0b1111111; //set x to 0xFF or 255 A. Can you figure it out without looking at the answer? Its a simple error, but its easy to glan Throughout history, it has caused countless hours of wasted time. 0b1111111=127, not 255, Binary values always come in groups of 8 bits, and one should always mentally check that 8 Q. Whats wrong with the following code?

unsigned char i; for (i=7;i>=0;i--) { }; //BAD BUG will loop forever A. A very insidious bug. When it gets to zero, it decrements it and then checks to see wheth zero. But, of course, since its unsigned it has already rolled over to 255. Thus it will loop unti Change variable i to signed, as below: signed char i; for (i=7;i>=0;i--) { }; //works correctly Note that when counting up from 0, chars can be both signed and unsigned as there is no roll

Q. What datatypes are available on a PIC? A. The following: unsigned char a; //8 bits, 0 to 255 signed char b; //8 bits, -128 to 127 unsigned int c; //16 bits, 0 to 65535 signed int d; //16 bits, -32768 to 32767 long e; //32 bits, -2147483648 to 2147483647 float f; //24 or 32 bits, depending on options under edit project

Q. How do I switch bits on and off in a variable? A. Use the following code for turning single bits on or off in a variable. Remember that the b 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 ensu independence, if int changes from 16-bit to 32-bit. Remember that the bits in an 8-bit variable from right to left, 0 to 7. For example, bit 0 of 0b00000001 is 1. Bit 1 is 0, through to the mos left. Example C: unsigned char x=0b0001; bit_set(x,3); //now x=0b1001; bit_clr(x,0); //now x=0b1000;*/ #define bit_set(var,bitno) ((var) |= 1 << (bitno)) #define bit_clr(var,bitno) ((var) &= ~(1 << (bitno)))

Use the following code for turning multiple bits on or off in a variable, according to mask. /*for turning multiple bits on/off according to mask. Use ~0 instead of 0xFFFF, etc, because th independence if int changes from 16-bit to 32-bit. Example C: unsigned char x=0b1010; bits_on(x,0b0001); //now x=0b1011 bits_off(x,0b0011); //now x=0b1000 */ #define bits_on(var,mask) var |= mask #define bits_off(var,mask) var &= ~0 ^ mask 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 nu 0 to 7. For example, bit 0 of 0b00000001 is 1. Bit 1 is 0, through to the most significant bit 7 o Example C: x=0b1000; //decimal 8 or hexadecimal 0x8 if (testbit(x,3)) a(); else b(); //function a() gets executed if (testbit(x,0)) a(); else b(); //function b() gets executed

if (!testbit(x,0)) b(); //function b() gets executed */ #define testbit_on(data,bitno) ((data>>bitno)&0x01) 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 left gives 0b100 or 4. To multiply by four, use x<<=2. By eight, x<<=3. To divide by two, use four, use x>>=2. Having said this, most compilers would optimise a x=x/2 into a shift anyway. A. Use the following code: unsigned int x; unsigned char y; #define hibyte(x) (unsigned char)(x>>8) #define lobyte(x (unsigned char)(x & 0xFF) x=0x1234; y=hibyte(x); //now y=0x12 y=lobyte(x); //now y=0x34

Q. If an integer is 16 bits on a PIC, and a byte is 8 bits, how do I reference one of the bytes in

/*note: the above method is as efficient as pointers, as with Hi-Tech C the optimiser picks out (x>>7) would result in 7 shifts. Local and Global optimisations must be on*/ Note the use of typecasting when converting any variable to another type, one should typec to explain this further. Note, unions are not necessary and are not recommended because pa functions is made more difficult. The above method is good for looking at any variable in any bank of memory. Unfortunately, a byte in an int. For this, pointers are needed. A different #define is needed to alter variables #define lobyte_atbank0(x) (unsigned char)(*(((unsigned char *)&x)+0)) #define hibyte_atbank0(x) (unsigned char)(*(((unsigned char *)&x)+1)) #define lobyte_atbank1(x) (unsigned char)(*(((bank1 unsigned char *)&x)+0)) #define hibyte_atbank1(x) (unsigned char)(*(((bank1 unsigned char *)&x)+1)) Q. Is the following code inefficient? Doesnt x>>=8 have 8 shifts? unsigned int x; unsigned char y; x=0xFF00; y=(unsigned char)(x>>8);

//now y=0xFF

A. No. Its very efficient the Hi-Tech C compiler goes through and just refers directly to the Local and global optimisations must be on in the project. Of course, y=x>>7 would have 7 shi on a PIC. Q. Instead of using (unsigned char)(x>>8) as per the previous question, why dont you use po

A. It is possible, but because there is 4 banks of memory it needs a different #define for varia

simpler and effectively the same to use (unsigned char)(x>>8), unless youre altering the varia Q. Whats the difference between the following two lines of code: x++; if (x>=4) x=0; 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 b count all the way up to the max before wrapping around. Of course, one may want such error 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 code inside it is inserted rather than called. This reduces the overhead of jumping to the f 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 single large line. The only disadvantage is that there is no way to return a variable. For exam code. unsigned char x,y #define domaths_inline(z) \ x+=z; \ y++; void domaths_procedure(unsigned char z) { x+=z; y++; } main() { domaths_inline(4); //puts instructions x+=4;y++ directly into program domaths_procedure(4); //calls procedure which executes instructions x+=4;y++ } Q. Whats wrong with the port initialization code below? //these 4 lines are correct #define INPUT 1 #define OUTPUT 0 #define CLOCK RB1 #define CLOCK_DIRECTION TRISB0 //method 1 - set direction, then port (CORRECT) // CORRECT CLOCK_DIRECTION=OUTPUT; DelayUs(10); //delay 10 microseconds CLOCK=1; //method 2 - set port then direction (WRONG)

// WRONG - MAY LEAVE PORT VALUE AS 0 CLOCK=1; DelayUs(10); //delay 10 microseconds CLOCK_DIRECTION=OUTPUT; Of the two methods above, method is 1 is correct, method 2 is wrong.

If method 2 is used, clock will be set to 1, but since clock is an input, it will change back to a 0 zero. When the port is set to an output, it may be a zero or a one.

Thus, if method 2 is used to set up ports, the port could end up initialized to a zero, instead of With the correct method 1, clock is initially an input. Thus, the value of clock reflects the read Thus, setting any port from an input to an output wont change the value of the port. Once the can be changed to another value.

Rule of thumb: when changing ports from input -> output, always set direction first, then chang Worked Example

To clarify, heres a worked example of what could go wrong in action: 1. We wish to set CLOCK=OUTPUT, and CLOCK to logic level 0 (RA4=0, TRISA4=0). Compa 2. CLOCK=INPUT, on microcontroller (TRISA4=1). All ports are set to input as the power up d 3. An external pull-up resistor has pulled CLOCK to logic level 1 (RA4=1). 4. Setting CLOCK to 0 tries to set clock to 0 (RA4=0). 5. But ... on the next instruction, since CLOCK is an input, it goes high again (RA4=1). 6. Next, CLOCK is set to OUTPUT (TRISA4=0). 7. Now, CLOCK=OUTPUT, and CLOCK is logic level 1 (RA4=1, and TRISA4=0). Compare th 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 th

1. Char variables are 8 bits can be displayed in a variety of formats. 2. Integer variables are 16 bits and the byte order is low:hi in every case, as shown below 3. Long variables are 32 bits and the byte order is low:hi in every case, as shown below. Of course, to display variables inside functions, the switch -fakelocal must be added to the lin switch to work, check that you have the latest version of Hi-Tech C, v7.86pl3 or above. This i on how to set up a project.

Q. How do I add another variable to a watch window? 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 a diagram below. To look at the array named array, select main.array from the add watch sy address 0x21, and shows array[0]. To look at array[1] enter 0x22 as the symbol. Alternatively 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 op in the tutorial on how to set up a project. For this switch to work, check that you have the late v7.85 or above. Errors and what they mean 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 16F87 bytes. Move some variables to another bank, by the following method: unsigned char array_char[79]; //goes in bank0, 96 bytes excluding overhead bank1 unsigned int array_int[40]; //goes in bank1, 96 bytes excluding overhead bank2 unsigned long array_long[24]; //goes in bank2, 96 bytes of 32-bit longs bank3 float array_float[30]; //goes in bank3, 96 bytes of 24-bit floats

After this, use the variables as per normal. However, there are some issues with passing pointers. For example, a function that accepts 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, otherw overflow in expression*/ //strcpy(unsigned char *to,unsigned char *from) //works fine strcpy(bank2 unsigned char *to,bank1 unsigned char *from) { while(*to++ = *from++); //copies strings } bank1 unsigned char x[3];

bank2 unsigned char y[3]; main() { x[0]=O;x[1]=K;x[2]=0; //x contains string Ok strcpy (&y[0],&x[0]); //now array y contains string Ok }

The following error is produced by passing pointers in different banks, so to fix it refer to the c project.obj:33:Fixup overflow in expression (loc 0xFD2 (0xFCC+6), size 1, value 0xA1) (error) Weird quirks of the PIC micro

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 o Q. Port RA4 doesnt work. A. Port RA4 requires a 10k pullup. This is because it can be the input for an external timer. Q. My A/D doesnt work. A. Check out the sample files in the c:\ht-pic\samples\ directory for an example. For sample PIC16F876/77, check out source code. Q. Unexplained Operation and Stack Levels

A. The PIC16F87x has 8 stack levels. This means that function calling in C can be nested up calling is nested more than this, unexplained operation will occur, because the oldest return a Realistically, function calling can only be nested 7 times, because the interrupts use 1, if not m interrupt service routine (ISR) calls a 1 function then 2 stack levels are used just for the interru should never, under any circumstances, call any functions if you use Hi-Tech C. This is becau the function calling area, which takes lots of precious cycles.

The unexplained operation is characterised by the program jumping to functions that it should

If you are unsure, always check to see how many stack levels your program uses. Unfortunate on a PIC micro is not readable or accessible by the program. The best way to check the amount of stack levels used, in Hi-Tech C, is to look at the .map file the linking options. In MPLab, select Project..Edit Project..Node Properties..Map File On.."mai how many levels the function calling is nested. Allow as many stack levels for the interrupts as Another way is to manually keep a track of the stack levels with a counter. Every time a functi the counter. Every time a function is returned from, decrement the counter. Keep a track of the counter gets to, ie:

stack_level++;if (stack_level>stack_level_max) stack_level_max=stack_level; However, this method is not recommended. If your program is big enough to warrant checking

a royal pain to add all the calls. A #define makes it easier, also used to switch on/off the debu 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 with it. Currently I have an 8k, 5000 line C program that works beautifully. Make sure that yo v7.86pl2, as some earlier versions have bugs. For example, v7.84 without the patch level 1 w 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 x++; \ y++ #include <pic.h> unsigned char x,y; main() { DOMATHS; }

A. An insidious problem. Check that theres no invisible spaces after any of the \ characters cursor to every line with a \, and pressing the <end> key. Symptoms? It will generate multiple errors, with the one below as the last one. c:\pic\main.c: 12: illegal character (0134) (error) Serial Port with PIC

Q. Im using a 16F876 PIC micro to communicate to a PC with a serial port. It wont work. Ho

A. Here is PIC Hi-Tech C code, schematic picture and protel 99 files, plus VB 6 example cod Do you have Hyperterminal set to the correct COM port, N,8,1 with no flow control?

Get an oscilloscope, and put it in pin 3 of the serial port. Type some characters, and you shou the oscilloscope. Connect pins 2 and 3 on the serial cable. This makes a loopback. Everything you type in Hyp instead of lost. The PIC sends out 5V logic levels. The serial line operates with 13V/+13V logic levels. Som needed, usually using a MAX232, MAX3222 or SIPEX232 chip. Look up the datasheet and c right. Check the capacitor values. The capacitors need to be a minimum size, anything abov electrolytic caps are fine, if a bit of an overkill. Make sure that the order of the lines into the MAX232 chip is correct, as above.

Check it from the micro side of things. Run the program, downloaded above, and verify that 5 out of the transmit (TX) pin. Check that the crystal speed matches the value used to calculate SPBRG and BRGH. If you 2000, check that the crystal speed, set in the menu options, matches the ones used to calcula

Send out 0xAA, which is 10101010 in binary. Using the oscilloscope, measure the time betwe that they match the baud rate. If all else fails, change computer and try it on another. 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 re recorded in software, the overrun bit, OERR, gets set. This shuts off all further transmissions. 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 rec buffer in the background, using interrupts. Its almost like the hardware serial port on a high-en Interrupts Q. How do I use interrupts?

A. Interrupts are very useful. When a certain event happens such as the logic level on a p overflowing or a serial character arriving a flag is set. For example, if the logic level on port the flag INTF will get set. If the particular interrupt is enabled, the current state of the processor is saved, and execution routine.

For example, if INTE is enabled, then it will jump to the interrupt routine as soon as INTF is se 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

#include <pic.h> main() { //set up capture port interrupt CCP1CON=0B00000100; //every falling edge of clock interrupts it CCP1IE=1; //enable capture port interrupt on data line PEIE=1; GIE=1; //global interrupt enable while(1); //whiz around doing nothing until interrupted, it jumps to isr } /*note the keyword interrupt. Hi-Tech C handles the code to save and restore the state of the calculating the address to hook into the interrupt*/ interrupt isr() { //when clock line goes low, falling edge, it reads data line if (CCP1IF) //clock line falling edge on CCP1IF, RC2, pin 13 on micro { CCP1IF=0;

//read data line in here } } 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 chain is enabled. The diagram below has been reproduced from the PIC16F876 manual, from interrupts. For example, to enable the interrupt on the 16-bit timer 1 overflow, TMR1IE, PEIE enabled for the interrupt to interrupt to CPU. If PEIE or GIE is disabled, it will never jump to t

2. You must clear the interrupt flag, and in some cases read the port involved with the inter interrupt routine. Otherwise, it will keep going back into the interrupt routine continuously for e 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 op program store a temporary copy of the variable in a register. If the interrupt comes along and 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 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 include this web link somewhere in your document. //WRONG METHOD x IS REFERENCED IN BOTH MAIN() AND INTERRUPT //unsigned char x; //correct method volatile unsigned char x; #define FALSE 0 #define TRUE 1 main() { INTE=1;

GIE=1; x=FALSE; while(x==FALSE) { //idling loop waiting for interrupt to change x //if x is not declared volatile, it will check its value from a temporary //register. When the interrupt changes x in ram, it will never know. } //wait for interrupt to change x to true, reaching this portion of code } interrupt isr() { //interrupt on port RB0 change if (RBIF) { RBIF=0; x=TRUE; } }

Q. Pins RB4 to RB7 all generate a common interrupt on change, RBIF. How do I tell what pin from? A. Keep a record of the previous state of the port, and use XOR to work out what pin change

//(c)Shane Tolmie, http://www.microchipc.com/, distribute freely for non commercial use on the include this web link somewhere in your document. #include <pic.h> main() { RBIE=1; GIE=1; while(1); //wait doing nothing } unsigned char prev_portb=0; interrupt isr() { //work out which pin portb changed to produce this interrupt if (RBIF) { RBIF=0; if ((prev_portb ^ PORTB) == 0B00010000) { //pin RB4 changed if ((PORTB & 0B00010000) == 0)

{ //now its 0, so its a falling edge //execute code here (only on falling edge) } } if ((prev_portb ^ PORTB) == 0B00100000) { //pin RB5 changed //execute code here (on pin change) } prev_portb=PORTB; } } Q. How do I execute some code precisely every 800us at 4MHz?

A. Use the built in timer. Set it up so when it rolls over it triggers an interrupt. When the inte flag T0IF high and executes some code. For this example, we will use the 8-bit timer 0, available on PIC micros. If the micro is running at 4Mhz, it is executing instructions at clk/4 speed, or 1MIPS. This is 1 For 800us, we need 800 timer ticks before it rolls over. The timer rolls over at 0xFF, or 255. 255 is smaller than 800, so use 4 lots of 200 ticks using

If we want 200 ticks, and the timer counts up and rolls over at 255, we need to set the timer to count up to 255. Note that the prescaler is not rewritten each time this needs to be only set manual seems to indicate that whenever tmr0 is rewritten, it rewrites the prescaler. However, 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, h 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 include this web link somewhere in your document. #include <pic.h> #define POLLING_PERIOD 200 //with 4Mhz processor, 200us #define TMR0_PRESCALER 1 //gives 1:4 prescaler //the -3 factor is to make up for overhead //the 0xff- factor is because the timer counts *up* to 0xff //do not change this #define TMR0_SETTING (0xff - (POLLING_PERIOD-3)) main() { OPTION&=0B11000000;

//turn off bottom 6 bits to configure tmr0

OPTION|=TMR0_PRESCALER; //set prescaler to 1:4 while(1) { TMR0=TMR0_SETTING; T0IF=0; while(T0IF==0); //wait 800us for flag to go high //OK, tmr0 has overflowed, flag T0IF has gone high //this code right here is executed every 800us } } Method 2: generate an interrupt to execute code every 800us in background

//(c)Shane Tolmie, http://www.microchipc.com/, distribute freely for non commercial use on the include this web link somewhere in your document. #include <pic.h> #define POLLING_PERIOD 200 //with 4Mhz processor, 200us #define TMR0_PRESCALER 1 //gives 1:4, 800us //the -5 factor is to make up for overhead //the 0xff- factor is because the timer counts up to 0xff #define TMR0_SETTING (0xff - (POLLING_PERIOD-5)) main() { OPTION&=0B11000000; //turn off bottom 6 bits to configure tmr0 OPTION|=TMR0_PRESCALER; //set prescaler to 1:4 //work out which interrupt enable bits to set by referring to diagram T0IE=1; GIE=1; while(1) { //idle, using interrupt to execute code

} } void interrupt isr(void) { if (T0IF) { TMR0=TMR0_SETTING; T0IF=0; //code right here is executed every 800us } } Q. How do I speed up my interrupts? A. Here is a few tips:

Execute the least amount of code possible in the interrupt, do all background processing in th tasks in main() by setting a flag in the interrupt which is polled in main(). See the debt counter this. Do not use any functions in your interrupt. This means the compiler has to save the state of a slows it down. This is a problem of most compilers. Make everything inline or the equivalent b from the function. If you absolutely must have a function, to be on the safe side, use in-line as Double check how many cycles it takes to get into the interrupt.

Here is an example for the PIC16F87x under Hi-Tech C. To check if your interrupt is saving to in the ROM memory window, put a breakpoint at 0x0004, the entry point of the interupt service program until it interrupts. Then, single step until the program gets to the first C line in the ISR it takes to get into the interrupt. Q. Whats wrong with the following interrupt code? //incorrect code (if SSPIE or ADIE is being disabled/enabled in main) interrupt void isr (void) { if (SSPIF) { SSP_INT_SERV(); } if (ADIF) { ADC_INT_SERV(); } //...add other ints here } Symptoms: The program hangs after some minutes.

Use: if (ADIE && ADIF)... and etc. intead of if (ADIF). Consider what will heppen if you will dis some reason (ADIE=0), and the SPI interrupt will occur. both handlers will be executed, not on

expected , because ADIF is set independetly of ADIE value. //correct code (if SSPIE or ADIE is being disabled/enabled in main) interrupt void isr (void) { if (SSPIF && SSPIE) { SSP_INT_SERV(); } if (ADIF && ADIE) { ADC_INT_SERV(); } //...add other ints here } Q. How do I time exact intervals?

My favorite way to handle this 'non-commensurate' intervals problem is to steal a concept from drawing algorithm. Using the current case: 4.00 MHz crystal 1Mhz instruction rate 256 cycles and prescaler of 64 each overflow of the timer represents 256*64 == 16384 microseconds 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

This technique will work for any interval. It can be made perfect for intervals that have a ration instruction cycle time, and can be abitrary close to perfect even for irrational ratios, for examp

Simulator/Emulator Breakpoint Problems Q. I cant seem to get a breakpoint in the right spot. It either wont put one on the line that I wa right line. A. Theres a trick to setting breakpoints. See the closing bracket } in the code? It hasnt got 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 want it. Use the #define to set b (for breakpoint) to inline assembly language, asm(nop). N Operation it doesnt do anything.

Emulator Problems 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 va initially. If a program doesnt initialise its variables, it will work in the simulator and emulator, b chip. Rule of thumb: Initialise every variable to a known value before using it

2. Is the chip programmed at all? 3. Is the chip programmed properly? XT for <8Mhz, HS for >8Mhz, etc. 4. Does the chip have power? Check 5V on the correct pins. 5. Is the reset pin pulled high with a 10k resistor? Check that pin 1 on micro is at 5V. 6. Is the crystal oscillating? Get an oscilloscope and touch it to the oscillator pins on the m be buzzing. If ts not oscillating, it means either the chip is not programmed at all, or not programmed proper capacitors are the wrong value, or your circuit is broken or wrong somehow. Check manual. 1 right, depending on frequency. You can check the value of the capacitors down in the electro component tester. 7. I all else fails, program up a chip with the following program, then check to see if the por #include <pic.h> main() { TRISB=0x0; //output while(1) { PORTB=0;PORTB=0xFF; } }

Q. My program works with the ICEPIC 2000 but not the ICD emulator.

A. Add the switch -ICD under the linker options, menu project then edit project then node reserves the last 256 bytes of memory, and 13 miscellaneous ram bytes that the ICD uses. C 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. 2. Crystal speeds of lower than 8MHz use XT for the oscillator setting instead HS.

When using an external crystal with speeds of higher than 8Mhz use the settings as sho

3. When using a RC oscillator for the clock, made up of a resistor and a capacitor, use RC instead of HS. Watchdog Timer 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 fro power supply or a rogue program. When the chip is programmed, the watchdog timer bit is en turned off in software, in case a rogue program overwrites it. If the timer is not reset regularly instruction, it will reset the micro. This will happen within 18ms to 2 seconds, depending on th

Q. After I programmed my PIC, it kept restarting itself every couple of seconds. A. Have you got the watchdog timer bit set? The watchdog is a good way to ensure that the freeze forever from a crash. When the chip is programmed, the watchdog timer bit is enabled in software, in case a rogue program overwrites it. If the timer is not reset regularly with a CLR

reset the micro. This will happen within 18ms to 2 seconds, depending on the prescaler selec temperature. It is interesting to note that it is possible to make a PIC into an accurate temperature sensor u watchdog timeout to sense the temperature.

The advantage of using a watchdog timer is that the micro is protected from crashing forever d 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 optimisations, they can vary. Thats why some of the routines have inline assembly. Delay ro download.

Q. How do I measure the time code takes? A. If youre using the simulator or the ICEPIC 2000, bring up the stopwatch under menu win 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 time code, then check it again at the finish. The timer increments at the same frequency as instruc maths and you have the time in clock cycles that the code takes. Q. How do I make a variable oscillate, ie: go 1-0-1-0 A. Do the following code: unsigned char x; x=1-x; //every time this statement is executed, x goes 1-0-1-0-1-0 etc

Q. How do I reset the micro? A. One way is to reset all variables to their defaults, as listed in the PIC manual. Then, use a jump to location 0x0000 in the micro. #asm ljmp 0x0000 #endasm This is quite safe to use, even when called within interrupts or procedures. The PIC 16x serie levels. Each time a procedure is called, one stack level is used up for the return address. It is even if the micro is 7 procedure levels deep and in an interrupt when a reset is called, this is t

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() i code. When you want the micro to reset, stop clearing the watchdog bit and the micro will res seconds depending on the prescaler. Q. Theres a variable in the PIC manual that the compiler doesnt recognise, even though I us 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 t internal variables. This is extremely useful for finding out exactly what variables are available example code from the header file, pic1687x.h for the PIC16F87x micro: /* * Header file for the Microchip * PIC 16F873 chip * PIC 16F874 chip * PIC 16F876 chip * PIC 16F877 chip * Midrange Microcontroller */ //[added for FAQ] we can see that the compiler has called PORTA by the same name as the m static volatile unsigned char PORTA @ 0x05; //[added for FAQ] ... the listing continues on ... /* PORTA bits */ static volatile bit RA5 @ (unsigned)&PORTA*8+5; static volatile bit RA4 @ (unsigned)&PORTA*8+4; //[added for FAQ] we now know that each bit in PORTA is called, for example, RA5, as per ma //[added for FAQ] ... the listing continues on ...

Q. Whats the rule of thumb for timeouts? A. Rule of thumb: every time a program waits for an operation that could fail, have a timeout time. For example, reading in a byte with SPI. There is the clock and data line, and a byte wi micro. If the sender of the byte stops halfway through, there is four garbage bits remaining. L the sender sends a new byte. Everything is now out of sync, with the first half going into one 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 include this web link somewhere in your document. // example of how to use timeouts: unsigned int timeout_int; //for max 491512us timeout @ 8Mhz //for max 245756us timeout @ 16Mhz timeout_int=timeout_int_us(500); while(timeout_int-- >= 1) {

if (x==y) break;

//typical overhead for checking ring buffer

} if (timeout_int<=2) { //theres been too much time elapsed } //for max timeout of 1147us @ 8Mhz //for max timeout of 573us @ 16Mhz timeout_char=timeout_char_us(500); while(timeout_char-- >= 1) { if (x==y) break; //typical overhead for checking ring buffer } if (timeout_int<=2) { //theres been too much time elapsed } /* Time taken: optimisations on: 9cyc/number loop, 4.5us @ 8Mhz with extra check ie: && (RB7==1), +3cyc/number loop, +1.5us @ 8Mhz Formula: rough timeout value = (<us desired>/<cycles per loop>) * (PIC_CLK/4.0) */ #define LOOP_CYCLES_CHAR 9 //how many cycles per loop, optimisations on #define timeout_char_us(x) (unsigned char)((x/LOOP_CYCLES_CHAR)*(PIC_CLK/4.0)) #define LOOP_CYCLES_INT 16 //how many cycles per loop, optimisations on #define timeout_int_us(x) (unsigned int)((x/LOOP_CYCLES_INT)*(PIC_CLK/4.0))

Q. I need more space in the micro 8k is not enough for a 16F876. A. Youve done well. One thing to check is that you havnt got any orphaned functions which Tech C includes the code, even though it is redundant. To automatically check for this, set th (negative nine) under menu Project then Edit Project then node properties. This introduces 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, bu youre not going to use it, comment it out.

You must have your project set up to 'compile at once' rather than 'linked' for the compiler to g tutorial. 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() r correct header file. It uses an extra 650 words of program memory. See the sample code he 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 Ed Properties. This uses up a additional 1600 words of rom space, but it allows printf to print lon Q. How do I store large amounts of data?

A. Use EEPROM or the Dataflash available from Microchip or Atmel. Capacities range from volatile chips.

Hardware for PIC 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, b rails. Attach the port to the middle between the LEDs. Connect a current limiting resistor in se rail and the top LED, and between the GND rail and the bottom LED. Different color LEDs req 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://w search for miniSMDC075. These are tiny autoresetting fuses that limit the current to no mor 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 seem the frequency. 2. Put the micro into sleep mode. It can wake itself up when an internal timer rolls over. B operations, in software and hardware, before putting the micro to sleep. For example, if a ser received in hardware, wait until it is fully received before shutting down. 3. Switch off external peripherals when they are not in use. For example, have one pin on the standby pin of the serial chip. You could even power external chips off the micro, as the m and simply switch off the port when it is not in use. 4. Use the lowest voltage possible. In saying this, be very careful to look up the voltage ra using it in your circuit. An example is a 5V embedded datalogger, which had a 4Mbit flash chi the AT45D041, the 5V part, the AT45DB041, the 3.5V part, was used. It seemed to work perf was that every 20th page of data read from the chip was completely corrupted. Q. My PIC sometimes resets by itself.

A. Bad power? Brownouts? Put a decoupling cap as close to the power supply as possible, doesnt brown itself out. 0.1uF for <8Mhz, 0.01uF for >8Mhz. Bootloader for PIC16F876 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 doe timeouts, so the code is loaded within 1 second of powerup. It also handles config bits properl 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 programm can crash its running code just like the computer. Pull the plug out of the programmer, shut

restart it, then retry it. This usually fixes the problem.

Q. How do I embed configuration words for the programmer into my C program Q. MPLab always loses my settings for the PICStart plus programmer when I exit A. Use the __CONFIG(); macro in your C code, after #include<pic.h> to set these bits. First, include file for your micro. Then compare this to the include bits in the PIC .pdf manual. For th 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 #define CONFIG_ADDR 0x2007 #define FOSC0 0x01 #define FOSC1 0x02 #define WDTE 0x04 //Watch Dog Timer (Enable low) - (include to disable) #define PWRTE 0x08 //PoWeR Up Timer (Enable low) - (include to disable) #define BODEN 0x40 //Brown Out Detect ENable - active HIGH (include to enable) #define RC (FOSC1 | FOSC0) #define HS FOSC1 #define XT FOSC0 #define LP 0x00 #define CP0 0x1510 #define CP1 0x2A20 /* code protection */ #define UNPROTECT (CP0 | CP1) // unprotected #define PROTECT50 CP1 // upper half program memory code protected #define PROTECT75 CP0 // upper 3/4 program memory code protected #define PROTECT 0x00 // all memory code is protected

Thus, to make PICStart Plus default to HS, Watchdog On, Power up time enabled, Brown Out Unprotected, use the following lines: #include<pic.h> __CONFIG(HS | BODEN | UNPROTECT);

Be careful of PWRTE. According to the PIC manual, this is active low, so missing it out turns t Including it turns it off. This is the same for WTDE. Some compilers recommend linking the fuse names with logical "OR", the symbol "|". Other co 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 For example, there is the following files: delay.c - delay routines in C such as DelayMs(x) delay.h - header file for delay.c

serial.c - serial RS232 routines such as putch() and getch() serial.h - header file for serial.c

One method of using these routines could be to include these files in your project. Put the follo .c file: #include "delay.h" #include "delay.c" #include "serial.h" #include "serial.c" main() { } However, this method has one key disadvantage: even if a routine is not used, it will still take compiled .hex file.

Using a library solves this problem. Once you have made a library out of your commonly used out the necessary routines and includes them in the final .hex file. Q. How do I make a library file?

View the latest answer to this question on MicrochipFault.com; tags PIC HiTechCcompiler

Lets say I have a number of modules, each one an object file, ending in ".obj". I can put these the following at the dos prompt: libr r xx.lib i2c.obj ser_877.obj delay1.obj

I now have a library called xx.lib which can be included in my project. Under 'Project' and 'Edit Path' box, enter the path to xx.lib. If it gives an error, see here. Alternatively, use 'Add Node' to project. 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 HiTechCcompile

A. Under Project..Edit Project, click in 'Library Path'. If you see the following error message, y project incorrectly.

You need install the 3 languages: under "Project..Install Language Tool" for compiler, Assemb

"c:\ht-pic\bin\picc.exe". Select "Project..New project (or Edit Project)" then click on "node property" ***[.HEX] : select language tool: Linker ***[.C]: select language tool: Compiler

If the language tool for ***[.HEX] is set to Compiler, then this means the linker is never used, a additional C files can be added. Serial Numbers with Hi-Tech C 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 HiTechCcompile A. Use the following to preserve the Rom location for a serial number: ;Reserves 4 bytes for Serial Number programming ;To be placed at 0x0FFC to 0x0FFF with the PICC option -L-Ppreserve=ffch ;The 0x0FFF=4096 is for a 4k micro, a 2k or 8k micro would be different psect preserve retlw 0xFF ;Serial No retlw 0xFF ;Serial No retlw 0xFF ;Serial No retlw 0xFF ;Serial No psect preserve

The "-L-Ppreserve=ffch" must be entered in the option field in MPLAB for the HiTech Linker to at the specific address.

The code is saved as an *.as file and included as a node in the MBLAB project and uses the P compile. Remember to set the Assembler in the Language tool to Picc.exe. Incremental Compiles with Hi-Tech C

Q. Under Hi-Tech C and MPLab, every time I recompile, it recompiles everything and then lin incremental compiles? View the latest answers to this question on MicrochipFault.com; tags PIC HiTechCcompile

A. Add the line 'c:\ht-pic\include' under 'include path' in the 'edit project' dialogue to enable inc

You must already have the 'language tool' under the root node set to 'PIC C Linker', not 'PIC C source file to the list to be compiled and then linked. PIC12F672 and OSCCAL Q. How do I set the OSCCAL register in Hi-Tech C for the PIC12F672?

View the latest answers to this question on MicrochipFault.com; tags PIC HiTechC PIC12F HiTechCFAQ

A. If the built-in 4Mhz RC oscillator for the PIC12Cx67x is used, it can drift with temperature v calibration speed is trimmed by setting register OSCCAL at run time. The top ROM byte in me this value at runtime. Looking in the header file, c:\htpic\include\pic1267x.h, we find the following lines, in different p static volatile unsigned char bank1 OSCCAL @ 0x8F; #if defined(_12C672) || defined(_12CE674) #define _READ_OSCCAL_DATA() (*(unsigned char(*)())0x7FF)() #endif Thus, use the following C line at the start of the program: OSCCAL=_READ_OSCCAL_DATA();

If you are using a flash -F- part or a UV-erasable -JW- part, remember to record the value of t It will be in the form retfw N where N=calibration value. For example, if N=0x90, the instruction

I used seven PIC12C672-JW parts in development. The OSCCAL values that I recorded for th 0xB0, 0x84, 0xC8, 0xB0, 0xC0. This illustrates the fact that there is process variation among b

If you lose the value of OSCCAL for a particular JW part, you can retrieve it, with effort. Write 10kHz pulses. Alter the OSCCAL value until the pulses are indeed 10kHz as viewed on an os

Potrebbero piacerti anche