martes, 6 de marzo de 2012

Unidad de control de un motor de gasolina




La idea u objetivo del proyecto es controlar un motor de un automóvil, para después de ponerlo en funcionamiento,  poder controlar diferentes reacciones. Para ello hemos creado una CPU o Unidad de control que controle diferentes parámetros. También se conoce como centralita y su función es controlar varios parámetros para poder dar respuesta a las peticiones del usuario. El motor es de la marca OPEL, tiene 4 cilindros y en cada cilindro tiene un inyector y una bujía para poder crear la combustión  necesaria para su funcionamiento.
La CPU o Unidad de control debe controlar los siguientes parámetros:
  • Cantidad de masa de aire de entrada al motor en porcentajes (%0, %5, %25, %50, %75, %100).
  • Tiempo de inyección de gasolina en milisegundos (de 0ms a 16ms).
  • Angulo de avance del salto de chispa respecto al PMS (Punto muerto superior) y PMI (Punto muerto inferior). También conocido como ángulo Dwell.
Para poder controla todos estos parametros tendremos una señal situada en el motor.
Esta señal nos la proporcionara un sensor inductivo situado en el bolante motor. Interpretando esta señal y conociendo los diferentes parámetros debemos dar respuesta a las peticiones del usuario.







Tiempo de inyeccion y angulo Dwell
(Alimentacion, etapa de control y etapa de potencia)

Medidor de masa de aire
(Etapa de control )

(Etapa de potencia; puente en H)



PROGRAMA
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*********************************************************************
*********************************************************************
                 AUTOAREN CPU OPEL 2000 16v
                 MOTOREAN PROBATZEKO BERTSIOA                      
********************************************************************

OPEL: Sensor Inductivo: 57+1 Dientes=58 flanko positibo

                                                    Tiempo inyeccion+Angulo Dwell
      
*********************************************************************/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <16F877.H>  //16F877 PIC-a erabiliko dugu Inyekzioa eta txispa kontrolatzeko
#device ADC=10       //Bihurgailu analogiko/digitalak 10 byte edukiko ditu//1024
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4M) //4MHz-tako kristal harria
#use RS232(baud=19200, xmit=PIN_C6, rcv=PIN_C7,DISABLE_INTS)//Serie Portua
#include <math.h>                                           //19200Abiadura//Pin C6 datuak bidaltzeko
                                                            //Disable_Ints Etendurak desabilitatzen ditu RS232 Serie Portutik                    datuak bidaltzerakoan
int1 k=0;         //RPM-ak kalkulatzeko agindua
float t1=0;       //Hortzen arteko oraingo denbora
float t2=0;       //Hortzen arteko aurreko denbora
int8 kont_dient=0;  //Bira batean hortz kopurua
float aux_rpm=0;  //Abiadura RPM-tan    
int16 rpm;        //Abiadura RPM-tan
int16 t_grado;    //Gradu bat igarotzeko behar den denbora 
int16 pot_iny;    //Inyekzio denbora; Potentziometroa balio digitala
int16 pot_av;     //Angulo Avance; Potentziometroa balio digitala
int16 VDmax=1024; //Balio digital maximoa;ADC=10(byte) bada->1024/ADC=8(byte) bada->255
int8 Tmax=17;     //Inyekzio denbora maximoa
int8 T=0;         //Inyekzio denbora
int8 Gmax=43;     //Gradu maximoa ez errealak;24 gradu negatibo+18 gradu positibo=42 gradu guztira
int8 G=0;         //Graduak ez errealak; 0 gradutik 43 gradu arte
signed int8 Gr=0; //Gradu errealak; Gradu ez errealak-24 
float a=0;        //Hortzetik hortzera dagoen denbora segunduetan, hau da t1-etik t2-ra dagoen denbora
float b=0;        //1 bira zenbat segundu diren kalkulatzeko;1 bira = 360º = 58 flanko positibo = 60 hortz
int8 i;
char bidali[7];   //Portu serietik bidaltzeko datuak;
                  //rpm (2 digitu)/angelu (zeinua + 2 digitu)/inyekzio (2 digitu)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/********************************************************************
   Interrupcion TIMER 2 Etendura 
   Inyekzioa mozteko erabiliko dugu
