Phase sequence detection

Thread Starter

mitko89

Joined Sep 20, 2012
127
Hello guys,
I was asked to design a phase sequence detector, which utilizes low end uC (pic10f200). Below is my code:
Code:
/*#############################################################################
* Phase Sequence Detector
############################################################################ */
#include <xc.h>
#include <stdint.h>

/***** CONFIGURATION *****/
#pragma config MCLRE=OFF
#pragma config CP=OFF
#pragma config WDTE=OFF

/*#############################################################################
* Functions
############################################################################ */

/*#############################################################################
* timer0_init ()
* Usage - Initializes the TMR0 module for future use.
############################################################################ */
void timer0_init (void){
    OPTION = 0b11010110; // Timer mode with Prescaler 64
                         // Timer period = 4MHz/(4*128) = 7812Hz
                         // Period = 128us
                         // 20ms/128ms = 156,25 for 1 period
                         // 156,25/20 = 7,8125 ticks for 1ms
}

/*#############################################################################
* timer0_start ()
* Usage - Clears and starts the timer.
############################################################################ */
void timer0_start (void){
    TMR0 = 0b00000000;  // Reset and start the Timer
}

/*#############################################################################
* Debounce  ()
* Usage - Filters the edge detections.
############################################################################ */
uint8_t debounce (uint8_t PortMask){
    uint8_t counter = 0;
    while( PortMask == (GPIO & PortMask) && counter<15 )
    {
        counter++;
    }
    return (counter > 10)?(1):(0);
}
/*#############################################################################
* div_uint_by5  ()
* Usage - Optimized division by constant for the particular task. (max divident
* is expected to be less than 80)
############################################################################ */
uint8_t udiv (uint8_t divider){
    uint8_t divident = TMR0;
    uint8_t counter = 0;   
    while(divident)
    {
        divident -= divider;
        counter++;
    }
    return counter;
}


void main(){

    volatile uint8_t Margin = 0; // varriable to store the duration of the pulse on GP1
                                     // and the 20% margin
    volatile uint8_t PortCurrentState = 0;
    volatile uint8_t PortPreviousState = 0;
    volatile uint8_t Flag = 0;
    const uint8_t Phase2 = 51;
    const uint8_t Phase3 = 102;
    const uint8_t Phase1 = 153;
    volatile uint8_t temp2 = 0;

    OPTION = 0b11010110;
    TRISGPIO = 0b11111011;// Initialize GPIO port
  
    GPIO = _GPIO_GP2_MASK;// Turn the LED on for error;

    // Get the pulse width for initial calculations
    do{
         PortCurrentState = GPIO;
         if( (PortPreviousState & _GPIO_GP0_MASK)==0x00 && (PortCurrentState & _GPIO_GP0_MASK)!=(PortPreviousState & _GPIO_GP0_MASK) )
         {
            if( debounce(_GPIO_GP0_MASK) )
            {
                TMR0 = 0b00000000;
                if(Margin)
                {
                    break;
                }
            }
         }
         if( (PortPreviousState & _GPIO_GP0_MASK)==_GPIO_GP0_MASK && (PortCurrentState & _GPIO_GP0_MASK)!=(PortPreviousState&_GPIO_GP0_MASK) )
         {
            if( debounce(_GPIO_GP0_MASK) )
            {
               Margin = udiv(5); // calculate the 20% margin
            }
         }
        PortPreviousState = PortCurrentState;
    }while(1);
  
    while(1)
    {
        switch( udiv(Phase2)+1 )
        {
            case 1 :
            {
                temp2 = Phase2 + Margin;
                while( TMR0<temp2 )
                {
                    if( debounce(_GPIO_GP1_MASK) )
                    {
                        Flag |= _GPIO_GP1_MASK;
                        break;
                    }
                }
            }
            break;
            case 2 :
            {
                temp2 = Phase3 + Margin;
                while( TMR0<temp2 )
                {
                    if( debounce(_GPIO_GP3_MASK) )
                    {
                        Flag |= _GPIO_GP3_MASK;
                        break;
                    }
                }
            }
            break;
            case 3 :
            {
                temp2 = Phase1 + Margin;
                while( TMR0<temp2 )
                {
                    if( debounce(_GPIO_GP0_MASK) )
                    {
                         Flag |= _GPIO_GP0_MASK;                       
                         if( Flag == 0x0B )
                         {
                            TMR0 = 0b00000000;
                            Flag = 0x00;
                            GPIO = ~_GPIO_GP2_MASK;
                         }
                         break;
                    }
                }
            }
            break;
            case 4 :
            {
                temp2 = Phase1 + Margin;
                if(TMR0>temp2)
                {
                    GPIO = _GPIO_GP2_MASK;
                    Flag = 0x00;
                    TMR0 = 0b00000000;
                }
            }
            break;
        }
    }
}
But I can't quite find where's my mistake. The code compiles and the logic seems right to me, but failed on the proteus test. Can you help me out with some suggestions on where the problem is or how to improve the algorith? Thank you!
 

