0% acharam este documento útil (0 voto)
36 visualizações58 páginas

Pic16 Programacao Abc

O documento discute estruturação de código-fonte para microcontroladores PIC16F628A. Ele explica a importância de estruturar o código com comentários, variáveis, rotinas e includes. Também discute definições como EQU e #DEFINE para facilitar a programação, além de explicar seleção de bancos de memória e operações com dados.
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
36 visualizações58 páginas

Pic16 Programacao Abc

O documento discute estruturação de código-fonte para microcontroladores PIC16F628A. Ele explica a importância de estruturar o código com comentários, variáveis, rotinas e includes. Também discute definições como EQU e #DEFINE para facilitar a programação, além de explicar seleção de bancos de memória e operações com dados.
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
Você está na página 1/ 58

PIC16F628A

Criando um Programa
 Estruturando o Código-Fonte:

 Para que um programa seja escrito e funcione corretamente,


basta que as instruções certas sejam colocadas na ordem
correta.

 Entretanto, é recomendado que se tenha sempre uma


preocupação com a estruturação e a organização desse arquivo.

 A subdivisão e identificação de todas as tarefas (definição de


variáveis, entradas, saídas, rotinas, sub-rotinas, programa
principal, etc.) é a maneira mais utilizada pela grande maioria dos
programadores .
Criando um Programa
 A Importância dos Comentários:

 Outro recurso tão importante quanto a estruturação do


arquivo são os comentários inseridos pelo programador.

 No compilador do PIC, para escrever um comentário, basta


iniciá-lo com um ponto e vírgula (;) em qualquer lugar do
programa.

 É importante ter em mente que o compilador MPLab


diferencia letras maiúsculas das minúsculas.
Criando um Programa
 Arquivos de Definição: Includes

 São os arquivos “Includes”.

 São arquivos de texto, ou mesmo código-fonte, que serão


inclusos no programa.

 Dessa forma, a própria Microchip já criou um arquivo include


para cada tipo de microcontrolador, em que estão definidos os
nomes e endereços de todos os SFRs e uma série de outras
definições necessárias para a utilização dos microcontroladores.

 Os arquivos de includes devem ser gravados com a extensão INC.


Criando um Programa
 Arquivos de Definição: Includes

 Par a utilização de um arquivo de definições, a seguinte sintaxe deve


ser utilizada:
#INCLUDE <nome_do_arquivo.inc>

 O arquivo deve estar localizado no mesmo diretório de instalação do


MPLab. Esta é a melhor forma de referenciar-se aos arquivos
fornecidos pela Microchip.

 Para os arquivos personalizados deve ser escrita , além do nome do


arquivo, sua localização completa. Nesse caso, os símbolos < e > são
substituídos por aspas (“”).
#INCLUDE “Drive:diretório\nome_do_arquivo.inc”
Constantes e Definições: EQU e DEFINES
 Na programação do PIC, podemos utilizar a diretriz, para o
compilador, EQU.

 Essa diretriz associa um nome ao número.

 Dessa maneira, fica muito mais fácil nos referenciarmos a uma


variável pelo seu nome, no lugar do seu endereço de
memória.

 Isso também é muito utilizado para definirmos constantes que


serão utilizadas no decorrer da programação.
Constantes e Definições: EQU e DEFINES
 A sintaxe para a utilização do EQU é a seguinte:
nome_da_variável EQU Endereço_da_memória
 ou
nome_da_constante EQU Valor_da_constante

 Um número qualquer pode ser representado de várias


formas dentro do assembler do PIC:
 Decimal: D’??’ ou .??
 Hexadecimal: H’??’ ou 0X??
 Binário: B’????????’
 ASCII: A’?’
Constantes e Definições: EQU e DEFINES
 Vejamos, então, um exemplo utilizado no arquivo P16F628A.INC:
 STATUS EQU H ‘0003’
 FSR EQU H’0004’
 PORTA EQU H’0005’
 PORTB EQU H’0006’

 Na hora de compilar o código-fonte, toda vez que aparecer a palavra


PORTA, ela será automaticamente substituída pelo número 5 (em hexa),
que é o endereço de memória para a porta A.

 Para esse mesmo tipo de aplicação existe também a diretriz #DEFINE.

 Esta, no entanto, é um pouco mais poderosa que a EQU, pelo fato de que
