View previous topic :: View next topic |
Author |
Message |
skybox63
Joined: 30 Jun 2018 Posts: 17
|
Assigning port pins to variables |
Posted: Thu Jul 26, 2018 2:30 pm |
|
|
Hello all,
I'm confused and respectfully request some help. I need to use a variable of pin B0 and D0 in my program to avoid duplication, but running into difficulties. Here is a short abstract program to illustrate:
Code: |
16F887
#define testPin PIN_B0
void start_program(){
output_drive(testPin);
output_low(testPin);
}
|
The above works but does not allow me to change the content of variable "testPin" to another pin such as PIN_D0.
I need to alternate between PIN_B0 and PIN_D0. For example, I have two temp sensors one for indoor and one for outdoor. I want to alternate the value of "testPin" from B0 to D0 but to my knowledge can't do it with define statements. I tried using #bit testPin = 0x b.0 to no avail. That said, since these commands are pre-compiler I'm pretty sure it's the wrong approach anyway.
I see that CCS defines PIN_B0 as 48 and D0 as 64 but can't figure out how to put it all together to make it work. I know how to design a function to accept a variable but making a variable to emulate B0 and D0 has me frustrated.
Much appreciated
Roger |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Thu Jul 26, 2018 2:40 pm |
|
|
You just declare a variable:
Code: |
int16 pin_to_use;
pin_to_use=PIN_B0;
output_low(pin_to_use);
pin_to_use=PIN_B1;
output_low(pin_to_use);
|
You don't need 'output_drive', outputting a value to a pin always sets it to drive already.
However there is a major 'caveat'. This takes a _lot_ of code space. A fixed output_high/low codes as just a handful of instructions. The same operation using a variable, takes dozens of instructions. So if you are doing anything involving timing, don't use this solution. Better in this case to encode your own pin macro:
Code: |
#define DRIVE_LOW(pin) if (pin==0) output_low(PIN_B0) else output_low(PIN_B1)
//Then you can use
DRIVE_LOW(0); //drives pin B0 low
DRIVE_LOW(1); //drives pin B1 low
|
Since this uses two fixed definitions, it adds just a couple of line logic test leaving the operation not having to solve what pin to use. |
|
|
skybox63
Joined: 30 Jun 2018 Posts: 17
|
|
Posted: Thu Jul 26, 2018 3:45 pm |
|
|
Thanks I get the top part but confused about the define statement where you have (pin == 0) ? |
|
|
skybox63
Joined: 30 Jun 2018 Posts: 17
|
|
Posted: Thu Jul 26, 2018 4:42 pm |
|
|
Ttelmah,
I read your reply again a little more closely. If I understand correctly you're saying don't use the variable solution if timing is a concern ( which it is). You then state that output_drive is not needed because it ends up being a duplicate statement.
Where I was confused is how you used the define statement to develop a macro - I didn't know about this but did some research and now understand it.
All that said, could you elaborate a bit more on how the macro works. I'll need to resort to something like this because of the timing issue, but don't understand the logic you presented. For example drive_low(pin) and (pin==0)
Is "pin" a replacement for B0 and is drive_low a viable statement?
Sorry if this comes across as elementary but I'm at the beginning stage of learning this language. Again thanks
Roger |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Thu Jul 26, 2018 6:20 pm |
|
|
comment: cause I ain't a real C programmer but I look at it this way...
Quote: |
#define DRIVE_LOW(pin) if (pin==0) output_low(PIN_B0) else output_low(PIN_B1)
//Then you can use
DRIVE_LOW(0); //drives pin B0 low
DRIVE_LOW(1); //drives pin B1 low |
The 'macro' is called 'DRIVE_LOW' that will do 'stuff' based upon what 'pin' is. In this case it will do 1 of two operations.
if 'pin' is really zero, then execute the imediate code, which is output_low(PIN_B0)
if 'pin' is really anything but zero, execute the code AFTER the else, which is
output_low(PIN_B1)
MACROs are a neat, tidy way of creating code , kinda in a 'short hand'. You code a macro once, but can use it all over your program. I look at them as 'small functions' and anyone that started with assembler knows the power of macros.
I'm sure the pros can explain in great detail what's going on, probably entire shelves of books dedicated to macros !
Jay |
|
|
skybox63
Joined: 30 Jun 2018 Posts: 17
|
|
Posted: Thu Jul 26, 2018 7:24 pm |
|
|
Thanks Jay, the macro threw me and still does. I suppose because of its name: DRIVE_LOW(pin). Is this a valid name for a macro? I get the general idea but don't understand the code.
Roger |
|
|
skybox63
Joined: 30 Jun 2018 Posts: 17
|
|
Posted: Thu Jul 26, 2018 8:10 pm |
|
|
I got it now. Did some research and figured it out. Thanks everyone for leading me in the right direction.
Roger |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Thu Jul 26, 2018 8:39 pm |
|
|
Macros can have any names, unless there are 'reserved' words.
DRIVE_LOW(pin) could have been called MY_DRIVE_PIN_B0_LOW_OR_DRIVE_PIN_B1_LOW(pin). which self describes what it does.
It could also be called X(pin) and leave you wondering 3 dayze later 'what does this do ??'
As with any code , add a //comment at the end of the line to remind you what it does. Most assembler guys comment 99% of their code,even the simple obvious stuff cause later on you'll wonder..hmmm, yeah THAT'S what it does !
Like any other language, it take time and reading and practice to become good. It is GREAT that CCS supplies a LOT of examples and drivers. ANother trick is to press F11 while your project is open. It'll launch the CCS Manual,making it easy to lookup 'stuff'.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Fri Jul 27, 2018 1:25 am |
|
|
Macros can be a b&*!ard to learn, but are a very useful tool.
It gets even more fun when you use things like string catenation!.
They can save a huge amount of code typing.
On 'output_drive', I realise that this is only 'unneeded', if you are using standard_io. If you are using fast_io, then it is required. The standard_io 'output_low' instruction, automatically performs an output_drive for you whenever you output something to a pin, and an output_float for you whenever you read a pin. I must admit in the early days of the compiler there were enough problems with standard_io' to make it worth using fast_io. However for the last few years for 99% of code, standard_io, is likely to work better and be much simpler than having to control TRIS yourself. |
|
|
skybox63
Joined: 30 Jun 2018 Posts: 17
|
|
Posted: Fri Jul 27, 2018 7:46 am |
|
|
I agree it can be a bit confusing. The issue with first starting out with learning this language is the barrage of obstacles that come to light when attempting to write a program. As one contemplates solutions for one obstacle three more pop-up in the process. For example, my first question above was how to assign a Port Pin to a variable. The answer was easy enough but it didn't work because it involved timing (DHT11 sensor). I had no clue that assigning the variable to Pin B0 was more time hungry than using the "define" statement.
The macro was also a new revaluation. Although I get the general idea there are 10 locations in the program where I need to alternate between two pins. As such, a macro with this level of sophistication is beyond my knowledge level at this time. At this point, I believe my only solution is to use two "define" statements for the pins and incorporate if/else statements using a flag value. May not be pretty but it will work.
I do have a question though. How do you guys measure the time it takes to complete any particular statement/function? In my way of thinking would I set a timer at the beginning of a statement and read the count variable at the end? Of course the oscillator comes into play. Or is there some handy macro one of you designed that you would like to share
Best
Roger |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Fri Jul 27, 2018 8:04 am |
|
|
You should check the 'code library' here, there may be a driver for the DHT11 sensor, as you're not the first to use it with a PIC and CCS C. If there is one, it'll be a good starting point. Just click the 'search' button ,top of the page...fill in the blanks..see what comes up..
As for timing, I'm old enough to have 'played with PICs' for half my life( I'm 65), so I recall that a 16 series PIC ,using a 4MHz xtal, will execute one instruction every microsecond. Great thing about CCS is the abilty to dump the listing(programname.LST) and you can 'play computer' to calculate the times. Some say the MPLAB simulator is good at timings, though I'm old enough to NOT trust any simulator, prefer to use the Real World and a scope.
If you don't have a scope, save your coins and get one. Even an old school 2 chnl,20MHz CRT style will be a great asset!
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19545
|
|
Posted: Fri Jul 27, 2018 9:10 am |
|
|
On time several ways:
1 Look at the assembler, and count instruction times.
2) Use the MPLAB simulator.
3) Pulse an output pin each side of the operation.
4) Reset a timer.
Just how slow the variable output is, has actually been covered here I think when dealing with Maxim one-wire sensors, where somebody wanted to do a code library portable to several pins.
Problem is 'think about it'.
A #defined name, is that name. Doesn't change at run time.
So compiler can work out 'what port', and 'what bit' at compile time.
Code result is just a bit_set instruction.
A variable, instead involves the compiler in calculating the address of the port to use (it's value/8), and then what bit in this to use. Using indirect addressing of the port with this value rather than a direct addressing, and then generating a mask to access the bit (setting the corresponding bit for the low 3bits of the value), and using this to access the bit. Phew!... |
|
|
skybox63
Joined: 30 Jun 2018 Posts: 17
|
|
Posted: Fri Jul 27, 2018 10:48 am |
|
|
Thanks Jay I'm 63 and most of my time was spent tooling around with "basic". Was a signal officer in the army for 33 years building networks in the latter part of my career. Not much programming experience until I retired in 2008 then took up an interest in micro controllers. Again started with basic but got tired of its work-arounds so moved to "c" a few months ago. I'm caching on but still a lot to learn. I sure appreciate the patience you guys have in assisting. As you probably know all too well the old mind is a little slower than it used to be. Thanks for the heads=up on checking for a library. Laying my cads on the table I found a program someone else designed and now trying to modify it to work with two sensors - hence the timing questions. |
|
|
skybox63
Joined: 30 Jun 2018 Posts: 17
|
|
Posted: Fri Jul 27, 2018 10:56 am |
|
|
Ttelmah,
As always thank you for the detail you put into your answers. I was perplexed as to why the variable solution was timing out while the "define" statement didn't. I know now. LOL, I laid in bed last night half conscious thinking about timing....
Roger |
|
|
|