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

DSPic30F4012 Cycle time measurement with 133Hz software PWM

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



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

DSPic30F4012 Cycle time measurement with 133Hz software PWM
PostPosted: Sat Sep 26, 2015 12:04 pm     Reply with quote

Hi Everyone!

I've been testing the DSPic30F4012 on a trip computer for my 4WD for a while. I could not use HW PWM due to EXT_INT0, 1 & 2 (are being used by RPM, Speed and fuel flow meter). So I decided to study software PWM. Yes, I know it may not be a good idea for high frequencies like i.e. > 100Hz, however, I decided to test it and measure the cpu cycle time to compare the performance @ different frequencies.

Below is the test code, with software PWM by Ttelmah & PCM_Programmer.

The point is that, even with my full code, It did not show the CPU to be overloaded when I increase the frequency of timer 3 from 1Khz to 4Khz or even more. Is it because of the 30MIPS? Or at this rate it shouldn't affect anyway?

Longest cpu cycle time w/ Software PWM @ 66Hz (Timer 3 Period = 500uSec): 0,005277Sec
Longest cpu cycle time w/ Software PWM @ 133Hz (Timer 3 Period = 250uSec): 0,005294Sec

CCS Version: 5.049

Any comments would be appreciated!!
Hugo


_________________
Hugo Silva


Last edited by younder on Sat Sep 26, 2015 5:44 pm; edited 6 times in total
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

Custom_Fct.h
PostPosted: Sat Sep 26, 2015 12:05 pm     Reply with quote

Custom_Fct.h
Code:

unsigned int i,Temp0;
// =============================================================
// "Timer1 ISR", -> called every 568,888mSec <-
// =============================================================
Unsigned int1 Cycle_Time_Overflow=0;
Unsigned int16 Cycle_Time=0,Cycle_Time_Mem[2]={0,0};
Unsigned int32 Cycle_Time_Total=0,Cycle_Time_Max=0;
#INT_TIMER1             
void timer1()         
  {
        Cycle_Time++;
        Cycle_Time_Overflow=1;
  }
// *************************************************************
// =============================================================
// "Timer2 ISR", -> called every 25ms <-
// 117,964,800 as the oscillator internal (Tosc) rate.
// Divide by 4 to get the timer increment rate (Tclk), so 29,491,200 Hz.
// Divide by 64 since the divide by 64 pre-scaler was set, so 460,800 counts / sec on the timer.
// The timer is set to 54,015 (65,536-11,520), so it will overflow after 11,520 counts.
// (1/460,800)*11,520=0,025s or 25ms.
// set_timer2(54,015 + get_timer2()) Timer2 will overflow every 25ms...
// =============================================================
union pulse_data_type { 
   int8 buffer;
   int1 clock[8];
   struct {
      int1 _25;
      int1 _50;
      int1 _100;
      int1 _200;
      int1 _500;
      int1 _1000;
   } mSec;
};
 union pulse_data_type pulse=0;

#INT_TIMER2
void timer2()           
{
  static int8 counter_SP[6] = {1,2,4,8,20,40}; //Counters Setpoint (Value*25ms)
  static int8 i, counter[6] = {1,2,3,4,5,6}, mask;

 // set_timer2(54015 + get_timer2()); //11520counts = 25mSec
  mask=1;
  for (i=0;i<6;i++)
  {
      counter[i]--;
     if (counter[i]==0)
     {
        counter[i]=counter_SP[i];
        pulse.buffer^=mask;
     }
     mask*=2;
  }
}
// *************************************************************
// =============================================================
// Rising/Falling edge pulses
// =============================================================
union edge_data_type { 
   int1 buffer[8];
   struct {
      int1 _25;
      int1 _50;
      int1 _100;
      int1 _200;
      int1 _500;
      int1 _1000;
   } mSec;
};
 union edge_data_type R_Edge={0,0,0,0,0,0,0,0};

 typedef struct Edge_scan {
 int1 scan[8];
 };
 
union edge_scan_type {
 struct Edge_scan Buffer[6];
 struct {
      int1 _25_scan[8];
      int1 _50_scan[8];
      int1 _100_scan[8];
      int1 _200_scan[8];
      int1 _500_scan[8];
      int1 _1000_scan[8];
   } mSec;   
}; 
   union edge_scan_type Edge={0,0,0,0,0,0};
   
