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

Naming IO Pins

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
bob_4610



Joined: 30 Nov 2003
Posts: 3
Location: Beervelde (Belgium)

View user's profile Send private message

Naming IO Pins
PostPosted: Wed Feb 04, 2004 6:36 am     Reply with quote

I have an application that uses several IO pins to drive various leds. The pins are scattered over ports A, B & C (PIC16F73) because I use special functions like I2C, ext. IRQ etc... so some pins are not available.

To ease addressing I tried to use following approach :

Define pin addresses as an array

const int leddrv[6] = {pin_a1, pin_a2, pin_b2, pin_b4, pin_c0, pin_c2};

with the idea of using :

output_high(leddrv[var]) or output_low(leddrv[var])
However, this only works if var is a constant.

But if I want to use a variable e.g. :

for(i=0;i<=6;++i) output_low(leddrv[i]);

I get a compiler error "Expression must evaluate to a constant"

Does anyone know if there is another way to do this?
Regards,
Bob
rwyoung



Joined: 12 Nov 2003
Posts: 563
Location: Lawrence, KS USA

View user's profile Send private message Send e-mail

PostPosted: Wed Feb 04, 2004 9:29 am     Reply with quote

This may not be the cleanest implementation but I believe it will work. It does compile (V3.184). Based on the suggestion found in the FAQ titled:

"How can I pass a variable to functions like OUTPUT_HIGH()?"


Code:
#include <16F877A.H>
#fuses HS, NOLVP, NOWDT, PUT
#use delay (clock=20000000,RESTART_WDT)
#use rs232(baud=19200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=OUT232)

void changeme(int8 pin_to_use, int1 h_l);

// change the names as necesssary and their pin assignments
enum mypins {led1=PIN_A1, led2=PIN_A2, led3=PIN_A3, led4=PIN_A4, led5=PIN_A5};
// this is your array for when you want to hit everybody in sequence
int8 const mypins_a[] = {led1, led2, led3, led4, led5};
 
void main(void)
{
   int8 i;
   int1 x;
   x = 1;
   while(TRUE) {
      for(i=0;i<5;i++) // use the sizeof() operator instread of hard-coding a 5...
         changeme(mypins_a[i],x); // write your own function for changing pin states
      x ^= 1;
      delay_ms(1000);
   }
}

// encapsulate the pin change function
// use the switch/case statements to translate from a variable
// back to a constant so the output_bit() function is happy
void changeme(int8 pin_to_use, int1 h_l)
{

   switch(pin_to_use) {
      case led1 :
         if (h_l) output_high(led1);
         else     output_low(led1);
         break;
      case led2 :
         if (h_l) output_high(led2);
         else     output_low(led2);
         break;
      case led3 :
         if (h_l) output_high(led3);
         else     output_low(led3);
         break;
      case led4 :
         if (h_l) output_high(led4);
         else     output_low(led4);
         break;
      case led5 :
         if (h_l) output_high(led5);
         else     output_low(led5);
         break;
    }
}

_________________
Rob Young
The Screw-Up Fairy may just visit you but he has crashed on my couch for the last month!
bob_4610



Joined: 30 Nov 2003
Posts: 3
Location: Beervelde (Belgium)

View user's profile Send private message

PostPosted: Wed Feb 04, 2004 2:32 pm     Reply with quote

hi Rob

Thanks for your reply. This is very similar to the way I did it right now. However since there are 13 leds in total, the switch/case statement is quite extensive. Also, each led has 3 states (on, off, blink). The blinking is achieved by setting a bit in an int16 (led_blink_state). When a bit is set, the corresponding led is toggled at a preset blinking frequency.

That blinking function is again quite long since I can't pass a variable to output_high(pin#) and output_low(pin#). So I have to write the blinking code 13 times.

That's why I was looking for a way to pass variables to these output functions, but I'm afraid I'll have to stick to the current solution.

Anyway, thanks for your suggestion.

Regards,
Bob
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Wed Feb 04, 2004 3:29 pm     Reply with quote

This is how I do it. You can use a similar approach and overlay the union on the ports. Mine are actually on 6 pins of one port and then multiplexed. If you look at the LCD thread that was just recently brought up, you will see this technique used in the lcd driver file that CCS supplies.

Code:

