On Mon, April 2, 2012 4:34 pm, eMyListsDDg wrote:
> new to using hi-tech c and would like to know which is preferred way to
> define a pin for use.
>
> one can use TRIS, PORT or LAT bits to define a pin to put a LED on, yes?
>
> does one use one of the above or is it as simple as this?
>
> #define LED1 RA0
>
>
> i'm a bit unsure which of the SFRs such as listed above that one would
> use. i'm using 16f88
On a PIC16F88, I would use:
#define LED1 PORTAbits.RA0
TRIS defines the direction (TRIState), PORT is the I/O, LAT defines an
output LATch (but isn't on the PIC16F88- it was introduced on later PICs,
like the PIC18Fxxxx and the PIC24, dsPICs, etc).
Matt Bennett
Just outside of Austin, TX
30.51,-97.91
The views I express are my own, not that of my employer, a large
multinational corporation that you are familiar with
>
> new to using hi-tech c and would like to know which is preferred way to define
a pin for use.
>
> one can use TRIS, PORT or LAT bits to define a pin to put a LED on, yes?
>
> does one use one of the above or is it as simple as this?
>
> #define LED1 RA0
>
> i'm a bit unsure which of the SFRs such as listed above that one would use.
i'm using 16f88
> Yes, it is that simple. Make sure that you set corresponding TRIS bit to output, in your case: TRISA = 0bxxxxxxx0;
where x - 0 or 1
for simple use no need to do anything else. You should #include <htc.h> file,
it defines all different SFRs for the processor you use.
Sergey Dryga http://beaglerobotics.com
> eMyListsDDg<emylistsddg<at> gmail.com> writes:
>
>>
>> new to using hi-tech c and would like to know which is preferred way to define
> a pin for use.
>>
>> one can use TRIS, PORT or LAT bits to define a pin to put a LED on, yes?
>>
>> does one use one of the above or is it as simple as this?
>>
>> #define LED1 RA0
>>
>> i'm a bit unsure which of the SFRs such as listed above that one would use.
> i'm using 16f88
>>
> Yes, it is that simple.
> Make sure that you set corresponding TRIS bit to output, in your case:
> TRISA = 0bxxxxxxx0;
>
> where x - 0 or 1
>
> for simple use no need to do anything else. You should #include<htc.h> file,
> it defines all different SFRs for the processor you use.
>
> Sergey Dryga
> http://beaglerobotics.com
So, it's not that simple, since you also need to set the tris bit to the right state. Which could involve another macro statement, like:
#define LED1_TRIS_BIT SomeTrisBitUnion.SomeTrisBit And maybe another level of macro like #define ENABLE_LED (some code)
It is good to know that rather than set the whole tris reg, in the case where some other code has already set it up, you can just (re)set the individual bit with a bit instruction or a bitwise AND or OR.
Joe Wronski <jwronski <at> stillwatereng.net> writes:
> So, it's not that simple, since you also need to set the tris bit to the
> right state. Which could involve another macro statement, like:
> #define LED1_TRIS_BIT SomeTrisBitUnion.SomeTrisBit And maybe another
> level of macro like #define ENABLE_LED (some code)
>
Sure, one can make life as complicated, or as simple, as one wishes. For the OP question, the whole program can be as simple as:
#include <htc.h>
//define XTAL_FREQ, needed for __delay_ms()
#define _XTAL_FREQ 20000000
or, one can define a whole set of macros and write several functions to turn LED
on and off. It all depends on one's style and needs of the project (and also on
one's definition of "simple" :-) ).
>
> On 4/2/2012 7:08 PM, Sergey Dryga wrote:
> > eMyListsDDg<emylistsddg<at> gmail.com> writes:
> >
> >>
> >> new to using hi-tech c and would like to know which is preferred way
> >> to define
> > a pin for use.
> >>
> >> one can use TRIS, PORT or LAT bits to define a pin to put a LED on,
> yes?
> >>
> >> does one use one of the above or is it as simple as this?
> >>
> >> #define LED1 RA0
> >>
> >> i'm a bit unsure which of the SFRs such as listed above that one
> would use.
> > i'm using 16f88
> >>
> > Yes, it is that simple.
> > Make sure that you set corresponding TRIS bit to output, in your
> case:
> > TRISA = 0bxxxxxxx0;
> >
> > where x - 0 or 1
> >
> > for simple use no need to do anything else. You should
> > #include<htc.h> file, it defines all different SFRs for the
> processor you use.
> >
> > Sergey Dryga
> > http://beaglerobotics.com
>
> So, it's not that simple, since you also need to set the tris bit to
> the right state. Which could involve another macro statement, like:
> #define LED1_TRIS_BIT SomeTrisBitUnion.SomeTrisBit And maybe another
> level of macro like #define ENABLE_LED (some code)
>
> It is good to know that rather than set the whole tris reg, in the case
> where some other code has already set it up, you can just (re)set the
> individual bit with a bit instruction or a bitwise AND or OR.
Yes, this is something I've struggled with when writing my tutorials -
deciding what the best advice to give is. There's certainly a need to teach
good practices, such as defining pins using macros, whether at the start of
the program or in a header, making the code far more maintainable - I make
the point that pin assignments can and do change, and you don't want to be
ferreting around trying to find everywhere you've referred to each LED. On
the other hand, you can end up with so many macros that the code becomes
lost and so does the point I'm trying to explain.
So I've ended up with a compromise. I define macros for individual pins
like this, and/or for the shadow equivalents of them, but not TRIS - or
others such as enabling pull-ups or interrupt on change (it can go on and
on). Instead I keep all port configuration in a single initialisation
routine. So, if a pin assignment changes later, I only need to make two
changes - a macro at the start of the program, and in the initialisation
code - which could be much more than changing one TRIS expression. Maybe
the new pin has an analog input that has to be disabled, while the old one
didn't.
But of course there are always exceptions. If you have some code that
flipping a pin between input and output (say multiplexing a switch with an
output), then sure it's best practice to define macros for the TRIS bits and
changing them one at a time to avoid affecting anything else, as you say.
At the end of the day, some level of judgement has to apply. There can't be
one rule fits all.
David Meiklejohn <david <at> gooligum.com.au> writes:
>
> Sergey Dryga wrote:
> >
> > //define XTAL_FREQ, needed for __delay_ms() #define _XTAL_FREQ 20000000
>
> Slightly off-topic, but - that can't work can it? The whole line is a
> comment.
>
> Don't you need:
> #define _XTAL_FREQ 20000000 //define XTAL_FREQ, needed for __delay_ms()
David Meiklejohn <david <at> gooligum.com.au> writes:
> So I've ended up with a compromise. I define macros for individual pins
> like this, and/or for the shadow equivalents of them, but not TRIS - or
> others such as enabling pull-ups or interrupt on change (it can go on and
> on). Instead I keep all port configuration in a single initialisation
> routine. So, if a pin assignment changes later, I only need to make two
> changes - a macro at the start of the program, and in the initialisation
> code - which could be much more than changing one TRIS expression. Maybe
> the new pin has an analog input that has to be disabled, while the old one
> didn't.
It's good to know how other people do it. I have come to exactly the same
practice (although I do not have to teach others PIC programming). I also put
all pin definitions in an include file, and provide description of pin
functions, so that even without looking at the schematics, it is clear what a
pin does.
Regards,
Sergey Dryga http://beaglerobotics.com
> On a PIC16F88, I would use:
> #define LED1 PORTAbits.RA0
In most cases this will put you at the mercy of the Read-Modify-Write problem. Better define a bit in a porta-shadow register, chacge that bit, and copy it to PORTA after each change of any bit.
>> On a PIC16F88, I would use:
>> #define LED1 PORTAbits.RA0
> In most cases this will put you at the mercy of the Read-Modify-Write
> problem. Better define a bit in a porta-shadow register, chacge that
> bit, and copy it to PORTA after each change of any bit.
Read-Modify-Write - Something that every PIC programmer should be aware of.
Whenever you write a bit on any register, including port registers, the CPU actually reads the whole register, modifies the bit you want to set/clear and then writes the whole register back. When you write a port pin it sets a latch on that port but when you read it, it is the actual voltage on the port pin that is read.
This would all be fine in an ideal world. However, it can take some time for the actual voltage on a port pin to rise from a 0 to a 1 (or vice versa). This is depending on the capacitive and resistive load on that pin.
Before the port pin output voltage have reach the threashold value for a digital 1 on the input circuitry for that pin it will be read as a 0. So even if you have set the port pin latch to a 1, it can take some time before the port register bit for that pin will be read back as a 1.
Now, if you set two bits on the same port right after each other, the second write can reset the first because the output pin for the first bit has not settled to a high level yet (as read by the input circuitry).
There are a couple of ways to solve this.
On newer pics, each port actually has two registers, the port pin register itself that sees the voltage on the port pin and also the latch register that holds the value last written to the port. The latch register is always a 1 when it has been set to a 1 even if the voltage on the port pin hasn't reached its final voltage yet (and ofcourse vice versa for a 0). Therefor you should use the latch register when writing individual bits to a port since a read on that register always reflects what was last written.
Older pics can't read the latch register so there you have to solve the problem by not writing individual bits to a port register one at a time but instead always write all bits at once. You do this by using a shadow register (which works the same way as the latch register). Set and clear individual bits to the shadow register and then copy this whole register to the actual port register. This way, writing an individual bit to an outport, never involves a read on that port.
> not sure i fully understand your suggestion. could you provide a a few lines
> of code for me to view?
>
> thank you
>
>
> >> On a PIC16F88, I would use:
> >> #define LED1 PORTAbits.RA0
>
> > In most cases this will put you at the mercy of the Read-Modify-Write
> > problem. Better define a bit in a porta-shadow register, chacge that
> > bit, and copy it to PORTA after each change of any bit.
>
> > --
>
> > Wouter van Ooijen
>
> > -- -------------------------------------------
> > Van Ooijen Technische Informatica: http://www.voti.nl
> > consultancy, development, PICmicro products
> > docent Hogeschool van Utrecht: http://www.voti.nl/hvu
> > C++ on uC blog: http://www.voti.nl/erblog
>
>
>
>
> --
> Bill
> Key fingerprint = DB4D 251B FE8A BDCD 2BE4 E889 13F1 78D0 A386 B32B
>
Here is an example of using a dummy port variable. This code is for a standard LCD.
void display(unsigned char *tmpPtr)
{
unsigned char currentCH; //THIS IS THE SHADOW PORT VARIABLE
rs=0; //RS in Command mode for position byte
while(*tmpPtr) //LCD Data on bits D4-D7 of PORT
{
currentCH=*tmpPtr; //DATA IS COPIED TO SHADOW PORT VARIABLE
LCDPORT&=0x0F; //THIS IS THE REAL PORT, #define LCDPORT PORTB
LCDPORT|=(currentCH&0xF0); //Mask off upper nibble REAL PORT COPIES SHADOW PORT VARIABLE CONTENTS.
sendit(rs);
currentCH<<=4; //Now select lower nibble
LCDPORT&=0x0F;
LCDPORT|=currentCH;
sendit(rs);
t40();
rs=1; //make sure RS is in data mode
tmpPtr++; //get next character
}
eMyListsDDg wrote:
>
> not sure i fully understand your suggestion. could you provide a a few
> lines of code for me to view?
This was after Wouter wrote:
> >
> > In most cases this will put you at the mercy of the Read-Modify-Write
> > problem. Better define a bit in a porta-shadow register, chacge that
> > bit, and copy it to PORTA after each change of any bit.
Here's one example, showing how I've set up a shadow register as a union,
making it possible to refer to the whole register ("GPIO = sGPIO.port") or
to individual shadow bits with logical names ("sFLASH = 1"). Don't be
scared off - the lessons start simpler than this!
/************************************************************************
* *
* Description: Lesson 3, example 4 *
* *
* Demonstrates use of Timer0 in counter mode *
* *
* LED flashes at 1 Hz (50% duty cycle), *
* with timing derived from 32.768 kHz input on T0CKI *
* *
*************************************************************************
* *
* Pin assignments: *
* GP1 = flashing LED *
* T0CKI = 32.768 kHz signal *
* *
************************************************************************/
#include <htc.h>
#include <stdint.h>
/***** CONFIGURATION *****/
// ext reset, no code protect, no watchdog, int RC clock
__CONFIG(MCLRE_ON & CP_OFF & WDT_OFF & OSC_IntRC);
// Pin assignments
#define sFLASH sGPIO.GP1 // flashing LED (shadow)