void Edge_Pulses()           
{
static int1 aux_R[6];     //Auxiliar Variable
static int8 Scan_Count[6]={0,0,0,0,0,0};

  for (i=0;i<6;i++)
  {
//Rising edge
   if (pulse.clock[i]) { //If pulse is true     
         if (aux_R[i]==0) R_Edge.buffer[i]=1; else R_Edge.buffer[i]=0; //and aux is false then edge=TRUE for only one scan
         aux_R[i]=1; //Next scan edge pulse will be false
      } else aux_R[i]=0,R_Edge.buffer[i]=0; //Clear aux till next rising edge detection

//Edge array bits
            if (Edge.Buffer[i].scan[Scan_Count[i]]) {
            if (Scan_Count[i]<7) Edge.Buffer[i].scan[Scan_Count[i]+1]=1;             
               Edge.Buffer[i].scan[Scan_Count[i]]=0;
                  Scan_Count[i]++;
                     if (Scan_Count[i]>7) Scan_Count[i]=0;
      }
         if (R_Edge.buffer[i] && (Scan_Count[i]==0)) Edge.Buffer[i].scan[0]=1;   
  }
}

// *************************************************************

// =============================================================
// A/D Function
// =============================================================
Long Read_AD(int Channel)
  {
  Static Long Analog_Value;
  Switch(Channel)
    {
    case 0 : input(BAT_VOLTAGE), setup_adc_ports(sAN0, VSS_VDD); break;
    case 1 : input(ALTERNATOR_CURRENT), setup_adc_ports(sAN0 | sAN1, VSS_VDD); break;
    case 2 : input(FUEL_TANK_LEVEL), setup_adc_ports(sAN0 | sAN1 | sAN2, VSS_VDD); break;
    case 3 : input(COOLANT_TEMP), setup_adc_ports(sAN0 | sAN1 | sAN2 | sAN3, VSS_VDD); break;
    case 4 : input(AIR_TEMP), setup_adc_ports(sAN0 | sAN1 | sAN2 | sAN3 | sAN4, VSS_VDD); break;
    default: return(0);
    }
  set_adc_channel(channel);
  Analog_Value = read_adc();
  setup_adc_ports(NO_ANALOGS);
  return(Analog_Value);
  }
// *************************************************************

_________________
Hugo Silva
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

Test.c
PostPosted: Sat Sep 26, 2015 12:05 pm     Reply with quote

Test.c
Code:

#include <30F4012.h>
#device ADC=10     
#fuses FRC_PLL16,NOPROTECT,NOWRT,MCLR,BORRES,PUT64,NOCKSFSM,BORV27,NODEBUG,NOWDT
#use delay(Internal=117964800) // Internal 7.3728Mhz * FRC_PLL16 = 117964800Hz (30MIPS)
#use i2c(MASTER, SCL=PIN_F3, SDA=PIN_F2, FAST, stream=I2C_SOFTWARE)
#build (stack=256) // 128,256,384 or 512 depending how big the code is

//PORT B
#define BAT_VOLTAGE           PIN_B0  //AD0 - 12V battery level
#define ALTERNATOR_CURRENT    PIN_B1  //AD1 - AlternatorĀ“s current
#define FUEL_TANK_LEVEL       PIN_B2  //AD2 - Fuel tank level
#define COOLANT_TEMP          PIN_B3  //AD3 - Coolant Temperature
#define AIR_TEMP              PIN_B4  //AD4 - Internal Air Temperature
#define KEY_BIT_1             PIN_B5  //IN - Key Bit 01

//PORT C
#define KEY_BIT_2             PIN_C13  //IN - Key Bit 02
#define KEY_BIT_3             PIN_C14  //IN - Key Bit 03
#define LED_OUT               PIN_C15  //OUT - LED

//PORT D
#define GAS_FLOW_IN           PIN_D0  //INT1 - Gasoline Flow Pulse
#define SPEED_IN              PIN_D1  //INT2 - Speed Sensor pulse