ela não substitui nomes somente por números, mas sim por expressões
inteiras.
Constantes e Definições: EQU e DEFINES
 Essa diretriz é comumente utilizada para definirmos os pinos
de entrada e saída do sistema.

 Para nos referenciarmos a um pino, devemos especificar o bit


correto dentro do registrador da porta em questão.

 Podemos, então, dar um nome ao conjunto registrador/bit


para facilitar o entendimento do programa.

 Por exemplo:
 #DEFINE LED PORTB,1
Constantes e Definições: EQU e DEFINES
 LED é o nome da definição, e PORTB,1 é o que será
considerado toda vez que o nome for utilizado durante o
programa.

 Desta forma, após a utilização do define, podemos nos referir


ao pino RB1 com a palavra LED.

 Isso também facilita muito as alterações futuras no hardware.

 Caso esse LED seja alterado para o pino RB2, basta alterarmos
o #DEFINE, sem precisarmos modificar o código inteiro.
Exemplo 0 - Estruturação
 Vejamos agora um exemplo de estruturação completa.

 Este modelo será utilizado, no decorrer das aulas, como


ponto de partida para todos os programas.

Exemplo 0 – Estruturação
Arquivo EX0.ASM
Exemplo 0 - Estruturação
 Algumas novas diretrizes de compilação aparecem no exemplo e
devem ser explicadas:

 ORG:
 Trata-se de um direcionamento para a posição de memória de
programação.
 Observe que, como o vetor de reset do PIC16F628A é o endereço 0x00,
antes da escrita da primeira instrução é dada a diretriz ORG 0x00, para
que o programa comece neste ponto.
 Logo em seguida, um pulo é dado para uma rotina localizada bem mais
à frente (GOTO INICIO).
 Isso é necessário porque no endereço 0x00 deve ser iniciada a rotina de
interrupção.
 Para tal, uma nova diretriz é especificada: ORG 0x04.
Exemplo 0 - Estruturação
 END:
 Essa diretriz deve ser sempre colocada ao final do programa,
pois, quando o compilador encontrá-la, a compilação será
terminada.

 CBLOCK e ENDC:
 É uma maneira simplificada de definirmos vários EQUs com
endereços sequenciais.
 Observe que utilizamos esse recurso na definição das variáveis
do sistema, mas precisamos informar somente o endereço da
primeira variável (CBLOCK 0x20).
 As demais são definidas na sequencia.
Trabalhando com a Memória
 O objetivo deste tópico se refere a como guardar e
recuperar valores e também movê-los de um lugar para
outro.

 O registrador WORK (W ou ACUMULADOR):


 É um registrador temporário utilizado nas operações da
ULA e não faz parte direta da memória RAM do sistema.
Trabalhando com a Memória
 Conhecendo os bancos de memória:
 O PIC possui quatro bancos de memória para os
registradores SFRs e para a memória de variáveis do
sistema.
Trabalhando com a Memória
 Por isso, quando queremos acessar algum registrador SFR
que está no banco 1, por exemplo, devemos primeiramente
informar ao sistema que queremos trabalhar com este
banco.
Trabalhando com a Memória
 É preciso alterar o valor dos bits RP0 e RP1 no registrador STATUS.

 A combinação desses dois bits possibilita selecionar um dos quatro


bancos como o ativo no momento.

 A tabela seguinte relaciona o valor desses bits com o banco


selecionado:
Banco RP1 RP0
0 0 0
1 0 1
2 1 0
3 1 1
Trabalhando com a Memória
 Sempre que o PIC é ligado, tanto RP1 quanto RP0 são iniciados com o valor 0. Dessa
forma, o banco 0 sempre é o primeiro a ser selecionado.

 Para as primeiras experiências, vamos trabalhar somente com os bancos 0 e 1. Desta


forma, podemos então nos preocuparmos somente com o bit RP0.

 Partindo dessa premissa e com o objetivo de tornar essa tarefa mais fácil, criamos dois
