# Pic programming help needed

#### Don Omar

Joined May 5, 2017
49
Hi dear,
i need you help with programming the pic using c language .
this is what i have to do using the pickit 3

1) A positive-going pulse every crank revolution for the fuel injector whose length can be varied between approximately 500 us and 8 ms in 256 steps by use of one of the two potentiometer controls provided on the demonstration board pic-kit3

2)A positive-going pulse every crank revolution for the spark ignition. The pulse should be approximately 2 ms long and the falling edge of this pulse is assumed to generate the spark with minimal delay. The position of this negative firing edge should be variable from approximately 84° before top-dead-centre (BTDC) to 12° after top-dead-centre. The method of varying the firing position will also be by turning one of the potentiometers on the board and will provide 32 different firing positions with a resolution of 3°. Note that sparks will be generated on both TDC positions of the four-stroke cycle and the missing teeth on the “Toothed Wheel simulator” occur 120° BTDC

this is what i have done so far:
C:
#include <xc.h>
#include <timers.h>

// Configuration settings
#pragma config OSC=HS,FSCM=OFF,IESO=OFF
#pragma config PWRT=ON,BOR=OFF,BORV=45
#pragma config WDT=OFF
#pragma config MCLRE=ON
#pragma config STVR=OFF,LVP=OFF,DEBUG=OFF
#pragma config CP0=OFF,CP1=OFF
#pragma config CPB=OFF,CPD=OFF
#pragma config WRT0=OFF,WRT1=OFF
#pragma config WRTB=OFF,WRTC=OFF,WRTD=OFF
#pragma config EBTR0=OFF,EBTR1=OFF
#pragma config EBTRB=OFF
//===============================================================

void    main(void)
{
void OpenTimer0 (unsigned char);
void WriteTimer0(unsigned int timer0);
void CloseTimer0 (void);

OSCCONbits.SCS0=0;     //set oscillator to external
OSCCONbits.SCS1=0;

TRISA = 0b00110011;        //Set port input output directions
TRISB = 0b11000100;
ADCON1 = 0b11111100;    //All bits digital I/O except AN0 and AN1
RCON=0b00000000;        //disable interrupt priorities (compatible with 16F series)
INTCON=0b00000000;        //disable interrupts
INTCON2=0b00000000;     //pull-ups enabled interrupt are all low priority

//            0b01111110 ); //ADCON1 - AN0 set as analogue in
//    ADCON0bits.VCFG1=0;//Discovered bug - OpenADC left this bit set leaving AVSS as external vref which is connected to an LED!

OpenTimer0(    TIMER_INT_OFF    & //no timer interrupts
T0_16BIT        & //16 bit mode
T0_SOURCE_INT    &
T0_EDGE_FALL    & //Not important for this
T0_PS_1_64           // divide by 64 prescaler
);

WriteTimer0(0);
INTCONbits.TMR0IF=0;

while(1)    //Loop forever
{

while(PORTBbits.RB2==0); //wait until pulse goes high
WriteTimer0(0);
while(PORTBbits.RB2==1);// wait until the pulse goes low
while(PORTBbits.RB2==0);

????

}

CloseTimer0();

//    CloseADC(); // Not actually used but placed here so you know the function exists!

}

void OpenTimer0 (unsigned char config)
{

T0CON = (0X7f & config);
TMR0H = 0;
TMR0L = 0;

INTCONbits.TMR0IF = 0;

if(config&0x80)

INTCONbits.TMR0IE = 1;
else
INTCONbits.TMR0IE = 0;

T0CONbits.TMR0ON = 1;
}

void WriteTimer0(unsigned int timer0)
{
union Timers timer;
timer.lt = timer0;

TMR0H = timer.bt[1];
TMR0L = timer.bt[0];
}

void CloseTimer0 (void)
{
T0CONbits.TMR0ON = 0;
INTCONbits.TMR0IE = 0;

}

{
union Timers timer;

timer.bt[0] = TMR0L;  // Copy Timer0 low byte into union
timer.bt[1] = TMR0H;  // Copy Timer0 high byte into union

return (timer.lt);    // Return the int
}

//{
//
//        return ADRESH;//Returns 8 MSB of 10 bit result
//}
//
//{
//}
//
//              unsigned char config2,
//              unsigned char portconfig)
//{
//
//    ADCON0 = ((config2 >> 1) & 0b00111100) |
//             ((config2 << 6) & 0b11000000);
//    ADCON2 = ((config & 0b10000000)|((config >> 4) & 0b00000111)) |
//             ((config << 2) & 0b00111000);
//
//    if( config2 & 0b10000000 )
//    {
//      INTCONbits.PEIE = 1;
//    }
//}
//
//{
//}
//
//{
//}