//PORT E
#define AUX_01_OUT            PIN_E0  //OUT - Auxiliar Output 1 (PWM 1)
#define AUX_02_OUT            PIN_E1  //OUT - Auxiliar Output 2 (PWM 2)
#define RELAY_01_OUT          PIN_E2  //OUT - Relay #01
#define RELAY_02_OUT          PIN_E3  //OUT - Relay #02
#define AUX_01_IN             PIN_E4  //IN - Auxiliar Input 1
#define AUX_02_IN             PIN_E5  //IN - Auxiliar Input 2
#define RPM_IN                PIN_E8  //INT0 - Tachometer Pulse
#use FIXED_IO( E_outputs=PIN_E0,PIN_E1,PIN_E2,PIN_E3 )

#include <lib\i2c_Flex_LCD.h>
#include <lib\Custom_Fct.h>

#define PWM_PIN  PIN_E2
#define PWM_PIN2  PIN_E3
#define LOOPCNT 29

// =============================================================
// Global variables declaration
// =============================================================
Unsigned int16 ADC_0=0,ADC_1=0,ADC_2=0,ADC_3=0,ADC_4=0,Key;
Unsigned int8 width, width2;
int1 first_scan_bit=1,Edge_new_screen=1,UP_Key, DOWN_Key, ENTER_Key;

#int_timer3
void timer3_isr(void)
{
static int8 loop = LOOPCNT;
static int8 pulse,pulse2;

if(--loop == 0) {
   loop = LOOPCNT;
   pulse = width;
   pulse2 = width2;
  }

if(pulse) output_high(PWM_PIN), pulse--; else output_low(PWM_PIN);
if(pulse2) output_high(PWM_PIN2), pulse2--; else output_low(PWM_PIN2);
}

void Initialization() {
//Disable all interrupts
   disable_interrupts(INTR_GLOBAL);
// Initialize 20x4 LCD Display
   lcd_init();
//Configures Timer1
   setup_timer1 (TMR_INTERNAL | TMR_DIV_BY_256, 65535); //Configures timer1 to overflow every 568,888mSec
   enable_interrupts(INT_TIMER1);
//Configures Timer2
   setup_timer2 (TMR_INTERNAL | TMR_DIV_BY_64, 11520); //Configures timer2 to overflow every 25mSec
   enable_interrupts(INT_TIMER2);
//Configures Timer3
   setup_timer3 (TMR_INTERNAL | TMR_DIV_BY_1, 7500); //7500counts = 250uSec 
   enable_interrupts(INT_TIMER3); 
//ADC clock
   setup_adc(ADC_CLOCK_DIV_64 | ADC_TAD_MUL_8);
//Set GIE&PEIE bits and Enable all interrupts
   enable_interrupts(INTR_GLOBAL);
 }

void LCD_Display_Diag()
  {
         if (Edge.mSec._50_scan[0])  {
                  lcd_gotoxy(1, 1);
                  printf(LCD_PUTC,"Actual Cycle:");
                  lcd_gotoxy(1, 2);
                  printf(LCD_PUTC,"%1.6lws",Cycle_Time_Total/100);
         }
          if (Edge.mSec._100_scan[1])  {                 
                  lcd_gotoxy(1, 3);
                  printf(LCD_PUTC,"Longest Cycle:");
                  lcd_gotoxy(1, 4);
                  printf(LCD_PUTC,"%1.6lws",Cycle_Time_Max/100);
                  }
   }

long KeyScan() {     
static long inKey=0, key_mem=0;
#bit  inKey_bit0 = inKey.0       
#bit  inKey_bit1 = inKey.1   
#bit  inKey_bit2 = inKey.2   

      If (input(KEY_BIT_1)) {
      if (!UP_Key) delay_ms(20);          //debouncing time
      UP_Key=1;
      inKey_bit0=1;
      } else UP_Key=0,inKey_bit0=0;
     
      If (input(KEY_BIT_2)) {
      if (!DOWN_Key) delay_ms(20);        //debouncing time
      DOWN_Key=1;
      inKey_bit1=1;
      } else DOWN_Key=0,inKey_bit1=0;
     
      If (input(KEY_BIT_3)) {
      if (!ENTER_Key) delay_ms(20);       //debouncing time
      ENTER_Key=1;
      inKey_bit2=1;
      } else ENTER_Key=0,inKey_bit2=0;
 
    if(inKey != key_mem){
       key_mem=inKey;
       return inKey;
    } else return 0;
 }

