![](/media/cache/profiles/740b339e4f5b8fc4937f9769f05cc202.jpg.50x50_q85.jpg)
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.
Diff: main.cpp
- 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; +} + + + + +