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

Square Wave Data Logging
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
iso9001



Joined: 02 Dec 2003
Posts: 262

View user's profile Send private message

Square Wave Data Logging
PostPosted: Fri Aug 20, 2004 11:55 am     Reply with quote

Hello,

I have a 6-8V square wave I'de like to monitor and log. Its a variable width wave with 100us and 50us high and lows for 1's and 0's, as well as a few special charactors like a 'start of transmission' high that lasts for 200us and an 'end of transmission' high that lasts for 200-300us.

My goal is to monitor the line and when I see a start bit, I record it using a byte on the internal flash memory, then I keep monitoring till I see 8 bits and record that byte, etc etc untill I see the stop bit and then record that...

I'm using a 16F876A so, I have 256bytes of internal memory and enough ram to hold off on writing to the internal memory untill I have a pause in the transmission (long pauses are common after a max of 80 bits)

What I'm curious about is the coding.... I know I want to be sampling at least double the rate... but at 20Mhz, that should be simple. I've never used interupts but I'm guessing that I'll have to wait till I see a change in the edge (raising or falling) and start a timer, then stop the timer at change in edge again, restarting the timer

I think I read that even though I'm using a 5V supply that one pin on RA4 can handel upto 8.5V. I made a diagram with a voltage divider before I found that out, so look at the bottomer picture

Can anyone help me with the algorithm and some exmaple of timer code to measure lengths and interupts to monitor change in edge ???




Mark



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

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

PostPosted: Fri Aug 20, 2004 12:57 pm     Reply with quote

You should take a look at the capture port on the PIC. Read the section in the data sheet and take a look at CCS's examples. You can probably search the board and find a bunch of examples.
Ttelmah
Guest







PostPosted: Fri Aug 20, 2004 3:22 pm     Reply with quote

RA4, can go up to 8.5v _when used as an output_. However raising it above the supply rail, when used as an input, is not officially supported (if you look at the 'input high' specification, the maximum, is given as Vdd). Add a resistor/zener to clip the voltage at the supply rail, or you risk latching up the cmos input.

Best Wishes
iso9001



Joined: 02 Dec 2003
Posts: 262

View user's profile Send private message

PostPosted: Fri Aug 20, 2004 3:45 pm     Reply with quote

Yea, I was uncertain about that RA4 thing.... Curiously though... HOW does it get up to 8.5V ??? If I supply now more then 5.5, then maybe it has a little charge pump inside ???
Mark



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

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

PostPosted: Fri Aug 20, 2004 3:59 pm     Reply with quote

It won't supply any voltage. Look at the datasheet. Its open collector. Get one of our hardware guys every time!
iso9001



Joined: 02 Dec 2003
Posts: 262

View user's profile Send private message

PostPosted: Fri Aug 20, 2004 4:04 pm     Reply with quote

I'm looking at the datasheet and searches to see what the capture function does...


Oh, I forgot to mention, I'm actually kinda dumb, so.... Whats an Open-Collector ?

I'm guessing that say I had an 8V led hooked to that pin it would pull all 8V instead of the 5.0 I suplly for VDD ?
Mark



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

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

PostPosted: Fri Aug 20, 2004 5:00 pm     Reply with quote

Open collector means that it can not source, only sink. You would have to tie one side of whatever you are connecting to a voltage source and the other to the pic.
iso9001



Joined: 02 Dec 2003
Posts: 262

View user's profile Send private message

PostPosted: Fri Aug 20, 2004 6:00 pm     Reply with quote

Mark:
Oh.... So.... I output RA4 low and I can sink 8.5V into it ? I cant read that 8.5V with the ADC can I ? I mean since the ADC still uses Vdd as Vref ?
(Thanks btw)


I saw the ccpmp.c example and realized that thier code is only counting high pulses, where as I need to count the length of highs and lows. Using some of the ccs code I came up with this:


Code:

long rise,fall,pulse_width;
int active=FALSE;                //this varaible prevents the first
                                 //rise from being counted