typedef union
{
  struct
  {
    UINT8:1;
    UINT8:1;
    UINT8 Thursday : 1;
    UINT8 Wednesday : 1;
    UINT8 Tuesday : 1;
    UINT8 Monday : 1;
    UINT8 Program : 1;
    UINT8 Run : 1;

    UINT8:1;
    UINT8:1;
    UINT8 Input1 : 1;
    UINT8 Input2 : 1;
    UINT8 Input3 : 1;
    UINT8 Input4 : 1;
    UINT8 Input5 : 1;
    UINT8 Input6 : 1;

    UINT8:1;
    UINT8:1;
    UINT8:1;
    UINT8 Input7 : 1;
    UINT8:1;
    UINT8:1;
    UINT8 Input8 : 1;
    UINT8 Photocell : 1;

    UINT8:1;
    UINT8:1;
    UINT8:1;
    UINT8:1;
    UINT8:1;
    UINT8:1;
    UINT8 Remote : 1;
    UINT8 Relay8 : 1;

    UINT8:1;
    UINT8:1;
    UINT8:1;
    UINT8 Relay7 : 1;
    UINT8 Relay6 : 1;
    UINT8 Relay5 : 1;
    UINT8 Relay4 : 1;
    UINT8 Relay3 : 1;

    UINT8:1;
    UINT8:1;
    UINT8 Relay2 : 1;
    UINT8 Relay1 : 1;
    UINT8 Holiday : 1;
    UINT8 Sunday : 1;
    UINT8 Saturday : 1;
    UINT8 Friday : 1;
  };
  struct
  {
    UINT8 row1;
    UINT8 row2;
    UINT8 row3;
    UINT8 row4;
    UINT8 row5;
    UINT8 row6;
  };
} LED_REGS;


extern volatile LED_REGS  LEDS;
extern volatile LED_REGS  Blink;

/* *************************************************************************
  LED driver routines £

  DESCRIPTION:  This function sets the keypad relay LEDs

  RETURN: none

  ALGORITHM:  none

  NOTES:  none
 *************************************************************************** */
void Hardware_Set_Relay_LEDS(
  UINT8 byte) /* FIX ME: add comment */
{
  if (byte & 0x01)
    LEDS.Relay1 = 1;
  else
    LEDS.Relay1 = 0;
  if (byte & 0x02)
    LEDS.Relay2 = 1;
  else
    LEDS.Relay2 = 0;
  if (byte & 0x04)
    LEDS.Relay3 = 1;
  else
    LEDS.Relay3 = 0;
  if (byte & 0x08)
    LEDS.Relay4 = 1;
  else
    LEDS.Relay4 = 0;
  if (byte & 0x10)
    LEDS.Relay5 = 1;
  else
    LEDS.Relay5 = 0;
  if (byte & 0x20)
    LEDS.Relay6 = 1;
  else
    LEDS.Relay6 = 0;
  if (byte & 0x40)
    LEDS.Relay7 = 1;
  else
    LEDS.Relay7 = 0;
  if (byte & 0x80)
    LEDS.Relay8 = 1;
  else
    LEDS.Relay8 = 0;
}

/* *************************************************************************
  DESCRIPTION:  This function sets the keypad relay LEDs blink enable

  RETURN: none

  ALGORITHM:  none

  NOTES:  none
 *************************************************************************** */
void Hardware_Set_Relay_Blink(
  UINT8 byte) /* FIX ME: add comment */
{
  if (byte & 0x01)
    Blink.Relay1 = 1;
  else
    Blink.Relay1 = 0;
  if (byte & 0x02)
    Blink.Relay2 = 1;
  else
    Blink.Relay2 = 0;
  if (byte & 0x04)
    Blink.Relay3 = 1;
  else
    Blink.Relay3 = 0;
  if (byte & 0x08)
    Blink.Relay4 = 1;
  else
    Blink.Relay4 = 0;
  if (byte & 0x10)
    Blink.Relay5 = 1;
  else
    Blink.Relay5 = 0;
  if (byte & 0x20)
    Blink.Relay6 = 1;
  else
    Blink.Relay6 = 0;
  if (byte & 0x40)
    Blink.Relay7 = 1;
  else
    Blink.Relay7 = 0;
  if (byte & 0x80)
    Blink.Relay8 = 1;
  else
    Blink.Relay8 = 0;
}

