quinta-feira, 24 de novembro de 2022

Montando um PLC com Arduino + comunicação Modbus RTU com Supervisório Elipse Scada

 Que tal montar um Sistema de Automação Industrial na sua casa utilizando um Arduino?

Sim! Isto é possível. Neste post você encontra algumas dicas e um projeto simples pra montar em casa para estudar e aprender um pouco do que encontramos dentro de uma Indústria.

Exemplo de aplicação do Sistema de Supervisão e Controle Elipse Scada (Supervisório) comunicando com um Arduino através do protocolo MODBUS RTU.


A aplicação com Elipse Scada possui os exemplos de:

Entrada digital.
Saída digital.
Entrada analógica.
Saída analógica.
Comando manual/automático.
Comando liga/desliga.
Objeto dinâmico do motor (animado com imagens).
Controle de velocidade.
Gráfico em tempo real.
Gráfico através de histórico.
Tela de alarmes e eventos.

O vídeo mostra:

O programa do Arduino e a biblioteca utilizada.
A aplicação do Elipse Scada.
A configuração da comunicação MODBUS RTU  no Arduino (escravo) e no Elipse Scada (mestre).
Configuração do banco de dados do historiador.
Configuração da tela de alarmes.
Configuração dos objetos da tela do Supervisório.

Foi utilizada a Biblioteca SimpleModbusSlaveV10 para o Arduino.

O Elipse Scada possui o driver para a comunicação Modbus Master. 


Figura 1 - Montagem do nosso PLC Modbus RTU com Arduino Pro mini no protoboard.


Figura 2 - Tela do nosso Supervisório Elipse Scada.


Assista ao vídeo para aprender os detalhes da comunicação MODBUS RTU e como fazer as configurações no Supervisório Elipse Scada.


Vídeo 1 - Arduino PLC Modbus RTU com Elipse Scada.



O código que roda no Arduino do vídeo é este aqui:




#include <SimpleModbusSlave.h>


//    EXEMPLO DE COMUNICAÇÃO MODBUS RTU ENTRE ARDUINO(SLAVE) E SUPERVISORIO ELIPSE SCADA(MASTER)

// V1.2 19-05-2018  M.R.G.


/* 
   SimpleModbusSlaveV10 supports function 3, 6 & 16.
   
   This example code will receive the adc ch0 value from the arduino master. 
   It will then use this value to adjust the brightness of the led on pin 9.
   The value received from the master will be stored in address 1 in its own
   address space namely holdingRegs[].
   
   In addition to this the slaves own adc ch0 value will be stored in 
   address 0 in its own address space holdingRegs[] for the master to
   be read. The master will use this value to alter the brightness of its
   own led connected to pin 9.
   
   The modbus_update() method updates the holdingRegs register array and checks
   communication.

   Note:  
   The Arduino serial ring buffer is 64 bytes or 32 registers.
   Most of the time you will connect the arduino to a master via serial
   using a MAX485 or similar.
 
   In a function 3 request the master will attempt to read from your
   slave and since 5 bytes is already used for ID, FUNCTION, NO OF BYTES
   and two BYTES CRC the master can only request 58 bytes or 29 registers.
 
   In a function 16 request the master will attempt to write to your 
   slave and since a 9 bytes is already used for ID, FUNCTION, ADDRESS, 
   NO OF REGISTERS, NO OF BYTES and two BYTES CRC the master can only write
   54 bytes or 27 registers.
 
   Using a USB to Serial converter the maximum bytes you can send is 
   limited to its internal buffer which differs between manufactures. 
*/

// I/Os Digitais do PLC Arduino
#define  RELE_TERMICO 7            //vem do rela termico do motor 1 = ok
#define  LED_ON_OFF_MOT 8   //vai para rele do motor
#define  LED_PWM_VELOC 9    //controle de velocidade do motor por PWM 5V


// declara variaveis globais
bool Falha;
int Ref_Velocidade;

// Using the enum instruction allows for an easy method for adding and 
// removing registers. Doing it this way saves you #defining the size 
// of your slaves register array each time you want to add more registers
// and at a glimpse informs you of your slaves register layout.

//////////////// registers of your slave ///////////////////
enum 
{     
  // just add or remove registers and your good to go...
  // The first register starts at address 0
  ANALOG_IN_01,     //0-1023
  ANALOG_IN_02,     //0-1023
  ANALOG_IN_03,     //0-1023
  MODO_OPERACAO,    //0-1
  MOTOR_COMANDO,    //0-1
  MOTOR_STATUS,     //0-3
  VELOCIDADE,       //0-100
  HOLDING_REGS_SIZE // leave this one
  // total number of registers for function 3 and 16 share the same register array
  // i.e. the same address space
};

