quinta-feira, 4 de janeiro de 2024

Frequencímetro com 2 canais usando o PIC16F887 e mostrando via serial RS232 (frequencímetro duplo)

     Olá neste primeiro projeto de 2024 vou colocar um exemplo de frequencímetro duplo para medir 2 frequências através dos CCP'S e enviar via seria, além de funções prontas para calculo da frequência e configuração do prescaler para cada faixa de frequência desejada.     

    Nos testes do simulador e no projeto físico funcionou muito bem e com muita precisão, um exemplo de simulação é visto na figura a seguir:


    Note que os leds são pra indicar que esta lendo pulsos nos pinos dos ccp's , como foi configurado para cada borda de subida logo terá a o valor de frequência menor. Para este foi colocado o mesmo sinal nos 2 canais para simular.

O código fonte :

/*
 *
 * Compilador : MPlabXC8
 * Microcontroladores compativeis : 16F886 e 887
 * Autor: Aguivone Moretti Fógia
 * Versão: 1.1.2
 * Data :  02/01/2024 - inicio de testes com oscilador interno (de 8MHZ) - 100 a 8000hz no simulador 
 * Data :  02/01/2024 - inicio de testes com oscilador interno (de 20MHZ) - 
 * descrição : Frequencimetro 
 * 
 */
#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
// se igual a 8MHZ:
/* #define _XTAL_FREQ 8000000
   #pragma config FOSC = INTRC_NOCLKOUT// Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
 */ 
// se igual a 20MHZ:
  #define _XTAL_FREQ 20000000
  #pragma config FOSC = HS        //  cristal de 20mhz
#include <xc.h>
/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////////

#pragma config WDTE  = OFF       // Watchdog Timer Enable bit (WDT habilitado)
#pragma config PWRTE = OFF       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP   = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD   = OFF         // Data EE Memory Code Protection bit (proteção da eeprom)
#pragma config CP    = OFF         // Flash Program Memory Code Protection bit (proteção do codigo)

///////////////defines utilizados///////////////////////////////////////////////////////////////////////////////////////////
//o pino R/W é conectado ao terra pois não é feita nenhuma leitura no display
//configuração:
//
// pino da porta selecionada / pino display
//
// C4 = pino de D4 do display
// C5 = pino de D5 do display
// C6 = pino de D6 do display
// C7 = pino de D7 do display
//
// C1 = pino de RS do display
// C2 = pino de EN do display
//
/*************************** configuração dos pinos **************************************************/
////////PINOS DO DISPLAY DE LCD ///////////////

//16F88
/*
 #define BIT_0              RB0
 #define BIT_1              RB1
 #define BIT_2              RB3
 #define BIT_3              RB4

 #define PIN_RS485          RA1 //pino de controle da rs485
 #define EN                 RA2
 #define RS                 RA3
///////// PINO DE SINALIZAÇÃO //////////////
#define  LED_STATUS         RA4
//////////PINOS DE ENTRADA  ///////////////
#define  BOT_FUNCAO         RB7
#define  BOT_SELECAO        RB6
#define  BOT_OK             RA6
*/
//16F887
#define  LED_STATUS         RB0
#define  LED_freq1          RB1
#define  LED_freq2          RB2

