Serial Communication/ Analog Read/ FFT compute / LCD Text / Write on SD Card / read and write RTC application. K64F app developed for Electrical Engineering undergraduate final project at Ulbra university.

Dependencies:   SDFileSystem TextLCD mbed

Serial, LCD 20x4, RTC, SD-Card, ADC features application. Included 5-key keyboard using AN0 channel, RTC update via serial, compute FFT and storage in SD-Card.

main.cpp

Committer:
flencina
Date:
2016-08-24
Revision:
4:398325c79937
Parent:
3:ec85930e953c

File content as of revision 4:398325c79937:

/*
 --------------------------------------------------------------
 Universidade Luterana do Brasil
 Departamento de Engenharia Elétrica
 Trabalho de Conclusão de Curso de Engenharia Elétrica
 MCSA - Motor Current Signature Analysis - Diagnóstico por Análise Espectral de Corrente de Motor
 Aluno: Flávio Dutra Lencina
 Orientador: Prof. Eng. Eletricista João Daniel de Oliveira Klein
 Data: 20/03/2016
 Dispositivo de Coleta e envio de dados espectrais de Corrente
 Desenvolvido para plataforma NXP FRDM-K64F co processador ARM Cortex-M4 MK64FN1M0VLL12 MCU
 utilizando Kinetis Devlopment Studio da NXP
 ADC0 :coleta de dados de corrente
 FFT para análise em frequência dos  4096 pontos
 Envio dos dados de |FFT| x freq[k] pela serial em 115200bps
 Grava dados no SD card \sd\Estreito\EE_Coletaxx.csv ou \sd\Estreito\EA_Coletaxx.csv
 ou envia para serial
 Leitura da AN0 para o teclado.
 Teste com LCD 20x4 

-------------------------------------------------------------- */

// 15-04-2016:
// Mudança de estratégia de interrupções para utilização do teclado com LCD Shield do Arduino.
// Colocar Interrupção para a porta serial e retirar das teclas SW2 e SW3. Utilização do teclado do Shield.
// 15-06-2016:
// Revisado para AN2 - Coleta a 4096 SPS e AN1 - 512 SPS
// 03-08-2016: Revisão para adicionar PGA com CD4066 e controle com CD4028 BCD para decimal
// 21-08-2016: Ajuste de RTC.

#include "mbed.h"
#include "SDFileSystem.h"
#include "math.h"
#include "mbed_debug.h"
#include "TextLCD.h"
#include <complex>

#define ZRef 0.5 // Eleva para metade
#define Ts 244.14062    //4096Hz

 // SD-CARD Interface
#define SD_MOSI        PTE3
#define SD_MISO        PTE1
#define SD_SCLK        PTE2
#define SD_CS          PTE4
#define SD_DETECT	   PTE6

// Interface LCD 20x04 - 4bits de dados
#define RS PTC12 //D8 // instead PTA0 pin 34, we have to use PTC12 -  pin 84
//#define RW  GND-3
#define EN PTC4  //D9
#define DB7 PTC3 //D7
#define DB6 PTC2 //D6
#define DB5 PTA2 //D5
#define DB4 PTB23 //D4

// Teclas do Teclado Shield
#define btn1 1
#define btn2 2
#define btn3 3
#define btn4 4
#define btn5 5
#define btnNONE 0


 // modos de envio de dados

#define SERIAL 01
#define SDCARD 02

// Canais analógicos
AnalogIn kbd(A0); // Teclado funcional
AnalogIn ainc(A1); // Entrada analógica espectro curto 
AnalogIn ainl(A2); // Entrada analógica espectro longo
DigitalIn SD_OK(SD_DETECT,PullDown);  // Card Detect
//Saídas Digitais
DigitalOut GV0(PTA1);  //A
DigitalOut GV1(PTB9);  //B
DigitalOut GV2(PTC17); //C

// Tipo Complexo
typedef complex<float> Complex; 

// Protótipos de Funções
void Coleta(uint8_t mult);
uint16_t reverse(uint16_t x);
void fft(uint16_t N_FFT_);
void gravar(uint8_t mult);
uint16_t Countfile(uint8_t n);
uint8_t le_teclado(void);

