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

Shadow in the S6A0069 16x2 LCD

 
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

Shadow in the S6A0069 16x2 LCD
PostPosted: Thu Jul 11, 2013 6:10 pm     Reply with quote

Hi Everyone!

I could not fix the "shadow" that appears when any variable value changes in the blue LCD (S6A0069). Sliding texts is even worse.

In the image below you can see the back shadow in purple when changing from 850Rpm to 900Rpm.



It might be related to currently LCD update rate that I'm using (100ms), but the strange part is that I had no issue with the hd44780 controller by usuing the same update rate! Video (Sorry only in portuguese) available at http://www.youtube.com/watch?v=mJWwJaoi9q0

I've already tried the post below,( but did not work too...)
http://ccsinfo.com/forum/viewtopic.php?t=25961&highlight=&sid=862da1013c12444a90c72d7eb2fd61ca

CCS Version is 4.114, full code is below.

Any help from the experts would be really appreciated!

Thanks in advance!
Hugo

Code:

#include <18f4550.h>           
#device ADC=10               
#use delay (clock=48000000)   
#include <flex_lcd.h>       
#fuses HS, NOWDT, NOPROTECT, NOBROWNOUT, NOLVP, PUT // configura fuses
#include <usb_bootloader.h>
#priority INT_TIMER1, INT_EXT, INT_TIMER0

//Input Pin Map
#Define RPM_PULSE             PIN_B0  //Tachometer Pulse - Pulso do Conta Giros
#Define FUEL_PULSE            PIN_B1  //Carburetor Fuel Flow Pulse - Pulso medidor de gasolina
#Define SPEED_PULSE           PIN_B2  //Speed Sensor pulse - Pulsos Sensor de velocidade
#Define HAND_BREAK_ACTIVE     PIN_B3  //Hand Break On Lamp - Lâmpada Freio de mão puxado
#Define 4X4_LOCK_ON           PIN_B4  //4wd Lock active - Bloquêio diferencial central ligado
#Define BRAKE_OIL_LAMP        PIN_B5  //Brake system oil monitoring - Lâmpada reservatório óleo de freio
#Define LEFT_DOOR_OPEN        PIN_B6  //Left door open - Porta esquerda aberta
#Define RIGHT_DOOR_OPEN       PIN_B7  //Right door open - Porta direita aberta
#Define ENTER                 PIN_C0  //Enter Button - Botão de Enter
#Define UP                    PIN_C1  //Up Button - Botão Seta p/ cima
#Define DOWN                  PIN_C2  //Down Button - Botão Seta p/ baixo
#Define BAT_VOLTAGE_LEVEL     PIN_A0  //AN_00 12V battery level - Tensão da bateria
#Define FUEL_LEVEL            PIN_A1  //AN_01 Fuel tank level - Nível do combustível
#Define OIL_PRESSURE          PIN_A2  //AN_02 Engine Oil Pressure - Pressão do óleo do motor
#Define ENGINE_TEMP           PIN_A3  //AN_03 Engine Temperature - Temperatura do Motor
#Define ENGINE_WATER_TEMP     PIN_A5  //AN_04 Engine Water Temperature - Temperatura da água do motor
#Define ALTERNATOR_CURRENT    PIN_E0  //AN_05 Alternator´s current - Corrente do Alternador
#Define CAR_LOAD_CURRENT      PIN_E1  //AN_06 Car´s load current - Corrente da carga instalada
#Define AIR_TEMPERATURE       PIN_E2  //AN_07 Internal Air Temperature - Temperatura do Ar Interna

//Output Pin Map
#Define USB_5V                PIN_A4  //5Volts Supply to USB Port - Tomada 5v para porta usb
#Define RELAY_01              PIN_C6  //Relay #01 - Relê 01
#Define RELAY_02              PIN_C7  //Relay #02 - Relê 02
#Define BUZZER                PIN_D0  //Enter Button - Botão de Enter
#Define LAMP_SHIFT_LIGHT      PIN_D1  //Up Button - Botão Seta p/ cima
// =============================================================
//  Shift Text to Left and display it on LCD - Corre texto para esquerda e mostra no display
// =============================================================
Char*text00="                             ";  // Global Variable Text 00 - Variavel Global Texto 00
void Shift_Info_Text()
  {
  static int i=0;
      for ( i=0 ; i<30 ; i++ )
      {
      if (i==0) Text00[29]=Text00[i];
      else Text00[i-1]=Text00[i];   
      }
  }
// *****************************************************
// =============================================================
//  Clock Logic - Lógica do Relógio
// =============================================================
unsigned int S, M, H;            // Global variable clock variables - variáveis globais do relógio
Char colon=':';                  // Global variable colon - variável global dois pontos do relógio
int1 Clock_Adjustment_Active=0;  // Global variable clock adjustment active - variáveis global ajuste do relogio ativo
void Clock()
  {
  static int i=0;
    IF (Clock_Adjustment_Active==0) {   
            S++;
            IF (S>=60) {
                  S=0;
                  M++;
                  IF (M>=60)  {
                     M=0;
                     H++;
                     IF (H>=24) H=0;
                              }
                       }
       }
  }
// *****************************************************
// =============================================================
// Printf to LCD Display - Imprime informações no Display LCD
// =============================================================
unsigned int Active_Screen_Nr=0;          // Global Variable Active Screen Number - Variavel Global Numero da Tela Ativa
Unsigned int16 EngineTemp=0,EngineTemp_Av=0,OilPressure=0,OilPressure_Av=0,WaterTemp=0,WaterTemp_Av=0,AirTemp=0,AirTemp_Av_temp=0,AirTemp_Av=0; // Global Variable Analog Inputs - Variaveis Globlais entradas analógicas
Unsigned int16 BatVoltage=0,BatVoltage_Av=0;       // Global Variable Analog Inputs - Variaveis Globlais entradas analógicas
Unsigned int8 FuelTankLevel=0,FuelTankLevel_Av=0;  // Global Variable Analog Inputs - Variaveis Globlais entradas analógicas
Unsigned int16 AlternatorCurrent=0,AlternatorCurrent_Av=0,LoadCurrent=0,LoadCurrent_Av=0;
Unsigned long RPM=0, Speed=0, Trip=0, Ins_consumption=0, Avg_consumption=0, test=0;                             // Global Variable RPM Display - Variavel Global RPM
Char*Info="          ";                   // Global Variable Function Information  - Variavel Global Texto da Função
Char *BarGraph="                                        ";

void LCD_Display()
  {
    Switch(Active_Screen_Nr)
    {                                     
    case 1 : lcd_load_custom_chars(1), printf(LCD_PUTC,"\f%3.1w\003\001\005 %3LD Km/h\n%02u%c%02u\002\004 %4LD Rpm",AirTemp_Av,Speed,H,colon,M,RPM); break;                                                //LCD Display SPEED/RPM
    case 2 : lcd_load_custom_chars(2), printf(LCD_PUTC,"\f%3.1w\003\001 \004 %2D Lts \n%02u%c%02u\002Aut.:%3LDKm",AirTemp_Av,FuelTankLevel_Av,H,colon,M,Trip); break;                                      //LCD Display FUEL TANK LEVEL/KMS TO EMPTY
    case 3 : lcd_load_custom_chars(3), printf(LCD_PUTC,"\f%3.1w\003\001\004 %3.1w L/h\n%02u%c%02u\002\005 %3.1w L/h",AirTemp_Av,Ins_consumption,H,colon,M,Avg_consumption); break;                         //LCD Display INSTANTANEOUS CONSUMPTION/AVERAGE CONSUPMTION
    case 4 : lcd_load_custom_chars(4), printf(LCD_PUTC,"\f%3.1w\003\001Ar/Combust\n%02u%c%02u\002%c%c%c%c%c%c%c%c%c%c",AirTemp_Av,H,colon,M,BarGraph[0],BarGraph[1],BarGraph[2],BarGraph[3],BarGraph[4],BarGraph[5],BarGraph[6],BarGraph[7],BarGraph[8],BarGraph[9]); break; //OXIGEN SENSOR                                                                //LCD Display AIR/FUEL Mixture
    case 5 : lcd_load_custom_chars(5), printf(LCD_PUTC,"\f%3.1w\003\001\004 M.%3.1w\003\n%02u%c%02u\002\004 A.%3.1w\003",AirTemp_Av,EngineTemp_Av,H,colon,M,WaterTemp_Av); break;                          //LCD Display ENGINE TEMPERATURE/WATER TEMPERATURE
    case 6 : lcd_load_custom_chars(6), printf(LCD_PUTC,"\f%3.1w\003\001\004 %3.1w Vdc\n%02u%c%02u\002\005%2LDA  \006%2LDA",AirTemp_Av,BatVoltage_Av,H,colon,M,LoadCurrent_Av,AlternatorCurrent_Av); break; //LCD Display BATTERY LEVEL/CAR CURRENT LOAD & ALTERNATOR CURRENT
    }
  }
