|
|
View previous topic :: View next topic |
Author |
Message |
Charles Linquist
Joined: 07 May 2005 Posts: 28 Location: Campbell, CA
|
Individual port bits |
Posted: Thu May 26, 2005 12:34 pm |
|
|
Please excuse me if I'm dense, but I have looked through the manual, and I can't find how to do something.
I would like to read all bits of a port at one time - (map them to a variable), and then test each bit individually.
Can someone show me how to do this? |
|
|
valemike Guest
|
|
Posted: Thu May 26, 2005 12:52 pm |
|
|
you need to define a RAM variable...
#byte PORT_B 0x07 // device-dependent mapping
...
unsigned char my_port_b;
...
my_port_b = PORT_B;
...
if (port_b & 0x01) // is port_b bit 0 a 1?
{
...
}
if (port_b & 0x02) // is port_b bit 1 a 1?
...
if (port_b & 0x10) // is port_b bit 4 a 1?
{
} |
|
|
valemike Guest
|
oops |
Posted: Thu May 26, 2005 12:53 pm |
|
|
all the (port_b ...) in parenthesis should be "my_port_b" |
|
|
DragonPIC
Joined: 11 Nov 2003 Posts: 118
|
|
Posted: Thu May 26, 2005 12:56 pm |
|
|
Code: | #byte port_b 6
int read;
int bit;
main()
{
read = port_b; // or you could use "read = input_b();" which will also change your port direction to input if not already when using #use standard_IO directive
if(bit_test(read,3)) bit = 1;
else bit = 0;
} |
There are other ways to test each bit like:
Code: | int i, temp; //added variables
int bit[8]; // changed to an array
for(i = 0;i<8;i++)
{
temp = (read>>i)&0x01
if (temp) bit[i] = 1;
else bit[i] = 0;
} |
_________________ -Matt |
|
|
Charles Linquist
Joined: 07 May 2005 Posts: 28 Location: Campbell, CA
|
|
Posted: Fri May 27, 2005 9:01 am |
|
|
Thanks! Your answers and code were very helpful. |
|
|
seven
Joined: 26 May 2005 Posts: 10
|
|
Posted: Thu Jun 02, 2005 5:51 am |
|
|
valemike wrote: | you need to define a RAM variable...
#byte PORT_B 0x07 // device-dependent mapping
...
unsigned char my_port_b;
...
my_port_b = PORT_B;
...
if (port_b & 0x01) // is port_b bit 0 a 1?
{
...
}
if (port_b & 0x02) // is port_b bit 1 a 1?
...
if (port_b & 0x10) // is port_b bit 4 a 1?
{
} |
how do you know that port is 0x07?
could you say me please the mapping for PORTA,C,D,E for a pic18F4550.
thank you |
|
|
valemike Guest
|
|
Posted: Thu Jun 02, 2005 6:08 am |
|
|
Looking at the datasheet of the PIC18F4550, go to page 68 of the .pdf file. Page 68 of the .pdf file is also page 66 in print. You'll see a table that maps all the registers. So for the PIC18F4550
#byte PORT_A 0xF80
#byte PORT_B 0xF81
#byte PORT_C 0xF82
I was just making up the 0x07 because i was too lazy last time to download the datasheet. |
|
|
seven
Joined: 26 May 2005 Posts: 10
|
|
Posted: Thu Jun 02, 2005 9:02 am |
|
|
valemike wrote: | Looking at the datasheet of the PIC18F4550, go to page 68 of the .pdf file. Page 68 of the .pdf file is also page 66 in print. You'll see a table that maps all the registers. So for the PIC18F4550
#byte PORT_A 0xF80
#byte PORT_B 0xF81
#byte PORT_C 0xF82
I was just making up the 0x07 because i was too lazy last time to download the datasheet. |
thank you |
|
|
UFAnders
Joined: 13 Apr 2005 Posts: 36 Location: Michigan
|
input_b()&MASK is adding 64 to real value! |
Posted: Thu Jun 09, 2005 2:33 pm |
|
|
Fellas, I have a problem-->
My code line is pretty simple; read PORTB within some pin range and display them through the serial port:
Code: | buttons = (input_b()&0b00011111);
...
fprintf(swrs232, "X=%04lu\tY=%04lu\tZ=%04lu\tButtons:%03u\r", ADCResult0, ADCResult1, ADCResult2, buttons);
|
But for some reason, this is what I get:
Quote: | X=0390 Y=0360 Z=0502 Buttons:064 |
What I have noticed is that it does display "Buttons:000" until I get near the unit physically. What I'm thinking is that some static charge is energizing the floating PIN_B7, but it's masked in my read routine! All of my button inputs are pulled down by 33K resistors, and the button current is fed through a single 330 ohm resistor. Any ideas? You guys are invaluable! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jun 09, 2005 2:42 pm |
|
|
Post a very small (but complete) program that demonstrates the problem.
Post all #fuses, #use, and #include statements. Post a list of all the
wiring connections to Port B pins. Don't leave anything out. |
|
|
UFAnders
Joined: 13 Apr 2005 Posts: 36 Location: Michigan
|
input_b()&MASK is adding 64 to real value! |
Posted: Thu Jun 09, 2005 2:50 pm |
|
|
Aiight, here we go - this is the main() from my I2C slave that updates everything whilst it waits for the master to poll it. The SSP ISR does nothing to/with variable 'buttons':
Code: | #include <18F2520.h>
#device adc=10
#include <stdlib.h>
#fuses HS, NOWDT, NOLVP, PUT, NOPROTECT
#use delay(clock=20000000)
#use i2c(SLAVE, ADDRESS=0xA0, FORCE_HW, FAST, SCL=PIN_C3, SDA=PIN_C4)
#use rs232(BAUD=9600, BITS=8, PARITY=N, XMIT=PIN_C1, RCV=PIN_C2, INVERT, STREAM=swrs232)
int8 ADCHighByte, ADCLowByte, buttons;
int16 ADCResult0=0, ADCResult1=0, ADCResult2=0;
typedef enum {NOTHING, CONTROL_READ,
ADDRESS_READ, READ_COMMAND_READ} I2C_STATE;
I2C_STATE fState = NOTHING;
BYTE address=0x00, buffer[0x10];
int8 i;
void main()
{
setup_adc_ports(AN0_TO_AN2|VSS_VDD);
setup_adc(ADC_CLOCK_DIV_8);
enable_interrupts(INT_SSP);
enable_interrupts(global);
for (i=0;i<0x10;i++) buffer[i] = 0x00;
putc('\f');
while(1)
{
buttons = (input_b()&0b00011111);
if(buttons>0)
{
output_high(PIN_C2);
}
else
{
output_low(PIN_C2);
}
//output_high(PIN_C0);
set_adc_channel(0);
ADCResult0=read_adc();
set_adc_channel(1);
ADCResult1=read_adc();
set_adc_channel(2);
ADCResult2=read_adc();
fprintf(swrs232, "X=%04lu\tY=%04lu\tZ=%04lu\tButtons:%03u\r", ADCResult0, ADCResult1, ADCResult2, buttons);
//output_low(PIN_C0);
// ADCHighByte = ADCResult >> 8;
// ADCLowByte = ADCResult & 0xFF;
//
if(ADCResult0<341)
{
output_high(pin_C5);
output_low(pin_C6);
output_low(pin_C7);
}
else if(ADCResult0>342 && ADCResult0<480)
{
output_high(pin_C6);
output_low(pin_C5);
output_low(pin_C7);
}
else
{
output_high(pin_C7);
output_low(pin_C6);
output_low(pin_C5);
}
}
} |
PORTB wiring:
RB0: button output
RB1: button output
RB2: button output
RB3: button output
RB4: button output
RB5: floating
RB6: PGC to ISCP
RB7: PGD to ISCP
Thanks for your time! |
|
|
Ttelmah Guest
|
|
Posted: Thu Jun 09, 2005 3:16 pm |
|
|
What you describe, should not be happening with the code as shown. You should try to narrow the fault down, and change the test after the buttons are read, to change the output pin if '64' is seen, to see if the fault is actually occurring in the read, or the bit is somehow being set latter in the code. Also try seperating the read, and the mask. So:
buttons=input_b();
buttons &= 0b00011111;
I have seen some problems in the past with some of the internal functions being macros, and not true functions, and not behaving quite as they should when used in logic statements...
There is one glaring fault with the code as shown, which does not affect this, but should be fixed for it to work. You need to allow the ADC capacitor time to charge when a new channel is selected. As it stands, the second reading will be returning the voltage that was present from the first selection, with a little drift towards the newly selected value. Read the section on the chip's data sheet about the time needed for this...
Seperately, for 'elegance', consider using a union to access the bytes in the adc values.
So:
Code: |
union access {
int8 b[2];
int16 w;
}
union access ADCResult0,ADCResult1,ADCResult2;
//Static variables, are _allways_ cleared by the compiler.
//Then to read the ADC value:
set_adc_channel(0);
delay_us(12);
ADCResult0.w=read_adc();
|
You can then access the low and high bytes as 'ADCResult0.b[0]', and 'ADCResult.b[1]', taking just one machine cycle to do this.
The latter compilers will generally optimise the code to almost the same result, but this is more certain.
You will also face problems if SSP interrupts occur during your serial I/O. Consider 'encapsulating' the I/O routine.
So:
Code: |
void putcsoft(int8 val) {
disable_interrupts(global);
fputc(swrs232,val);
enable_interrupts(global);
}
//Then print using:
fprintf(putcsoft, "X=%04lu\tY=%04lu\tZ=%04lu\tButtons:%03u\r", ADCResult0, ADCResult1, ADCResult2, buttons);
|
This way, the interrupt is disabled/enabled on a 'per character' basis, and if an SSP interrupt does occur, it'll be responded to as soon as a character is finished, but will not interfere with the serial communication...
Best Wishes |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jun 09, 2005 3:24 pm |
|
|
There are a few strange things about your code.
1. You've enabled SSP interrupts and global interrupts, but there
is no #int_ssp service routine. What happens if you get an
interrupt ? The old jumperino off into space somewhere.
2. You have selected ADC_CLOCK_DIV_8, but the data sheet
says that for a 20 MHz crystal, you must use Div by 16, or greater.
3. Do you have a pull-down resistor on pin RB5 ? If not, try putting
one on there. If for some reason the NOLVP fuse was not getting
programmed, then a floating PGM pin (RB5) could cause a lock-up.
If you put a pull-down on that pin, it will eliminate this as a possible
cause of your problem. (in terms of trouble-shooting the problem) |
|
|
UFAnders
Joined: 13 Apr 2005 Posts: 36 Location: Michigan
|
input_b()&MASK is adding 64 to real value! |
Posted: Thu Jun 09, 2005 3:44 pm |
|
|
Wow, this is some really great stuff! Regarding my low ADC clock divisor, I guess I forgot to recalculate the charge time - I had originally been working with a 4MHz crystal before switching to 20MHz. About the missing #int_SSP handler, I omitted it because it never used or modified my 'buttons' variable.
I will try the pulldown resistor, and I'm a big fan of programming elegance so I'll rewrite my serial debugging statements plus experiment with the union construct.
I'm really digging this forum |
|
|
UFAnders
Joined: 13 Apr 2005 Posts: 36 Location: Michigan
|
input_b()&MASK is adding 64 to real value! |
Posted: Fri Jun 10, 2005 11:09 pm |
|
|
Hey guys, that suggestion where I split up my input_b() and masking statements worked! Now I'm only getting response with button presses.
-=Yessssssssssssssssssssss=-
I changed my ADC clock divisor and used the union construct, both of which make my life much easier, thanks to those who contributed! Everything you guys have suggested thus far I have implemented (including the interrupt-less serial functions), and they work swell.
I ran into some trivial syntactical errors in case anyone visiting this page cares...The syntax for encapsulating the serial debugging statements should read:
Code: | printf[(putcsoft, "X=%04lu\tY=%04lu\tZ=%04lu\tButtons:%03u\r", ADCResult0.word, ADCResult1.word, ADCResult2.word, buttons); |
And:
Code: | void putcsoft(int8 c)
{
disable_interrupts(global);
fputc(c, swrs232);
enable_interrupts(global);
} |
By the way, I used the following union:
Code: | union ADC
{
int8 byteField[2];
int16 word;
} ADCResult0, ADCResult1, ADCResult2; |
Thanks for all the pointers guys, nothing but good can come from this... |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|