// Inicializa SD card
SDFileSystem sd(SD_MOSI, SD_MISO, SD_SCLK, SD_CS, "sd");
// Inicializa LCD
TextLCD lcd(RS, EN, DB4, DB5, DB6, DB7,TextLCD::LCD20x4); // rs, e, d4-d7
// Inicializa Serial
Serial pc(USBTX, USBRX); // tx, rx

// Variáveis
const long N=4096;
const unsigned int m = 12;
//float t[N]
float f[N/2+1];
double x0[N];
Complex y2[N/2+1];
bool sdsel=false;
bool conectado = true;//false;
char buffer[32]; // para o rtc
// Interrupção de leitura da serial
void SerialRecInt(void)
{
	
	if (sdsel==false)
	{
		unsigned char msg;
		uint32_t tempo=0;
		char UTS[11];
	    time_t seconds = time(NULL);
        strftime(buffer,32,"%d/%m/%Y %H:%M:%S\n",localtime(&seconds));
		msg=pc.getc();
		while(!pc.writeable()){}
		switch (msg){
		case 'C':// Iniciar conexão
		{
			pc.printf("OK\n");
			conectado = true;
			break;
		}
		case 'D':// Terminar conexão
		{
			pc.printf("OK\n");
			conectado = false;
			break;
		}
		case 'E': // Espectro Estreito
		{
			// Envia espectro Curto via Serial.
			if (conectado)
			{
				Coleta(4);
				for(int n=0;n<N/2;n++)
					pc.printf("%8.4f;%8.4f\n",f[n],x0[n]);
			}		
			break;
		}
		case 'L': // Espectro Longo
		{
			// Envia espectro Amplo via Serial.
			if (conectado)
			{
				Coleta(1);
				for(int n=0;n<N/2;n++)
					pc.printf("%8.4f;%8.4f\n",f[n],x0[n]);
			}		
			break;
		}
		case 'R': // Relógio
		{
			pc.gets(UTS,11); // Recebe o valor de Timestamp
            for(int n=0;n<10;n++)
            {
                tempo = tempo * 10  + (UTS[n] -48);
                
            }
            set_time(tempo);  
            pc.printf("%s",buffer);
			break;
		}
		case 'T': // Teste
		{
	        pc.printf("%s",buffer);
			if (SD_OK.read())
				debug("Cartao SD Ok-> %d\n",SD_OK.read());
			else
				debug("Cartao SD NOk-> %d\n",SD_OK.read());
			break;
		}
		default:
			break;
		}
		//tm.start();		
	}

		//msg = ' ';
}
// Leitura do teclado
uint8_t le_teclado(void)
{
	uint16_t tecla = kbd.read_u16();
	if (tecla > 60000) return btnNONE; //sem tecla
	if (tecla > 40000) return btn5;
	if (tecla > 30000) return btn4;
	if (tecla > 15000) return btn3;
	if (tecla > 5000) return btn2;
	if (tecla >= 0) return btn1;
	return btnNONE;
}