// *****************************************************
// =============================================================
// "Interrupcao Timer0"
// =============================================================
Float Actual_Value_Tmr0=0.0;  // Global variable that contains tmr0 accumulated timer - variável global com tempo atual do Timer 0
#INT_TIMER0             // Definition that next line will be associated to Timer0 interrupt - linha que define que a próxima função será associada à interrupção do TIMER0
void timer0()           // Function called automaticaly  - esta função não precisará ser chamada. Será executada automaticamente.
  {
         Actual_Value_Tmr0=Actual_Value_Tmr0+1.39810133333333; //1.39810133333333=Tempo Total para overflow to contator (TMR0 16bits) = (Tempo de cada incremento * 65536)
  }
// *************************************************************
// =============================================================
// "Interrupcao Timer1", executada a cada 10ms
// =============================================================
int1 Pulse_50ms=0;      // Global variable - variável global com pulso de clock de 50ms
int1 Pulse_100ms=0;     // Global variable - variável global com pulso de clock de 100ms
int1 Pulse_200ms=0;     // Global variable - variável global com pulso de clock de 200ms
int1 Pulse_500ms=0;     // Global variable - variável global com pulso de clock de 500ms
int1 Pulse_1000ms=0;    // Global variable - variável global com pulso de clock de 1000ms
#INT_TIMER1             // Definition that next line will be associated to Timer1 interrupt - linha que define que a próxima função será associada à interrupção do TIMER1
void timer1()           // Function called automaticaly every 100ms - esta função não precisará ser chamada. Será executada automaticamente.
  {
  static int8 Counter50=0;
  static int8 Counter100=0;
  static int8 Counter500=0;
 
      set_timer1(50536 + get_timer1()); //Pulso de clock de 100ms @ 48 MHz
         
//50ms Clock generator - Gerador de Pulso de 50ms
    Counter50++;
       if (Counter50==5) Pulse_50ms=!Pulse_50ms, Counter50=0;     
//100ms&200ms Clock generator - Gerador de Pulso de 100ms
    Counter100++;
       if (Counter100==10) Pulse_100ms=1;
       if (Counter100==20)
       {
       Pulse_200ms=!Pulse_200ms;
       Pulse_100ms=0;
       Counter100=0;
            if ((Clock_Adjustment_Active==0)&&(Active_Screen_Nr>6)) Shift_Info_Text(); //call Shift Text routine if: 1-) Not Clock Setup Active and 2-) Info Text Cmd Active
       }
//500ms&1s Clock generator - Gerador de Pulso de 500ms
    Counter500++;
       if (Counter500==50) Pulse_500ms=1, colon=':';
       if (Counter500==100)
       {
       Pulse_1000ms=!Pulse_1000ms;
       Pulse_500ms=0;
       Counter500=0;
       colon=' ';
            if (Clock_Adjustment_Active==0) Clock();
       }
 }