long periodo_anterior_1=0;
long periodo_anterior_2=0;
long periodo1=0;
long periodo2=0;
char  CCP1_mult,CCP2_mult;
float aux = 0;
float fator_de_div = 0;
void CCP_div_por(char CCP1_V,char CCP2_V)
{//valor da divisão do CCPs
    CCP1CON = 0X05;//captura a cada borda 
    CCP2CON = 0X05;//por padrao
    CCP1_mult = CCP1_V;
    if(CCP1_mult == 4)
    {
       CCP1CON = 0X06; 
    }
    if(CCP1_mult == 16)
    {
       CCP1CON = 0X07; 
    }
    CCP2_mult = CCP2_V;
    if(CCP2_mult == 4)
    {
       CCP2CON = 0X06; 
    }
    if(CCP2_mult == 16)
    {
       CCP2CON = 0X07; 
    } 
}
void prescaler_por(char prescaler)
{
    switch(prescaler)
    {
        case 1:///por 1
                fator_de_div =  _XTAL_FREQ/4;
                T1CON = 0X01;
        break;
        case 2: /// por 2
                fator_de_div =  _XTAL_FREQ/8;
                T1CON = 0X11;
        break;
        case 4: /// por 4
                fator_de_div =  _XTAL_FREQ/16;
                T1CON = 0X21;
        break;
        case 8:/// por 8
                fator_de_div =  _XTAL_FREQ/32;
                T1CON = 0X31;
        break;
    }
}
void interrupt interrupcoes(void)//vetor de interrupção
 {
        long periodo_atual_1  = CCPR1;//pega valores  depois vê se é pra tratar
        long periodo_atual_2  = CCPR2;        
        /*if(TMR1IF)
        { //não será usado aqui
            TMR1IF = 0;
        }*/
        if(CCP1IF)
        {
            CCP1IF = 0;//limpa flag de interrupção
                   if(periodo_atual_1> periodo_anterior_1)
                    {
                      periodo1 = periodo_atual_1 - periodo_anterior_1;
                    }
                    else
                    {
                      periodo1 = (65535 - periodo_anterior_1) + periodo_atual_1;
                    }             
            LED_freq1 = ~LED_freq1;
            periodo_anterior_1 = periodo_atual_1;    
            
        }
        if(CCP2IF)
        {
            CCP2IF = 0;//limpa flag de interrupção
                   if(periodo_atual_2> periodo_anterior_2)
                        {
                          periodo2 = periodo_atual_2 - periodo_anterior_2;
                        }
                        else
                        {
                          periodo2 = (65535 - periodo_anterior_2) + periodo_atual_2;
                        }             
            LED_freq2 = ~LED_freq2;
            periodo_anterior_2 = periodo_atual_2;
        }
        if(RCIF == 1)
        {//interrupção de recepção de dados
            char aux;
            //lembrar de por um timeout pra não ficar travado esperando dados
            RCIF = 0;//  limpa flag de interrupção de recepção
            aux = RCREG;  //deve ler para não trava o chip esperando tratar a interrupçao
            // não será utilizado aqui
        }
}
void imprime_rs232(char frase[],int tamanho)
{ //para conseguir imprimir em hexa sem problemas é melhor passar o tamanho do pacote
       int indice = 0;
       __delay_us(1);
       for(indice = 0;indice < tamanho;indice++)
       {
           while(TRMT==0);//espera enviar caracter, esvaziando o shift register , usando o trmt é mais garantido a entrega 
           TXREG = frase[indice];//no datasheet diz que ao carregar o TXREG limpa o bit TXIF           
           while(TRMT==0);
       }        
}
void inicializa_RS232(long velocidade,int modo,char pega_ref)
{////por padrão é usado o modo 8 bits e sem paridade, mas se necessario ajuste aqui a configuração desejada.
    //verifique datasheet para ver a porcentagem de erro e se a velocidade é possivel para o cristal utilizado.
    RCSTA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono.
    long valor;
        if(modo == 1)
        {//modo = 1 ,modo alta velocidade
         TXSTA = 0X24;//8bits/transmissão habilitado/modo assincrono/highspeed
         valor =(((_XTAL_FREQ/velocidade)-16)/16);//calculo do valor do gerador de baud rate -> 10_06_2022
        }
        else
        {//modo = 0 ,modo baixa velocidade
         TXSTA = 0X20;////8bits/transmissão habilitado/modo assincrono/lowspeed
         valor =(((_XTAL_FREQ/velocidade)-64)/64);//calculo do valor do gerador de baud rate
        }
    if(pega_ref == 0)
    {//valor calculado
       SPBRG =(int)valor; // veja a pagina 101 do datasheet já tem calculado para 8MHZ
    }
    else
    {//valor colocado diretamente
      SPBRG =(int)velocidade; //coloca valor direto baseado no data sheet  
    }
    RCIE = 1;//habilita interrupção de recepção
    PEIE =1;
    TXEN = 1; // habilita o modulo de transmisão
    TXIE = 0;//deixa interrupção de transmissão desligado(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo)
}
void long_to_char(long valor)
{
    char Buffer_serial_out[5]; //delimitador pra facilitar jogar no excel
    Buffer_serial_out[0]='0';
    Buffer_serial_out[1]='0';
    Buffer_serial_out[2]='0';
    Buffer_serial_out[3]='0';
    Buffer_serial_out[4]='0';
    if(valor < 65535)
    {
        while(valor>=10000)
             {
                 valor = valor - 10000;
                 Buffer_serial_out[0]++;
             }
        while(valor>=1000)
           {
               valor = valor - 1000;
               Buffer_serial_out[1]++;
           }
        while(valor>=100)
           {
               valor = valor - 100;
               Buffer_serial_out[2]++;
           }
        while(valor>=10)
           {
               valor = valor - 10;
               Buffer_serial_out[3]++;
           }
        while(valor>=1)
           {
               valor = valor - 1;
               Buffer_serial_out[4]++;
           }
        imprime_rs232(Buffer_serial_out ,5);
    }

}

//*******************************Rotina principal*********************************************/

