Mostrando postagens com marcador PIC. Mostrar todas as postagens
Mostrando postagens com marcador PIC. Mostrar todas as postagens

domingo, 5 de maio de 2019

PIC32 Graphics Primitive Layer - Funções Básicas


 PIC32 e GOL - Graphics Primitive Layer - Funções Básicas para desenhar em um Display Gráfico colorido TFT

 Aprenda a utilizar elementos gráficos em display colorido (QVGA - 240x320 - TFT), como texto, linha, retângulo, círculo, gradiente e imagem. 

Exemplos de aplicação das Funções Básicas da Biblioteca Gráfica da Microchip no MPLAB C32.



Graphic Primitive Layer

Esta é a configuração que utilizei para este projeto:

Hardware:
PIC32 Ethernet Starter Kit
    PIC32MX795F512L
    MIPS32 M4K Core @80 MHz 32-bit
    512 kB de Flash
   128 kB de RAM

Multimedia Expansion Board
     Solomon Systech Graphics Controller (SSD1926)
     Truly LCD ModuleTFT-G240320LTSW-118W-E
     3.2 inch (8.1 cm) QVGA TFT Touchscreen, 240x320, 65000 cores.

Software:
MPLAB IDE v8.83
MPLAB C32 Compiler v2.02
Graphics Library 3.06.04, MLA v2013-06-15



Funções e Macros da Graphics Primitive Layer:

Text Functions
    FONT_HEADER Structure
    FONT_FLASH Structure
    FONT_EXTERNAL Type
    SetFont Function
    GetFontOrientation Macro
    SetFontOrientation Macro
    OutChar Function
    OutText Function
    OutTextXY Function
    GetTextHeight Function
    GetTextWidth Function
    XCHAR Macro
Gradient
    BarGradient Function
    BevelGradient Function
    GFX_GRADIENT_TYPE Enumeration
    GFX_GRADIENT_STYLE Structure
Line Functions
    Line Function
    LineRel Macro
    LineTo Macro
    Thickness Macro
    SetLineType Macro
    Line Types
        SOLID_LINE Macro
        DASHED_LINE Macro
        DOTTED_LINE Macro
    Line Size
        NORMAL_LINE Macro
        THICK_LINE Macro
Rectangle Functions
    Bar Function
    Rectangle Macro
    DrawPoly Function
Circle Functions
    Circle Macro
    FillCircle Macro
    Arc Function
    Bevel Function
    FillBevel Function
    SetBevelDrawType Macro
Graphic Cursor
    GetX Macro
    GetY Macro
    MoveRel Macro
    MoveTo Macro
Bitmap Functions
    PutImage Function
    GetImageHeight Function
    GetImageWidth Function
    BITMAP_HEADER Structure
    Bitmap Settings
        IMAGE_NORMAL Macro
        IMAGE_X2 Macro
    Bitmap Source 


Aprenda a seguir como iniciar o seu programa para utilizar as funçoes da Graphics Primitive Layer da Microchip.

Parte do código foi retirado do programa de exemplo da Microchip: 
Microchip Graphics Library Application. 
MainDemo.c
MLA - Microchip_Solutions_v2013-06-15.
Graphics Primitives Layer Demo.


1 - Primeiramente vamos incluir no nosso projeto os arquivos .H das bibliotecas:


////////////////////////////// INCLUDES //////////////////////////////
    #include "Compiler.h"
    #include "GenericTypeDefs.h"
    #include "HardwareProfile.h"
    #include "Graphics/Graphics.h"
    #include "TimeDelay.h"
    #include "cpld.h"


2 - Depois adicionamos as declarações:


/////////////////////////////////////////////////////////////////////////////
//                            LOCAL PROTOTYPES
/////////////////////////////////////////////////////////////////////////////
void         InitializeBoard(void);          

/////////////////////////////////////////////////////////////////////////////
//                            FONTS
/////////////////////////////////////////////////////////////////////////////
extern const FONT_FLASH     Font25;
extern const FONT_FLASH     Font35;
extern const FONT_FLASH     Font35_Antialiased;
extern const XCHAR          AntialisedText[];

/////////////////////////////////////////////////////////////////////////////
//                            PICTURES
/////////////////////////////////////////////////////////////////////////////

extern const IMAGE_FLASH 	Sep_1BPP;
extern const IMAGE_FLASH        Sun8bit;
extern const IMAGE_FLASH        Gaming4bit;
extern const GFX_IMAGE_HEADER   Gaming4bit_RLE;
extern const GFX_IMAGE_HEADER   Sun8bit_RLE;
extern const GFX_IMAGE_HEADER 	raio_8bpp;
extern const GFX_IMAGE_HEADER 	SPFC_4BPP;
extern const GFX_IMAGE_HEADER 	bateria;

/////////////////////////////////////////////////////////////////////////////
//                            MACROS
/////////////////////////////////////////////////////////////////////////////
#define WAIT_UNTIL_FINISH(x)    while(!x)
#define MIN(x,y)                ((x > y)? y: x)
#define DEMODELAY		1000


3 - Aqui iniciamos nosso programa pela função MAIN:


/////////////////////////////////////////////////////////////////////////////
//                            MAIN
/////////////////////////////////////////////////////////////////////////////
int main(void)
{
    SHORT       width, height, temp, x1, y1, x2, y2;
    SHORT       counter;
    const SHORT polyPoints[] = {
        (GetMaxX()+1)/2,    (GetMaxY()+1)/4,
        (GetMaxX()+1)*3/4,  (GetMaxY()+1)/2,
        (GetMaxX()+1)/2,    (GetMaxY()+1)*3/4,
        (GetMaxX()+1)/4,    (GetMaxY()+1)/2,
        (GetMaxX()+1)/2,    (GetMaxY()+1)/4,
    };

    const SHORT poligonoPontos[] = {			//poligono 5 lados
        (GetMaxX()+1)/2,    (GetMaxY()+1)*2/7,
        (GetMaxX()+1)*6/8,  (GetMaxY()+1)*3/7,
        (GetMaxX()+1)*5/8,  (GetMaxY()+1)*5/7,
        (GetMaxX()+1)*3/8,  (GetMaxY()+1)*5/7,
        (GetMaxX()+1)*2/8,  (GetMaxY()+1)*3/7,
	(GetMaxX()+1)/2,    (GetMaxY()+1)*2/7,
    };

    
    // inicializa componentes de hardware e periféricos
    InitializeBoard();


4 - Pronto! 
Agora podemos utilizar as funçoes da Graphics Primitive Layer da Microchip.
Essa é parte mais legal do nosso blog.
Mãos a obra!
Veja como ficaram as minhas telas:

+++++++++++ Desenha MENSAGEM inicial na tela ++++++++++++++++++++++++++++


// desenha mensagem inicial na tela
        SetFont((void *) &Font25);
        SetColor(BRIGHTRED);
        width = GetTextWidth("Graphic Primitives Layer ", (void *) &Font25);
        height = GetTextHeight((void *) &Font25);

        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 2, "Graphic Primitives Layer ");

        SetColor(WHITE);
        width = GetTextWidth("Utilizando as Funcoes Basicas", (void *) &Font25);
        height = GetTextHeight((void *) &Font25);

        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 1, "Utilizando as Funcoes Basicas");





