0
\$\begingroup\$

I'm trying to develop a C program to control the turn on/off of thyristors by changing the angle of the output signal (down time, and up time). I use a pot to control the angle, and I receive an input signal generated by a zero crossing detector, the input signal period is 8.3 ms. This input signal triggers an External Interruption that the program uses to decide the down time of the output signal.

This is the output signal:

enter image description here

The problem I'm having is that the program runs slow or even stops when simulating the complete circuit.

I've tried to change the lcd display with a count but it goes slower.

This is my code:

        #include <xc.h>
    #include  <stdlib.h>
    #include  <math.h>
    #define _XTAL_FREQ 48000000
    #include "lcd.h"
    #pragma config PLLDIV   = 5         // (20 MHz crystal)
    #pragma config CPUDIV   = OSC1_PLL2 
    #pragma config USBDIV   = 2         // Clock source from 96MHz PLL/2
    #pragma config FOSC     = HSPLL_HS //HSPLL_HS
    #pragma config WDT      = OFF
    #pragma config FCMEN = OFF 
    #pragma config MCLRE    = ON
    #pragma config LVP      = OFF

    //Variables
    CHAR lcd[16];
    CHAR msg[]="alfa(deg) = ";
    unsigned int adcValue = 0;
    int us = 0;
    int i = 0;
    int count = 0;
    unsigned int show_degrees = 0;
    unsigned int degrees = 0;
    unsigned int downTime = 0;
    double lowTime = 0;
    double lowTime_us = 0;
    unsigned int lowTime_ms = 0;

    // Functions
    unsigned int adc_read(unsigned char ch);
    void select_delay_us();
    void convert_to_degrees(unsigned int adc);
    void display_degrees();

    // Interrupts
    void interrupt my_isr(void){
        if (INTCONbits.INT0IF == 1)
        {           
            count++;
            
            if (degrees == 0) {
                PORTC = 0x04;
                __delay_ms(8);
            } 
            else if (degrees == 180) {
                PORTC = 0x00;
            }
            else {
                lowTime = (degrees * 8.3) / 180;    // Calculate lowTime
                lowTime_ms = (int) lowTime;     
                lowTime_us = (lowTime - lowTime_ms) * 10; 
                us = (int) lowTime_us;
                
                PORTC = 0x00;
                for (i=0; i < lowTime_ms; i++)
                    __delay_ms(1);
                
                for (i=0; i < us; i++)
                    __delay_ms(0.1);
                    
                PORTC = 0x04;
            }
            
            INTCONbits.INT0IF = 0;  // Clear EXTERNAL INTERRUPTION FLAG
        }
    }

    // MAIN 
    VOID main() {
    
    ADCON1 |= 0x0F;
    PORTE = TRISE = 0x00;
    PORTB = TRISB = 0x00;

    TRISAbits.TRISA0 = 1;   //AN0
    TRISAbits.TRISA3 = 1;   //AN3

    lcd_init();

    TRISB=TRISC=TRISD = 0x00;          // set direction to be output
    PORTD=0x0;

    INTCONbits.GIE  = 1;        //enable global interrupts
    INTCONbits.PEIE = 1;        //enable peripherical interrupts
    INTCONbits.INT0IE = 1;  //enable INT0 Interrupt
    
    TRISBbits.RB0 = 1;          //RB0 As Input

    adcValue = adc_read(0);     // Read from AN0
    convert_to_degrees(adcValue); // Convert & Display degrees to LCD
    
    do { 
        
        //if (count == 50) { 
                adcValue = adc_read(0);     // Read from AN0
                convert_to_degrees(adcValue); // Convert & Display degrees to LCD
                
                //display_degrees();
                //count = 0;
        //}
    }
    while(1);
    }

    // ADC Conversion 
    unsigned int adc_read(unsigned char ch)
    {
        unsigned int result;
        ADCON0 = (ch & 0x0F) << 2;
        //ADCON1 = 0x1B;        //RA0-RA3 Analog inputs. & AN3=VREF
        ADCON1 = 0x0B;          //RA0-RA3 Analog inputs.
        ADCON2 = 0x95;          // right justify,4 TAD, A/D FOSC/16
        ADCON0bits.ADON = 1;    // ADC on

        ADCON0bits.GO_DONE = 1;

        while (ADCON0bits.GO_DONE == 1);
        result = ((unsigned int)(ADRESH) << 8) + ADRESL;
        ADCON0bits.ADON = 0;    // ADC Off
        return result;
    }

    void convert_to_degrees(unsigned int adc)
    {
        show_degrees = adc * 0.1759;
        degrees = adc * 0.1759;
        if (degrees == 179)
            degrees ++;
    }

    void display_degrees()
    {       
        itoa(lcd, show_degrees, 10); // Convert Vdec to string in "op"
        lcd_display(1, 1, msg); // Display degrees message
        lcd_display(1, 13, lcd); // Output to LCD
    }
\$\endgroup\$
4
  • 1
    \$\begingroup\$ You are doing a lot of math with an 8-bit processor, and doing a chunk of it repetitively in the ISR. You also have interrupts in your peripherals. Check your disassembly listing and you can see how many instructions are required. \$\endgroup\$ Jun 30 at 16:17
  • \$\begingroup\$ __delay_ms(0.1);This function don't work with a float value. \$\endgroup\$
    – Mike
    Jul 1 at 11:08
  • \$\begingroup\$ Don't use floaton such a small uC. \$\endgroup\$
    – Mike
    Jul 1 at 11:13
  • \$\begingroup\$ check your oszillator. Are you sure you could combine a 20 MHz chrystal and the PLL to 48 MHz? \$\endgroup\$
    – Mike
    Jul 1 at 11:22
0
\$\begingroup\$

There are lots of fundamental problems in this code. Some of the most severe problems:

  • You need to keep ISRs minimal and not run some expensive floating point math in them. Nor should you have delays or anything taking up time there.
  • This is a horribly inefficient 8 bit MCU and not a PC, so you should stay clear of any expensive calculations. Particularly >32 bit arithmetic or floating point.
  • It doesn't seem like this part even comes with a FPU so you shouldn't be using floating point arithmetic in the first place. Any floating point math will result in very big and cumbersome software floating point libraries getting linked, killing everything that is performance and memory space. If you actually need "advanced math" like trigonometry, you picked the wrong part for the task.
  • Variables shared between an ISR and the main program must be declared as volatile and also protected against race conditions.
  • This part only got 2k RAM so there is a very high probability of stack overflows all over the place. PIC in particular are notorious for this - some parts are having limits to call stack depth as well, I don't remember which ones. I don't know how much RAM you've reserved for the stack, but you have some pretty deep call stack depth inside that ISR, where the software floating point libs will keep calling various internal functions.

You might not be able to salvage this project. Start over with the requirements, ask someone with embedded systems experience what MCU that would be suitable to fulfil them, then take it from there.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.