********************************************************************/
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#int_timer2
void tiempo2(void)
{
   output_low(PIN_C2);  //Inyektorea itzali
   output_low(PIN_C3);  //Inyektorea itzali
   disable_interrupts(INT_TIMER2);   //Timer 2 Etendura desaktibatu
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**********************************************************************
   Kampoko Etendura PIN_B0
   Birak kontatzeko erabiliko dugu
***********************************************************************/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#int_ext
void birak(void)
{  
   t1=get_timer1(); //2 hortzen harteko denbora hartu//get timer-aren bidez momentuan timerraren akumulagailuan dagoen balioa artuko du
   set_timer1(0);  //Timer1 Hasieratu, momentu honetan timer-a kontatzen hasiko da
   if((t1>1.5*t2)||(kont_dient>=58))    //Oraingo denbora, aurreko denbora baino andiagoa bada
   {                                   //PMS -ean dagoela esan nahi du beraz kontaketa hasi
      kont_dient=1;     
   }
   else
   {
      kont_dient ++; //Kont_dient inkrementatu
      if((kont_dient==5)||(kont_dient==34)) //Gasolina inyektatu
      {
         output_high(PIN_C2); //Inyectar
         output_high(PIN_C3); //Inyectar
         setup_timer_2 ( T2_DIV_BY_16,pot_iny/4,4 ); //Timer 2 konfiguratu//Inkrementu bakoitzak 16uS,potentziometroaren bidez kargatu behar dugun balioa artuko du.
         set_timer2(0); //Timer2 Hasieratu//etendura abilitatu bezahin laster asiko da kontaketa gainezka egin arte, timer-ak gainezka egitean etendurara joango da eta inyektoreak itzali egingo ditu
         enable_interrupts(INT_TIMER2);   //Timer 2 Etendura aktibatu
      }
      if(kont_dient==10)    //RPM-ak kalkulatzeko
      {
         k=1;        
      }
   }         
   t2=t1; //Oraingo denbora aurreko bezala gorde
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**********************************************************************
   Funtzio Nagusia
**********************************************************************/
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void main(void)
   delay_ms(2000);
   
   setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_1 );  //Timer 1 konfiguratu//Inkrementu bakoitzak 1uS
   set_timer1(0);  //Timer1 Hasieratu 
   //setup_timer_0 ( RTCC_INTERNAL | RTCC_DIV_64 );   //Timer 0//0-16,320ms//Inkrementu bakoitzak 64uS
   //set_rtcc(0); //Timer0 hasieratu
   setup_timer_2 ( T2_DIV_BY_16,0xff,4 );   //Timer 2 konfiguratu//Inkrementu bakoitzak 16uS
   set_timer2(0); //Timer2 Hasieratu
   
   enable_interrupts(INT_TIMER2);   //Timer 2 Etendura aktibatu
   enable_interrupts(GLOBAL);       //Etendura guztiak aktibatu
   
   enable_interrupts(INT_EXT); //Kampoko etendura aktibatu B0 portua, B0 portuan kanpoko seinale bat jasotzean programa nagusia utzi eta programa zati zehatz batetara joaten da
   ext_int_edge(H_TO_L);      //Kampoko etendura aktibatu LtoH(goranzko flankoa), hau da 0v-tik 5v-rako aldaketa somatzen duenean exekutatzen hari den programa utzi eta int_ext etendurara joango da bertan dauden aginduak exekutatzeko     
   
   setup_adc_ports(AN0_AN1_AN3);      //PIN A0,A1 eta A3 Analogiko bezala konfiguratu, hau da pin hauetan balio analogiko bat sartuko dugu eta pic-ak balio hau digital bihurtuko du//ADC=10 bada 10 byteraino hau da 1024 arteko balio tartea// ADC=8 bada 8 byterain, hau da 255 arteko balio tartea.
   setup_adc(adc_clock_internal);    //CAD Konfiguratu
                    
   while(1)
   {
      //RPM//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      if(k==1)
      {
         a=((t1/1000.0)/1000.0); //Hortzetik hortzera dagoen denbora microsegundutatik segundutara pasatu //3300uS = 0,0033s     
         b=a*58.0;       //1 bira zenbat segundu diren kalkulatzeko// Motorrean 58 hortz
         aux_rpm=60.0/b; //Bira kopurua minutuko RPM    //60/0,2=300rpm
         rpm=aux_rpm;    //aux_rpm:float/rpm:int16
         k=0;            //RPM-ak kalkulatzeko balioa 0-an jarri        
      }
      
      //TIEMPO INYECCION/////////////////////////////////////////////////////////////////////////////////////////////////////
      set_adc_channel(0);   //A0 kanala aktibatu
      delay_us(10);
      pot_iny=read_adc();   //A0-tik sartutako balioa irakurri
      T=pot_iny*Tmax/VDmax; //Inyekzio denbora milisegundutan 
            
      //ANGULO AVANCE////////////////////////////////////////////////////////////////////////////////////////////////////////
      set_adc_channel(1);   //A1 kanala aktibatu
      delay_us(10);
      pot_av=read_adc();    //A1-etik sartutako balioa irakurri 
      G=pot_av*Gmax/VDmax;  //Angulo avance gradutan
      Gr=G-24;

      //DATUAK EGOKITU///////////////////////////////////////////////////////////////////////////////////////////////////////
      bidali[0]=rpm/1000;   bidali[0]=bidali[0]+0x30;//RPM; Milakoak kalkulatu eta ASCII kodera pasa 
      bidali[1]=(rpm%1000)/100;  bidali[1]=bidali[1]+0x30;//RPM; Ehunekoak kalkulatu eta ASCII kodera pasa 

      if(Gr<0) //Angulo de Avance negatiboa
         bidali[2]='-';
      else     //Angulo de Avance positiboa
         bidali[2]='+';
      bidali[3]=fabs(Gr)/10;   bidali[3]=bidali[3]+0x30;//Angulo de Avance; Hamarrekoa kalkulatu eta ASCII kodera pasa
      bidali[4]=fabs(Gr)%10;   bidali[4]=bidali[4]+0x30;//Angulo de Avance; Batekoak kalkulatu eta ASCII kodera pasa

      bidali[5]=T/10;   bidali[5]=bidali[5]+0x30;//Inyekzioa: Hamarrekoak kalkulatu eta ASCII kodera pasa
      bidali[6]=T%10;   bidali[6]=bidali[6]+0x30;//Inyekzioa; Batekoak kalkulatu eta ASCII kodera pasa

      //PORTU SERIEA RS232////////////////////////////////////////////////////////////////////////////////////////////////////
      disable_interrupts(global);   //Etendurak desaktibatu
      putc('Z'); //Komunikazioa hasteko marka
      for(i=0;i<7;i++)
         putc(bidali[i]);  //Datuak bidali portu serietik
      enable_interrupts(global); //Etendurak aktibatu
     
     //BUJIAK////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      if((Gr<=18)&&(Gr>12))   //18º 
      {
         while(kont_dient!=3)
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu       
         } 
         output_low(PIN_C0); //Bujias 1-4 Deskargatu!!¡!¡!
         delay_us(500);
         while(kont_dient!=32)
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu        
         }
         output_low(PIN_C1); //Bujias 2-3 Deskargatu!!¡!¡!
         delay_us(500);        
      }
      else if((Gr<=12)&&(Gr>6))  //12º 
      {
         while(kont_dient!=2)
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu       
         } 
         output_low(PIN_C0); //Bujias 1-4 Deskargatu!!¡!¡!
         delay_us(500);
         while(kont_dient!=31)
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu       
         }
         output_low(PIN_C1); //Bujias 2-3 Deskargatu!!¡!¡!
         delay_us(500);
      }
      else if((Gr<=6)&&(Gr>0)) //6º 
      {
         while(kont_dient!=1) 
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu       
         } 
         output_low(PIN_C0); //Bujias 1-4 Deskargatu!!¡!¡!
         delay_us(500);
         while(kont_dient!=30)
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu       
         }
         output_low(PIN_C1); //Bujias 2-3 Deskargatu!!¡!¡!
         delay_us(500);
      }
      else if((Gr<=2)&&(Gr>=-2))    //0º
      {
         while(kont_dient!=58)//PMS//
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu       
         } 
         output_low(PIN_C0); //Bujias 1-4 Deskargatu!!¡!¡!
         delay_us(500);
         while(kont_dient!=29)//Erdia PMI//
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu        
         }
         output_low(PIN_C1); //Bujias 2-3 Deskargatu!!¡!¡!
         delay_us(500);
      } 
      else if((Gr<0)&&(Gr>=-6))  //-6º
      {
         while(kont_dient!=57)
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu       
         } 
         output_low(PIN_C0); //Bujias 1-4 Deskargatu!!¡!¡!
         delay_us(500);
         while(kont_dient!=28)
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu        
         }
         output_low(PIN_C1); //Bujias 2-3 Deskargatu!!¡!¡!
         delay_us(500);  
      }  
      else if((Gr<-6)&&(Gr>=-12))  //-12º
      {
         while(kont_dient!=56)
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu       
         } 
         output_low(PIN_C0); //Bujias 1-4 Deskargatu!!¡!¡!
         delay_us(500);
         while(kont_dient!=27)
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu       
         }
         output_low(PIN_C1); //Bujias 2-3 Deskargatu!!¡!¡!
         delay_us(500);   
      }
      else if((Gr<-12)&&(Gr>=-18))  //-18º
      {
         while(kont_dient!=55)
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu       
         } 
         output_low(PIN_C0); //Bujias 1-4 Deskargatu!!¡!¡!
         delay_us(500);
         while(kont_dient!=26)
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu       
         }
         output_low(PIN_C1); //Bujias 2-3 Deskargatu!!¡!¡!
         delay_us(500);   
      }
      else if((Gr<-18)&&(Gr>=-24))  //-24º
      {
         while(kont_dient!=54)
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu       
         } 
         output_low(PIN_C0); //Bujias 1-4 Deskargatu!!¡!¡!
         delay_us(500);
         while(kont_dient!=25)
         {
            output_high(PIN_C0); //Bujias 1-4 kargatu
            output_high(PIN_C1); //Bujias 2-3 kargatu       
         }
         output_low(PIN_C1); //Bujias 2-3 Deskargatu!!¡!¡!
         delay_us(500);      
      }     
   }  //While(1)bukaera
}  //main() bukaera   
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*********************************************************************
**********************************************************************
                 AUTOAREN CPU OPEL 2000 16v
                 MOTOREAN PROBATZEKO BERTSIOA