void main(void)
{    
    TRISA = 0XF7;//configura portA  pino habilita rs    
    TRISB = 0X00;//configura portB
    TRISC = 0X06;//configura portC //tx é saida
    TRISD = 0X00;//configura portD  // somente no 16F887
    TRISE = 0XFF;//configura portD     
    PORTA = 0;
    PORTB = 0;//deixa pino tx em nivel alto
    PORTC = 0;
    PORTD = 0;// somente no 16F887 
    GIE = 0;//já desliga as interrrupções para terminar as configurações
    OPTION_REG = 0X80; // pull up desabilitados e prescaler para timer 0 - desabilita watchdog
    INTCON = 0;//desabilita todas as interrupções 
    //CMCON = 0X07;//desliga comparadores  no 16F887 é outro
    //---------------------------------------------------------
   // CCP1CON = 0X05;   //Capture mode, every rising edge
   // CCP2CON = 0X05;
     CCP_div_por(1,1);// modo do ccp dividido por 1,4 ou 16.
    //---------------------------------------------------------
    ANSEL = 0X00; //portas digitais e AN0 e AN1.
    ANSELH = 0X00; //portas digitais e AN8 e AN13.// 
    OSCTUNE = 0X1F;  // oscilador vel maxima(para que o baud rate tambem dê certo)
    // ----------------------------------------------------------------------------------------------------------
    // para oscilador interno de 8 mhz use :           
         // OSCCON = 0XFE ; // oscilador interno com frequencia de 8mhz ->16F88
       //  OSCCON = 0XF5 ; // oscilador interno com frequencia de 8mhz ->16F887         
     //----------------------------------------------------------------------------------------------------------    
    // para cristal de 20 Mhz use:   
     OSCCON = 0XFE; // oscilador de 20mhz
     //----------------------------------------------------------------------------------------------------------
    inicializa_RS232(19200,1,0);
    CCP1IE = 1;//habilita interrupçao de ccp
    CCP2IE = 1;//habilita interrupçao de ccp
   // T1CON=1;	//Timer on(para fazer as contagem)) qunado uas a afunção abaixo não precisa por este
    prescaler_por(1);
   // TMR1IE = 1;//habilita interrupção de estouro de timer para verificar quantos estouros houve não será usado
    PEIE = 1;//habilita interrupção de hardware
    GIE = 1;
    imprime_rs232("Frequencimetro duplo com pic \n\r",30);
   for(;;)
     {
       __delay_ms(10);
       GIE = 0;
       //imprime o valor da frequencia atual a cada 200ms 
       imprime_rs232("\n\r FREQUENCIAS : ",17);
       aux =  fator_de_div / periodo1;
       aux  = aux*CCP1_mult;
       if(aux > 99999)
       {
           aux/1000;
           periodo1  = (long)aux;
           long_to_char(periodo1);//valor de frequencia calculada
           imprime_rs232("KHz ",3);
       }
       else
       {
           periodo1  = (long)aux;
           long_to_char(periodo1);//valor de frequencia calculada
           imprime_rs232("Hz - freq.2 = ",3);
       }
       aux =  fator_de_div / periodo2;
       aux  = aux*CCP2_mult;
       if(aux > 99999)
       {
           aux/1000;
           periodo2  = (long)aux;
           long_to_char(periodo2);//valor de frequencia calculada
           imprime_rs232("KHz ",3);
       }
       else
       {
           periodo2  = (long)aux;
           long_to_char(periodo2);//valor de frequencia calculada
           imprime_rs232("Hz ",3);
       }
       LED_STATUS = ~LED_STATUS; 
       GIE = 1;
     }//loop infinito
}


//  Notas:  *****************
/*
 estando com o CCP1 e CCP2 sem divisão ( div por 1) e com cristal de 20mhz
 * a faixa de range confiavel é aprox :
 * prescaler para  1 :  a partir de 80hz a 100Khz(estimado)
 * prescaler para  2 :  a partir de 40hz a 70khz(etimado) 
 * prescaler para  4 :  a partir de 10hz a 30khz(simulado)
 * prescaler para  8 :  a partir de 10hz a 25khz(simulado)
 * 
 * para faixa maxima o simulador proteus é limitado o ideal é usar um frequencimetro 
 * isso se deve ao estouro do timer para frequencia baixa(se for operar nessas frequencia use clock menor)
 */

formatado por : http://hilite.me/  acessando em 04/01/2024.

quarta-feira, 8 de novembro de 2023

Frequencímetro com 2 canais usando o C8051F380 e mostrando via serial RS232 da Silicon Labs,.

     Olá, neste artigo vou aproveitar o código que já havia sido planejado no exemplo do post anterior, quando se configura o hardware para captura já pega o sinal que é inserido nos pinos T0(P3.4 - pino26) e T1(P3.5 - pino25).

    Pode-se mudar as configurações para estar na faixa desejada para sua necessidade, neste exemplo um range previsto é  algo em torno de 750hz a 4,75KHZ.

    Deixei também alguns leds para testar se estava lendo o sinal no pino, e se havia processamento no microcontrolador.

O código fonte:

// Target:         C8051F380 e C8051F382
// Tool chain:     Simplicity Studio / Keil C51 9.51
//autor: Aguivone Moretti
//

//Data: 06_11_2023 - serial ok e modulos CCP ok
//Data: 07_11_2023 - calculado para um range de 3khz a 19Mhz(embora dê mais porem não fica muito bom)
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include "si_toolchain.h"
#include <SI_C8051F380_Register_Enums.h>
#include <stdio.h>
#include <string.h>

//-----------------------------------------------------------------------------
// Global Constants
//-----------------------------------------------------------------------------

#define SYSCLK       48000000          // Internal oscillator frequency in Hz
#define BAUDRATE      19200           // Baud rate of UART in bps
#define INT_DEC       256              // Integrate and decimate ratio

//-----------------------------------------------------------------------------
// Function Prototypes
//-----------------------------------------------------------------------------
SI_INTERRUPT_PROTO(PCA0_ISR, PCA0_IRQn);
void Liga_Port4(const char pino);
void Desliga_Port4(const char pino);
void Config_Init(void);
void UART0_Init (void);
//-----------------------------------------------------------------------------
//definicão dos pinos
//-----------------------------------------------------------------------------

SI_SBIT(SW1, SFR_P0, 6);                  // SW1 ='0' botão pressionado
SI_SBIT(SW2, SFR_P0, 7);                  // SW2 ='0' botão pressionado


//leds vermelho e sinal de saida
SI_SBIT(LED_1, SFR_P0, 0);                      // LED='1' Ligado     ->  lacoA
SI_SBIT(LED_2, SFR_P0, 1);                      // LED='1' Desligado  ->  lacoB
//led verde
#define LED_freq1    0x7F  
#define LED_freq2    0xBF  
//led azul
#define LED_Status   0xF7  // P4.3
//led vermelho
#define LED_ping     0xEF  //P4.4