// *************************************************************
// =============================================================
// "Interrupcao Timer2", executada a cada
// =============================================================
//#INT_TIMER2             // Definition that next line will be associated to Timer2 interrupt - linha que define que a próxima função será associada à interrupção do TIMER2
//void timer2()           // Function called automaticaly every 100ms - esta função não precisará ser chamada. Será executada automaticamente.
//  {
//       output_toggle(PIN_C0);   
//  }
// *************************************************************
// =============================================================
// "External Interrupt Pin_B0", Interrupção Externa Pino B0
// =============================================================
Float TimeCount_Total=0.0;
Float Pulse_Lenght[10]={0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
#INT_EXT                     // Definition that next line will be associated to External interrupt - linha que define que a próxima função será associada à interrupção externa
void ext_isr(void)           // Function called automaticaly @ Pin_B0 rise edge detection - função executada automaticamente a cada detecção de borda de subida no pino B0.
  {   
      Static Signed int i=0;
       
         TimeCount_Total=Actual_Value_Tmr0+(get_timer0()*0.0000213333333333333); //0.0000213333333333333=Tempo de "cada" Incremento do contador Timer0 (Período) = 1/((F.Oscilador/4) / Prescaler)
         set_timer0(0);       //Clear Actual "Counter" Timer0
         Actual_Value_Tmr0=0; //Clear Actual "Time" Timer0
         
         Pulse_Lenght[i]=TimeCount_Total;
         i++;
         If (i>=10) i=0;
         clear_interrupt(INT_EXT);
  }
// *************************************************************
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 50ms - Gera pulso na borda de subida do clock de 50ms
// =============================================================
int1 Edge_50ms;  //Global variable - Variável global pulso 50ms (Borda de subida)
void Function_Edge_50ms() //Function declaration - Declaração da função
{
static int1 aux50;     //Auxiliar Variable - Variável local usada para intertravamento
   if (Pulse_50ms) //If pulse is true - Se Pulso está Ligado
      { 
         if (aux50==0) Edge_50ms=1; else Edge_50ms=0; //and aux50 is false then Edge_50ms=TRUE for only one scan - e aux50 em Zero, Pulso de Subida vai pra 1
         aux50=1; //Next scan Edge_50ms will be false - Coloca variavel auxiliar em 1 que vai zerar borda de subida no próximo scan
      }
      else aux50=0; //Clear aux50 till next rising edge detection - Espera por novo pulso
}
// *************************************************************
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 100ms - Gera pulso na borda de subida do clock de 100ms
// =============================================================
int1 Edge_100ms;  //Global variable - Variável global pulso 100ms (Borda de subida)
void Function_Edge_100ms() //Function declaration - Declaração da função
{
static int1 aux100; //Auxiliar Variable - Variável local usada para intertravamento
   if (Pulse_100ms) //If pulse is true - Se Pulso está Ligado
      { 
         if (aux100==0) Edge_100ms=1; else Edge_100ms=0; //and aux100 is false then Edge_100ms=TRUE for only one scan - e aux100 em Zero, Pulso de Subida vai pra 1
         aux100=1; //Next scan Edge_100ms will be false - Coloca variavel auxiliar em 1 que vai zerar borda de subida no próximo scan
      }
      else aux100=0; //Clear aux100 till next rising edge detection - Espera por novo pulso
}
// *************************************************************
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 200ms - Gera pulso na borda de subida do clock de 200ms
// =============================================================
int1 Edge_200ms;  //Global variable - Variável global pulso 200ms (Borda de subida)
void Function_Edge_200ms() //Function declaration - Declaração da função
{
static int1 aux200; //Auxiliar Variable - Variável local usada para intertravamento
   if (Pulse_200ms) //If pulse is true - Se Pulso está Ligado
      { 
         if (aux200==0) Edge_200ms=1; else Edge_200ms=0; //and aux200 is false then Edge_200ms=TRUE for only one scan - e aux200 em Zero, Pulso de Subida vai pra 1
         aux200=1; //Next scan Edge_200ms will be false - Coloca variavel auxiliar em 1 que vai zerar borda de subida no próximo scan
      }
      else aux200=0; //Clear aux200 till next rising edge detection - Espera por novo pulso
}
// *************************************************************
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 500ms - Gera pulso na borda de subida do clock de 500ms
// =============================================================
int1 Edge_500ms;  //Global variable - Variável global pulso 500ms (Borda de subida)
void Function_Edge_500ms() //Function declaration - Declaração da função
{
static int1 aux500; //Auxiliar Variable - Variável local usada para intertravamento
   if (Pulse_500ms) //If pulse is true - Se Pulso está Ligado
      { 
         if (aux500==0) Edge_500ms=1; else Edge_500ms=0; //and aux500 is false then Edge_500ms=TRUE for only one scan - e aux500 em Zero, Pulso de Subida vai pra 1
         aux500=1; //Next scan Edge_500ms will be false - Coloca variavel auxiliar em 1 que vai zerar borda de subida no próximo scan
      }
      else aux500=0; //Clear aux500 till next rising edge detection - Espera por novo pulso
}
// *************************************************************
// =============================================================
// "One Shot Rising, OSR", Generates rising edge pulse every 1000ms - Gera pulso na borda de subida do clock de 1000ms
// =============================================================
int1 Edge_1000ms;  //Global variable - Variável global pulso 1000ms (Borda de subida)
void Function_Edge_1000ms() //Function declaration - Declaração da função
{
static int1 aux1000; //Auxiliar Variable - Variável local usada para intertravamento
   if (Pulse_1000ms) //If pulse is true - Se Pulso está Ligado
      { 
         if (aux1000==0) Edge_1000ms=1; else Edge_1000ms=0; //and aux1000 is false then Edge_1000ms=TRUE for only one scan - e aux1000 em Zero, Pulso de Subida vai pra 1
         aux1000=1; //Next scan Edge_1000ms will be false - Coloca variavel auxiliar em 1 que vai zerar borda de subida no próximo scan
      }
      else aux1000=0; //Clear aux500 till next rising edge detection - Espera por novo pulso
}
// *************************************************************
// =============================================================
// "Timer ON Delay", Temporizador com retardo para ativar (em milisegundos)
// TON.SP = Setpoint
// TON.PV = Timer counter value - Tempo atual
// TON.Q  = Timer output - Sáida do Temporizador 1= Setpoint atingido
// TON.R  = Reset - Zera temporizador
// =============================================================
 const int8 TimerArray=2;
Typedef Struct {
   int8 SP;   
   int8 PV;       
   int8 Q;
   int8 R;
   int8 EN;
}  TON_Struct;

 TON_Struct TON[TimerArray]={{0,0,0,0,0},{0,0,0,0,0}}; //Timer array declaration - define a quantidade de temporizadores que poderão ser usadas no programa
   
void Timer(int8 IN_TON_Nr,int8 IN_SP) //Timer Function  - Declaração da função
  {     
  static int8 temp[TimerArray];       
  static int8 Edge_EN[TimerArray];     
//------------------------------------ //TON[X].EN=1 ->Generates Edge Rising pulse for Reset Timer 
   if (TON[IN_TON_Nr].EN) { 
         if (temp[IN_TON_Nr]==0) Edge_EN[IN_TON_Nr]=1; else Edge_EN[IN_TON_Nr]=0; 
         temp[IN_TON_Nr]=1;
      }
      else temp[IN_TON_Nr]=0;
//-----------------------------------

         TON[IN_TON_Nr].SP=IN_SP; // Initializes .SP according called Timer - Copia Setpoint do TON chamadado
   
            if (TON[IN_TON_Nr].PV>=TON[IN_TON_Nr].SP) TON[IN_TON_Nr].Q=1, TON[IN_TON_Nr].EN=0; // If .PV reaches .SP, Output .Q is True - Se Contador >= Setpoint seta saída "Q"
            if ((Edge_50ms)&&(TON[IN_TON_Nr].EN)&&(TON[IN_TON_Nr].PV<TON[IN_TON_Nr].SP)) TON[IN_TON_Nr].PV=(TON[IN_TON_Nr].PV+1); // Increment counter every 100ms - Inicia contagem de tempo, incrementa a cada 100ms
            if ((TON[IN_TON_Nr].R)||(Edge_EN[IN_TON_Nr])) TON[IN_TON_Nr].PV=0, TON[IN_TON_Nr].Q=0, TON[IN_TON_Nr].R=0; //If .R is True, Clear Timer - Reseta e Zera variáveis do contador quando TON[x].R=1
  }
// *************************************************************
// =============================================================
// Scale Function - Função de Escalonamento
// =============================================================
Float Scale(float In_Min_A,float In_Max_A,float In_Min_B,float In_Max_B,float In_Process_input) //Scale Function  - Declaração da função de escalonamento
  {     
  static float Dif_A, Dif_B, Razao;       
 
  //Difference A
  Dif_A=In_Max_A-In_Min_A;
  //Difference B
  Dif_B=In_Max_B-In_Min_B;
  //Difference A / Difference B
  Razao=Dif_A/Dif_B;
  //Out_Scaled_value
  return(((In_Process_input/Razao)+(In_Min_B*2))-((In_Min_A/Razao)+In_Min_B)); 
  }
// *************************************************************
// =============================================================
// Average Function - Função de Cálculo de Média
// =============================================================
/*
const int8 AvArrayLenght=8;
Typedef Struct {
   int16 Temp[10];   
}  Average_Struct;

 Average_Struct Av_Calc[AvArrayLenght]={{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0}}; //array initialization
Float Average(int8 AvCalcNr,float Analog_IN) //Scale Function  - Declaração da função de escalonamento
  {     
  static unsigned int i[AvArrayLenght], j;   
  static float Av_Value_temp[AvArrayLenght],Av_Value[AvArrayLenght];
  j=i[AvCalcNr];
 
  if (Edge_100ms)
     {
         Av_Calc[AvCalcNr].Temp[j]=Analog_IN;
         Av_Value_temp[AvCalcNr]+=Av_Calc[AvCalcNr].Temp[j];
            if (j==9)
            {
            Av_Value[AvCalcNr]=Av_Value_temp[AvCalcNr]/10;
            Av_Value_temp[AvCalcNr]=0;
            }
         j++;
         If (j>=10) j=0;
     }
  i[AvCalcNr]=j;
  return(Av_Value[AvCalcNr]); 
  }
// *************************************************************
*/
// =============================================================
// Average Function - Função de Cálculo de Média NEW
// =============================================================
const int8 AvArrayLenght=8;
Float Average(int8 AvCalcNr,float Analog_IN,int8 NrOfSamples) //Scale Function  - Declaração da função de escalonamento
  {     
  static unsigned int i[AvArrayLenght], j=0;
  static float Av_Value_temp[AvArrayLenght],Av_Value[AvArrayLenght];
  j=i[AvCalcNr];
 
  //if (Edge_100ms)
   //  {
         Av_Value_temp[AvCalcNr]+=Analog_IN;;
            if (j==(NrOfSamples-1))
            {
            Av_Value[AvCalcNr]=Av_Value_temp[AvCalcNr]/NrOfSamples;
            Av_Value_temp[AvCalcNr]=0;
            }
         j++;
         If (j>=NrOfSamples) j=0;
   //  }
  i[AvCalcNr]=j;
  return(Av_Value[AvCalcNr]);
  }
// *************************************************************
// =============================================================
// Round Function - Função de arredondamento
// =============================================================
Long Round(int16 In_var) //Round Function  - Declaração da função de arredondamento
  { 
  static unsigned int VAR_Digit[4],i=0; 
  static unsigned int16 temp=0, Result=0;
  temp=In_var;

            for ( i=0 ; i<4 ; i++ )
            {
               VAR_Digit[i] = temp%10 ;
               temp /= 10 ;
            }
 
   IF (VAR_Digit[0]>5) VAR_Digit[0]=10; else VAR_Digit[0]=0; //Round last Variable digit either to Zero or Ten
   Result=(((long)VAR_Digit[3]*1000)+((long)VAR_Digit[2]*100)+(VAR_Digit[1]*10)+VAR_Digit[0]);
   
   return(Result);
  }
// *************************************************************
// =============================================================
// A/D Function - Função de leitura A/D
// =============================================================
Long Read_AD(int Channel)
  {
  Static Long Analog_Value;
  Switch(Channel)
    {
    case 0 : input(BAT_VOLTAGE_LEVEL), setup_adc_ports(AN0); break;
    case 1 : input(FUEL_LEVEL), setup_adc_ports(AN0_TO_AN1); break;
    case 2 : input(OIL_PRESSURE), setup_adc_ports(AN0_TO_AN2); break;
    case 3 : input(ENGINE_TEMP), setup_adc_ports(AN0_TO_AN3); break;
    case 4 : input(ENGINE_WATER_TEMP), setup_adc_ports(AN0_TO_AN4); break;
    case 5 : input(ALTERNATOR_CURRENT), setup_adc_ports(AN0_TO_AN5); break;
    case 6 : input(CAR_LOAD_CURRENT), setup_adc_ports(AN0_TO_AN6); break;
    case 7 : input(AIR_TEMPERATURE), setup_adc_ports(AN0_TO_AN7); break;
    //case 8 : input(PIN_B2), setup_adc_ports(AN0_TO_AN8); break;
    //case 9 : input(PIN_B3), setup_adc_ports(AN0_TO_AN9); break;
    //case 10 : input(PIN_B1), setup_adc_ports(AN0_TO_AN10); break;
    //case 11 : input(PIN_B4), setup_adc_ports(AN0_TO_AN11); break;
    //case 12 : input(PIN_B0), setup_adc_ports(ALL_ANALOG); break;
    default: return(0);
    }
  set_adc_channel(channel);
  delay_us(50);
  Analog_Value = read_adc();
  setup_adc_ports(NO_ANALOGS);
  return(Analog_Value);
  }
// *************************************************************
void main()
 {
//Variables - Declaração das variáveis
   signed long ADC_0,ADC_1,ADC_2,ADC_3,ADC_4,ADC_5,ADC_6,ADC_7, counter=0,temp2=0; // signed long 
   float Average_Pulse_Lenght=0;
   unsigned int i, Setup_mode=2, Hold_exit_stup=0, shift_counter=0, Count_EN_Random=0; //RPM_Digit[4]
   int1 Display_Shifted_Info=0,Start_Info_Shif=0,Edge_Add_Active_Text_Nr=0, Random_Display_Mode_Active=0;
   int1 aux1=0,aux2=0,aux3=0,aux4=0,Edge_Adjust=0,Edge_Select=0,Edge_Beep_ON=0;
   //fuel tank
   unsigned int8  FuelTank_Mem[50], FuelTank_Mem_Count[50],Moda=0,FuelTank_Moda=0,FuelTankLevel_Av2=0;  //FuelTank_Mem_Av[6]
   //unsigned int16 FuelTank_Moda_Av=0; 
   unsigned int8  k=0,n=0; //a=0
   
   Char pbar="\004";
   Char ibar="\005";
   Char rbar="\006";
   Char blank="\007";
   
   Char*text01="       1 Consumo Instantaneo ";
   Char*text02="       2 >> Consumo Medio << ";
   Char*text03="       3 Nivel Do Combustivel";
   Char*text04="       4 Rotacoes Por Minuto ";
   Char*text05="       5 Temperatura Do Motor";
   Char*text06="       6 Temperatura Da Agua ";
   Char*text07="       7 Tensao Da Bateria ++";

// Initialize 16x2 LCD Display- inicializa display LCD 16x2
   lcd_init();
//Configure Timer0 - Configura Timer0
   setup_timer_0 (T0_INTERNAL | T0_DIV_256 ); //Configures timer0 - Configura o timer1 para clock interno e prescaler dividindo por 256
   enable_interrupts(INT_TIMER0);
//Configure Timer1 - Configura Timer1
   setup_timer_1 (T1_INTERNAL | T1_DIV_BY_8); //Configures timer1 - Configura o timer1 para clock interno e prescaler dividindo por 8
   enable_interrupts(INT_TIMER1); //Enable Timer1 interrupt - Habilita a interrupção do timer1
//Configure Timer2 - Configura Timer2
          //     (1/20000000)*4*1*24 =  004.8 us or 208333,33 Hz
          //     (1/20000000)*4*4*254 = 204.0 us or   4901,96 Hz
          //     (1/20000000)*4*16*254= 816.0 us or   1225,49 Hz
//   setup_ccp1(CCP_PWM);                 // Configure CCP1 as a PWM
//   setup_timer_2(T2_DIV_BY_16, 254, 1); //Configures timer2 for PWM - Configura o timer2 para CCP1 como PWM
//   enable_interrupts(INT_TIMER2);       //Enable Timer2 interrupt - Habilita a interrupção do timer2
//   set_pwm1_duty(ADC_2);                // This sets the time of the pulse (deve ser chamado no main loop)
//Configure External Interrupt - Configura Interrupção externa no pino B0 
   ext_int_edge(H_TO_L);        // ext_int_edge(1,H_TO_L) p/ External Int. #1
   clear_interrupt(INT_EXT);    // clear_interrupt(INT_EXT1) p/ External Int. #1
   enable_interrupts(INT_EXT);  // enable_interrupts(INT_EXT1) p/ External Int. #1
//Set AD for Internal Clock - Configura o AD para clock interno
   setup_adc(ADC_CLOCK_INTERNAL);
//Set GIE&PEIE bits and Enable all interrupts - Habilita todas as interrupções 
   enable_interrupts(GLOBAL);

//Initialize Text00 Array
 for (i=0;i<=29;++i) Text00[i]=Text01[i];
//Initialize TON'S 
 TON[0].EN=1;
 
//Read eeprom
FuelTankLevel_Av=read_eeprom(1);  //Lê eeprom, nivel do tanque
AirTemp_Av=(read_eeprom(2)*2);    //Lê eeprom, temperatura ar
S=read_eeprom(40);  //Lê eeprom, SEGUNDOS
M=read_eeprom(41);  //Lê eeprom, MINUTOS
H=read_eeprom(42);  //Lê eeprom, HORAS

//Initialize Fuel Tank Level Mem. Average Array
// for (i=0;i<=6;++i) FuelTank_Mem_Av[i]=FuelTankLevel_Av;
   
// =============================================================
// Clock Adjustment - Ajuste do Relógio
// =============================================================
      if (input(ENTER)==0)
      {
      delay_ms(10);      //debouncing time
      Clock_Adjustment_Active=1;
      }
      do {
          Function_Edge_50ms(); //Call Edge 50ms Function
       
       //Adjust Edge Bit
          if (input(UP)==1)
            { 
             delay_ms(20);          //debouncing time
               if (aux1==0) Edge_Adjust=1; else Edge_Adjust=0;
               aux1=1;
            }
       else aux1=0, Edge_Adjust=0; //Hold=0
       
       //Setup mode Edge bit
                 if (input(ENTER)==0)
            { 
               delay_ms(20);         //debouncing time
               if (aux2==0) Edge_Select=1; else Edge_Select=0;
               aux2=1;
            }
       else aux2=0, Edge_Select=0;
       
       //Setup Mode: 0: Adjust Seconds , 1: Adjust Minutes, 2: Adjust Hours
            if (Edge_Select) {
             Setup_mode++;
             if (Setup_mode>2) Setup_mode=0;
            }
           
            //Adjust Seconds
               if (Setup_mode==0) {
               if (Edge_Adjust) S++;
               IF (S>=60) S=0;
               }
            //Adjust Minutes
               if (Setup_mode==1) {
               if (Edge_Adjust) M++;
               IF (M>=60) M=0;
               }
            //Adjust Hours
               if (Setup_mode==2) {
               if (Edge_Adjust) H++;
               IF (H>=24) H=0;
               }       
               // Display current setup mode
                     If (Setup_mode==0) {if (Edge_50ms) printf(LCD_PUTC,"\f->Ajustar Seg.\n%02u%c%02u%c%02u ",H,':',M,':',S);}
                     If (Setup_mode==1) {if (Edge_50ms) printf(LCD_PUTC,"\f->Ajustar Min.\n%02u%c%02u%c%02u ",H,':',M,':',S);}
                     If (Setup_mode==2) {if (Edge_50ms) printf(LCD_PUTC,"\f->Ajustar Hora\n%02u%c%02u%c%02u ",H,':',M,':',S);}
                     
                     //exit setup function
                           if (input(ENTER)==0)
                           {   
                             delay_ms(10);     //debouncing time
                              if (Edge_50ms) {
                              Hold_exit_stup++;
                              if (Hold_exit_stup>=20) Clock_Adjustment_Active=0,Count_EN_Random=21, printf(LCD_PUTC,"\f    RELOGIO     \n   AJUSTADO!!   "), delay_ms(1500);   //Exit setut and enable clock
                              }
                           } else Hold_exit_stup=0;
                       
                    } While (Clock_Adjustment_Active==1);               
// *************************************************************
// =============================================================
// Welcome Msg
// =============================================================
 printf(LCD_PUTC,"\f    Sistema     \n -------------- ");
 delay_ms(800);
 printf(LCD_PUTC,"\f   Interativo   \n -------------- ");
 delay_ms(800);
 printf(LCD_PUTC,"\f de Informacoes \n -------------- ");
 delay_ms(800);
 printf(LCD_PUTC,"\f   LADA NIVA    \n -------------- ");
 delay_ms(1200);
 printf(LCD_PUTC,"\f By Hugo Silva  \nNIVA GalinhaReia");
 delay_ms(2000);
// *************************************************************
 while(1)
   {
//Function Call - Chamadas das funções
//------------------------------------------------------
   Function_Edge_50ms(); 
   Function_Edge_100ms();
   Function_Edge_200ms();
   Function_Edge_500ms();
   Function_Edge_1000ms();
   if (Edge_100ms) LCD_Display();
// *****************************************************
       
//Enable or Disable Ramdom Display mode
//------------------------------------------------------
       if (input(ENTER)==0)
                           {   
                             delay_ms(10);     //debouncing time
                              if (Edge_50ms) {
                              Count_EN_Random++;
                              if (Count_EN_Random==20) {
                              Random_Display_Mode_Active=!Random_Display_Mode_Active;
                                    if (Random_Display_Mode_Active==1){
                                      printf(LCD_PUTC,"\f MODO ALEATORIO \n    LIGADO!!    ");
                                          output_high(BUZZER);
                                          delay_ms(300);
                                          output_low(BUZZER);
                                    }
                                    else
                                    {
                                      printf(LCD_PUTC,"\f MODO ALEATORIO \n   DESLIGADO!   ");
                                      Active_Screen_Nr--; //Because after releasing ENTER, Active_Text_Nr will be incremented
                                          output_high(BUZZER);
                                          delay_ms(300);
                                          output_low(BUZZER);
                                          delay_ms(90);
                                          output_high(BUZZER);
                                          delay_ms(300);
                                          output_low(BUZZER);
                                    }
                              delay_ms(1500);
                              TON[0].EN=1;
                              //Active_Screen_Nr--; //Because after releasing ENTER, Active_Text_Nr will be incremented
                              }
                              }
                           } else Count_EN_Random=0; 
// *****************************************************
 
//Add Active_Text_Nr (Random Mode Enabled)
//------------------------------------------------------
          if (((TON[1].Q==1)&&(Random_Display_Mode_Active==1))||((input(ENTER)==1)&&(Random_Display_Mode_Active==0))){
               if (aux3==0) Active_Screen_Nr++, Edge_Add_Active_Text_Nr=1; else Edge_Add_Active_Text_Nr=0;
               aux3=1;
               If (Active_Screen_Nr>6) Active_Screen_Nr=1;
            }
       else aux3=0;
   
    if (Edge_Add_Active_Text_Nr) {
    If (Active_Screen_Nr==1) for (i=0;i<=29;++i) Text00[i]=Text01[i];
    If (Active_Screen_Nr==2) for (i=0;i<=29;++i) Text00[i]=Text02[i];
    If (Active_Screen_Nr==3) for (i=0;i<=29;++i) Text00[i]=Text03[i];
    If (Active_Screen_Nr==4) for (i=0;i<=29;++i) Text00[i]=Text04[i];
    If (Active_Screen_Nr==5) for (i=0;i<=29;++i) Text00[i]=Text05[i];
    If (Active_Screen_Nr==6) for (i=0;i<=29;++i) Text00[i]=Text06[i];
    shift_counter=0;
    }
// *****************************************************

// Shift Text to Left and display it on LCD - Corre texto para esquerda e mostra no display
//------------------------------------------------------
 if ((Edge_50ms)&&(input(ENTER)==1))
    {
    Info[0]=Text00[0];
    Info[1]=Text00[1];
    Info[2]=Text00[2];
    Info[3]=Text00[3];
    Info[4]=Text00[4];
    Info[5]=Text00[5];
    Info[6]=Text00[6];
    Info[7]=Text00[7];
    Info[8]=Text00[8];
    Info[9]='\0';
    }
// ***************************************************** 
// Custom Clock Pulse for automatic screen change (Generates 100ms pulse clock every 5,3s)
//------------------------------------------------------
      Timer(0,53); // Timer(#,Setpoint x 100ms) -> Timer 0 Declaration with 5,3s of setpoint
         if (TON[0].Q) TON[1].EN=1;  //TON[1].EN=1 ->Enable, Reset and Start Timer
      Timer(1,1);  // Timer(#,Setpoint x 100ms) -> Timer 1 Declaration with 100ms of setpoint
         if (TON[1].Q) TON[0].EN=1;  //TON[0].EN=1 ->Enable, Reset and Start Timer
// *****************************************************

//Calculates RPM Average Value - Calcula Média do RPM para mostrar no Display
//------------------------------------------------------
    Average_Pulse_Lenght=(Pulse_Lenght[0]+Pulse_Lenght[1]+Pulse_Lenght[2]+Pulse_Lenght[3]+Pulse_Lenght[4]+Pulse_Lenght[5]+Pulse_Lenght[6]+Pulse_Lenght[7]+Pulse_Lenght[8]+Pulse_Lenght[9])/10.0;
    temp2=((1.0/Average_Pulse_Lenght)/2.0)*60.0;
    RPM=Round(temp2);
/*
            for ( i=0 ; i<4 ; i++ )
            {
               RPM_Digit[i] = temp2%10 ;
               temp2 /= 10 ;
            }
 
   IF (RPM_Digit[0]>5) RPM_Digit[0]=10; else RPM_Digit[0]=0; //Round last RPM digit either to Zero or Ten
   RPM=(((long)RPM_Digit[3]*1000)+((long)RPM_Digit[2]*100)+(RPM_Digit[1]*10)+RPM_Digit[0]);
 */   
// *****************************************************

//Read all analog inputs
//------------------------------------------------------
    //Analog input 00
    If (Active_Screen_Nr==6)
     {
         If (Edge_50ms) { ADC_0=Read_AD(0);                 // Read AD Channel - Le Canal AD
            BatVoltage=Scale(0,1023,0,158, ADC_0);          // Out_Scaled_Value=(IN_Min,IN_Max,OUT_Min,OUT_Max,IN_Input_Value)  15,637v=5v NO RES. 4K7
            BatVoltage_Av=Average(0,BatVoltage,5);          // Display calculated average value
        }           
     }
     else  //Still processing in Background at lower scan rate
     {
         If (Edge_1000ms) { ADC_0=Read_AD(0);                 // Read AD Channel - Le Canal AD
            BatVoltage=Scale(0,1023,0,158, ADC_0);            // Out_Scaled_Value=(IN_Min,IN_Max,OUT_Min,OUT_Max,IN_Input_Value)  15,637v=5v NO RES. 4K7
            BatVoltage_Av=Average(0,BatVoltage,5);            // Display calculated average value
         }
     }
     
    //Analog input 01
         If (Edge_100ms) { ADC_1=Read_AD(1);                // Read AD Channel - Le Canal AD
            if (ADC_1>487) ADC_1=487;
            if (ADC_1<80) ADC_1=80;
            FuelTankLevel=Scale(487,80,0,42, ADC_1);        // Out_Scaled_Value=(IN_Min,IN_Max,OUT_Min,OUT_Max,IN_Input_Value)
            FuelTankLevel_Av2=Average(1,FuelTankLevel,5);   // Display calculated average value
         }
   
    If (Edge_500ms)
      {
        if (k<50)  //Array of 50 samples of fuel tank level
        {
           FuelTank_Mem[k]=FuelTankLevel_Av2;    //FuelTankLevel
           k++;         //increment k
        }
      }
        if (k>=50) //if k reachs last position
           {
       
            if (n<50)  //check all stored samples looking for value repeatability
            {
               for ( i=0 ; i<50 ; i++ )  //check all stored samples looking for value repeatability
               {
                  if (FuelTank_Mem[i]==FuelTank_Mem[n]) FuelTank_Mem_Count[n]++ ; //add position counter every repeated value
               }
            }
               n++;
               if (n>=50)
                     {
                        for ( i=0 ; i<50 ; i++ )
                           {  //loop to identify which position had more values repeated
                              //if (Moda<FuelTank_Mem_Count[i]) Moda=FuelTank_Mem_Count[i],FuelTank_Moda=FuelTank_Mem[i];  //Memorize the fuel tank level of the position found above;
                              if (Moda<FuelTank_Mem_Count[i]) Moda=FuelTank_Mem_Count[i],FuelTankLevel_Av=FuelTank_Mem[i];
                           }
                              /*
                              //-----------------------------------------------------------------------
                              FuelTank_Mem_Av[a]=FuelTank_Moda;   //Array to Calculate Fuel Tank Mem Average
                                      a++;                             
                                            for (i=0;i<6;++i) FuelTank_Moda_Av+=FuelTank_Mem_Av[i];
                                            FuelTankLevel_Av=FuelTank_Moda_Av/6;
                                            FuelTank_Moda_Av=0;
                                                 if (a>=6) a=0;
                              //------------------------------------------------------------------------
                              */
                                    for ( i=0 ; i<50 ; i++ ) FuelTank_Mem_Count[i]=0,FuelTank_Mem[i]=0; //Clear all variables, re-start over again                                               
                                    k=0,n=0,Moda=0;     //clear k,n and Moda
                     }
            }
    Trip=5*FuelTankLevel_Av;
    test=ADC_1;
   
    //Analog input 02
    If (Active_Screen_Nr==4)
      {
         If (Edge_50ms) { ADC_2=Read_AD(4);                 // Read AD Channel every 50ms - Le Canal AD a cada 50ms
             OilPressure=Scale(4,203.6,0,10, ADC_2);        // Out_Scaled_Value=(IN_Min,IN_Max,OUT_Min,OUT_Max,IN_Input_Value)   
           //OilPressure_Av=Average(2,OilPressure,2);
        }
    //Bargraph to indicate Oxigen sensor level
      if (OilPress ure>0) BarGraph[0]=pbar; else BarGraph[0]=".";
      if (OilPressure>1) BarGraph[1]=pbar; else BarGraph[1]=".";
      if (OilPressure>2) BarGraph[2]=pbar; else BarGraph[2]=".";
      if (OilPressure>3) BarGraph[3]=ibar; else BarGraph[3]=blank;
      if (OilPressure>4) BarGraph[4]=ibar; else BarGraph[4]=blank;
      if (OilPressure>5) BarGraph[5]=ibar; else BarGraph[5]=blank;
      if (OilPressure>6) BarGraph[6]=ibar; else BarGraph[6]=blank;
      if (OilPressure>7) BarGraph[7]=rbar; else BarGraph[7]=".";
      if (OilPressure>8) BarGraph[8]=rbar; else BarGraph[8]=".";
      if (OilPressure>9) BarGraph[9]=rbar; else BarGraph[9]=".";
     }
     
    //Analog input 03
    If (Active_Screen_Nr==5)
      {
         If (Edge_100ms) { ADC_3=Read_AD(3);              // Read AD Channel - Le Canal AD
         if ((ADC_3>785)||(ADC_3<0)) ADC_3=785;
         EngineTemp=Scale(785,630,500,900, ADC_3);        // Out_Scaled_Value=(IN_Min,IN_Max,OUT_Min,OUT_Max,IN_Input_Value)   7.5V=0Deg(3,75V) 6.1V=90Deg(3,05v) 10K E 10K
         EngineTemp_Av=Average(3,Engine_Temp,30);         // Display calculated average value
         }
      }
      else  //Still processing in Background at lower scan rate
      {
         If (Edge_1000ms) { ADC_3=Read_AD(3);              // Read AD Channel - Le Canal AD 
         if ((ADC_3>785)||(ADC_3<0)) ADC_3=785;
         EngineTemp=Scale(785,630,500,900, ADC_3);        // Out_Scaled_Value=(IN_Min,IN_Max,OUT_Min,OUT_Max,IN_Input_Value)   7.5V=0Deg(3,75V) 6.1V=90Deg(3,05v) 10K E 10K
         EngineTemp_Av=Average(3,Engine_Temp,30);         // Display calculated average value
         }
      }
       
    //Analog input 04
    If (Active_Screen_Nr==5)
      {
         If (Edge_100ms) { ADC_4=Read_AD(4);             // Read AD Channel - Le Canal AD
         WaterTemp=Scale(0,307.2,0,1500, ADC_4);         // Out_Scaled_Value=(IN_Min,IN_Max,OUT_Min,OUT_Max,IN_Input_Value)   
         WaterTemp_Av=Average(4,WaterTemp,30);           // Display calculated average value
         }
      }
      else  //Still processing in Background at lower scan rate
      {
         If (Edge_1000ms) { ADC_4=Read_AD(4);            // Read AD - Le Canal AD
         WaterTemp=Scale(0,307.2,0,1500, ADC_4);         // Out_Scaled_Value=(IN_Min,IN_Max,OUT_Min,OUT_Max,IN_Input_Value)   
         WaterTemp_Av=Average(4,WaterTemp,30);           // Display calculated average value
         }
      }
   
    //Analog input 05
    If (Active_Screen_Nr==6)
      {
         If (Edge_100ms) { ADC_5=Read_AD(5);                    // Read AD Channel - Le Canal AD
         AlternatorCurrent=Scale(0,1005,-50,50, ADC_5);        // Out_Scaled_Value=(IN_Min,IN_Max,OUT_Min,OUT_Max,IN_Input_Value)
         AlternatorCurrent_Av=Average(5,AlternatorCurrent,15); // Display calculated average value                         
         }
      }
      else  //Still processing in Background at lower scan rate
      {
         If (Edge_1000ms) { ADC_5=Read_AD(5);                  // Read AD Channel - Le Canal AD
         AlternatorCurrent=Scale(0,1005,-50,50, ADC_5);        // Out_Scaled_Value=(IN_Min,IN_Max,OUT_Min,OUT_Max,IN_Input_Value)
         AlternatorCurrent_Av=Average(5,AlternatorCurrent,15); // Display calculated average value                           
         }
      }
   
    //Analog input 06
    If (Active_Screen_Nr==6)
      {
         If (Edge_100ms) { ADC_6=Read_AD(6);             // Read AD Channel - Le Canal AD
         LoadCurrent=Scale(0,1005,-50,50, ADC_6);       // Out_Scaled_Value=(IN_Min,IN_Max,OUT_Min,OUT_Max,IN_Input_Value)
         LoadCurrent_Av=Average(6,LoadCurrent,15);      // Display calculated average value 
         }
      }
      else  //Still processing in Background at lower scan rate
      {
         If (Edge_1000ms) { ADC_6=Read_AD(6);           // Read AD Channel - Le Canal AD
         LoadCurrent=Scale(0,1005,-50,50, ADC_6);       // Out_Scaled_Value=(IN_Min,IN_Max,OUT_Min,OUT_Max,IN_Input_Value)
         LoadCurrent_Av=Average(6,LoadCurrent,15);      // Display calculated average value 
         }
      }
   
    //Analog input 07
         If (Edge_100ms) { ADC_7=Read_AD(7);            //Read AD Channel - Le Canal AD
         AirTemp=Scale(0,307.2,0,1500, ADC_7);          // Out_Scaled_Value=(IN_Min,IN_Max,OUT_Min,OUT_Max,IN_Input_Value)
         AirTemp_Av_temp=Average(7,AirTemp,30);
        }     
            If (AirTemp_Av_temp>0) AirTemp_Av=AirTemp_Av_temp;
     
// *****************************************************   
       
//Beep Sound when ENTER pressed - Som do Bip quando Enter Pressionado
// *****************************************************
         if (input(ENTER)==1)
            { 
              delay_ms(10);          //debouncing time
               if (aux4==0) Edge_Beep_ON=1;
               aux4=1;
            }
       else aux4=0, Edge_Beep_ON=0, TON[2].R=1;

            if (Edge_Beep_ON==1) {
            output_high(BUZZER);
            delay_ms(20);
            output_low(BUZZER);
            Edge_Beep_ON=0;
            }
       
//------------------------------------------------------

//Write eeprom
//------------------------------------------------------
if  (Edge_1000ms) {
write_eeprom(1, FuelTankLevel_Av);  //Grava na eeprom, nível do tanque
write_eeprom(2, (AirTemp_Av/2));    //Grava na eeprom, temperatura do ar
write_eeprom(40, S);  //Grava na eeprom, SEGUNDOS
write_eeprom(41, M);  //Grava na eeprom, MINUTOS
write_eeprom(42, H);  //Grava na eeprom, HORAS
}
// *****************************************************
   
    If (TON[0].Q) output_high(LAMP_SHIFT_LIGHT); ELSE output_low(LAMP_SHIFT_LIGHT);
    If (input(DOWN)==0) output_high(USB_5V); ELSE output_low(USB_5V);
   
   }
 }


_________________
Hugo Silva
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

Flex LCD Code
PostPosted: Thu Jul 11, 2013 6:17 pm     Reply with quote

Code:

// These pins are for the Microchip PicDem2-Plus board,
// which is what I used to test the driver.  Change these
// pins to fit your own board.

#define LCD_DB4   PIN_D5 // D5     D5
#define LCD_DB5   PIN_D4 // D4     D4
#define LCD_DB6   PIN_D3 // D3     D7
#define LCD_DB7   PIN_D2 // D2     D6

#define LCD_E     PIN_D6 // D6     C6
#define LCD_RS    PIN_D7 // D7     C7
//#define LCD_RW    PIN_D6

// If you only want a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.

//#define USE_LCD_RW   1     

//========================================

#define lcd_type 2        // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the 2nd line

void lcd_load_custom_chars(void);

int8 const LCD_INIT_STRING[4] =
{
 0x20 | (lcd_type << 2), // Func set: 4-bit, 2 lines, 5x8 dots
 0xc,                    // Display on
 1,                      // Clear display
 6                       // Increment cursor
 };


//-------------------------------------
void lcd_send_nibble(int8 nibble)
{
// Note:  !! converts an integer expression
// to a boolean (1 or 0).
 output_bit(LCD_DB4, !!(nibble & 1));
 output_bit(LCD_DB5, !!(nibble & 2));
 output_bit(LCD_DB6, !!(nibble & 4));   
 output_bit(LCD_DB7, !!(nibble & 8));   

 delay_cycles(1);
 output_high(LCD_E);
 delay_us(2);
 output_low(LCD_E);
}

//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine.  For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.     

#ifdef USE_LCD_RW
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3

retval = 0;

output_high(LCD_E);
delay_cycles(1);

retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);