unsigned int holdingRegs[HOLDING_REGS_SIZE]; // function 3 and 16 register array
////////////////////////////////////////////////////////////

void setup()
{
  /* parameters(HardwareSerial* SerialPort,
                long baudrate, 
		unsigned char byteFormat,
                unsigned char ID, 
                unsigned char transmit enable pin, 
                unsigned int holding registers size,
                unsigned int* holding register array)
  */
  
  /* Valid modbus byte formats are:
     SERIAL_8N2: 1 start bit, 8 data bits, 2 stop bits
     SERIAL_8E1: 1 start bit, 8 data bits, 1 Even parity bit, 1 stop bit
     SERIAL_8O1: 1 start bit, 8 data bits, 1 Odd parity bit, 1 stop bit
     
     You can obviously use SERIAL_8N1 but this does not adhere to the
     Modbus specifications. That said, I have tested the SERIAL_8N1 option 
     on various commercial masters and slaves that were suppose to adhere
     to this specification and was always able to communicate... Go figure.
     
     These byte formats are already defined in the Arduino global name space. 
  */
	

  modbus_configure(&Serial, 9600, SERIAL_8N1, 1, 2, HOLDING_REGS_SIZE, holdingRegs);

  // modbus_update_comms(baud, byteFormat, id) is not needed but allows for easy update of the
  // port variables and slave id dynamically in any function.


  modbus_update_comms(9600, SERIAL_8N1, 1);
  
  pinMode(RELE_TERMICO, INPUT);
  pinMode(LED_ON_OFF_MOT, OUTPUT);
  pinMode(LED_PWM_VELOC, OUTPUT);
}

void loop()
{
  // modbus_update() is the only method used in loop(). It returns the total error
  // count since the slave started. You don't have to use it but it's useful
  // for fault finding by the modbus master.
  
  modbus_update();
  
    
  // analogWrite(LED, holdingRegs[PWM_VAL]>>2); // constrain adc value from the arduino master to 255

  // Leitura das entradas analogicas do PLC Arduino
  holdingRegs[ANALOG_IN_01] = analogRead(A0); 
  holdingRegs[ANALOG_IN_02] = analogRead(A1);
  holdingRegs[ANALOG_IN_03] = analogRead(A2);

  //leitura das entradas digitais do PLC Arduino
  Falha = !digitalRead(RELE_TERMICO);   //inverte o bit



  //se modo de operacao esta em manual...
  if(holdingRegs[MODO_OPERACAO] == 0){

    // velocidade do motor eh controlada pelo potenciomentro
    Ref_Velocidade = map(holdingRegs[ANALOG_IN_01],0,1023,0,255);
    
    //atualiza valor de velocidade na rede
    holdingRegs[VELOCIDADE] = map(Ref_Velocidade,0,255,0,100);
 
  } 
 
  else{   // se modo de operacao esta em automatico...

    // velocidade do motor eh controlada pelo supervisorio
    Ref_Velocidade = map(holdingRegs[VELOCIDADE],0,100,0,255);

  }  


  //verifica status do motor
  if (Falha == 1)   {                        //falha
      holdingRegs[MOTOR_STATUS] = 3;
      holdingRegs[MOTOR_COMANDO] = 0;   //desliga o motor
  }  
     // comandos remotos do supervisorio parao motor
  else  if (holdingRegs[MOTOR_COMANDO] == 1) //ligado
      holdingRegs[MOTOR_STATUS] = 1;
  else                                      //desligado
     holdingRegs[MOTOR_STATUS] = 2;



  //escrita das saidas digitais do PLC Arduino
  // comando do motor
    if (holdingRegs[MOTOR_STATUS] == 1){
      digitalWrite(LED_ON_OFF_MOT,HIGH);
    }
    else {
      digitalWrite(LED_ON_OFF_MOT,LOW);  
    }


  //escrita das saidas analogicas  
  analogWrite(LED_PWM_VELOC,Ref_Velocidade);

  
  
  /* Note:
     The use of the enum instruction is not needed. You could set a maximum allowable
     size for holdinRegs[] by defining HOLDING_REGS_SIZE using a constant and then access 
     holdingRegs[] by "Index" addressing. 
     I.e.
     holdingRegs[0] = analogRead(A0);
     analogWrite(LED, holdingRegs[1]/4);
  */
  
}
	