**********************************************************************        
LCD                
**********************************************************************/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <16F876.H>//16F876 PIC-a erabiliko dugu datuak jaso eta LCD-an pantailaratzeko
#fuses XT,NOWDT,NOPROTECT
#use delay(clock=4M)
#use RS232(baud=19200, xmit=PIN_C6, rcv=PIN_C7) //Portu seriea Pin C6 datuak jasotzeko
#include "LCD.c"  //LCD-a erabiltzeko Programa gehigarria

char datuak[7];//Portu serietik jasotako datuak gordetzeko
int8 i;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/***********************************************************************
   Funtzio Nagusia
************************************************************************/
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void main(void)
{  
   lcd_init();       //LCD Hasieratu
   
   lcd_gotoxy(6,1);   //Lehenengo lerroa,6.posizioa
   printf(lcd_putc,"RPM");
   lcd_gotoxy(4,2);  //Bigarren lerroa, 5.posizioa
   printf(lcd_putc,"ms");
   lcd_gotoxy(12,2);  //Bigarren lerroa, 11.posizioa
   printf(lcd_putc,"Gradu");
   while(1)
   {
      while(getc()!='Z');  //Itxaron datuak jasotzeko marka jaso arte
      for(i=0;i<7;i++)
         datuak[i]=getc(); //Portu serietik datuak jaso
      for(i=0;i<7;i++)
         write_eeprom(i,datuak[i]); //Eeprom memorian jasotako datuak gorde
        
      //LCD RPM///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
      lcd_gotoxy(1,1);                 //Lehenengo lerroa,1.posizioa   
      printf(lcd_putc,"%c",datuak[0]);    //RPM; Milakoak 
      printf(lcd_putc,"%c",datuak[1]);    //RPM; Ehunekoak
      printf(lcd_putc,"00");              //RPM; Hamarrekoak eta Batekoak   
               
      //LCD ANGULO AVANCE///////////////////////////////////////////////////////////////////////////////////////////
      lcd_gotoxy(8,2);                 //Bigarren lerroa,8.posizioa
      printf(lcd_putc,"%c",datuak[2]);    //Angulo Avance; Seinua +-
      printf(lcd_putc,"%c",datuak[3]);    //Angulo Avance; Hamarrekoa
      printf(lcd_putc,"%c",datuak[4]);    //Angulo Avance; Batekoa
       
      //LCD TIEMPO INYECCION///////////////////////////////////////////////////////////////////////////////////////
      lcd_gotoxy(1,2);                 //Bigarren lerroa, 1.posizioa
      printf(lcd_putc,"%c",datuak[5]);    //Inyekzioa; Hamarrekoa
      printf(lcd_putc,"%c",datuak[6]);    //Inyekzioa; Batekoa    
   }//while(1) bukara
}//main() bukaera
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////