output_low(LCD_E);

return(retval);   
}   
#endif

//---------------------------------------
// Read a byte from the LCD and return it.

#ifdef USE_LCD_RW
int8 lcd_read_byte(void)
{
int8 low;
int8 high;

output_high(LCD_RW);
delay_cycles(1);

high = lcd_read_nibble();

low = lcd_read_nibble();

return( (high<<4) | low);
}
#endif

//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);

#ifdef USE_LCD_RW
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60);
#endif

if(address)
   output_high(LCD_RS);
else
   output_low(LCD_RS);

 delay_cycles(1);

#ifdef USE_LCD_RW
output_low(LCD_RW);
delay_cycles(1);
#endif

output_low(LCD_E);

lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}

//----------------------------
void lcd_init(void)
{
int8 i;

output_low(LCD_RS);

#ifdef USE_LCD_RW
output_low(LCD_RW);
#endif

output_low(LCD_E);

delay_ms(15);

for(i=0 ;i < 3; i++)
   {
    lcd_send_nibble(0x03);
    delay_ms(5);
   }

lcd_send_nibble(0x02);

for(i=0; i < sizeof(LCD_INIT_STRING); i++)
   {
    lcd_send_byte(0, LCD_INIT_STRING[i]);

    // If the R/W signal is not used, then
    // the busy bit can't be polled.  One of
    // the init commands takes longer than
    // the hard-coded delay of 60 us, so in
    // that case, lets just do a 5 ms delay
    // after all four of them.
    #ifndef USE_LCD_RW
    delay_ms(5);
    #endif
   }
}

