CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Individual port bits
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Charles Linquist



Joined: 07 May 2005
Posts: 28
Location: Campbell, CA

View user's profile Send private message

Individual port bits
PostPosted: Thu May 26, 2005 12:34 pm     Reply with quote

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







PostPosted: Thu May 26, 2005 12:52 pm     Reply with quote

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
PostPosted: Thu May 26, 2005 12:53 pm     Reply with quote

all the (port_b ...) in parenthesis should be "my_port_b"
DragonPIC



Joined: 11 Nov 2003
Posts: 118

View user's profile Send private message

PostPosted: Thu May 26, 2005 12:56 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri May 27, 2005 9:01 am     Reply with quote

Thanks! Your answers and code were very helpful.
seven



Joined: 26 May 2005
Posts: 10

View user's profile Send private message

PostPosted: Thu Jun 02, 2005 5:51 am     Reply with quote

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







PostPosted: Thu Jun 02, 2005 6:08 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Jun 02, 2005 9:02 am     Reply with quote

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

View user's profile Send private message Send e-mail Visit poster's website AIM Address

input_b()&MASK is adding 64 to real value!
PostPosted: Thu Jun 09, 2005 2:33 pm     Reply with quote

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! Rolling Eyes 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

View user's profile Send private message

PostPosted: Thu Jun 09, 2005 2:42 pm     Reply with quote

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

View user's profile Send private message Send e-mail Visit poster's website AIM Address

input_b()&MASK is adding 64 to real value!
PostPosted: Thu Jun 09, 2005 2:50 pm     Reply with quote

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







PostPosted: Thu Jun 09, 2005 3:16 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Jun 09, 2005 3:24 pm     Reply with quote

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

View user's profile Send private message Send e-mail Visit poster's website AIM Address

input_b()&MASK is adding 64 to real value!
PostPosted: Thu Jun 09, 2005 3:44 pm     Reply with quote

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. Embarassed 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 Mr. Green
UFAnders



Joined: 13 Apr 2005
Posts: 36
Location: Michigan

View user's profile Send private message Send e-mail Visit poster's website AIM Address

input_b()&MASK is adding 64 to real value!
PostPosted: Fri Jun 10, 2005 11:09 pm     Reply with quote

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...
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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