Referências:

Série de 3 artigos do site Embarcados.com.br com os links para download das bibliotecas e código de exemplo:

Integração Arduino e Elipse Scada:
https://www.embarcados.com.br/integracao-arduino-e-elipse-scada/

Realizando acionamentos simples com Elipse SCADA e Arduino:
https://www.embarcados.com.br/acionamentos-simples-scada-arduino/

Monitoramento de variáveis de processo com Elipse SCADA e Arduino:
https://www.embarcados.com.br/processo-com-elipse-scada-e-arduino/

Site do Elipse:
https://www.elipse.com.br/

Na página de download do Elipse Scada você encontra a versão demo:
https://www.elipse.com.br/downloads/?cat=69&key=&language=ptbr

Biblioteca Modbus RTU para o Arduino (arquivo SimpleModbusSlaveV10.zip):
https://drive.google.com/drive/folders/0B0B286tJkafVYnBhNGo4N3poQ2c?tid=0B0B286tJkafVSENVcU1RQVBfSzg

Driver Modicon Modbus Master (ASC/RTU/TCP) para o Elipse Scada:
https://www.elipse.com.br/downloads/?cat=48&key=&language=ptbr
Modbus.dll:
https://www.elipse.com.br/downloads/?cat=48&key=&language=ptbr#header-main

Instalador do Elipse SCADA com aplicação demo:
https://www.elipse.com.br/downloads/?cat=69&key=&language=ptbr#header-main







quarta-feira, 12 de maio de 2021

80C32 + EPROM - Como Apagar e Gravar a Memória EPROM 27C512

 Aprenda a trabalhar com as memórias EPROM do tipo UVPROM, que necessitam da Luz Ultravioleta para serem apagadas.

Neste artigo você vai aprender como apagar uma memória EPROM 27C512 com luz Ultravioleta UV e fazer a gravação de um novo programa com o programador de memórias Minipro / TL866 II plus.

Escolhemos uma placa de sucata de impressora antiga para o nosso aprendizado. 


Figura 1 - Placa de sucata com o microcontrolador 80C32 e memória EPROM 27C512.



Figura 2 - Memória EPROM 27C512 de 64 kB com a janela de quartzo sem o selo.


Figura 3 - Pinos da memória EPROM 27C512. Fonte: datasheet da ST.



Figura 4 - Exemplo de diagrama de um circuito com uma memória EPROM.



Figura 5 - Equipamentos para trabalhar com as memórias EPROM.


Vejamos o que dizem os datasheets das memórias EPROMs com relação a forma de apagá-las.


Fonte: datasheet da EPROM M27C512 da ST.

Fonte: datasheet da EPROM TMS27C512 da TI.

Resumindo tudo: para apagarmos o conteúdo da memória temos que utilizar um apagador de EPROM, que possui uma lâmpada Ultravioleta, e deixar nosso chip lá dentro durante 20 minutos com a janela de quartzo exposta a luz UV!   Simples assim né!  :)

Figura 6 - Memória pronta para ser limpa com o Apagador de EPROM.



Figura 7 - Memória EPROM sendo apagada com Luz Ultravioleta.


Depois de apagar a memória EPROM todos os bits passam para o nível lógico 1 (bytes com valor  FF em hexadecimal).
Dizemos que a memória está limpa, ou em branco, e pode ser gravada com um novo programa.

Existem diversos modelos de programadores no mercado. Neste post vamos utilizar o programador de memórias Minipro / TL866 II plus da XGecu.

Figura 8 - Memória encaixada no soquete ZIF do programador Minipro / TL866 II plus.


Figura 9 - Software XGpro para programação de memórias.




Figura 10 - Programa .HEX ou .BIN aberto no programador.


Figura 11 - Processo de programação e verificação do programa na memória EPROM.

Devemos proteger novamente a janela de quartzo do chip com um selo para evitar que o programa seja apagado parcialmente ao ser exposto a luz solar ou lâmpadas fluorescente.

Figura 12 - Memória EPROM já programada, montada na placa e com o selo na janela de quartzo.


Acompanhe no vídeo todo o processo passo-a-passo para Apagar e Programar uma memória EPROM 27C512!

Vídeo 1 - 80C32 + EPROM - Como Apagar e Gravar a Memória EPROM 27C512


terça-feira, 20 de abril de 2021