+++++++++++ PAUSAR e LIMPAR a TELA ++++++++++++++++++++++++++++

O código abaixo executa uma pausa de 4 segundos para permitir visualizar a imagem na tela, depois limpa o display com a cor preta para o fundo.


    DelayMs(4*DEMODELAY);
    SetColor(BLACK);
    ClearDevice();



+++++++++++ Função para desenhar TEXTO ++++++++++++++++++++++++++++



//funcao para desenhar TEXTO
		//WORD OutTextXY(SHORT x,SHORT y,XCHAR * textString);

        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Funcoes de Texto", (void *) &Font25);
        OutTextXY(
			(GetMaxX() - width) >> 1, 
			(GetMaxY() - height) >> 2, 
			"Funcoes de Texto");

		SetColor(BRIGHTGREEN);
		width = GetTextWidth("Fonte 25 Verde", (void *) &Font25);
		OutTextXY(
			(GetMaxX() - width) >> 1, 
			(GetMaxY() - height) >> 1, 
			"Fonte 25 Verde");

		SetFont((void *) &Font35);
		SetColor(BRIGHTBLUE);
	        height = GetTextHeight((void *) &Font35);
		width = GetTextWidth("Fonte 35 Azul", (void *) &Font35);
        OutTextXY(
			(GetMaxX() - width) >> 1, 
			3*((GetMaxY() - height) >> 2), 
			"Fonte 35 Azul");



+++++++++++ Funções para desenhar LINHA ++++++++++++++++++++++++++++



// funcoes para desenhar linha
	// WORD Line(SHORT x1,SHORT y1,SHORT x2,SHORT y2);

		// texto
        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Linha Normal-1 Pixel", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 3, "Linha Normal-1 Pixel");


		// desenha tipos de LINHAS NORMAIS
		SetLineThickness(NORMAL_LINE);  //1 pixel

		SetColor(BRIGHTRED);
		SetLineType(SOLID_LINE);
		WAIT_UNTIL_FINISH(
			Line(
				GetMaxX()>>2, 
				GetMaxY()>> 2, 
				3*(GetMaxX()>>2),
				GetMaxY()>> 2));

		SetColor(BRIGHTYELLOW);
		SetLineType(DOTTED_LINE);
		WAIT_UNTIL_FINISH(
			Line(GetMaxX()>>2, 
				GetMaxY()>> 1, 
				3*(GetMaxX()>>2),
				GetMaxY()>> 1));

		SetColor(BRIGHTGREEN);
		SetLineType(DASHED_LINE);
		WAIT_UNTIL_FINISH(
			Line(GetMaxX()>>2, 
				3*(GetMaxY()>> 2), 
				3*(GetMaxX()>>2),
				3*(GetMaxY()>> 2)));




+++++++++++ LINHA Grossa ++++++++++++++++++++++++++++



		// texto
        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Linha Grossa-3Pixels", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 3, "Linha Grossa-3Pixels");


		//desenha tipos de LINHAS GROSSAS
		SetLineThickness(THICK_LINE);  // 3 pixel

		SetColor(BRIGHTRED);
		SetLineType(SOLID_LINE);
		WAIT_UNTIL_FINISH(
			Line(GetMaxX()>>2, 
				GetMaxY()>> 2, 
				3*(GetMaxX()>>2),
				GetMaxY()>> 2));

		SetColor(BRIGHTYELLOW);
		SetLineType(DOTTED_LINE);
		WAIT_UNTIL_FINISH(
			Line(GetMaxX()>>2, 
				GetMaxY()>> 1, 
				3*(GetMaxX()>>2),
				GetMaxY()>> 1));

		SetColor(BRIGHTGREEN);
		SetLineType(DASHED_LINE);
		WAIT_UNTIL_FINISH(
			Line(GetMaxX()>>2, 
				3*(GetMaxY()>> 2), 
				3*(GetMaxX()>>2),
				3*(GetMaxY()>> 2)));



+++++++++++ Funções para desenhar RETÂNGULO ++++++++++++++++++++++++++++



// funcoes para desenhar retangulo
		// WORD Bar(SHORT left,SHORT top,SHORT right,SHORT bottom);
		// WORD DrawPoly(SHORT numPoints,SHORT * polyPoints);
				//SHORT polyPoints[numPoints] = {x0, y0, x1, y1, x2, y2 … xn, yn};
				//onde n = numero de Pontos - 1
		//Rectangle Macro
		// #define Rectangle(left, top, right, bottom) Bevel(left, top, right, bottom, 0)


		// texto
        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Retangulo", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 3, "Retangulo");


		// desenha RETANGULO
		SetLineType(SOLID_LINE);
		SetLineThickness(NORMAL_LINE);  //1 pixel
		SetColor(BRIGHTBLUE);
        WAIT_UNTIL_FINISH		
			(
				Bar(					//retangulo preenchido com funcao BAR
					GetMaxX() /4 - 30, 
					GetMaxY() / 2 - 60, 
					GetMaxX() / 4 + 30, 
					GetMaxY() / 2 + 60
					)
			);

		SetColor(BRIGHTYELLOW);
        WAIT_UNTIL_FINISH		
			(
				Rectangle(				//retangulo com Macro RECTANGLE
					(GetMaxX() / 4) * 3 - 30, 
					GetMaxY() / 2 - 60, 
					(GetMaxX() / 4)* 3  + 30, 
					GetMaxY() / 2 + 60
					)
			);



+++++++++++ POLIGONO 5 lados ++++++++++++++++++++++++++++



		// texto
        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Poligono", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 3, "Poligono");

			
		// desenha POLIGONO de 5 lados
		SetColor(BRIGHTRED);
		WAIT_UNTIL_FINISH(
			DrawPoly	(6, (SHORT *)poligonoPontos));



+++++++++++ Funções para desenhar CIRCULOS ++++++++++++++++++++++++++++