//----------------------------

void lcd_gotoxy(int8 x, int8 y)
{
int8 address;

if(y != 1)
   address = lcd_line_two;
else
   address=0;

address += x-1;
lcd_send_byte(0, 0x80 | address);
}

//-----------------------------
void lcd_putc(char c)
{
 switch(c)
   {
    case '\f':
      lcd_send_byte(0,1);
      delay_ms(2);
      break;
         
    case '\n':
       lcd_gotoxy(1,2);
       break;

    case '\b':
       lcd_send_byte(0,0x10);
       break;

    default:
       lcd_send_byte(1,c);
       break;
   }
}

//------------------------------
#ifdef USE_LCD_RW
char lcd_getc(int8 x, int8 y)
{
char value;

lcd_gotoxy(x,y);

// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7));

output_high(LCD_RS);
value = lcd_read_byte();
output_low(lcd_RS);

return(value);
}
#endif

//=============================================
// Special Character Function
// This table holds the data for the LCD custom chars.
// It can only hold a maximum of 8 custom characters.
//
// Octal numbers 000 to 007 must be used with the "escape"
// backslash to display a custom char with printf.
// The line below displays the degrees symbol with \002.
// The "F" is for Fahrenheit. The "%3d" displays the
// temperature. The \f clears the LCD before displaying
// anything.