int storage[100];                //some array to store my info

#int_ccp1
void isr()
{
   if (active) {
   rise = CCP_1;
   fall = CCP_2;
   low_width = rise - fall;
   i++
   storage[i]=low_width * -1)
   }

#int_ccp2
void isr()
{
   rise = CCP_1;
   fall = CCP_2;
   high_width = fall - rise;     
   active=TRUE;
   i++
   storage[i]=high_width;
}                                 


void main()
{

   setup_ccp1(CCP_CAPTURE_RE);   
   setup_ccp2(CCP_CAPTURE_FE);   
   setup_timer_1(T1_INTERNAL);
                                                // I want the timer
                                                //to be FAST so I'm
                                                //not sure of the value
                                                //that goes here.


   enable_interrupts(INT_CCP1);
   enable_interrupts(INT_CCP2);
   enable_interrupts(GLOBAL);


However, I don't know what to do about timer overflows... I think I can get by with a sampling speed of between 5us and 20us... anything thats going to overflow the timer is going to be a long silence in the line (which I dont care about). If I could figure out how to watch for overflows and just assign a max time to them, that would also be a good time to move my array data over to my internal rom.

Ideas on what I have so far ??
iso9001



Joined: 02 Dec 2003
Posts: 262

View user's profile Send private message

PostPosted: Fri Aug 20, 2004 6:31 pm     Reply with quote

Hmmm.... I spoke out what I want to do in enligsh and think maybe I'm making this harder then it has to be....

I still not sure if the code i wrote is right or not, but... This is the alorithm I think I should be looking into,

1. Take time from Rise to Fall... This is High Time
2. At the interupt, Fall will be Low Time
4. Rinse, Repeat

Arg, I'm confusing myself now,

I think that algorithm is close to what I have coded above... but I only need 1 isr I think....

Code:

long rise,fall,pulse_width;
int active=FALSE;                //this varaible prevents the first
                                 //rise from being counted
int storage[100];                //some array to store my info

#int_ccp1                     //Count on rises
void isr()
{
   rise = CCP_1;
   fall = CCP_2;
   high_width = rise - fall;     
   low_width = fall;            //Would I now need to reset times?

   i++;
   storage[i]=high_width;
   i++;
   storage[i]=low_width * -1;
}                                 


void main()
{
   setup_ccp1(CCP_CAPTURE_RE);   
   setup_ccp2(CCP_CAPTURE_FE);   
   setup_timer_1(T1_INTERNAL);
                                             // I want the timer
                                             //to be FAST so I'm
                                             //not sure of the value
                                             //that goes here.


   enable_interrupts(INT_CCP1);
   enable_interrupts(GLOBAL);
iso9001



Joined: 02 Dec 2003
Posts: 262

View user's profile Send private message

PostPosted: Fri Aug 20, 2004 7:53 pm     Reply with quote

I just read nearly all the 127 search results for "capture"...

I cant find anyone thats counting the high AND the low.... Thats all I really need, is to measure the high and the low pulses...

Sad
Guest
Guest







Square wave hi and lo
PostPosted: Fri Aug 20, 2004 8:27 pm     Reply with quote

MEMSIC sells accelerometers with duty cycle output, and they USED to have an app. note on their site that had PIC "C" code for measuring the duty cycle - length of both high and low durations. The app. note is no longer there oddly enough, but maybe it is google-able.

HTH,
Bill
iso9001



Joined: 02 Dec 2003
Posts: 262

View user's profile Send private message

PostPosted: Fri Aug 20, 2004 8:30 pm     Reply with quote

OK! How about this one ?



Code:

long old_rise=0, fall=0, new_rise=0;


#int_ccp1                     //Count on rises
void isr()
{

   if (old_rise == new_rise)
    old_rise=CCP_1;
  else {
   old_rise = new_rise;
   new_rise = CCP1;
  }
   fall = CCP_2;


   high_width = fall - old_rise;                                 
   low_width = (new_rise-old_rise) - high_width;


   i++;
   storage[i]=high_width;
   i++;
   storage[i]=low_width * -1;

//The -1 is so when I sort through the data I can see what was a low and what was a high... even though I know they will always alternate.


I think this is a good start... This allows for 1 int, counting of high and low pulses... But maybe too much logic for my int ? The smaller the footprint I have the faster my sampling is going to be no ?

Well ?? How am I doing ?
Mark



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

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

PostPosted: Fri Aug 20, 2004 9:50 pm     Reply with quote

If you want to measure the time between edges, just change the ccp setup inside the isr. The next time the int occurs, read the ccpr register to determine the time. Based on the edge (rising or falling) you will know whether this is the time low or the time high. Here is some IR receive stuff I did a while back. It uses the C18 compiler but if you study it, you will see how I handled it.
Code:

/****************************************************************************
* NAME:        IR_Receive
* DESCRIPTION: CCP2 is used to measure the IR pulse widths.
* PARAMETERS:  none
* RETURN:      none
* ALGORITHM:   none
* NOTES:       none
*****************************************************************************/
void IR_Receive(void)
{
  #define START_BIT_TIME       0x2710         // 2000 us
  #define HIGH_BIT_TIME        0x0BB8         // 600uS
  static unsigned char i = 0;
  static unsigned char data;
  static unsigned char checksum = 0;
  static unsigned char ir_data[11];                   // IR receive buffer
  unsigned int fade = 0;

  if (!CCP2CONbits.CCP2M0)
  {
    OpenCapture2(CAPTURE_INT_ON & C2_EVERY_RISE_EDGE);
    CLEAR_IR_INT_FLAG();
    // Reset our timer
    OpenTimer1(TIMER_INT_OFF & T1_SOURCE_INT & T1_PS_1_1 & T1_SYNC_EXT_ON & T1_OSC1EN_OFF);
    WriteTimer1(0);

    // Set a receive timeout
    IR_Rx_Timeout = IR_RX_TIMEOUT_VALUE;

    if (IR_State == IDLE)
    {
      checksum = 0;
      i = 0;
      IR_State = WAIT_FOR_START_BIT;
      // Clear IR Buffer
      ir_data[0] = 0;
      ir_data[1] = 0;
      ir_data[2] = 0;
      ir_data[3] = 0;
      ir_data[4] = 0;
      ir_data[5] = 0;
      ir_data[6] = 0;
      ir_data[7] = 0;
      ir_data[8] = 0;
      ir_data[9] = 0;
    }

  }
  else
  {
    OpenCapture2(CAPTURE_INT_ON & C2_EVERY_FALL_EDGE);
    CLEAR_IR_INT_FLAG();
 

    // Process the IR data
    switch (IR_State)
    {
      case IDLE:
        // Why are we idle - we shouldn't be unless something reset
        // our state machine.
        break;
      case WAIT_FOR_START_BIT:
        if (CCPR2 > START_BIT_TIME)
        {
          // Beginning of the data - clear our data byte
          data = 0;
          IR_State = WAIT_FOR_BIT_7;
        }
        else
          IR_State = IDLE;
        break;
      case WAIT_FOR_BIT_7:
        if (CCPR2 > HIGH_BIT_TIME)
          bit_set(data,7);
        IR_State = WAIT_FOR_BIT_6;
        break;
      case WAIT_FOR_BIT_6:
        if (CCPR2 > HIGH_BIT_TIME)
          bit_set(data,6);
        IR_State = WAIT_FOR_BIT_5;
        break;
      case WAIT_FOR_BIT_5:
        if (CCPR2 > HIGH_BIT_TIME)
          bit_set(data,5);
        IR_State = WAIT_FOR_BIT_4;
        break;
      case WAIT_FOR_BIT_4:
        if (CCPR2 > HIGH_BIT_TIME)
          bit_set(data,4);
        IR_State = WAIT_FOR_BIT_3;
        break;
      case WAIT_FOR_BIT_3:
        if (CCPR2 > HIGH_BIT_TIME)
          bit_set(data,3);
        IR_State = WAIT_FOR_BIT_2;
        break;
      case WAIT_FOR_BIT_2:
        if (CCPR2 > HIGH_BIT_TIME)
          bit_set(data,2);
        IR_State = WAIT_FOR_BIT_1;
        break;
      case WAIT_FOR_BIT_1:
        if (CCPR2 > HIGH_BIT_TIME)
          bit_set(data,1);
        IR_State = WAIT_FOR_BIT_0;
        break;
      case WAIT_FOR_BIT_0:
        if (CCPR2 > HIGH_BIT_TIME)
          bit_set(data,0);
        IR_State = WAIT_FOR_START_BIT;
 
    //------------------------------------------------------------------------
    //               data now contains a byte of data
    //------------------------------------------------------------------------

        // see if this is the end of the message.
        if (data == 0xFF)
        {
          // Setup for the next message
          IR_State = IDLE;
          IR_Rx_Timeout = 0;

          --i;
          // Subtract the message checksum from our accumulated checksum
          checksum -= ir_data[i];

          // clear the MSB.  0xFF is used as the terminator so we don't want to
          // confuse a possible checksum with the terminator
          bit_clear(checksum, 7);
          if (checksum == ir_data[i])
          {
            // Clear any previous button presses
            IR_Buttons[0] = 0;
            IR_Buttons[1] = 0;
            IR_Buttons[2] = 0;
            IR_Buttons[3] = 0;
            IR_Buttons[4] = 0;
            IR_Buttons[5] = 0;
            IR_Buttons[6] = 0;
            IR_Buttons[7] = 0;
            IR_Buttons[8] = 0;
            TURN_ON_NET_LED();
            Net_LED_Timeout = NET_LED_TIMEOUT_VALUE;

            // Process msg
            switch (ir_data[0])
            {
              // Preset activate
              case 0x05:
                Select_Preset(ir_data[2]);
                IR_Timeout = IR_TIMEOUT_VALUE;
                break;
              // ON Command
              case 0x06:
                IR_Buttons[0] = 0x10;
                IR_Timeout = IR_TIMEOUT_VALUE;
                break;
              // OFF Command
              case 0x07:
                IR_Buttons[0] = 0x01;
                IR_Timeout = IR_TIMEOUT_VALUE;
                break;
              // Save Preset
              case 0x08:
                Save_Preset = SAVE_PRESET_START;
                IR_Scene = ir_data[2];
                // Disable the IR remote until the Preset has been saved.
                DISABLE_IR_CONTROL();
                break;
              // Set Fade
              case 0x09:
                // Indicate that the fade time needs to be sent
                CommFlags.Send_Fade = TRUE;
               
                fade = (ir_data[5] << 4) | (ir_data[6] & 0x0F);
                fade <<= 8;
                fade |= (ir_data[7] << 4) | (ir_data[8] & 0x0F);
               
                // Convert the fade time to our segmented (bargraph display).
                // Levels[2] is the fade display
                Levels[2] = Convert_Fade(fade);

                break;
              // Channel Raise
              case 0x0C:
                IR_Buttons[5] = ir_data[1];
                IR_Buttons[6] = ir_data[2];
                IR_Buttons[7] = ir_data[3];
                IR_Timeout = IR_TIMEOUT_VALUE;
                break;
              // Channel Lower
              case 0x0E:
                IR_Buttons[5] = ir_data[1] << 4;
                IR_Buttons[6] = ir_data[2] << 4;
                IR_Buttons[7] = ir_data[3] << 4;
                IR_Timeout = IR_TIMEOUT_VALUE;
                break;
              default:
                break;
            }
          }
          // Error in message
          else
          {
          }
        }
        // Continue receiving the IR data
        else
        {
          checksum = checksum + data;
          if (i < sizeof(ir_data))
          {
            ir_data[i] = data;
            i++;
          }
          else
            IR_State = IDLE;
        }
        break;
      default:
        break;
    }
  }
}




Okay, I found a CCS version of it too
Code:

#INT_CCP2
void IR_Receive(void)
{
  /* 2000 us */
  #define START_BIT_TIME       0x2710
  /* 600uS */
  #define HIGH_BIT_TIME        0x0BB8

  static UINT8 i = 0;
  UINT8 data;
  static UINT8 checksum = 0;
  /* IR receive buffer */
  static UINT8 ir_data[11];
  UINT16 fade = 0;

  /* make sure interrupts were disabled. */

  if (Capture_State == CCP_CAPTURE_FE)
  {
    setup_ccp2(CCP_CAPTURE_RE);
    Capture_State = CCP_CAPTURE_RE;
    /* Reset our timer */
    setup_timer_1(T1_DISABLED);
    set_timer1(0);
    setup_timer_1(T1_DIV_BY_1 || T1_INTERNAL);

    /* Set a receive timeout */
    IR_Rx_Timeout = IR_RX_TIMEOUT_VALUE;

    if (IR_State == IDLE)
    {
      checksum = 0;
      i = 0;
      IR_State = WAIT_FOR_START_BIT;
      /* Clear IR Buffer */
      ir_data[0] = 0;
      ir_data[1] = 0;
      ir_data[2] = 0;
      ir_data[3] = 0;
      ir_data[4] = 0;
      ir_data[5] = 0;
      ir_data[6] = 0;
      ir_data[7] = 0;
      ir_data[8] = 0;
      ir_data[9] = 0;
    }

  }
  else
  {
    setup_ccp2(CCP_CAPTURE_FE);
    Capture_State = CCP_CAPTURE_FE;

    /* Process the IR data */
    switch (IR_State)
    {
      case IDLE:
        /* Why are we idle - we shouldn't be unless something reset
           our state machine. */
        break;
      case WAIT_FOR_START_BIT:
        if (CCP_2 > START_BIT_TIME)
        {
          /* Beginning of the data - clear our data byte */
          data = 0;
          IR_State = WAIT_FOR_BIT_7;
        }
        else
          IR_State = IDLE;
        break;
      case WAIT_FOR_BIT_7:
        if (CCP_2 > HIGH_BIT_TIME)
          bit_set(data,7);
        IR_State = WAIT_FOR_BIT_6;
        break;
      case WAIT_FOR_BIT_6:
        if (CCP_2 > HIGH_BIT_TIME)
          bit_set(data,6);
        IR_State = WAIT_FOR_BIT_5;
        break;
      case WAIT_FOR_BIT_5:
        if (CCP_2 > HIGH_BIT_TIME)
          bit_set(data,5);
        IR_State = WAIT_FOR_BIT_4;
        break;
      case WAIT_FOR_BIT_4:
        if (CCP_2 > HIGH_BIT_TIME)
          bit_set(data,4);
        IR_State = WAIT_FOR_BIT_3;
        break;
      case WAIT_FOR_BIT_3:
        if (CCP_2 > HIGH_BIT_TIME)
          bit_set(data,3);
        IR_State = WAIT_FOR_BIT_2;
        break;
      case WAIT_FOR_BIT_2:
        if (CCP_2 > HIGH_BIT_TIME)
          bit_set(data,2);
        IR_State = WAIT_FOR_BIT_1;
        break;
      case WAIT_FOR_BIT_1:
        if (CCP_2 > HIGH_BIT_TIME)
          bit_set(data,1);
        IR_State = WAIT_FOR_BIT_0;
        break;
      case WAIT_FOR_BIT_0:
        if (CCP_2 > HIGH_BIT_TIME)
          bit_set(data,0);
        IR_State = WAIT_FOR_START_BIT;
 
    /*************** data now contains a byte of data **************************/

        /* see if this is the end of the message. */
        if (data == 0xFF)
        {
          /* Setup for the next message */
          IR_State = IDLE;
          IR_Rx_Timeout = 0;

          --i;
          /* Subtract the message checksum from our accumulated checksum */
          checksum -= ir_data[i];

          /* clear the MSB.  0xFF is used as the terminator so we don't want to
             confuse a possible checksum with the terminator */
          bit_clear(checksum, MSB);
          if (checksum == ir_data[i])
          {
            /* Clear any previous button presses */
            IR_Buttons[0] = 0;
            IR_Buttons[1] = 0;
            IR_Buttons[2] = 0;
            IR_Buttons[3] = 0;
            IR_Buttons[4] = 0;
            IR_Buttons[5] = 0;
            IR_Buttons[6] = 0;
            IR_Buttons[7] = 0;
            IR_Buttons[8] = 0;
            TURN_ON_NET_LED();
            Net_LED_Timeout = NET_LED_TIMEOUT_VALUE;

            /* Process msg */
            switch (ir_data[0])
            {
              /* Preset activate */
              case 0x05:
                Select_Preset(ir_data[2]);
                IR_Timeout = IR_TIMEOUT_VALUE;
                break;
              /* ON Command */
              case 0x06:
                IR_Buttons[0] = 0x10;
                IR_Timeout = IR_TIMEOUT_VALUE;
                break;
              /* OFF Command */
              case 0x07:
                IR_Buttons[0] = 0x01;
                IR_Timeout = IR_TIMEOUT_VALUE;
                break;
              /* Save Preset */
              case 0x08:
                Save_Preset = SAVE_PRESET_START;
                IR_Scene = ir_data[2];
                /* Disable the IR remote until the Preset has been saved. */
                disable_interrupts(INT_CCP2);
                break;
              /* Set Fade */
              case 0x09:
                /* Indicate that the fade time needs to be sent */
                Send_Fade_Flag = TRUE;
               
                fade = (ir_data[5] << 4) | (ir_data[6] & 0x0F);
                fade <<= 8;
                fade |= (ir_data[7] << 4) | (ir_data[8] & 0x0F);
               
                /* Convert the fade time to our segmented (bargraph display).
                   Levels[2] is the fade display */
                Levels[2] = Convert_Fade(fade);

                break;
              /* Channel Raise */
              case 0x0C:
                IR_Buttons[5] = ir_data[1];
                IR_Buttons[6] = ir_data[2];
                IR_Buttons[7] = ir_data[3];
                IR_Timeout = IR_TIMEOUT_VALUE;
                break;
              /* Channel Lower */
              case 0x0E:
                IR_Buttons[5] = ir_data[1] << 4;
                IR_Buttons[6] = ir_data[2] << 4;
                IR_Buttons[7] = ir_data[3] << 4;
                IR_Timeout = IR_TIMEOUT_VALUE;
                break;
              default:
            }
          }
          /* Error in message */
          else
          {
          }
        }
        /* Continue receiving the IR data */
        else
        {
          checksum = checksum + data;
          if (i < sizeof(ir_data))
          {
            ir_data[i] = data;
            i++;
          }
          else
            IR_State = IDLE;
        }
        break;
      default:
    }
  }
}


Guest








PostPosted: Sat Aug 21, 2004 1:13 pm     Reply with quote

wow, thanks mark!


Um.... I'm still trying to sort through that... The one I wrote (though probally doesnt work) is alot easier for me to read Embarassed

Also, If I'm running at 20Mhz.... How long is 1 increment of Timer_1 ? The ccs help says its 1.6us ???
Mark



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

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

PostPosted: Sat Aug 21, 2004 1:31 pm     Reply with quote

The timer increments and the frequency / 4 or in your case 5MHz (200ns). The timers can have prescales and postscales in which case this number can be divided down. A divide by 8 would give you the 1.6us that you speak of.

The code I posted was way more complex probably than you need. It does demonstrate how I switch between the edges and read in the bits to form a byte.
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