//-----------------------------------------------------------------------------
//definicão das variaveis globais
//-----------------------------------------------------------------------------
bool flag_teste;
unsigned char porta4 = 0XFF;
uint16_t pisca =0;
char liga_pino_status  = 0;

// variaveis da serial RS232

#define  UART_BUFFERSIZE 10
uint8_t  UART_Buffer_rx[UART_BUFFERSIZE];
uint8_t  UART_Buffer_tx[UART_BUFFERSIZE];//para transmissão
uint8_t  pos_buffer=0;
uint8_t  tam_buffer_tx=0;
uint8_t  pos_buffer_tx=0;
bool     tem_recp = 0;
bool     rec_232 = 0;
bool     trans_232 = 0;

//variaveis para timers e captura

bool     sinal0 = 0;
bool     sinal1 = 0;

float periodo_1  = 0;
uint16_t periodo_anterior_1=0;
uint16_t periodo_atual_1=0;
uint8_t  num_itens1 = 0;

float periodo_2 = 0;
uint16_t periodo_anterior_2=0;
uint16_t periodo_atual_2=0;
uint8_t  num_itens2 = 0;

//-----------------------------------------------------------------------------
// SiLabs_Startup() Routine
// é chamada após reset
//-----------------------------------------------------------------------------
void SiLabs_Startup (void)
{
   PCA0MD = 0x00;                      // Disable watchdog timer
}


//------------------------ -----------------------------------------------------
// configura todo o hardware necessario
//-----------------------------------------------------------------------------

void Config_Init (void)
{

      IE_EA = 0; //desabilita todas as interrupções.

   //configura oscilador
      OSCICN  = 0X83;                     // IHFOsc Enable, sem divisão ira rodar a 12MHz
      CLKMUL  = 0XC0;                     // talvez nem precise neste microcontrolador -> habilita  e inicializa pll
      CLKSEL  = 0X03;                     // SYSCLK derived from the Internal High-Frequency Oscillator.sem divisão  48MHZ se estiver habilitado o clksel

      PFE0CN  = 0X20;                     //(para High Speed) Prefetch Engine Control,otimiza tempo de execu��o lendo 2 bytes de execu��o por vez
      /* FLSCL.FOSE(7) = 0 for < 10MHz and 1 for SYSCLK > 10MHz
      FLSCL.FLRT(4) = 0 for < 25MHz and 1 for SYSCLK > 25MHz */
      FLSCL   = 0x90;
      CKCON   = 0x00;  //  todos os timer ligado ao clock do sistema por meio do prescaler / clock dividido por 12(repensar depois)
      SPI0CN  = 0x02;                     //Select Mode 3-Wire pra liberar pino NSS

    //configura portas //////////////////////////////////////////////////////////////////////////////////////////////////////////////

      P0MDIN  = 0xFF;                     //  are digital
      P1MDIN  = 0xFF;                     //  are digital
      P2MDIN  = 0xFF;                     //  are digital
      P3MDIN  = 0xFF;                     //  are digital
      P4MDIN  = 0xFF;                     //  are digital

      P0MDOUT = 0x20;                     // coloca pino 4 como saida
      P1MDOUT = 0x00;                     // enable Switches as open-drain
      P2MDOUT = 0x00;                     // enable Switches as open-drain
      P3MDOUT = 0x00;                     // enable Switches as open-drain
      P4MDOUT = 0x04;                     // enable Switches as open-drain

      P0SKIP = 0xCF;                      // TXeRX precisa do Skip pra funcionar
      P1SKIP = 0xFF;
      P2SKIP = 0xFF;
      P3SKIP = 0xCF;

      P4 = 0XFF;  //portas de p4 ligadas (desliga leds)

      XBR0   = 0x01;                     // CP1AE,CP1E,CP0AE,CP0E,SYSCKE,SMB0E,SPI0E,(UART0E)  ///habilita UART0
      XBR2   = 0x00;                     // RESRV,RSRV,RESRV,RESRV,RESRV,RESRV,SMB1E, UART1E
      XBR1   = 0xC2;                     // WEAKPUD,(XBARE),T1E,T0E,ECIE,(PCA0ME):000:Nenhum,001:CEX0,010:CEX0eCEX1,...
    // VDM0CN -> monitor de tens�o de reset
      VDM0CN = 0x80;                     // Colocado porque senão da problema na gravacao da flash(já estava isso)
      RSTSRC = 0x02;                     // ativa reset de falha de oscilação.

    //configura modulos de captura /////////////////////////////////////////////////////////////////////////

      TMOD = 0x11;                       // 16-bit timer0 e timer1 interrupção no pino


      PCA0CN = 0x00;                      // Stop counter; clear all flags
      PCA0CPM0 = 0x21;                   //  ;5:CapPos, 4:CapNeg// habilita modulo ccp0 na borda de subida
      PCA0CPL0 = 0x00;
      PCA0CPH0 = 0x00;

      PCA0CPM1 = 0x21;                  //  ;5:CapPos, 4:CapNeg// habilita modulo ccp1 na borda de subida
      PCA0CPL1 = 0x00;
      PCA0CPH1 = 0x00;

      PCA0CPM2 = 0x00;     // desabilitado
      PCA0CPM3 = 0x00;
      PCA0CPM4 = 0x00;

      PCA0MD = 0x09;     //desliga watdog - clock sem divisão - habilita interrupção do counter/timer overflow
   //   PCA0MD = 0x03;     //desliga watdog - clock dividido por 4 - habilita interrupção do counter/timer overflow //se mudar aqui deverá mudar os calculos
  //    PCA0MD = 0x01;     //desliga watdog - clock dividido por 12 - habilita interrupção do counter/timer overflow
      EIP1 =   0x10;     //seta para alta prioridade , EIP1.PPCA0
      EIE1 =   0x10;     //Habilita Interrupcao da Captura
      PCA0CN_CR = 1;      // Habilita contadores



}
//-----------------------------------------------------------------------------
// UART0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// Configure the UART0 using Timer1, for <BAUDRATE> and 8-N-1.
//-----------------------------------------------------------------------------