comandos virtuais chamados BANK0 E BANK1, que são definidos no arquivo modelo da
seguinte maneira:
 #DEFINE BANK0 BCF STATUS, RP0 ;SETA BANK 0 DE MEMÓRIA
 #DEFINE BANK1 BSF STATUS, RP0 ;SETA BANK 1 DE MEMÓRIA
Trabalhando com a Memória
 Assim sendo, quando escrevemos BANK0, na verdade mandamos limpar o bit
RP0 do registrador STATUS; e quando escrevemos BANK1, mandamos setar este
mesmo bit.
 É recomendado, no entanto, que após efetuada as alterações necessárias no
banco 1 o sistema retorne sempre para o banco 0.
 Por exemplo, observe como foram ajustados alguns registradores do banco 1
no arquivo modelo:
Trabalhando com a Memória
 Caso os comando BANK0 e BANK1 não existissem, o sistema ficaria assim:
Trabalhando com a Memória
 Lidando com Dados (MOVLW, MOVWF, MOVF, CLRF E CLRW):
 Os comandos mais utilizados no PIC são:
 MOVLW = move (MOV) uma literal (L) para o registrador work (W).
 MOVWF = move (MOV) o valor de work (W) para um registrador (F).
 MOVF = move (MOV) o valor de um registrador (F) par um local de destino passado como
argumento (f ou w).

 As sintaxes dessas instruções são:


 MOVLW k ; ONDE k É O NÚMERO QUE SERÁ COLOCADO EM W.
 MOVWF f ; ONDE f É O ENDEREÇO DA MEMÓRIA ONDE SERÁ
; GUARDADO O VALOR DE W.
 MOVF f,d ;ONDE f É O REGISTRADOR QUE SERÁ MOVIDO PARA O DESTINO d

 Assim sendo, para guardar um número em uma posição de memória, devemos


primeiramente movê-lo para o work (MOVLW) e depois movê-lo do work para
o registrador propriamente dito (MOVWF).
Trabalhando com a Memória
 Por exemplo, para definirmos as condições de operação da máquina, devemos
ajustar os bits do registrador OPTION_REG.

 A maneira mais rápida de fazermos isso é movendo um número para o endereço


desse registrador.

 O número é representado na forma binária para compreendermos melhor o estado


de cada bit.

 Lembre-se de que pela sintaxe do comando MOVWF deveríamos especificar o


endereço do registrador.

 No entanto, no arquivo de include, esse endereço foi sobrecarregado no nome


OPTION_REG.
 MOVLW B’10000100’
 MOVWF OPTION_REG ;DEFINE OPÇÕES DE OPERAÇÃO
Trabalhando com a Memória
 Já a instrução MOVF é utilizada para movermos o conteúdo de um registrador para
outro registrador.

 Por exemplo, veja como fica o código para escrevermos em TEMPO2 o mesmo valor
existente em TEMPO1:
 MOVF TEMPO1,W ;MOVE O VALOR DE TEMPO 1 PARA O W (WORK)
 MOVWF TEMPO2 ;MOVE O VALOR DE W (TEMPO1) PARA TEMPO2

 Para limparmos um registrador, poderíamos mover 0 (zero) para ele, mas uma
operação de movimento de um número para um registrador exige duas instruções
(MOVLW e MOVWF), e portanto, dois ciclos de máquina.

 A fim de agilizar este processo, podemos utilizar o comando CLRF:


 CLRF = Limpa (CLR) o registrador (F)

 A sintaxe dessa instrução é:


 CLRF f ;ONDE f É O ENDEREÇO DA MEMÓRIA QUE SE DESEJA LIMPAR
Trabalhando com a Memória
 Desta forma, as instruções:
 MOVLW B’00000000’
 MOVWF TRISB ;DEFINE ENTRADAS E SAÍDAS DO PORTB

 Poderiam ser substituídas por:


 CLRF TRISB ;DEFINE ENTRADAS E SAÍDAS DO PORTB

 De maneira análoga, para limpeza do work:


 CLRW ; LIMPA O WORK
PIC16F628A
Inicializando o Sistema
 Esta seção é destinada a uma melhor explicação e
exemplificação da estrutura apresentada no arquivo
modelo.

 Definindo locais para as variáveis:


 Seguindo a estrutura existente no modelo, o primeiro bloco