// Funcoes para desenhar CIRCULOS
		// WORD Arc(SHORT xL,SHORT yT,SHORT xR,SHORT yB,SHORT r1,SHORT r2,BYTE octant);
			//SHORT xL x location of the upper left center in the x,y coordinate.
			//SHORT yT y location of the upper left center in the x,y coordinate.
			//SHORT xR x location of the lower right center in the x,y coordinate.
			//SHORT yB y location of the lower right center in the x,y coordinate.
			//SHORT r1 The smaller radius of the two concentric cicles that defines the thickness of theobject.
			//SHORT r2 The larger of radius the two concentric circles that defines the thickness of theobject.
		//WORD Bevel(SHORT x1,SHORT y1,SHORT x2,SHORT y2,SHORT rad);
		//WORD FillBevel(SHORT x1,SHORT y1,SHORT x2,SHORT y2,SHORT rad);
				//SHORT rad defines the redius of the circle, that draws the rounded corners.

		//Circle Macro  #define Circle(x, y, radius) Bevel(x, y, x, y, radius)
				//x Center x position.
				//y Center y position.
				//radius the radius of the circle.
		//FillCircle Macro  #define FillCircle(x1, y1, rad) FillBevel(x1, y1, x1, y1, rad)
				//x1 x coordinate position of the center of the circle.
				//y1 y coordinate position of the center of the circle.
				//rad defines the redius of the circle.
		//SetBevelDrawType Macro	#define SetBevelDrawType(type) (_bevelDrawType = type)
				//• DRAWFULLBEVEL to draw the full shape
				//• DRAWTOPBEVEL to draw the upper half portion
				//• DRAWBOTTOMBEVEL to draw the lower half portion
	

		// texto
        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Circulo", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 3, "Circulo");	

		SetColor(BRIGHTRED);
		//Desenha CIRCULO
		WAIT_UNTIL_FINISH(
			Circle(
				GetMaxX() >> 2, 
				GetMaxY() >> 1, 
				50));	

	    SetColor(BRIGHTGREEN);
		//Desenha CIRCULO Preenchido
		WAIT_UNTIL_FINISH(
			FillCircle(
				3*(GetMaxX() >> 2),
 				GetMaxY() >> 1, 
				50));



+++++++++++ RETANGULO com borda grossa e arredondada +++++++++++++++++++++++++



		// texto
        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Funcao Arc", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 3, "Funcao Arc");	


		// desenha RETANGULO com borda grossa e arredondada
        SetColor(BRIGHTRED);
        WAIT_UNTIL_FINISH
        (
            Arc
                (
                    (GetMaxX() >> 2) - 25,		//xL
                    (GetMaxY() >> 1) - 25,		//xT
                    (GetMaxX() >> 2) + 25,		//yR
                    (GetMaxY() >> 1) + 25,		//yB
                    5,					//r1
                    10,					//r2
                    0xFF				//octant
                )
        );

		// desenha CIRCULO cheio no centro da tela
        SetColor(BRIGHTGREEN);
        WAIT_UNTIL_FINISH
        (
            Arc
                (
                    (GetMaxX() >> 1),		    //xL
                    (GetMaxY() >> 1),		    //xT
                    (GetMaxX() >> 1),		    //yR
                    (GetMaxY() >> 1),		    //yB
                    0,				    //r1
                    25,				    //r2
                    0xFF			    //octant
                )
        );

		// desenha RETANGULO
        SetColor(BRIGHTBLUE);
        WAIT_UNTIL_FINISH
        (
            Arc
                (
                    3*(GetMaxX() >> 2) - 25,	        //xL
                    (GetMaxY() >> 1) - 25,		//xT
                    3*(GetMaxX() >> 2) + 25,	        //yR
                    (GetMaxY() >> 1) + 25,		//yB
                    0,					//r1
                    0,					//r2
                    0xFF				//octant
                )
        );




+++++++++++ RETANGULO chanfrados (arredondados) ++++++++++++++++++++++++++++




		// texto
        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Funcao Bevel", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 3, "Funcao Bevel");


		// desenha RETANGULO chanfrados (arredondados) 
        SetColor(BRIGHTRED);
        WAIT_UNTIL_FINISH
		(
			Bevel
				(
					(GetMaxX() >> 2) - 25, 	//x1
					(GetMaxY() >> 1) - 25, 	//y1
					(GetMaxX() >> 2) + 25, 	//x2
					(GetMaxY() >> 1) + 25, 	//y2
					20			//rad
				)
		);

		// desenha CIRCULO no meio da tela
        SetColor(BRIGHTGREEN);
        WAIT_UNTIL_FINISH
		(
			Bevel
				(
					(GetMaxX() >> 1), 	//x1
					(GetMaxY() >> 1), 	//y1
					(GetMaxX() >> 1), 	//x2
					(GetMaxY() >> 1), 	//y2
					25			//rad
				)
		);   

		// desenha RETANGULO 
        SetColor(BRIGHTBLUE);
        WAIT_UNTIL_FINISH
		(
			Bevel
				(
					(GetMaxX() >> 2)*3 - 25, 	//x1
					(GetMaxY() >> 1) - 25, 		//y1
					(GetMaxX() >> 2)*3 + 25, 	//x2
					(GetMaxY() >> 1) + 25, 		//y2
					0				//rad
				)
		);     



+++++++++++ RETANGULO chanfrados (arredondados) cheio ++++++++++++++++++++++



		// texto
        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Funcao FillBevel", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 3, "Funcao FillBevel");


		// desenha RETANGULO chanfrados (arredondados) cheio
        SetColor(BRIGHTRED);
        WAIT_UNTIL_FINISH
		(
			FillBevel
				(
					(GetMaxX() >> 2) - 25, 	//x1
					(GetMaxY() >> 1) - 25, 	//y1
					(GetMaxX() >> 2) + 25, 	//x2
					(GetMaxY() >> 1) + 25, 	//y2
					20			//rad
				)
		);

		// desenha CIRCULO cheio no meio da tela
        SetColor(BRIGHTGREEN);
        WAIT_UNTIL_FINISH
		(
			FillBevel
				(
					(GetMaxX() >> 1), 	//x1
					(GetMaxY() >> 1), 	//y1
					(GetMaxX() >> 1), 	//x2
					(GetMaxY() >> 1), 	//y2
					25			//rad
				)
		);   

		// desenha RETANGULO cheio
        SetColor(BRIGHTBLUE);
        WAIT_UNTIL_FINISH
		(
			FillBevel
				(
					(GetMaxX() >> 2)*3 - 25, 	//x1
					(GetMaxY() >> 1) - 25, 		//y1
					(GetMaxX() >> 2)*3 + 25, 	//x2
					(GetMaxY() >> 1) + 25, 		//y2
					0							//rad
				)
		);     




+++++++++++ Funções para GRADIENT ++++++++++++++++++++++++++++