int main()
{
	//Timer tm0;
    uint8_t tecla;
    pc.baud(115200);
    pc.attach(&SerialRecInt,pc.RxIrq); // Chamada de IRQ para Serial
    lcd.cls();
    lcd.printf("TCC  - MCSA - ULBRA\n"); // linha 0
    // debug("MCSA - Aquisição de Motor.\n\r");
   // tm0.start();
    while(1) {
          // Comando via teclado
    	  tecla=le_teclado();
    	  lcd.locate(0,3); // aponta para linha 3
    	  lcd.printf("1- Amplo / 2- Curto"); 
    	  //lcd.printf("%d",tecla); // tecla pressionada
    	  switch(tecla){
    	  case btn1: // Espectro Longo
    	  {
    		  sdsel=true;
    		  Coleta(1);
    		  gravar(1);
    		  sdsel=false;
    		  break;
    	  }
    	  case btn2: // Espectro Curto
    	  {
    	  	  sdsel=true;
    	  	  Coleta(4);
    	  	  gravar(4);
    	  	  sdsel=false;
    	      break;
    	  }
    	  case btn3: // Limpa comando
    	  {
    		  lcd.locate(0,1);
    		  lcd.printf("                 ");
    	      break;
    	  }
    	  case btn4: // Créditos
    	  {
    		  lcd.cls();
    		  lcd.printf("ULBRA  ENG. ELETRICA\n");
    		  lcd.printf("      TCC - MCSA \n   ");
    		  lcd.printf("Flavio Dutra Lencina\n");
    		  lcd.printf("Prof. Joao D. Klein \n");
    		  while(1)
    		  {
    		  	 tecla=le_teclado();
    		  	 if tecla(<> btnNONE)
    		  	    break;
    		  	 wait_ms(200);   
    		  }
    		  lcd.cls();
    		  lcd.printf("TCC  - MCSA - ULBRA\n"); // linha 0
    	      break;
    	  }
    	  default:
    	 	  break;
    	  }
    	  wait_ms(300);
    //	  tm0.reset();
    //	  while(tm0.read_ms()<500);
    	  lcd.locate(0,2);
    	  // Verifica se há cartão SD
          if (SD_OK.read())
          	lcd.printf("                   ");
          else
          	lcd.printf(" Insira o Cartao SD");
          
     }
}
// Coleta de dados
void Coleta(uint8_t mult)
{
    Timer tm;
    tm.stop();
    double max,z;
    uint8_t Ganho =0;
    float fs,df;//,dt;
    // multiplicador
    if(mult<1) 
    	mult=1;
    else
    	mult=4;
    
    // Informações para LCD
    
    lcd.locate(0,1);
    lcd.printf("                  ");
    lcd.locate(0,1);
    lcd.printf("Ajustando Ganho...");
          
    // Fazer Ajuste de ganho
        
    tm.start(); // Ativa Timer
    while(1)//Ganho < 5) // de 0 até 5
    {	
    	tm.reset();
    	max = ainl.read();
    	for (int n=1;n<137;n++)
    	{
    		 while (tm.read_us()<(Ts));
    		 tm.reset();
    		 z=ainl.read();
    		 if (max < z) max=z;
    	}
    //	tm.stop();
      	//debug
    	lcd.locate(0,2);
    	lcd.printf("Max: %4.2f",max);
    	if (max < 0.632)	 
    	{
        	Ganho++;
        	if (Ganho > 5) // Ganho máx
			{	
				Ganho = 5;
				break;
			}	
		    ///Saidas para PGA
        	GV0 =  Ganho & 0x01;
        	GV1 = (Ganho & 0x02)>>1;
        	GV2 = (Ganho & 0x04)>>2;
        	//debug
        	lcd.printf("%d %d %d\n", (uint8_t)GV0,(uint8_t)GV1,(uint8_t)GV2);
        }
		else
			break;
	//	tm.start();	
	}
	tm.stop();
	lcd.locate(0,1);
    lcd.printf("Coletando dados...");
    // Cálculo de espectro de frequência
    fs= (float)1000/(Ts*mult); // frequência de amostragem 4098kHz~4096
    df= 1000*(fs/N);           // delta de frequência
    f[0]=0.0001;
    for (int n=1;n<N/2;n++)
         f[n]= f[n-1]+df; 
	tm.start(); // Retiva Timer
    for (long int n=0;n<N;n++){
        tm.reset();
        // Por enquanto Espectro longo e curto no mesmo
        //if (mult==1)
           x0[n]= ainl.read(); // espetro longo
        // else
        //   x0[n]= ainc.read(); // espectro curto
        while (tm.read_us()<(Ts*mult)); // freq de amostragem: 4096 Hz ou 512 Hz
        for (int i=0;i<mult;i++)
        {	__NOP();
        	__NOP();
        	__NOP();
        	//__NOP();
        }
     }
     tm.stop(); // Para o Timer
     // Reseta Ganho
     GV0=0;
     GV1=0;
     GV2=0;
     // Ajuste de zero
     for (long int n=0;n<N;n++){

        x0[n]=x0[n]-ZRef;
     }
     //debug("Foi ate o N:%d\n ",N);


     fft(N);
     // Módulo da FFT
     for(long int n=0;n<N/2;n++)
         x0[n]=(double)sqrt(y2[n].real()*y2[n].real()+y2[n].imag()*y2[n].imag());
     // encontra maior valor
     max=x0[0];
     for (int n=1;n<N/2;n++)
          if (x0[n] > max) max =x0[n];
     // Normaliza valores a 1 máx   (linear)  
     // for (int n=0;n<N/2;n++){
     //     x0[n]= x0[n]/max;     
     // }
     
     
     
     // Normaliza valores
     for (int n=0;n<N/2;n++){
          x0[n]= 20* log10(x0[n]/max);
     }
     lcd.locate(0,1);
     lcd.printf("                  ");
     
}