void UART0_Init (void)
{
   SCON0 = 0x10;                       // SCON0: 8-bit variable bit rate
                                       //        level of STOP bit is ignored
                                       //        RX enabled
                                       //        ninth bits are zeros
                                       //        clear SCON0_RI and SCON0_TI bits
   if (SYSCLK/BAUDRATE/2/256 < 1) {
      TH1 = -(SYSCLK/BAUDRATE/2);
      CKCON &= ~0x0B;                  // T1M = 1; SCA1:0 = xx
      CKCON |=  0x08;
   } else if (SYSCLK/BAUDRATE/2/256 < 4) {
      TH1 = -(SYSCLK/BAUDRATE/2/4);
      CKCON &= ~0x0B;                  // T1M = 0; SCA1:0 = 01
      CKCON |=  0x01;
   } else if (SYSCLK/BAUDRATE/2/256 < 12) {
      TH1 = -(SYSCLK/BAUDRATE/2/12);
      CKCON &= ~0x0B;                  // T1M = 0; SCA1:0 = 00
   } else {
      TH1 = -(SYSCLK/BAUDRATE/2/48);
      CKCON &= ~0x0B;                  // T1M = 0; SCA1:0 = 10
      CKCON |=  0x02;
   }
   IE_ES0 = 1;                         //habilita interrupção de serial
   TL1 = TH1;                          // Init Timer1
   TMOD &= ~0xF0;                      // TMOD: timer 1 in 8-bit autoreload
   TMOD |=  0x20;
   TCON_TR1 = 1;                            // START Timer1

}

//-----------------------------------------------------------------------------
// tratamento especial para port 4
//-----------------------------------------------------------------------------
void Desliga_Port4(const char pino)
{//desliga em nivel alto
   porta4 = porta4 | (~pino);
   P4 = porta4;
}
void Liga_Port4(const char pino)
{
  porta4 = porta4 & pino;
  P4 = porta4;
}
//-----------------------------------------------------------------------------
// Interrupt Service Routines
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// UART0_Interrupt
//-----------------------------------------------------------------------------
//
// This routine is invoked whenever a character is entered or displayed on the
// Hyperterminal.
//
//-----------------------------------------------------------------------------

SI_INTERRUPT(UART0_Interrupt, UART0_IRQn)
{
   if (SCON0_RI == 1)
   {
       char RX_232 = SBUF0;
       SCON0_RI = 0;
       if(pos_buffer >= UART_BUFFERSIZE)  // tem um bug no compilador ou chip que faz reseta
                {//erro descarta, pois é maior que o tamanho maximo do buffer
                  rec_232=0; //não recebendo
                  pos_buffer=0;//limpa buffer
                  tem_recp = 0;//sinaliza fim de pacote
                }
       if(rec_232 && RX_232 == '*')
                {//esta recebendo e chegou delimitador de fim
                  rec_232=0; //não recebendo
                  tem_recp = 1;//sinaliza fim de pacote
                  Liga_Port4(LED_ping);
                }
       if(rec_232)
         {//esta recebendo
           UART_Buffer_rx[pos_buffer] = RX_232;
           pos_buffer++;
         }
       if(RX_232 == '#')
         {
           pos_buffer=0;//sinaliza recepção
           rec_232=1; //recebendo
         }
   }
   if (SCON0_TI)  //testa se tem transmissão
     {
        SCON0_TI = 0;                          // limpa flag de tranmissão
        if(trans_232 == 1)
          {

           if (pos_buffer_tx <  tam_buffer_tx)
            {// transmitindo
               SBUF0  = UART_Buffer_tx[pos_buffer_tx];//escreve na porta serial
               pos_buffer_tx++;

            }
            else
              {
                trans_232 = 0; //fim de transmissao
                pos_buffer_tx =0;
              }
        }
     }

}
void  imprime_hexa(char dados[] ,uint8_t tam)
{
    while(trans_232);  //faz nada só espera enviar todo o pacote  talvez por um time out
       //se ja houver dados para ser enviado espera terminar para comecar a enviar. // veja que pode travar um pouco aqui o processamento
    tam_buffer_tx = 0;
    while(tam > tam_buffer_tx)
      {
         UART_Buffer_tx[tam_buffer_tx] = dados[tam_buffer_tx];//transfere dados
         tam_buffer_tx++;
      }
    trans_232 = 1;//sinaliza que deve transmitir
    SCON0_TI = 1; //para dar inicio a transmissão
}