// Funcoes para Gradient
		//WORD BarGradient(SHORT left,SHORT top,SHORT right,SHORT bottom,GFX_COLOR color1,GFX_COLOR color2,DWORD length,BYTE direction);
			//From 0-100%. How much of a gradient is wanted

		//WORD BevelGradient(SHORT left,SHORT top,SHORT right,SHORT bottom,SHORT rad,GFX_COLOR color1,GFX_COLOR color2,DWORD length,BYTE direction);
		
		//GFX_GRADIENT_TYPE Enumeration
			//GRAD_NONE = 0 No Gradients ( see page 361) to be drawn
			//GRAD_DOWN gradient changes in the vertical direction
			//GRAD_RIGHT gradient change in the horizontal direction
			//GRAD_UP gradient changes in the vertical direction
			//GRAD_LEFT gradient change in the horizontal direction
			//GRAD_DOUBLE_VER two gradient transitions in the vertical direction
			//GRAD_DOUBLE_HOR two gradient transitions in the horizontal direction

		// texto
        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Funcao BarGradient", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 3, "Funcao BarGradient");


		BarGradient		//11
			(
				(GetMaxX() >> 2) - 20, 		//x1
				(GetMaxY() >> 2)*3/2 - 20, 	//y1
				(GetMaxX() >> 2) + 20, 		//x2
				(GetMaxY() >> 2)*3/2 + 20, 	//y2
				BRIGHTRED, 			//color1
				BRIGHTBLUE, 			//color2
				100, 				//lenght
				GRAD_DOWN			//direction
			);
        while(IsDeviceBusy());

		BarGradient		//12
			(
				(GetMaxX() >> 1) - 20, 		//x1
				(GetMaxY() >> 2)*3/2 - 20, 	//y1
				(GetMaxX() >> 1) + 20, 		//x2
				(GetMaxY() >> 2)*3/2 + 20, 	//y2
				BRIGHTRED, 			//color1
				BRIGHTBLUE, 			//color2
				100, 				//lenght
				GRAD_RIGHT			//direction
			);
        while(IsDeviceBusy());

		BarGradient		//13
			(
				(GetMaxX() >> 2)*3 - 20, 	//x1
				(GetMaxY() >> 2)*3/2 - 20, 	//y1
				(GetMaxX() >> 2)*3 + 20, 	//x2
				(GetMaxY() >> 2)*3/2 + 20, 	//y2
				BRIGHTRED, 			//color1
				BRIGHTBLUE, 			//color2
				100, 				//lenght
				GRAD_UP				//direction
			);
        while(IsDeviceBusy());

		BarGradient		//21
			(
				(GetMaxX() >> 2) - 20, 		//x1
				(GetMaxY() >> 2)*3 - 20, 	//y1
				(GetMaxX() >> 2) + 20, 		//x2
				(GetMaxY() >> 2)*3 + 20, 	//y2
				BRIGHTRED, 			//color1
				BRIGHTBLUE, 			//color2
				100, 				//lenght
				GRAD_LEFT			//direction
			);
        while(IsDeviceBusy());

		BarGradient		//22
			(
				(GetMaxX() >> 1) - 20, 		//x1
				(GetMaxY() >> 2)*3 - 20, 	//y1
				(GetMaxX() >> 1) + 20, 		//x2
				(GetMaxY() >> 2)*3 + 20, 	//y2
				BRIGHTRED, 			//color1
				BRIGHTBLUE, 			//color2
				100, 				//lenght
				GRAD_DOUBLE_VER			//direction
			);
        while(IsDeviceBusy());

		BarGradient		//23
			(
				(GetMaxX() >> 2)*3 - 20, 	//x1
				(GetMaxY() >> 2)*3 - 20, 	//y1
				(GetMaxX() >> 2)*3 + 20, 	//x2
				(GetMaxY() >> 2)*3 + 20, 	//y2
				BRIGHTRED, 			//color1
				BRIGHTBLUE, 			//color2
				100, 				//lenght
				GRAD_DOUBLE_HOR			//direction
			);
        while(IsDeviceBusy());





+++++++++++ GRADIENT  arredondado ++++++++++++++++++++++++++++



		// texto
        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Funcao BevelGradient", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 3, "Funcao BevelGradient");


		BevelGradient		//11
			(
				(GetMaxX() >> 2) - 20, 		//x1
				(GetMaxY() >> 2)*3/2 - 20, 	//y1
				(GetMaxX() >> 2) + 20, 		//x2
				(GetMaxY() >> 2)*3/2 + 20, 	//y2
				10,				//rad
				BRIGHTRED, 			//color1
				BRIGHTBLUE, 			//color2
				100, 				//lenght
				GRAD_DOWN			//direction
			);
        while(IsDeviceBusy());

		BevelGradient		//12
			(
				(GetMaxX() >> 1) - 20, 	//x1
				(GetMaxY() >> 2)*3/2 - 20, 	//y1
				(GetMaxX() >> 1) + 20, 	//x2
				(GetMaxY() >> 2)*3/2 + 20, 	//y2
				10,				//rad
				BRIGHTRED, 			//color1
				BRIGHTBLUE, 			//color2
				100, 				//lenght
				GRAD_RIGHT			//direction
			);
        while(IsDeviceBusy());

		BevelGradient		//13
			(
				(GetMaxX() >> 2)*3 - 20, 	//x1
				(GetMaxY() >> 2)*3/2 - 20, 	//y1
				(GetMaxX() >> 2)*3 + 20, 	//x2
				(GetMaxY() >> 2)*3/2 + 20, 	//y2
				10,				//rad
				BRIGHTRED, 			//color1
				BRIGHTBLUE, 			//color2
				100, 				//lenght
				GRAD_UP				//direction
			);
        while(IsDeviceBusy());

		BevelGradient	//21
			(
				(GetMaxX() >> 2) - 20, 	//x1
				(GetMaxY() >> 2)*3 - 20, 	//y1
				(GetMaxX() >> 2) + 20, 	//x2
				(GetMaxY() >> 2)*3 + 20, 	//y2
				10,				//rad
				BRIGHTRED, 			//color1
				BRIGHTBLUE, 			//color2
				100, 				//lenght
				GRAD_LEFT			//direction
			);
        while(IsDeviceBusy());

		BevelGradient		//22
			(
				(GetMaxX() >> 1) - 20, 	//x1
				(GetMaxY() >> 2)*3 - 20, 	//y1
				(GetMaxX() >> 1) + 20, 	//x2
				(GetMaxY() >> 2)*3 + 20, 	//y2
				10,				//rad
				BRIGHTRED, 			//color1
				BRIGHTBLUE, 			//color2
				100, 				//lenght
				GRAD_DOUBLE_VER			//direction
			);
        while(IsDeviceBusy());

		BevelGradient		//23
			(
				(GetMaxX() >> 2)*3 - 20, 	//x1
				(GetMaxY() >> 2)*3 - 20, 	//y1
				(GetMaxX() >> 2)*3 + 20, 	//x2
				(GetMaxY() >> 2)*3 + 20, 	//y2
				10,				//rad
				BRIGHTRED, 			//color1
				BRIGHTBLUE, 			//color2
				100, 				//lenght
				GRAD_DOUBLE_HOR			//direction
			);
        while(IsDeviceBusy());





+++++++++++ Função para desenhar IMAGEM BITMAP 1 BPP - Preto & Branco +++++++++



// Funcao para desenhar IMAGEM BITMAP
		//WORD PutImage(SHORT left,SHORT top,void * bitmap,BYTE stretch);
				//IMAGE_NORMAL - Normal image stretch code
				//IMAGE_X2 - Stretched image stretch code
		//SHORT GetImageHeight(void * bitmap);
		//SHORT GetImageWidth(void * bitmap);

		// texto
        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Imagem 1 BPP", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 3, "Imagem 1 BPP");

	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("51x56  402 bytes", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, ((GetMaxY() - height) >> 3)*7, "51x56  402 bytes");


		// desenha figura na tela 1 BPP bitmap,  402 bytes, 51x56
		height = GetImageHeight((void *) &Sep_1BPP);
        width = GetImageWidth((void *) &Sep_1BPP);
        WAIT_UNTIL_FINISH
			(
				PutImage
					(
						(GetMaxX() - width*2) >> 1,	//left
						(GetMaxY() - height*2) >> 1, 	//top
						(void *) &Sep_1BPP, 		//* bitmap
						IMAGE_X2						//stretch
					)
			);