refere-se à definição das variáveis.

 Isso porque os SFRs já estão definidos no arquivo de include


(veja P16F628A.INC).
Inicializando o Sistema
 Desta forma, devemos criar espaço e nomes para todas as
variáveis que utilizaremos no programa.
 É recomendado também comentar para que serve cada
uma delas.
 Vejamos um exemplo:
Inicializando o Sistema
 Neste exemplo, estamos usando as diretrizes CBLOCK e
ENDC.
 Sem sua utilização, o mesmo código seria escrito da
seguinte maneira:
Inicializando o Sistema

 A memória disponível ao usuário para o PIC16F628A vai de:


 0x20 até 0x7F: banco 0
 0xA0 até 0xEF: banco 1
 0x120 até 0x14F: banco 2
Inicializando o Sistema
 Reservando espaço para flags:

 Flags são bits que definimos dentro de um byte para serem


utilizados como chaves on/off.

 Desta forma, em um único endereço de memória (registrador)


podemos guardar até oito flags que registrarão oito estados
diferentes.

 Por exemplo, um flag pode marcar se um byte já foi transmitido


ou não, outro pode marcar se existe algum dado recebido ou não
e assim por diante.
Inicializando o Sistema
 A primeira ação para podermos trabalhar com flags é a
definição de um registrador onde eles serão armazenados.
 Se muitos flags forem necessários, mais de um registrador
pode ser utilizado.
Inicializando o Sistema
 Depois, fica mais fácil se definirmos nomes específicos para
cada um dos flags por meio da diretriz #DEFINE.

 Desta forma, o flag TRANSMITIDO fica armazenado no bit 0


do registrador FLAG, e o RECEBIDO fica no bit 1.
Inicializando o Sistema
 Criando constantes:
 As constantes são muito úteis para simplificar alterações
em valores do sistema.
 Com a criação de constantes, é possível substituir um
número (literal) por um nome qualquer:
Inicializando o Sistema
 Definindo as entradas e saídas:
 Neste momento, devemos saber em quais pinos do PIC
serão ligadas as suas entradas e saídas.

 Para facilitar a compreensão, serão dados nomes a esses


pinos por meio da diretriz #DEFINE.

 Por exemplo, suponhamos que o projeto necessite de um


botão ligado ao pino RA0, um buzzer (aparelho que emite
som) ligado ao pino RA1 e oito LEDs ligados aos pinos de
RB0 a RB7.
Inicializando o Sistema
 Podemos então definir as entradas e saídas da seguinte
maneira:
Inicializando o Sistema
Inicializando o Sistema
 Nota:

 O demonstrado anteriormente é apenas uma definição de nomes


para facilitar a programação.

 Não estamos ainda configurando os referidos pinos como


entradas ou saídas propriamente ditas.

 Para tal, posteriormente configuraremos os registradores TRISA e


TRISB.
Inicializando o Sistema
 O Vetor de Reset:

 O PIC possui um endereço para o qual o programa é desviado


toda vez que um reset ocorre, seja ele pela energização do
sistema, pelo Master Clear externo (MCLR) ou pelo estouro do
WDT.

 Esse endereço é chamado de vetor de reset.

 No caso do PIC16F628A, esse vetor localiza-se no endereço 0x00.

 A maneira recomendada para iniciar a escrita é mostrada no


exemplo a seguir:
Inicializando o Sistema
Inicializando o Sistema
Inicializando o Sistema
 No exemplo dado, a seguinte configuração foi efetuada:

 Todo o PORTB como saída (“0” em todos os bits do TRISB);


 Pino RA0 como entrada (“1” no bit zero do TRISA);
 Os demais pinos de PORTA como saída (“0” nos demais bits do
TRISA);
 Prescaler (divisor de frequência) de 1:32 no TMR0 e pull-ups
(mantém o sinal em um nível conhecido) desabilitados (veja bits
do OPTION_REG);
 Todas as interrupções desligadas (veja bits do INTCON);
 Para alterar esses registradores, foi necessário mudar para o
banco 1.
Inicializando o Sistema
 Inicializando as variáveis:
 É muito importante que as variáveis também sejam
inicializadas, mesmo que seus valores devam ser iguais a
zero, pois nunca se sabe como a memória do PIC acordará.
 Inicializando as variáveis corretamente, muitos problemas