//-----------------------------------------------------------------------------
// PCA0_ISR
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// This is the ISR for the PCA.  It handles the case when a capture occurs on
// channel 0, and updates the variables to reflect the new capture information.
//
//-----------------------------------------------------------------------------

SI_INTERRUPT(PCA0_ISR, PCA0_IRQn)
{
        periodo_atual_1  = (PCA0CPH0<<8) + PCA0CPL0;//pega valores  depois vê se é pra tratar
        periodo_atual_2  = (PCA0CPH1<<8) + PCA0CPL1;
   /*  if(PCA0CN_CF)      // houve estouro do contador (1 só pra todos)
       {
         //a fazer
         PCA0CN_CF = 0;
       }*/
     if(PCA0CN_CCF0)      // interrupção no modulo 0
           {
             PCA0CN_CCF0 = 0;// Clear module 0 interrupt flag.

            if(num_itens1<10)
              {
                  if(periodo_atual_1> periodo_anterior_1)
                    {
                      periodo_1 = (periodo_atual_1 - periodo_anterior_1)+periodo_1;
                    }
                  else
                    {
                      periodo_1  = (( 65535 - periodo_anterior_1) + periodo_atual_1)+periodo_1;
                    }
                num_itens1++;
              }

           }
     if(PCA0CN_CCF1)      // interrupção no modulo 2
            {
             PCA0CN_CCF1 = 0;// Clear module 0 interrupt flag.
              if(num_itens2<10)
                {
                  if(periodo_atual_2> periodo_anterior_2)
                        {
                          periodo_2 = (periodo_atual_2 - periodo_anterior_2)+periodo_2;
                        }
                      else
                        {
                          periodo_2  = (( 65535 - periodo_anterior_2) + periodo_atual_2)+periodo_2;
                        }
                  num_itens2++;
                }

            }
     PCA0CN = 0X40;//limpa todos os estouros e deixa o modo captura e timer ligado
     periodo_anterior_1 = periodo_atual_1;
     periodo_anterior_2 = periodo_atual_2;

}
void long_to_char(long valor)
{
    char Buffer_serial_out[5]; //delimitador pra facilitar jogar no excel
    Buffer_serial_out[0]='0';
    Buffer_serial_out[1]='0';
    Buffer_serial_out[2]='0';
    Buffer_serial_out[3]='0';
    Buffer_serial_out[4]='0';
    if(valor < 65535)
    {
        while(valor>=10000)
             {
                 valor = valor - 10000;
                 Buffer_serial_out[0]++;
             }
        while(valor>=1000)
           {
               valor = valor - 1000;
               Buffer_serial_out[1]++;
           }
        while(valor>=100)
           {
               valor = valor - 100;
               Buffer_serial_out[2]++;
           }
        while(valor>=10)
           {
               valor = valor - 10;
               Buffer_serial_out[3]++;
           }
        while(valor>=1)
           {
               valor = valor - 1;
               Buffer_serial_out[4]++;
           }
        imprime_hexa(Buffer_serial_out ,5);
    }

}

//-----------------------------------------------------------------------------
// main() Routine
//-----------------------------------------------------------------------------

void main (void)
{  //variaveis locais
   Config_Init();                       // inicializa CPU
   UART0_Init();                       // inicializa UART0

   LED_1 = 1;//desliga leds
   LED_2 = 1;
   Desliga_Port4(LED_freq1);
   Desliga_Port4(LED_freq2);
   Desliga_Port4(LED_Status);
   liga_pino_status  = 0;
   IE_EA = 1;//habilita interrupções globais
   flag_teste = 0;
   while (1)
   {
       if(tem_recp)//recebeu dados
                        {
                           //trata os dados recebidos que estão em : UART_Buffer_RX

                             imprime_hexa("\n\r",2);//salta linha e retorna para o inicio de linha
                             imprime_hexa("dados =>" ,8);
                             imprime_hexa(UART_Buffer_rx ,pos_buffer);
                             pos_buffer = 0;
                             tem_recp = 0;//sinaliza que já leu
                             Desliga_Port4(LED_ping);
                        }

       if(num_itens1==10)
              {
               imprime_hexa("\n\r",2);//salta linha e retorna para o inicio de linha
               imprime_hexa("freq1=> " ,8);
               if(periodo_1 > 30000)  //pra não ultrapassar o limite de impressão
                 {
                   imprime_hexa("(hz)",4);
                   periodo_1 = 250000000/((periodo_1/10)*5.199);//já tira a media
                 }
               else
                 {
                   imprime_hexa("(khz)",5);
                   periodo_1 = 250000/((periodo_1/10)*5.199);//já tira a media
                 }
               long_to_char(periodo_1);
               if(sinal0 == 0 )
                  {
                    Liga_Port4(LED_freq1);
                    sinal0 = 1;
                  }
                else
                  {
                    Desliga_Port4(LED_freq1);
                    sinal0 = 0;
                  }
               num_itens1 = 0;
               periodo_1 = 0;
              }
       if(num_itens2==10)
               {
                imprime_hexa("\n\r",2);//salta linha e retorna para o inicio de linha
                imprime_hexa("freq2=> " ,8);
                if(periodo_2 > 30000)  //pra não ultrapassar o limite de impressão
                   {
                     imprime_hexa("(hz)",4);
                     periodo_2 = 250000000/((periodo_2/10)*5.199);//já tira a media
                   }
                 else
                   {
                     imprime_hexa("(khz)",5);
                     periodo_2 = 250000/((periodo_2/10)*5.199);//já tira a media
                   }
                long_to_char(periodo_2);// valor em htz
                if(sinal1 == 0 )
                     {
                      Liga_Port4(LED_freq2);
                      sinal1 = 1;
                     }
                     else
                     {
                       Desliga_Port4(LED_freq2);
                       sinal1 = 0;
                     }
                num_itens2 = 0;
                periodo_2 = 0;
               }
                     pisca++;
                     if(pisca > 100)
                       { // pisca led
                         if(liga_pino_status  == 0)
                           {
                             liga_pino_status  = 1;
                             Liga_Port4(LED_Status);
                             SCON0_TI = 0;
                           }
                         else
                           {
                             liga_pino_status  = 0;
                             Desliga_Port4(LED_Status);
                           }
                        pisca =0;
                       }
   }
}