+++++++++++ IMAGEM BITMAP 4 BPP ++++++++++++++++++++++++++++



		// texto
        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Imagem 4 BPP Comprimida", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 3, "Imagem 4 BPP Comprimida");

	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("108x112 6086 => 2072 bytes", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, ((GetMaxY() - height) >> 3)*7, "108x112 6086 => 2072 bytes");


		// desenha figura na tela 4 BPP bitmap,  2072 bytes, 108x112
	height = GetImageHeight((void *) &SPFC_4BPP);
        width = GetImageWidth((void *) &SPFC_4BPP);
        WAIT_UNTIL_FINISH
			(
				PutImage
					(
						(GetMaxX() - width) >> 1,		//left
						(GetMaxY() - height) >> 1, 		//top
						(void *) &SPFC_4BPP, 			//* bitmap
						IMAGE_NORMAL				//stretch
					)
			);






+++++++++++ IMAGEM BITMAP 8 BPP ++++++++++++++++++++++++++++



		// texto
        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Imagem 8 BPP Comprimida", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 3, "Imagem 8 BPP Comprimida");

	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("99x99 10319 => 5112 bytes", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, ((GetMaxY() - height) >> 3)*7, "99x99 10319 => 5112 bytes");


		// desenha figura na tela 4 BPP bitmap,  99x99 10319 => 5112 bytes
	height = GetImageHeight((void *) &raio_8bpp);
        width = GetImageWidth((void *) &raio_8bpp);
        WAIT_UNTIL_FINISH
			(
				PutImage
					(
						(GetMaxX() - width) >> 1,		//left
						(GetMaxY() - height) >> 1, 		//top
						(void *) &raio_8bpp, 			//* bitmap
						IMAGE_NORMAL				//stretch
					)
			);






+++++++++++ IMAGEM BITMAP 16 BPP ++++++++++++++++++++++++++++



		// texto
        SetFont((void *) &Font25);
        SetColor(WHITE);
	height = GetTextHeight((void *) &Font25);
        width = GetTextWidth("Imagem 16 BPP 110x81 17kB", (void *) &Font25);
        OutTextXY((GetMaxX() - width) >> 1, (GetMaxY() - height) >> 4, "Imagem 16 BPP 110x81 17kB");


		// desenha figura na tela 4 BPP bitmap,  99x99 10319 => 5112 bytes
	height = GetImageHeight((void *) &bateria);
        width = GetImageWidth((void *) &bateria);
        WAIT_UNTIL_FINISH
			(
				PutImage
					(
						(GetMaxX() - width*2) >> 1,		//left
						((GetMaxY() - height*2) >> 1)+10, 	//top
						(void *) &bateria, 			//* bitmap
						IMAGE_X2				//stretch
					)
			);








 
Assista ao vídeo para ver o resultado do meu programa de exemplo para treino das funções da Graphics Primitive Layer da Microchip.

CRIE seu programa também! 
A sua imaginação é o seu limite!


Vídeo 1 - PIC32 + GOL - Graphics Primitive Layer - Funções Básicas

Referencias:

MICROCHIP web site: www.microchip.com

MICROCHIP - Graphics Library Application. MLA - Microchip_Solutions_v2013-06-15.
Graphics Primitives Layer Demo.  

terça-feira, 11 de setembro de 2018

Display de Mensagem com MAX7219 Matriz de LEDs 4x8x8 (8x32)




Olá pessoal!!!           
Bora aprender a usar um display de LEDs?
Dá pra montar um montão de coisas legais!        :)



Quer montar um display de mensagens com Matriz de LEDs?

Este post contém algumas informações de como utilizar o display matriz de LEDs 8x8 para os seus projetos com Arduino, PIC e o controlador de display MAX7219.
No final você encontra os vídeos de algumas aplicações interessantes para o display Matriz de LEDs como um display de mensagem rolante, demonstração dos recursos da biblioteca C para MAX7219, o Jogo do Tetris e um Relógio Digital!


O Display Matriz de LEDs 8x8

Como o próprio nome diz este tipo de display é composto por uma matriz de LEDs.
A Figura 1 mostra um display com a matriz 8x8, um dos mais comuns utilizados nos projetos e encontrados no mercado. Na esquerda vemos a parte frontal do display e a direita a parte de trás com os terminais para a ligação à placa de circuito impresso - PCI (PCB).

Figura 1 - Display Matriz de LEDs 8x8: frente e verso.

O diagrama da Figura 2 mostra a interligação interna dos LEDs do display Matriz de LEDs 8x8, modelo 1088AS. Observe que existem 8 colunas, 8 linhas e o display é do tipo "catodo comum" conforme a ligação dos LEDs. O diagrama mostra o pino (pin) correspondente para cada coluna e linha (column/row) do display.

Figura 2 - Diagrama de interligação interno e pinos do Display Matriz de LEDs 8x8.

Como faço para acender os LEDs do display?
 
Bem, para acender 1 LED basta aplicar uma tensão positiva (exemplo 5 Vcc) no pino da coluna correspondente ao LED que se quer acender, com um resistor em série para limitar a corrente do LED, e aterrar o pino da linha do LED que se quer acender. Por exemplo, para o LED11 (primeira coluna e primeira linha) basta aplicar a tensão com o resistor no pino 13 do display e aterrar o pino 9. Exatamente como se faz para acender 1 único LED.

No entanto para acender diversos LEDs do display não podemos aplicar a tensão em todas as colunas e aterrar todas as linhas. O acionamento deve ser feito por etapas, ligando 1 linha por vez. Esse processo é chamado de multiplexação. O chaveamento entre as linhas é feito tão rápido que o olho humano é incapaz de perceber a comutação entre as linhas para uma frequência superior a 20 Hz, devido ao fenômeno da cintilação.

Para o processo de multiplexação das linhas do display podemos utilizar um microcontrolador (uC).

Na Figura 3 é mostrada a forma mais simples de ligar um display matriz de LEDs 8x8, interligando os terminais das 8 linhas e 8 colunas do display diretamente aos terminais do microcontrolador. 
Note que gastamos 16 pinos do microcontrolador para ligar apenas 1 display de matriz 8x8! Portanto se desejamos ligar 2 display utilizaremos 32 pinos de I/O!!
Por este motivo esta configuração é recomendada apenas para circuitos simples.
Você pode utilizar qualquer microcontrolador: PIC, 8051, Arduino, etc... desde que o pino de I/O suporte a corrente dos LEDs.
Ah.. e não se esqueça de ligar os resistores em série para limitar a corrente!


Figura 3 - Diagrama para ligar diretamente o microcontrolador ao Display Matriz de LEDs 8x8.