80C32 + EPROM 27C512 - O primeiro projeto 8051 Pisca LED 1 Hz

 Transformando uma placa de sucata  em um Kit de Desenvolvimento 8051: Microcontrolador 80C32 com memória de programa externa EPROM 27C512.


Projeto 8051 Pisca LED a 1 Hz no Port P1.4.

Você vai aprender a trabalhar com a memória EPROM 27C512, como fazer o apagamento da memória com luz Ultra Violeta e fazer a gravação com o programador Minipro / TL866 II plus.

Figura 1 - Diagrama do circuito com o Microcontrolador 80C32 e memória externa EPROM 27C512.


Figura 2 - Placa de sucata com o Microcontrolador 80C32 e memória externa EPROM 27C512.


Figura 3 - Ferramentas utilizadas.


Código para o primeiro projeto 8051 Pisca LED 1 Hz.



 ;############ PISCA LED 1 HZ ###############

; MICROCONTROLADOR 8051 
; COMPILADOR ASM51 ou Keil
; MAIO/2013  M.R.G. original placa desenvolvimento  aT89s82
; MARC/2021  M.R.G. adaptado para placa 80c32 + EPROM 27C512
; PINO 5, P1.4 = LED


$MOD51

; *************** DEFINE CONSTANTES   ************** 
		TEMPO10MS			EQU 	9210
		LED				EQU	P1.4
		ENABLE_INPUT_DRIVE_MTA011	EQU	P3.5
		
;*************** VETOR DE RESET ****************************************

		ORG	000H

		LJMP INICIO

;************************** MAIN ***************************************
		ORG	100H

INICIO:	

;CONFIGURA TIMER0

		MOV	TMOD,#00000001B				;TIMER 0 MODO 1 - 16 BITS



; HABILITA ENTRADAS DO DRIVE MTA011 - TEM PORTA INVERSORA LS05 ENTRE 80C32 E MTA011
               CLR ENABLE_INPUT_DRIVE_MTA011	                ;QUANDO EM ZERO HABILITA DRIVE



LOOP:
		MOV R0, #50D			                ;50 X 10 MS = 500 MS
DELAY10MS:							  	
		MOV TL0, #LOW (65535-TEMPO10MS)	                ;CARREGA VALOR PARA TIMER 0
		MOV TH0, #HIGH(65535-TEMPO10MS)
		SETB TR0					;LIGA TIMER 0
		JNB TF0, $					;AGUARDA FIM DA CONTAGEM
		CLR TR0						;LIMPA FLAG
		CLR TF0
		DJNZ R0, DELAY10MS				;DECREMENTA E VERIFICA SE TERMINOU OS 50 LOOPS

		CPL LED						;INVERTE SAIDA PARA O LED
		LJMP LOOP

		
	END	

Figura 4 - Código em Assembly do programa 8051 Pisca LED 1Hz.



Figura 5 - Apagando a memória EPROM com Luz Ultravioleta.


Figura 6 - Programando a memória EPROM com Minipro TL866 II plus.


Figura 7 - Placa 80C32 rodando o programa. LED piscando a 1 Hz




Assista ao vídeo para ver como ficou nosso projeto:

Vídeo 1 - 80C32 EPROM - O primeiro projeto 8051 Pisca LED 1 Hz.




Referência:

NICOLOSI, D. E. C.; Laboratório de Microcontroladores: Treino de instruções, hardware e software. São Paulo: Érica, 2002.




80C32 + EPROM 27C512 - Projeto Testando a Comunicação Serial do 8051

Transformando uma placa de sucata  em um Kit de Desenvolvimento 8051: Microcontrolador 80C32 com memória de programa externa EPROM 27C512. 


Projeto Teste da Comunicação Serial com o 8051: o programa inicia e envia algumas mensagens de texto para o computador pela comunicação serial. Depois passa a aguardar dados vindos pela serial e retorna os caracteres para o computador como uma função de echo. A cada dado recebido o 8051 inverte o status do LED ligado no Port P1.4. Trabalha com a Interrupção Serial.

Você vai aprender a trabalhar com a memória EPROM 27C512, como fazer o apagamento da memória com luz Ultra Violeta e fazer a gravação com o programador Minipro / TL866 II plus.


Figura 1 - Diagrama do circuito com o Microcontrolador 80C32 e memória externa EPROM 27C512.


Figura 2 - Placa de sucata com o Microcontrolador 80C32 e memória externa EPROM 27C512.



Figura 3 - Ferramentas utilizadas.



Código do projeto Testando a Comunicação Serial do 8051.