void PWM() {
static int8 cnt=0, cnt2=0;
static int1 dup=1, ddown=1;
//PWM 1
If (Edge.mSec._25_scan[1]) {
   if (dup) cnt++; else cnt--;
   if (cnt>29) dup=0;
   if (cnt==0) dup=1;
      width = cnt;
   }

//PWM 2
If (Edge.mSec._50_scan[2]) {
   if (ddown) cnt2++; else cnt2--;
   if (cnt2>29) ddown=0;
   if (cnt2==0) ddown=1;
      width2 = cnt2;
 } 
}

void AD() {
static int8 Read_Analog=0;

 Read_Analog++;
if (Read_Analog>4)Read_Analog=0;
Switch(Read_Analog)
  {
    case 0 : {
               ADC_0=Read_AD(0);
             } break;       
    case 1 : {
               ADC_1=Read_AD(1);
             } break;   
    case 2 : {
               ADC_2=Read_AD(2);   
             } break;
    case 3 : {
               ADC_3=Read_AD(3); 
             } break;
    case 4 : {
               ADC_4=Read_AD(4); 
             } break;
  }
}

void Cycle_time_measuring()
{
static int1 Flag_ResetCycleTime=0;
static int8 Reset_Cycle_Time=0;
static unsigned int16 Cycle_Time_Buffer=0;

         Cycle_Time_Buffer=Cycle_Time;
         Cycle_Time_Mem[0]=get_timer1(); //get actual tmr1 value
         if ((Cycle_Time_Mem[0]==65535) && Cycle_Time_Overflow) Cycle_Time_Mem[0]=0,Cycle_Time_Overflow=0;
               if (Cycle_Time_Mem[0]>Cycle_Time_Mem[1])
                  {
                     Temp0=Cycle_Time_Mem[0]-Cycle_Time_Mem[1]; //how many tmr1 counts since last measuring?
                     Cycle_Time_Total=((((int32)Cycle_Time_Buffer*65535)+Temp0)*868); 
                  }
               else
                  { 
                     if (Cycle_Time_Buffer<=0) Temp0=1; else Temp0=Cycle_Time_Buffer;
                     Cycle_Time_Total=((((int32)Temp0*65535)-Cycle_Time_Mem[1]+Cycle_Time_Mem[0])*868); 
                  }
                     Cycle_Time_Mem[1]=Cycle_Time_Mem[0]; //memorizes current tmr1 value in case a new interrupt happens before tmr1 overflows
                     Cycle_Time=0;   //Reset Actual Cycle time counter

         if (Cycle_Time_Total>Cycle_Time_Max) Cycle_Time_Max=Cycle_Time_Total;
         
         //Reset Longest Cycle Time

            If (ENTER_Key) Flag_ResetCycleTime=1;
               If (!ENTER_Key && Flag_ResetCycleTime && R_Edge.mSec._50) Reset_Cycle_Time++;
                 if (Reset_Cycle_Time>=10) {
                 Flag_ResetCycleTime=0;
                 Reset_Cycle_Time=0;
                 Cycle_Time_Max=0;
     }
 }

void Main() {
  Initialization();
   while(1){
   
  Edge_Pulses();           //Edge pulses pulses for general use
  Key=keyScan();           //Up, Down and Enter Keys
  Cycle_time_measuring();  //At this point, measure actual and longest cycle time
  AD();                    //Just read AD ports
  PWM();                   //Perform a Software 4Khz PWM (Timer 3 @ 250uSec)
  LCD_Display_Diag();      //Display measured values
 
  }
}
//------------------ EOF ---------------------


_________________
Hugo Silva
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Sun Sep 27, 2015 1:42 am     Reply with quote

Nobody is going to plod though that length of code.

Obviously 30MIPS does make a huge difference. Most of the people here asking about software PWM, are running at perhaps only 1 or 2 MIPS.