// Display temperature on top line of LCD.   
// printf(lcd_putc, "\f    %3d \002F \n", temperature);

const int8 custom_chars_Screen_1[] =
{
// Char Number 0 -- Not Used
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000   // ........
// Char Number 1 -- Screen Position 1
0b00011011,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
// Char Number 2 -- Screen Position 2
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........ 
// Char Number 3 -- Degrees Celcius
0b00011000,  // ........
0b00011000,  // ........
0b00000111,  // ........
0b00000100,  // ........
0b00000100,  // ........
0b00000100,  // ........
0b00000111,  // ........
0b00000000,  // ........
// Char Number 4 -- RPM
0b00001110,  // ........
0b00010001,  // ........
0b00011001,  // ........
0b00010101,  // ........
0b00000010,  // ........
0b00000001,  // ........
0b00000001,  // ........
0b00000000,  // ........
// Char Number 5 -- Speed
0b00000001,  // ........
0b00000001,  // ........
0b00011111,  // ........
0b00000000,  // ........
0b00011110,  // ........
0b00000001,  // ........
0b00011110,  // ........
0b00000000   // ........
};
const int8 custom_chars_Screen_2[] =
{
// Char Number 0 -- Not Used
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000   // ........
// Char Number 1 -- Screen Position 1
0b00000100,  // ........
0b00000000,  // ........
0b00011011,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
// Char Number 2 -- Screen Position 2
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
// Char Number 3 -- Degrees Celcius
0b00011000,  // ........
0b00011000,  // ........
0b00000111,  // ........
0b00000100,  // ........
0b00000100,  // ........
0b00000100,  // ........
0b00000111,  // ........
0b00000000,  // ........
// Char Number 4 -- Fuel Icon
0b00011111,  // ........
0b00010001,  // ........
0b00010001,  // ........
0b00011111,  // ........
0b00001110,  // ........
0b00001110,  // ........
0b00011111,  // ........
0b00000000,  // ........
};
const int8 custom_chars_Screen_3[] =
{
// Char Number 0 -- Not Used
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000   // ........
// Char Number 1 -- Screen Position 1
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00011011,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
// Char Number 2 -- Screen Position 2
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
// Char Number 3 -- Degrees Celcius
0b00011000,  // ........
0b00011000,  // ........
0b00000111,  // ........
0b00000100,  // ........
0b00000100,  // ........
0b00000100,  // ........
0b00000111,  // ........
0b00000000,  // ........
// Char Number 4 -- Instantaneous Consumption
0b00000100,  // ........
0b00000100,  // ........
0b00001110,  // ........
0b00011111,  // ........
0b00011111,  // ........
0b00001110,  // ........
0b00000000,  // ........
0b00000000   // ........
// Char Number 5 -- Average Consumption
0b00000100,  // ........
0b00001110,  // ........
0b00010101,  // ........
0b00010101,  // ........
0b00010101,  // ........
0b00001110,  // ........
0b00000100,  // ........
0b00000000,  // ........
};
const int8 custom_chars_Screen_4[] =
{
// Char Number 0 -- Not Used
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000   // ........
// Char Number 1 -- Screen Position 1
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00011011,  // ........
0b00000000,  // ........
// Char Number 2 -- Screen Position 2
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
// Char Number 3 -- Degrees Celcius
0b00011000,  // ........
0b00011000,  // ........
0b00000111,  // ........
0b00000100,  // ........
0b00000100,  // ........
0b00000100,  // ........
0b00000111,  // ........
0b00000000,  // ........
// Char Number 4 -- P Icon with bar
0b00001110,  // ........
0b00001010,  // ........
0b00001110,  // ........
0b00001000,  // ........
0b00000000,  // ........
0b00011111,  // ........
0b00011111,  // ........
0b00000000,  // ........
// Char Number 5 -- I Icon with bar
0b00001110,  // ........
0b00000100,  // ........
0b00000100,  // ........
0b00001110,  // ........ 
0b00000000,  // ........
0b00011111,  // ........
0b00011111,  // ........
0b00000000,  // ........
// Char Number 6 -- R Icon with bar
0b00001100,  // ........
0b00001010,  // ........
0b00001100,  // ........
0b00001010,  // ........ 
0b00000000,  // ........
0b00011111,  // ........
0b00011111,  // ........
0b00000000,  // ........
// Char Number 7 -- Blank
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00001110,  // ........
0b00000000,  // ........
};
const int8 custom_chars_Screen_5[] =
{
// Char Number 0 -- Not Used
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000   // ........
// Char Number 1 -- Screen Position 1
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
// Char Number 2 -- Screen Position 2
0b00011011,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
// Char Number 3 -- Degrees Celcius
0b00011000,  // ........
0b00011000,  // ........
0b00000111,  // ........
0b00000100,  // ........
0b00000100,  // ........
0b00000100,  // ........
0b00000111,  // ........
0b00000000,  // ........
// Char Number 4 -- Temperature Icon
0b00000100,  // ........ 
0b00000110,  // ........ 
0b00000100,  // ........ 
0b00000110,  // ........
0b00000100,  // ........
0b00011111,  // ........
0b00010101,  // ........
0b00000000,  // ........
};
const int8 custom_chars_Screen_6[] =
{
// Char Number 0 -- Not Used
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000,  // ........
0b00000000   // ........
// Char Number 1 -- Screen Position 1
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
// Char Number 2 -- Screen Position 2
0b00000100,  // ........
0b00000000,  // ........
0b00011011,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
0b00000100,  // ........
0b00000000,  // ........
// Char Number 3 -- Degrees Celcius
0b00011000,  // ........
0b00011000,  // ........
0b00000111,  // ........
0b00000100,  // ........
0b00000100,  // ........
0b00000100,  // ........
0b00000111,  // ........
0b00000000,  // ........
// Char Number 4 -- Baterry
0b00011111,  // ...OOOOO
0b00011011,  // ...OO.OO
0b00010001,  // ...O...O
0b00011011,  // ...OO.OO
0b00011111,  // ...OOOOO
0b00010001,  // ...O...O
0b00011111,  // ...OOOOO
0b00000000,  // ........
// Char Number 5 -- Load Current
0b00010001,  // ........
0b00011111,  // ........
0b00010001,  // ........
0b00000000,  // ........
0b00010001,  // ........
0b00010001,  // ........
0b00011111,  // ........
0b00000000,  // ........
// Char Number 6 -- Alternator Current
0b00011111,  // ........
0b00010100,  // ........
0b00011111,  // ........
0b00000000,  // ........
0b00010001,  // ........
0b00010001,  // ........
0b00011111,  // ........
0b00000000,  // ........ 
};