#include <timers.h>

// Configuration settings
#pragma config OSC=HS,FSCM=OFF,IESO=OFF
#pragma config PWRT=ON,BOR=OFF,BORV=45
#pragma config WDT=OFF
#pragma config MCLRE=ON
#pragma config STVR=OFF,LVP=OFF,DEBUG=OFF
#pragma config CP0=OFF,CP1=OFF
#pragma config CPB=OFF,CPD=OFF
#pragma config WRT0=OFF,WRT1=OFF
#pragma config WRTB=OFF,WRTC=OFF,WRTD=OFF
#pragma config EBTR0=OFF,EBTR1=OFF
#pragma config EBTRB=OFF
//===============================================================

void    main(void)
{
void OpenTimer0 (unsigned char);
void WriteTimer0(unsigned int timer0);
void CloseTimer0 (void);

OSCCONbits.SCS0=0;     //set oscillator to external
OSCCONbits.SCS1=0;

TRISA = 0b00110011;        //Set port input output directions
TRISB = 0b11000100;
ADCON1 = 0b11111100;    //All bits digital I/O except AN0 and AN1
RCON=0b00000000;        //disable interrupt priorities (compatible with 16F series)
INTCON=0b00000000;        //disable interrupts
INTCON2=0b00000000;     //pull-ups enabled interrupt are all low priority

//            0b01111110 ); //ADCON1 - AN0 set as analogue in
//    ADCON0bits.VCFG1=0;//Discovered bug - OpenADC left this bit set leaving AVSS as external vref which is connected to an LED!

OpenTimer0(    TIMER_INT_OFF    & //no timer interrupts
T0_16BIT        & //16 bit mode
T0_SOURCE_INT    &
T0_EDGE_FALL    & //Not important for this
T0_PS_1_64           // divide by 64 prescaler
);

WriteTimer0(0);
INTCONbits.TMR0IF=0;

while(1)    //Loop forever
{

while(PORTBbits.RB2==0); //wait until pulse goes high
WriteTimer0(0);
while(PORTBbits.RB2==1);// wait until the pulse goes low
while(PORTBbits.RB2==0);

????

}

CloseTimer0();

//    CloseADC(); // Not actually used but placed here so you know the function exists!

}

void OpenTimer0 (unsigned char config)
{

T0CON = (0X7f & config);
TMR0H = 0;
TMR0L = 0;

INTCONbits.TMR0IF = 0;

if(config&0x80)

INTCONbits.TMR0IE = 1;
else
INTCONbits.TMR0IE = 0;

T0CONbits.TMR0ON = 1;
}

void WriteTimer0(unsigned int timer0)
{
union Timers timer;
timer.lt = timer0;

TMR0H = timer.bt[1];
TMR0L = timer.bt[0];
}

void CloseTimer0 (void)
{
T0CONbits.TMR0ON = 0;
INTCONbits.TMR0IE = 0;

}

{
union Timers timer;

timer.bt[0] = TMR0L;  // Copy Timer0 low byte into union
timer.bt[1] = TMR0H;  // Copy Timer0 high byte into union

return (timer.lt);    // Return the int
}

//{
//
//        return ADRESH;//Returns 8 MSB of 10 bit result
//}
//
//{
//}
//
//              unsigned char config2,
//              unsigned char portconfig)
//{
//
//    ADCON0 = ((config2 >> 1) & 0b00111100) |
//             ((config2 << 6) & 0b11000000);
//    ADCON2 = ((config & 0b10000000)|((config >> 4) & 0b00000111)) |
//             ((config << 2) & 0b00111000);
//
//    if( config2 & 0b10000000 )
//    {
//      INTCONbits.PEIE = 1;
//    }
//}
//
//{
//}
//
//{
//}
thank you

#### AlbertHall

Joined Jun 4, 2014
12,187
Can you describe the problem in terms of the inputs and outputs of the PIC. I understand coding with XC8 but assume that I know nothing of engines. Presumably the PIC receives at least one timing pulse from the engine - what is the timing of this pulse and which pin is it on.
Which pins have the voltage from the pots and what each of those is expected to control.
I think there are supposed to be two pins for output pulses - please describe the timing expected in relation to the the timing pulse input.