Para reduzir o número de pinos de I/O do microcontrolador  podemos utilizar o circuito integrado (CI) 74HC164 (CMOS 2 V a 6 V) ou 74HCT164 (TTL 4,5 V a 5,5 V).
O 74HC164 é um 8-bit serial-in/parallel-out shift register. Com ele conseguimos com apenas 3 pinos de I/O do uC, comandar 8 saídas  do shift register e ainda ligar vários 74HC164 em série (cascata) para podermos ligar vários displays de Matriz de LEDs!

A Figura 4 mostra um diagrama para ligar 2 displays Matriz de LEDs 8x8 utilizando o 74HC164 (um para cada display). 

Os terminais para o controle das saídas são:
CP - clock input (LOW-to-HIGH, edge-triggered)
MR - master reset input (active LOW)
DSA/DSB - data input. 
Q0 - Q7: parallel data output

Obs.: o pino  Q7 é utilizado para a ligação em série/cascata de vários 74HC164 para ligar vários displays!

Resumidamente: os dados são enviados para a saída na forma serial, mantendo os dados no pino DSA/DSB e gerandode pulsos no pino CP.
Uma grande desvantagem do 74HC164 é que necessitamos manter as saídas em nível baixo, pelo pino de reset MR, até transmitir todos os dados seriais. Somente após todos os dados serem transferidos é que habilitamos as saídas para mostrar a mensagem no display. Caso contrário iremos ver os LEDs se deslocando no display.
Este período de todos os LEDs desligados até o final da transmissão de todos os dados na forma serial faz com que os LEDs fiquem ligados por pouco tempo, isto representa um brilho menor do display.
Para reduzir a cintilação, ou seja, o olho humano perceber as linhas do display piscando, devido a multiplexação, o seu circuito deve ter um microcontrolador mais rápido (velocidade de processamento maior).
 
O CI ULN2803 foi utilizado como drive de corrente para aterrar as linhas de catodo comum dos displays. Caso o seu uC suporte a corrente drenada pelos LEDs, este CI pode ser retirado. 
Não esqueça dos resistores em série com as 8 colunas de cada display!

Figura 4 - Ligando a Matriz de LEDs com 74HC164.


A Figura 5 mostra uma melhoria para o circuito agora utilizando o CI 74HC595 (ou 74HCT595).
O  74HC595 é um 8-bit serial-in/serial or parallel-out shift register with output latches 3-state. 
Parece a mesma função do CI anterior, mas o "latch" das saídas faz toda a diferença neste caso, porque o estado da saída se mantém enquanto enviamos os dados seriais para o registrador interno do 74HC595 e os mesmos são transferidos para a saída com um pulso no pino ST.

Os pinos de controle são: 
SH: shift register clock input
ST: storage register clock input
DS: serial data input
Q0 - Q7: parallel data output
Q7': serial data output
OE: output enable (active LOW)
MR: master reset (active LOW)

Obs.: o pino  Q7' é utilizado para a ligação em série/cascata de vários 74HC795 para ligar vários displays!


Figura 5 - Ligando a Matriz de LEDs com 74HC595.


Você está achando tudo isso muito complicado??

Que tal substituirmos os shift registers, os resistores e o drive de corrente por um único CI?
Sim! Isto é possível! Alguém já teve esta grande ideia ou cansou de tanto circuito externo só pra ligar um display de LEDs... :)


O Controlador de display MAX7219


 Figura 6 - Diagrama de pinos do MAX7219 e circuito com aplicação típica. Fonte: datasheet MAXIM.




  Figura 7 - Diagrama de interligação entre Microcontrolador, MAX7219 e display Matriz de LEDs 8x8.


 Figura 8 - Módulo FC-16 com 4 display 8x8 Matriz de LEDs e 4 MAX7219.



 Figura 9 -Diagrama para interligar 4 módulos MAX7219.



Figura 10 - Módulo FC-16 com 4 display 8x8 Matriz de LEDs e MAX7219: frente.


Figura 11 - Módulo FC-16 com 4 display 8x8 Matriz de LEDs e MAX7219: verso.


Figura 12 - Montagem no Proteus com 4 display 8x8 Matriz de LEDs e MAX7219.



Figura 13 - Montagem no protoboard do módulo FC-16 4x8x8 Matriz de LEDs.



Display de Mensagem com Matriz de LEDs 4x8x8, MAX7219 e Arduino Promini


Quer montar um Display de Mensagem com seu Arduino?


Componentes e recursos:

Arduino Pro Mini
Atmel Microcontroller Atmega328
MAX7219 Library in C ++ Linguage by Marco Colli
Configurable Number of Devices MAX7219
FC-16 display module (4x8x8)
MAX7219 Display Controller
8x8 dot LED Matrix Display
Scrolling Text Speed Variable


Figura 14 -Módulo Arduino Promini.


Figura 15 -Arduino Promini e conversor USB/Serial: frente e verso.



Figura 16 -Arduino Promini montado no protoboard.



Figura 17 - Arduino Promini com o conversor USB/Serial montado no protoboard.


Figura 18 -Arduino Promini, PIC18F4550 e Display matriz de LEDs no protoboard.


Figura 19 - Primeira mensagem com o display Matriz de LEDs 4x8x8 (8x32).



Source Code:
MD_MAX72xx LED Matrix Display Library by Marco Colli.: https://github.com/MajicDesigns/MD_MA...
Example code: MD_MAX72xx_Message

Change the message in MD_MAX72xx_Message.ino
void setup()
strcpy(curMessage, "Hello! ");

Configure number of the MAX7219 devices:
#define MAX_DEVICES            4.

Change config display type in MD_MAX72xx.h for use FC-16 Module:
#define USE_PAROLA_HW       0
#define USE_FC16_HW             1


Video 1 - Arduino MAX7219 Dot LED Matriz 4x8x8 (8x32) FC-16.




Display de Mensagem com Matriz de LEds 4x8x8, MAX7219 e PIC18F4550


Microchip PIC Microcontroller
Microcontroller PIC18F4550
MPLAB IDE and MPLAB C18 Compiler
Configurable Number of Devices MAX7219
FC-16 display module (4x8x8)
MAX7219 Display Controller
8x8 dot LED Matrix
Display Display Brightness Control
Scrolling Text Speed Variable
5x7 Font Table ' ' to '~'
Simulation in Proteus 8



Video 2 - PIC18F MAX7219 Dot LED Matriz 4x8x8 (8x32) FC-16 Module Scrolling Text.



Figura 20 - Mensagem rolante com display Matriz de LEDs 4x8x8 (8x32).


Video 3 -PIC18F MAX7219 C Library Demonstration 4x8x8 LED.

Biblioteca em Linguagem C para MAX7219 com PIC18F4550 e Módulo FC-16 Matriz de LEDs 4x8x8 (8x32).


Recursos da biblioteca:

Microchip PIC Microcontroller
Microcontroller PIC18F4550 with USB Bootloader
MPLAB IDE and MPLAB C18 Compiler
Configurable Number of Devices MAX7219
MAX7219 C Library (not C++)
FC-16 display module (4x8x8)
MAX7219 Display Controller
8x8 dot LED Matrix Display
5x7 fixed characters Font Table ' ' to '~' or
Variable width characters Font Table 0x00 to 0xFF
Strings in program memory
Show drawings in the display 00:05 03:28
Static Text 00:12
Scroling Text (not Circular or Circular) 00:22 00:32 Shift Register Left, Right, Up and Down (not Circular or Circular) 00:52 01:08
Display Brightness Control 01:30
Scrolling Text Speed Variable 02:05
Message 1 02:54
Message 2 03:09

O Jogo do Tetris com display Matriz de LEDs 4x8x8 (8x32)

E agora que você já sabe ligar um display Matriz de LEDs 8x8...que tal montar seu próprio jogo do Tetris???



C Library MAX7219 with PIC18F4550 and FC-16 Module LED Matrix 4x8x8 (8x32).

Resources:
- standard Tetris pieces: O, I, S, Z, L, J and T;
- Tetris board: 20 lines x 8 columns;
- color: monochrome block (red);
- game record storage in internal EEPROM memory;
- Tetris falling iteration delay: 0.5 sec
- 0.15 sec; - standard Tetris score;
- 8 difficulty Levels (LED Bargraph);
- show level, score and record in the LED Matrix Display;.
- randomizes pieces with Timer4 (not used random function of the C Language).



Figura 21 - Jogo do Tetris com display Matriz de LEDs 4x8x8 (8x32).

Hardware:
- PIC18F4550.
- 4 MAX7219 Display Controller.
- 4x8x8 dot LED Matrix Display.

Software:
- MPLAB IDE v8.83.
- MPLAB C18 Compiler.

Firmware:
- MAX7219 Library.


Figura 22 - Imagem do jogo Tetris com display Matriz de LEDs 4x8x8 (8x32).



Video 4 - Jogo do Tetris com display Matriz de LEDs 4x8x8 (8x32).



Alexey Pajitnov created the first electronic version of Tetris in 1985 in Russia.



References:

FAHEY, Colin. Standard Tetris. History of Tetris. Tetris A.I. system. 2003-2012.
Available in: http://colinfahey.com/tetris/tetris.html.


Relógio com display Matriz de LEDs 4x8x8 (8x32) e RTCC DS1302


Um relógio digital com PIC18F e Matriz de LEDs!


Figura 23 - Relógio com display Matriz de LEDs 4x8x8 (8x32) e RTCC DS1302.

Recursos:
- Hora.
- Data.
- Mensagem rolante: Bom Dia/Boa Tarde/Boa Noite.
- Buzzer para Alarme/Despertador.
- 4 Botões para ajuste da data/hora, dia da semana, hora do alarme e brilho do display.
- Display Matriz de LEDs 4x8x8 (8x32).
- Bateria de backup do RTCC (mantém o relógio rodando quando falta energia AC).



Figura 24 - Diagrama no Proteus do Relógio com Matriz de LEDs.

Hardware:
- PIC18F4550.
- 4 MAX7219 Display Controller.
- 4x8x8 dot LED Matrix Display.
- RTCC DS1302.

Software:
- MPLAB IDE v8.83.
- MPLAB C18 Compiler.

Firmware:
- MAX7219 Library.
- DS1302 Library.


Figura 25 - Simulação do Proteus: pulsos digitais do RTCC DS1302.


Figura 26 - Data mostrada pelo relógio de Matriz de LEDs.



Figura 27 - Hora mostrada pelo relógio de Matriz de LEDs.



Video 5 - Relógio com display Matriz de LEDs 4x8x8 (8x32) e RTCC DS1302.





Estes foram os meus projetos.
Agora é a sua vez de criar os seus programas!
Use a sua criatividade!

Até mais pessoal!!!


domingo, 15 de março de 2015

Como Utilizar a FFT com o PIC32MX - DSP Library

Neste post você encontra informações de como utilizar a Fast Fourier Transformer (FFT) em seu projeto com PIC32MX.

A família de microcontroladores PIC32MX não possui instruções de DSP. Operações de DSP estão disponíveis na família PIC32MZ. Aqui iremos apresentar a utilização da função mips_fft16 ( ) disponível na biblioteca DSP Library para o PIC32MX. Utilizaremos a linguagem C com o compilador MPLAB XC32 no ambiente de desenvolvimento MPLAB X.

Não entraremos em detalhes da teoria da Transformada Rápida de Fourier - FFT. Partiremos direto para a utilização da função mips_fft16 ( ). Para saber mais sobre a FFT você pode acessar estes posts: "Como Utilizar a FFT com o dsPIC - DSP Library" e "FFT-PIC - Um Analisador de Espectro para a Rede de Energia Elétrica ".


No início do nosso projeto devemos incluir os headers "dsplib_dsp.h" e "fftc.h" da biblioteca DSP, conforme mostra o Código 1. O arquivo "fftc.h" contém os coeficientes utilizados nos cálculos da FFT.


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include <p32xxxx.h>
#include <xc.h>         // comentar esta linha para usar o MPLAB C32
#include <plib.h>

#include "dsplib_dsp.h"
#include "fftc.h"

Código 1 - Incluindo headers da DSP Library ao projeto.

Para o nosso projeto temos que definir o número de "pontos" da FFT, conforme o Código 2.


/*         FFT com 128 pontos       */

#define N    128        // N = 2^7 = 128

#define fftc fft16c128  // from fftc.h, for N = 128

Código 2 - Define 128 pontos da FFT.

128 amostras no domínio do tempo (lidas pelo conversor analógico-digital, por exemplo), se transformarão em 64 pontos no domínio da frequência.

Dados da FFT deste exemplo:
- Frequência de amostragem (Fs): 7,68 ksps;
- Pontos da FFT: 128;
- log2 (N) = 7;
- Passo entre as frequências (Fo): 60 Hz.
A frequência de amostragem (Fs) do sinal de entrada irá determinar o espaçamento entre as frequências de cada ponto de saída (Fo).

A frequência de amostragem (Fs) do nosso sinal gerado (a onda quadrada) é de 7680 Hz, portanto Fo é 60 Hz, ou seja, 7680 sps / 128 pontos da FFT!

Isto quer dizer que temos na saída o valor do espectro das frequências múltiplas de 60 Hz, de 0 à 3840 Hz (60 Hz * 64 pontos no domínio da frequência).

Para o sinal de entrada que será aplicado a FFT iremos utilizar um vetor com dados de uma onda quadrada de 780 Hz e frequência de amostragem 7680 Hz. Esta onda foi gerada com o auxílio do Software dsPICworks, da Microchip. Para mais informações de como gerar este vetor de dados acesse "Como Utilizar a FFT com o dsPIC - DSP Library". O vetor sinal_Entrada [ ] do tipo int16, com 128 amostragens é visto no Código 3.



