Curso de Linguagem C
Rinaldo Câmara Gonçalves Labtools – Mosaico Didactic Division Revisão 2
Sumário SUMÁRIO .....................................................................................................................................................................3 RECURSOS BÁSICOS: EXEMPLO 1
BOTÃO E LED ............................................................................................5
RECURSOS DO LIVRO ..................................................................................................................................................5 LÓGICA DO EXEMPLO ...................................................................................................................................................5 ESQUEMA ELÉTRICO....................................................................................................................................................6 FLUXOGRAMA ..............................................................................................................................................................7 CÓDIGO ......................................................................................................................................................................8 EXERCÍCIOS PROPOSTOS ..........................................................................................................................................10 ANOTAÇÕES ..............................................................................................................................................................11 RECURSOS BÁSICOS: EXEMPLO 2
PISCA – PISCA VARIÁVEL .....................................................................13
RECURSOS DO LIVRO ................................................................................................................................................13 LÓGICA DO EXEMPLO .................................................................................................................................................13 ESQUEMA ELÉTRICO..................................................................................................................................................14 FLUXOGRAMA ............................................................................................................................................................15 CÓDIGO ....................................................................................................................................................................16 EXERCÍCIOS PROPOSTOS ..........................................................................................................................................18 ANOTAÇÕES ..............................................................................................................................................................19 RECURSOS BÁSICOS: EXEMPLO 3
CONTADOR HEXADECIMAL ..................................................................20
RECURSOS DO LIVRO ................................................................................................................................................20 LÓGICA DO EXEMPLO .................................................................................................................................................20 ESQUEMA ELÉTRICO..................................................................................................................................................21 FLUXOGRAMA ............................................................................................................................................................22 CÓDIGO ....................................................................................................................................................................25 EXERCÍCIOS PROPOSTOS ..........................................................................................................................................28 ANOTAÇÕES ..............................................................................................................................................................29 RECURSOS AVANÇADOS: EXEMPLO 4
MAXIMIZAÇÃO DE PINOS DE I/O...................................................30
RECURSOS DO LIVRO ................................................................................................................................................30 LÓGICA DO EXEMPLO .................................................................................................................................................30 ESQUEMA ELÉTRICO..................................................................................................................................................31 FLUXOGRAMA ............................................................................................................................................................32 CÓDIGO ....................................................................................................................................................................36 EXERCÍCIOS PROPOSTOS ..........................................................................................................................................40 ANOTAÇÕES ..............................................................................................................................................................41 RECURSOS AVANÇADOS: EXEMPLO 5
VARREDURA DE DISPLAY .............................................................42
RECURSOS DO LIVRO ................................................................................................................................................42 LÓGICA DO EXEMPLO .................................................................................................................................................42 ESQUEMA ELÉTRICO..................................................................................................................................................44 FLUXOGRAMA ............................................................................................................................................................45 CÓDIGO ....................................................................................................................................................................50 EXERCÍCIOS PROPOSTOS ..........................................................................................................................................57 ANOTAÇÕES ..............................................................................................................................................................58 RECURSOS AVANÇADOS: EXEMPLO 6 CONTROLE DO LCD ............................................................................59 RECURSOS DO LIVRO ................................................................................................................................................59 LÓGICA DO EXEMPLO .................................................................................................................................................59 ESQUEMA ELÉTRICO..................................................................................................................................................60 FLUXOGRAMA ............................................................................................................................................................61 CÓDIGO ....................................................................................................................................................................68 EXERCÍCIOS PROPOSTOS ..........................................................................................................................................76 ANOTAÇÕES ..............................................................................................................................................................77 RECURSOS AVANÇADOS: EXEMPLO 7
CONVERSOR ANALÓGICO DIGITAL..............................................78
RECURSOS DO LIVRO ................................................................................................................................................78 LÓGICA DO EXEMPLO .................................................................................................................................................78 Linguagem C para PIC
3
ESQUEMA ELÉTRICO..................................................................................................................................................79 FLUXOGRAMA ............................................................................................................................................................80 CÓDIGO ....................................................................................................................................................................82 EXERCÍCIOS PROPOSTOS ..........................................................................................................................................86 ANOTAÇÕES ..............................................................................................................................................................87 RECURSOS AVANÇADOS: EXEMPLO 8
CONTROLE DO PWM E EEPROM INTERNA ..................................88
RECURSOS DO LIVRO ................................................................................................................................................88 LÓGICA DO EXEMPLO .................................................................................................................................................88 ESQUEMA ELÉTRICO..................................................................................................................................................89 FLUXOGRAMA ............................................................................................................................................................90 CÓDIGO ....................................................................................................................................................................93 EXERCÍCIOS PROPOSTOS ..........................................................................................................................................99 ANOTAÇÕES ............................................................................................................................................................100 RECURSOS AVANÇADOS: EXEMPLO 9
COLETOR DE DADOS ....................................................................101
RECURSOS DO LIVRO ..............................................................................................................................................101 LÓGICA DO EXEMPLO ...............................................................................................................................................101 ESQUEMA ELÉTRICO................................................................................................................................................102 FLUXOGRAMA ..........................................................................................................................................................103 CÓDIGO ..................................................................................................................................................................109 EXERCÍCIOS PROPOSTOS ........................................................................................................................................114 ANOTAÇÕES ............................................................................................................................................................115 RECURSOS AVANÇADOS: EXEMPLO 10 FUNÇÕES MATEMÁTICAS..............................................................116 RECURSOS DO LIVRO ..............................................................................................................................................116 LÓGICA DO EXEMPLO ...............................................................................................................................................116 ESQUEMA ELÉTRICO................................................................................................................................................117 FLUXOGRAMA ..........................................................................................................................................................118 CÓDIGO .................................................................................................................................................................119 EXERCÍCIOS PROPOSTOS ........................................................................................................................................121 ANOTAÇÕES ............................................................................................................................................................122
4
Linguagem C para PIC
Recursos Básicos: Exemplo 1
Botão e Led
1.1 - Recursos do Livro Para o bom entendimento deste nosso primeiro exemplo são necessários os conhecimentos de programação em linguagem C, comandos de controle de Fluxo (cap.7 do livro Programação em C), declaração de variáveis, constantes e tipos de dados (cap.5 do livro Programação em C), diretivas de configuração dos pinos de I/O (cap.10-pág.170, cap.11.5; 11.6-pág.202; 11.7 e cap.12.2-pág. 250 do livro Programação em C).
1.2 - Lógica do exemplo Nosso exemplo será composto de um programa capaz de ler um botão e controlar um led. Com o botão S1 pressionado o led L2 acende, com o botão S1 liberado o led L2 apaga. Veremos os primeiros comandos para controle de fluxo de um programa e como ler uma entrada e acionar uma saída, fundamental já que estamos trabalhando com um microcontrolador. Neste exemplo você verá o comando WHILE, (Faça enquanto for verdadeiro) sendo utilizado para o controle de fluxo de nossa rotina principal, forçando um loop infinito. O comando IF ELSE, (Se verdadeiro {comando}, Se falso {comando}), realiza o teste do botão e determina o caminho a ser seguido, se acende ou apaga o led. Caso o botão esteja pressionado o teste determina que o led deve acender, caso contrário o led será apagado. Para o teste do botão está sendo utilizado o operando “!” (NOT), para botão pressionado temos nível lógico zero no pino de I/O, neste caso o teste com o comando IF será verdadeiro para botão pressionado e falso para botão liberado.
Linguagem C para PIC
5
1.3 - Esquema Elétrico
+5V
RESET 10K 2 3 4 5 6 7
+5V
8 9 10 11 12 13 14 15
4MHz
+5V
MC1 1
16 17 18 23 24
MCLR RA0 RA1 RA2 RA3 RA4 RA5 RE0 RE1 RE2 VDD VSS OSC1 OSC2 RC0 RC1 RC2 RC3 RC4 RC5
VDD VSS RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 RD7 RD6 RD5 RD4 RD3 RD2 RD1 RD0 RC7 RC6
16F877A
6
Linguagem C para PIC
32 31
+5V
40 39 38
RB1
RB0
37 36 35
10K
330R
34 33 30 29 28 27 22 21 20 19 26 25
S1
L2
1.4 - Fluxograma
MAIN
CONFIGURAÇÕES INICIAIS TRIS, PORTAS, WATCHDOG, PRESCALER.
A LIMPA WATCHDOG
NÃO
BOTÃO S1 PRESS.?
APAGA LED L2
SIM
ACENDE LED L2
A
Linguagem C para PIC
7
1.5 - Código /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Programação em C - Recursos Básicos de programação * * Exemplo 1 * * * * CENTRO DE CAPACITAÇÃO - LABTOOLS * * * * TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br * * E-MAIL:
[email protected] * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * VERSÃO : 1.0 * * DATA : 05/06/2003 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * // //
* * * * * * * * * * * * * * * * * * * * * * * * * * * * Descrição geral * * * * * * * * * * * * * * * * * * * * * * * * * * * * Este software está preparado para demonstrar o controle este primeiro programa demonstrará o estado de um botão
* * * * * * * * * * * * * * * * */ dos pinos de I/O por meio de um led.
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição das variáveis internas do PIC * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include
<16f877A.h>
// microcontrolador utilizado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações para gravação * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt fusíveis
// configuração dos
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização das variáveis * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //Neste bloco estão definidas as variáveis globais do programa. //Este programa não utiliza nenhuma variável de usuário /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Constantes internas * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de constantes facilita a programação e a manutenção. //Este programa não utiliza nenhuma constante de usuário /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Declaração dos flags de software * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de flags ajuda na programação e economiza memória RAM. //Este programa não utiliza nenhum flag de usuário /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização dos port's * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8
#use #use #use #use #use
fast_io(a) fast_io(b) fast_io(c) fast_io(d) fast_io(e)
#byte #byte #byte #byte #byte
porta portb portc portd porte
= = = = =
Linguagem C para PIC
0x05 0x06 0x07 0x08 0x09
/* * * * * * * * * * * * * * * * * * * * * // As entradas devem //futuras alterações #bit
* * * * * * * * * * * * * * * * * * * * * * * * * * ENTRADAS * * * * * * * * * * * * * * * * * * * * * * * * * * ser associadas a nomes para facilitar a programação do hardware.
botao = portb.0
// Estado do botão // 1 -> Liberado // 0 -> Pressionado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * SAÍDAS * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // As saídas devem ser associadas a nomes para facilitar a programação //futuras alterações do Hardware. #bit
* * */ e
* * */ e
led = portb.1 // Led correspondente ao botão // 1 -> Led ligado // 0 -> Led desligado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações do Microcontrolador * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void main () { setup_counters(RTCC_INTERNAL, WDT_2304MS); set_tris_a(0b11111111); set_tris_b(0b11111101); set_tris_c(0b11111111); set_tris_d(0b11111111); set_tris_e(0b00000111); porta=0x00; portb=0x00; portc=0x00; portd=0x00; porte=0x00;
// configuração dos pinos de I/O
// // // // //
limpa limpa limpa limpa limpa
porta portb portc portd porte
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Loop principal * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ while(TRUE) { RESTART_WDT(); if(!botao) { led = 1; } else led=0; }
// testa botão // Se botão = 0, então led = 1 // caso contrário, led = 0 // FIM DO PROGRAMA
}
1.6 -
Linguagem C para PIC
9
1.7 - Exercícios Propostos Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e soluções, seguindo os exercícios propostos: 1. Utilize as funções do Compilador para controlar o Led, OUTPUT_HIGH e OUTPUT_LOW. 2. Altere a lógica do programa para que o led acenda com o botão liberado e apague com o botão pressionado. 3. Troque o pino de I/O que controla o botão, por exemplo, utilize o pino RB3. 4. Com o botão pressionado acenda o led 2 e apague o led 3, para o botão liberado apague o led 2 e acenda o led 3.
10 Linguagem C para PIC
1.8 - Anotações
Linguagem C para PIC
11
Recursos Básicos: Exemplo 2
Pisca – Pisca Variável
1.9 - Recursos do Livro Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos no exemplo 1 e mais, funções do compilador para controle de atraso (cap.11.4 pág. 195 do livro Programação em C), Operadores para criação de expressões lógicas e aritméticas (cap.6 do livro Programação em C), diretivas de configuração para uso de função de atraso (cap.10, pág.169 do livro Programação em C).
1.10 - Lógica do exemplo A finalidade de nosso exemplo é demonstrar a inversão de portas e a utilização da função de delay da Linguagem C. Através dos botões S1 e S2, Up e Down é possível ajustar a freqüência de oscilação dos Leds 3 e 4 da placa McLab2. As constantes min e max determinam os limites, máximos e mínimos de ajuste da freqüência de oscilação. Para a inversão das portas está sendo utilizado o operador lógico “~”, (NOT, complemento de 1), com este operando estaremos invertendo bit a bit o conteúdo do registrador portb. A função delay_ms gera um atraso de milisegundos usando o ciclo de máquina, ou seja, o programa fica travado nesta função até o tempo desejado. O camando For (inicialização, teste condicional, incremento) é utilizado para controle do laço da rotina de delay, definindo a quantidades de vezes que o laço será executado, nesta rotina não utilizaremos a opção de inicialização do comando For, sendo a mesma executada fora do laço.
Linguagem C para PIC
13
1.11 - Esquema Elétrico
+5V
RESET 10K 1 2 3 4 5 6 7
+5V
8 9 10 11 12 13 14 15
4MHz
+5V
MC1
16 17 18 23 24
MCLR RA0 RA1 RA2 RA3 RA4 RA5 RE0 RE1 RE2 VDD VSS OSC1 OSC2 RC0 RC1 RC2 RC3 RC4 RC5
VDD VSS RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 RD7 RD6 RD5 RD4 RD3 RD2 RD1 RD0 RC7 RC6
32 31 40 39 38 37 36 35 34 33 30 29 28 27 22 21 20 19 26 25
16F877A
+5V
+5V
10K
RB0
10K
RB1 S1
RB2 S2
RB3 330R
L3
14 Linguagem C para PIC
330R
L4
1.12 - Fluxograma A MAIN
CONFIGURAÇÕES INICIAIS TRIS, PORTAS, WATCHDOG, PRESCALER.
NÃO
SIM
BOTÃO S1 PRESS.?
INICIALIZA PORTB COM 0X0F
SIM
TEMPO = MAX?
B NÃO
LIMPA WATCHDOG
INCREMENTA TEMPO COMPLEMENTA PORTB
A NÃO
SIM
BOTÃO S2 PRESS.?
SIM
TEMPO = MIN?
NÃO
DECREMENTA TEMPO
CARREGA A VARIÁVEL CONTADOR COM O VALOR DA VARIÁVEL TEMPO
ROTINA DE DELAY LAÇO FOR
B
NÃO
CONTADOR ≠ 0
SIM DELAY (10MS)
Linguagem C para PIC
15
1.13 - Código /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Programação em C - Recursos Básicos de programação * * Exemplo 2 * * * * CENTRO DE CAPACITAÇÃO - LABTOOLS * * * * TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br * * E-MAIL:
[email protected] * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * VERSÃO : 1.0 * * DATA : 05/06/2003 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Descrição geral * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // Este software demonstrará a utilização da função de delay e //a frequência de oscilação dos leds é controlada pelos botões
* * * * * * * * * * * * */ a inversão de portas S1 (UP) e S2 (DOWN).
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição das variáveis internas do PIC * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <16f877A.h> // microcontrolador utilizado /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações para gravação * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt // configuração dos fusíveis /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definições para uso de Rotinas de Delay * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use delay(clock=4000000, RESTART_WDT) // diretiva para o uso da função delay /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização das variáveis * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //Neste bloco estão definidas as variáveis globais do programa. int contador = 0 ; int tempo = 9; /* * * * * * * * * * * * * * * * * * * * * * * * * * Constantes internas * * * * * * * * * * * * * * * * * * * * * * * * * //A definição de constantes facilita a programação //Este programa não utiliza constantes #define max 255 // Limite de ajuste do #define min 10
* * * * * * * * * * * * * * * * * * * * * * * * */ e a manutenção. tempo
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Declaração dos flags de software * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de flags ajuda na programação e economiza memória RAM. //Este programa não utiliza nenhum flag de usuário. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização dos port's * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use fast_io(a) #use fast_io(b) #use fast_io(c) #use fast_io(d) #use fast_io(e) #byte #byte #byte #byte
porta portb portc portd
= = = =
16 Linguagem C para PIC
0x05 0x06 0x07 0x08
#byte porte = 0x09 /* * * * * * * * * * * * * * * * * * * * * // As entradas devem //futuras alterações #bit botao_0 #bit
botao_1
* * * * * * * * * * * * * * * * * * * * * * * * * * ENTRADAS * * * * * * * * * * * * * * * * * * * * * * * * * * ser associadas a nomes para facilitar a programação do hardware. = portb.0 // Estado do botão_0 // 1 -> Liberado // 0 -> Pressionado = portb.1 // Estado do botão_1 // 1 -> Liberado // 0 -> Pressionado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * SAÍDAS * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // As saídas devem ser associadas a nomes para facilitar a programação //futuras alterações do hardware.
* * */ e
* * */ e
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações do Microcontrolador * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void main () { setup_counters(rtcc_internal,wdt_2304ms); set_tris_a(0b11111111); set_tris_b(0b11110011); set_tris_c(0b11111111); set_tris_d(0b11111111); set_tris_e(0b00000111); porta portb portc portd porte
= = = = =
0x00; 0x0f; 0x00; 0x00; 0x00;
// carrega portb com valor inicial
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Loop principal * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ while(TRUE) { RESTART_WDT(); portb = ~portb;
// complemanta o portb
if (!botao_0) // { if (tempo != max) // { tempo = tempo + 1; // } } //
O botão_0 foi pressionado? sim, tempo é diferente de max? não, incrementa tempo botão_0 liberado, testa botão 1
if (!botao_1) // O botão 1 foi pressionado ? { if (tempo != min) // sim, tempo é diferente de min? { tempo = tempo - 1; // não, decrementa tempo } } // botão_1 liberado contador = tempo; // carrega contador for (;contador!=0; contador--) // contador é diferente de 0? se sim // decrementa contador e executa o comando delay_ms(10); // comando: delay de 10 milisegundos. } }
Linguagem C para PIC
// FIM DO PROGRAMA
17
1.14 - Exercícios Propostos Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e soluções, seguindo os exercícios propostos: 1. Implemente a inversão de portas para que o led 3 e o led 4 pisquem alternadamente. 2. Utilize a forma reduzida para incrementar e decrementar a variável tempo. 3. Troque a função delay_ms por delay_us e ajuste as constantes para obter o mesmo ajuste de freqüência. 4. Substitua o comando For pelo comando While.
18 Linguagem C para PIC
1.15 - Anotações
Linguagem C para PIC
19
Recursos Básicos: Exemplo 3
Contador Hexadecimal
1.16 - Recursos do Livro Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos nos exemplos anteriores e tabela de constante (cap.12.21 pág. 309 do livro Programação em C).
1.17 - Lógica do exemplo Através dos botões S1 e S2 o contador será incrementado ou decrementado, e o seu valor mostrado no display de sete segmentos ds4. A finalidade de nosso exemplo é demonstrar a implementação de tabelas utilizando a memória de programa, sendo está tabela uma matriz unidimensional, nossa tabela fará a conversão de BCD para sete segmentos, realizando a função de um circuito decodificador. Para o devido tratamento dos botões, neste exemplo foi implementada uma rotina de filtro para cada botão evitando o problema de debouncing, além do filtro foi criado um flag, para cada botão, que tem a função de indicar se a tecla está pressionada ou liberada. Desta forma para que o contador seja incrementado ou decrementado o botão deve ser pressionado e depois liberado. A variável contador será utilizada como indexador da tabela de constante, assim sendo para o contador igual à zero, será retornado o código de sete segmentos para o número zero e assim por diante.
20 Linguagem C para PIC
1.18 - Esquema Elétrico
220R +5V a b c d e f g Dp
+5V RESET
10K
MC1 1 2 3 4 5 6 7
+5V
8 9 10 11 12 13 14 15
4MHz
16 17 18 23 24
MCLR RA0 RA1 RA2 RA3 RA4 RA5 RE0 RE1 RE2 VDD VSS OSC1 OSC2 RC0 RC1 RC2 RC3 RC4 RC5
VDD VSS RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 RD7 RD6 RD5 RD4 RD3 RD2 RD1 RD0 RC7 RC6
32
DS4 a f
g
e
b c
d
Dp
31 40
220R
39 38
BC337
4,7K
37 36 35 34 33 30 29 28 27 22 21 20 19 26 25
16F877A
+5V
+5V
10K
10K
RB1
RB0 S1
S2
PIC16F877
Linguagem C para PIC
21
1.19 - Fluxograma
MAIN
CONFIGURAÇÕES INICIAIS TRIS, PORTAS, WATCHDOG, PRESCALER.
INICIALIZA PORTB COM 0X10 B LIMPA WATCHDOG
A
22 Linguagem C para PIC
A
NÃO
BOTÃO S1 PRESS.?
SIM
Re-carrrega o Filtro do Botão Marca botão liberado
O botão já estava pressionado ?
SIM
NÃO
C
NÃO
Filtro ≠ 0 ?
Marca Botão pressionado
SIM
Decrementa o Filtro
Contador ≠ Max ?
NÃO
SIM Incrementa o contador Consulta tabela de conversão e atualiza o display
C
Linguagem C para PIC
23
C
NÃO
BOTÃO S2 PRESS.?
SIM
Re-carrrega o Filtro do Botão Marca botão liberado
O Botão já estava pressionado ?
NÃO
B
NÃO
Filtro ≠ 0 ?
Marca Botão pressionado
SIM
Decrementa o Filtro NÃO
Contador ≠ Min ?
SIM Decrementa o contador Consulta tabela de conversão e atualiza o display
B
24 Linguagem C para PIC
SIM
1.20 - Código /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Programação em C - Recursos Básicos de programação * Exemplo 3 * * CENTRO DE CAPACITAÇÃO - LABTOOLS * * * TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br * * E-MAIL:
[email protected] * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * VERSÃO : 1.0 * DATA : 05/06/2003 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /* * * // //
* * * * * * * * */
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Descrição geral * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ Contador hexadecimal que utiliza dois botões para incrementar e decrementar o valor da variável "contador". O contador está limitado pelas constantes min e max.
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DEFINIÇÃO DAS VARIÁVEIS INTERNAS DO PIC * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include <16f877A.h> // microcontrolador utilizado /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações para gravação * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt // configuração dos fusíveis /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definições para uso de Rotinas de Delay * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use delay(clock=4000000, RESTART_WDT) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Constantes internas * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de constantes facilita a programação e a manutenção. #define t_filtro 400 #define min 0 #define max 15
// tamanho do filtro // valor mínimo para o contador // valor máximo para o contador
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização das variáveis * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //Neste bloco estão definidas as variáveis globais do programa. int contador=min; // long int filtro0=t_filtro; // long int filtro1=t_filtro; // int flags=0; //
inicia contador com mínimo inicia filtro do bot1 inicia filtro do bot2 limpa os flags
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Declaração dos flags de software * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de flags ajuda na programação e economiza memória RAM. #bit bt_UP_press = flags.0 #bit bt_DOWN_press = flags.1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização dos port's * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use fast_io(a) #use fast_io(b) #use fast_io(c) #use fast_io(d) #use fast_io(e)
Linguagem C para PIC
25
#byte #byte #byte #byte #byte
porta portb portc portd porte
= = = = =
0x05 0x06 0x07 0x08 0x09
/* * * * * * * * * * * * * * * * * * * * * // As entradas devem //futuras alterações
* * * * * * * * * * * * * * * * * * * * * * * * * * ENTRADAS * * * * * * * * * * * * * * * * * * * * * * * * * * ser associadas a nomes para facilitar a programação do hardware.
#bit
botao_UP = portb.0
#bit
botao_DOWN = portb.1 // Estado do botão DOWN // 1 -> Liberado // 0 -> Pressionado
/* * * // //
* * */ e
// Estado do botão UP // 1 -> Liberado // 0 -> Pressionado
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * SAÍDAS * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * As saídas devem ser associadas a nomes para facilitar a programação futuras alterações do hardware.
* * */ e
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tabela de Valores * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ byte const tabela[16] = { //PGFEDCBA ; POSIÇÃO RELATIVA AOS SEGMENTOS 0b00111111, // 0H - 0 0b00000110, // 1H - 1 0b01011011, // 2H - 2 0b01001111, // 3H - 3 0b01100110, // 4H - 4 0b01101101, // 5H - 5 0b01111101, // 6H - 6 0b00000111, // 7H - 7 0b01111111, // 8H - 8 0b01101111, // 9H - 9 0b01110111, // AH - A 0b01111100, // BH - B 0b00111001, // CH - C 0b01011110, // DH - D 0b01111001, // EH - E 0b01110001}; // FH - F /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações do Microcontrolador * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void main() { setup_counters(rtcc_internal, wdt_2304ms); set_tris_a(0b11111111); set_tris_b(0b11101111); set_tris_c(0b11111111); set_tris_d(0b00000000); set_tris_e(0b00000111); porta = 0x00; portb=(0b00010000); // seleciona display ds4 portc = 0x00; portd = (tabela[contador]); // mostra no display valor inicial do contador porte = 0x00;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
26 Linguagem C para PIC
* Loop principal * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ while(TRUE) // rotina principal { RESTART_WDT(); // incia o watch-dog timer /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tratamento do Botão 0 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ if (!botao_UP) // O botão UP está pressionado ? { // sim, if (!(bt_UP_press)) // O botão UP já foi tratato ? { // não. if (filtro0 !=0) // Fim do filtro do botão UP ? { filtro0--; // Não, então decrementa o filtro } else // Sim, Faz a ação do botão { bt_UP_press = 1; // Marca que o botão está pressionado if (contador != max) { contador++; // incrementa o contador portd = (tabela[contador]); // consulta tabela, atualiza // display } } } } else { // botão 0 liberado filtro0 = t_filtro; // inicia o filtro do botão 0 bt_UP_press = 0; // marca que o botão foi liberado } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tratamento do Botão 1 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ if (!botao_DOWN) // testa botão DOWN { // botão DOWN pressionado if (!(bt_DOWN_press)) // o botão DOWN já foi tratato ? { // não if (filtro1 !=0) // Fim do filtro do botão DOWN ? { filtro1--; // não, então decrementa o filtro } else // SIM. Faz a ação do botão { bt_DOWN_press = 1; // marca que o botão está pressionado if (contador != min) { contador--; // decrementa o contador portd = (tabela[contador]);// consulta tabela, atualiza // display } } } } else { // botão 1 liberado filtro1 = t_filtro; // inicia o filtro do botão 1 bt_DOWN_press = 0; // marca que o botão foi liberado } } }
Linguagem C para PIC
27
1.21 - Exercícios Propostos Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e soluções, seguindo os exercícios propostos: 1. 2. 3. 4.
Modifique o programa para que o contador conte de 1 a 5. Implemente um botão para reset do contador. Altere a tabela para que as posições de A a F da tabela apaguem o display. Mude a contagem do dsp4 para o display dsp3.
28 Linguagem C para PIC
1.22 - Anotações
Linguagem C para PIC
29
Recursos Avançados: Exemplo 4
Maximização de Pinos de I/O
1.23 - Recursos do Livro Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos nos exemplos anteriores e mais, funções do compilador para controle de interrupção, tratamento automático (cap.12 pág.254 do livro Programação em C), controle do processador (cap.11 pág.223 do livro Programação em C), manipulação de Timers (cap.11.8 pág.211 do livro Programação em C), diretivas de configuração para uso de interrupções, #int_xxx e #priority (cap.10, pág.161 e pág.166 do livro Programação em C).
1.24 - Lógica do exemplo Nosso exemplo será composto de um programa capaz de ler quatro botões e tocar o buzzer com uma freqüência diferente para cada combinação de botões. Para cada botão existe um led ligado no mesmo pino, que será utilizado para indicar os botões pressionados no momento. Utilizaremos os timers e duas interrupções para controlarmos a freqüência de leitura dos botões e a freqüência do buzzer: • Timer 0: controlará a freqüência de varredura dos botões; • Timer 2: controlará a freqüência do som. O som será feito excitando o buzzer com uma onda quadrada de freqüência variável. Variaremos esta freqüência alterando o valor de PR2, que controla o estouro deste timer. Desta forma, nosso programa principal será um loop infinito sem efeito algum. Somente ficaremos esperando o acontecimento das interrupções. Para a varredura dos botões ajustaremos a interrupção de TMR0 para aproximadamente 500Hz: Ciclo de Máq. 1 µs
Prescale 8
Conta TMR0 256
Auxiliar -
Período 2048 µs
Freqüência 488 Hz
Além disso, o sistema possui um filtro, regulado pela constante FILTRO_BOTAO, para evitar o debounce da tecla. Este filtro garante que a tecla fique pressionada pelo tempo de FILTRO_BOTAO x 2048µs. Quanto à freqüência do buzzer, esta será controlada por TMR2. Calibramos os valores de pre e postscale para que a freqüência da interrupção do TMR2 varie entre 100Hz e 2kHz, com a variação de PR2 entre 16 e 240: Ciclo de Máq. 1 µs 1 µs
Prescale 16 16
Postscale 1 1
PR2 16 240
Período 256 µs 3840 µs
Freqüência 3906 Hz 260 Hz
Para facilitar a implementação, a cada interrupção inverteremos o estado do pino de acionamento do buzzer. Desta forma, a freqüência deste será equivalente à metade da freqüência da interrupção do TMR2. O Livro Conectando o PIC, possui um cápitulo dedicado a este assunto.
30 Linguagem C para PIC
1.25 - Esquema Elétrico
+5V
RESET 10K 1 2 3 4 5 6 7
BUZZER
8
+5V
9 10 11 12 13 14 15 16
4MHz
+5V
MC1
17 18 23 24
MCLR RA0 RA1 RA2 RA3 RA4 RA5 RE0 RE1 RE2 VDD VSS OSC1 OSC2 RC0 RC1 RC2 RC3 RC4 RC5
VDD VSS RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 RD7 RD6 RD5 RD4 RD3 RD2 RD1 RD0 RC7 RC6
32 31 40 39 38 37 36 35 34 33 30 29 28 27 22 21 20 19 26 25
16F877A
+5V
+5V
10K
RB0
10K
330R
L1
Linguagem C para PIC
10K
RB1 S1
+5V
10K
330R
L2
10K
RB2 S2
+5V
10K
330R
L3
10K
RB3 S3
10K
330R
S4
L4
31
1.26 - Fluxograma
MAIN
CONFIGURAÇÕES INICIAIS TRIS, PORTAS, WATCHDOG, PRESCALER.
LIGA AS INTERRUPÇÕES
LIMPA WATCHDOG
32 Linguagem C para PIC
INTERRUPÇÕES
NÃO
INT DE TMR0?
SIM
Trata TMR2
Trata TMR0
TRATA TMR2
NÃO
SAÍDA DO BUZZER ESTÁ LIGADA?
SIM
DESLIGA A SAÍDA DO BUZZER
LIGA A SAÍDA DO BUZZER
FIM DA INTERRUPÇÃO
Linguagem C para PIC
33
TRATA TMR0
Convetre pinos dos botões em entradas
Delay de 4 ciclos de máquina para estabilização do port
Lê todos os botões e guarda em variável temporária (STATUS_BOTÕES)
Converte pinos dos botões em saída
CHECA BOTÃO S1
Reinicia Filtro
NÃO
Botão S1 PRESS ?
SIM
Limpa Flag de botão pressionado (Status Leds)
Fim do Filtro ?
SIM Marca flag de botão pressionado
CHECA BOTÃO S2
CHECA BOTÃO S3
CHECA BOTÃO S4
A
34 Linguagem C para PIC
NÃO
AÇÃO DOS BOTÕES
A
Atualiza leds conforme botões pressionados
NÃO
Algum botão pressionado ?
SIM
Inicializa PER com 255
Consulta tabela conforme conbinação de botões pressionados
Deliga interrupção de TMR2
Inicializa TMR2
Desliga a saída do Buzzer
Liga Interrupção de TMR2
FIM DA INTERRUPÇÃO
Linguagem C para PIC
35
1.27 - Código /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Programação em C - Recursos Básicos de programação * Exemplo 4 * * CENTRO DE CAPACITAÇÃO - LABTOOLS * * * TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br * * E-MAIL:
[email protected] * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * VERSÃO : 1.0 * DATA : 05/06/2003 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * Descrição geral * * * * * * * * * * * * * * * * * * * * * * * * * * * * // Este software está preparado para ler quatro botões e //duração variavel conforme a tecla pressionada, além de //indicando a última tecla pressionada.
* * * * * * * * */
* * * * * * * * * * * * * * * * * * */ tocar o buzzer com acender o led
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DEFINIÇÃO DAS VARIÁVEIS INTERNAS DO PIC * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include
<16f877A.h>
// microcontrolador utilizado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações para gravação * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt fusíveis
// configuração dos
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Constantes internas * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de constantes facilita a programação e a manutenção. #define t_filtro 20
// tamanho do filtro
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização das variáveis * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //Neste bloco estão definidas as variáveis globais do programa. int status_botoes = 0; int status_leds = 0; int per = 0; int int int int
filtro1 filtro2 filtro3 filtro4
= = = =
t_filtro; t_filtro; t_filtro; t_filtro;
// armazena o estado lógico dos botões // atualiza leds conforme o botão pressionado // limitador de contagem do Timer2 // // // //
inicia inicia inicia inicia
filtro filtro filtro filtro
do do do do
botao1 botao2 botao3 botao4
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização dos port's * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use #use #use #use #use
fast_io(a) fast_io(b) fast_io(c) fast_io(d) fast_io(e)
#byte #byte #byte #byte #byte
porta portb portc portd porte
= = = = =
36 Linguagem C para PIC
0x05 0x06 0x07 0x08 0x09
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Declaração dos flags de software * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de flags ajuda na programação e economiza memória RAM. /* * * * * * * * * * * * * * * * * * * * * // As entradas devem //futuras alterações
* * * * * * * * * * * * * * * * * * * * * * * * * * ENTRADAS * * * * * * * * * * * * * * * * * * * * * * * * * * ser associadas a nomes para facilitar a programação do hardware.
#bit
botao1 = status_botoes.0 // Estado do botão 1 // 1 -> Liberado // 0 -> Pressionado
#bit
botao2 = status_botoes.1 // Estado do botão 2 // 1 -> Liberado // 0 -> Pressionado
#bit
botao3 = status_botoes.2// Estado do botão 3 // 1 -> Liberado // 0 -> Pressionado
#bit
botao4 = status_botoes.3 // Estado do botão 4 // 1 -> Liberado // 0 -> Pressionado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * SAÍDAS * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // AS SAÍDAS DEVEM SER ASSOCIADAS A NOMES PARA FACILITAR A PROGRAMAÇÃO //FUTURAS ALTERAÇÕES DO HARDWARE. #bit #bit #bit #bit
botao1_press botao2_press botao3_press botao4_press
= = = =
#bit
buzzer = porta.5
* * */ e
* * */ E
status_leds.0 status_leds.1 status_leds.2 status_leds.3
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tabela de Valores * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ byte const tabela[16] = {255,16,32,48,64,80,96,112,128,144,160,176,192,208,224,240}; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configuração do Microcontrolador * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // A rotina principal simplesmente limpa o WDT, pois toda a lógica do // programa é tratada dentro das interrupções. void main() { setup_adc_ports (no_analogs); setup_counters(rtcc_internal , rtcc_div_8); setup_timer_2 (t2_div_by_16,per,1); set_tris_a(0b11011111); set_tris_b(0b11110000); set_tris_c(0b11111111); set_tris_d(0b11111111); set_tris_e(0b00000111); porta=(0b00000000); portb=(0b00000000); portc=(0b00000000); portd=(0b00000000); porte=(0b00000000); enable_interrupts(GLOBAL); enable_interrupts(INT_RTCC); #priority timer0,timer2
Linguagem C para PIC
// prioridade para a int de trm0
37
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina principal * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ while(TRUE) // rotina principal { RESTART_WDT(); // incia o watch-dog timer } } /* * * // // // // // //
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina de Tratamento de interrupção de TMR0 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ Esta interrupção ocorrerá a cada 2048us. O filtro dos botões tem duração de 40ms (2048us x 20) e são decrementados a cada interrupção. Esta interrupção é responsável por converter os pinos dos botões em entrada, salvar a condição dos botões em variável temporária e converter os pinos em saída novamente.
#int_rtcc void trata_int_tmr0() { set_tris_b(0b00001111); delay_cycles(4); status_botoes = portb; set_tris_b(0b00000000);
// configura os pinos como entrada para // testar os botões // aguarda 4 ciclos de máquina para a // estabilização do portb // lê o status dos botoes, salva em variável // temporária // configura os pinos como saída para // controle dos leds
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tratamento do Botão 1 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ if (!botao1) { filtro1--; if (filtro1 == 0) { botao1_press = 1; } } else { filtro1 = t_filtro; botao1_press = 0; }
// // // //
testa botão 1 botão 1 está pressionado ? Sim, então decrementa o filtro acabou o filtro do botão 1 ?
// marca que o botão está pressionado
// botão 1 liberado // inicia o filtro do botão 1 // marca que o botão foi liberado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tratamento do Botão 2 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ if (!botao2) { filtro2--; if (filtro2 == 0) { botao2_press = 1; } } else { filtro2 = t_filtro; botao2_press = 0; } /* * * * * * * * * * * * * * * * * * * * * Tratamento do * * * * * * * * * * * * * * * * * * * * if (!botao3) {
38 Linguagem C para PIC
// // // //
testa botão 2 botão 2 está pressionado ? Sim, então decrementa o filtro fim do filtro do botão 2 ?
// marca que o botão está pressionado
// botão 2 liberado // inicia o filtro do botão 2 // marca que o botão foi liberado * * * * * * * * * * * * * * * * Botão 3 * * * * * * * * * * * * * * * * */ // testa botão 3 // botão 3 está pressionado ?
filtro3--; if (filtro3 == 0) { botao3_press = 1; } } else { filtro3 = t_filtro; botao3_press = 0; } /* * * * * * * * * * * * * * * * * * * * * Tratamento do * * * * * * * * * * * * * * * * * * * * if (!botao4) { filtro4--; if (filtro4 == 0) { botao4_press = 1; } } else { filtro4 = t_filtro; botao4_press = 0; }
// Sim, então decrementa o filtro // fim do filtro do botão 3 ? // marca que o botão está pressionado
// botão 3 liberado // inicia o filtro do botão 3 // marca que o botão foi liberado * * * * * * * * * * * * * * * * Botão 4 * * * * * * * * * * * * * * * * */ // testa botão 4 // botão 4 está pressionado ? // Sim, então decrementa o filtro // fim do filtro do botão 4 ? // marca que o botão está pressionado
// botão 4 liberado // inicia o filtro do botão 4 // marca que o botão foi liberado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Atualiza Leds conforme botões pressionados * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ portb = status_leds; // atualiza os leds if (status_leds == 0) { per = 0xff; setup_timer_2 (t2_div_by_16,per,1); disable_interrupts (INT_TIMER2); buzzer = 0; } else { per = (tabela[status_leds]);// consulta tabela e inicializa timer2. setup_timer_2 (t2_div_by_16,per,1); enable_interrupts (INT_TIMER2); // habilita interrupção de timer2. } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina de Tratamento de interrupção de TMR2 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Está interrupção só irá ocorrer quando alguma tecla estiver pressionada, // o periodo de ocorrência depende do botão ou da conbinação de botões pressionados, // ela irá inverter o pino de I/O do buzzer a cada interrupção. #int_timer2 void trata_int_tmr2() { if (buzzer != 0) // o buzzer está ligado ? { buzzer = 0; // sim, então desliga } else { buzzer = 1; // não, então liga } }
Linguagem C para PIC
39
1.28 - Exercícios Propostos Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e soluções, seguindo os exercícios propostos: 1. Utilize as funções disponíveis do Compilador para inverter o estado do buzzer. 2. Modifique o controle dos leds, os botões pares controlam os leds impares e os botões impares controlam os leds pares, conforme a tabela abaixo. Botão 1 Botão 2 Botão 3 Botão 4 Led 2 Led 1 Led 4 Led3
40 Linguagem C para PIC
1.29 - Anotações
Linguagem C para PIC
41
Recursos Avançados: Exemplo 5
Varredura de Display
1.30 - Recursos do Livro Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos nos exemplos anteriores e mais, funções do compilador para controle de interrupção, tratamento manual (cap.12 pág.254 do livro Programação em C), controle do processador (cap.11 pág.223 do livro Programação em C), manipulação de Timers (cap.11.8 pág.211 do livro Programação em C), introdução de código em assembly no programa em C (cap.10, pág.151 do livro Programação em C),retorno de valores em funções assembly (cap.9, pág.147 do livro Programação em C), diretivas de configuração para uso de interrupções, #int_global e #priority (cap.10, pág.162 e pág.166 do livro Programação em C).
1.31 - Lógica do exemplo O exemplo desenvolvido para esta aula faz muito mais que simplesmente implementar a varredura dos displays. Trata-se de um contador regressivo de segundos, ou seja, um temporizador capaz de contar até 9.999 segundos. Para isso, utilizaremos os displays para indicar o valor atual do temporizador. A primeira tecla (S1) não possui nenhuma função. Por outro lado, o led relacionado a ela (L1) será utilizado para indicar o estado do temporizador: L1 Aceso Apagado
Descrição Temporizador em contagem regressiva Temporizador paralisado
Os demais botões apresentam as funções de controle do temporizador: Botão S2 S3 S4
Descrição Incrementa o valor inicial em 1 segundo Decrementa o valor inicial em 1 segundo Inicia e paralisa o temporizador
Os botões de incremento e decremento operam de forma rotativa, isto é, comutam automaticamente entre 0000 e 9999. Outra característica destes botões é que eles executam suas funções repetidamente quando mantidos pressionados e só funcionam quando o temporizador está paralisado. Ao atingir o valor zero (0000) o temporizador é automaticamente paralisado, desligandose o led indicativo (L1). Para o sistema de varredura foram criadas 4 variáveis para armazenamento dos dígitos mostrados nos respectivos displays: UNIDADE, DEZENA, CENTENA e MILHAR. Estas variáveis representam o valor atual do temporizador e são incrementadas e decrementadas através dos botões. Na verdade, os botões alteram diretamente o valor da unidade. A lógica do sistema compara este valor com os limites (0 e 9) para alterar ou não os demais dígitos. A freqüência de varredura é controlada pela interrupção de Timer0. Ajustamos seus parâmetros para que a comutação entre displays (tempo da interrupção) seja de aproximadamente 4kHz: Ciclo de Máq. 1 µs 42 Linguagem C para PIC
Prescale 1
Conta TMR0 256
Auxiliar -
Período 256 µs
Freqüência 3900 Hz
A freqüência de varredura será a freqüência de comutação dividida pelo número de displays, que no nosso caso será de aproximadamente 1kHz. Dentro do tratamento da interrupção de TMR0 é desligado o display atual, carregado o valor do dígito correspondente ao display e ligado o display seguinte. Quanto à contagem dos segundos, utilizamos a interrupção de Timer1 para esta finalidade. Veja os ajustes dos parâmetros para esta interrupção: Ciclo de Máq. 1 µs
Prescale 8
Conta TMR1 62500
Auxiliar 2
Período 1.000.000 µs
Freqüência 1 Hz
Para isso, configuramos o prescale de TMR1 em 1:8 e iniciamos o contador com o valor total menos o desejado para a contagem (65.536 – 62.500). Desta maneira a interrupção acontecerá a cada 0,5 segundo. Para podermos contar 1 segundo foi criado uma variável auxiliar denominada DIVISOR_TMR1. Cada vez que o sistema entrar na interrupção de TMR1 e o contador auxiliar (DIVISOR_TMR1) terminar, o tempo é decrementado, começando pela unidade e chegando até a milhar, se for necessário. Quando o tempo termina (0000) tanto o led quanto o TMR1 são desligado. Neste exemplo está sendo utilizado o tratamento Manual de interrupções, neste modo nós devemos providenciar todo o código necessário para o tratamento da interrupção, tais como: salvar contexto, restaurar contexto, limpar os flags de indicação de interrupção e criar os registradores para as rotinas de salvar e restaurar contexto. A prioridade de tratamento da interrupção depende da seqüência de teste dos flags de int, que também é de responsabilidade do programador. Para este tipo de tratamento estamos utilizando a diretiva #int global.
Linguagem C para PIC
43
1.32 - Esquema Elétrico 220R a b c d e f g Dp
f
DS1
DS2
DS3
a
a
a
g
e d
220R
b
f
c
e
g
d
Dp
Comum 1 BC337
b
f
c
e
Dp
Comum 2 BC337
g
d
DS4 a b
f
c
e
Dp
Comum 3 BC337
+5V +5V RESET
10K
2 3 4 5 6 7 8 9 10 11 12 13 14 15
4MHz
4,7K
4,7K
MC1 1
+5V
4,7K
16 17 18 23 24
MCLR RA0 RA1 RA2 RA3 RA4 RA5 RE0 RE1 RE2 VDD VSS OSC1 OSC2 RC0 RC1 RC2 RC3 RC4 RC5
VDD VSS RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 RD7 RD6 RD5 RD4 RD3 RD2 RD1 RD0 RC7 RC6
32 31 40 39 38 37 36 35 34 33 30 29 28 27 22 21 20 19 26 25
16F877A
+5V
+5V
+5V
RB0 330R
10K
RB1 S2 L1
44 Linguagem C para PIC
10K
10K
RB2
RB3 S3
S4
4,7K
g
b c
d
Dp
Comum 4 BC337
1.33 - Fluxograma
MAIN
CONFIGURAÇÕES INICIAIS TRIS, PORTAS, WATCHDOG, PRESCALER.
Configura Timer1
Liga as interrupções A Limpa WATCHDOG
BOTÃO UP PRESS.?
SIM
Trata Botão UP
NÃO
BOTÃO DOWN PRESS.?
SIM
Trata Botão Down
NÃO
BOTÃO Start/Stop PRESS.?
SIM
Trata Botão Start/Stop
NÃO
Recarrega Filtro e turbo das teclas
Linguagem C para PIC
45
INTERRUPÇÕES
NÃO
INT DE TMR0?
SIM
SWITCH CASE Recarrega Timer1
Atualiza Display da Unidade?
SIM
decrementa contador de int.
Incrementa ponteiro de seleção de Display, desliga display do milhar, consulta tabela de conversão para sete segmentos, liga display da unidade
NÃO
Passou 1 segundo ?
NÃO
Atualiza Display da Dezena?
SIM
NÃO
SIM
Recarrega contador de int. Atualiza Display da Centena?
Decrementa Timer
Timer Chegou a zero?
NÃO
Atualiza Display do milhar?
NÃO
Desliga led de indicação de timer operando FIM DA INTERRUPÇÃO
FIM DA INTERRUPÇÃO
46 Linguagem C para PIC
SIM
Incrementa ponteiro de seleção de Display, desliga display da dezena, consulta tabela de conversão para sete segmentos, liga display da centena
NÃO
SIM
Desabilita interrupção de Timer1
Incrementa ponteiro de seleção de Display, desliga display da unidade, consulta tabela de conversão para sete segmentos, liga display da dezena
SIM
Zera ponteiro de seleção de Display, desliga display da centena, consulta tabela de conversão para sete segmentos, liga display do milhar
Trata Botão UP
Timer Ligado ?
Trata Botão DOWN
SIM
Timer Ligado ?
NÃO
NÃO
Decrementa Filtro
Decrementa Filtro
NÃO Fim do Filtro ?
NÃO Fim do Filtro ?
SIM
SIM
Decrementa Turbo
Fim do Temporizador para Turbo do Botão?
Decrementa Turbo
NÃO
Fim do Temporizador para Turbo do Botão?
SIM
NÃO
SIM
Recarrega temporizador para Turbo
Recarrega temporizador para Turbo
Incrementa Timer
Decrementa Timer
A
A
Linguagem C para PIC
SIM
47
Trata botão Start/Stop
SIM Ação já foi executada ?
NÃO
NÃO Filtro terminou ?
SIM
NÃO Timer ligado ?
SIM SIM Timer é igual a zero ?
Apaga led de indicação de Timer ligado
NÃO
Acende Led de indicação de Timer ligado
Carrega Timer1
Carrega contador de interrupções
Habilita interrupção de Timer 1
A
48 Linguagem C para PIC
Desabilita interrupção de Timer1
A
Incrementa Timer
Decrementa Timer
Incrementa unidade
Decrementa unidade
NÃO Unidade = 10 ?
NÃO Unidade = 0XFF ?
SIM
SIM
Zera unidade Incrementa dezena
Unidade = 9 Decrementa dezena
NÃO Dezena = 10 ?
NÃO Dezena = 0XFF ?
SIM
SIM
Zera dezena Incrementa centena
Dezena = 9 Decrementa centena
NÃO centena = 10 ?
NÃO centena = 0XFF ?
SIM
SIM
Zera centena Incrementa milhar
Centena = 9 Decrementa milhar
NÃO Milhar = 10 ?
Linguagem C para PIC
NÃO Milhar = 0XFF ?
SIM
SIM
Zera milhar
Milhar = 9
Return
Return
49
1.34 - Código /* * * * * * * * * * * * /* * * // // // // // // // // /* * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Programação em C - Recursos Básicos de programação * Exemplo 5 * * CENTRO DE CAPACITAÇÃO - LABTOOLS * * TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br * E-MAIL:
[email protected] * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * VERSÃO : 1.0 * DATA : 05/06/2003 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Descrição geral * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ Este exemplo foi preparado para demonstrar o funcionamento do TIMER de 16 bits do PIC (TMR1), da varredura de displays e do tratamento manual de int. Consiste num temporizador de segundos. dois botões foram utilizados para programar o tempo da contagem. Um outro botão foi utilizado para disparar o contador. O temporizador consegue contar até 9999 segundos, de forma que os 4 displays de 7 segmentos foram necessários. A contagem é regressiva. um led indica que o temporizador está operando. Quando o sistema chega a 0000 (ZERO) o led é desligado automaticamente. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DEFINIÇÃO DAS VARIÁVEIS INTERNAS DO PIC * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include
<16f877A.h>
// microcontrolador utilizado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações para gravação * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt fusíveis
// configuração dos
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definições para uso de Rotinas de Delay * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use
delay(clock=4000000, RESTART_WDT)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Constantes internas * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de constantes facilita a programação e a manutenção. #define t_filtro 250 // tamanho do filtro #define turbo_tecla 60 #define delta_timer1 (65536 - 62500) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização das variáveis * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //Neste bloco estão definidas as variáveis globais do programa. int int int int int int int int
display = 0 ; contador = 2; filtro = t_filtro; turbo = 1; unidade = 9; dezena = 9; centena = 9; milhar = 9;
static static static static
int int int INT
W_TEMP; STATUS_TEMP; FSR_TEMP; PCLATH_TEMP;
50 Linguagem C para PIC
// atualiza os displays // contador de interrupções de timer1 // inicia filtro dos botões // inicia turbo das teclas // variável unidade do timer de 1 seg // variável dezena do timer de 1 seg // variável centena do timer de 1 seg // variável milhar do timer de 1 seg // variáveis para salvar contexto
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização dos port's * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use fast_io(a) #use fast_io(b) #use fast_io(c) #use fast_io(d) #use fast_io(e) #byte #byte #byte #byte #byte
porta=0x05 portb=0x06 portc=0x07 portd=0x08 porte=0x09
/* * * * * * * * * * * * * * * * * * * * * * * * * * * Definição de SFR's * * * * * * * * * * * * * * * * * * * * * * * * * * #bit tmr1if = 0x0c.0 // tmr1if é #bit t0if = 0x0b.2 // t0if é o #bit tmr1ie = 0x8c.0 // tmr1ie é #byte status = 0x03 // define endereço #byte fsr = 0x04 // define endereço #byte pclath = 0x0a // define endereço
* * * * * * * * * * * * * * * * * * * * * * */ o bit 0 do sfr pir1 bit 2 do sfr intcon o bit 0 do fsr pie1 do reg de status do reg de fsr do reg de pclath
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Declaração dos flags de software * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de flags ajuda na programação e economiza memória RAM. /* * * * * * * * * * * * * * * * * * * * * // As entradas devem //futuras alterações
* * * * * * * * * * * * * * * * * * * * * * * * * * ENTRADAS * * * * * * * * * * * * * * * * * * * * * * * * * * ser associadas a nomes para facilitar a programação do hardware.
#bit
bt_up = portb.1
#bit
bt_down
#bit
bt_start_stop = portb.3 // Estado do botão start_stop // 1 -> Liberado // 0 -> Pressionado
// Estado do botão up // 1 -> Liberado // 0 -> Pressionado
= portb.2
// Estado do botão down // 1 -> Liberado // 0 -> Pressionado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * SAÍDAS * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // AS SAÍDAS DEVEM SER ASSOCIADAS A NOMES PARA FACILITAR A PROGRAMAÇÃO //FUTURAS ALTERAÇÕES DO HARDWARE. #bit
estado_timer = portb.0
#bit #bit #bit #bit
disp0 disp1 disp2 disp3
= portb.4 = portb.5 = portb.6 = portb.7
Linguagem C para PIC
* * */ e
* * */ E
// led de estado do timer // 1 -> timer contando // 0 -> timer parado // seleção do display unidade (0) // seleção do display dezena // seleção do display centena (2) // seleção do display milhar (3)
(1)
51
/* * * * * * * * * * * * * * * * * * * * * * * * Tabela de Valores * * * * * * * * * * * * * * * * * * * * * * * byte const converte[11] = { //PGFEDCBA 0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110, 0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111, 0b00000000}; /* * * * * * * * * * * * * * Função * * * * * * * * * * * * * decrementa_timer() { unidade --; if (unidade == 0xff) { unidade = 9; dezena --; } if (dezena == 0xff) { dezena = 9; centena --; } if (centena == 0xff) { centena = 9; milhar --; } if (milhar == 0xff) { milhar = 9; } } /* * * * * * * * * * * * * * Função * * * * * * * * * * * * * incrementa_timer() { unidade ++; if (unidade == 10) { unidade = 0; dezena ++; } if (dezena == 10) { dezena = 0; centena ++; } if (centena == 10) { centena = 0; milhar ++; } if (milhar == 10) { milhar = 0; } }
52 Linguagem C para PIC
* * * * * * * * * * * * * * * * * * * * * * * * * * */ POSIÇÃO RELATIVA AOS SEGMENTOS // 0H - 0 // 1H - 1 // 2H - 2 // 3H - 3 // 4H - 4 // 5H - 5 // 6H - 6 // 7H - 7 // 8H - 8 // 9H - 9 // blank
* * * * * * * * * * * * * * * * * * * * * * * de decremento do Timer * * * * * * * * * * * * * * * * * * * * * * * */
* * * * * * * * * * * * * * * * * * * * * * * de incremento do Timer * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função de tratamento de interrupção de Timer1 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Esta interrupção ocorrerá a cada 0,5 segundos, a rotina de tratamento é executada a // cada 2 interrupções (contador). #inline trata_tmr1() { set_timer1(delta_timer1); // carraga timer1 tmr1if = 0; // limpa flag de interrupção contador --; // decrementa contador de interrupções if (contador == 0) { set_timer1(delta_timer1); // carraga timer1 contador = 2; // carrega contador de int decrementa_timer(); if((unidade==0)&&(dezena==0)&&(centena==0)&&(milhar==0))// timer está zerado? { estado_timer = 0; // sim, apaga o led e tmr1ie = 0; // desliga tratamento de interrupção de timer1 } } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina de Tratamento de interrupção de TMR0 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Esta interrupção ocorrerá a cada 256us. #inline trata_tmr0() { t0if = 0; switch(display) // início da varredura dos display´s { case 0: display++; // incrementa a variável de varredura disp3 = 0; // desliga o display 3 portd = (converte[unidade]); // atualiza o portd disp0 = 1; // liga o display 0 break; // sai case 1: display++; // disp0 = 0; // portd = (converte[dezena]); disp1 = 1; // break; //
incrementa a variável de varredura desliga o display 0 // atualiza o portd liga o display 1 sai
case 2: display++; // disp1 = 0; // portd = (converte[centena]); disp2 = 1; // break; //
incrementa a variável de varredura desliga o display 1 // atualiza o portd liga o display 2 sai
case 3: display disp2 = portd = disp3 = break;
inicia a variável de varredura desliga o display 2 // atualiza o portd liga o display 3 sai
= 0; // 0; // (converte[milhar]); 1; // //
} }
Linguagem C para PIC
53
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função para salvar contexto * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ salva_contexto() { #asm MOVWF W_TEMP // SALVA REGISTRADOR DE TRABALHO E SWAPF STATUS,W // DE STATUS DURANTE O TRATAMENTO MOVWF STATUS_TEMP // DA INTERRUPÇÃO. MOVF FSR,W MOVWF FSR_TEMP // SALVA REGISTRADOR FSR MOVF PCLATH,W MOVWF PCLATH_TEMP // SALVA REGISTRADOR PCLATH CLRF PCLATH // LIMPA REGISTRADOR PCLATH, SELECIONA PAGINA 0 CLRF STATUS // LIMPA REGISTRADOR STATUS #endasm } /* * * * * * * * * * * * * * * * * * * * * * * * * * Função para restaurar contexto * * * * * * * * * * * * * * * * * * * * * * * * * restaura_contexto() { #asm MOVF PCLATH_TEMP,W MOVWF PCLATH // RECUPERA REG. MOVF FSR_TEMP,W MOVWF FSR // RECUPERA REG. SWAPF STATUS_TEMP,W MOVWF STATUS // RECUPERA REG. SWAPF W_TEMP,F SWAPF W_TEMP,W // RECUPERA REG. #endasm }
* * * * * * * * * * * * * * * * * * * * * * */
PCLATH (PAGINAÇÃO) FSR (END. INDIRETO) STATUS WORK
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configuração do Microcontrolador * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void main() { setup_adc_ports (no_analogs); setup_counters(rtcc_internal, wdt_2304ms); setup_timer_1 (t1_internal | t1_div_by_8); set_tris_a(0b11111111); set_tris_b(0b00001110); set_tris_c(0b11111111); set_tris_d(0b00000000); set_tris_e(0b00000111); porta=(0b00000000); portb=(0b00000000); portc=(0b00000000); portd=(0b00000000); porte=(0b00000000); enable_interrupts(INT_RTCC ); enable_interrupts(GLOBAL); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Loop principal * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ loop: while(TRUE) { RESTART_WDT();
54 Linguagem C para PIC
// rotina principal // incia o watch-dog timer
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tratamento do Botão de incremento (UP) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ if (!bt_up) {
// testa botão up goto
trata_up;// desvia para a rotina de incremento do timer
} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tratamento do Botão de decremento (down) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ if (!bt_down) {
// testa botão down goto
trata_dowm;// desvia para a rotina de decremento do timer
} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tratamento do Botão de Start / Stop * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ if (!bt_start_stop) // testa botão start_stop { goto trata_start_stop; // desvia para a rotina para ligar ou // desligar o timer } filtro = t_filtro; turbo = 1; } //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * trata_up: if (estado_timer == 0) // o timer está parado? { filtro --; // decrementa o filtro if (filtro == 0) // fim do filtro do botão? { turbo --; // decrementa o turbo da tecla if (turbo == 0) // sim, fim do turbo do botão ? { turbo = turbo_tecla; // carrega o turbo incrementa_timer(); // incrementa o timer } } } goto loop; //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * trata_dowm: if (estado_timer == 0) // o timer está parado? { filtro --; // decrementa o filtro if (filtro == 0) // fim do filtro do botão? { turbo --; // decrementa o turbo da tecla if (turbo == 0) // sim, fim do turbo do botão ? { turbo = turbo_tecla; // carrega o turbo decrementa_timer(); // decrementa o timer } } } goto loop;
Linguagem C para PIC
55
//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * trata_start_stop: if (filtro != 0) // o timer está parado? { filtro --; // decrementa o filtro if (filtro == 0) // fim do filtro do botão? { if (estado_timer != 0) // sim, o timer está ligado ? { estado_timer = 0; // indica timer parado tmr1ie = 0; // desliga o tratamento de interrupção de timer1 } else { if((unidade!=0)||(dezena!=0)||(centena!=0)||(milhar != 0)) // timer está zerado? { estado_timer = 1;// não, indica que o timer está contando contador = 2; // carrega contador auxiliar set_timer1(delta_timer1); // carrega timer 1 tmr1if = 0; // limpa flag de int tmr1 tmr1ie = 1; // liga o tratamento de interrupção de timer1 } } } } goto loop; } /* * * // // // //
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função de Tratamento de interrupções * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ Todo o tratamento de interrupção é feito manualmente. As funções salva contexto e restaura contexto foram feitas em assembler Observe que a prioridade das interrupções é realizada através do comando IF e a ordem do teste determina a prioridade no tratamento da interrupção.
#int_global Void trata_int() { salva_contexto();// salva os registradores antes do tratamento da int if (t0if) { trata_tmr0(); } else
// É int de tmr0 ? // sim, trata tmr0
// não, { if (tmr1if) // É int de tmr1 ? { trata_tmr1(); // sim, trata tmr1 } }
// não.
restaura_contexto(); }
56 Linguagem C para PIC
// restaura contexto e sai da int.
1.35 - Exercícios Propostos Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e soluções, seguindo os exercícios propostos: 1. Mude a rotina para que o temporizador conte de forma crescente e desligue quando chegar a zero. 2. Altere a rotina de temporização para que o timer seja decrementado a cada 1 minuto. 3. Mude a rotina do timer para que ele funcione como um cronômetro com um botão de start e um de reset.
Linguagem C para PIC
57
1.36 - Anotações
58 Linguagem C para PIC
Recursos Avançados: Exemplo 6 Controle do LCD 1.37 - Recursos do Livro Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos no exemplo 1 e mais, controle do LCD (cap.12.7.2 pág. 310 do livro Programação em C).
1.38 - Lógica do exemplo Este exemplo foi criado para demonstrar a inicialização de LCD de 2 linhas por 16 caracteres utilizando 8 vias de dados, e como enviar dados e comandos para o LCD. O exemplo controla o acionamento de leds e do ventilador através de um MENU, tecla S1, de escolha de opções, onde será possível escolher as opções de ligar ou desligar através da tecla ENTER, tecla S2. A escolha das telas será controlada pelo comando SWITCH do compilador C. Após o programa ser carregado a seguinte tela será visualizada no display: T a r e f a S e l e c i o n e P r e s s M e n u Quando a tecla S1 é pressionada a mensagem é trocada indicando as opções de controle, pressionando a tecla menu é possível escolher entre controle de leds e controle do ventilador. O controle selecionado é indicado por uma seta .
c t r c t r
d o s d o
l e d s v e n t
Uma vez que a tela de controle foi escolhida, pressione a tecla enter para entrar na tela de controle, de acordo com a tela selecionada poderemos visualizar as seguintes telas: c t r d o s l e d s O N > O F F
V e n t i l a d o r O N > O F F Na tela de controle, deve se pressionar enter para escolher a opção desejada, ON ou OFF, quando a tecla for pressionada o símbolo “>” será deslocado para a condição desejada.
Linguagem C para PIC
59
1.39 - Esquema Elétrico +5V
7 8 9 1 0 1 1 1 2 1 13 4
DB0 DB1 DB2 DB3 DB4 DB5 DB6 DB7
10K
VDD 2 VO 3 VSS 1 4
RS
RS 6 EN 5 R/W
EN
LCD +5V
RESET
10K
+5V
MC1 1
MCLR RA0 RA1 4 RA2 5 RA3 6 RA4 7 RA5 8 RE0 9 RE1 10 1 RE2 1 VDD 1 2 VSS 1 3 OSC1 1 4 1 OSC2 5 1 RC0 6 RC1 1 7 RC2 1 8 2 RC3 3 RC4 2 4 RC5 2 3
RS EN
+5V
4MHz
VDD VSS RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 RD7 RD6 RD5 RD4 RD3 RD2 RD1 RD0 RC7 RC6
3 2 3 1 4 0 3 9 3 8 3 7 3 6 3 5 3 4 33 3 0 2 9 2 8 2 7 2 2 2 1 2 0 1 9 2 6 2 5
16F877 A RB2 +5V
RB3
+5V 330R
10K +Vcc
10K
4,7K
60 Linguagem C para PIC
MINI VENTILADOR BC337
L3
RB1
RB0 S1
1N4148
330R
S2
L4
1.40 - Fluxograma MAIN
CONFIGURAÇÕES INICIAIS TRIS, PORTAS, W ATCHDOG, PRESCALER.
Configura Timer0
Inicializa LCD
Tela principal
Habilita as interrupções A Limpa W ATCHDOG
Escreve tela principal ?
SIM
Tela principal
NÃO
BOTÃO MENUPRESS.?
SIM
Trata Botão Menu
NÃO
BOTÃO ENTER PRESS.?
SIM
Trata Botão ENTER
NÃO
Recarrega Filtro dos Botões
Linguagem C para PIC
61
INT ERRUPÇÕ ES
Declara Variáveis locais
Incrementa contador de interrupções
Temp1 = 40
NÃO
SIM
Zera contador de interrupções SW IT CH CASE
Controle do Led2
SIM
Verifica se o led 1 está aceso Se sim: Pisca o Led 2 a cada 1 segundo. Se não: Apaga o led 2.
NÃO
Controle do T ime - out da tela principal
NÃO
FIM DA INT ERRUPÇÃO
62 Linguagem C para PIC
SIM
Incrementa contador de time out, após 5 segundos, limpa o flag "f_tela_principal", para liberar atualização da tela principal.
Trata Botão MENU
Ação já foi executada ?
SIM
NÃO
Decrementa Filtro
SIM
SIM
Fim do Filtro ?
NÃO
NÃO Contador de Tela < 2
Posiciona a seta na linha 0, coluna 0 do LCD
Posiciona a seta na linha 1, coluna 0 do LCD
A
Linguagem C para PIC
63
Trata Botão ENTER
Ação já foi executada ?
SIM
NÃO
Decrementa Filtro
SIM
Fim do Filtro ?
Carrega a tela de seleção de tarefa: Controle dos Leds ou Controle do Ventilador
Re-inicia time-out
A
64 Linguagem C para PIC
NÃO
Linguagem C para PIC
65
Seleção da Tela de Menu Switch Case
SIM Tela 1 do Menu ?
Posiciona a seta na linha 0 coluna 0
NÃO
SIM Tela 2 do Menu
Posiciona a seta na linha 1 coluna 0
NÃO
Return
Beep
Fim do loop do Beep ? (conta beep)
NÃO
Liga Beep Delay
Desliga Beep Delay
Decrementa conta beep
66 Linguagem C para PIC
SIM
Return
Seleção da Tela de Enter Switch Case
SIM Tela 1 do Enter ? Carrega a tela de controle de leds. Carrega contador para tela 3
NÃO
SIM Tela 2 do Enter Carrega a tela de controle do Ventilador Carrega contador para tela 4
NÃO
SIM Tela 3 do Enter Indica estado dos leds On ou Off emite beep.
NÃO
SIM Tela 4 do Enter
NÃO
Return
Linguagem C para PIC
Indica estado do ventilador On ou Off emite beep
A
67
1.41 - Código /* * * * * * * * * * * * /* * * // // // // // // //
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Programação em C - Recursos Básicos de programação * Exemplo 6 * * CENTRO DE CAPACITAÇÃO - LABTOOLS * * TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br * E-MAIL:
[email protected] * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * VERSÃO : 1.0 * DATA : 05/06/2003 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Descrição geral * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ Este exemplo foi elaborado para explicar o funcionamento do módulo de LCD. Foi criada uma rotina para escrever comandos e uma para escrever caracteres, existe também uma rotina de inicialização necessária para a correta configuração do LCD. Os botões S1 e S2 são respectivamente botão Menu e Enter, o botão Menu seleciona a tarefa que desejamos executar (controle de Leds ou do Ventilador), o botão Enter seleciona a tarefa e funciona como controle de liga/desliga para a tarefa selecionada.
/* * * * * // O //os //de
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DEFINIÇÃO DAS VARIÁVEIS INTERNAS DO PIC * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ arquivo de definições do pic utilizado deve ser referenciado para que nomes definidos pela Microchip possam ser utilizados, sem a necessidade redigitação.
#include
<16f877A.h>
// microcontrolador utilizado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações para gravação * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt fusíveis
// configuração dos
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definições para uso de Rotinas de Delay * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use
delay(clock=4000000, RESTART_WDT)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Constantes internas * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de constantes facilita a programação e a manutenção. #define t_filtro 500
// tamanho do filtro
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização das variáveis * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //Neste bloco estão definidas as variáveis globais do programa. long int filtro = t_filtro; // inicia filtro dos botões int flags1 = 0; // registrador de flags int contador_tela = 0; // contador para seleção de tela int time_out = 0; // registrador para contagem de tempo de time-out int contador,temp1,temp2; // variaveis para a rotina de int de Timer0 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização dos port's * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use fast_io(a)
68 Linguagem C para PIC
#use #use #use #use
fast_io(b) fast_io(c) fast_io(d) fast_io(e)
#byte #byte #byte #byte #byte
porta portb portc portd porte
= = = = =
0x05 0x06 0x07 0x08 0x09
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Declaração dos flags de software * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de flags ajuda na programação e economiza memória RAM. #bit f_tela_principal = /* * * * * * * * * * * * * * * * * * * * * // As entradas devem //futuras alterações
flags1.0
* * * * * * * * * * * * * * * * * * * * * * * * * * * * ENTRADAS * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ser associadas a nomes para facilitar a programação e do hardware.
#bit
menu
= portb.0
#bit
enter = portb.1
// Estado do botão menu // 1 -> Liberado // 0 -> Pressionado // Estado do botão enter // 1 -> Liberado // 0 -> Pressionado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * SAÍDAS * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // AS SAÍDAS DEVEM SER ASSOCIADAS A NOMES PARA FACILITAR A PROGRAMAÇÃO E //FUTURAS ALTERAÇÕES DO HARDWARE. #bit #bit #bit #bit #bit #bit
rs = porte.0 enable = porte.1 led1 = portb.2 // led led2 = portb.3 // led ventilador = portc.1 buzzer = porta.5
// // s3 s4 // //
via do lcd que sinaliza recepção de dados ou comando enable do lcd controle do ventilador controle do buzzer
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina que envia um COMANDO para o LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void comando_lcd(int caracter) { rs = 0; portd = caracter; enable = 1 ; delay_us(1); enable = 0; delay_us(40); }
// // // // //
// seleciona o envio de um comando carrega o portd com o caracter gera pulso no enable espera 1 microsegundo desce o pino de enable espera mínimo 40 microsegundos
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina que envia um DADO a ser escrito no LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void escreve_lcd(int caracter) { rs = 1; portd = caracter; enable = 1; delay_us(1); enable = 0; delay_us(40); }
Linguagem C para PIC
// // // // //
*
*
// seleciona o envio de um comando carrega o portd com o caracter gera pulso no enable espera 1 microsegundo desce o pino de enable espera mínimo 40 microsegundos
69
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função para limpar o LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void limpa_lcd() { comando_lcd(0x01); delay_ms (2); }
*
// limpa lcd
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Inicialização do Display de LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void inicializa_lcd() { comando_lcd(0x30); delay_ms(4);
// envia comando para inicializar display // espera 4 milisengundos
comando_lcd(0x30); delay_us(100);
// envia comando para inicializar display // espera 100 microsengundos
comando_lcd(0x30); comando_lcd(0x38);
// envia comando para inicializar display // configura LCD, 8 bits, matriz de 7x5, 2 linhas
limpa_lcd();
// limpa lcd
comando_lcd(0x0c); comando_lcd(0x06);
// display sem cursor // desloca cursor para a direita
*
} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função de Bip´s * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void bip(long int tempo, long int periodo) { long int conta_bip; conta_bip = tempo / periodo; while (conta_bip) { buzzer = 1; delay_ms(periodo/2);
// define variável local // contabiliza quantas vezes terá // que fazer o loop de bip´s // faça o loop até acabar o conta_bip // liga o buzzer // conta tempo para o período escolhido
buzzer = 0; delay_ms(periodo/2);
// desliga o buzzer // conta tempo para o período excolhido
conta_bip--;
// decrementa o conta_bip
} } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tela Principal * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void tela_principal() { comando_lcd(0x80); // posiciona o cursor na linha 0, coluna 0 printf (escreve_lcd, "Seleciona Tarefa"); // imprime mensagem no lcd comando_lcd(0xC0); // posiciona o cursor na linha 1, coluna 2 printf (escreve_lcd, " Press Menu "); // imprime mensagem no lcd f_tela_principal = 1; // indica que a tecla foi atualizada time_out = 0; // re-inicia contagem do tempo de time-out }
70 Linguagem C para PIC
*
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tela Menu * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void tela_menu() { limpa_lcd(); comando_lcd(0x82); // posiciona o cursor na linha 0, coluna 2 printf (escreve_lcd, "ctr dos leds"); // imprime mensagem no lcd comando_lcd(0xc2); // posiciona o cursor na linha 1, coluna 2 printf (escreve_lcd, "ctr do vent"); // imprime mensagem no lcd } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Seleção de tela após pressionar a tecla enter * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
*
void tela_ctr_led() { limpa_lcd(); comando_lcd(0x82); // posiciona o cursor na linha 0, coluna 2 printf (escreve_lcd, "ctr dos leds"); // imprime mensagem no lcd comando_lcd(0xc4); printf (escreve_lcd, "ON
// posiciona o cursor na linha 1, coluna 4 OFF"); // imprime mensagem no lcd
if (!led1) { comando_lcd(0xc7); escreve_lcd(0x3e); comando_lcd(0xc3); escreve_lcd(' '); } else { comando_lcd(0xc3); escreve_lcd(0x3e); comando_lcd(0xc7); escreve_lcd(' '); }
// // // //
posiciona o cursor na linha 1, coluna 7 envia simbolo "maior" para o lcd posiciona o cursor na linha 1, coluna 3 envia simbolo "espaço" para o lcd
// // // //
posiciona o cursor na linha 1, coluna 3 envia simbolo "maior" para o lcd posiciona o cursor na linha 1, coluna 7 envia simbolo "espaço" para o lcd
} void tela_ctr_ventilador() { limpa_lcd(); comando_lcd(0x83); // posiciona o cursor na linha 0, coluna 3 printf (escreve_lcd, "Ventilador"); // imprime mensagem no lcd comando_lcd(0xc4); printf (escreve_lcd, "ON
// posiciona o cursor na linha 1, coluna 4 OFF"); // imprime mensagem no lcd
if (!ventilador) { comando_lcd(0xc7); escreve_lcd(0x3e); comando_lcd(0xc3); escreve_lcd(' '); } else { comando_lcd(0xc3); escreve_lcd(0x3e); comando_lcd(0xc7); escreve_lcd(' '); }
// // // //
posiciona o cursor na linha 1, coluna 7 envia simbolo "maior" para o lcd posiciona o cursor na linha 1, coluna 3 envia simbolo "espaço" para o lcd
// // // //
posiciona o cursor na linha 1, coluna 3 envia simbolo "maior" para o lcd posiciona o cursor na linha 1, coluna 7 envia simbolo " " para o lcd
}
Linguagem C para PIC
71
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Seleção das telas de Menu * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void sel_tela_menu() { switch(contador_tela) { case 1: tela_menu(); comando_lcd(0x80); // posiciona o cursor na linha 0, coluna 0 escreve_lcd(0x7e); // envia simbolo "seta" para o lcd break; // retorna case 2: tela_menu(); comando_lcd(0xc0); // posiciona o cursor na linha 1, coluna 0 escreve_lcd(0x7e); // envia simbolo "seta" para o lcd break; // retorna da função } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Seleção das telas após pressionar Enter * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
*
void sel_tela_enter() { switch(contador_tela) { case 1: tela_ctr_led(); contador_tela = 3; break;
// retorna da função
case 2: tela_ctr_ventilador(); contador_tela = 4; break;
// retorna da função
case 3: if (!led1) { led1 = 1; // acende o led bip(50,2); comando_lcd(0xc3);// posiciona o cursor na escreve_lcd(0x3e);// envia simbolo "maior" comando_lcd(0xc7);// posiciona o cursor na escreve_lcd(' ');// envia simbolo "espaço"
linha 1, coluna 3 para o lcd linha 1, coluna 7 para o lcd
} else { led1 = 0; // apaga o led comando_lcd(0xc7);// posiciona o cursor na escreve_lcd(0x3e);// envia simbolo "maior" comando_lcd(0xc3);// posiciona o cursor na escreve_lcd(' ');// envia simbolo "espaço" bip(50,2); delay_ms(250); bip(50,2); } break; // retorna da função
72 Linguagem C para PIC
linha 1, coluna 7 para o lcd linha 1, coluna 3 para o lcd
case 4: if (!ventilador) { bip(750,2); ventilador = 1; comando_lcd(0xc3); escreve_lcd(0x3e); comando_lcd(0xc7); escreve_lcd(' '); }
// // // //
// liga o ventilador posiciona o cursor na linha 1, coluna 3 envia simbolo "maior" para o lcd posiciona o cursor na linha 1, coluna 7 envia simbolo "espaço" para o lcd
// // // //
// desliga o ventilador posiciona o cursor na linha 1, coluna 7 envia simbolo "maior" para o lcd posiciona o cursor na linha 1, coluna 3 envia simbolo "espaço" para o lcd
else { bip(1000,2); ventilador = 0; comando_lcd(0xc7); escreve_lcd(0x3e); comando_lcd(0xc3); escreve_lcd(' '); } break;
// retorna da função
} } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações do Pic * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void main() { setup_adc_ports (no_analogs); setup_counters (rtcc_internal, WDT_2304MS); set_tris_a(0b11011111); set_tris_b(0b11110011); set_tris_c(0b11111101); set_tris_d(0b00000000); set_tris_e(0b00000100);
// configuração da direção dos pinos de I/O
porta=0x00; portb=0x00; portc=0x00; portd=0x00; porte=0x00;
// // // // //
limpa limpa limpa limpa limpa
porta portb portc portd porte
inicializa_lcd(); tela_principal();
// configura o lcd // imprime a tela principal no LCD
enable_interrupts(INT_RTCC); enable_interrupts(GLOBAL); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina principal * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ loop: while(TRUE) // rotina principal { RESTART_WDT(); // incia o watch-dog timer /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Verifica se algum botão foi pressionado * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ if (!f_tela_principal) { tela_principal(); }
Linguagem C para PIC
73
//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * if (!menu) {
// testa botão 1 goto
trata_menu;// desvia para a rotina de incremento do timer
} //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * if (!enter) {
// testa botão 2 goto
trata_enter;// desvia para a rotina de incremento do timer
} //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * filtro = t_filtro;
// recarga da variável filtro
} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tratamento do Botão S1 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ trata_menu: //ligar time - out if (filtro != 0) // Ação já foi executada? { filtro --; // não, decrementa o filtro if (filtro == 0) // fim do filtro do botão? { // sim, executa tarefa if (contador_tela < 2) // De selecionar a próxima tarefa? { contador_tela ++;// sim, incrementa contador de seleção de tarefa sel_tela_menu(); // seleciona a tela de menu time_out = 0; // re-inicia contagem do tempo de time-out } else // não, { contador_tela = 1;// Volta para a primeira tela do menu sel_tela_menu(); // carrega a tela de menu time_out = 0; // re-inicia contagem do tempo de time-out } } } goto loop; // sim, volta para o loop principal /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tratamento do Botão S2 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * trata_enter: if (filtro != 0) // Ação já foi executada? { filtro --; // não, decrementa o filtro if (filtro == 0) // fim do filtro do botão? { sel_tela_enter(); // sim, carrega a tela de seleção time_out = 0; // re-inicia contagem do tempo de } } goto loop; }
74 Linguagem C para PIC
* * * * * * * * * * * * * * */
de tarefa time-out
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina de Tratamento de interrupção de TMR0 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Esta interrupção ocorrerá a cada 256us. // A variável auxiliar temp1 será utilizada para contar 40 interrupções, // totalizando 10ms. O comando switch será executado a cada 10ms. #int_rtcc void trata_int_tmr0() { temp1 ++; if (temp1 == 40) { temp1 = 0;
// já passou 10ms? // sim, zera contador de interrupção
switch(contador) { case 0: temp2 ++; if (temp2 == 50) { temp2 = 0;
// seleciona tarefa // controle do led2 // passou 1 segundo? // sim, zera contador de interrupção
if (led1) // O led1 está ligado { if (!led2) // sim, o led2 está ligado? { led2 = 1; // não, liga o led2 } else { led2 = 0; // sim, desliga o led2 } } // não, então não controla o led2 else { led2 = 0;// não, mantém o led2 desligado } } contador ++; // incrementa contador de tarefa break; // fim de execução de execução da tarefa case 1: // time_out = 10ms * 250 * 2 time_out ++; if (time_out == 250) // já passou 5 segundos? { time_out = 0; // sim, zera time_out contador_tela = 0; // zera contador de tela f_tela_principal = 0; // libera atual.tela principal } contador ++; // incrementa contador de tarefa break; // fim de execução de execução da tarefa default: contador = 0; } }
// não, sai da int.
} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Fim do Programa * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Linguagem C para PIC
75
1.42 - Exercícios Propostos Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e soluções, seguindo os exercícios propostos: 1. Mude a rotina para que seja controlado o buzzer no lugar do led 2. 2. Crie mais um nível no Menu para controlar o buzzer.
76 Linguagem C para PIC
1.43 - Anotações
Linguagem C para PIC
77
Recursos Avançados: Exemplo 7
Conversor Analógico Digital
1.44 - Recursos do Livro Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos no exemplo 1 e mais, funções do compilador para controle do conversor analógico digital (cap.11-pág 206 do livro Programação em C).
1.45 - Lógica do exemplo Este exemplo foi elaborado para explicar as funções do CCS para o módulo de conversão analógico digital interno do PIC. É convertido o valor analógico presente no pino RA1 do microcontrolador, sendo que este valor pode ser alterado através do potenciômetro P2 da placa MCLAB2 este valor é ajustado entre 0 e 5V e mostrado no LCD. Neste exemplo foi utilizado variável do tipo float para armazenar o resultado da conversão A/D. Para que possamos visualizar o valor de 0 à 5V no LCD, foi feita uma segunda conversão o valor digital foi convertido para “Volts” realizando uma regra de 3. Valor máximo da resolução do AD (10 bits)
(5V * ADRES) / 1023 = "n" Volts
Tensão de Referência
78 Linguagem C para PIC
Valor a ser mostrado no display
Valor de tensão medido
1.46 - Esquema Elétrico
+5V
4,7K
+
P2 10K
330R RA1
LM358
+5V 1uF
7 8 9 10 11 12 13 14
DB0 DB1 DB2 DB3 DB4 DB5 DB6 DB7
10K
VDD 2 VO 3 VSS 1 4
RS 6 EN 5 R/W
RS EN
LCD +5V
RESET
10K
+5V
MC1 1 2 3 4 5 6 7
RS EN
+5V
8 9 10 11 12 13 14 15
4MHz
16 17 18 23 24
MCLR RA0 RA1 RA2 RA3 RA4 RA5 RE0 RE1 RE2 VDD VSS OSC1 OSC2 RC0 RC1 RC2 RC3 RC4 RC5
VDD VSS RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 RD7 RD6 RD5 RD4 RD3 RD2 RD1 RD0 RC7 RC6
32 31 40 39 38 37 36 35 34 33 30 29 28 27 22 21 20 19 26 25
16F877A
Linguagem C para PIC
79
1.47 - Fluxograma
MAIN
CONFIGURAÇÕES INICIAIS TRIS, PORTAS, WATCHDOG, PRESCALER.
Configura AD: RA0,RA1 e RA3 como entradas analógicas. adc = 10 bits Tensão de Refêrencia interna (VDD e VSS) Frequencia de conversão = fosc / 32 Selecionado Canal 1 Módulo ligado
Inicializa LCD
Prepara Tela principal
A
80 Linguagem C para PIC
A
LIMPA WATCHDOG
Inicia e lê o resultado da conversão
Multiplica valor da conversão por 5
Divide resultado da multiplicação por 1023
Envia resultado para o display
Linguagem C para PIC
81
1.48 - Código /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Programação em C - Recursos Avançados de programação * Exemplo 7 * * CENTRO DE CAPACITAÇÃO - LABTOOLS * * * TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br * * E-MAIL:
[email protected] * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * VERSÃO : 1.0 * DATA : 05/06/2003 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Descrição geral * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Este exemplo foi elaborado para explicar o funcionamento do módulo de // conversão analógico digital interno do PIC. É convertido o valor analógico // presente no pino RA2 do microcontrolador, sendo que este valor pode ser // alterado através do potenciômetro P2 da placa MCLAB2. O valor da conversão // A/D é ajustado numa escala de 0 à 5V e mostrado no LCD. /* * * * * // O //os //de
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DEFINIÇÃO DAS VARIÁVEIS INTERNAS DO PIC * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ arquivo de definições do pic utilizado deve ser referenciado para que nomes definidos pela Microchip possam ser utilizados, sem a necessidade redigitação.
#include <16f877A.h> // microcontrolador utilizado #device adc=10 // configura AD para retornar valor em 10 bits /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações para gravação * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt fusíveis
// configuração dos
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definições para uso de Rotinas de Delay * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use delay(clock=4000000, RESTART_WDT) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Constantes internas * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de constantes facilita a programação e a manutenção. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização das variáveis * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //Neste bloco estão definidas as variáveis globais do programa. float conversao = 0; // armazena o resultado da conversão AD /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização dos port's *
82 Linguagem C para PIC
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use fast_io(a) #use fast_io(b) #use fast_io(c) #use fast_io(d) #use fast_io(e) #byte #byte #byte #byte #byte
porta portb portc portd porte
= = = = =
0x05 0x06 0x07 0x08 0x09
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Declaração dos flags de software * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de flags ajuda na programação e economiza memória RAM. /* * * * * * * * * * * * * * * * * * * * * // As entradas devem //futuras alterações
* * * * * * * * * * * * * * * * * * * * * * * * * * * * ENTRADAS * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ser associadas a nomes para facilitar a programação e do hardware.
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * SAÍDAS * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // As saídas devem ser associadas a nomes para facilitar a programação e //futuras alterações do hardware. #bit rs = porte.0 #bit enable = porte.1
// via do lcd que sinaliza recepção de dados ou comando // enable do lcd
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina que envia um COMANDO para o LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void comando_lcd(int caracter) { rs = 0; portd = caracter; enable = 1 ; delay_us(1); enable = 0; delay_us(40);
// // // //
*
// seleciona o envio de um comando carrega o portd com o caracter gera pulso no enable espera 1 microsegundo desce o pino de enable
// espera mínimo 40 microsegundos
} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina que envia um DADO a ser escrito no LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void escreve_lcd(int caracter) { rs = 1; portd = caracter; enable = 1; delay_us(1); enable = 0; delay_us(40);
// // // //
*
// seleciona o envio de um comando carrega o portd com o caracter gera pulso no enable espera 1 microsegundo desce o pino de enable
// espera mínimo 40 microsegundos
} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função para limpar o LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void limpa_lcd() { comando_lcd(0x01); delay_ms (2); }
Linguagem C para PIC
// limpa lcd
83
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Inicialização do Display de LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void inicializa_lcd() { comando_lcd(0x30); // envia comando para inicializar display delay_ms(4); // espera 4 milisengundos comando_lcd(0x30); // envia comando para inicializar display delay_us(100); // espera 100 microsengundos comando_lcd(0x30); // envia comando para inicializar display comando_lcd(0x38); // liga o display, sem cursor e sem blink limpa_lcd(); // limpa lcd comando_lcd(0x0c); // display sem cursor comando_lcd(0x06); // desloca cursor para a direita } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * void tela_principal() { comando_lcd(0x83); // printf (escreve_lcd, "Voltimetro"); comando_lcd(0xcd); // printf (escreve_lcd, " V"); }
* * * * * * * * * * * * * * * * * * * * Tela Principal * * * * * * * * * * * * * * * * * * * * */ posiciona o cursor na linha 0, coluna 3 // imprime mensagem no lcd posiciona o cursor na linha 1, coluna 14 // imprime mensagem no lcd
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações do Pic * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void main() { setup_adc_ports (RA0_RA1_RA3_analog); setup_adc (adc_clock_div_32); setup_counters (rtcc_internal, WDT_2304MS); set_adc_channel (1); // seleciona o canal 1 do AD set_tris_a(0b11111111); set_tris_b(0b11111111); set_tris_c(0b11111111); set_tris_d(0b00000000); set_tris_e(0b00000100);
// configuração da direção dos pinos de I/O
porta=0x00; portb=0x00; portc=0x00; portd=0x00; porte=0x00;
// // // // //
limpa limpa limpa limpa limpa
porta portb portc portd porte
inicializa_lcd(); tela_principal();
// configura o lcd // imprime a tela principal no LCD
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina principal * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ loop: while(TRUE) // rotina principal { RESTART_WDT(); // incia o watch-dog timer conversao = read_adc(); // inicia conversão AD conversao = (conversao * 5); // faz regra de 3 para converter o valor, conversao = (conversao / 1023); // das unidades de AD em Volts. comando_lcd(0xC2); // posiciona o cursor na linha 1, coluna 2 printf (escreve_lcd,"%1.9f", conversao);// envia dados para o display de LCD // 1 número inteiro e 9 casas decimais.
84 Linguagem C para PIC
} } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Fim do Programa * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Linguagem C para PIC
85
1.49 - Exercícios Propostos Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e soluções, seguindo os exercícios propostos: 1. Mude a configuração do A/D para que ele retorne apenas os 8 bits mais significativos. 2. Altere a função de escrita no LCD para que ela imprima apenas 3 casas depois da virgula. 3. Mude a configuração do A/D para que ele realize as conversões com a Fosc/8.
86 Linguagem C para PIC
1.50 - Anotações
Linguagem C para PIC
87
Recursos Avançados: Exemplo 8 Interna
Controle do PWM e EEPROM
1.51 - Recursos do Livro Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos no exemplo 1 e mais, funções do compilador para controle do PWM (cap.11.9 pág.218 do livro Programação em C), funções do compilador para operação com EEPROM (cap.11.10 pág.219 do livro Programação em C), diretiva #ROM (cap.10, pág.167 do livro Programação em C) e função de manipulação de registradores make8 e make16 (cap.11, pág.200 e 201 do livro Programação em C).
1.52 - Lógica do exemplo Este exemplo foi elaborado para explicar o funcionamento do módulo de PWM e da escrita da EEPROM interna do microcontrolador. Um ventilador terá a sua velocidade controlada através do PWM, o valor ajustado poderá ser salvo na memória EEPROM e restaurado através dos botões. A velocidade do ventilador é medida em rotações por segundo, através do timer1(usado como contador) e mostrada no LCD. Através do botão S1, o PWM é incrementado e decrementado pelo botão S2. Realizando a operação nestes botões será visualizado no LCD o incremento e o decremento em porcentagem(%) e a rotação do ventilador em rps (rotações por segundo). O botão S4 salva o valor de ajuste em EEPROM e o botão S3 restaura o valor salvo atualizando o PWM. Para que possamos utilizar o PWM do PIC não podemos esquecer de configurar a freqüência do PWM no Timer2. T = [(PR2 + 1) * 4] * Tosc * Prescaler TMR2 A função set_pwm_duty(valor), determina o período do pulso do PWM, ou seja, o tempo em que a saída do PWM permanecerá em nível lógico 1. Este valor pode chegar a 1023, enquanto o período do PWM pode chegar a 1024, com PR2 igual a 255. Por está razão dependendo da freqüência do PWM não será possível alcançar os 100% de Duty Cyle. DC = (valor / T), 1023 / 1024 = 0,9990 Então antes de utilizar o PWM, estude o funcionamento do Módulo CCP para um melhor aproveitamento. Este conhecimento pode ser adquirido através do livro Conectando o PIC.
88 Linguagem C para PIC
1.53 - Esquema Elétrico +5V
7 8 9 10 11 12 13 14
DB0 DB1 DB2 DB3 DB4 DB5 DB6 DB7
10K
VDD 2 VO 3 VSS 1 4
RS
RS 6 EN 5 R/W
EN
LCD +5V
RESET
10K
+5V
MC1 1 2 3 4 5 6 7
RS EN
+5V
8 9 10 11 12 13 14 15
4MHz
16 17 18
TACOMETRO
23 24
MCLR RA0 RA1 RA2 RA3 RA4 RA5 RE0 RE1 RE2 VDD VSS OSC1 OSC2 RC0 RC1 RC2 RC3 RC4 RC5
32
VDD VSS RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 RD7 RD6 RD5 RD4 RD3 RD2 RD1 RD0 RC7 RC6
31 40 39 38 37 36 35 34 33 30 29 28 27 22 21 20 19 26 25
16F877A
+5V
+5V
10K
+5V
10K
10K
RB1
RB0
+5V
10K
RB3
RB2
S1
S2
S3
S4
1N4148
4,7K
MINI VENTILADOR
+Vcc
+5V
+5V
BC337 150R SIR381583F
10K 1K RPT38PT3F
1K
Linguagem C para PIC
TACOMETRO
BC337
89
1.54 - Fluxograma M A IN
C O N FIG U R AÇ Õ E S IN IC IAIS T R IS , P O R T AS , W A T C H D O G , P R E SC A LE R .
C onfigura T im er0
Inic ializa LC D
T ela princ ipal
H abilita as interrupç ões A Lim pa W AT C H D O G
S IM E sc reve tela princ ipal ?
T ela principal
NÃO
S IM B O T Ã O U P P R ES S.?
T rata B otão U P
N ÃO
BO T ÃO D O W N P R ES S .?
S IM
T rata B otão D O W N
N ÃO
N ÃO G rava D ados em E E PR O M ?
SIM
S alva dados em EE PR O M
N ÃO
R estaura D ados da E E PR O M ?
N ÃO
90 Linguagem C para PIC
SIM
Lê E EP R O M
A tualiza P wm
Trata Botão UP
Ação já foi executada ?
Trata Botão DOWN
SIM
Ação já foi executada ?
NÃO
NÃO
Decrementa Filtro
Decrementa Filtro
Fim do Filtro ?
NÃO
Fim do Filtro ?
NÃO
SIM
SIM Decrementa Turbo
Decrementa Turbo
Fim do Turbo ?
Fim do Turbo ?
Re-carrega variavel do Turbo
Re-carrega variavel do Turbo
Decrementa PWM do ventilador Atualiza a tela principal
Incrementa PWM do ventilador Atualiza a tela principal
A
Linguagem C para PIC
SIM
A
91
INTERRUPÇÕES
Contador de interrupções é igual a zero ? (Temp1 = 0)
SIM
NÃO
Decrementa contador de interrupções
Carrega variável rotação com o valor do Timer1
Divide variável rotação por 7 (número de palhetas do ventilador) habilita atualização do LCD
FIM DA INTERRUPÇÃO
92 Linguagem C para PIC
1.55 - Código /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Programação em C - Recursos Avançados de programação * Exemplo 8 * * CENTRO DE CAPACITAÇÃO - LABTOOLS * * * TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br * * E-MAIL:
[email protected] * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * VERSÃO : 1.0 * DATA : 05/06/2003 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Descrição geral * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Este exemplo foi elaborado para explicar o funcionamento do módulo de // PWM e da escrita da EEPROM interna do microcontrolador. Um ventilador terá // a sua velocidade controlada através do PWM, o valor ajustado poderá ser // salva na memória EEPROM e restaurado através dos botões. // A velocidade do ventilador é medida em rotações por segundo, através do // timer1 e mostrada no lcd. #include
<16f877A.h>
// microcontrolador utilizado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações para gravação * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt fusíveis
// configuração dos
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição para uso de Rotinas de Delay * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use
delay(clock=4000000, RESTART_WDT)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Inicializa EEPROM * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #rom 0x2100 = {0x03,0xe8} // carrega eeprom com valor inicial, inicia PWM com 97% /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Constantes internas * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de constantes facilita a programação e a manutenção. #define t_filtro 200 #define turbo_tecla 5
// tamanho do filtro // turbo dos botões
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização das variáveis * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //Neste bloco estão definidas as variáveis globais do programa. float duty_cycle = 0; // armazena o resultado da conversão AD long int duty_cycle1 = 0; // armazena o resultado da conversão AD long int periodo_pulso = 0; // long int rotacao = 0; // rps do ventilador int end = 0; // variável para endereçamento da eeprom int flags1 = 0; // flags int filtro = t_filtro; // inicia filtro dos botões int temp1 = 125; // variável aux para int de tmr0 int turbo = 1; // inicia turbo das teclas int dado; // variável de dados para eeprom
Linguagem C para PIC
93
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização dos port's * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use #use #use #use #use
fast_io(a) fast_io(b) fast_io(c) fast_io(d) fast_io(e)
#byte #byte #byte #byte #byte
porta=0x05 portb=0x06 portc=0x07 portd=0x08 porte=0x09
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Declaração dos flags de software * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de flags ajuda na programação e economiza memória RAM. #bit atualiza_lcd = flags1.0 /* * * * * * * * * * * * * * * * * * * * * // As entradas devem //futuras alterações
* * * * * * * * * * * * * * * * * * * * * * * * * * * * ENTRADAS * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ser associadas a nomes para facilitar a programação e do hardware.
#bit
botao1 = portb.0
// Estado do botão 2 // 1 -> Liberado // 0 -> Pressionado
#bit
botao2 = portb.1
// Estado do botão 3 // 1 -> Liberado // 0 -> Pressionado
#bit
botao3 = portb.2
// Estado do botão 4 // 1 -> Liberado // 0 -> Pressionado
#bit
botao4 = portb.3
// Estado do botão 4 // 1 -> Liberado // 0 -> Pressionado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * SAÍDAS * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // As saídas devem ser associadas a nomes para facilitar a programação e //futuras alterações do hardware. #bit rs = porte.0 #bit enable = porte.1 #bit ventilador = portc.1
// via do lcd que sinaliza recepção de dados ou comando // enable do lcd // pino de I/O para controle do ventilador (PWM)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função que envia um COMANDO para o LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void comando_lcd(int caracter) { rs = 0; portd = caracter; enable = 1 ; delay_us(1); enable = 0; delay_us(40); }
94 Linguagem C para PIC
// // // //
// seleciona o envio de um comando carrega o portd com o caracter gera pulso no enable espera 1 microsegundo desce o pino de enable
// espera mínimo 40 microsegundos
*
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função que envia um DADO a ser escrito no LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void escreve_lcd(int caracter) { rs = 1; portd = caracter; enable = 1; delay_us(1); enable = 0; delay_us(40);
// // // //
// seleciona o envio de um caracter carrega o portd com o caracter gera pulso no enable espera 1 microsegundo desce o pino de enable
// espera mínimo 40 microsegundos
} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função para limpar o LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void limpa_lcd() { comando_lcd(0x01); delay_ms (2); }
// limpa lcd
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função de inicialização do Display de LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void inicializa_lcd() { comando_lcd(0x30); delay_ms(4);
// envia comando para inicializar display // espera 4 milisengundos
comando_lcd(0x30); delay_us(100);
// envia comando para inicializar display // espera 100 microsengundos
comando_lcd(0x30);
// envia comando para inicializar display
comando_lcd(0x38);
// liga o display, sem cursor e sem blink
limpa_lcd();
// limpa lcd
comando_lcd(0x0c);
// display sem cursor
comando_lcd(0x06);
// desloca cursor para a direita
} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função para imprimir a Tela Principal * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void tela_principal() { comando_lcd(0x80); // posiciona o cursor na linha 0, coluna 0 printf (escreve_lcd, "Duty cycle RPS"); // imprime mensagem no lcd comando_lcd(0xc3); // posiciona o cursor na linha 1, coluna 3 printf (escreve_lcd,"%" "3Lu%%", duty_cycle1); // envia dados para o display de LCD comando_lcd(0xcb); // posiciona o cursor na linha 1, coluna 11 printf (escreve_lcd,"%" "3Lu", rotacao); // envia dados para o display de LCD }
Linguagem C para PIC
95
/* * * // //
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Salva Dados na EEPROM * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ salva dado na eeprom no endereço indicado através da variável "end", o dado a ser salvo é passado para a Função através da variável "dado".
*
void salva_dados() { write_eeprom (end,dado); } /* * * // //
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Lê Dados na EEPROM * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ lê o dado na eeprom no endereço indicado através da variável "end", o dado lido é carregado na variável "dado".
le_dados(end) { dado = read_eeprom (end); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Atualiza PWM * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void atualiza_pwm() { set_pwm2_duty(periodo_pulso); }
// atualiza duty cicle do PWM
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações do Pic * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void main() { setup_adc_ports (no_analogs); // desliga as entradas analógicas setup_counters (rtcc_internal, rtcc_div_64);// tmr0 clock interno, ps: 1:64 setup_timer_1 (t1_external_sync | t1_div_by_1);// tmr1 clock externo, ps: 1:1 setup_timer_2 (t2_div_by_16,255,1);// tmr2 ps=1:16, pr2=255 e postscale: 1:1 setup_ccp2(ccp_pwm); // modo PWM ligado set_pwm2_duty(periodo_pulso); // ajusta duty cycle em 0. set_tris_a(0b11111111); set_tris_b(0b11111111); set_tris_c(0b11111101); set_tris_d(0b00000000); set_tris_e(0b00000100);
// configuração da direção dos pinos de I/O
porta=0x00; portb=0x00; portc=0x00; portd=0x00; porte=0x00;
// // // // //
inicializa_lcd(); tela_principal();
// configura o lcd // imprime a tela principal no LCD
limpa limpa limpa limpa limpa
porta portb portc portd porte
enable_interrupts(INT_RTCC); enable_interrupts(GLOBAL); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina principal * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * loop: while(TRUE) // rotina principal { RESTART_WDT(); // incia o watch-dog if (atualiza_lcd != 0)
96 Linguagem C para PIC
* * */
timer
{ duty_cycle = periodo_pulso; // carrega valor da rotação medida duty_cycle = (duty_cycle / 1024); // efetua cálculo do duty cycle duty_cycle = (duty_cycle * 100); // converte para porcentagem (%) duty_cycle1 = (long int) duty_cycle; // carrega os 16 bits menos significativos da parte inteira // do resultado da converão tela_principal(); atualiza_lcd = 0; }
// imprime a tela principal no LCD // indica LCD atualizado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tratamento do Botão de incremento (UP) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ if (!botao1) {
// testa botão 1 goto
trata_up;
// desvia para a rotina de incremento do PWM
} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tratamento do Botão de decremento (down) * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ if (!botao2) {
// testa botão 2 goto
trata_dowm;
// desvia para a rotina de decremento do PWM
} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tratamento do Botão ler dados da EEPROM * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ if (!botao3) { le_dados(1); periodo_pulso = dado;
// testa botão 3 // lê byte_low da eeprom // carrega valor lido em variável de 16 bits
le_dados(0); // lê byte_high da eeprom periodo_pulso = make16(dado, periodo_pulso); // recompõe o dado de 16 bits atualiza_pwm(); atualiza_lcd = 1; }
// Função para atualizar o PWM // habilita atualização do LCD
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tratamento do Botão salvar dados na EEPROM * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ if (!botao4) // testa botão 4 { end = 0; // endereço do byte_high dado = make8(periodo_pulso,1); // retorna byte_high salva_dados(); // salva byte_high end = 1; // endereço do byte_low dado = make8(periodo_pulso,0); // retorna byte_low salva_dados(); // salva byte_low } filtro = t_filtro; turbo = 1; }
// carrega filtro dos botões // fecha while
//* * * * * * * * * * * Incrementa duty cycle do PWM * * * * * * * * * * trata_up: { filtro --; // decrementa o filtro if (filtro == 0) // fim do filtro do botão? {
Linguagem C para PIC
97
goto
turbo --; // decrementa o turbo da tecla filtro = t_filtro; if (turbo == 0) // sim, fim do turbo do botão ? { turbo = turbo_tecla; if (periodo_pulso < 1023) // limita incremento do periodo do pulso em 1023 { periodo_pulso ++; atualiza_pwm(); // Função para atualizar o PWM atualiza_lcd = 1; // habilita atualização do LCD } } } } loop;
//* * * * * * * * * * * Decrementa duty cycle do PWM * * * * * * * * * * trata_dowm: { filtro --; // decrementa o filtro if (filtro == 0) // fim do filtro do botão? { turbo --; // decrementa o turbo da tecla filtro = t_filtro; if (turbo == 0) // sim, fim do turbo do botão ? { turbo = turbo_tecla; if (periodo_pulso != 0) // limita decremento do periodo do pulso em 0 { periodo_pulso --; atualiza_pwm(); // Função para atualizar o PWM atualiza_lcd = 1; // habilita atualização do LCD } } } } goto loop; } /* * * // // // //
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina de Tratamento de interrupção de TMR0 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ Esta interrupção ocorrerá a cada 8ms. A variável auxiliar temp1 será utilizada para contar 125 interrupções, totalizando 1 segundo. Quando isto ocorrer, a variável rotação será carregada com o valor de rotações por segundo do ventilador.
#int_rtcc void trata_int_tmr0(void) { set_rtcc(256-125); if (temp1 == 0 ) { rotacao = get_timer1(); set_timer1 (0); rotacao = (rotacao / 7); atualiza_lcd = 1; temp1 = 125; } else
// ja passou 1 segundo? // Sim, // le valor do timer 1 // zera timer 1 // divide por 7 (quantidade de palhetas do ventilador) // habilita atualização do LCD // re-inicia temp1 // Não,
{ temp1 --; }
// decrementa temp1
} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Fim do Programa * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
98 Linguagem C para PIC
1.56 - Exercícios Propostos Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e soluções, seguindo os exercícios propostos: 1. Mude a freqüência do PWM para que possamos ajustar o Duty cycle de 0 a 100%. 2. Ative os dois PWM`s um para o ventilador e outro para a resistência.
Linguagem C para PIC
99
1.57 - Anotações
100 Linguagem C para PIC
Recursos Avançados: Exemplo 9
Coletor de Dados
1.58 - Recursos do Livro Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos no exemplo 1 e mais, funções do compilador para controle de comunicação serial I2C (cap.11.14 pág 240 do livro Programação em C), funções do compilador para controle de comunicação serial RS232 (cap.11.13 pág 230 do livro Programação em C), diretiva de configuração #use i2c e #use RS232 (cap.10, pág.171 e 172 do livro Programação em C).
1.59 - Lógica do exemplo Este exemplo foi elaborado para explicar as funções de I2C do compilador CCS e comunicação serial com a USART. Neste exemplo iremos coletar dados do A/D e armazenar estes dados na EEPROM externa (24c04), estes dados serão enviados ao PC para a visualização dos mesmos. O PC controlará as funções do coletor de dados. Quando for recebido o dado 0x55 o PIC inicia a coleta de dados, ao final da coleta e enviado para o PC o comando 0x0b, para a liberação da transmissão de dados. Após o fim da coleta de dados o PIC aguarda o comando 0xaa, recebendo este dado, ele inicia a transmissão de dados para o PC plotar os dados na tela. Ao final da transmissão ele aguarda novo comando de inicio de coleta de dados.
Linguagem C para PIC
101
1.60 - Esquema Elétrico
+5V
330R RA1
4,7K
+
P2 10K
+5V
1uF
7 8 9 10 11 12 13 14
+5V
RESET 10K 2 3 4 5 6 7
+5V
+5V
RS EN
8 9 10 11 12 13 14
1 2 3 4
A0 A1 A2 GND
VCC WP SCL SDA
8
10K
15
10K
16
4MHz
7 6 5
17 18 23 24
24C04
+5V
MC1 1
MCLR RA0 RA1 RA2 RA3 RA4 RA5 RE0 RE1 RE2 VDD VSS OSC1 OSC2 RC0 RC1 RC2 RC3 RC4 RC5
VDD VSS RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 RD7 RD6 RD5 RD4 RD3 RD2 RD1 RD0 RC7 RC6
31 40 39 38 37 36 35 34 33 30 29 28 27 22 21 20 19 26 25
16F877A
+5V
1uF
1uF
1 3
C1+ C1 -
4 5
C2+ C2 -
13 14
T1IN T1OUT R1OUT R1IN 11
8
T2IN T2OUT R2OUT R2IN 10
7 15
3
2
5
CONECTOR DB9 FEMEA
102 Linguagem C para PIC
+C 2 -C 6
1K
12
9
GND
VCC
MAX-232
16
+5V
1uF
10K
VDD 2 VO 3 VSS 1 4
RS 6 EN 5 R/W
LCD
32
1uF
DB0 DB1 DB2 DB3 DB4 DB5 DB6 DB7
RS EN
1.61 - Fluxograma MAIN
CONFIGURAÇÕES INICIAIS TRIS, PORTAS, W ATCHDOG, PRESCALER.
Configuração: AD, rs232 e I2C
Inicializa LCD
Tela principal
Habilita as interrupções A Limpa W ATCHDOG
Verifica se chegou comando pela USART B
SIM Inicia coleta de dados ?
Coleta Dados
NÃO
Deve transmitir dados para o PC ?
SIM TX Dados para o PC
NÃO
SIM Para a coleta de Dados ?
Cancela coleta de dados Transmite para o PC comando de fim de coleta de dados
NÃO
A
Linguagem C para PIC
103
Recebe comando do PC
Chegou comando do PC ?
SIM
SIM
Recebeu o comando de inicio de Coleta de Dados ?
Tarefa = coleta de dados
NÃO
B SIM
Recebeu o comando de transmissão de dados para o PC ?
Tarefa = transmite dados para o PC
NÃO
B SIM
Recebeu o comando de parar coleta de dados ?
NÃO
Tarefa = para coleta de dados
B
104 Linguagem C para PIC
NÃO
Coleta Dados
Escreve no LCD: "Coletando Dados"
Lê Dados do AD Salva em EEPROM Serial
NÃO
Fim da Coleta de Dados ?
SIM
Aguarda novo comando do PC
Envia para o PC comando de Fim de Coleta de Dados
Escreve no LCD: "Pronto para TX"
Return
Linguagem C para PIC
105
Transmite dados para o PC
Escreve no LCD: "TX para o PC"
Lê memória EEPROM Serial Transmite para o PC
NÃO
Fim da transmissão de Dados ?
SIM Escreve no LCD: "Fim da Trans..."
Aguarda novo comando do PC delay de 5 segundos
Escreve no LCD: "Press Inicio" delay de 1 segundo
Return
106 Linguagem C para PIC
Linguagem C para PIC
107
Escreve na memória EEPROM Serial
Lê dados da memória EEPROM Serial
Envia Start bit
Envia Start bit
Envia Controle
Envia Controle
Envia endereço low
Envia endereço low
Envia Dado
Envia Start bit
Envia Stop bit
Envia Controle
delay 10ms
Recebe dados da memória salva em variável dado
Return
Envia Stop bit
delay 10ms
Return
108 Linguagem C para PIC
1.62 - Código /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Programação em C - Recursos Avançados de programação * * Exemplo 9 * * * * CENTRO DE CAPACITAÇÃO - LABTOOLS * * * * TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br * * E-MAIL:
[email protected] * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * VERSÃO : 1.0 * * DATA : 05/06/2003 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Descrição geral * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Este exemplo foi elaborado para explicar as funcões de I2C do compilador // CCS. Neste exemplo iremos coletar dados do AD e armazenar estes dados na // EEPROM externa (24c04), estes dados serão enviados ao PC para a // visualização dos mesmos. O PC controlará as funções do coletor de dados. #include
<16f877A.h>
// microcontrolador utilizado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações para gravação * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt fusíveis
// configuração dos
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição para uso de Rotinas de Delay * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use
delay(clock=4000000, RESTART_WDT)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configuração do Módulo I2C * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use i2c(master,sda=pin_c4, scl=pin_c3, SLOW, RESTART_WDT, FORCE_HW) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configuração da USART * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use rs232 (baud=9600, xmit = pin_c6, rcv = pin_c7) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Constantes internas * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de constantes facilita a programação e a manutenção. #define #define
ctrl_le ctrl_escr
0b10100001// byte de controle da memória p/ leitura 0b10100000// byte de controle da memória p/ escrita
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Constante internas do tipo Enumeração * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ enum selecao_de_tarefa { aguarda_comando, coleta_de_dados, transmite_para_pc, parar_coleta }tarefa;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Linguagem C para PIC
109
* Definição e inicialização das variáveis * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //Neste bloco estão definidas as variáveis globais do programa. static int flags1 = 0; // flags static int dado = 0; static int end_low = 0; static int tx_pc; static int comando = 0; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização dos port's * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use fast_io(a) #use fast_io(b) #use fast_io(c) #use fast_io(d) #use fast_io(e) #byte #byte #byte #byte #byte
porta=0x05 portb=0x06 portc=0x07 portd=0x08 porte=0x09
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Declaração dos flags de software * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de flags ajuda na programação e economiza memória RAM. #bit atualiza_lcd = flags1.0 /* * * * * * * * * * * * * * * * * * * * * // As entradas devem //futuras alterações
* * * * * * * * * * * * * * * * * * * * * * * * * * * * ENTRADAS * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ ser associadas a nomes para facilitar a programação e do hardware.
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * SAÍDAS * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ // As saídas devem ser associadas a nomes para facilitar a programação e //futuras alterações do hardware. #bit rs = porte.0 // via do lcd que sinaliza recepção de dados ou comando #bit enable = porte.1 // enable do lcd /* * * * * * * * * * * * * Função * * * * * * * * * * * * escr_mem_serial () { i2c_start(); i2c_write(ctrl_escr); i2c_write(end_low); i2c_write(dado); i2c_stop(); delay_ms(10); } /* * * * * * * * * * * * * Função * * * * * * * * * * * * le_mem_serial () { i2c_start(); i2c_write(ctrl_escr); i2c_write(end_low); i2c_start(); i2c_write(ctrl_le); dado = i2c_read(0); i2c_stop(); }
* * * * * * * * * * * * * * * * * * * * * * * * * * para escrita na EEPROM externa I2C * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Condição de início // Envia o byte de controle de leitura // Envia endereço baixo // Escreve dado na E²PROM // Condição de parada // espera a gravação estar completa * * * * * * * * * * * * * * * * * * * * * * * * * * para leitura na EEPROM externa I2C * * * * * * * * * * * * * * * * * * * * * * * * * * */ // Condição de início // Envia o byte de controle de leitura // Envia endereço baixo // Nova condição de início // Envia o byte de controle de leitura // lê o dado armazenado na E²PROM // Condição de parada
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
110 Linguagem C para PIC
* Função que envia um COMANDO para o LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void comando_lcd(int caracter) { rs = 0; portd = caracter; enable = 1 ; delay_us(1); enable = 0; delay_us(40);
// // // //
*
// seleciona o envio de um comando carrega o portd com o caracter gera pulso no enable espera 1 microsegundo desce o pino de enable
// espera mínimo 40 microsegundos
} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função que envia um DADO a ser escrito no LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void escreve_lcd(int caracter) { rs = 1; portd = caracter; enable = 1; delay_us(1); enable = 0; delay_us(40);
// // // //
*
// seleciona o envio de um caracter carrega o portd com o caracter gera pulso no enable espera 1 microsegundo desce o pino de enable
// espera mínimo 40 microsegundos
} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função para limpar o LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void limpa_lcd() { comando_lcd(0x01); delay_ms (2); }
// limpa lcd
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função de inicialização do Display de LCD * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void inicializa_lcd() { comando_lcd(0x30); delay_ms(4); comando_lcd(0x30); delay_us(100); comando_lcd(0x30); comando_lcd(0x38); limpa_lcd(); comando_lcd(0x0c); comando_lcd(0x06); }
// envia comando para inicializar display // espera 4 milisengundos // envia comando para inicializar display // espera 100 microsengundos // envia comando para inicializar display // liga o display, sem cursor e sem blink // limpa lcd // display sem cursor // desloca cursor para a direita
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Função para imprimir a Tela Principal * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void tela_principal() { limpa_lcd() comando_lcd(0x80); // posiciona o cursor na linha 0, coluna 0 printf (escreve_lcd, "Coletor de dados"); // imprime mensagem no lcd }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina para coleta de dados *
Linguagem C para PIC
111
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ coleta_dados() { comando_lcd(0xc0); // posiciona o cursor na linha 1, coluna 0 printf (escreve_lcd, "Coletando Dados"); // imprime mensagem no lcd do { dado = read_adc(); // le resuldado do AD escr_mem_serial (); // salva em eeprom end_low += 1; // incrementa endereço, seleciona nova posição delay_ms(10); // delay de 10 ms }while (end_low != 0); // fim da coleta ? tarefa = aguarda_comando; // aguarda comando do PC comando_lcd(0xc0); // posiciona o cursor na linha 1, coluna 0 printf (escreve_lcd, " Pronto para TX "); // imprime mensagem no lcd tx_pc = 11; // indica para o pc fim da coleta de dados printf ("%x\r\n",tx_pc);// envia ao PC o comando de fim da coleta de dados delay_ms(2000); // delay de 2 segundos } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina para transmitir dados para o PC * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ tx_dados_pc() { comando_lcd(0xc0); // posiciona o cursor na linha 1, coluna 0 printf (escreve_lcd, " TX para o PC "); // imprime mensagem no lcd do { le_mem_serial (); // le dados da eeprom printf ("%x\r\n",dado); // envia ao PC o valor da eeprom externa end_low +=1; // incrementa endereço, seleciona nova posição delay_ms(100); // delay de 100 ms }while (end_low != 0); // fim da transmissão de dados tarefa = aguarda_comando; // aguarda comando do PC comando_lcd(0xc0); // posiciona o cursor na linha 1, coluna 0 printf (escreve_lcd, " Fim da Trans..."); // imprime mensagem no lcd delay_ms(3000); // delay de 3 segundos comando_lcd(0xc0); // posiciona o cursor na linha 1, coluna 0 printf (escreve_lcd, " "); // imprime mensagem no lcd delay_ms(1000); // delay de 1 segundo } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Tratamento de recepção serial * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void recebe_comando() { if (kbhit()) { comando = getc(); if (comando == 0x55) // recebeu o camando de coleta de dados ? { tarefa = coleta_de_dados; // sim, libera coleta de dados } if (comando == 0xaa) // recebeu o camando de transmissão de dados ? { tarefa = transmite_para_pc; // sim, transmite dados para o PC } if (comando == 0x7f) // recebeu o camando para cancelar coleta de dados ? { tarefa = parar_coleta; // sim, cancela coleta de dados } } }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações do Pic *
112 Linguagem C para PIC
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void main() { setup_adc_ports (RA0_RA1_RA3_analog); setup_adc (adc_clock_div_8); set_adc_channel (1); setup_counters (rtcc_internal, WDT_2304MS); set_tris_a(0b11111111); set_tris_b(0b11111111); set_tris_c(0b10110111); set_tris_d(0b00000000); set_tris_e(0b00000100);
// configuração da direção dos pinos de I/O
porta=0x00; portb=0x00; portc=0x00; portd=0x00; porte=0x00;
// // // // //
inicializa_lcd(); tela_principal();
// configura o lcd // imprime a tela principal no LCD
limpa limpa limpa limpa limpa
porta portb portc portd porte
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina principal * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ loop: while(true) // rotina principal { RESTART_WDT(); // incia o watch-dog timer recebe_comando(); if (tarefa == coleta_de_dados) // inicia coleta de dados ? { end_low = 0; // sim, carrega endereço inicial coleta_dados(); // executa função de coleta de dados } if (tarefa == transmite_para_pc)// inicia transmissão de dados para o PC ? { end_low = 0; // sim, carrega endereço inicial tx_dados_pc(); // executa função de transmissão de dados } if (tarefa == parar_coleta) // cancela coleta de dados ? { end_low = 0; // sim, carrega endereço inicial tarefa = aguarda_comando; // espera envio de comando do PC tx_pc = 11; // fim da coleta de dados tx_dados_pc(); // envia comando para o PC } } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Fim do Programa * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
Linguagem C para PIC
113
1.63 - Exercícios Propostos Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e soluções, seguindo os exercícios propostos: 1. Mude a rotina de coleta de dados para que seja armazenado na EEPROM um valor de 0 à 5V e não um valor de 0 a 255. Implemente a regra de três necessária. 2. Altere a configuração do A/D para que ele retorne os 10 bits do resultado da conversão e salve este dado na EEPROM.
114 Linguagem C para PIC
1.64 - Anotações
Linguagem C para PIC
115
Recursos Avançados: Exemplo 10 Funções Matemáticas 1.65 - Recursos do Livro Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos no exemplo 1 e mais, funções matemáticas do compilador (cap.11.1 pág 175 do livro Programação em C).
1.66 - Lógica do exemplo A elaboração deste exemplo foi pensando na demonstração das funções matemáticas, nele veremos o microcontrolador realizando o calculo do seno de 0 a 2π, um software para PC foi elaborado para coletar os cálculos realizas e plotar os cálculos na tela do PC. Outras funções podem ser visualizadas, bastando para isso alterar a função matemática de nosso programa.
116 Linguagem C para PIC
1.67 - Esquema Elétrico
+5V
RESET
10K
+5V
MC1 1 2 3 4 5 6 7
+5V
RS EN
8 9 10 11 12 13 14 15
4MHz
16 17 18 23 24
MCLR RA0 RA1 RA2 RA3 RA4 RA5 RE0 RE1 RE2 VDD VSS OSC1 OSC2 RC0 RC1 RC2 RC3 RC4 RC5
VDD VSS RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 RD7 RD6 RD5 RD4 RD3 RD2 RD1 RD0 RC7 RC6
32 31 40 39 38 37 36 35 34 33 30 29 28 27 22 21 20 19 26 25
16F877A
+5V
1uF
1uF
1uF
3
2
5
1 3
C1+ C1 -
4 5
C2+ C2 -
13 14
T1IN T1OUT R1OUT R1IN 11
8 7
T2IN T2OUT R2OUT R2IN 10
15
GND
+C 2 -C 6
1K
12
9
VCC 16
+5V
1uF
MAX-232
CONECTOR DB9 FEMEA
Linguagem C para PIC
117
1.68 - Fluxograma MAIN
CO NFIG URAÇÕ ES INICIAIS TRIS, PO RTAS, W ATCHDO G , PRESCALER.
Inicializa a variável X=0
NÃO X < (2 * PI)
SIM
LIMPA W ATCHDO G
Y = seno (x)
Envia o valor de X para o PC
Envia o valor de Y para o PC
Incrementa a variável X X = x + 0,01
118 Linguagem C para PIC
1.69 - Código /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Programação em C - Recursos Avançados de programação * * Exemplo 10 * * * * CENTRO DE CAPACITAÇÃO - LABTOOLS * * * * TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br * * E-MAIL:
[email protected] * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * VERSÃO : 1.0 * * DATA : 05/06/2003 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* * * // // //
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Descrição geral * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ Este software foi desenvolvido para mostrar a implementação de funções matemáticas, como exemplo estamos calculando o seno e enviando para o PC os valores de "x" e "y" para serem plotados.
/* * * * * * * * * * * * * * * * * Definição * das funções * * * * * * * * * * * * * * * * #include <16f877A.h> #device adc=10
* * * * * * * * * * * * * * * * * * * * * dos I/O's e opções de configuração para periféricos * * * * * * * * * * * * * * * * * * * * * */
*
// microcontrolador utilizado
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Carrega bibliteca Matemática * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include
// microcontrolador utilizado /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações para gravação * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt // configuração dos fusíveis /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definições para uso de Rotinas de Delay * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use
delay(clock=4000000, RESTART_WDT)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configuração da Usart * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use
rs232(baud=9600,xmit=pin_c6,rcv=pin_c7)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização das variáveis * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //Neste bloco estão definidas as variáveis globais do programa. float y; float x; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Constantes internas * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de constantes facilita a programação e a manutenção. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Declaração dos flags de software * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ //A definição de flags ajuda na programação e economiza memória RAM. //Este programa não utiliza nenhum flag de usuário
Linguagem C para PIC
119
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Definição e inicialização dos port's * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #use #use #use #use #use
fast_io(a) fast_io(b) fast_io(c) fast_io(d) fast_io(e)
#byte #byte #byte #byte #byte
porta=0x05 portb=0x06 portc=0x07 portd=0x08 porte=0x09
/* * * * * * * * * * * * * * * * * * * * * // As entradas devem //futuras alterações
* * * * * * * * * * * * * * * * * * * * * * * * * * ENTRADAS * * * * * * * * * * * * * * * * * * * * * * * * * * ser associadas a nomes para facilitar a programação do hardware.
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * SAÍDAS * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // AS SAÍDAS DEVEM SER ASSOCIADAS A NOMES PARA FACILITAR A PROGRAMAÇÃO //FUTURAS ALTERAÇÕES DO HARDWARE.
* * */ e
* * */ E
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Configurações do Pic * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void main() { setup_adc_ports (no_analogs); // desliga as entradas analógicas setup_counters (rtcc_internal, wdt_2304ms);// tmr0 clock interno, ps: 1:64 set_tris_a(0b11111111); set_tris_b(0b11111111); set_tris_c(0b11111111); set_tris_d(0b11111111); set_tris_e(0b00000111);
// configuração da direção dos pinos de I/O
porta=0x00; portb=0x00; portc=0x00; portd=0x00; porte=0x00;
// // // // //
limpa limpa limpa limpa limpa
porta portb portc portd porte
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Rotina principal * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ while(TRUE) { x=0; while(x < 2*PI) { restart_wdt(); // limpa wdt y = sin (x); // calculo da função printf ("X=%1.3f",x); // envia ao PC o valor de x printf (" "); printf ("Y=%1.3f\r\n",y); // envia ao PC o valor de y x = x + 0.01; // incrementa x } } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Fim do Programa * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
120 Linguagem C para PIC
1.70 1.71 - Exercícios Propostos Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e soluções, seguindo os exercícios propostos: 1. Altere a função matemática para que o PIC calcule o co-seno. 2. Altere a função matemática para que o PIC calcule o log de um número.
Linguagem C para PIC
121
1.72 - Anotações
122 Linguagem C para PIC