#### Don Omar

Joined May 5, 2017
49
Hi Albert,
the program to perform a simplified open loop engine control function using the demonstration board provided. This software will simulate ECU operation for a single cylinder, four stroke gasoline injection engine assumed to be operating between 600 and 5825 RPM.
The software should use the “Toothed Wheel simulator” output pulse stream to provide interrupts every 3° of crank rotation
The pulse train will be fed through to RB2 or RB7

#### AlbertHall

Joined Jun 4, 2014
12,187
Is the 'toothed wheel simulator' an actual circuit of some sort sending pulses to the PIC?
And is the speed of this simulated wheel going to be varied by something external to the PIC?

#### Don Omar

Joined May 5, 2017
49
as you can see from the pickit the pic16f84 is used for the actual tooth wheel simulator and its already been programmed
also the second photo show how we change the RPM using the switch setting

#### Attachments

• 74.6 KB Views: 9
• 135.8 KB Views: 9

#### AlbertHall

Joined Jun 4, 2014
12,187
So if the switches are set for a simulated 600RPM what will be the timing of the waveform being fed to the PIC?
Width of the generated pulses?
Width of the gaps between the pulses?
How many pulses before a pulse is missed?

This is my poor representation of a pulse train where the missing pulse is. Which part of this is 120° btdc - the last negative edge before the gap or the first positive edge after the gap?
/\/\_/\/\

#### Don Omar

Joined May 5, 2017
49
60 tooth with 2 consecutive teeth missing
this the what i supposed to do in order to find the missing pulse
1. Measure the length of the high part of the pulse using a timer. This timer value which will, of course, vary slightly from pulse to pulse, then becomes our basic unit of time which represents 3° of crank angle.

2. Wait for the next high pulse to start (ie the next rising edge on RB2) OR wait for 1.5 time units whichever happens soonest.

3. If we have proceeded from step 2 because we have exceeded 1.5 units then we have found the missing pulse. If we have not exceeded 1.5 units then go back to step 1.

#### Don Omar

Joined May 5, 2017
49
please have look at the waveform

#### Attachments

• 10.2 KB Views: 5

#### AlbertHall

Joined Jun 4, 2014
12,187
So TDC is 1.5 units (4.5°) after the last falling edge of the waveform?

#### Don Omar

Joined May 5, 2017
49
So TDC is 1.5 units (4.5°) after the last falling edge of the waveform?
Yeah.

Last edited by a moderator:

#### Don Omar

Joined May 5, 2017
49
@AlbertHall
Please could you help me with it im stuck
Thanks

#### AlbertHall

Joined Jun 4, 2014
12,187
I will have a go at this tomorrow morning. It is not trivial.

#### AlbertHall

Joined Jun 4, 2014
12,187
You don't give the timing of the fuel injector pulse relative to TDC so the following ignores that part of the problem but I think the following will give you more than enough to get going on.

This is the description of the loop the program should go through:

Use ADC to read timing pot. Scale this value to 0 to 31 range. This number is TIMING.

Using interrupt on change (IOC) and a timer, time pulses from the toothed wheel until the widths of two consecutive pulses are within 10%. This width is WHEEL.

On each negative edge start a timer which will overflow in 1.5 * WHEEL. On each positive edge stop the timer.

When the timer overflows we have reached 120 degrees BTDC.

Now count toothed wheel pulse edges (both positive and negative edges) until (36-3)+TIMING edges have occured.

Wait half the WHEEL time.

Set firing pulse output high
Wait 2mS
Set firing pulse low

Start again from the top

#### AlbertHall

Joined Jun 4, 2014
12,187
I noticed an error in my previous post. The number '36' in it is 36 degrees but it should be converted into toothed wheel edges. Each edge represents 3 degrees so the number to use is 12.
Corrected version:

Use ADC to read timing pot. Scale this value to 0 to 31 range. This number is TIMING.

Using interrupt on change (IOC) and a timer, time pulses from the toothed wheel until the widths of two consecutive pulses are within 10%. This width is WHEEL.

On each negative edge start a timer which will overflow in 1.5 * WHEEL. On each positive edge stop the timer.

When the timer overflows we have reached 120 degrees BTDC.

Now count toothed wheel pulse edges (both positive and negative edges) until (12-3)+TIMING edges have occured.

Wait half the WHEEL time.

Set firing pulse output high
Wait 2mS
Set firing pulse low

Start again from the top