Thread Starter

mitko89

Joined Sep 20, 2012
127
The device is supposed to provide indication (GP2 will be on in case of error) if the phases of a 3 phase power supply (50Hz) are swapped/removed (the assignment of the phases is GP0 - P1, GP1-P2,GP3-P3). The input signals are pulses generated by MOSFETs.
The algorith is: Initialize (set IOs & Prescaler for the timer and set the led to error state (on) ) -> in the do-while I measure the pulse width of the 1st phase and then calculate the 20% margin for the phases -> Main loop, which uses switch statement, which is branched according to the value in the timer ( I reset the timer before entering the main loop on the rising edge of P1, which means I expect the rising edge of the 2nd phase to arrive in 6ms (51 ticks of the timer, but no later than 51+ the 20% of pulse width). The signal is debounced and if it happens to pass the debounce test I set a bit in the Flag variable. This happens for phases 2,3 and 1. At case 3 (the case for phase 1), if the phase passes the debounce test I check the value of the Flag variable. If all the phases have arrived (and arrived in time) I clear the error (turn the led off), clear the Flag variable and reset the timer. If the phases arrive at time, the program should never branch to case 4, but I added it in case phase 1 doesn't arrive in time (it turns on the error led, clears the Flag and resets the timer).
By failing the Proteus test I mean: I drawed the schematic in proteus, loaded the code in the simulation model of the pic and used pulse signal generators to feed the pic the correct phase sequence. Although the signals were in the correct sequence, the device shows there is an error (led is on). I'm currently debugging it by removing pieces of the code, but yet I haven't found where is the problem. There is no debugger for this processor and Proteus has no debugger for XC8... It's quite frustrating to debug such tiny devices.
 

Papabravo

Joined Feb 24, 2006
21,225
I'm guessing you have no spare pins to help with the debugging process. My long experience in embedded systems suggests that you must increase the observability of your process. Since you are still at the prototype stage, my recommendation is to debug your code on a larger (more pins), but similar processor. A serial port connected to a PC with a terminal emulator will do wonders for insight into the possible causes. When you have working code you can return to the limited part with a higher degree of confidence.

At least you don't have to put up with the ECB ( Edit, Compile, Burn) cycle, where each iteration produces a chiclet.*

*chiclet -- 1. A throwaway one-time programmable chip. Also, 2. A small piece of gum or candy.

You need to make certain that edges are detected when they are there, and not detected when they are absent. You need to make sure that after detecting an event that all of your hardware is configured to detect the next event. You must ensure that you can recover from various error conditions including unexpected timer overflow. Since you are not using interrupts I would also check for loops that require a single specific condition to exit. It should be a rule that all loops require 2 or more conditions to exit and that none of the loops take longer than some critical period to execute.
 
Last edited:

Thread Starter

mitko89

Joined Sep 20, 2012
127
Ok, I'll test it on something like pic16 (that's what I have available). Does my algorith seem correct to you? Can you give me any suggestions on how to improve it?
 
Top