formatado em : http://hilite.me/  acessado em 08/11/2023.

sexta-feira, 3 de novembro de 2023

Configurando o 8051CF380 para 48MHZ ( através do pll, com oscilador interno) e configurando a porta serial

     Neste exemplo é demonstrado alguns aspectos na configuração deste microcontrolador :

1 - Como configurar o PLL para gerar 48MHZ interno.

2 - Configurando a serial para receber e enviar dados, com funções prontas e mais otimizadas.

3 - Como acionar e configura o PORT4.

4 - Exemplo de leitura de pinos e acionamento das IO's.

        Aqui é usado o caracter '/' para indicar inicio de dados, mas pode ser trocado por outro, e o caracter '\n' para fim de dados. Assim basta digitar num terminal serial os dados da seguinte forma : "/dados\n."

O código fonte :

//Autor : Aguivone M. F.
//Compilador: Simplicity studio - Silicon labs 
// EXEMPLO DE COMO USAR A A SERIAL E OS PINOS DO MICROCONTROLADOR C8051F380-A-GQ //----------------------------------------------------------------------------- // Includes //----------------------------------------------------------------------------- #include <SI_C8051F380_Register_Enums.h> //----------------------------------------------------------------------------- // Global CONSTANTS //----------------------------------------------------------------------------- #define SYSCLK 48000000 // frequencia em Hz #define BAUDRATE 9600 // Baud rate da UART0 em bps // todos o led são ligados ao VCC #define LED_freq1 0x7F #define LED_freq2 0xBF #define LED_Status 0xF7 // P4.3 #define LED_ping 0xEF //P4.4 unsigned char porta4 = 0XFF; //----------------------------------------------------------------------------- // Function PROTOTYPES //----------------------------------------------------------------------------- SI_INTERRUPT_PROTO(UART0_Interrupt, UART0_IRQn); void SYSCLK_Init (void); void UART0_Init (void); void PORT_Init (void); //----------------------------------------------------------------------------- // Global Variables //----------------------------------------------------------------------------- // variaveis da serial RS232 #define UART_BUFFERSIZE 30 uint8_t UART_Buffer_rx[UART_BUFFERSIZE]; uint8_t UART_Buffer_tx[UART_BUFFERSIZE];//para transmissão uint8_t pos_buffer=0; uint8_t tam_buffer_tx=0; uint8_t pos_buffer_tx=0; bool tem_recp = 0; bool rec_232 = 0; bool trans_232 = 0; uint16_t pisca =0; char liga_pino_status = 0; //----------------------------------------------------------------------------- // SiLabs_Startup() - POSIÇÃO INICIAL A SER EXECUTADA // ---------------------------------------------------------------------------- void SiLabs_Startup (void) { PCA0MD &= ~0x40; // WDTE = 0 (clear watchdog timer } //----------------------------------------------------------------------------- // tratamento especial para port 4 //----------------------------------------------------------------------------- void Desliga_Port4(const char pino) {//desliga em nivel alto porta4 = porta4 | (~pino); P4 = porta4; } void Liga_Port4(const char pino) { porta4 = porta4 & pino; P4 = porta4; } //----------------------------------------------------------------------------- // PORT_Init - INICIALIZA AS PORTAS //----------------------------------------------------------------------------- // // Return Value : None // Parameters : None // // Configure the Crossbar and GPIO ports. // // P0.4 digital push-pull UART TX // P0.5 digital open-drain UART RX // //----------------------------------------------------------------------------- void PORT_Init (void) { P0MDIN = 0xFF; // are digital P0MDOUT = 0x20; // Enable UTX as push-pull output XBR0 = 0x01; // Enable UART on P0.4(TX) and P0.5(RX) XBR1 = 0x40; // Enable crossbar and weak pull-ups P4MDOUT = 0x04; // enable Switches as open-drain P4MDIN = 0xFF; // are digital P4 = 0XFF ; //portas de p4 ligadas (desliga leds) } //----------------------------------------------------------------------------- // SYSCLK - INICIA A CONFIGURAÇÃO DO CLOCK //----------------------------------------------------------------------------- void SYSCLK_Init (void) { // configurado para 48mhz OSCICN = 0X83; // IHFOsc Enable, sem divisão ira rodar a 12MHz CLKMUL = 0XC0; // talvez nem precise neste microcontrolador -> habilita e inicializa pll CLKSEL = 0X03; // SYSCLK derived from the Internal High-Frequency Oscillator.sem divisão 48MHZ se estiver habilitado o clksel PFE0CN = 0X20; //(para High Speed) Prefetch Engine Control,otimiza tempo de execu��o lendo 2 bytes de execu��o por vez /* FLSCL.FOSE(7) = 0 for < 10MHz and 1 for SYSCLK > 10MHz FLSCL.FLRT(4) = 0 for < 25MHz and 1 for SYSCLK > 25MHz */ FLSCL = 0x90; CKCON = 0x30; RSTSRC = 0x04; // Enable missing clock detector } //----------------------------------------------------------------------------- // UART0_Init //----------------------------------------------------------------------------- // // Return Value : None // Parameters : None // // Configure the UART0 using Timer1, for <BAUDRATE> and 8-N-1. //----------------------------------------------------------------------------- void UART0_Init (void) { SCON0 = 0x10; // SCON0: 8-bit variable bit rate // level of STOP bit is ignored // RX enabled // ninth bits are zeros // clear SCON0_RI and SCON0_TI bits if (SYSCLK/BAUDRATE/2/256 < 1) { TH1 = -(SYSCLK/BAUDRATE/2); CKCON &= ~0x0B; // T1M = 1; SCA1:0 = xx CKCON |= 0x08; } else if (SYSCLK/BAUDRATE/2/256 < 4) { TH1 = -(SYSCLK/BAUDRATE/2/4); CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 01 CKCON |= 0x01; } else if (SYSCLK/BAUDRATE/2/256 < 12) { TH1 = -(SYSCLK/BAUDRATE/2/12); CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 00 } else { TH1 = -(SYSCLK/BAUDRATE/2/48); CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 10 CKCON |= 0x02; } IE_ES0 = 1; //habilita interrupção de serial TL1 = TH1; // Init Timer1 TMOD &= ~0xF0; // TMOD: timer 1 in 8-bit autoreload TMOD |= 0x20; TCON_TR1 = 1; // START Timer1 } //----------------------------------------------------------------------------- // Interrupt Service Routines //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // UART0_Interrupt //----------------------------------------------------------------------------- // // This routine is invoked whenever a character is entered or displayed on the // Hyperterminal. // //----------------------------------------------------------------------------- SI_INTERRUPT(UART0_Interrupt, UART0_IRQn) { if (SCON0_RI == 1) { char RX_232 = SBUF0; SCON0_RI = 0; if(pos_buffer >= UART_BUFFERSIZE) // tem um bug no compilador ou chip que faz reseta {//erro descarta, pois é maior que o tamanho maximo do buffer rec_232=0; //não recebendo pos_buffer=0;//limpa buffer tem_recp = 0;//sinaliza fim de pacote } if(rec_232 && RX_232 == '\n') {//esta recebendo e chegou delimitador de fim rec_232=0; //não recebendo tem_recp = 1;//sinaliza fim de pacote Liga_Port4(LED_ping); } if(rec_232) {//esta recebendo UART_Buffer_rx[pos_buffer] = RX_232; pos_buffer++; } if(RX_232 == '/') { pos_buffer=0;//sinaliza recepção rec_232=1; //recebendo } } if (SCON0_TI) //testa se tem transmissão { SCON0_TI = 0; // limpa flag de tranmissão if(trans_232 == 1) { if (pos_buffer_tx < tam_buffer_tx) {// transmitindo SBUF0 = UART_Buffer_tx[pos_buffer_tx];//escreve na porta serial pos_buffer_tx++; } else { trans_232 = 0; //fim de transmissao pos_buffer_tx =0; } } } } void escreve_frase(char dados[] ,uint8_t tam) { while(trans_232); //faz nada só espera enviar todo o pacote talvez por um time out //se ja houver dados para ser enviado espera terminar para comecar a enviar. // veja que pode travar um pouco aqui o processamento tam_buffer_tx = 0; while(tam > tam_buffer_tx) { UART_Buffer_tx[tam_buffer_tx] = dados[tam_buffer_tx];//transfere dados tam_buffer_tx++; } trans_232 = 1;//sinaliza que deve transmitir SCON0_TI = 1; //para dar inicio a transmissão } //----------------------------------------------------------------------------- // MAIN Routine //----------------------------------------------------------------------------- void main (void) { // enable) PORT_Init(); // Initialize Port I/O SYSCLK_Init (); // Initialize Oscillator UART0_Init(); IE_EA = 1;//habilita todas as interrupções escreve_frase("Escreva na formato: /xx\n \r" ,25); while(1) { if(tem_recp)//recebeu dados { //trata os dados recebidos que estão em : UART_Buffer_RX escreve_frase("\n\r",2);//salta linha e retorna para o inicio de linha escreve_frase("recebeu dados =>" ,16); escreve_frase(UART_Buffer_rx ,pos_buffer); pos_buffer = 0; tem_recp = 0;//sinaliza que já leu Desliga_Port4(LED_ping); } pisca++; if(pisca > 65500) { // pisca led if(liga_pino_status == 0) { liga_pino_status = 1; Liga_Port4(LED_Status); SCON0_TI = 0; } else { liga_pino_status = 0; Desliga_Port4(LED_Status); } pisca =0; } } } //----------------------------------------------------------------------------- // End Of File //-----------------------------------------------------------------------------

Formatado em http://hilite.me/  acessado em 03_11_2023.