// A FFT por decimação de frequência
void fft(uint16_t N_FFT_)
{
    Complex u_[N_FFT_],wTable_[N_FFT_];
    Complex uTmp;
    uint16_t bTable_[N_FFT_];
    uint16_t nHalf = N_FFT_/2;
    Complex arg = Complex(0, -6.283185f/N_FFT_);
    
    uint16_t nShift = __clz(N_FFT_) + 1; // Apenas no mbed
    for (uint16_t k=0; k<N_FFT_; k++){
         wTable_[k] = exp(arg*(float)k);
         bTable_[k] = __rbit(k) >> nShift; // Apenas no mbed
         //bTable_[k] = reverse(k);
         u_[k]=x0[k];
         //debug("%d ",k);
    }
    for (uint16_t stg=1; stg<N_FFT_/2; stg*=2)
     {
          uint16_t nHalf2 = nHalf*2;
          for (uint16_t kp=0; kp<N_FFT_; kp+=nHalf2)
          {
               uint16_t kx = 0;
                    for (uint16_t k=kp; k<kp+nHalf; k++)
                    {
                        // Butterfly operation
                        Complex uTmp = u_[k+nHalf];
                        u_[k+nHalf] = (u_[k] - uTmp)*wTable_[kx];
                        u_[k] = u_[k] + uTmp;
                        kx = kx + stg;
                    }
                }
                nHalf = nHalf/2;
       }
     // Last stage
      y2[0] = u_[0] + u_[1];
      y2[0] = u_[0] + u_[1];
      y2[N_FFT_/2] = u_[0] - u_[1];
      for (uint16_t k=2; k<N_FFT_; k+=2)
           u_[k] = u_[k] + u_[k+1];
      // Reorder to bit reversal
      for (uint16_t k=1; k<N_FFT_/2; k++)
          y2[k] = u_[bTable_[k]];
}
// Bit reverso
uint16_t reverse(uint16_t x)
{
   uint16_t NO_OF_BITS = sizeof(x) * 8;
   uint16_t reverse_num = 0;
   for (uint16_t i = 0; i < NO_OF_BITS; i++)
   {
       if((x & (1 << i)))
           reverse_num |= 1 << ((NO_OF_BITS - 1) - i);
   }
   return (reverse_num >> (NO_OF_BITS-m));
}
// Grava em SD Card
void gravar(uint8_t x)
{
    char arquivo[64];
    if (SD_OK.read())
    {
       // debug("Gravando em cartao SD\n\r");
	    lcd.locate(0,1);
        lcd.printf("Gravando dados...");
    	if (x==1) // Amplo
    	{
    		mkdir("/sd/Amplo", 0777);
    		sprintf(arquivo, "/sd/Amplo/EA_Coleta%03d.csv", Countfile(1));
    		//  pc.printf("Arquivo: %s\n\r",arquivo);
    	}
    	else // Estreito
    	{
    		mkdir("/sd/Estreito", 0777);
    		sprintf(arquivo, "/sd/Estreito/EE_Coleta%03d.csv", Countfile(2));
    	}
    	FILE *fp =fopen(arquivo,"w");
    	fprintf(fp,"Freq[Hz];Amplitude[dB]\r\n");

    	for(int n=0;n<N/2;n++){
    		//fputc(0x0A,fp);
    		// 
    		fprintf(fp,"%8.4f;%8.4f\r\n",f[n],x0[n]);
    	}

    	//fputc(0x0D,fp);
    	fclose(fp);
    	lcd.locate(0,1);// (0,1);
    	lcd.printf("                 ");
    }
    else
    {
    	//debug("Sem cartao SD.\n\r");
    	lcd.locate(0,1);
    	lcd.printf("Sem cartao SD.\n");
    } 
    //tm.start();   
}
// Manipulação de arquivos
uint16_t Countfile(uint8_t n)
{
    struct dirent *p;
    uint16_t numFiles = 0;
    DIR * sdDir;
    if (n==1){
    	sdDir = opendir("/sd/Amplo");
    }
    else
    	sdDir = opendir("/sd/Estreito");
    while ((p = readdir( sdDir )) != NULL)
            numFiles++;
    closedir(sdDir);
    return numFiles;       
}