However you are also missing a fundamental 'point'. It is not the frequency of the PWM that matters, but the product of frequency and resolution. If a poster is talking about a PWM to control a device needing perhaps 100 different levels, and needs 100Hz, then the timer tick has to be occurring at 10KHz....
A 1000Hz PWM, with only four levels, conversely only needs 4KHz.
Most of the posters asking about software PWM here are doing things that require fine control. :(
Many of the posters want PWM at KHz rates, and high resolution.

Then you have the second question/problem. If an error in the timing of the PWM 'matters' at all significantly, then this has to be given priority over the other interrupts. Otherwise if (for instance) serial data, arrives just at the same time, the actual pulse edge on the PWM will be delayed by the total latency for the serial handler. Now on the smaller PIC's the total serial buffer is less than two characters, so the serial - if fast, will have to be given priority - result errors in the PWM timing when serial data arrives. On the PIC 30, you have much more buffering, so you could instead give the PWM priority....

I'm puzzled though about your comment about not being able to use hardware PWM. You need to be aware that you can specify an input change interrupt on CN0 to CN7, so there are actually eight more pins that can be used for input interrupts.
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Sun Sep 27, 2015 8:41 am     Reply with quote

Thanks Ttelmah for your comments about the product of frequency and resolution.

In my case it is going to be used to control a fuel and temperature gauges, so it may works considering that the gauge has a slow response...I'm not sure about the resolution, as I do not have the spec., just need to test it later to see if like 10 or 20 levels @ 4Khz are enough.

Regarding the CNx Interrupts, yes I went thru this already, but I realized that it is not so flexible, since I have only one ISR handler and the interrupts always happens in the falling and rising edges. I thought it would be not nice to have RPM, Fuel flow & speed pulses being processed in the same ISR, besides it would increase the interrupt ticks twice at least.

I was aware about the code length, however in the main loop you can see that there are just a couple of basic function calls...so that the cpu cycle time analysis & sw pwm could be tested considering a few lines of code. BTW, I hope this is a right way to measure cpu time.

Thanks
Hugo
_________________
Hugo Silva
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Sun Sep 27, 2015 1:42 pm     Reply with quote

You need to be aware that there are dozens of hidden 'ticks' involved _outside_ your interrupt routine, to handle each interrupt.
There is _less_ process work handling multiple things in one handler, than having multiple handlers. For every interrupt handler you have, dozens of registers are saved and restored when it is called....

It is always tempting to think interrupts just jump you to the routine, but there is a lot of overhead instructions and time involved in this.

On IOC, have a look at this thread:
<https://www.ccsinfo.com/forum/viewtopic.php?t=52574>
and the example.

Several of the later chips have the ability to specify which edge is used as well. I don't think yours offers this though.
guy



Joined: 21 Oct 2005
Posts: 297

View user's profile Send private message Visit poster's website

PostPosted: Mon Sep 28, 2015 1:42 am     Reply with quote

You could also use a more straightforward PWM implementation (but it requires a timer for each PWM channel) -
1. output_high(PWM)
2. set the timer for positive pulse time
3. wait for timer (polling or interrupt)
4. output_low(PWM)
5. set the timer for negative pulse time
6. wait for timer (polling or interrupt)

This (which could be done with or without an interrupt) saves dozens of interrupt calls (=overhead). Anyway 4KHz on 30 MIPS is not very challenging, esp. if you don't need extremely high accuracy and resolution in the PWM. You could actually do it in the main loop as I explained and avoid interrupt issues altogether.

As for measuring interrupt "costs", I either use the simulator with stopwatch, or create a simple
void main() {
output_toggle(SQWAVE);
}
this shows on the oscilloscope how much time is spent 'not running the main code' which is equal to how much time is spent on interrupts.
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Mon Sep 28, 2015 5:07 pm     Reply with quote

The 'output_toggle(SQWAVE);' in the main loop is a good idea, however I've been using this cpu measure method as an embedded function in my "diag. screen".

I normally enable it when I want to see the interrupt "costs" at different times and conditions in the field, this give me an idea about code behavior at all w/o a scope.

I know it is related to the particular application, but I'm wondering what would be a good main loop maximum cycle time? In my case (the test code above = 5,294mSec) or even the full Trip Computer code (which is much bigger and with more interrupts = 8,011mSec) running in a chip @ 30MIPS... I'm just curious to know if there is a good pratice for this, to be considered when developing a project.

BW,
Hugo
_________________
Hugo Silva
guy



Joined: 21 Oct 2005
Posts: 297

View user's profile Send private message Visit poster's website

PostPosted: Mon Sep 28, 2015 11:56 pm     Reply with quote

In my humble opinion it depends on the specific application - critical time between tasks in the main loop, buffer sizes etc.
I didn't go into the code so I can't comment on it but I rarely have main loops which take more than a few cycles. Tasks are executed 'on-demand': If an interrupt raises a flag the main loop will continue handling the data; display and UI functions are handled every 100ms (or upon change to the display). etc.
hope this helps.
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Tue Sep 29, 2015 11:27 am     Reply with quote

Guy, thanks for your comments, I'm not doing projects for living, but I definitely love to spend hours (my wife doesn't!) trying to improve my poor knowledge, I hope one day I'll be able to finish my trip computer!

