View previous topic :: View next topic |
Author |
Message |
Geps
Joined: 05 Jul 2010 Posts: 129
|
input_state() With A Variable? |
Posted: Mon Sep 26, 2011 3:46 pm |
|
|
Hi,
I have a subroutine that is designed to check a Pin can go to 5V and 0V as follows:
Code: | int1 test_pin(int16 PinToTest) {
int1 PinState = 0;
// first drive pin to 5 volts
output_high(PinToTest);
// wait briefly
delay_us(100);
// get state:
PinState = input_state(Pin_c4);
// Check if went to 5 volts
if (!PinState) {return (1);}
// Now drive to 0V
output_low(PinToTest);
// wait briefly
delay_us(100);
// get state:
PinState = input_state(PinToTest);
// Check if went to 5 volts
if (!PinState) {return (0);}
else {return (1);}
}
|
However it won't compile as it needs a constant for the input_state() function. Is there a tidy work around or do I have to use a large switch with hard coded pin values?
Cheers, |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Mon Sep 26, 2011 4:35 pm |
|
|
You could read the manual(press F11 when your project is open) and lookup bit_test(...).... and checkout the examples CCS gives either onscreen(F11) or in the examples folder.... |
|
|
Geps
Joined: 05 Jul 2010 Posts: 129
|
|
Posted: Tue Sep 27, 2011 9:12 am |
|
|
I think you misunderstood me - _with_ a variable not _on_ a variable.
The variable should contain the pin to be passed as a parameter of the input_state().
I think I'll just disable fast_io, manually set the TRIS and then use input() instead. |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Sep 27, 2011 9:44 am |
|
|
If you are attempting to do readback of outputs then yes, you have no option other than to *enable" fast_io mode and do the TRIS stuff yourself. The reason for this is that any CCS input function will set the bit/port to input mode and any output function set them to output automatically. If I understand what you're tryin to do, then you need to set the direction to output and then set the output to set the state and input to read it back.
Note that if the readback is ever different from the drive then your PIC is in a state where it may be damaged. At the very least its functioning may be impaired, such as inaccurate ADC readings. You should treat a bad readback as a fatal fault and stop driving the pin immediately and shut everything down to a safe state.
By the way, as all the ports are memory mapped, then they are just variables. Variables that are absolutely addressed and vary with external influence. In otherwords they are volatile in C terms.
Also while your comments state the PIC waits "briefly", 100us is a pretty long time in hardware terms. Certainly enough for damage to occur in many case. It depends on what you are hanging of the output of course, but for any load that the PIC can reliably drive it will be a looooooong time.
And finally, you cannot prove the pin goes to 5V or 0V, or indeed anywhere close. All the input shows is that the output went beyond the Vil or Vih threshold. That may be good enough for the PIC, but it doesn't mean any device driven by the PIC will see good logic levels. If you *really* want to know the voltage then you'll have to read back with an analogue input. In short readbacks don't live up to their promise in many practical situations.
RF Developer.
Last edited by RF_Developer on Tue Sep 27, 2011 9:52 am; edited 1 time in total |
|
|
Geps
Joined: 05 Jul 2010 Posts: 129
|
|
Posted: Tue Sep 27, 2011 9:49 am |
|
|
Thanks RF,
You can use the input_state() function though to read a pin without changing it's direction but I can't seem to get it to work without explicitly saying which pin it should check.
Unless there is a work around I'm missing? |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Tue Sep 27, 2011 9:58 am |
|
|
Oh yes, so it does! Oops.
The pin constants should work for it as normal. Maybe there are are some ports on some PICs that don't work with input_state()... maybe. What PIC are you using?
Ah! It appears that the defintion of input_state() is something like:
int1 input_state(const int16 pin)
which, obvioiusly, requires a constant :-(( |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Tue Sep 27, 2011 10:54 am |
|
|
You could dump the listing to see how CCS does it, then create your own 'check_pin_state' function that allows the pin in question to be a varible and not a constant. |
|
|
Battery David
Joined: 01 Feb 2010 Posts: 25
|
|
Posted: Tue Sep 27, 2011 1:19 pm |
|
|
I know people on this forum (with TONS of experience) usually (always?) say to use normal IO but I have always used fast IO. I don't think I have ever had trouble because of it.
I think the code using the functions looks terrible and this looks much better:
Code: |
#use fast_io(ALL)
/**********************************************************
Port C Defn's
**********************************************************/
#bit cbBlueLED_IO = regPortCDataDir.0
#bit cbPC_Connected_IO = regPortCDataDir.1
#bit cbRedLED_IO = regPortCDataDir.2
#bit cbSCL_IO = regPortCDataDir.3
#bit cbSDA_IO = regPortCDataDir.4
#bit cbTestPoint12_IO = regPortCDataDir.5
#bit cbRS232_TX_IO = regPortCDataDir.6
#bit cbRS232_RX_IO = regPortCDataDir.7
#bit pinBlueLED = regPortCPins.0
#bit pinPC_Connected = regPortCPins.1
#bit pinRedLED = regPortCPins.2
#bit pinSCL = regPortCPins.3
#bit pinSDA = regPortCPins.4
#bit pinTestPoint12 = regPortCPins.5
#bit pinRS232_TX = regPortCPins.6
#bit pinRS232_RX = regPortCPins.7
cbBlueLED_IO = PIN_OUTPUT;
cbPC_Connected_IO = PIN_INPUT;
cbRedLED_IO = PIN_OUTPUT;
// cbSCL_IO = PIN_INPUT;
// cbSDA_IO = PIN_OUTPUT;
cbTestPoint12_IO = PIN_OUTPUT;
// cbRS232_TX_IO = PIN_OUTPUT; // RX & TX are set by the compiler
// cbRS232_RX_IO = PIN_INPUT; // RX & TX are set by the compiler
pinBlueLED = LED_OFF;
// pinPC_Connected = // Input pin, no initial value
pinRedLED = LED_OFF;
// pinSCL = // Input pin, no initial value
// pinSDA = PIN_LOW;
pinTestPoint12 = PIN_LOW;
// pinRS232_TX = // RX & TX are set by the compiler
// pinRS232_RX = // RX & TX are set by the compiler
// to check the state of a pin
if( pinPC_Connected )
{
// Code
}
// to toggle a pin
pinRedLED = !pinRedLED;
// to turn the LED on
pinRedLED = LED_ON;
|
This is not a full program, just the appropriate parts.
BTW, I also spent a bunch of time renaming the control registers to names that make more sense. It took a lot of work but I think it's easier to see regPortCDataDir rather than TRISC (OK, we all know what TRIS means but someone reviewing our code doesn't)
The cool part about handling the port pins this way is, if you change the logic of how an LED turns on and off, you don't have to go through your code and change all of the output_high(PIN) to output_low(PIN), you just have to change the definition of LED_ON at one place in a header file.
Just my way of doing things.
David |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9246 Location: Greensville,Ontario
|
|
Posted: Tue Sep 27, 2011 3:06 pm |
|
|
David
You must know how to touchtype ! Even TRISC is a lot for me as I grew up on 2 letter variables.....early 70s... |
|
|
Battery David
Joined: 01 Feb 2010 Posts: 25
|
|
Posted: Tue Sep 27, 2011 3:28 pm |
|
|
Actually I don't touch type (I can fake it pretty well) and, while I didn't do computers in the 70s, I did use: LET A1 = 3 and had to include line numbers.
It took a lot of self-discipline to get myself to use long variable names. I'm still working on using "Temperature" instead of "Temp" since Temp can have other meanings.
I am a work in progress! |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Sep 28, 2011 6:53 am |
|
|
Back to the original topic:
The v3 compiler did not support variable names in the input and output functions but v4 added this feature to the input(), output_low() and output_high() functions. Too bad the feature wasn't added to the input_state() function.
Basically the input_state() function is the same as input() but without touching the TRIS direction register. This behaviour is easy to simulate by setting the fast_io pragma in combination with input(): Code: | int16 read_pin = PIN_D0;
#use FAST_IO(D)
i = input(read_pin);
#use STANDARD_IO | This works fine except when you don't know which port you are going to read from and/or you don't know what IO-mode the port was using beforehand.
In the old times, before the v4 compiler, PCM Programmer posted a function to read and write from variable pins:
For 16F: http://www.ccsinfo.com/forum/viewtopic.php?t=25280&start=4
For 18F: http://www.ccsinfo.com/forum/viewtopic.php?t=27723&start=3
Based on those functions I came up with the following simplified function: Code: | #include <18F458.H>
#fuses HS,NOWDT,NOLVP
#use delay(clock=16000000)
// input_pin_state() --
// This function reads the level of a pin without changing the direction of the
// pin as input() does. It is identical to the CCS function input_state() but
// will accept variables as parameter as well.
// The ccs_pin parameter must be a value defined in the .H file for your PIC,
// such as PIN_B0, PIN_C5, etc.
//
// Note that this function takes more memory space and code cycles than the
// original CCS function, so only use this when you need the variable PIN name
// functionality.
//
// This function should work for the 12F, 16F and 18F series PICs.
int8 input_pin_state(int16 ccs_pin)
{
int16 io_port;
int8 bitmask;
int8 retval;
io_port = ccs_pin >> 3; // Get the i/o port address
bitmask = 1 << (ccs_pin & 7); // get mask
retval = (*io_port & bitmask) ? 1 : 0; // Read pin (ret. 0 or 1)
return retval;
}
void main()
{
int8 i;
int8 state;
for(i=0; i<8; i++)
{
state = input_pin_state(PIN_D0 + i);
delay_ms(500);
}
#ignore_warnings 203
while(1);
#ignore_warnings none
}
|
|
|
|
Geps
Joined: 05 Jul 2010 Posts: 129
|
|
Posted: Fri Sep 30, 2011 9:33 am |
|
|
Thanks alot ckielstra. |
|
|
|