;############ PROGRAMA 8051 COM LED E SERIAL ###############

; ENVIA MENSAGENS INICIAIS PARA O COMPUTADOR
; DEVOLVE DADO RECEBIDO PARA O COMPUTADOR E INVERTE STATUS DO LED
; COMPILADOR ASM51 ou Keil

; V 1.1 ABRIL/2013  PLACA AT89S52
; V 1.2 MARÇO/2021  ADAPTADO PARA PLACA 80C32
; v 1.3		    CORRIGIDO BUG DA INTERRUPCAO SERIAL
; M.R.G.


; PINO 10, P3.0 = RX
; PINO 11, P3.1 = TX
; PINO  5, P1.4 = LED
; PINO 15, P3.5 = enable drive MTA011


$MOD51


; *************** DEFINE CONSTANTES   ************** 
		TEMPO		EQU 	60535
		TEMPO2		EQU	15535


		STRING01	EQU	0500h
		STRING02	EQU	0520h
		STRING03	EQU	0540h
		STRING04	EQU	0560h
		STRING05	EQU	0580h
		STRING06	EQU	0600h
		STRING07	EQU	0620h	
		STRING08	EQU	0640h	

		TRANSMIT	EQU	F0	;UTILIZANDO BIT DO PSW PARA FLAG DE TRANSMISSÃO


		LED				EQU	P1.4
		ENABLE_INPUT_DRIVE_MTA011	EQU	P3.5





; ******************** DECLARACAO DE VARIAVEIS DA RAM **********************



  
;*************** VETOR DE RESET **********************************************

		ORG	000H

		MOV	R0, #0FFH
		LJMP INICGERAL


;****************** TRATAMENTO DA INTERRUPÇÃO SERIAL ***************************
		ORG    023H
		LJMP INT_SERIAL


		ORG	100H
INT_SERIAL:
 		JNB RI, INT_TX 		;SEPARA POR SOFTWARE A INTERRUPCAO DA TRANSMISSAO E DA RECEPCAO
INT_RX:
		MOV	A,SBUF		;MOVE DADO RECEBIDO DA SERIAL PARA R1
		MOV R1, A		;MOVE DADO DO ACUMULADOR PARA REGISTRADOR R1

		CALL TRANSMITE		;DEVOLVE DADO RECEBIDO PARA O COMPUTADOR                   			

		CPL 	LED		;INVERTE SAIDA DO LED
		CLR	RI		;LIMPA FLAG DE RECEPCAO SERIAL

INT_TX:					
    		CLR TI         		;LIMPA FLAG DE TRANSMISSAO SERIAL
		RETI



;************************** MAIN ***************************************
		

INICGERAL:
	
; HABILITA ENTRADAS DO DRIVE MTA011 - TEM PORTA INVERSORA LS05 ENTRE 80C32 E MTA011
               CLR ENABLE_INPUT_DRIVE_MTA011	;QUANDO EM ZERO HABILITA DRIVE



;CONFIGURA SERIAL

		MOV	TMOD,#00100001B	;TIMER 1 NO MODO2	TIMER 0 MODO 1
		MOV	TH1,#232D	;VALOR DA RECARGA AUTOMÁTICA PARA BAUD RATE = 2400 @11,0592 MHz
		SETB	TR1		;LIGO TIMER1
		MOV	A,PCON		
		SETB	ACC.7		;SETA BIT SMOD PARA TER BAUD RATE = 2400
		MOV PCON,A
		;MOV IE,#10010000B	;HABILITA INTERRUPÇÃO GERAL E SERIAL
		MOV SCON,#01000000B	;MODO 1 DA SERIAL, DESABILITA RECEPÇÃO

  


; ENVIA MENSAGENS INICIAIS PELA SERIAL - COM AS INTERRUPCOES DESABILITADAS

MENSAGEM7:	
		MOV DPTR, #STRING07	;carrega endereço da string
		LCALL WRITESTRING
		LCALL ENVIA_ENTER
		LCALL ATRASO


MENSAGEM1:	
		MOV DPTR, #STRING01	;carrega endereço da string
		LCALL WRITESTRING
		LCALL ENVIA_ENTER
		LCALL ATRASO


MENSAGEM2:	
		MOV DPTR, #STRING02	;carrega endereço da string
		LCALL WRITESTRING
		LCALL ENVIA_ENTER
		LCALL ATRASO


MENSAGEM3:	
		MOV DPTR, #STRING03	;carrega endereço da string
		LCALL WRITESTRING
		LCALL ENVIA_ENTER
		LCALL ATRASO