For non critical timing application, I usually use in the main loop my custom ticks. For each custom clock, like i.e. 100mSec, I have an 8 bit edge moment array associated to it. I then try to do not "overload that particular scan" by executing different tasks in different scans.

Code:

If (Edge.mSec._100_scan[0]) Speed_Calc(); //Call the function every 100ms (scan 0)
.
.
.
If (Edge.mSec._100_scan[7]) PWM(); //Call the function every 100ms (scan 7)


Same as above for other clocks (25mSec,200mSec,500mSec etc.)

I Think I can combine also the 'on-demand' requests in some cases, which will also improve the main loop.

Code:

union pulse_data_type {
   int8 buffer;
   int1 clock[8];
   struct {
      int1 _25;
      int1 _50;
      int1 _100;
      int1 _200;
      int1 _500;
      int1 _1000;
   } mSec;
};
 union pulse_data_type pulse=0;
#INT_TIMER2
void timer2()           
{
  static int8 counter_SP[6] = {1,2,4,8,20,40}; //Counters Setpoint (Value*25ms)
  static int8 i, counter[6] = {1,2,3,4,5,6}, mask;

 // set_timer2(54015 + get_timer2()); //11520counts = 25mSec
  mask=1;
  for (i=0;i<6;i++)
  {
      counter[i]--;
     if (counter[i]==0)
     {
        counter[i]=counter_SP[i];
        pulse.buffer^=mask;
     }
     mask*=2;
  }
}
// *************************************************************
// =============================================================
// Rising/Falling edge pulses
// =============================================================
union edge_data_type {
   int1 buffer[8];
   struct {
      int1 _25;
      int1 _50;
      int1 _100;
      int1 _200;
      int1 _500;
      int1 _1000;
   } mSec;
};
 union edge_data_type R_Edge={0,0,0,0,0,0,0,0};

 typedef struct Edge_scan {
 int1 scan[8];
 };
 
union edge_scan_type {
 struct Edge_scan Buffer[6];
 struct {
      int1 _25_scan[8];
      int1 _50_scan[8];
      int1 _100_scan[8];
      int1 _200_scan[8];
      int1 _500_scan[8];
      int1 _1000_scan[8];
   } mSec;   
};
   union edge_scan_type Edge={0,0,0,0,0,0};
   
void Edge_Pulses()           
{
static int1 aux_R[6];     //Auxiliar Variable
static int8 Scan_Count[6]={0,0,0,0,0,0};

  for (i=0;i<6;i++)
  {
//Rising edge
   if (pulse.clock[i]) { //If pulse is true     
         if (aux_R[i]==0) R_Edge.buffer[i]=1; else R_Edge.buffer[i]=0; //and aux is false then edge=TRUE for only one scan
         aux_R[i]=1; //Next scan edge pulse will be false
      } else aux_R[i]=0,R_Edge.buffer[i]=0; //Clear aux till next rising edge detection

//Edge array bits
            if (Edge.Buffer[i].scan[Scan_Count[i]]) {
            if (Scan_Count[i]<7) Edge.Buffer[i].scan[Scan_Count[i]+1]=1;             
               Edge.Buffer[i].scan[Scan_Count[i]]=0;
                  Scan_Count[i]++;
                     if (Scan_Count[i]>7) Scan_Count[i]=0;
      }
         if (R_Edge.buffer[i] && (Scan_Count[i]==0)) Edge.Buffer[i].scan[0]=1;   
  }
}

_________________
Hugo Silva
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