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.

Revision:
3:ec85930e953c
Parent:
2:03e1399ed9eb
--- a/main.cpp	Thu Oct 29 06:33:32 2015 +0000
+++ b/main.cpp	Wed Aug 24 15:36:59 2016 +0000
@@ -1,59 +1,509 @@
-//--------------------------------------------------------------
-// Demo program of FftReal class
-// Copyright (c) 2015 MIKAMI, Naoki,  2015/10/29
-//--------------------------------------------------------------
+/*
+ --------------------------------------------------------------
+ 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 
 
-#include "dftComplex.hpp"
-#include "fftReal.hpp"
+-------------------------------------------------------------- */
+
+// 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>
 
-using namespace Mikami;
+#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()
 {
-//    const int N = 16;       // number of date for FFT
-    const int N = 256;       // number of date for FFT
-
-    float x1[N], x2[N];
-    Complex y1[N], y2[N/2+1];
-
-    // Generate random data
-    srand(1234);
-    for (int n=0; n<N; n++)
-        x1[n] = 2.0f*rand()/(float)RAND_MAX - 1.0f;
-    printf("\r\n#### Original data for DFT ####\r\n");
-    for (int n=0; n<N; n++)
-        printf("f[%2d]: %8.4f\r\n", n, x1[n]);
-
-    // DFT, for comarison
-    DftComplex(x1, y1, N);
-    printf("\r\n#### Result of direct DFT ####\r\n");
-    printf("          real    imaginary\r\n");
-    for (int n=0; n<N; n++)
-        printf("F[%2d]: %8.4f, %8.4f\r\n", n, y1[n].real(), y1[n].imag());
-
-    Timer tm;   // for measurement of execution time
+	//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++){
 
-    // FFT
-    FftReal fft(N);
-    tm.reset();
-    tm.start();
-    fft.Execute(x1, y2);
-    tm.stop();
-    printf("\r\nExecution time (FFT): %d [us]\r\n", tm.read_us());
-    printf("\r\n#### Result of DFT using FFT ####\r\n");
-    for (int n=0; n<=N/2; n++)
-        printf("F[%2d]: %8.4f, %8.4f\r\n", n, y2[n].real(), y2[n].imag());
+        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_);
     
-    // IFFT
-    tm.reset();
-    tm.start();
-    fft.ExecuteIfft(y2, x2);
-    tm.stop();
-    printf("\r\nExecution time (IFFT): %d [us]\r\n", tm.read_us());
-    printf("\r\n#### Result of IFFT ####\r\n");
-    printf("        original  IFFT of FFT\r\n");
-    for (int n=0; n<N; n++)
-        printf("f[%2d]: %8.4f, %8.4f\r\n", n, x1[n], x2[n]);
+    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;       
+}
+       
+       
+       
+       
+