void load_custom_chars(int8 Active_Screen_Nr)
{
int8 i;

// Set address counter pointing to CGRAM address 0.
lcd_send_byte(0, 0x40); 
 
// Load custom lcd character data into CGRAM.
// It can only hold a maximum of 8 custom characters.

Switch(Active_Screen_Nr)
    {                                     
    case 1 : for(i = 0; i < sizeof(custom_chars_Screen_1); i++) lcd_send_byte(1, custom_chars_Screen_1[i]); break;                                               
    case 2 : for(i = 0; i < sizeof(custom_chars_Screen_2); i++) lcd_send_byte(1, custom_chars_Screen_2[i]); break;                                   
    case 3 : for(i = 0; i < sizeof(custom_chars_Screen_3); i++) lcd_send_byte(1, custom_chars_Screen_3[i]); break;
    case 4 : for(i = 0; i < sizeof(custom_chars_Screen_4); i++) lcd_send_byte(1, custom_chars_Screen_4[i]); break;
    case 5 : for(i = 0; i < sizeof(custom_chars_Screen_5); i++) lcd_send_byte(1, custom_chars_Screen_5[i]); break;
    case 6 : for(i = 0; i < sizeof(custom_chars_Screen_6); i++) lcd_send_byte(1, custom_chars_Screen_6[i]); break;
    }
   
// Set address counter pointing back to the DDRAM.
lcd_send_byte(0, 0x80);
}
void lcd_load_custom_chars(int8 Actual_screen)
{
static int8 Actual_screen_mem=0;
static int1 Actual_screen_edge=0;

if (Actual_screen!=Actual_screen_mem) load_custom_chars(Actual_screen);
Actual_screen_mem=Actual_screen;
}