podem ser evitados.
PIC16F628A
Trabalhando com Rotinas
Rotinas de Desvio e Chamada.
MAIN

Instruções
diversas ROT

Instruções
CALL ROT diversas

Instruções RETURN
diversas

GOTO MAIN
Trabalhando com Rotinas
 Rotinas de desvio:

 As rotinas de desvio são utilizadas, geralmente, para deixar o


programa mais estruturado e organizado.

 No entanto, a instrução GOTO é frequêntemente utilizada em


qualquer programa para possibilitar “pulos” necessários à
lógica do sistema.

 A sintaxe dessa instrução é:


 GOTO nome ;ONDE nome É A IDENTIFICAÇÃO DO LOCAL
; PARA ONDE SE DESEJA PULAR

 Os nomes de rotinas não podem possuir espaços.


Trabalhando com Rotinas
 Este compilador possibilita o uso do $. Ele é utilizado
para representar a linha atual do programa.

 Veja, então, como fica o comando GOTO em conjunto


com o $:
 GOTO $+3 ;PULA 3 LINHAS PARA BAIXO
 GOTO $-2 ;PULA 2 LINHAS PARA CIMA

 Esta técnica não é recomendada para pulo muito


grandes, para não complicar o entendimento e a
manutenção do programa (inclusão de linhas...).
Trabalhando com Rotinas
 Rotinas de Chamada:

 As rotinas de chamada são utilizadas quando uma tarefa deve


ser repetida várias vezes e não se deseja reescrevê-la para não
gastar memória de programa.

 Desta forma, a rotina pode ser usada como uma função, que é
chamada de diversos pontos do programa sem gerar
problemas.

 A sintaxe dessa instrução é:


 CALL nome ; ONDE nome É A IDENTIFICAÇÃO DA ROTINA
Trabalhando com Rotinas
 Para retornar de uma rotina, devem ser utilizadas as
instruções RETURN e RETLW.

 As sintaxes dessas instruções são:


 RETURN ;FINALIZA A ROTINA VOLTANDO AO ÚLTIMO
;ENDEREÇO DA PILHA
 RETLW k ;FINALIZA A ROTINA VOLTANDO AO ÚLTIMO
;ENDEREÇO DA PILHA COM O VALOR k (LITERAL)
; EM W.
Tomando Decisões e Fazendo Desvios
 Testando Bits e Flags (BTFSC e BTFSS):

 As instruções empregadas para testar diretamente bits, que


podem ser portas ou flags, são BTFSC e BTFSS.

 Vamos utilizar o sistema de termos predefinidos para


entendermos melhor suas funções:

 BTFSC = testa (T) o bit (B) do registrador (F) e pula (S) a próxima
linha se a resposta for 0 (C).

 BTFSS = testa (T) o bit (B) do registrador (F) e pula (S) a próxima
linha se a resposta for 1 (S).
Tomando Decisões e Fazendo Desvios
 As sintaxes dessas instruções são:

 BTFSC f,b ;ONDE f É O REGISTRADOR E b É O BIT A SER


;TESTADO.
 LINHA1 ;PASSA POR ESTA LINHA SE O BIT TESTADO FOR 1.
 LINHA2 ;PULA DIRETO PARA ESTA LINHA SE O BIT
; TESTADO FOR 0.

 BTFSS f,b ;ONDE f É O REGISTRADOR E b É O BIT A SER


;TESTADO.
 LINHA1 ;PASSA POR ESTA LINHA SE O BIT TESTADO FOR 0.
 LINHA2 ;PULA DIRETO PARA ESTA LINHA SE O BIT
;TESTADO FOR 1.
Tomando Decisões e Fazendo Desvios
 Normalmente, as especificações do registrador e do bit
podem ser substituídas por um #DEFINE, como no
exemplo seguinte:

 #DEFINE BOTAO PORTA,0 ;DEFINE O BOTÃO NO PINO RA0


;0 -> LIBERADO
;1 -> PRESSIONADO

 BTFSS BOTAO ;O BOTÃO ESTÁ PRESSIONADO?


 GOTO BT_LIB ;NÃO -> VAI TRATAR BOTÃO