/* *************************************************************************
  DESCRIPTION:  This function sets the keypad Input LEDs

  RETURN: none

  ALGORITHM:  none

  NOTES:  none
 *************************************************************************** */
void Hardware_Set_Input_LEDS(
  UINT8 byte) /* FIX ME: add comment */
{
  if (byte & 0x01)
    LEDS.Input1 = 1;
  else
    LEDS.Input1 = 0;

  if (byte & 0x02)
    LEDS.Input2 = 1;
  else
    LEDS.Input2 = 0;

  if (byte & 0x04)
    LEDS.Input3 = 1;
  else
    LEDS.Input3 = 0;

  if (byte & 0x08)
    LEDS.Input4 = 1;
  else
    LEDS.Input4 = 0;

  if (byte & 0x10)
    LEDS.Input5 = 1;
  else
    LEDS.Input5 = 0;

  if (byte & 0x20)
    LEDS.Input6 = 1;
  else
    LEDS.Input6 = 0;

  if (byte & 0x40)
    LEDS.Input7 = 1;
  else
    LEDS.Input7 = 0;

  if (byte & 0x80)
    LEDS.Input8 = 1;
  else
    LEDS.Input8 = 0;
  if (byte & 0xFF00)
    LEDS.Photocell = 1;
  else
    LEDS.Photocell = 0;
}


Another approach would be to create your own output_high function and pass the same pin numbers. You can extract the port and bit from that number quite easily.
Code:

void my_output_high(int num)
{
  int* port;
  int pin;

  port = num/8;  // We are dividing by 8
  pin = num & 0x07;  // We are getting the remainder

  bit_set(*port,pin);
}
void my_output_low(int num)
{
  int* port;
  int pin;

  port = num>>3;
  pin = num & 0x07;

  bit_clear(*port,pin);
}
bob_4610



Joined: 30 Nov 2003
Posts: 3
Location: Beervelde (Belgium)

View user's profile Send private message

PostPosted: Wed Feb 04, 2004 5:16 pm     Reply with quote

Thanks for the suggestion, but it has the same disadvantage as what I'm using now, i.e. you need as many "switch/case" or "if's" as there are I/O pins involved since you must use constants.

What I had in mind was something like this, but I guess to achieve this I will have to write my own I/O driver as you suggested.

Code:
// Sample code
/* Leds to I/O pins mapping */

const int   leddrv[6] = {PIN_A0, PIN_A1, PIN_A3, PIN_B2, PIN_B4, PIN_C1};
typedef  enum  {led1 = 0, led2, led3, led4, led5, led6} ledname;

/* Led states */

typedef  enum  {BLINK, ON, OFF}ledmode;

int   led_blink_state;


...

void set_led(ledname led_id, ledmode led_state)
{
   switch(led_state)
   {
      case  ON    :  output_low(leddrv[led_id]);bit_clear(led_blink_state, led_id);break;
      case  OFF   :  output_high(leddrv[led_id]);bit_clear(led_blink_state, led_id);break;
      case  BLINK :  output_low(leddrv[led_id]);bit_set(led_blink_state, led_id);break;
   }
}

// MAIN PROGRAM

void  main()
{
...

set_led(led3, ON);
...

set_led(led1, BLINK);

...
}


Bob
rwyoung



Joined: 12 Nov 2003
Posts: 563
Location: Lawrence, KS USA

View user's profile Send private message Send e-mail

PostPosted: Wed Feb 04, 2004 6:17 pm     Reply with quote

Note about enums and switch/case:

It is somewhere on the old forum but I had a discussion with RJ Hamlett about how CCS was generating the switch/case statements. We kept disagreeing about how it was generated and it turned out that there was something about the use of enums as the case arguments versus the use of a hard coded integer or #define. I think the code was tighter when #define'd values were used as the case arguments.

Just for the heck of it you might try a quick test of your switch/case statements where you try enum'd values, #defines, and hard coded constants. Also the presense of a "default" case makes the code larger if I remember correctly.

Look at the LST file and see how the switch/case code is generated under different condtions.
_________________
Rob Young
The Screw-Up Fairy may just visit you but he has crashed on my couch for the last month!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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