/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*********************************************************************************************
                VDO  
Medidor masa de aire

**********************************************************************************************             
output_high(PIN_c3);//1
output_low(PIN_c4);//0
delay_ms(5000);
output_low(PIN_c3);//0
output_low(PIN_c4);//0
delay_ms(5000);
output_low(PIN_c3);//0
output_high(PIN_c4);//1
delay_ms(5000);
output_high(PIN_c3);//1
output_high(PIN_c4);//1
                               
***********************************************************************************************/
#include <16F876A.H>
#device ADC=10
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4M)

int16 a;
int1 b,c,d,e,f,g;

void main(void) 
{   
   setup_adc_ports(AN0);
   setup_adc(adc_clock_internal);
   set_adc_channel(0);
   
   while(1)
   {
      a=read_adc();
      
      b=input(PIN_B1);//0%
      c=input(PIN_B2);//punto muerto
      d=input(PIN_B3);//25%
      e=input(PIN_B4);//50%
      f=input(PIN_B5);//75%
      g=input(PIN_B6);//100%
   
      if(b==0)
      {
         output_low(PIN_c4);//guztiz itxi
         output_high(PIN_c3);  
      }
      else if(c==0)
      {
         output_high(PIN_c4);//jetsi baina motorrak lagunduta
         output_high(PIN_c3);//punto muerto  
      }
      else if(d==0)
      {
         if(a>637)//50%   380
         {
            output_high(PIN_c4);//Ireki
            output_low(PIN_c3);
         }
         else 
         {
            output_high(PIN_c3);//jetsi baina motorrak lagunduta
            output_high(PIN_c4);
         }   
      }
      else if(e==0)
      {
         if(a>515)//50%   380
         {
            output_high(PIN_c4);//Ireki
            output_low(PIN_c3);
         }
         else 
         {
            output_high(PIN_c3);//jetsi baina motorrak lagunduta
            output_high(PIN_c4);
         }   
      }
      else if(f==0)
      {
         if(a>392)//50%   380
         {
            output_high(PIN_c4);//Ireki
            output_low(PIN_c3);
         }
         else 
         {
            output_high(PIN_c3);//jetsi baina motorrak lagunduta
            output_high(PIN_c4);
         }   
      }
      else if(g==0)
      {
         if(a>392)//50%   380
         {
            output_high(PIN_c4);//Ireki
            output_low(PIN_c3);
         }   
      }
   }
}  
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

No hay comentarios:

Publicar un comentario