_________________
Hugo Silva
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jul 11, 2013 9:14 pm     Reply with quote

Code:
Char*text00="                             "; 

The line above doesn't make an array. It makes a pointer. If you want
an array, you need to declare it. Example:
Code:
char text00[30];


There are several places in your program with false "arrays" like this.
You need to fix all of them.
gpsmikey



Joined: 16 Nov 2010
Posts: 588
Location: Kirkland, WA

View user's profile Send private message

PostPosted: Thu Jul 11, 2013 10:20 pm     Reply with quote

Just a comment on the update rate - I don't think I would go less than 250 ms. Less than that and even if the display can handle it, your eyes typically can not deal with numbers changing that fast. 500ms would probably be even better. There are some things like rpm that are often better displayed with an analog type meter (either a real one or an led type bar graph). 499, 500, 502, 498, 503 all in less than a second generally will simply confuse your eyes (and brain).

mikey
_________________
mikey
-- you can't have too many gadgets or too much disk space !
old engineering saying: 1+1 = 3 for sufficiently large values of 1 or small values of 3
temtronic



Joined: 01 Jul 2010
Posts: 9226
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Jul 12, 2013 5:16 am     Reply with quote

Mikey's right about the update rate. consider an LCD clock. The colon between the hrs and min flashes at a 1hz rate( 1/2 sec on, 1/2 off).Any faster and it'd be 'blurry'.LCD DVMs typically update at 3 HZ.
Same holds true for digital tachs, 1-2 readings per second.
It's a case where faster is not better.

hth
jay
younder



Joined: 24 Jan 2013
Posts: 53
Location: Brazil

View user's profile Send private message

PostPosted: Sun Jul 21, 2013 3:05 pm     Reply with quote

Guys thanks for the replys, and I agree that 250ms should be fine in most of the applications... The point is that in that particular application I'd like to have the texts sliding in at least 200ms for a better and fast reading of the messages... and as you can see in the video (link above) it was working ok with 200ms update rate.... however after I've replaced to the new one I could not make it work again...Just do not know why or if it's related to the new controller S6A0069.
_________________
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