int16 sinal_Entrada [128]= {                   //vetor que ira armazenar os dados de entrada
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,        //valores iniciais declarados para simulacao
0x8001, 0x8001, 0x8001, 0x8001, 0x8001,        //e teste do programa
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,        //square signal 780 Hz, 7680 sps, -1.0 a +1.0
0x8001, 0x8001, 0x8001, 0x8001, 0x8001,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x8001, 0x8001, 0x8001, 0x8001, 0x8001,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x8001, 0x8001, 0x8001, 0x8001, 0x8001,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x8001, 0x8001, 0x8001, 0x8001, 0x8001,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x8001, 0x8001, 0x8001, 0x8001, 0x8001,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x8001, 0x8001, 0x8001, 0x8001, 0x8001,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x8001, 0x8001, 0x8001, 0x8001, 0x8001,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x8001, 0x8001, 0x8001, 0x8001, 0x8001,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x8001, 0x8001, 0x8001, 0x8001, 0x8001,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x8001, 0x8001, 0x8001, 0x8001, 0x8001,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x8001, 0x8001, 0x8001, 0x8001, 0x8001,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x8001, 0x8001, 0x8001};

 
Código 3 - Vetor com dados de entrada para a simulação e cálculo da FFT.

 A seguir precisamos declarar os vetores e variáveis utilizadas para o cálculo da função mips_fft16 ( ), conforme o Código 4.



    int log2N = 7;      // log2(128) = 7        N = 128 = (1<<log2N)     N = 2^7 = 128
    int16c din[N];
    int16c dout[N];
    int16c scratch[N];
    int16c *p_fftc = &fftc;
Código 4 - Declaração das variáveis utilizadas no cálculo da FFT.


Os vetores utilizados pela função mips_fft16 ( ) são do tipo int16c, ou seja, inteiro 16-bit complexo, com partes real e imaginária.

No início da função main ( ) iremos transferir os coeficientes para o cálculo da FFT, conhecidos como Twiddle Factors, da memória de programa para a memória RAM, para execução mais rápida do cálculo. Veja o Código 5.


    p_fftc = &fftc;                      //inicializa ponteiro

    for (i = 0; i < N / 2; i++)          //move twiddleFactors da flash para a RAM
    {
        twiddleFactors [i] = *p_fftc;
        *p_fftc++;                       //incrementa o ponteiro
    }


Código 5 - Movendo os coeficientes para a memória RAM.


Agora podemos partir para um loop while onde continuamente o PIC32 irá mover os dados contidos no vetor sinal_Entrada [ ] para o vetor din [ ] e limitar a escala entre -0.5 e +0.5. Note que sinal_Entrada [ ] pode conter dados vindos de um conversor analógico-digital ADC, por exemplo, e din [ ] é o vetor com dados complexos utilizados nos cálculos da FFT.

   while (TRUE) {

        //move buffer do sinal de entrada (real)para vetor da FFT (complexo)
        for (i = 0; i < N; i++)
        {
            din[i].re = sinal_Entrada [i];  //parte real
            din[i].im = 0;                  //parte imaginaria
            din[i].re = din[i].re >> 1;     //divide pela metade, escalona para -0.5 a +0.5
        }
          
        ...

  
Código 6 - Preparando o vetor de dados complexos de entrada para os cálculos da FFT.


A chamada para a função mips_fft16 ( ), que aplica a Transformada Rápida de Fourier ao sinal, é mostrada no Código 7. Detalhes sobre os argumentos desta função você encontra em "PIC32 DSP Library".


        // Executa o Calculo da FFT
        mips_fft16 (dout, din, twiddleFactors, scratch, log2N);


Código 7 - Cálculo da FFT.


O resultado da FFT está contido no vetor complexo dout [ ].

Para exibir o resultado gráfico da FFT comumente se computa o single sided FFT, a magnitude quadrática do espectro de frequência, ou o módulo do número complexo. O Código 8 apresenta as fórmulas que devem ser aplicadas a cada posição do vetor de dados.



        /*     Computa o single sided FFT    */
        // Calcula a soma do quadrado das partes real e imaginária transformando vetor complexo em um vetor real.
  
        square_Magnitude = parte_Real^2 + parte_Imaginaria^2
        

        /*          Calcula o Modulo         */
        // Extrai a raiz quadrada da soma dos quadrados da parte real e imaginaria
        
        modulo = sqrtf(parte_Real^2 + parte_Imaginaria^2)  

        
  
Código 8 - Cálculo da magnitude quadrática do resultado da FFT.


Por fim, podemos calcular o espectro da frequência de maior magnitude do sinal amostrado, conforme exemplificado no Código 9.



  
       // Encontra a frequency Bin ( indice da frequencia) que possui a maior energia
        picoFrequenciaBin = vectorMaxBin (PONTOS_FFT/2,squareMagnitude);

        // Calcula a frequencia em Hz com maior espectro
        picoFrequencia = picoFrequenciaBin*(SAMPLING_FREQ/PONTOS_FFT);

Código 9 - Cálculo do espectro da frequência de maior magnitude.


O programa agora pode ser testado.


Para confirmar se o seu projeto está correto, verifique se a variável picoFrequencia apresenta o valor de 780 [Hz] após os cálculos. Esta é a frequência da onda quadrada gerada no dsPICwork para a simulação dos cálculos da FFT.

A posição do vetor com o espectro de frequência de maior valor é SquareMagnitude [13].

Veja os cálculos finais:

Fs               /    PONTOS_FFT              =      Fo
7680 sps    /     128 pontos da FFT         =     60 Hz

60 Hz * [13]       =        780 Hz!


O Vídeo 1 mostra este código rodando no MPLAB X em modo simulação passo-a-passo.


Vídeo 1 - Simulação dos cálculos da FFT com o PIC32MX.



O Vídeo 2 mostra uma aplicação da FFT com o PIC32MX para a identificação da frequência de um sinal. O display gráfico mostra os dados do vetor squareMagnitude [ ] como resultado da FFT, o espectro das frequências.

Vídeo 2 - Aplicação da FFT para identificar a frequência de um sinal.


Para quem gosta de música e áudio, o Vídeo 3 mostra uma aplicação bem legal para a FFT: um Analisador de Espectro de Áudio para a animação de um MP3 Player com o PIC32MX!
 Vídeo 3 - PIC32 MP3 Player & Audio Spectrum Analyser com a FFT.


Foi utilizada a função mips_fft16 para o cálculo da FFT com 128 pontos.

A FFT é testada com o arquivo de áudio Sine3kHz.MP3 contendo uma onda senoidal variando de 20 Hz à 3 kHz.



Referências:

HAYKIN, Simon S.; VAN VEEN, Barry. Sinais e sistemas. Porto Alegre: Bookman, 2001. 668p.

MICROCHIP. Code Examples. CE018 - Using the Fast Fourier Transform (FFT) for Frequency Detection. Disponível em: http://ww1.microchip.com/downloads/en/DeviceDoc/CE018_FFT_DSPlib_101007.zip


MICROCHIP. Software Libraries. Disponível em: http://www.microchip.com/SoftwareLib.aspx