MENSAGEM4:	
		MOV DPTR, #STRING04	;carrega endereço da string
		LCALL WRITESTRING
		LCALL ENVIA_ENTER
		LCALL ATRASO


MENSAGEM5:	
		MOV DPTR, #STRING05	;carrega endereço da string
		LCALL WRITESTRING
		LCALL ENVIA_ENTER
		LCALL ATRASO

MENSAGEM6:	
		MOV DPTR, #STRING06	;carrega endereço da string
		LCALL WRITESTRING
		LCALL ENVIA_ENTER
		LCALL ATRASO

MENSAGEM8:	
		MOV DPTR, #STRING08	;carrega endereço da string
		LCALL WRITESTRING
		LCALL ATRASO


; FIM DAS MENSAGENS NO DISPLAY - HABILITA COMUNICACAO SERIAL
		MOV IE,#10010000B	;HABILITA INTERRUPÇÃO GERAL E SERIAL
		MOV SCON,#01010000B	;MODO 1 DA SERIAL, HABILITA RECEPÇÃO

LOOP:

		LJMP LOOP





; ----------- SUB-ROTINAS DE ENVIO DE MENSAGENS ----------------



WRITESTRING:
		MOV A, #0
		MOVC A, @A + DPTR
		CJNE A, #'$', WRITE_NEXT
		SJMP FINIS_STRING
WRITE_NEXT:
		MOV R1, A		;MOVE DADO DO ACUMULADOR PARA REGISTRADOR R1
		LCALL TRANSMITE		;ENVIA CARACTERE PARA O COMPUTADOR
		INC DPTR
		SJMP WRITESTRING
FINIS_STRING:
		RET

ENVIA_ENTER:
		MOV A, #13		;CR (Carriage Return) = “\r” = (char) 13
		MOV R1, A		;MOVE DADO DO ACUMULADOR PARA REGISTRADOR R1
		LCALL TRANSMITE		;ENVIA CARACTERE PARA O COMPUTADOR
		RET



; *********** SUBROTINAS DE DELAY ****************************************

T5MS:
		MOV TL0, #LOW(TEMPO)
		MOV TH0, #HIGH(TEMPO)
		SETB TR0
		JNB TF0, $
		CLR TR0
		CLR TF0
		RET



ATRASO:
		MOV R2, #10D
DENOVO:
		MOV TL0, #LOW (TEMPO2)
		MOV TH0, #HIGH(TEMPO2)
		SETB TR0
		JNB TF0, $
		CLR TR0
		CLR TF0
		DJNZ R2, DENOVO
		RET


	

; *********** TRANSMISSAO SERIAL ****************************************
TRANSMITE:
	MOV	SBUF,R1		;TRANSMITE DADO QUE ESTÁ EM R1
ESPERA:
	JNB	TI, ESPERA	;ESPERA TRANSMISSAO
	CLR	TI
	RET

; MENSAGENS SALVAS NA FLASH - MEMORIA DE PROGRAMA

		ORG STRING01
		DB ' Microcontrolador$'

		ORG STRING02
		DB ' 80C32, LED e RS232$'

		ORG STRING03
		DB ' Freq 11.0592 MHz$'

		ORG STRING04
		DB ' 256 B RAM$'

		ORG STRING05
		DB ' 64 kB EPROM$'

		ORG STRING06
		DB ' 32 kB Ext RAM$'

		ORG STRING07
		DB 'Inicializando...$'

		ORG STRING08
		DB '8051 echo:>_ $'


;ENTER
;CR (Carriage Return) = “\r” = (char) 13
;LF (Line Feed) = “\n” = (char) 10

		
	END	

Figura 4 - Código em Assembly do programa 8051 Teste Serial.


Figura 5 - Apagando a memória EPROM com Luz Ultravioleta.


Figura 6 - Programando a memória EPROM com Minipro TL866 II plus.


Figura 7 - Placa 80C32 conectada ao computador pela porta serial.


Figura 8 - Mensagens iniciais enviadas do 80C32 para o computador.


Figura 9 - Frame da comunicação serial de 1 caractere medida com o osciloscópio.


Assista ao vídeo para ver como ficou nosso projeto:

Vídeo 1 - 80C32 EPROM - Projeto Teste Comunicação Serial com o 8051.





Referência:

NICOLOSI, D. E. C.; Laboratório de Microcontroladores: Treino de instruções, hardware e software. São Paulo: Érica, 2002.


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.