LIBERADO
 GOTO BT_PRES ;SIM -> VAI TRATAR B0TÃO
;PRESSIONADO
Tomando Decisões e Fazendo Desvios
 Mudando Bits e Flags (BSF e BCF):

 As instruções empregadas para a alteração de um bit são BSF e BCF.

 Utilizando a técnica de termos predefinidos, teremos:


 BSF = o bit (B) do registrador (F) deve ser setado (S) – igualado a 1
 BCF = o bit (B) do registrador (F) deve ser zerado (C) – igualado a 0

 A sintaxe das instruções são:


 BSF f,b ;ONDE f É O REGISTRADOR E b O BIT QUE SERÁ SETADO
 BCF f,b ;ONDE f É O REGISTRADOR E b O BIT QUE SERÁ ZERADO

 Aqui também o registrador e o bit são comumente substituídos por


#DEFINES.
Trabalhando com as Portas

 As portas são provavelmente o recurso mais poderoso de


um microcontrolador, pois é por meio delas que o PIC pode
se comunicar com os demais componentes do sistema.

 Com essas portas podemos ler um botão, acender e apagar


um LED, etc.
Trabalhando com as Portas
 Lendo uma Porta:

 Uma porta pode ser lida de duas maneiras: como um conjunto, isto é,
todos os seus pinos de uma só vez, ou individualmente.

 Por exemplo, podemos ter ligado a todo o PORTB um barramento


paralelo de dados, em que cada pino representa um bit e o PORTB
representa o byte todo.

 Então para sabermos qual valor está escrito no PORTB, basta lê-lo
integralmente:

 MOVF PORTB,W ;ESCREVE O VALOR DE PORTB EM W


 MOVWF DADO ;ESCREVE O VALOR DE W EM DADO
;DADO = VALOR DE PORTB
Trabalhando com as Portas
 Neste exemplo, copiamos o valor do registrador PORTB para o
registrador DADO.

 Como o registrador PORTB expressa exatamente o estado de todos


os pinos da porta B, então estamos lendo diretamente seus valores.

 Observe que isso serve tanto para os pinos configurados como


entrada quanto para os configurados como saída.

 No caso de um pino do tipo entrada, quando lemos o seu valor,


obtemos o sinal imposto pelos circuitos externos ao PIC.

 No caso dos pinos do tipo saída, vamos ler o valor imposto pelo
próprio PIC.
Trabalhando com as Portas

 Por outro lado, na maior parte das vezes, uma entrada é


associada a somente 1 pino, e não ao PORT inteiro.

 Nesse caso, é muito mais fácil trabalharmos diretamente com


o bit em questão.

 O exemplo dado anteriormente para a leitura de um botão,


com a utilização das instruções BTFSS e/ou BTFSC, é o
melhor exemplo disso.
Trabalhando com as Portas
 Escrevendo em uma Porta:

 A escrita nas portas é similar o processo de leitura , com algumas ressalvas.

 Durante o processo de escrita em um pino, não estamos afetando diretamente o


estado dele, mas sim um “latch” intermediário.

 A cada pino das portas é associada uma chave interna (latch) que é alterada toda
vez que escrevemos em um desses pinos.

 Se o pino estiver configurado como saída, então seu estado também é afetado,
mas se ele for uma entrada, então só o latch é afetado.

 Devido a isso, é possível escrevermos um valor em um pino que é entrada, e


quando o alteramos para a saída, seu estado será garantido.
Trabalhando com as Portas
 Vejamos um exemplo:

 BANK1 ;MUDA PARA BANCO 1


 BSF TRISB,0 ;TRANSFORMA RB0 EM ENTRADA
 BANK0 ;RETORNA PARA BANCO 0

 BSF PORTB,0 ;ESCREVE 1 NO LATCH DO RB0 (QUE AINDA É


; ENTRADA)
 BANK1 ;MUDA PARA O BANCO 1
 BCF TRISB,0 ;TRANSFORMA RB0 EM SAÍDA. NESTE
;MOMENTO, O PINO SERÁ INICIALIZADO EM
;1 DEVIDO AO LATCH
 BANK0 ;RETORNA PARA O BANCO 0

Você também pode gostar

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy