DETUA Departamento de Electrónica e Telecomunicações Universidade de Aveiro
Microcontroladores PIC Guia de Trabalhos Práticos do Professor
José Miguel Oliveira Gaspar
Olímpia Rodrigues
Alunos de seminário da Licenciatura em Ensino de Electrónica e Informática Última Revisão 4 de Maio de 2006
Guia realizado sob a orientação do Prof. Doutor José Luís Azevedo <[email protected]> Prof. Auxiliar do Departamento de Electrónica e Telecomunicações da Universidade de Aveiro
Resumo
A elaboração deste guia insere-se no âmbito do seminário da Licenciatura em Ensino de Electrónica e Informática. A motivação do trabalho vêm ao encontro da lacuna documental existente sobre microcontroladores no âmbito da disciplina de Sistemas Digitais do ensino secundário, por forma minimizar a falta de recursos foram desenvolvidos dois guias de trabalhos práticos sobre microcontroladores, um para cada, aluno e professor. Para o efeito escolheu-se um microcontrolador da família 16F87X da Microchip, para a realização dos diversos trabalhos práticos
iii
Agradecimentos
O nosso agradecimento vai para todos aqueles que connosco colaboraram para que este guia fosse uma realidade. Em especial aos colegas da sala 317 que em muito contribuíram durante todo o seminário.
Conteúdo
Resumo
iii
Conteúdo
ix
Lista de Figuras
xii
Lista de Tabelas
xiii
Introdução 1
1
Enquadramento geral . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1.1
Trabalhos práticos a realizar . . . . . . . . . . . . . . . . . . . . . . . . . .
1
2
Algumas características do PIC16F876 . . . . . . . . . . . . . . . . . . . . . . . . .
3
3
Hardware - Placa PIC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
TP0 - Introdução ao Assembly e MPLAB IDE
5
1
Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
2
Objectivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
3
Descrição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
Ambiente de desenvolvimento MPLAB IDE . . . . . . . . . . . . . . . . .
5
Trabalho a Realizar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
4.1
Criação de um projecto no MPLAB IDE . . . . . . . . . . . . . . . . . . .
8
4.2
Tradução do código fonte em código máquina . . . . . . . . . . . . . . . . .
10
4.3
Programação do PIC16F876 através da linha série . . . . . . . . . . . . . .
11
4.4
Estrutura base de um programa em Assembly . . . . . . . . . . . . . . . . .
12
3.1 4
v
Guião Prático Sobre micro-controladores PIC 4.5
Análise do programa exemplo . . . . . . . . . . . . . . . . . . . . . . . . .
TP1 - Entrada/Saída
13 15
1
Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
2
Objectivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
3
Descrição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
3.1
Registos TRIS e PORT . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
3.2
Inicialização dos portos . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
4
Trabalho a realizar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
5
Implementação em Assembly do PIC . . . . . . . . . . . . . . . . . . . . . . . . . .
20
5.1
Ponto 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
5.2
Ponto 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
5.3
Ponto 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
TP2 - Descodificador Hexadecimal / 7Seg, 1 display
31
1
Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
2
Objectivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
3
Descrição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
3.1
Endereçamento Indirecto, Registo FSR e INDF . . . . . . . . . . . . . . . .
31
3.2
Selecção do Banco de Memória . . . . . . . . . . . . . . . . . . . . . . . .
33
4
Trabalho a realizar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
5
Implementação em Assembly do PIC . . . . . . . . . . . . . . . . . . . . . . . . . .
35
5.1
Ponto 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
5.2
Ponto 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
TP3 - Descodificador Hexadecimal / 7Seg, 3 Displays
43
1
Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
2
Objectivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
3
Descrição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
4
Trabalho a realizar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
vi
Índice de Conteúdos 4.1 5
Descrição do registo STATUS . . . . . . . . . . . . . . . . . . . . . . . . .
45
Implementação em Assembly do PIC . . . . . . . . . . . . . . . . . . . . . . . . . .
47
TP4 – Contador de 60 segundos, versão I
53
1
Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
2
Objectivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
3
Descrição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
3.1
Rotina Delay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
4
Trabalho a realizar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
5
Implementação em Assembly do PIC . . . . . . . . . . . . . . . . . . . . . . . . . .
59
5.1
Ponto 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
59
5.2
Ponto 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
5.3
Ponto 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
TP5 – Relógio de 60 segundos, versão II
79
1
Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
2
Objectivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
3
Descrição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
3.1
Timer 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
80
3.2
Registo OPTION_REG
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
3.3
Registo INTCON
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
4
Trabalho a realizar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
84
5
Implementação em Assembly do PIC . . . . . . . . . . . . . . . . . . . . . . . . . .
85
TP6 – Semáforo rodoviário(automóveis/peões)
91
1
Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
91
2
Objectivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
91
3
Descrição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
91
3.1
Diagrama de estados - Semáforo rodoviário . . . . . . . . . . . . . . . . . .
92
Trabalho a realizar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
93
4
vii
Guião Prático Sobre micro-controladores PIC 5
Implementação em Assembly do PIC . . . . . . . . . . . . . . . . . . . . . . . . . .
TP7 - Relógio 60 segundos, versão III
95 101
1
Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
2
Objectivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
3
Descrição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 3.1
Led pisca-pisca com botão ON/OFF por interrupção . . . . . . . . . . . . . 102
4
Trabalho a realizar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
5
Implementação em Assembly do PIC . . . . . . . . . . . . . . . . . . . . . . . . . . 106 5.1
Ponto 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
5.2
Ponto 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
5.3
Ponto 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
TP8 – USART Universal Synchronous Asynchronous Receiver Transmitter
127
1
Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
2
Objectivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
3
Descrição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 3.1
Configuração dos pinos de transmissão/recepção . . . . . . . . . . . . . . . 128
3.2
Taxa de transmissão da USART . . . . . . . . . . . . . . . . . . . . . . . . 128
3.3
Operação de transmissão . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
3.4
Operação de recepção . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
3.5
Registo TXSTA
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
3.6
Registo RCSTA
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
4
Trabalho a realizar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
5
Implementação em Assembly do PIC . . . . . . . . . . . . . . . . . . . . . . . . . . 134 5.1
Ponto 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
5.2
Ponto 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
5.3
Ponto 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
TP9 – ADC - Conversão Analógica / Digital
145
viii
Índice de Conteúdos 1
Resumo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
2
Objectivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
3
Descrição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 3.1
Entrada Analógica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
3.2
Resultado da conversão A/D . . . . . . . . . . . . . . . . . . . . . . . . . . 146
3.3
Mecanismo de aquisição da ADC . . . . . . . . . . . . . . . . . . . . . . . 147
3.4
Etapas na programação da ADC (polling) . . . . . . . . . . . . . . . . . . . 148
3.5
Registo ADCON0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
3.6
Registo ADCON1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
4
Trabalho a realizar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
5
Implementação em Assembly do PIC . . . . . . . . . . . . . . . . . . . . . . . . . . 153 5.1
Ponto 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
5.2
Ponto 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
5.3
Ponto 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
Apendix A
177
Apendix B
179
ix
Guião Prático Sobre micro-controladores PIC
x
Lista de Figuras 1
Disposição dos componentes na placa de CI DETUA . . . . . . . . . . . . . . . . .
4
2
Esquema da placa PIC DETUA . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
3
Janela associada ao processo de simulação de um programa no MPLAB IDE . . . . .
7
4
Projecto em MPLAB IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
5
Visualização de janelas de informação memória do PIC . . . . . . . . . . . . . . . .
8
6
fase 1 - criação de um novo projecto . . . . . . . . . . . . . . . . . . . . . . . . . .
8
7
fase 2 - selecção do microcontrolador. . . . . . . . . . . . . . . . . . . . . . . . . .
9
8
Adicionar um ficheiro fonte existente ou criar um novo. . . . . . . . . . . . . . . . .
9
9
Tradução do código fonte em código máquina. . . . . . . . . . . . . . . . . . . . . .
10
10
WinPIC Loader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
11
Configuração de uma linha em E/S . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
12
Diagrama do circuito, led on/off. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
13
Diagrama temporal da saída temporizada . . . . . . . . . . . . . . . . . . . . . . . .
18
14
Diagrama do circuito para o contador up/down . . . . . . . . . . . . . . . . . . . . .
19
15
Acesso memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
16
Endereçamento Indirecto código de demonstração . . . . . . . . . . . . . . . . . . .
32
17
Selecção do banco de memória . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
18
Diagrama do circuito, 1 display de 7 segmentos . . . . . . . . . . . . . . . . . . . .
34
19
Processo de refrescamento dos displays . . . . . . . . . . . . . . . . . . . . . . . .
44
20
Selecção dos bancos de memória RAM. . . . . . . . . . . . . . . . . . . . . . . . .
45
21
Diagrama de fluxo da rotina Delay . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
22
Diagrama do circuito para para visualização do valor ‘0x60’ . . . . . . . . . . . . .
56
xi
Guião Prático Sobre micro-controladores PIC 23
Diagrama do circuito, exemplifica a passagem de ‘60’ à ‘59’ . . . . . . . . . . . . .
57
24
Diagrama do circuito, exemplifica o término da contagem . . . . . . . . . . . . . . .
57
25
Diagrama do circuito com sw, antes de se pressionar no botão . . . . . . . . . . . . .
58
26
Diagrama do circuito com sw, após pressionar no botão . . . . . . . . . . . . . . . .
58
27
registo contador de 8 bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
28
Diagrama de blocos do timer 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
80
29
Semáforo rodoviário (automóveis/peões) . . . . . . . . . . . . . . . . . . . . . . . .
91
30
Diagrama de estados do trabalho prático . . . . . . . . . . . . . . . . . . . . . . . .
92
31
Diagrama do circuito, semáforo rodoviário . . . . . . . . . . . . . . . . . . . . . . .
93
32
Exemplo de uma interrupção . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
33
Diagrama do circuito, interrupção do RBO/INT . . . . . . . . . . . . . . . . . . . . 104
34
Atribuição do porto série . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
35
Operação de transmissão assíncrona . . . . . . . . . . . . . . . . . . . . . . . . . . 129
36
Operacão de recepcção assíncrona . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
37
Ligação série entre o PIC e o Computador . . . . . . . . . . . . . . . . . . . . . . . 133
38
ADC, entradas analógicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
39
Formato do resultado de 10 bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
40
Mecanismo de aquisição da ADC . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
41
Diagrama do circuito do voltímetro digital, visualização com displays 7 segmentos . 151
42
Diagrama do circuito do voltímetro digital, visualização terminal série . . . . . . . . 151
43
Mapa de memória RAM, registos do PIC e registos de uso geral . . . . . . . . . . . 177
xii
Lista de Tabelas 1
Descrição dos temas a abordar. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
2
HEX ß 7 segmentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
34
3
Descrição do estado dos leds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
92
4
Tempo minímo entre estados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
93
5
Taxa de transmissão em modo assíncrono (BRGH = 1) . . . . . . . . . . . . . . . . 128
xiii
Introdução
1
Enquadramento geral
Os trabalhos práticos apresentados neste guia foram organizados de modo a que o aluno adquira, numa perspectiva evolutiva, conceitos fundamentais associados à programação de microcontroladores. Cada um dos trabalhos dá ênfase ao desenvolvimento de uma temática específica, podendo cada um deles ser realizado independentemente um dos outros. Contudo, para um aluno sem experiência prévia que utilize a programação de microcontroladores é aconselhável que os trabalhos sejam realizados pela ordem em que são apresentados, resultando esta recomendação em dois aspectos fundamentais: a) os trabalhos estão organizados com um grau de dificuldade crescente, sendo importante que os conceitos aí abordados, sejam compreendidos, antes de se passar aos seguintes; b) o código realizado num dado trabalho possa ser reaproveitado em trabalhos posteriores.
1.1
Trabalhos práticos a realizar
Trabalho
Duração
Descrição
0
1 aula
Familiarização c/ a linguagem assembly e ambiente de desenvolvimento MPLAB
1
3 aulas
Entrada/Saída - Configuração dos portos do PIC
2
1 aula
Implementação de uma lookup table
3
2 aulas
Implementação de um sistema de visualização por multiplexagem no tempo
4
2 aulas
Contagem de tempo por contagem de instruções
5
1 aula
Contagem de tempo com recurso a timers
6
2 aulas
Implementação de uma máquina de estados
7
3 aulas
Programação com interrupções (Interrupt driven I/O)
8
2 aulas
Comunicação série assíncrona (USART)
9
4 aulas
Conversão Analógia à Digital (ADC)
Tabela 1: Descrição dos temas a abordar. A tabela 1 fornece uma curta descrição dos temas a abordar em cada trabalho prático. O primeiro trabalho prático TP0 tem como principal objectivo a familiarização com a linguagem assembly e o ambiente de desenvolvimento MPLAB IDE. Com este trabalho pretende-se que o aluno tome conhecimento das potencialidades que ambiente de desenvolvimento disponibiliza na realização dos trabalhos
1
Guia prático sobre microcontroladores PIC futuros; o trabalho seguinte TP1, continua com a familiarização do aluno com novos conceitos, desta vez a familiarização do aluno com a linguagem assembly do PIC para programação dos portos de entrada e saída na leitura e escrita de dados. No trabalho prático 2, TP2, pretende-se que o aluno adquira os conhecimentos necessários de modo a compreender o acesso a variáveis na memória RAM por endereçamento indirecto. Para tal, pretende-se implementar um descodificador hexadecimal / 7 segmentos através de um único display. No seguimento deste trabalho, surge o trabalho 3 (TP3), em que se pretende uma ampliação do trabalho anterior a 3 displays de 7 segmentos, com o objectivo de construir um programa que permita a visualização de dados nos displays, recorrendo ao refrescamento destes por multiplexagem no tempo. No trabalho prático seguinte (TP4), recorre-se a contagem de tempo por contagem de instruções, usando para tal uma rotina de contagem de tempo por contagem de instruções (rotina Delay). O trabalho prático 5 (TP5), tem como um objectivo principal a introdução à programação do timer 0 do PIC. Com este, vai-se poder alargar a gama de contagem de tempo, algo que com a utilização da rotina Delay não é possível. Com o trabalho 6 (TP6), pretende-se construir uma máquina de estados que implementa um semáforo rodoviário para peões e automóveis, com o objectivo de aprofundar os conhecimentos acerca do timer 0. Nos trabalhos práticos 4 e 5 implementou-se um relógio de 60seg recorrendo á rotina Delay e timer 0, respectivamente. Ambos implementados recorrendo à transferência de informação por polling. Durante o trabalho 7 (TP7) pretende-se implementar novamente um relógio, recorrendo agora à transferência de informação por interrupção. Para isso é necessária a compreensão do conceito de interrupção de um programa. Com o grau de dificuldade a crescer, os dois últimos trabalhos reflectem essa complexidade nos conceitos a adquirir. Assim, o trabalho 8 (TP8) tem como objectivo, a comunicação série entre um computador (anfitrião) e o PIC, elaborando para tal um programa que implemente um terminal série, recorrendo a rotinas para envio e recepção de caracter ou caracteres. Por fim, o trabalho 9 (TP9) tem como objectivo principal a introdução à conversão A/D, implementando para esse fim 2 trabalhos: um voltímetro digital básico, e um sistema de medição de distâncias recorrendo a um sensor infravermelhos.
2
Introdução
2
Algumas características do PIC16F876
O PIC16F876, fabricado com a tecnologia CMOS dispõe de:
• Processador RISC (Reduce Instrution Set Computer) í 35 instruções de 14 bits; í Frequência máxima de funcionamento - 20Mhz (frequência do cristal); í Cada ciclo de relógio corresponde à frequência do cristal / 4 = 5Mhz, efectuando a cada segundo 5 MIPS (milhões de instruções por segundo); í Tempo de execução das instruções normais: 1 ciclo de relógio; í Tempo de execução das instruções de salto condicional (decfsz, incfsz, btfss, btfsc), quando a executada a instrução de salto: 2 ciclos de relógio; í Tempo de execução de instruções de salto incondicional (goto): 2 ciclos de relógio. • As seguintes características da memória; í Memória de programa (FLASH) de 8K (words) de 14 bits; í Cada instrução é codificada numa word de 14 bits; í Memória de dados RAM de 368 bytes; í Memória de dados EEPROM de 256 bytes; í Stack de 8 níveis. • As seguintes características de periféricos: í 22 linhas de entrada/saída, agrupadas em 3 portos (PORTA à 6 linhas, PORTB e PORTC à 8 linhas); í 3 timers, 2 de 8 bits e 1 de 16 bits; í Conversor analógico à digital de 10 bits, com um máximo de 5 canais de entrada analógica; í USART (Universal Synchronous Asynchronous Receiver Transmitter); í 13 tipos de interrupções, por exemplo externa RB0/INT, TMR0 timer overflow.
3
Hardware - Placa PIC
Não é propósito do guião descrever o funcionamento da placa PIC, este é feito no site da disciplina. Neste pode-se encontrar todas as informações relevantes sobre o layout e funcionamento da placa. Contudo para que o aluno/professor se se enquadrem com o hardware apresenta-se nas páginas seguintes o esquema eléctrico do circuito bem como a disposição dos componentes na placa de circuito impresso.
3
Guia prático sobre microcontroladores PIC
Figura 1: Disposição dos componentes na placa de CI DETUA
Figura 2: Esquema da placa PIC DETUA
4
TP0 - Introdução ao Assembly e MPLAB IDE
1
Tema a desenvolver
Duração
Familiarização com o Assemly e MPLAB IDE
1 aula
Resumo
Pretende-se mostrar com este trabalho os passos necessários à criação de um projecto no ambiente de desenvolvimento MPLAB IDE (programa de software destinado a desenvolver aplicações para microcontroladores da Microchip) e à tradução para código máquina do código fonte associado, recorrendo a um pequeno exemplo em linguagem Assembly. Mostra-se ainda, o processo de programação do PIC16F876 através da linha série.
2
Objectivos • Criação de um projecto no ambiente de desenvolvimento MPLAB IDE. • Conhecer o processo de tradução de código fonte para código máquina. • Conhecer o processo de programação do microcontrolador através do WinPIC Loader. • Introdução à programação em linguagem Assembly.
3 3.1
Descrição Ambiente de desenvolvimento MPLAB IDE
O MPLAB IDE é um ambiente de desenvolvimento integrado que permite a edição, o debugging e a tradução para código máquina de programas em linguagem Assembly. Disponibiliza essencialmente, as seguintes ferramentas: • Editor com reconhecimento das instruções do PIC e directivas do Assembler em syntax highlight. • Visualização dos registos (memória RAM), da memória de programa e da EEPROM . • MPLAB SIM, simulador de eventos, com as seguintes características: í Possibilidade de alteração do código fonte do programa, permitindo a sua re-execução imediata;
5
Guia prático sobre microcontroladores PIC í Possibilidade de modificação dos valores dos registos e posições de memória do PIC em intervalos de tempo pré determinados. í Possibilidade de modificação do valor lógico presente nas entradas do PIC. í Simulação da evolução do programa através da criação de um cenário de estímulos externos. No desenvolvimento inicial de um programa, é muito provável que este contenha erros de concepção que o impedem de realizar correctamente as tarefas para o qual foi projectado. Se porventura isso acontecer, é necessário voltar a analisar o código, de modo a encontrar a origem dos problemas. Em programas com alguma complexidade este processo é lento, e muitas vezes ineficiente, dado que é necessário carregar várias vezes o programa no PIC, de modo a testar o seu funcionamento. Este é um dos casos em que o simulador de software MPLAB SIM é útil uma vez que permite simular o programa no PC, como se este estivesse a ser executado no PIC. Outra das vantagens da utilização do simulador é a possibilidade da criação a priori de cenários de teste que servem de entrada para o simulador. A figura 3 mostra a janela associada ao processo de simulação do programa exemplo. O ambiente de edição do projecto do programa exemplo é mostrado na figura 4. A janela localizada no canto superior esquerdo representa o Project Manager, que contém as referências aos ficheiros que compõem o projecto; logo abaixo desta, temos o Memory Usage Gauge, que mostra a informação da quantidade de memória do programa e dados usada; no lado direito temos o editor; finalmente abaixo encontra-se a janela de output (saída), que fornece informações sobre o estado do programa aquando da tradução de código Assembly para código máquina. No MPLAB IDE, a visualização da memória (ver figura 5) é feita através das seguintes janelas: • Program Memory mostra os endereços de memória o Opcode e a mnemónica correspondente do programa, alocados dentro da gama de memória disponível para o processador seleccionado. Se o PIC seleccionado suportar memória externa, e se esta estiver activa, a mesma também será visualizada. • File Register mostra todos os registos do dispositivo seleccionado (corresponde á memória RAM do PIC). • EEPROM mostra a memória de dados EEPROM para qualquer microcontrolador que disponha deste tipo de memória (por exemplo o PIC16F876).
6
TP0 - Introdução ao Assembly e MPLAB IDE
Figura 3: Janela associada ao processo de simulação de um programa no MPLAB IDE
Figura 4: Projecto em MPLAB IDE
7
Guia prático sobre microcontroladores PIC
Figura 5: Visualização de janelas de informação memória do PIC
4
Trabalho a Realizar
4.1
Criação de um projecto no MPLAB IDE
1. Uma vez aberto o programa MPLAB IDE, na área de trabalho, selecciona-se no menu principal ‘Project → New’. 2. Quando a dialog box ‘New Project’ surgir introduz-se no campo ‘Project Name’ exemplo, e no campo ‘Project Directory’ c:\aulas\exemplo (ver figura 6).
Figura 6: fase 1 - criação de um novo projecto .
8
TP0 - Introdução ao Assembly e MPLAB IDE 3. Escolha do microcontrolador associado ao projecto: ir ao menu ‘Configure → Select Device ...’ seleccionar o PIC16F876 e clicar OK (ver figura 7).
Figura 7: fase 2 - selecção do microcontrolador. 4. Ao projecto que acabou de se criar, associa-se agora o ficheiro com o código fonte do programa; se este não existir cria-se um novo (para criar um novo clicar em ‘File → New’). Antes de iniciar o processo de edição, deve-se guardar o ficheiro com a extensão ".asm", de modo a activar a funcionalidade syntax highlight (menu ‘File → Save As...’ guardando o ficheiro no directório c:\aulas\exemplo criado anteriormente). Neste exemplo o código fonte já se encontra num ficheiro no directório do projecto. Este ficheiro pode ser adicionado ao projecto clicando com o botão direito do rato em cima de ‘Source Files → Add Files...’ (ver figura 8(b)).
(a) Novo ficheiro.
(b) Adicionar ficheiro.
Figura 8: Adicionar um ficheiro fonte existente ou criar um novo.
9
Guia prático sobre microcontroladores PIC 5. Dado que o projecto usa oMPlink, é necessário associar-se um linker script; este ficheiro define os comandos do linker para cada PIC, especificando o seguinte:
• Regiões de memória de dados e programa do PIC. • Mapeamento de secções lógicas no código fonte, em regiões de programa e dados. Estão disponíveis ficheiros originais de script para todos os PIC, localizados por defeito no seguinte directório: c:\Program Files\Microchip\MPASM Suite\LKR. Para adicionar o ficheiro pretendido, clicar com o botão direito do rato em cima de ‘Script Files → Add Files...’.
4.2
Tradução do código fonte em código máquina
1. Após a edição do código fonte em Assembly do programa passa-se à fase de tradução do código fonte em código máquina. Para isso clica-se no ícone ‘Build All’
disponível na toolbar do
ambiente de desenvolvimento. No caso de o programa não apresentar erros de syntax, o gráfico de saída que mostra a evolução da compilação ficará completo a 100% e de cor verde; caso contrário ficará vermelho, o que indica a existência de um ou mais erros. Na ausência de erros de syntax, é criado o ficheiro de saída que tem como nome principal o nome do projecto com extensão ".hex".
(a) Evolução do assembling.
(b) Ocorreu um erro.
Figura 9: Tradução do código fonte em código máquina.
10
TP0 - Introdução ao Assembly e MPLAB IDE 4.3
Programação do PIC16F876 através da linha série
Após a tradução bem sucedida do código fonte em código máquina, passa-se à fase de programação do PIC. Para tal, é necessário que, previamente, tenha sido instalado no PIC um pequeno programa (o boot-loader) que gere a comunicação com o computador de desenvolvimento e que escreve o programa na memória Flash. O que é o boot-loader? O boot-loader é um programa que permite re-programar o PIC sem ter de o retirar do circuito onde está montado e sem ter que recorrer a um programador ( i.e., a um aparelho para programar os PICs ). Como funciona? O boot-loader funciona em conjunto com um programa que corre no PC, designado por WinPIC Loader ( disponível para DOS / Windows / Linux ) que controla o envio de um ficheiro em formato Intel Hex para o PIC. Sempre que o PIC é ligado, inicia-se a execução do boot-loader. Este começa por inquirir o PC sobre o que fazer. Se não obtém resposta dentro de um tempo limite e se existir um programa válido na memória do PIC, então o boot-loader inicia a execução desse programa. No caso em que obtém uma resposta válida, inicia o processo de transferência e armazenamento de um novo programa. Como re-programar? 1. Compilar o programa que se pretende transferir para o PIC usando o MPLAB. O compilador produz um ficheiro em formato Intel Hex ( extensão ".hex"). 2. Executar o programa WinPIC Loader, clicar em ‘File → Open’ seleccionar o ficheiro ".hex" respectivo, clicar OK. 3. Premir o botão de reset da placa PIC. A transferência e programação iniciam-se de imediato. A progressão é assinalada na janela WinPIC Loader no campo, Progress:. 4. Finalmente, para executar o programa, premir novamente o botão de reset da placa PIC.
Figura 10: WinPIC Loader
11
Guia prático sobre microcontroladores PIC 4.4
Estrutura base de um programa em Assembly list
p=16f876
radix
decimal
; - directiva "list", define ; o processador a usar ; - directiva "radix" especifica ; a definição das variáveis ; - directiva "include" inclui ; ficheiro adicional
#include "p16f876.inc"
;------------ Definição de constantes -------------------------------
;------------ Definição de variáveis --------------------------------
;------------ Definição de macros -----------------------------------
;==================================================================== ; ORG 0x0000 ; - directiva "ORG" origem do ; programa "ORG 0x0000" vector ; de reset clrf PCLATH ; - instrução "clrf PCLATH" apaga ; todos os bits do registo garante ; que a memória do programa ; é iniciada na página 0 goto main ; - instrução "goto main" salta para ; o endereço de memória do programa ; principal ; ;------------ Rotina Main ------------------------------------------; ORG 0x0005 ; - "0x0005" 1º endereço livre da ; memória de programa ; main ; - label programa principal ; goto main ; Código assembly do ; programa principal ; ;************ ROTINAS *********************************************** ; ; ; ; ;******************************************************************** END ; - directiva "END" fim do programa
12
TP0 - Introdução ao Assembly e MPLAB IDE 4.5
Análise do programa exemplo
O objectivo do programa é manter o led (ligado ao bit 0 do PORTB, RB0), acesso durante um tempo t1 e apagado durante um tempo t2. Para efectuar a contagem de tempo utiliza-se a rotina Delay (ver código Assembly página, 14). Esta rotina permite a parametrização na gama [1..255] a que corresponde uma contagem de tempo na gama [0,1s..2,5s]. O registo W é utilizado para a passagem do parâmetro da entrada para a rotina. O trecho de código abaixo indicado, representa o código da rotina main do programa. Inicialmente é feita a configuração do PORTB do PIC como saída, para que seja possível a activação/desactivação do led (RB0). De seguida o programa entra num ciclo infinito forçando a saída RB0 ao estado ON durante 0,5s e ao estado OFF durante 1s. A primeira instrução (bsf PORTB,RB0) coloca na saída (RB0) o nível lógico ‘1’ (5 volts). A seguinte instrução (movlw 50) coloca no registo W o valor do parâmetro de entrada da rotina Delay, invocada de seguida, o que vai fazer com que o led esteja acesso durante 0,5s. A instrução (bcf PORTB,RB0) coloca na saída (RB0) o nível lógico ‘0’ (0 volts). A rotina Delay é novamente invocada tendo agora como valor de entrada 100, o que vai fazer com que o led esteja apagado durante um tempo t2. Este ciclo repete-se sempre.
main
Bank1 movlw movwf Bank0
b’11111110’ TRISB
bsf
PORTB,RB0
movlw call
50 Delay
bcf
PORTB,RB0
movlw call
100 Delay
goto
loop
loop
13
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Memória RAM -> Bank 1 RB[0] output RB[7:1] inputs Memória RAM -> Bank 0 while(1) { Set LED in RB0 ON 50 -> W(reg) delay( 0,5 seg ) Set LED in RB0 OFF 100 -> W(reg) delay( 0,10 seg ) }
Guia prático sobre microcontroladores PIC ;===================================================================; ; Delay ; ; Pode gerar delays entre 10 mS e 2,5 S ; ; O valor de entrada e’ passado em W (1..255) ; ; ; ; Notas: o loop base e’ de 1 uS (T=200 nS <=> 4*1/20MHz) ; ; ; ;===================================================================; Delay movwf delay_mult ; Carrega o valor múltiplo Del_m10 movlw 50 ; de 10 mS movwf delay_k50 ; 50 => 10 mS Del_50 movlw 200 ; 200 => 200 uS movwf delay_k200 ; Carrega o valor Del_200 nop ; correspondente a 200 uS nop decfsz delay_k200,f ; Decrementa "delay_k200". ; O resultado é colocadao em ; "delay_k200" goto Del_200 ; while( delay_k200 > 0 ) decfsz delay_k50,f ; goto Del_50 ; while( delay_k50 > 0 ) decfsz delay_mult,f ; Decrementa "delay_mult". ; O resultado é colocadao ; em "delay_mult" goto Del_m10 ; while( delay_mult > 0 ) return
•
Elementos de Apoio í Manual teórico da disciplina. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 3. - I/O Ports, página 29. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 13 - Instrution Set Summary, página 135.
14
TP1 - Entrada/Saída
1
Tema a desenvolver
Duração
Entrada e Saída básica
2 aulas
Resumo
Programação e interface dos portos do PIC, através da implementação de programas em linguagem Assembly para leitura e escrita de dados nas linhas de entrada/saída (E/S) que compõem os portos.
2
Objectivos • Familiarização do aluno com a linguagem assembly do PIC; • Programação dos registos associados aos portos de E/S; • Leitura e escrita de dados nos portos; • No final do trabalho, deverá estar compreendido o mecanismo básico de E/S do PIC.
3
Descrição
O PIC16F876 dispõe de um total de 22 linhas de E/S de 1 bit. Estas estão organizados em 3 portos, denominados de porto A, porto B e porto C. Cada porto tem associado um par de registos: TRIS e PORT (ver descrição mais à frente). O porto A agrupa 5 linhas de 1 bit configuráveis, como entrada ou como saída, identificadas pelas siglas RA0, RA1, RA2, RA3 e RA4. Cada um dos portos B e C agrupa 8 linhas configuráveis como entrada ou como saída identificadas pelas siglas Rx0, Rx1, Rx2, Rx3, Rx4, Rx5, Rx6 e Rx7, em que ‘x’ pode tomar o valor B ou C. Algumas destas 22 linhas têm atribuídas diversas funções (que não a de simples linha de entrada/saída), podendo o programador configurar por software a função efectivamente desempenhada. De entre as funções disponíveis destacam-se as seguintes: • Entrada analógica, disponível, por exemplo na linha RA0/AN0 (2); • Interrupção externa, disponível em RB0/INT (21); • Entrada de clock externo do Timer 0, disponível em RA4/T0CKL (6);
15
Guia prático sobre microcontroladores PIC • Transmissão de dados em comunicação série, RC6/TX (16); • Recepção de dados em comunicação série, RC7/RX (18);
3.1
Registos TRIS e PORT
O registo PORT é um registo de dados, é aqui que a informação presente nas linhas de entrada ou saída é recolhida ou disponibilizada. Cada porto tem associado um registo de dados próprio, PORTA, PORTB e PORTC. O registo TRIS é um registo programável de 1 byte (8 bits) disponível no banco 1 (memória RAM), que controla se uma linha em particular é uma entrada ou uma saída. Existe um registo TRIS para cada porto. O TRISA controla o estado de E/S das 6 linhas do porto A, enquanto que TRISB e TRISC controlam respectivamente o estado de E/S das 8 linhas do porto B e porto C. Uma vez configurada as direcções pretendidas das linhas do porto, por programação do registo TRIS, pode-se efectuar leituras ou escritas no porto usando o registo PORT.
Utilização dos registos TRIS e PORT Todos os bits contidos nos registos mencionados, correspondem univocamente a uma linha de entrada/saída de um bit. Por exemplo, o bit 0 do registo PORTA e do registo TRISA, correspondem à linha RA0, o bit 1 à linha RA1 e assim por diante. Um ‘1’ no bit 0 do registo TRIS configura a linha como entrada enquanto um ‘0’ configura a linha como saída. Uma maneira intuitiva de relembrar o conceito, advém do facto de o ‘1’ ser parecido com o ‘I’ que provém da inicial da palavra inglesa Input e o ‘0’ ser parecido com ‘O’ que provém de Output. A figura 11 mostra um esquema conceptual da configuração através do registo TRISB, de um porto. A linha RB0 está configurada como entrada ou como saída? Qual será o nível lógico presente no bit 0 do registo PORTB? Observa-se na figura que o bit 0 do registo TRISB está definido a ‘1’, logo a linha RB0 está configurada como entrada. Quanto ao valor do bit 0 no registo PORTB, temos de considerar dois momentos, uma vez que a entrada varia no tempo: ao primeiro momento corresponde o nível lógico 0 e ao segundo o nível lógico ‘1’.
Figura 11: Configuração de uma linha em E/S
16
TP1 - Entrada e saída básica 3.2
Inicialização dos portos
Quando é necessário usar uma ou mais linhas de E/S de um determinado porto, importante fazer-se a sua inicialização logo no inicio da rotina main do programa. A inicialização não é mais que a configuração da direcção dos dados presentes nas linhas de E/S, por configuração do registo TRIS. É importante realçar que, se porventura a inicialização das linhas de E/S não for feita, estas por defeito (aquando do reset do PIC) encontram-se todas como entrada. Assim se uma das funcionalidades do programa a desenvolver for a recepção de informação digital em todas as linhas de um determinado porto (à excepção do porto A), este não necessita de ser inicializado. RA4 é a única linha do porto A que pode ser configurada como entrada digital pelo registo TRISA, para as restantes é necessário também a configuração do registo ADCON1 (descrição feita no trabalho prático 9). O trecho de código Assembly seguinte, exemplifica uma inicialização por programação de todos os portos do PIC. Este mostra, para cada porto, 3 formas de configuração do registo TRIS: 1. Transferência para o registo W do literal em binário, e consequente escrita em TRIS; 2. Colocação de todos os bits do registo TRIS a zero; 3. Read modify write, coloca apenas o bit correspondente a zero. ;---------------- I/O - Config -------------------------------------; Bank1 config 1
movlw movwf
b’00010000’ TRISA
config 2
clrf
TRISB
config 3
bcf
TRISC,RC0
Bank0 clrf clrf clrf
PORTA PORTB PORTC
17
; ; ; ; ; ; ; ; ; ; ; ; ; ;
DATA memory (RAM) Bank1 RA[7:5 & 3:0] RA[4]
saídas entradas
RB[7:0] RC[7:1] RC[0] DATA memory Apaga todos Apaga todos Apaga todos
entradas saída (RAM) Bank0 os bits do PORTA os bits do PORTB os bits do PORTC
Guia prático sobre microcontroladores PIC
4
Trabalho a realizar 1. Alteração do programa exemplo exemplo.asm de modo a que, através do botão de pressão S2 da placa PIC ligado a RA4 (ver esquema da figura 12), seja possível controlar o estado do led ligado ao pino RB0; botão premido → led ligado, botão não premido → led desligado.
Figura 12: Diagrama do circuito, led on/off. 2. Mantendo o circuito, alterar o programa anterior por forma a permitir o controlo temporizado do led ligado a RB0. Inicialmente o led é activado por pressão no botão ligado a RA4. Após se ter deixado de premir o botão, manter durante um tempo t o led acesso. A figura 13, mostra o comportamento pretendido para a saída, com t=2,5s.
Figura 13: Diagrama temporal da saída temporizada
18
TP1 - Entrada e saída básica 3. Construção de um programa, que implemente um contador binário up/down. O incremento ou decremento deve ser feito com um intervalo de tempo fixo (aproximadamente de 0,5 segundos), através de 4 leds, ligados aos portos RB3 a RB0 da placa PIC (ver esquema da figura 14). Inicialmente é feito o incremento de valores em binário no PORTB, contudo, se premir continuamente o botão de pressão ligado a RA4, dever-se-à, visualizar o seu decremento. A figura 14 mostra também a visualização do valor ‘5’ correspondente ao valor binário 0101, sendo que o bit mais significativo corresponde ao led3 ligado a RB3.
Figura 14: Diagrama do circuito para o contador up/down
•
Elementos de Apoio í Manual teórico da disciplina. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 3. - I/O Ports, página 29. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 11. - Analog-to-Digital Converter (A/D) Module, página 111. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 13 - Instrution Set Summary, página 135.
19
Guia prático sobre microcontroladores PIC
5 5.1
Implementação em Assembly do PIC Ponto 1
; Trabalho Prático nº 1 Ponto I ; Alteração do programa "exemplo.asm" inclusão de botão on/off ; ; Resumo: ; Led pisca-pisca (DUTTY CYCLE variável), com switch on/off. ; ; 5 V ; | ; / ; \ ; / RES 10K ; ___________ \ SW ; | | | __|__ ; | PIC16F876 |-<-- RA4 ---------*---------o o----- 0V ; | | ; | | /-----\ RES 220 ; | |->-- RB0 ------| LED |------\/\/\/---- 0V ; | | \-----/ ; |___________| ; ; figura 1. esquema de ligação PIC. ; ;******************************************************************** ; * ; Nome ficheiro: trab1p1.asm * ; Última actualização 22/Julho /2005 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2005 * ; * ;******************************************************************** ; * ; Ficheiro necessário: 16f876.lkr * ; * ;******************************************************************** list p=16f876 ; - directiva ’list’, define ; o processor a usar radix decimal ; - directiva ’radix’ especifica ; definição das variáveis #include "p16f876.inc" ; - directiva ’include’ inclui ; ficheiro adicional errorlevel -302 ; Turn off banking message ; known tested (good) code ;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RA0 EQU 0 RA1 EQU 1 RA2 EQU 2 RA3 EQU 3 RA4 EQU 4 RA5 EQU 5 RB0 EQU 0 RB1 EQU 1 RB2 EQU 2 RB3 EQU 3 RB4 EQU 4 RB5 EQU 5
20
TP1 - Entrada e saída básica RB6 RB7 RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU
6 7 0 1 2 3 4 5 6 7
;---------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) Bank0 ;---------------------------------------------------------------------UDATA 0x20 delay_mult RES 1 ; Variaveis de controlo delay_k50 RES 1 ; dos loops da rotina Delay delay_k200 RES 1 ; start_stop RES 1 ; start_stop FLAG ;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0 MACRO ; Macro to select data RAM Bank 0 bcf STATUS,RP0 bcf STATUS,RP1 ENDM Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG 0x0000 ; - directiva "ORG" origem do ; programa "ORG 0x0000" vector ; de reset clrf PCLATH ; - instrução "clrf PCLATH" apaga ; todos os bits do registo garante ; que a memória do programa ; é iniciada na página 0 goto main ; - instrução "goto main" salta para ; o endereço de memória do programa ; principal ;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG 0x0005 ; Program Memory PAGE 0 main ; Programa principal. Bank1 ; DATA memory (RAM) Bank1 movlw movwf movlw movwf
b’11111110’ TRISB b’00010000’ TRISA
; ; ; ;
RB[0] output RB[7:1] inputs RA[7:5 & 3:0] outputs RA[4] input
Bank0 clrf clrf
PORTB PORTA
; ; ; ;
DATA memory (RAM) Bank0 Inicialização PORTB Inicialização PORTA while(1) {
loop
21
Guia prático sobre microcontroladores PIC btfsc goto
PORTA,RA4 $-1
bcf
PORTB,RB0
movlw call
20 Delay
bsf movlw call
PORTB,RB0 20 Delay
goto
loop
; ; ; ; ; ; ; ; ; ; ; ; ;
switch ON ? Set LED in RB0 ON delay( 0,20 seg ) Set RB0 OFF delay( 0,20 seg ) }
;******************************************************************** ;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; Delay ; ; Pode gerar delays entre 10 mS e 2,5 S ; ; O valor de entrada e’ passado em W (1..255) ; ; ; ; Notas: o loop base e’ de 1 uS (T=200 nS <=> 4*1/20MHz) ; ; ; ;===================================================================; Delay movwf delay_mult ; Carrega o valor multiplo Del_m10 movlw 50 ; de 10 mS movwf delay_k50 ; 50 => 10 mS Del_50 movlw 200 ; 200 => 200 uS movwf delay_k200 ; Carrega o valor Del_200 nop ; correspondente a 200 uS nop decfsz delay_k200,f ; Decrementa "delay_k200". ; O resultado é colocadao em ; "delay_k200" goto Del_200 ; while( delay_k200 > 0 ) decfsz delay_k50,f ; goto Del_50 ; while( delay_k50 > 0 ) decfsz delay_mult,f ; Decrementa "delay_mult". ; O resultado é colocadao ; em "delay_mult" goto Del_m10 ; while( delay_mult > 0 ) return ;******************************************************************** END
; directive ’end of program’
22
TP1 - Entrada e saída básica 5.2
Ponto 2
; Trabalho Prático nº 1 Ponto II ; Saída temporizada, com visualização através de um led ; ; Resumo: ; Implementação de um programa em ’assembly’ que permita o activação ; temporizada de um led, após a pressão de um ’switch’, (ver figura 2). ; ; 5 V ; | ; / ; \ ; / RES 10K ; ___________ \ SW ; | | | __|__ ; | PIC16F876 |-<-- RA4 ----------*---------o o----- 0V ; | | ; | | /-----\ RES 220 ; | |->-- RB1 ------| LED |------\/\/\/---- 0V ; |___________| \-----/ ; ; ; figura 1. esquema de ligação PIC. ; ; ON | OFF ; ________________ ; | | ; switch _______| |_____________________________ ; ; ON | OFF ; ______________________________________ ; | | ; led _______| | |________ ; | | ; |<---- TEMPO_ON ----->| ; ; figura 2. diagrama temporal saída/entrada ; ;******************************************************************** ; * ; NomeFicheiro: trab1p2.asm * ; Última actualização: 22/Julho/2005 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2004 * ; * ;******************************************************************** ; * ; Ficheiro necessário: 16f876.lkr * ; * ;******************************************************************** list p=16f876 ; - directiva ’list’, define ; o processor a usar radix decimal ; - directiva ’radix’ especifica ; definição das variáveis #include "p16f876.inc" ; - directiva ’include’ inclui ; ficheiro adicional errorlevel -302 ; Turn off banking message ; known tested (good) cod ;-------------------------------------------------------------------; Constantes
23
Guia prático sobre microcontroladores PIC ;-------------------------------------------------------------------RA0 EQU 0 RA1 EQU 1 RA2 EQU 2 RA3 EQU 3 RA4 EQU 4 RA5 EQU 5 RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
TEMPO_ON
EQU
255
; Gama [1..255] = [10ms..2,5s]
;---------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) Bank0 ;---------------------------------------------------------------------delay_mult delay_k50 delay_k200
UDATA RES RES RES
0x20 1 1 1
; Variaveis de controlo ; dos loops da rotina Delay ;
;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** vector_reset ORG 0x00 ; Processor reset vector clrf PCLATH ; Ensure page bits are cleared goto main ; Go to beginning of program ;-------------------------------------------------------------------; Rotina Main ;--------------------------------------------------------------------
24
TP1 - Entrada e saída básica ORG
0x20
call
InitCfg
btfsc goto
PORTB,RB0 $-1
bsf
PORTB,RB1
btfss goto
PORTB,RB0 $-1
movlw call bcf
TEMPO_ON Delay PORTB, RB1
goto
loop
main loop
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Program Memory PAGE 0 Programa principal. While(1){ Testa se o SW em RB0 é pressionado ? Set LED em RB1 ON Testa se SW em RA0 deixa de ser pressionado ? delay( 2,5 seg ) Set LED em RB1 OFF }
;******************************************************************** ;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O ; ; ; ; Retorna em Bank0 ; ; ; ;===================================================================; InitCfg ;----------------- I/O - InitCfg -----------------------------------; Bank1 ; DATA memory (RAM) Bank0 movlw b’11111101’ ; RB[1] output movwf TRISB ; RB[7:2 & 0] inputs Bank0 clrf
; DATA memory (RAM) Bank0 ; Inicialização PORTB.
PORTB
return ;===================================================================; ; Delay ; ; Pode gerar delays entre 10 mS e 2,5 S ; ; O valor de entrada e’ passado em W (1..255) ; ; Retorna em Bank0 ; ; ; ; Notas: o loop base e’ de 1 uS (T=200 nS <=> 4*1/20MHz) ; ; ; ;===================================================================; Delay movwf delay_mult ; Carrega o valor multiplo Del_m10 movlw 50 ; de 10 mS movwf delay_k50 ; 50 => 10 mS Del_50 movlw 200 ; 200 => 200 uS movwf delay_k200 ; Carrega o valor Del_200 nop ; correspondente a 200 uS nop decfsz delay_k200,f ; Decrementa "delay_k200". ; O resultado é colocadao em ; "delay_k200" goto Del_200 ; while( delay_k200 > 0 ) decfsz delay_k50,f ; goto Del_50 ; while( delay_k50 > 0 ) decfsz delay_mult,f ; Decrementa "delay_mult". ; O resultado é colocadao ; em "delay_mult" goto Del_m10 ; while( delay_mult > 0 )
25
Guia prático sobre microcontroladores PIC
return ;******************************************************************** END ; directive ’end of program’
26
TP1 - Entrada e saída básica 5.3
Ponto 3
; Trabalho Prático nº 1 - Ponto III ; Implementação de um contador binário up/down ; ; Resumo: ; Inicialmente conta up ao presionar RC2, inverte o sentido ; da contagem, se deixar de precionar RC2 volta à situação ; inicial de conta up ; ; 5 V ; | ; / ; \ ; / RES ; ___________ \ SW ; | | | __|__ ; | PIC16F876 |-<-- RC2 ---------*---------o o----- 0V ; | | ; | | /----\ RES ; | |->-- RB0 -----| LED1 |------\/\/\/---- 0V ; | | \----/ ; | | /----\ RES ; | |->-- RB1 -----| LED2 |------\/\/\/---- 0V ; | | \----/ ; | | /----\ RES ; | |->-- RB2 -----| LED3 |------\/\/\/---- 0V ; | | \----/ ; | | /----\ RES ; | |->-- RB3 -----| LED4 |------\/\/\/---- 0V ; |___________| \----/ ; ; figura 1. esquema de ligação PIC. ; ;******************************************************************** ; * ; NomeFicheiro: trab1p3.asm * ; Data: 3/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2004 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.INC * ; * ;******************************************************************** list p=16f876 ; - directiva ’list’, define ; o processor a usar radix decimal ; - directiva ’radix’ especifica ; definição das variáveis #include "p16f876.inc" ; - directiva ’include’ inclui ; ficheiro adicional errorlevel -302 ; Turn off banking message ; known tested (good) coe ;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RA0 EQU 0 RA1 EQU 1
27
Guia prático sobre microcontroladores PIC RA2 RA3 RA4 RA5 RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7 RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU
2 3 4 5 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
;---------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) Bank0 ;---------------------------------------------------------------------UDATA 0x20 delay_mult RES 1 ; Variaveis de controlo delay_k50 RES 1 ; dos loops da rotina Delay delay_k200 RES 1 ; ;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0 MACRO ; Macro to select data RAM Bank 0 bcf STATUS,RP0 bcf STATUS,RP1 ENDM Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG 0x0000 ; - directiva "ORG" origem do ; programa "ORG 0x0000" vector ; de reset clrf PCLATH ; - instrução "clrf PCLATH" apaga ; todos os bits do registo garante ; que a memória do programa ; é iniciada na página 0 goto main ; - instrução "goto main" salta para ; o endereço de memória do programa ; principal ;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG 0x0005 ; Program Memory PAGE 0 main ; Programa principal. call InitCfg ; incrementa ;
28
TP1 - Entrada e saída básica incf
PORTB,f
movlw call
75 Delay
btfsc goto
PORTA,RA4 incrementa
decf
PORTB,f
movlw call
75 Delay
btfss goto goto
PORTA,RA4 decrementa incrementa
decrementa
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
add 1 to port B delay( 3/4 seg ) RA4 está ON ? sub 1 to port B delay( 3/4 seg ) RA4 está OFF ?
;******************************************************************** ;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O ; ; ; ; Retorna em Bank0 ; ; ; ;===================================================================; InitCfg ;----------------- I/O - InitCfg -----------------------------------; Bank1 ; DATA memory (RAM) Bank1 movlw b’11110000’ ; RA[3:0] outputs movwf TRISB ; RA[7:4] inputs movlw b’00001000’ ; RA[7:5 & 3:0] outputs movwf TRISA ; RA[4] inputs ; Bank0 ; DATA memory (RAM) Bank0 clrf PORTB ; Inicialização PORTB. return ;===================================================================; ; Delay ; ; Pode gerar delays entre 10 mS e 2,5 S ; ; O valor de entrada e’ passado em W (1..255) ; ; Retorna em Bank0 ; ; ; ; Notas: o loop base e’ de 1 uS (T=200 nS <=> 4*1/20MHz) ; ; ; ;===================================================================; Delay movwf delay_mult ; Carrega o valor multiplo Del_m10 movlw 50 ; de 10 mS movwf delay_k50 ; 50 => 10 mS Del_50 movlw 200 ; 200 => 200 uS movwf delay_k200 ; Carrega o valor Del_200 nop ; correspondente a 200 uS nop decfsz delay_k200,f ; Decrementa "delay_k200". ; O resultado é colocadao em ; "delay_k200" goto Del_200 ; while( delay_k200 > 0 ) decfsz delay_k50,f ; goto Del_50 ; while( delay_k50 > 0 ) decfsz delay_mult,f ; Decrementa "delay_mult". ; O resultado é colocadao ; em "delay_mult" goto Del_m10 ; while( delay_mult > 0 )
29
Guia prático sobre microcontroladores PIC return ;******************************************************************** END
; directive ’end of program’
30
TP2 - Descodificador Hexadecimal / 7Seg, 1 display
1
Tema a desenvolver
Duração
Implementação de uma lookup table
1 aula
Resumo
Com este trabalho, pretende-se consolidar os conhecimentos adquiridos nos trabalhos anteriores e estudar o modo de acesso a variáveis em memória RAM, por endereçamento indirecto.
2
Objectivos • Implementação de um descodificador hexadecimal / 7Segmentos por software. • Utilização de subrotinas na estrutura do programa. • Compreensão dos conceitos associados ao acesso a variáveis na memória RAM por endereçamento indirecto.
3 3.1
Descrição Endereçamento Indirecto, Registo FSR e INDF O FSR (File Select Register). É usado no acesso em endereçamento indirecto ou indexado de outros registos, em particular dos registos de uso geral. Se um registo com endereçamento entre [0x20-0x7F] (Banco 0 de memória RAM) é carregado no FSR, o conteúdo desse registo pode ser lido ou escrito através do registo de endereçamento indirecto (INDF), localizado no topo de cada banco de memória (ver mapa de registos do PIC, Anexo A). Este método pode ser usado no acesso a um grupo de dados localizados em memória RAM, através da leitura ou escrita de dados em INDF, a selecção do próximo elemento do grupo é feito através do incremento de FSR (ver figura 16). O endereçamento indirecto ou indexado, é particularmente útil na salvaguarda em memória RAM, de um grupo de dados lidos de um dado
Figura 15: Acesso memória
porto E/S, e, por exemplo no acesso a arrays ou tabelas.
31
Guia prático sobre microcontroladores PIC Endereçamento Indirecto - Exemplo Uma demonstração de endereçamento indirecto, é o trecho de código Assembly seguinte, em que o objectivo é apagar posições consecutivas de memória RAM, localizadas entre 0x20h e 0x2F. Inicialmente é feita a inicialização de FSR com o primeiro valor do grupo de valores a ser apagado, ou seja FSR opera como ponteiro para o valor ‘0’ do array (bloco de valores), sendo incrementado a cada operação de escrita. Em cada ciclo "NEXT", está-se na realidade a apagar (clrf INDF) os conteúdos das posições de memória apontadas por FSR, usando para isso o registo INDF, que não é um registo físico e que só mostra o conteúdo do endereço guardado em FSR.
NEXT
movlw movwf movlw movwf clrf incf decfsz goto
0x20 FSR n_val i INDF FSR,F i,f NEXT
; ; ; ; ; ; ; ;
inicializa ponteiro copia para a RAM nº de posições mem contador apaga registo INDF incrementa ponteiro contador-apaga o próximo
CONTINUE :
; continua
Figura 16: Endereçamento Indirecto código de demonstração
32
TP2 - Descodificador Hexadecimal / 7Seg, 1 display 3.2
Selecção do Banco de Memória
A memória de dados (RAM) encontra-se organizada em bancos distintos (Banco 0, 1, 2 e 3) 4 no total, sendo que o acesso a cada um deles é feito através de selecção. A selecção pode ser feita através de endereçamento directo (ver registo STATUS página 45) ou indirecto. neste último o bit mais significativo do registo FSR, é usado como bit menos significativo na selecção do banco de memória a aceder; os restantes 7 bits são usados na especificação do registo dentro do banco de memória seleccionado. O bit mais significativo para selecção do banco de memória, é dado pelo bit IRP do registo de STATUS. Para mais detalhes ver descrição sobre o registo STATUS, página 45 do guia.
Figura 17: Selecção do banco de memória
4
Trabalho a realizar 1. Visualização, num display de 7 segmentos, de um digito codificado em hexadecimal (ver diagrama do circuito, figura 18). Para isso é necessária a construção de uma rotina que receba um digito em hexadecimal e devolva o correspondente valor para activação de cada um dos segmentos do display. Este valor deverá ser depois enviado para o PORTB. Para melhor compreender o conceito, a tabela 2 mostra a correspondência entre os dígitos hexadecimal de entrada e o valor a enviar para cada um dos 7 segmentos do display. Por exemplo, para visualizar o digito 7 é necessário que o segmento a,b e c estejam activos, isto é, mover para o PORTB o valor em binário b’00001110’. 2. Construir finalmente um contador [0..F] crescente/decrescente por pressão nos botões S1/S2 respectivamente (S1 encontra-se ligado a RB0, S2 encontra-se ligado a RA4).
33
Guia prático sobre microcontroladores PIC
Figura 18: Diagrama do circuito, 1 display de 7 segmentos Valor BCD
PORTB ß Segmentos do Display RB7 ß g
RB6 ß f
RB5 ß e
RB4 ß d
RB3 ß c
RB2 ß b
RB1 ß a
0
0
1
1
1
1
1
1
1
0
0
0
0
1
1
0
2
1
0
1
1
0
1
1
3
1
0
0
1
1
1
1
4
1
1
0
0
1
1
0
5
1
1
0
1
1
0
1
6
1
1
1
1
1
0
0
7
0
0
0
0
1
1
1
8
1
1
1
1
1
1
1
9
1
1
0
0
1
1
1
A
1
1
1
0
1
1
1
B
1
1
1
1
1
0
0
C
0
1
1
1
0
0
1
D
1
0
1
1
1
1
0
E
1
1
1
1
0
0
1
F
1
1
1
0
0
0
1
Tabela 2: Valores Hexadecimal ß 7 segmentos. •
Elementos de Apoio í Manual teórico da disciplina. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 2. - Memory Organization, secção 2.5 - Indirect Addressing, INDF and FSR Registers página 27. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 3. - I/O Ports, página 29. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 13 - Instrution Set Summary, página 135.
34
TP2 - Descodificador Hexadecimal / 7Seg, 1 display
5 5.1
Implementação em Assembly do PIC Ponto 1
; Trabalho Prático nº 2 I ; Implementação descodificador hex para 1 display de 7 segmentos ; ;******************************************************************** ; * ; Nome ficheiro: trab2.asm * ; Última revisão 3/Junho/2005 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2004 * ; * ;******************************************************************** ; * ; Ficheiro necessário: p16f876.lkr * ; * ;******************************************************************** list p=16f876 radix decimal #include "p16f876.inc"
; ; ; ; ; ;
errorlevel -302
list directive to define processor processor specific variable definitions Turn off banking message known tested (good) code
;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RA0 EQU 0 RA1 EQU 1 RA2 EQU 2 RA3 EQU 3 RA4 EQU 4 RA5 EQU 5 RB0 EQU 0 RB1 EQU 1 RB2 EQU 2 RB3 EQU 3 RB4 EQU 4 RB5 EQU 5 RB6 EQU 6 RB7 EQU 7 RC0 EQU 0 RC1 EQU 1 RC2 EQU 2 RC3 EQU 3 RC4 EQU 4 RC5 EQU 5 RC6 EQU 6 RC7 EQU 7 ;-------------------------------------------------------------------; Displays de 7 segmentos -|gfedcba-| ;-------------------------------------------------------------------seg7_0 EQU b’01111110’ ; Valor 0 seg7_1 EQU b’00001100’ ; Valor 1 seg7_2 EQU b’10110110’ ; Valor 2 seg7_3 EQU b’10011110’ ; Valor 3 seg7_4 EQU b’11001100’ ; Valor 4 seg7_5 EQU b’11011010’ ; Valor 5
35
Guia prático sobre microcontroladores PIC seg7_6 seg7_7 seg7_8 seg7_9 seg7_A seg7_B seg7_C seg7_D seg7_E seg7_F
EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU
b’11111000’ b’00001110’ b’11111110’ b’11001110’ b’11101110’ b’11111000’ b’01110010’ b’10111100’ b’11110010’ b’11100010’
; ; ; ; ; ; ; ; ; ;
Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor
6 7 8 9 A B C D E F
;-------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) Bank0 ;-------------------------------------------------------------------RAM UDATA 0x20 seg70 RES 1 ; Valor 0 endereço seg71 RES 1 ; Valor 1 endereço seg72 RES 1 ; Valor 2 endereço seg73 RES 1 ; Valor 3 endereço seg74 RES 1 ; Valor 4 endereço seg75 RES 1 ; Valor 5 endereço seg76 RES 1 ; Valor 6 endereço seg77 RES 1 ; Valor 7 endereço seg78 RES 1 ; Valor 8 endereço seg79 RES 1 ; Valor 9 endereço seg7A RES 1 ; Valor A endereço seg7B RES 1 ; Valor B endereço seg7C RES 1 ; Valor C endereço seg7D RES 1 ; Valor D endereço seg7E RES 1 ; Valor E endereço seg7F RES 1 ; Valor F endereço bcd_in RES 1 ; variavel bcd a afixar delay_mult RES 1 ; Variaveis de controlo delay_k50 RES 1 ; dos loops da rotina Delay delay_k200 EQU 1 ; ;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG 0x0000 ; Processor reset vector clrf PCLATH ; Ensure page bits are cleared goto main ; Go to beginning of program ;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG 0x0005 ; Program Memory PAGE 0
36
TP2 - Descodificador Hexadecimal / 7Seg, 1 display main call
InitCfg
bsf
PORTA,RA1
movlw
0x07
movwf call
bcd_in bcd_7seg
goto
loop
loop
; Programa principal. ; rotina de configuração ; ; ; ; ; ; ; ;
seleciona o display em RA1 while(1) { valor a ser enviado para o display 7 segmentos bcd_7seg(bcd_in) }
;******************************************************************** ;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O ; ; ; ; Retorna em Bank0 ; ; ; ;===================================================================; InitCfg ;----------------- Analog 2 Digital - InitCfg ----------------------; Bank1 ; DATA memory (RAM) Bank1 movlw 0x06 ; W(reg) = 0x06 movwf ADCON1 ; ADCON1 (PORTA I/O digital) ;----------------- I/O - InitCfg -----------------------------------; movlw b’00010000’ ; RA[7:5 & 3:0] outputs movwf TRISA ; RA[4] input movlw b’00000001’ ; RB[7:1] outputs movwf TRISB ; RB[0] input Bank0 clrf clrf clrf
; ; ; ;
PORTA PORTB bcd_in
DATA memory (RAM) Bank0 Inicialização PORTA. Inicialização PORTB. Inicialização BCD_IN.
;-------------------------------------------------------------------; Inicialização dos registros associados aos displays 7seg ;-------------------------------------------------------------------movlw seg7_0 ; Set 7segment valor 0 movwf seg70 ; Save valor 0 movlw seg7_1 ; Set 7segment valor 1 movwf seg71 ; Save valor 1 movlw seg7_2 ; Set 7segment valor 2 movwf seg72 ; Save valor 2 movlw seg7_3 ; Set 7segment valor 3 movwf seg73 ; Save valor 3 movlw seg7_4 ; Set 7segment valor 4 movwf seg74 ; Save valor 4 movlw seg7_5 ; Set 7segment valor 5 movwf seg75 ; Save valor 5 movlw seg7_6 ; Set 7segment valor 6 movwf seg76 ; Save valor 6 movlw seg7_7 ; Set 7segment valor 7 movwf seg77 ; Save valor 7 movlw seg7_8 ; Set 7segment valor 8 movwf seg78 ; Save valor 8 movlw seg7_9 ; Set 7segment valor 9 movwf seg79 ; Save valor 9 movlw seg7_A ; Set 7segment valor A movwf seg7A ; Save valor A movlw seg7_B ; Set 7segment valor B movwf seg7B ; Save valor B
37
Guia prático sobre microcontroladores PIC movlw movwf movlw movwf movlw movwf movlw movwf
seg7_C seg7C seg7_D seg7D seg7_E seg7E seg7_F seg7F
; ; ; ; ; ; ; ;
Set 7segment Save valor C Set 7segment Save valor D Set 7segment Save valor E Set 7segment Save valor F
valor C valor D valor E valor F
return ;===================================================================; ; bcd_7seg ; ; Input: bcd_in - valor BCD de entrada ; ; Output: não devolve nada (void) ; ; ; ; Resumo: routina => BCD to 7segment display, envia o valor ; ; passado em bcd_in para a PORTB por ; ; endereçamento indirecto por registo. ; ; Retorna em Bank0 ; ;===================================================================; bcd_7seg movlw seg70 ; Início da tabela de valores addwf bcd_in,w ; & do val a mostrar da tabela movwf FSR ; Set do endereço da tabela movf INDF,w ; leitura do valor de 7seg movwf PORTB ; envio do valor para o PORTB return ;===================================================================; ; Delay ; ; Pode gerar delays entre 10 mS e 2,5 S ; ; O valor de entrada e’ passado em W (1..255) ; ; ; ; Notas: o loop base e’ de 1 uS (T=200 nS <=> 4*1/20MHz) ; ; ; ; Retorna em Bank0 ; ;===================================================================; Delay movwf delay_mult ; Carrega o valor multiplo Del_m10 movlw 50 ; de 10 mS movwf delay_k50 ; 50 => 10 mS Del_50 movlw 200 ; 200 => 200 uS movwf delay_k200 ; Carrega o valor Del_200 nop ; correspondente a 200 uS nop decfsz delay_k200,f ; Decrementa "delay_k200". ; O resultado é colocadao em ; "delay_k200" goto Del_200 ; while( delay_k200 > 0 ) decfsz delay_k50,f ; goto Del_50 ; while( delay_k50 > 0 ) decfsz delay_mult,f ; Decrementa "delay_mult". ; O resultado é colocadao ; em "delay_mult" goto Del_m10 ; while( delay_mult > 0 ) return ; ;******************************************************************** END
; directive ’end of program’
38
TP2 - Descodificador Hexadecimal / 7Seg, 1 display 5.2
Ponto 2
; Trabalho Prático nº 2 II ; Implementação contador crescente para 1 display de 7 segmentos ; ;******************************************************************** ; * ; Nome ficheiro: trab2p2.asm * ; Última revisão 3/Junho/2005 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2004 * ; * ;******************************************************************** ; * ; Ficheiro necessário: p16f876.lkr * ; * ;******************************************************************** list p=16f876 radix decimal #include "p16f876.inc"
; ; ; ; ; ;
errorlevel -302
list directive to define processor processor specific variable definitions Turn off banking message known tested (good) code
;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RA0 EQU 0 RA1 EQU 1 RA2 EQU 2 RA3 EQU 3 RA4 EQU 4 RA5 EQU 5 RB0 EQU 0 RB1 EQU 1 RB2 EQU 2 RB3 EQU 3 RB4 EQU 4 RB5 EQU 5 RB6 EQU 6 RB7 EQU 7 RC0 EQU 0 RC1 EQU 1 RC2 EQU 2 RC3 EQU 3 RC4 EQU 4 RC5 EQU 5 RC6 EQU 6 RC7 EQU 7 ;-------------------------------------------------------------------; Displays de 7 segmentos -|gfedcba-| ;-------------------------------------------------------------------seg7_0 EQU b’01111110’ ; Valor 0 seg7_1 EQU b’00001100’ ; Valor 1 seg7_2 EQU b’10110110’ ; Valor 2 seg7_3 EQU b’10011110’ ; Valor 3 seg7_4 EQU b’11001100’ ; Valor 4 seg7_5 EQU b’11011010’ ; Valor 5 seg7_6 EQU b’11111000’ ; Valor 6 seg7_7 EQU b’00001110’ ; Valor 7 seg7_8 EQU b’11111110’ ; Valor 8 seg7_9 EQU b’11001110’ ; Valor 9
39
Guia prático sobre microcontroladores PIC seg7_A seg7_B seg7_C seg7_D seg7_E seg7_F
EQU EQU EQU EQU EQU EQU
b’11101110’ b’11111000’ b’01110010’ b’10111100’ b’11110010’ b’11100010’
; ; ; ; ; ;
Valor Valor Valor Valor Valor Valor
A B C D E F
;-------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) Bank0 ;-------------------------------------------------------------------RAM UDATA 0x20 seg70 RES 1 ; Valor 0 endereço seg71 RES 1 ; Valor 1 endereço seg72 RES 1 ; Valor 2 endereço seg73 RES 1 ; Valor 3 endereço seg74 RES 1 ; Valor 4 endereço seg75 RES 1 ; Valor 5 endereço seg76 RES 1 ; Valor 6 endereço seg77 RES 1 ; Valor 7 endereço seg78 RES 1 ; Valor 8 endereço seg79 RES 1 ; Valor 9 endereço seg7A RES 1 ; Valor A endereço seg7B RES 1 ; Valor B endereço seg7C RES 1 ; Valor C endereço seg7D RES 1 ; Valor D endereço seg7E RES 1 ; Valor E endereço seg7F RES 1 ; Valor F endereço bcd_in RES 1 ; variavel bcd a afixar delay_mult RES 1 ; Variaveis de controlo delay_k50 RES 1 ; dos loops da rotina Delay delay_k200 EQU 1 ; ;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG 0x0000 ; Processor reset vector clrf PCLATH ; Ensure page bits are cleared goto main ; Go to beginning of program ;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG 0x0005 ; Program Memory PAGE 0 main ; Programa principal. call InitCfg ; rotina de configuração bsf
PORTA,RA1
40
; seleciona o display em RA3
TP2 - Descodificador Hexadecimal / 7Seg, 1 display loop btfss incf
PORTA,RA4 bcd_in,f
; while(1) { ; Se SW em RB4, for selecionado ; incrementa bcd_in
call
bcd_7seg
; bcd_7seg(bcd_in)
movlw call
20 Delay
; W(reg) = 20 ; delay( 0,20 seg )
btfss decf
PORTB,RB0 bcd_in,f
; Se SW em RB0, for selecionado ; decrementa bcd_in
goto
loop
; }
;******************************************************************** ;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O ; ; ; ; Retorna em Bank0 ; ; ; ;===================================================================; InitCfg ;----------------- Analog 2 Digital - InitCfg ----------------------; Bank1 ; DATA memory (RAM) Bank1 movlw 0x06 ; W(reg) = 0x06 movwf ADCON1 ; ADCON1 (PORTA I/O digital) ;----------------- I/O - InitCfg -----------------------------------; movlw b’00010000’ ; RA[7:5 & 3:0] outputs movwf TRISA ; RA[4] input movlw b’00000001’ ; RB[7:1] outputs movwf TRISB ; RB[0] input Bank0 clrf clrf clrf
; ; ; ;
PORTA PORTB bcd_in
DATA memory (RAM) Bank0 Inicialização PORTA. Inicialização PORTB. Inicialização BCD_IN.
;-------------------------------------------------------------------; Inicialização dos registros associados aos displays 7seg ;-------------------------------------------------------------------movlw seg7_0 ; Set 7segment valor 0 movwf seg70 ; Save valor 0 movlw seg7_1 ; Set 7segment valor 1 movwf seg71 ; Save valor 1 movlw seg7_2 ; Set 7segment valor 2 movwf seg72 ; Save valor 2 movlw seg7_3 ; Set 7segment valor 3 movwf seg73 ; Save valor 3 movlw seg7_4 ; Set 7segment valor 4 movwf seg74 ; Save valor 4 movlw seg7_5 ; Set 7segment valor 5 movwf seg75 ; Save valor 5 movlw seg7_6 ; Set 7segment valor 6 movwf seg76 ; Save valor 6 movlw seg7_7 ; Set 7segment valor 7 movwf seg77 ; Save valor 7 movlw seg7_8 ; Set 7segment valor 8 movwf seg78 ; Save valor 8 movlw seg7_9 ; Set 7segment valor 9 movwf seg79 ; Save valor 9 movlw seg7_A ; Set 7segment valor A movwf seg7A ; Save valor A
41
Guia prático sobre microcontroladores PIC movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf
seg7_B seg7B seg7_C seg7C seg7_D seg7D seg7_E seg7E seg7_F seg7F
; ; ; ; ; ; ; ; ; ;
Set 7segment Save valor B Set 7segment Save valor C Set 7segment Save valor D Set 7segment Save valor E Set 7segment Save valor F
valor B valor C valor D valor E valor F
return ;===================================================================; ; bcd_7seg ; ; Input: bcd_in - valor BCD de entrada ; ; Output: não devolve nada (void) ; ; ; ; Resumo: routina => BCD to 7segment display, envia o valor ; ; passado em bcd_in para a PORTB por ; ; endereçamento indirecto por registo. ; ; Retorna em Bank0 ; ;===================================================================; bcd_7seg movlw seg70 ; Início da tabela de valores addwf bcd_in,w ; & do val a mostrar da tabela movwf FSR ; Set do endereço da tabela movf INDF,w ; leitura do valor de 7seg movwf PORTB ; envio do valor para o PORTB return ;===================================================================; ; Delay ; ; Pode gerar delays entre 10 mS e 2,5 S ; ; O valor de entrada e’ passado em W (1..255) ; ; ; ; Notas: o loop base e’ de 1 uS (T=200 nS <=> 4*1/20MHz) ; ; ; ; Retorna em Bank0 ; ;===================================================================; Delay movwf delay_mult ; Carrega o valor multiplo Del_m10 movlw 50 ; de 10 mS movwf delay_k50 ; 50 => 10 mS Del_50 movlw 200 ; 200 => 200 uS movwf delay_k200 ; Carrega o valor Del_200 nop ; correspondente a 200 uS nop decfsz delay_k200,f ; Decrementa "delay_k200". ; O resultado é colocadao em ; "delay_k200" goto Del_200 ; while( delay_k200 > 0 ) decfsz delay_k50,f ; goto Del_50 ; while( delay_k50 > 0 ) decfsz delay_mult,f ; Decrementa "delay_mult". ; O resultado é colocadao ; em "delay_mult" goto Del_m10 ; while( delay_mult > 0 ) return ; ;******************************************************************** END
; directive ’end of program’
42
TP3 - Descodificador Hexadecimal / 7Seg, 3 Displays Tema a desenvolver
Duração
Sistema de visualização com refrescamento,
2 aulas
por multiplexagem no tempo
1
Resumo
Ampliação do trabalho prático anterior a 3 displays de 7 segmentos.
2
Objectivos • Implementação de um sistema de visualização hexadecimal com 3 displays, com a construção de uma rotina para refrescamento dos 3 displays por multiplexagem no tempo. • Aprofundar os conhecimentos adquiridos durante o trabalho prático 3.
3
Descrição
O princípio de funcionamento deste circuito é em tudo igual ao circuito do trabalho anterior, o número dos displays é que vai ser alterado. Serão 3 os displays que terão de ser refrescados no tempo, para que os valores enviados possam ser visualizados em simultâneo. Analisando os diagramas dos circuitos (ver página 19) entende-se que apenas um valor é enviado, de cada vez para um só display, (só um interruptor se encontra fechado). Note-se ainda que os todos os segmentos dos displays estão ligados á mesma saída (PORTB RB[7..1]) do PIC. Assim e tendo em conta que os dados na saída são diferentes, aquando do envio de informação para cada display ao mesmo tempo. Estes devem ser actualizados periodicamente com uma taxa fixa (taxa de refrescamento aprox. = 10ms). uma vez que o olho humano não tem a percepção do envio da informação enviada aos três displays ao mesmo tempo.
43
Guia prático sobre microcontroladores PIC
(a)
(b)
(c)
Figura 19: Processo de refrescamento dos displays
4
Trabalho a realizar 1. Construção de um sistema de visualização em 3 displays de 7 segmentos, de valores codificados em hexadecimal. Para isso, sugere-se o reaproveitamento da "bcd_7seg" construída no trabalho anterior. De modo a que a rotina "bcd_7seg" seja chamada por uma outra rotina, esta controla o envio da informação para cada display em momentos distintos, ao longo do tempo. •
Elementos de Apoio í Manual teórico da disciplina. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 2. - Memory Organization, secção 2.5 - Indirect Addressing, INDF and FSR Registers página 27. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 3. - I/O Ports, página 29. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 13 - Instrution Set Summary, página 135.
44
TP3 - Descodificador Hexadecimal / 7Seg, 3 displays 4.1
Descrição do registo STATUS
O registo STATUS, fornece informações sobre o resultado de instruções aritméticas realizadas na ALU (Unidade Aritmética e Lógica do CPU), do banco de memória seleccionado e do estado de reset. bit 7
IRP: Usado na selecção do banco de memória em endereçamento indirecto. 1 = Bank 2,3 (100h - 1FFh) 0 = Bank 0,1 ( 00h - FFh)
Como se observa na figura 20(a), o banco de memória é especificado com o bit IRP e o bit mais significativo do registo FSR. Mais detalhes sobre o registo FSR, ver página 31 do guia. Um endereço dentro do banco seleccionado é especificado pelos 7 bits menos significativos do registo FSR. Uma vez que o registos STATUS e FSR são comuns a todos os bancos de memória RAM, não existe obstáculo na operação, mesmo que o banco de memória RAM seja alterado.
(a) Selecção com, IRP e FSR bits
(b) Selecção com RP1:RP0 bits
Figura 20: Selecção dos bancos de memória RAM. bit 6-5
RP1:RP0: Usados na selecção do banco de memória em endereçamento directo. 11 = Bank 3 (180h - 1FFh) 10 = Bank 2 (100h - 17Fh) 01 = Bank 1 ( 80h - FFh) 00 = Bank 0 ( 00h - 7Fh)
Na figura 20(b), o banco de memória pretendido é especificado com os bits RP1:RP0. Uma forma de optimizar este procedimento de alternância entre bancos é através do uso de MACROS. Para isso, basta definir inicialmente uma macro para cada banco de memória RAM. No exemplo seguinte temos
45
Guia prático sobre microcontroladores PIC uma macro para o Bank1 de memória RAM, a generalização para outros bancos é possível desde de que, seja respeitada a configuração dos bits RP1:RP0. Bank1
bit 4
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0; Set ’1’ - bit RP0 STATUS,RP1; Set ’0’ - bit RP1 ;
TO: Condição de time-out do watchdog timer, é permitida apenas leitura. 1 = Após power-on, reset, instrução de CLRWDT, ou com instrução de SLEEP. 0 = Ocorrência de time-out do watchdog timer.
bit 3
PD: Condição de power-down (poupança de energia), é permitida apenas leitura. 1 = Após power-up, ou após a execução da instrução de CLRWDT. 0 = Pela execução da instrução de SLEEP.
bit 2
Z: Flag de Z (zero flag). 1 = Quando o resultado de operação lógica ou aritmética é zero 0 = Quando o resultado de operação lógica ou aritmética não é zero.
NOTA: Provavelmente uma das flags mais utilizadas, usada na detecção de zero no resultado de uma operação lógica ou aritmética. bit 1
DC: Flag de Digit Carry. 1 = Quando o ocorre carry no bit 3 do resultado. 0 = Quando não ocorre carry no bit 3 do resultado.
NOTA: A flag é activa, aquando da execução de uma operação, ADDWF, ADDLW, SUBLW ou SUBWF, causando carry no bit 3 do resultado (operações de 4 bits). bit 0
C: Flag de carry 1 = Quando o ocorre carry no bit 8 do resultado. 0 = Quando não ocorre carry no bit 8 do resultado.
NOTA: Esta flag é activa, quando a operação sobre o registo causa um carry no bit 8 do resultado (operações de 8 bits).
46
TP3 - Descodificador Hexadecimal / 7Seg, 3 displays
5
Implementação em Assembly do PIC
; Trabalho Prático nº 3 ; Implementação descodificador hex para 3 displays de 7 segmentos ; á taxa máxima ; ;******************************************************************** ; * ; NomeFicheiro: trab3.asm * ; Data: 3/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2004 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.INC * ; * ;******************************************************************** list p=16f876 radix decimal #include "p16f876.inc"
; ; ; ; ; ;
errorlevel -302
list directive to define processor processor specific variable definitions Turn off banking message known tested (good) code
;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RA0 EQU 0 RA1 EQU 1 RA2 EQU 2 RA3 EQU 3 RA4 EQU 4 RA5 EQU 5 RB0 EQU 0 RB1 EQU 1 RB2 EQU 2 RB3 EQU 3 RB4 EQU 4 RB5 EQU 5 RB6 EQU 6 RB7 EQU 7 RC0 EQU 0 RC1 EQU 1 RC2 EQU 2 RC3 EQU 3 RC4 EQU 4 RC5 EQU 5 RC6 EQU 6 RC7 EQU 7 ;-------------------------------------------------------------------; Displays de 7 segmentos -|gfedcba-| ;-------------------------------------------------------------------seg7_0 EQU b’01111110’ ; Valor 0 seg7_1 EQU b’00001100’ ; Valor 1 seg7_2 EQU b’10110110’ ; Valor 2 seg7_3 EQU b’10011110’ ; Valor 3 seg7_4 EQU b’11001100’ ; Valor 4 seg7_5 EQU b’11011010’ ; Valor 5 seg7_6 EQU b’11111000’ ; Valor 6
47
Guia prático sobre microcontroladores PIC seg7_7 seg7_8 seg7_9 seg7_A seg7_B seg7_C seg7_D seg7_E seg7_F
EQU EQU EQU EQU EQU EQU EQU EQU EQU
b’00001110’ b’11111110’ b’11001110’ b’11101110’ b’11111000’ b’01110010’ b’10111100’ b’11110010’ b’11100010’
; ; ; ; ; ; ; ; ;
Valor Valor Valor Valor Valor Valor Valor Valor Valor
7 8 9 A B C D E F
;-------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) Bank0 ;-------------------------------------------------------------------variaveis seg70 seg71 seg72 seg73 seg74 seg75 seg76 seg77 seg78 seg79 seg7A seg7B seg7C seg7D seg7E seg7F
UDATA RES RES RES RES RES RES RES RES RES RES RES RES RES RES RES RES
0x20 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
bcd_in delay_mult delay_k50 delay_k200 aux disp_7seg
RES RES RES RES RES RES
1 1 1 1 1 1
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor
0 1 2 3 4 5 6 7 8 9 A B C D E F
endereço endereço endereço endereço endereço endereço endereço endereço endereço endereço endereço endereço endereço endereço endereço endereço
; variavel bcd a afixar ; Variaveis de controlo ; dos loops da rotina Delay ;
;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG 0x0000 ; Processor reset vector clrf PCLATH ; Ensure page bits are cleared goto main ; Go to beginning of program ;-------------------------------------------------------------------; Rotina Main
48
TP3 - Descodificador Hexadecimal / 7Seg, 3 displays ;-------------------------------------------------------------------ORG 0x0005 ; Program Memory PAGE 0 main ; Programa principal. call InitCfg ; rotina de configuração loop
; while(1){ ; disp_7seg = 0
clrf
disp_7seg
movlw call
0x0f ; 0x0f -> W(reg) prt_disp7seg ; prt_disp7seg(W(reg))
movlw call
0x0f prt_disp7seg ; prt_disp7seg(W(reg))
movlw call
0x00 prt_disp7seg ; prt_disp7seg(W(reg))
goto
loop
; }
;******************************************************************** ;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O ; ; ; ; Retorna em Bank0 ; ; ; ;===================================================================; InitCfg ;----------------- I/O - InitCfg -----------------------------------; Bank1 ; DATA memory (RAM) Bank1 clrf TRISA ; All bits outputs movlw b’00000001’ ; RB[7:1] outputs movwf TRISB ; RB[0] input Bank0 clrf clrf clrf clrf
; DATA memory (RAM) Bank0 ; Inicialização registos 0x00 ; ; ;
PORTA PORTB bcd_in aux
;-------------------------------------------------------------------; Inicialização dos registros associados aos displays 7seg ;-------------------------------------------------------------------movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw
seg7_0 seg70 seg7_1 seg71 seg7_2 seg72 seg7_3 seg73 seg7_4 seg74 seg7_5 seg75 seg7_6 seg76 seg7_7 seg77 seg7_8 seg78 seg7_9
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
49
Set 7segment Save valor 0 Set 7segment Save valor 1 Set 7segment Save valor 2 Set 7segment Save valor 3 Set 7segment Save valor 4 Set 7segment Save valor 5 Set 7segment Save valor 6 Set 7segment Save valor 7 Set 7segment Save valor 8 Set 7segment
valor 0 valor 1 valor 2 valor 3 valor 4 valor 5 valor 6 valor 7 valor 8 valor 9
Guia prático sobre microcontroladores PIC movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf
seg79 seg7_A seg7A seg7_B seg7B seg7_C seg7C seg7_D seg7D seg7_E seg7E seg7_F seg7F
; ; ; ; ; ; ; ; ; ; ; ; ;
Save valor 9 Set 7segment Save valor A Set 7segment Save valor B Set 7segment Save valor C Set 7segment Save valor D Set 7segment Save valor E Set 7segment Save valor F
valor A valor B valor C valor D valor E valor F
return ;===================================================================; ; Input: W(reg) = BCD_IN - valor BCD de entrada ; ; Output: não devolve nada (void) ; ; ; ; Retorna em Bank0 ; ;===================================================================; prt_disp7seg movwf bcd_in call display ; display(bcd_in,disp_7seg); movlw call
1 Delay
; W(reg) = 1 ; delay( 10ms )
incf
disp_7seg,f
; disp_7seg ++;
return ;===================================================================; ; Input: BCD_IN - valor BCD de entrada ; ; Input: DISP_7SEG - seleção do display a ser refrescado ; ; Output: não devolve nada (void) ; ; ; ; Resumo: Subroutina de Controlo dos displays ; ; Retorna em Bank0 ; ;===================================================================; display movf PORTA,w ; w = PORTA andlw 0xF1 ; movwf aux ; aux = w & 0xf1 disp_0
disp_1
disp_2 break
movfw sublw btfss goto movfw iorlw goto
disp_7seg 0x00 STATUS,Z disp_1 aux 0x08 break
; ; ; ; ; ; ;
switch(disp_7seg)
movfw sublw btfss goto movfw iorlw goto movfw iorlw
disp_7seg 0x01 STATUS,Z disp_2 aux 0x04 break aux 0x02
; ; ; ; ; ; ; ; ;
switch(dis_7seg)
movwf PORTA call bcd_7seg return
50
case_0 w = aux | 0x08 break
case_1 w = aux | 0x04 break case_2 w = aux | 0x02
; escrita na porta ; bcd_7seg(bcd_in);
TP3 - Descodificador Hexadecimal / 7Seg, 3 displays ;===================================================================; ; bcd_7seg ; ; Input: bcd_in - valor BCD de entrada ; ; Output: não devolve nada (void) ; ; ; ; Resumo: routina => BCD to 7segment display, envia o valor ; ; passado em bcd_in para a PORTB por ; ; endereçamento indirecto por registo. ; ; Retorna em Bank0 ; ;===================================================================; bcd_7seg movlw seg70 ; Início da tabela de valores addwf bcd_in,w ; & do val a mostrar da tabela movwf FSR ; Set do endereço da tabela movf INDF,w ; leitura do valor de 7seg movwf PORTB ; envio do valor para o PORTB return ;===================================================================; ; Delay ; ; Pode gerar delays entre 10 mS e 2,5 S ; ; O valor de entrada e’ passado em W (1..255) ; ; ; ; Notas: o loop base e’ de 1 uS (T=200 nS <=> 4*1/20MHz) ; ; ; ; Retorna em Bank0 ; ;===================================================================; Delay movwf delay_mult ; Carrega o valor multiplo Del_m10 movlw 50 ; de 10 mS movwf delay_k50 ; 50 => 10 mS Del_50 movlw 200 ; 200 => 200 uS movwf delay_k200 ; Carrega o valor Del_200 nop ; correspondente a 200 uS nop decfsz delay_k200,f ; Decrementa "delay_k200". ; O resultado é colocadao em ; "delay_k200" goto Del_200 ; while( delay_k200 > 0 ) decfsz delay_k50,f ; goto Del_50 ; while( delay_k50 > 0 ) decfsz delay_mult,f ; Decrementa "delay_mult". ; O resultado é colocadao ; em "delay_mult" goto Del_m10 ; while( delay_mult > 0 ) return
;
;******************************************************************** END
; directive ’end of program’
51
Guia prático sobre microcontroladores PIC
NOTAS:
52
TP4 - Contador de 60 segundos, versão I
1
Tema a desenvolver
Duração
Contagem de tempo, por contagem de instruções
2 aulas
Resumo
Implementação de um contador de 60 seg., usando contagem do tempo por execução de um programa.
2
Objectivos • Manipulação da rotina Delay para contagem de tempo; • Envio de informação para dois displays a partir de um registo de 8 bits; • Construção de uma rotina de decremento de uma variável em BCD.
3
Descrição
O tempo de execução de uma instrução normal é de 1 ciclo de relógio (200 ns), com a excepção das instruções de salto condicional, decfsz, incfsz, btfss, btfsc, (apenas quando executada a instrução de salto) e as de salto incondicional, goto, que levam 2 ciclos de relógio (400 ns). Assim e de forma precisa, pode-se o contar tempo recorrendo à contagem de instruções de um determinado trecho de código, exemplo:
delay loop
movlw movwf nop nop decfsz goto
; nº de ciclos de instruções ;--------------------------; 1 ; + 1 ; + (1 x 100) ; + (1 x 100) ; + (1 x 100) ; + (2 x 99) + 1 ;--------------------------; Total 501
100 timer
timer,f loop
return
O tempo que o processador leva a executar cada um dos primeiros 99 ciclos de loop é de 1µs, uma vez que, a instrução nop demora 1 ciclo de relógio, decfsz 1 ciclo de relógio e goto 2 ciclos de relógio. O último ciclo de loop demora menos 200ns, dado que a instrução goto não é executada. Logo o tempo total é de aproximadamente 100µs (mais exactamente 99,8µs).
53
Guia prático sobre microcontroladores PIC 3.1
Rotina Delay
Disponível deste o primeiro trabalho, a rotina Delay implementa a funcionalidade de contagem de tempo por contagem de instruções. Um exemplo disso, é o trabalho prático 0, onde o atraso efectuado pela rotina Delay, é útil no controle do tempo de on/off do led. A figura 21, mostra o diagrama de fluxo da rotina Delay, mostrando as várias etapas na contagem do tempo.
Figura 21: Diagrama de fluxo da rotina Delay
54
TP4 - 60 segundos, versão I Abaixo mostra-se o código Assembly da rotina Delay, de notar que, o ciclo base de 1µs da rotina, foi feito um pouco à imagem do trecho de código exemplo descrito no início do trabalho, recorrendo às instruções de nop (no operation), decfsz (decrement skip if zero) e goto. No entanto, envoltos no ciclo base estão mais dois ciclos de loop que provocam um aumento do valor de instruções executadas o que implica necessariamente um aumento de tempo. Estes ciclos Del_200 e Del_50, respectivamente de 1µs×200 = 200µs e 1µs×200×50 = 10ms, permitem que para uma entrada compreendida entre [1..255] podemos ter atrasos de entre 10ms e 2,5s. ;===================================================================; ; Delay ; ; Pode gerar delays entre 10 mS e 2,5 S ; ; O valor de entrada e’ passado em W (1..255) ; ; ; ; Notas: o loop base e’ de 1 uS (T=200 nS <=> 4*1/20MHz) ; ; ; ;===================================================================; Delay movwf delay_mult ; Carrega o valor múltiplo Del_m10 movlw 50 ; de 10 mS movwf delay_k50 ; 50 => 10 mS Del_50 movlw 200 ; 200 => 200 uS movwf delay_k200 ; Carrega o valor Del_200 nop ; correspondente a 200 uS nop decfsz delay_k200,f ; Decrementa "delay_k200". ; O resultado é colocadao em ; "delay_k200" goto Del_200 ; while( delay_k200 > 0 ) decfsz delay_k50,f ; goto Del_50 ; while( delay_k50 > 0 ) decfsz delay_mult,f ; Decrementa "delay_mult". ; O resultado é colocadao ; em "delay_mult" goto Del_m10 ; while( delay_mult > 0 ) return
55
Guia prático sobre microcontroladores PIC
4
Trabalho a realizar 1. Implementação de um programa que permita a visualização (com refrescamento a cada 10ms) em dois displays de 7 segmentos, de um valor presente em uma variável (registo de uso geral), inicializada com o valor ‘0x60’. A visualização deve ser feita utilizando as rotinas "display" e "bcd_7seg" desenvolvidas nos trabalhos anteriores. A figura 22 mostra o esquema de ligação pretendido, bem como a estratégia a usar na codificação dos bits a enviar para cada display de 7 segmentos.
Figura 22: Diagrama do circuito para para visualização do valor ‘0x60’ 2. Construir uma rotina que implemente a contagem decrescente do valor ‘0x60’ presente na variável, inicializada no ponto anterior. O decremento deve ser feito em decimal, ou seja de ‘60s’ à ‘59s’ até ’0s’ (ver figura 23). Esta rotina deve ser chamada, a cada segundo, no programa que implementa a visualização da variável descrita no ponto anterior. O programa principal deve, ao detectar a chegada da variável a ‘0’, enviar para os displays a mensagem End (ver figura 24)
56
TP4 - 60 segundos, versão I
Figura 23: Diagrama do circuito, exemplifica a passagem de ‘60’ à ‘59’
Figura 24: Diagrama do circuito, exemplifica o término da contagem
3. Depois do contador de 60s estar a funcionar correctamente, deve adicionar-se um botão de pressão que implemente apenas o START do início da contagem dos ‘60s’ (ver figuras 25 e 26).
57
Guia prático sobre microcontroladores PIC
Figura 25: Diagrama do circuito com sw, antes de se pressionar no botão
Figura 26: Diagrama do circuito com sw, após pressionar no botão •
Elementos de Apoio í Manual teórico da disciplina. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 3. - I/O Ports, página 29. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 13 - Instrution Set Summary, página 135.
58
TP4 - 60 segundos, versão I
5 5.1
Implementação em Assembly do PIC Ponto 1
; Trabalho Prático nº 4 II ; ; Implementação de relógio de 60 segundos, com rotina Delay ; ;******************************************************************** ; * ; NomeFicheiro: trab4p1.asm * ; Data: 3/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2004 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.LKR * ; * ;******************************************************************** list
p=16f876
radix
decimal
; - directiva ’list’, define ; o processor a usar ; - directiva ’radix’ especifica ; definição das variáveis ; - directiva ’include’ inclui ; ficheiro adicional
#include "p16f876.inc" errorlevel -302
; Turn off banking message ; known tested (good) code ;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RA0 RA1 RA2 RA3 RA4 RA5
EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5
RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
;-------------------------------------------------------------------; Displays de 7 segmentos -|gfedcba-|
59
Guia prático sobre microcontroladores PIC ;-------------------------------------------------------------------seg7_0 seg7_1 seg7_2 seg7_3 seg7_4 seg7_5 seg7_6 seg7_7 seg7_8 seg7_9 seg7_A seg7_B seg7_C seg7_D seg7_E seg7_F
EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU
b’01111110’ b’00001100’ b’10110110’ b’10011110’ b’11001100’ b’11011010’ b’11111000’ b’00001110’ b’11111110’ b’11001110’ b’11101110’ b’11111000’ b’01110010’ b’10111100’ b’11110010’ b’11100010’
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor
0 1 2 3 4 5 6 7 8 9 A B C D E F
seg7_n seg7_null
EQU EQU
b’10101000’ b’00000000’
; Valor n ; Valor Null
;-------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) Bank0 ;-------------------------------------------------------------------variaveis UDATA 0x20 seg70 RES 1 ; Valor 0 endereço seg71 RES 1 ; Valor 1 endereço seg72 RES 1 ; Valor 2 endereço seg73 RES 1 ; Valor 3 endereço seg74 RES 1 ; Valor 4 endereço seg75 RES 1 ; Valor 5 endereço seg76 RES 1 ; Valor 6 endereço seg77 RES 1 ; Valor 7 endereço seg78 RES 1 ; Valor 8 endereço seg79 RES 1 ; Valor 9 endereço seg7A RES 1 ; Valor A endereço seg7B RES 1 ; Valor B endereço seg7C RES 1 ; Valor C endereço seg7D RES 1 ; Valor D endereço seg7E RES 1 ; Valor E endereço seg7F RES 1 ; Valor F endereço seg7n seg7null
RES RES
1 1
; Valor n endereço ; Valor null endereço
bcd_in counter disp_7seg delay_mult delay_k50 delay_k200 delay_cnt aux
RES RES RES RES RES RES RES RES
1 1 1 1 1 1 1 1
; ; ; ; ; ;
endereço de entrada BCD valor a ser decrementado seleção do display de 7_seg Variaveis de controlo dos loops da rotina Delay
;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO
; Macro to select data RAM Bank 2
60
TP4 - 60 segundos, versão I
Bank3
bcf bsf ENDM
STATUS,RP0 STATUS,RP1
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG 0x0000 ; Processor reset vector clrf PCLATH ; Ensure page bits are cleared goto main ; Go to beginning of program ;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG 0x0005 ; Program Memory PAGE 0 main ; Programa principal. call InitCfg ; rotina de configuração
loop
movlw movwf
0x60 counter
; ; Valor Inicial do contador seg
movlw movwf movfw andlw call movlw call movlw movwf swapf andlw call movlw call
0 disp_7seg counter 0xf display 1 delay 1 disp_7seg counter,w 0x0f display 1 delay
; ; ; ; ; ; ; ; ; ; ; ; ; ;
goto
loop
;
display 2 display(W,disp_7seg); Delay(10 ms) display 1 display(W,disp_7seg); Delay(10 ms)
;******************************************************************** ;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O ; ; ; ; Retorna em Bank0 ; ; ; ;===================================================================; InitCfg ;----------------- I/O - InitCfg -----------------------------------; Bank1 ; DATA memory (RAM) Bank1 movlw b’00010000’ ; RA[7:5 & 3:0] outputs movwf TRISA ; RA[4] input movlw b’00000001’ ; RB[7:1] outputs movwf TRISB ; RB[0] input Bank0 clrf clrf clrf
PORTA PORTB disp_7seg
; ; ; ;
DATA memory (RAM) Bank0 inicialização PORTA inicialização PORTB disp_7seg = 0;
;-------------------------------------------------------------------; Inicialização dos registros associados aos displays 7seg
61
Guia prático sobre microcontroladores PIC ;-------------------------------------------------------------------movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf
seg7_0 seg70 seg7_1 seg71 seg7_2 seg72 seg7_3 seg73 seg7_4 seg74 seg7_5 seg75 seg7_6 seg76 seg7_7 seg77 seg7_8 seg78 seg7_9 seg79 seg7_A seg7A seg7_B seg7B seg7_C seg7C seg7_D seg7D seg7_E seg7E seg7_F seg7F seg7_n seg7n seg7_null seg7null
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Set 7segment Save valor 0 Set 7segment Save valor 1 Set 7segment Save valor 2 Set 7segment Save valor 3 Set 7segment Save valor 4 Set 7segment Save valor 5 Set 7segment Save valor 6 Set 7segment Save valor 7 Set 7segment Save valor 8 Set 7segment Save valor 9 Set 7segment Save valor A Set 7segment Save valor B Set 7segment Save valor C Set 7segment Save valor D Set 7segment Save valor E Set 7segment Save valor F Set 7segment Save pattern Set 7segment Save pattern
valor 0 valor 1 valor 2 valor 3 valor 4 valor 5 valor 6 valor 7 valor 8 valor 9 valor A valor B valor C valor D valor E valor F pattern N N pattern NULL N
return ;===================================================================; ; Input: BCD_IN - valor BCD de entrada ; ; Input: DISP_7SEG - seleção do display a ser refrescado ; ; Output: não devolve nada (void) ; ; ; ; Resumo: Subroutina de Controlo dos displays ; ; Retorna em Bank0 ; ;===================================================================; display movwf bcd_in ; movfw PORTA ; w = PORTA andlw 0xF1 ; movwf aux ; aux = w & 0xf1 disp_0
disp_1
movfw sublw btfss goto movfw iorlw goto
disp_7seg 0x00 STATUS,Z disp_1 aux 0x08 break
; ; ; ; ; ; ;
movfw sublw btfss goto movfw iorlw
disp_7seg 0x01 STATUS,Z disp_2 aux 0x04
; switch(dis_7seg) ; ; ; ; case_1 ; w = aux | 0x04
62
switch(disp_7seg)
case_0 w = aux | 0x08 break
TP4 - 60 segundos, versão I
disp_2
goto movfw iorlw
break aux 0x02
; break ; case_2 ; w = aux | 0x02
break
movwf PORTA call bcd_7seg
; escrita na porta ; bcd_7seg(bcd_in);
return ;===================================================================; ; bcd_7seg ; ; Input: bcd_in - valor BCD de entrada ; ; Output: não devolve nada (void) ; ; ; ; Resumo: routina => BCD to 7segment display, envia o valor ; ; passado em bcd_in para a PORTB por ; ; endereçamento indirecto por registo. ; ; Retorna em Bank0 ; ;===================================================================; bcd_7seg movlw seg70 ; Início da tabela de valores addwf bcd_in,w ; endereço do valor a mostrar movwf FSR ; Set do endereço da tabela movf INDF,w ; leitura do valor de 7seg movwf PORTB ; envio do valor para o PORTB return ;===================================================================; ; Delay ; ; Pode gerar delays entre 10 mS e 2,5 S ; ; O valor de entrada e’ passado em W (1..255) ; ; ; ; Notas: o loop base e’ de 1 uS (T=200 nS <=> 4*1/20MHz) ; ; ; ; Retorna em Bank0 ; ;===================================================================; delay movwf delay_mult ; Carrega o valor multiplo Del_m10 movlw 50 ; de 10 mS movwf delay_k50 ; 50 => 10 mS Del_50 movlw 200 ; 200 => 200 uS movwf delay_k200 ; Carrega o valor Del_200 nop ; correspondente a 200 uS nop decfsz delay_k200,f ; Decrementa "delay_k200". ; O resultado é colocadao em ; "delay_k200" goto Del_200 ; while( delay_k200 > 0 ) decfsz delay_k50,f ; goto Del_50 ; while( delay_k50 > 0 ) decfsz delay_mult,f ; Decrementa "delay_mult". ; O resultado é colocadao ; em "delay_mult" goto Del_m10 ; while( delay_mult > 0 ) return ;******************************************************************** END
; directive ’end of program’
63
Guia prático sobre microcontroladores PIC 5.2
Ponto 2
; Trabalho Prático nº 4 II ; ; Implementação de relógio de 60 segundos, com rotina Delay ; ;******************************************************************** ; * ; NomeFicheiro: trab4p2.asm * ; Data: 3/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2004 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.LKR * ; * ;******************************************************************** list
p=16f876
radix
decimal
; - directiva ’list’, define ; o processor a usar ; - directiva ’radix’ especifica ; definição das variáveis ; - directiva ’include’ inclui ; ficheiro adicional
#include "p16f876.inc" errorlevel -302
; Turn off banking message ; known tested (good) code ;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RA0 RA1 RA2 RA3 RA4 RA5
EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5
RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
;-------------------------------------------------------------------; Displays de 7 segmentos -|gfedcba-| ;-------------------------------------------------------------------seg7_0
EQU
b’01111110’
64
; Valor 0
TP4 - 60 segundos, versão I seg7_1 seg7_2 seg7_3 seg7_4 seg7_5 seg7_6 seg7_7 seg7_8 seg7_9 seg7_A seg7_B seg7_C seg7_D seg7_E seg7_F
EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU
b’00001100’ b’10110110’ b’10011110’ b’11001100’ b’11011010’ b’11111000’ b’00001110’ b’11111110’ b’11001110’ b’11101110’ b’11111000’ b’01110010’ b’10111100’ b’11110010’ b’11100010’
; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor
1 2 3 4 5 6 7 8 9 A B C D E F
seg7_n seg7_null
EQU EQU
b’10101000’ b’00000000’
; Valor n ; Valor Null
;-------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) Bank0 ;-------------------------------------------------------------------variaveis UDATA 0x20 seg70 RES 1 ; Valor 0 endereço seg71 RES 1 ; Valor 1 endereço seg72 RES 1 ; Valor 2 endereço seg73 RES 1 ; Valor 3 endereço seg74 RES 1 ; Valor 4 endereço seg75 RES 1 ; Valor 5 endereço seg76 RES 1 ; Valor 6 endereço seg77 RES 1 ; Valor 7 endereço seg78 RES 1 ; Valor 8 endereço seg79 RES 1 ; Valor 9 endereço seg7A RES 1 ; Valor A endereço seg7B RES 1 ; Valor B endereço seg7C RES 1 ; Valor C endereço seg7D RES 1 ; Valor D endereço seg7E RES 1 ; Valor E endereço seg7F RES 1 ; Valor F endereço seg7n seg7null
RES RES
1 1
; Valor n endereço ; Valor null endereço
bcd_in counter disp_7seg delay_mult delay_k50 delay_k200 delay_cnt aux
RES RES RES RES RES RES RES RES
1 1 1 1 1 1 1 1
; ; ; ; ; ;
endereço de entrada BCD valor a ser decrementado seleção do display de 7_seg Variaveis de controlo dos loops da rotina Delay
;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
65
Guia prático sobre microcontroladores PIC
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG 0x0000 ; Processor reset vector clrf PCLATH ; Ensure page bits are cleared goto main ; Go to beginning of program ;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG 0x0005 ; Program Memory PAGE 0 main ; Programa principal. call InitCfg ; rotina de configuração init_count
movlw movwf movfw andlw call movlw call movlw movwf swapf andlw call movlw call
0 disp_7seg counter 0xf display 1 delay 1 disp_7seg counter,w 0x0f display 1 delay
; ; ; ; ; ; ; ; ; ; ; ; ; ;
do_main
movlw call
1 delay
; do{ ; delay ( 10ms )
if_main
btfsc goto movfw andlw
disp_7seg,0 else_main counter 0x0F
else_main
display_main
loop
; ; ; ; ; goto display_main ; ; swapf counter,w ; andlw 0x0F ; btfsc STATUS,Z ; goto $+3 ; ; call display ; incf disp_7seg,w ; andlw 0x01 ; movwf disp_7seg ; decfsz delay_cnt,f ; goto do_main ; movlw 100 ; movwf delay_cnt ; call countdown ; btfss STATUS,Z ; goto do_main ; ; clrf
disp_7seg
movlw call movlw call movlw call
0x0d prt_disp7seg 0x10 prt_disp7seg 0x0E prt_disp7seg
66
display 2 display(W,disp_7seg); Delay(10 ms) display 1 display(W,disp_7seg); Delay(10 ms)
if(disp_7seg == 0) { w = counter w = w & 0x0F W = counter & 0x0F } else
W = counter >> 4 display(W,disp_7seg); disp_7seg=(++disp_7seg)&0x01 if((timer0_cnt--) == 0 ) { timer0_cnt = 100; countdown(counter); }while(STATUS,Z == 0); Yes, repeat COUNT No, TIME OUT
TP4 - 60 segundos, versão I
goto
loop
;******************************************************************** ;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O ; ; ; ; Retorna em Bank0 ; ; ; ;===================================================================; InitCfg ;----------------- I/O - InitCfg -----------------------------------; Bank1 ; DATA memory (RAM) Bank1 movlw b’00010000’ ; RA[7:5 & 3:0] outputs movwf TRISA ; RA[4] input movlw b’00000001’ ; RB[7:1] outputs movwf TRISB ; RB[0] input Bank0 clrf clrf clrf
PORTA PORTB disp_7seg
; ; ; ;
DATA memory (RAM) Bank0 inicialização PORTA inicialização PORTB disp_7seg = 0;
movlw movwf
0x60 counter
; ; Valor Inicial do contador seg
;-------------------------------------------------------------------; Inicialização dos registros associados aos displays 7seg ;-------------------------------------------------------------------movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw
seg7_0 seg70 seg7_1 seg71 seg7_2 seg72 seg7_3 seg73 seg7_4 seg74 seg7_5 seg75 seg7_6 seg76 seg7_7 seg77 seg7_8 seg78 seg7_9 seg79 seg7_A seg7A seg7_B seg7B seg7_C seg7C seg7_D seg7D seg7_E seg7E seg7_F seg7F seg7_n
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
67
Set 7segment Save valor 0 Set 7segment Save valor 1 Set 7segment Save valor 2 Set 7segment Save valor 3 Set 7segment Save valor 4 Set 7segment Save valor 5 Set 7segment Save valor 6 Set 7segment Save valor 7 Set 7segment Save valor 8 Set 7segment Save valor 9 Set 7segment Save valor A Set 7segment Save valor B Set 7segment Save valor C Set 7segment Save valor D Set 7segment Save valor E Set 7segment Save valor F Set 7segment
valor 0 valor 1 valor 2 valor 3 valor 4 valor 5 valor 6 valor 7 valor 8 valor 9 valor A valor B valor C valor D valor E valor F pattern N
Guia prático sobre microcontroladores PIC movwf movlw movwf
seg7n seg7_null seg7null
; Save pattern N ; Set 7segment pattern NULL ; Save pattern N
return ;===================================================================; ; Input: W(reg) = BCD_IN - valor BCD de entrada ; ; Output: não devolve nada (void) ; ; ; ; Retorna em Bank0 ; ;===================================================================; prt_disp7seg movwf bcd_in call display ; display(bcd_in,disp_7seg); movlw call
1 delay
; W(reg) = 1 ; delay( 10ms )
incf
disp_7seg,f
; disp_7seg ++;
return ;===================================================================; ; Input: W - valor BCD de entrada ; ; Input: DISP_7SEG - seleção do display a ser refrescado ; ; Output: não devolve nada (void) ; ; ; ; Resumo: Subroutina de Controlo dos displays ; ; Retorna em Bank0 ; ;===================================================================; display movwf bcd_in ; movfw PORTA ; w = PORTA andlw 0xF1 ; movwf aux ; aux = w & 0xf1 disp_0
disp_1
disp_2 break
movfw sublw btfss goto movfw iorlw goto
disp_7seg 0x00 STATUS,Z disp_1 aux 0x08 break
; ; ; ; ; ; ;
switch(disp_7seg)
movfw sublw btfss goto movfw iorlw goto movfw iorlw
disp_7seg 0x01 STATUS,Z disp_2 aux 0x04 break aux 0x02
; ; ; ; ; ; ; ; ;
switch(dis_7seg)
movwf PORTA call bcd_7seg
case_0 w = aux | 0x08 break
case_1 w = aux | 0x04 break case_2 w = aux | 0x02
; escrita na porta ; bcd_7seg(bcd_in);
return ;===================================================================; ; bcd_7seg ; ; Input: bcd_in - valor BCD de entrada ; ; Output: não devolve nada (void) ; ; ; ; Resumo: routina => BCD to 7segment display, envia o valor ; ; passado em bcd_in para a PORTB por ; ; endereçamento indirecto por registo. ; ; Retorna em Bank0 ;
68
TP4 - 60 segundos, versão I ;===================================================================; bcd_7seg movlw addwf movwf movf movwf
seg70 bcd_in,w FSR INDF,w PORTB
; ; ; ; ;
Início da tabela de valores endereço do valor a mostrar Set do endereço da tabela leitura do valor de 7seg envio do valor para o PORTB
return ;===================================================================; ; Input: COUNTER - valor de entrada ; ; Output: COUNTER - valor decrementado uma unidade ; ; Flag de Zero afectada: ; ; Z=0 if COUNTER != FF ; ; Z=1 if COUNTER == FF ; ; Retorna em Bank0 ; ;===================================================================; countdown decf counter,f ; counter-movfw counter ; w = counter sublw 0xFF ; btfsc STATUS,Z ; if( w == 0xFF ) return ; return movfw counter ; w = counter andlw 0x0F ; w = w & 0x0F sublw 0x0F ; btfss STATUS, Z ; if( w != 0x0F) goto dif_xf ; goto dif_xf movfw counter ; w = counter andlw 0xF0 ; w = w & 0xF0 iorlw 0x09 ; w = w | 0x09 movwf counter ; counter = w dif_xf: bcf STATUS,Z ; reset ZERO flag return ;===================================================================; ; Delay ; ; Pode gerar delays entre 10 mS e 2,5 S ; ; O valor de entrada e’ passado em W (1..255) ; ; ; ; Notas: o loop base e’ de 1 uS (T=200 nS <=> 4*1/20MHz) ; ; ; ; Retorna em Bank0 ; ;===================================================================; delay movwf delay_mult ; Carrega o valor multiplo Del_m10 movlw 50 ; de 10 mS movwf delay_k50 ; 50 => 10 mS Del_50 movlw 200 ; 200 => 200 uS movwf delay_k200 ; Carrega o valor Del_200 nop ; correspondente a 200 uS nop decfsz delay_k200,f ; Decrementa "delay_k200". ; O resultado é colocadao em ; "delay_k200" goto Del_200 ; while( delay_k200 > 0 ) decfsz delay_k50,f ; goto Del_50 ; while( delay_k50 > 0 ) decfsz delay_mult,f ; Decrementa "delay_mult". ; O resultado é colocadao ; em "delay_mult" goto Del_m10 ; while( delay_mult > 0 ) return ;********************************************************************
69
Guia prático sobre microcontroladores PIC END
; directive ’end of program’
70
TP4 - 60 segundos, versão I 5.3
Ponto 3
; Trabalho Prático nº 4 III ; ; Implementação de relógio de 60 segundos, com rotina Delay ; ;******************************************************************** ; * ; NomeFicheiro: trab4p3.asm * ; Data: 3/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2004 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.LKR * ; * ;******************************************************************** list
p=16f876
radix
decimal
; - directiva ’list’, define ; o processor a usar ; - directiva ’radix’ especifica ; definição das variáveis ; - directiva ’include’ inclui ; ficheiro adicional
#include "p16f876.inc" errorlevel -302
; Turn off banking message ; known tested (good) code
;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RA0 RA1 RA2 RA3 RA4 RA5
EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5
RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
;-------------------------------------------------------------------; Displays de 7 segmentos -|gfedcba-| ;--------------------------------------------------------------------
71
Guia prático sobre microcontroladores PIC seg7_0 seg7_1 seg7_2 seg7_3 seg7_4 seg7_5 seg7_6 seg7_7 seg7_8 seg7_9 seg7_A seg7_B seg7_C seg7_D seg7_E seg7_F
EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU
b’01111110’ b’00001100’ b’10110110’ b’10011110’ b’11001100’ b’11011010’ b’11111000’ b’00001110’ b’11111110’ b’11001110’ b’11101110’ b’11111000’ b’01110010’ b’10111100’ b’11110010’ b’11100010’
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor
0 1 2 3 4 5 6 7 8 9 A B C D E F
seg7_n seg7_null
EQU EQU
b’10101000’ b’00000000’
; Valor n ; Valor Null
;-------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) Bank0 ;-------------------------------------------------------------------variaveis UDATA 0x20 seg70 RES 1 ; Valor 0 endereço seg71 RES 1 ; Valor 1 endereço seg72 RES 1 ; Valor 2 endereço seg73 RES 1 ; Valor 3 endereço seg74 RES 1 ; Valor 4 endereço seg75 RES 1 ; Valor 5 endereço seg76 RES 1 ; Valor 6 endereço seg77 RES 1 ; Valor 7 endereço seg78 RES 1 ; Valor 8 endereço seg79 RES 1 ; Valor 9 endereço seg7A RES 1 ; Valor A endereço seg7B RES 1 ; Valor B endereço seg7C RES 1 ; Valor C endereço seg7D RES 1 ; Valor D endereço seg7E RES 1 ; Valor E endereço seg7F RES 1 ; Valor F endereço seg7n seg7null
RES RES
1 1
; Valor n endereço ; Valor null endereço
bcd_in counter disp_7seg delay_mult delay_k50 delay_k200 delay_cnt aux
RES RES RES RES RES RES RES RES
1 1 1 1 1 1 1 1
; ; ; ; ; ;
endereço de entrada BCD valor a ser decrementado seleção do display de 7_seg Variaveis de controlo dos loops da rotina Delay
;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
72
TP4 - 60 segundos, versão I ENDM Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG 0x0000 ; Processor reset vector clrf PCLATH ; Ensure page bits are cleared goto main ; Go to beginning of program ;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG 0x0005 ; Program Memory PAGE 0 main ; Programa principal. call InitCfg ; rotina de configuração init_count
movlw movwf movfw andlw call movlw call movlw movwf swapf andlw call movlw call btfsc goto
0 disp_7seg counter 0xf display 1 delay 1 disp_7seg counter,w 0x0f display 1 delay PORTA,RA4 init_count
do_main
movlw call
1 delay
if_main
btfsc goto movfw andlw
disp_7seg,0 else_main counter 0x0F
else_main
display_main
loop
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
; ; ; ; ; goto display_main ; ; swapf counter,w ; andlw 0x0F ; btfsc STATUS,Z ; goto $+3 ; ; call display ; incf disp_7seg,w ; andlw 0x01 ; movwf disp_7seg ; decfsz delay_cnt,f ; goto do_main ; movlw 100 ; movwf delay_cnt ; call countdown ; btfss STATUS,Z ; goto do_main ; ; clrf
disp_7seg
movlw call movlw call
0x0d prt_disp7seg 0x10 prt_disp7seg
73
display 2 display(W,disp_7seg); Delay(10 ms) display 1 display(W,disp_7seg); Delay(10 ms) START ON NO? YES do{ delay ( 10ms ) if(disp_7seg { ; w ; w W = counter
== 0) = counter = w & 0x0F & 0x0F
} else
W = counter >> 4 display(W,disp_7seg); disp_7seg=(++disp_7seg)&0x01 if((timer0_cnt--) == 0 ) { timer0_cnt = 100; countdown(counter); }while(STATUS,Z == 0); Yes, repeat COUNT No, TIME OUT
Guia prático sobre microcontroladores PIC movlw call
0x0E prt_disp7seg
goto
loop
;******************************************************************** ;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O ; ; ; ; Retorna em Bank0 ; ; ; ;===================================================================; InitCfg ;----------------- I/O - InitCfg -----------------------------------; Bank1 ; DATA memory (RAM) Bank1 movlw b’00010000’ ; RA[7:5 & 3:0] outputs movwf TRISA ; RA[4] input movlw b’00000001’ ; RB[7:1] outputs movwf TRISB ; RB[0] input Bank0 clrf clrf clrf
PORTA PORTB disp_7seg
; ; ; ;
DATA memory (RAM) Bank0 inicialização PORTA inicialização PORTB disp_7seg = 0;
movlw movwf
0x60 counter
; ; Valor Inicial do contador seg
;-------------------------------------------------------------------; Inicialização dos registros associados aos displays 7seg ;-------------------------------------------------------------------movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw
seg7_0 seg70 seg7_1 seg71 seg7_2 seg72 seg7_3 seg73 seg7_4 seg74 seg7_5 seg75 seg7_6 seg76 seg7_7 seg77 seg7_8 seg78 seg7_9 seg79 seg7_A seg7A seg7_B seg7B seg7_C seg7C seg7_D seg7D seg7_E seg7E seg7_F
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
74
Set 7segment Save valor 0 Set 7segment Save valor 1 Set 7segment Save valor 2 Set 7segment Save valor 3 Set 7segment Save valor 4 Set 7segment Save valor 5 Set 7segment Save valor 6 Set 7segment Save valor 7 Set 7segment Save valor 8 Set 7segment Save valor 9 Set 7segment Save valor A Set 7segment Save valor B Set 7segment Save valor C Set 7segment Save valor D Set 7segment Save valor E Set 7segment
valor 0 valor 1 valor 2 valor 3 valor 4 valor 5 valor 6 valor 7 valor 8 valor 9 valor A valor B valor C valor D valor E valor F
TP4 - 60 segundos, versão I movwf movlw movwf movlw movwf
seg7F seg7_n seg7n seg7_null seg7null
; ; ; ; ;
Save valor F Set 7segment Save pattern Set 7segment Save pattern
pattern N N pattern NULL N
return ;===================================================================; ; Input: W(reg) = BCD_IN - valor BCD de entrada ; ; Output: não devolve nada (void) ; ; ; ; Retorna em Bank0 ; ;===================================================================; prt_disp7seg movwf bcd_in call display ; display(bcd_in,disp_7seg); movlw call
1 delay
; W(reg) = 1 ; delay( 10ms )
incf
disp_7seg,f
; disp_7seg ++;
return ;===================================================================; ; Input: BCD_IN - valor BCD de entrada ; ; Input: DISP_7SEG - seleção do display a ser refrescado ; ; Output: não devolve nada (void) ; ; ; ; Resumo: Subroutina de Controlo dos displays ; ; Retorna em Bank0 ; ;===================================================================; display movwf bcd_in ; movfw PORTA ; w = PORTA andlw 0xF1 ; movwf aux ; aux = w & 0xf1 disp_0
disp_1
disp_2 break
movfw sublw btfss goto movfw iorlw goto
disp_7seg 0x00 STATUS,Z disp_1 aux 0x08 break
; ; ; ; ; ; ;
switch(disp_7seg)
movfw sublw btfss goto movfw iorlw goto movfw iorlw
disp_7seg 0x01 STATUS,Z disp_2 aux 0x04 break aux 0x02
; ; ; ; ; ; ; ; ;
switch(dis_7seg)
movwf PORTA call bcd_7seg
case_0 w = aux | 0x08 break
case_1 w = aux | 0x04 break case_2 w = aux | 0x02
; escrita na porta ; bcd_7seg(bcd_in);
return ;===================================================================; ; bcd_7seg ; ; Input: bcd_in - valor BCD de entrada ; ; Output: não devolve nada (void) ; ; ; ; Resumo: routina => BCD to 7segment display, envia o valor ; ; passado em bcd_in para a PORTB por ;
75
Guia prático sobre microcontroladores PIC ; endereçamento indirecto por registo. ; ; Retorna em Bank0 ; ;===================================================================; bcd_7seg movlw addwf movwf movf movwf
seg70 bcd_in,w FSR INDF,w PORTB
; ; ; ; ;
Início da tabela de valores endereço do valor a mostrar Set do endereço da tabela leitura do valor de 7seg envio do valor para o PORTB
return ;===================================================================; ; Input: COUNTER - valor de entrada ; ; Output: COUNTER - valor decrementado uma unidade ; ; Flag de Zero afectada: ; ; Z=0 if COUNTER != FF ; ; Z=1 if COUNTER == FF ; ; Retorna em Bank0 ; ;===================================================================; countdown decf counter,f ; counter-movfw counter ; w = counter sublw 0xFF ; btfsc STATUS,Z ; if( w == 0xFF ) return ; return movfw counter ; w = counter andlw 0x0F ; w = w & 0x0F sublw 0x0F ; btfss STATUS, Z ; if( w != 0x0F) goto dif_xf ; goto dif_xf movfw counter ; w = counter andlw 0xF0 ; w = w & 0xF0 iorlw 0x09 ; w = w | 0x09 movwf counter ; counter = w dif_xf: bcf STATUS,Z ; reset ZERO flag return ;===================================================================; ; Delay ; ; Pode gerar delays entre 10 mS e 2,5 S ; ; O valor de entrada e’ passado em W (1..255) ; ; ; ; Notas: o loop base e’ de 1 uS (T=200 nS <=> 4*1/20MHz) ; ; ; ; Retorna em Bank0 ; ;===================================================================; delay movwf delay_mult ; Carrega o valor multiplo Del_m10 movlw 50 ; de 10 mS movwf delay_k50 ; 50 => 10 mS Del_50 movlw 200 ; 200 => 200 uS movwf delay_k200 ; Carrega o valor Del_200 nop ; correspondente a 200 uS nop decfsz delay_k200,f ; Decrementa "delay_k200". ; O resultado é colocadao em ; "delay_k200" goto Del_200 ; while( delay_k200 > 0 ) decfsz delay_k50,f ; goto Del_50 ; while( delay_k50 > 0 ) decfsz delay_mult,f ; Decrementa "delay_mult". ; O resultado é colocadao ; em "delay_mult" goto Del_m10 ; while( delay_mult > 0 ) return
76
TP4 - 60 segundos, versão I ;******************************************************************** END
; directive ’end of program’
77
Guia prático sobre microcontroladores PIC
NOTAS:
78
TP5 - Relógio de 60 segundos, versão II
1
Tema a desenvolver
Duração
Contagem de tempo com recurso a timers
1 aula
Resumo
Implementação de um relógio de 60s, usando um temporizador (timer 0) para contagem de tempo.
2
Objectivos • Introdução à programação do timer 0, compreensão dos conceitos associados à configuração; • Modificar o programa desenvolvido em TP4, implementado o refrescamento dos displays por timers;
3
Descrição Em muitos programas escritos para microcon-
troladores, é muitas vezes necessário medir tempo de determinados eventos ou efectuar contagens. Por exemplo, um sensor ligado a uma roda de bicicleta pode dar-nos o nº de rotações em cada segundo/minuto, isto é conseguido com um registo contador que conta as voltas completas da roda, e um registo timer que conta os pulsos de relógio, sinalizando com um sinal interno a passagem de 1 segundo/minuto. Um registo contador/timer conta o número de
Figura 27: registo contador de 8 bits
pulsos digitais aplicados à sua entrada. Se o sinal de relógio usado é de uma frequência conhecida, estamos perante um registo timer, uma vez que o tempo de duração da contagem é igual ao valor apurado multiplicado pelo período de relógio. A figura 27 mostra um registo contador/timer de 8 bits, com entrada no bit menos significativo (LSB) à direita. O valor binário guardado no registo incrementa a cada pulso aplicado. Três pulsos
79
Guia prático sobre microcontroladores PIC relógio foram aplicados inicialmente, mostrando o contador o valor binário 3. Depois de 255 pulsos de relógio terem sido aplicados, o próximo pulso efectua a passagem, de ‘11111111’ (0xFF) a ‘00000000’ (0x00), sendo que a passagem é sinalizada através de um sinal de saída, a este sinal dá-se o nome de timer overflow. Pode ser gerado por interrupção (ver trabalho prático 7), ou por polling, a vantagem de usar uma interrupção para o timer é clara uma vez que o programa pode realizar outras operações, enquanto aguarda pela sinalização do overflow.
3.1
Timer 0 • Especificação do timer 0 í O temporizador / contador de 8 bits, TIMER 0 pode contar até 0xFF (255); í Permite leitura e escrita; í Pré-divisor de 8 bits programável; í Selecção de clock interno (FOSC/4) ou externo; í Activação por overflow do bit 2 INTCON TOIF, na passagem de 0xFF para 0x00; í Selecção de flanco ascendente ou descendente do clock externo; í Pode gerar interrupções de fim de contagem, bit 2 INTCON TOIF, desde que o bit 7 INTCON GIE, esteja activo.
Figura 28: Diagrama de blocos do timer 0
80
TP5 - 60 segundos, versão II A figura 28 mostra o diagrama de blocos para o timer 0. A linha a vermelho, descreve deste a entrada até ao timer o modo de selecção do sinal (relógio) de funcionamento. A selecção do sinal à entrada é feita pelo bit TOCS do registo OPTION_REG (ver página 82), sendo que este é o clock interno do PIC, 5Mhz, (1 ciclo de instrução de relógio do micro). A selecção efectuada usa ainda um pré-divisor ou contador programável (prescaler) de 8 bits, este permite dividir o sinal de entrada por um máximo de 256 (sinal de saída com pré divisão máxima = 19,5Khz). O número de contagens do pré-divisor é determinado pelos bits PS0, PS1, PS2 (bits 0, 1, & 2) do registo OPTION_REG. Finalmente o sinal de relógio chega ao módulo timer 0, este é um contador binário de 8 bits podendo contar até 256. Durante a contagem, quando é detectada a passagem de 255(0xFF) a 0(0x00), ou seja o overflow, é activado um sinal através de uma flag, (bit 2 do registo INTCON - TOIF, página 83). Esta flag deve ser reposta a zero por programação, de maneira a permitir a sinalização de novo overflow. O código Assembly seguinte mostra uma possível programação do timer 0 por polling, para uma contagem a cada 10 ms, na activação a ‘1’ ou a ‘0’ do registo switch. De notar que o valor carregado no registo TMR0 é o valor de partida de contagem do módulo timer 0, ou seja uma contagem crescente até 256. ;---------------- TRM0 Bank1 clrf bsf bsf bsf Bank0 movlw movwf clrf loop
btfss goto bcf movlw movwf incf andlw movwf goto
InitCfg ------------------------------------; ; DATA memory (RAM) Bank1 OPTION_REG ; clear OPTION_REG OPTION_REG,PS2 ; OPTION_REG,PS1 ; TMR0 prescaler rate OPTION_REG,PS0 ; 1:256 ; ; DATA memory (RAM) Bank0 60 ; TMR0 ; Set Hardware timer0 Value ; switch ; switch take val => 1/0 ; INTCON,T0IF ; while(TOIF == 0) {} $-1 ; INTCON,T0IF ; "reset flag" T0IF = 0; 60 ; TMR0 ; Set Hardware timer0 Value ; switch,w ; 0x01 ; Toogle switch ; ; loop ; repeat again
81
Guia prático sobre microcontroladores PIC 3.2
Registo OPTION_REG
bit 7
RBP U : Activação dos pull-ups em PORTB . 1 = Desactiva os pull-ups em PORTB. 0 = Activa os pull-ups em PORTB (individualmente em cada latch).
bit 6
INTEDG: Selecção da transição de interrupção. 1 = Transição de ‘0’ para ‘1’ do pino RB0/INT. 0 = Transição de ‘1’ para ‘0’ do pino RB0/INT.
bit 5
T0CS: Bit de selecção da fonte de clock do TIMER 0. 1 = Através do pino RA4/T0CKL. 0 = Clock de ciclo das instruções do PIC (CLKO).
bit 4
T0SE: Selecção da transição de incremento do TMR0. 1 = Incremento na transição de ‘1’ para ‘0’ do pino RB4/T0CKL. 0 = Incremento na transição de ‘0’ para ‘1’ do pino RB4/T0CKL.
bit 3
PSA: Atribuição do prescaler. 1 = Prescaler atribuído ao wachdogtimer (WDT). 0 = Prescaler atribuído ao timer 0.
bit 2-0
TMR0IF: Bits de selecção do valor da taxa do prescaler. Valor dos bits
Taxa do TMR0
Taxa do WDT
000 001 010 011 100 101 110 111
1:2 1:4 1:8 1:16 1:32 1:64 1:128 1:256
1:1 1:2 1:4 1:8 1:16 1:32 1:64 1:128
82
TP5 - 60 segundos, versão II 3.3
Registo INTCON
O INTCON contém vários bits que inibem e desinibem as respectivas fontes de interrupção: bit 7
GIE: Activação global das interrupções do PIC. 1 = Activa todas as interrupções. 0 = Desactiva todas as interrupções.
bit 6
PEIE: Activação das interrupções dos periféricos. 1 = Activa todas as interrupções dos periféricos. 0 = Desactiva todas as interrupções dos periféricos.
bit 5
T0IE: Activação da interrupção de overflow do timer 0. 1 = Activa a interrupção do timer 0. 0 = Desactiva a interrupção do timer 0.
bit 4
INTE: Activação da linha de interrupção RB0/INT. 1 = Activa RB0/INT. 0 = Desactiva RB0/INT.
bit 3
RBIE: Mudança de interrupção através do Porto RB. 1 = Activa a mudança de interrupção no Porto RB. 0 = Desactiva a mudança de interrupção no Porto RB.
bit 2
T0IF: Flag de overflow do timer 0. 1 = Indicação de overflow do timer 0, (reposição a 0 por programação). 0 = Ainda não acorreu overflow do timer 0.
bit 1
INTF: Flag de interrupção da linha RB0/INT. 1 = Ocorreu uma interrupção através da linha RB0/INT (reposição a 0 por programação). 0 = Não ocorreu qualquer interrupção na linha RB0/INT.
bit 0
RBIF: Flag de interrupção, alteração no porto RB. 1 = Quando pelo menos um dos portos RB7:RB4 mudam de estado (reposição a 0 por programação). 0 = Nenhum dos pinos RB7:RB4 mudou de estado.
83
Guia prático sobre microcontroladores PIC
4
Trabalho a realizar 1. Voltar ao trabalho trabalho prático 4 (ponto 3, relógio de 60s com botão START), substituir a contagem de tempo efectuada pela rotina Delay no refrescamento dos displays de 7 segmentos, pelo timer 0. Perguntas: (a) Notou alguma diferença no funcionamento do programa, com a inclusão do timer 0?
(b) Que vantagens existem na utilização de timers em virtude de rotinas Delay?
(c) Dê exemplos do dia à dia, em que o uso de timers ou contadores é relevante?
•
Elementos de Apoio í Manual teórico da disciplina. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 3. - I/O Ports, página 29. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 5. - Timer 0 Module, página 47. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 13 - Instrution Set Summary, página 135.
84
TP5 - 60 segundos, versão II
5
Implementação em Assembly do PIC
; Trabalho nº 5 ; Implementação de relógio de 60 segundos, V. II c/ timer0 ; ; Objecivos: ; Introdução á Programação de Timers ; ;******************************************************************** ; * ; Nome ficheiro: trab5.asm * ; Data: 1/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2005 * ; * ;******************************************************************** ; * ; Ficheiro necessário: p16f876.lkr * ; * ;******************************************************************** list radix
p=16f876 decimal
; list directive to define ; processor
#include "p16f876.inc"
; ; ; ;
errorlevel -302
processor specific variable definitions Turn off banking message known tested (good) code
;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RA0 RA1 RA2 RA3 RA4 RA5 RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7 RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
TMR0_HW_VAL1 TMR0_HW_VAL2 TMR0_SFW_VAL
EQU EQU EQU
60 120 100
; 10ms aprox. ; 5ms aprox. ;
;-------------------------------------------------------------------;Displays de 7 segementos -|gfedcba-| ;--------------------------------------------------------------------
85
Guia prático sobre microcontroladores PIC seg7_0 seg7_1 seg7_2 seg7_3 seg7_4 seg7_5 seg7_6 seg7_7 seg7_8 seg7_9 seg7_A seg7_B seg7_C seg7_D seg7_E seg7_F seg7_n seg7_null
EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU
b’01111110’ b’00001100’ b’10110110’ b’10011110’ b’11001100’ b’11011010’ b’11111000’ b’00001110’ b’11111110’ b’11001110’ b’11101110’ b’11111000’ b’01110010’ b’10111100’ b’11110010’ b’11100010’ b’10101000’ b’00000000’
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor
0 1 2 3 4 5 6 7 8 9 A B C D E F n Null
;---------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) ;---------------------------------------------------------------------variaveis UDATA 0x20 seg70 RES 1 ; Valor 0 endereço seg71 RES 1 ; Valor 1 endereço seg72 RES 1 ; Valor 2 endereço seg73 RES 1 ; Valor 3 endereço seg74 RES 1 ; Valor 4 endereço seg75 RES 1 ; Valor 5 endereço seg76 RES 1 ; Valor 6 endereço seg77 RES 1 ; Valor 7 endereço seg78 RES 1 ; Valor 8 endereço seg79 RES 1 ; Valor 9 endereço seg7A RES 1 ; Valor A endereço seg7B RES 1 ; Valor B endereço seg7C RES 1 ; Valor C endereço seg7D RES 1 ; Valor D endereço seg7E RES 1 ; Valor E endereço seg7F RES 1 ; Valor F endereço seg7n RES 1 ; Valor n endereço seg7null RES 1 ; Valor null endereço timer0_cnt bcd_in disp_7seg aux counter
RES RES RES RES RES
1 1 1 1 1
; Software timer0_count Value ; endereço de entrada BCD ; seleção do display de 7_seg ; valor a ser decrementado
;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
86
TP5 - 60 segundos, versão II ENDM ;******************************************************************** ORG clrf goto
0x0000 PCLATH main
; Processor reset vector ; Ensure page bits are cleared ; Go to beginning of program
;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG
0x0005
call
InitCfg
main btfss goto bcf movlw movwf
; ; ; INTCON,T0IF ; $-1 ; INTCON,T0IF ; TMR0_HW_VAL1 ; TMR0 ;
Programa principal. rotina de configuração do{ while(TOIF == 0) {}
btfsc goto movfw andlw movwf goto
disp_7seg,0 else_main counter 0x0F bcd_in display_main
; ; ; ; ; ; ; swapf counter,w ; andlw 0x0F ; btfsc STATUS,Z ; goto $+3 ; movwf bcd_in ; call display ; incf disp_7seg,w ; andlw 0x01 ; movwf disp_7seg ; decfsz timer0_cnt,f ; goto do_main ; movlw TMR0_SFW_VAL ; movwf timer0_cnt ; call countdown ; btfss STATUS,Z ; goto do_main ; ; ; clrf disp_7seg ;
if(disp_7seg == 0) { w = counter w = w & 0x0F bcd_in = counter & 0x0F
movlw call movlw call movlw call
0x0d prt_disp7seg 0x10 prt_disp7seg 0x0e prt_disp7seg
; ; ; ; ; ;
Val_disp0 prt_disp7seg(W(reg)) Val_disp1 prt_disp7seg(W(reg)) Val_disp2 prt_disp7seg(W(reg))
goto
loop
; }
do_main
if_main
else_main
display_main
loop
T0IF = 0; Set Hardware timer0 Value
} else
if (STATUS,Z==1) bcd_in = counter >> 4; display(bcd_in,disp_7seg); disp_7seg = (++disp_7seg) & 0x01; if((timer0_cnt--) == 0 ) timer0_cnt = 100; countdown(counter) }while(STATUS,Z == 0); Yes, repeat COUNT No, TIME OUT while(1){ disp_7seg = 0
;******************************************************************** ;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O, Timer0. ; ; ; ; Retorna em Bank0 ;
87
Guia prático sobre microcontroladores PIC ; ; ; Notas: ; ;===================================================================; InitCfg ;----------------- I/O - InitCfg -----------------------------------; Bank1 ; DATA memory (RAM) Bank1 clrf TRISA ; RA[7:0] outputs movlw b’00000001’ ; RB[7:1] outputs movwf TRISB ; RB[1] input ;----------------- TRM0 - InitCfg ----------------------------------; clrf OPTION_REG ; clear OPTION_REG bsf OPTION_REG,PS2 ; bsf OPTION_REG,PS1 ; TMR0 Rate bsf OPTION_REG,PS0 ; 1:256 Bank0 clrf
disp_7seg
; DATA memory (RAM) Bank0 ;
movlw movwf
0x59 counter
; ; Valor Inicial do contador seg
;-------------------------------------------------------------------; Inicialização dos registros associados aos displays 7seg ;-------------------------------------------------------------------movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf
seg7_0 seg70 seg7_1 seg71 seg7_2 seg72 seg7_3 seg73 seg7_4 seg74 seg7_5 seg75 seg7_6 seg76 seg7_7 seg77 seg7_8 seg78 seg7_9 seg79 seg7_A seg7A seg7_B seg7B seg7_C seg7C seg7_D seg7D seg7_E seg7E seg7_F seg7F seg7_n seg7n seg7_null seg7null
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Set 7segment Save valor 0 Set 7segment Save valor 1 Set 7segment Save valor 2 Set 7segment Save valor 3 Set 7segment Save valor 4 Set 7segment Save valor 5 Set 7segment Save valor 6 Set 7segment Save valor 7 Set 7segment Save valor 8 Set 7segment Save valor 9 Set 7segment Save valor A Set 7segment Save valor B Set 7segment Save valor C Set 7segment Save valor D Set 7segment Save valor E Set 7segment Save valor F Set 7segment Save pattern Set 7segment Save pattern
valor 0 valor 1 valor 2 valor 3 valor 4 valor 5 valor 6 valor 7 valor 8 valor 9 valor A valor B valor C valor D valor E valor F pattern N N pattern NULL N
;--------------------------------------------------------------------------; Programação do Timer0 ;--------------------------------------------------------------------------movlw movwf
TMR0_HW_VAL1 ; Set Hardware timer0 Value TMR0 ; Set TMR0
88
TP5 - 60 segundos, versão II movlw movwf
TMR0_SFW_VAL ; Set Software timer0_count Value timer0_cnt ; Save time0_count adjust
return ;===================================================================; ; Input: BCD_IN - valor BCD de entrada ; ; Input: DISP_7SEG - seleção do display a ser refrescado ; ; Output: ; ; ; ; Resumo: Subroutina de Controlo dos displays ; ;===================================================================; display movf PORTA,w ; w = PORTA andlw 0xF1 ; movwf aux ; aux = w & 0xf1 disp_0
disp_1
disp_2 break
movfw sublw btfss goto movfw iorlw goto
disp_7seg 0x00 STATUS,Z disp_1 aux 0x08 break
; ; ; ; ; ; ;
switch(disp_7seg)
movfw sublw btfss goto movfw iorlw goto movfw iorlw
disp_7seg 0x01 STATUS,Z disp_2 aux 0x04 break aux 0x02
; ; ; ; ; ; ; ; ;
switch(dis_7seg)
movwf call
PORTA bcd_7seg
; escrita na porta ; bcd_7seg(bcd_in);
case_0 w = aux | 0x08 break
case_1 w = aux | 0x04 break case_2 w = aux | 0x02
return ;===================================================================; ; Input: bcd_in - valor BCD de entrada ; ; Output: ; ; ; ; Resumo: Subroutina => BCD to 7segment display, envia o valor ; ; passado em bcd_in para a PORTB ; ;===================================================================; bcd_7seg movlw seg70 ; Início da tabela de valores addwf bcd_in,w ; & do val a mostrar da tabela movwf FSR ; Set do endereço da tabela movf INDF,w ; leitura do valor de 7seg movwf PORTB ; envio do valor para o PORTB return ;===================================================================; ; Input: W(reg) = BCD_IN - valor BCD de entrada ; ; Output: ; ; ; ; Resumo: ; ;===================================================================; prt_disp7seg movwf bcd_in ; bcd_in = w call display ; display(bcd_in,disp_7seg); btfss goto bcf movlw
INTCON,T0IF $-1 INTCON,T0IF 120
89
; while(TOIF == 0) {} ; ; T0IF = 0; ; Set Hardware timer0 Value
Guia prático sobre microcontroladores PIC movwf
TMR0
; Set TMR0
incf
disp_7seg,f
; disp_7seg ++;
return ;===================================================================; ; Input: COUNTER - valor de entrada ; ; Output: COUNTER - valor decrementado ; ; Flag de Zero afectada: Z=0 if COUNTER != FF ; ; Z=1 if COUNTER == FF ; ; Resumo: ; ; ; ; ; ;===================================================================; countdown decf counter,f ; counter-movfw counter ; w = counter sublw 0xFF ; btfsc STATUS,Z ; if( w == 0xFF ) return ; return movfw counter ; w = counter andlw 0x0F ; w = w & 0x0F sublw 0x0F ; btfss STATUS, Z ; if( w != 0x0F) goto dif_xf ; goto dif_xf movfw counter ; w = counter andlw 0xF0 ; w = w & 0xF0 iorlw 0x09 ; w = w | 0x09 movwf counter ; counter = w dif_xf: bcf STATUS,Z ; reset ZERO flag return END
90
TP6 - Semáforo rodoviário (automóveis/peões)
1
Tema a desenvolver
Duração
Implementação de uma máquina de estados
2 aulas
Resumo
Construção de uma máquina de estados que implemente um semáforo para automóveis e peões.
2
Objectivos • Aprofundar os conhecimentos sobre timers. • Implementação de uma máquina de estados por software.
3
Descrição
Figura 29: Semáforo rodoviário (automóveis/peões)
91
Guia prático sobre microcontroladores PIC 3.1
Diagrama de estados - Semáforo rodoviário
A figura 30 é um exemplo de um diagrama de estados, que mostra a interacção entre os vários estados propostos no trabalho prático, este exemplifica a maneira como são efectuadas as transições entre estados ao longo do tempo. De notar que os tempos t1 a t5 representam os tempos em que os estados estão em execução. A tabela 3 descreve a activação (ON) dos leds durante a execução dos estados.
Figura 30: Diagrama de estados do trabalho prático
Estados
vermelho_auto
amarelo_auto
verde_auto
vermelho_peões
on
on
S0 S1
on
verde_peões
on
S2
on
on
S3
on
on
S4
on
intermitente
S5
on
on Tabela 3: Descrição do estado dos leds
92
TP6 - Semáforo rodoviário
4
Trabalho a realizar 1. Dispondo de 5 leds ( 2 vermelhos, 2 verdes e 1 amarelo ), implementar na placa branca dois semáforos, um para automóveis e outro para peões, ligados respectivamente em RB1, RB2, RB3 e RB4,RB5 (ver figura 31 ).
Figura 31: Diagrama do circuito, semáforo rodoviário 2. Desenvolvimento de um programa em assembly para controlo dos semáforos, de acordo com o diagrama de estados da figura 30, que efectue a contagem de tempo na transição dos estados, com auxílio do timer 0. A tabela 4, define o tempo mínimo que deve ser respeitado entre cada transição de estados. estados
t(segundos)
botão pressão
S0 S1 S2
activo à 1,5 1
S3
4
S4
3
S5
1,5 Tabela 4: Tempo minímo entre estados
93
Guia prático sobre microcontroladores PIC •
Elementos de Apoio í Manual teórico da disciplina. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 3. - I/O Ports, página 29. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 5. - Timer 0 Module, página 47. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 13 - Instrution Set Summary, página 135.
94
TP6 - Semáforo rodoviário
5
Implementação em Assembly do PIC
; Trabalho nº 6 ; ; Semáforo Rodoviário (automóveis & peões) ; ; ;******************************************************************** ; * ; NomeFicheiro: trab6.asm * ; Data: 3/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2004 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.LKR * ; * ;******************************************************************** list p=16f876 radix decimal #include "p16f876.inc"
; ; ; ; ; ;
errorlevel -302
list directive to define processor processor specific variable definitions Turn off banking message known tested (good) code
;==================================================================== ; Constantes ;==================================================================== RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RA0 RA1 RA2 RA3 RA4 RA5 RA6 RA7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
TMR0_SFW_VAL TMR0_HW_VAL
EQU EQU
50 60
; Set Software timer0_count Value ; Set Hardware timer0 Value
;==================================================================== ; Constantes de tempo de espera nos estados em unidades de 0,5 seg ;==================================================================== t_verd2amar_A t_amar2verm_A t_verde_P t_verd_interm t_verm_A_P
EQU EQU EQU EQU EQU
3 2 8 6 3
; ; ; ; ;
tempo,s1 tempo,s2 tempo,s3 tempo,s4 tempo,s5
95
= = = = =
1,5s 1s 4s 3s 1,5s
Guia prático sobre microcontroladores PIC ;====================================================================== ; Definicoes - PORTA ;====================================================================== ; ;INPUTS SW1
EQU
RA4
; SW1 está ligado a RA4
;==================================================================== ; Definicoes - PORTB ;==================================================================== ; ;OUTPUTS LED_VERM_A LED_AMAR_A LED_VERD_A
EQU RB1 EQU RB2 EQU RB3
; LED1 está ligado a RB1 ; LED2 está ligado a RB2 ; LED3 está ligado a RB3
LED_VERM_P LED_VERD_P
EQU RB4 EQU RB5
; LED4 está ligado a RB4 ; LED5 está ligado a RB5
;==================================================================== ; Variaveis ;==================================================================== variaveis UDATA 0x20 delay_mult RES 1 ; Variaveis de controlo dos loops delay_k50 RES 1 ; da rotina Delay delay_k200 RES 1 conta_verd2amar_A RES 1 conta_amar2verm_A RES 1 conta_verde_P RES 1 conta_verd_interm RES 1 conta_verm_A_P RES 1 estado RES 1 timer0_cnt RES 1 ;==================================================================== ; Macros to select the register Banks ;==================================================================== Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;==================================================================== ; Macros to select the states ;==================================================================== macro_inicial
MACRO bsf PORTB,LED_VERD_A bcf PORTB,LED_AMAR_A bcf PORTB,LED_VERM_A bcf PORTB,LED_VERD_P bsf PORTB,LED_VERM_P
96
; ; ; ; ; ;
Macro to select state 0 LED VERDE AUTOMOVEIS ON LED AMARELO AUTOMOVEIS OFF LED VERMELHO AUTOMOVEIS OFF LED VERDE PEOES OFF LED VERMELHO PEOES ON
TP6 - Semáforo rodoviário ENDM macro_verd2amar_A
MACRO bcf PORTB,LED_VERD_A bsf PORTB,LED_AMAR_A bcf PORTB,LED_VERM_A bcf PORTB,LED_VERD_P bsf PORTB,LED_VERM_P ENDM
; ; ; ; ; ;
Macro to select state 1 LED VERDE AUTOMOVEIS OFF LED AMARELO AUTOMOVEIS ON LED VERMELHO AUTOMOVEIS OFF LED VERDE PEOES OFF LED VERMELHO PEOES ON
macro_amar2verm_A
MACRO bcf PORTB,LED_VERD_A bcf PORTB,LED_AMAR_A bsf PORTB,LED_VERM_A bcf PORTB,LED_VERD_P bsf PORTB,LED_VERM_P ENDM
; ; ; ; ; ;
Macro to select state 2 LED VERDE AUTOMOVEIS OFF LED AMARELO AUTOMOVEIS OFF LED VERMELHO AUTOMOVEIS ON LED VERDE PEOES OFF LED VERMELHO PEOES ON
macro_verde_P
MACRO bcf PORTB,LED_VERD_A bcf PORTB,LED_AMAR_A bsf PORTB,LED_VERM_A bsf PORTB,LED_VERD_P bcf PORTB,LED_VERM_P ENDM
; ; ; ; ; ;
Macro to select state 3 LED VERDE AUTOMOVEIS OFF LED AMARELO AUTOMOVEIS OFF LED VERMELHO AUTOMOVEIS ON LED VERDE PEOES ON LED VERMELHO PEOES OFF
macro_verd_interm
MACRO bcf PORTB,LED_VERD_A bcf PORTB,LED_AMAR_A bsf PORTB,LED_VERM_A bsf PORTB,LED_VERD_P bcf PORTB,LED_VERM_P ENDM
; ; ; ; ; ;
Macro to select state 4 LED VERDE AUTOMOVEIS OFF LED AMARELO AUTOMOVEIS OFF LED VERMELHO AUTOMOVEIS ON LED VERDE PEOES ON LED VERMELHO PEOES OFF
macro_verm_A_P
MACRO bcf PORTB,LED_VERD_A bcf PORTB,LED_AMAR_A bsf PORTB,LED_VERM_A bcf PORTB,LED_VERD_P bsf PORTB,LED_VERM_P ENDM
; ; ; ; ; ;
Macro to select state 4 LED VERDE AUTOMOVEIS OFF LED AMARELO AUTOMOVEIS OFF LED VERMELHO AUTOMOVEIS ON LED VERDE PEOES OFF LED VERMELHO PEOES ON
;******************************************************************** ORG clrf goto
0x0000 PCLATH main
; Processor reset vector ; Ensure page bits are cleared ; Go to beginning of program
;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG 0x0005 ; main ; Programa principal. call InitCfg loop ; do{ btfss INTCON,T0IF ; while(TOIF == 0){} goto $-1 ; bcf INTCON,T0IF ; T0IF = 0; movlw TMR0_HW_VAL ; Set Hardware timer0 Value movwf TMR0 ; Set TMR0 decfsz timer0_cnt,f ; if(timer0_cnt == 0) goto loop ; { movlw d’50’ ; movwf TMR0_SFW_VAL ; timer0_cnt = 100; ; while( timer0_cnt !=0 ) switch
movfw
estado
sublw
0x00
; w = estado
97
Guia prático sobre microcontroladores PIC
estado_inicial
btfsc goto
STATUS,Z estado_inicial
movfw sublw btfsc goto
estado 0x01 STATUS,Z estado_verd2amar_A
movfw sublw btfsc goto
estado 0x02 STATUS,Z estado_amar2verm_A
movfw sublw btfsc goto
estado 0x03 STATUS,Z estado_verde_P
movfw sublw btfsc goto
estado 0x04 STATUS,Z estado_verd_interm
movfw sublw btfsc nop goto
estado 0x05 STATUS,Z estado_verm_A_P
; estado inicial macro_inicial btfsc PORTA,SW1 ; while(sw1 == 0) {} goto estado_inicial incf estado,f ; estado++; movlw t_verd2amar_A movwf conta_verd2amar_A movlw t_amar2verm_A movwf conta_amar2verm_A movlw t_verde_P movwf conta_verde_P movlw t_verd_interm movwf conta_verd_interm movlw t_verm_A_P movwf conta_verm_A_P goto loop ; break;
estado_verd2amar_A macro_verd2amar_A decfsz conta_verd2amar_A,f ; if (count_amar_a == 0) goto loop ; { incf estado,f ; estado++: goto loop ; break; estado_amar2verm_A macro_amar2verm_A decfsz conta_amar2verm_A,f ; if (count_verm_a == 0) goto loop ; { incf estado,f ; estado++: goto loop ; break; estado_verde_P macro_verde_P decfsz conta_verde_P ,f goto loop incf estado,f goto loop
; ; ; ;
if (count_verd_p == 0) { estado++: break;
estado_verd_interm macro_verd_interm btfss conta_verd_interm,0
98
; led verde peoes on
TP6 - Semáforo rodoviário
off_led fim
goto bsf goto bcf decfsz goto incf goto
off_led PORTB,LED_VERD_P fim PORTB,LED_VERD_P conta_verd_interm,f loop estado,f loop
; if (count_inter_p == 0)
estado_verm_A_P macro_verm_A_P decfsz conta_verm_A_P,f goto loop clrf estado goto loop
; ; ; ;
if (count_verd_p == 0) { estado=0; break;
;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal ; ; ; ; Retorna em Bank0 ; ; ; ;===================================================================; InitCfg ;----------------- Analog 2 Digital - InitCfg ----------------------; Bank1 ; DATA memory (RAM) Bank1 movlw 0x06 ; W = 0x06 movwf ADCON1 ; ADCON1 (PORTA I/O digital) ;----------------- I/O - InitCfg -----------------------------------; movlw b’0001000’ ; R4 inputs movwf TRISA ; movlw b’1100000’ ; R[5:0] outputs movwf TRISB ; R[7:6] inputs ;----------------- TRM0 - InitCfg ----------------------------------; clrf OPTION_REG ; clear OPTION_REG bsf OPTION_REG,PS2 ; bsf OPTION_REG,PS1 ; TMR0 Rate bsf OPTION_REG,PS0 ; 1:256 Bank0 clrf clrf
; DATA memory (RAM) Bank0 ; estado = 0; ; Inicialização PORTA
estado PORTA
;--------------------------------------------------------------------------; Programação do Timer0 ;--------------------------------------------------------------------------movlw movwf
TMR0_HW_VAL TMR0
; Set Hardware timer0 Value ; Set TMR0
movlw movwf
TMR0_SFW_VAL ; Set Software timer0_count Value timer0_cnt ; Save time0_count adjust
return END
;
99
’end of program’
Guia prático sobre microcontroladores PIC
NOTAS:
100
TP7 - Relógio 60 segundos, versão III
1
Tema a desenvolver
Duração
Programação com interrupções (Interrupt driven I/O)
3 aulas
Resumo
Pretende-se com este trabalho prático, introduzir o conceito da transferência de informação I/O por interrupção, ilustrado-o com uma solução do trabalho 1 (led controlado por botão de pressão) por interrupção. No final do trabalho, utilizaremos o exemplo desenvolvido nos trabalhos 4 e 5 (relógio de 60s), para gerar interrupções através do timer 0 e da linha INT0/RB0 do PIC.
2
Objectivos • Compreensão da rotina de atendimento à interrupção RSI ( Rotina de Serviço de atendimento à Interrupção ) descrita em exemplo; • Construção de rotinas de atendimento à interrupção. • Geração de interrupções através da linha de interrupção RB0/INT do PIC. • Geração de interrupções através da flag de overflow TOIF do timer 0 do PIC, para refrescamento dos displays de 7 segmentos, e decremento da variável contadora do relógio.
3
Descrição
O PIC16F876 tem a possibilidade de contar com um sistema de interrupções. Este sistema, consiste num mecanismo através do qual um acontecimento interno ou externo, (assíncrono relativamente ao programa), pode interromper a execução, do programa em curso. É automaticamente produzido um salto para a rotina de atendimento (RSI), onde é executado o código que processa o evento gerador da interrupção, uma vez terminada a RSI, a execução do programa interrompido é retomada. Existem 13 fontes de interrupção no PIC16F876, vejamos algumas: • External RB0/INT pin, INTF. • TMR0 timer overflow, T0IF. • PORTB<7:4> interrupt-on-change, RBIF.
101
Guia prático sobre microcontroladores PIC
Figura 32: Exemplo de uma interrupção A figura 32, representa o esquema simples de uma interrupção genérica. Antes da RSI propriamente dita, é feito automáticamente o reset do bit GIE, (bit 7 do registo INTCON), ou seja a desactivação de todas as interrupções durante o atendimento. O endereço de retorno é guardado na stack, sendo atribuído ao PC (program counter) o endereço 0x0004 (o que equivale a um salto para o endereço 4 da memória de programa). É dever do programador, salvaguardar o contexto dos seguintes registos, W(reg), STATUS e PCLATH. Uma vez dentro da RSI, a fonte de interrupção pode ser determinada por polling aos bits de interrupção; das fontes de interrupção utilizadas. Os mesmos devem ser repostos a zero antes da terminação da RSI, evitando-se desse modo a geração (não desejada) de uma nova interrupção. activar as interrupções globais, evitando assim interrupções recursivas. Para melhor compreender o conceito, mostra-se em exemplo da rotina de atendimento à interrupção para o trabalho prático 1, ver página 104.
3.1
Led pisca-pisca com botão ON/OFF por interrupção
Nos trechos de código assembly seguintes, mostra-se em primeiro lugar o programa principal, inicialmente com a configuração dos registos TRISB e INTCON, cuja descrição pode ser encontrada nas páginas 16 e 83 respectivamente. De seguida o programa entra num ciclo infinito forçando a saída RB0 ao estado ON durante 0,5s e ao estado OFF durante 1s.
102
TP7 - 60 segundos, versão III Em segundo lugar temos a rotina de atendimento à interrupção (RSI), activada sempre que a linha RB0/INT é activa a zero. A rotina de atendimento implementa o toggle (activação ou desactivação de um bit), de um registo denominado de start_stop. Este registo é testado continuamente no ciclo infinito descrito em cima. ORG clrf goto ORG goto
0x0000 PCLATH main 0x0004 interrupt_start
; ; ; ; ;
Processor reset vector Ensure page bits are cleared Go to beginning of program Processor Interrupt Vector Go to ISR
;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG 0x0005 main ;Aqui começa o programa principal ;----------------- I/O - InitCfg -----------------------------------; Bank1 ; DATA memory (RAM) Bank1 movlw b’00000010’ ; RB1 output movwf TRISB ; RB[7:2 & 0] inputs ;----------------- Interrupts enable bits --------------------------; Bank0 ; DATA memory (RAM) Bank0 bsf INTCON,GIE ; Global Int. Enable bit bsf INTCON,INTE ; External Int. enable bit ;-------------------------------------------------------------------; clrf PORTB ; Inicialização PORTB. clrf start_stop ; while_1 ; while(1) { btfsc start_stop,0 ; while (start_stop == 1) {} goto $-1 ; bsf movlw call bcf movlw call
PORTB,RB1 25 Delay PORTB,RB1 25 Delay
; ; ; ; ; ;
goto
while_1
; }
103
Set RB1 ON delay( 0,25 seg ) Set RB1 OFF delay( 0,25 seg )
Guia prático sobre microcontroladores PIC ;************************** ISR ************************************* ;******************************************************************** ;******************************************************************** interrupt_start movwf w_save ; salvaguarda do W reg. swapf STATUS,W ; clrf STATUS ; DATA memory (RAM) Bank0 movwf status_save ; salvaguarda do STATUS reg. movf PCLATH,W ; movwf pclath_save ; salvaguarda do PCLATH reg. clrf PCLATH ; página 0, de memória de ; programa bcf INTCON,INTF ; reset, do bit INTF incf start_stop,w ; andlw 0x01 ; movwf start_stop ; toggle do start_stop (0/1) ; interrupt_end movf pclath_save,w; restauro do PCLATH reg. movwf PCLATH ; swapf status_save,w; restauro da DATA memory (RAM) ; Bank? inicial movwf STATUS ; swapf w_save,f ; restauro do W reg. swapf w_save,w ; retfie
4
; retorno ao prog. principal
Trabalho a realizar 1. Modificar o programa (contador de 60s, versão II ) implementado em TP5, este deve agora implementar o START / STOP do relógio de 60 segundos, em qualquer altura da contagem decrescente. O diagrama do circuito pretendido, é mostrado na figura 33.
Figura 33: Diagrama do circuito, interrupção do RBO/INT
104
TP7 - 60 segundos, versão III 2. Configurar o timer 0 de modo a que este gere interrupções por overflow, construir a rotina RSI que ao ser activada pelo TOIF (bit 2 do registo INTCON), sinalizando o overflow do timer 0 do PIC. Esta deve implementar o refrescamento dos displays de 7 segmentos a cada 10ms e decremento da variável contadora a cada segundo. 3. Finalmente, acrescentar mais uma interrupção à rotina anterior, desta vez gerada pela linha INT0/RB0 do PIC, de modo a implementar o START/STOP do relógio de de 60 segundos. Nota: A RSI anterior, deve ser capaz de distinguir qual o interrupção gerada, timer 0 ou RB0/INT, e agir em conformidade como a interrupção gerada.
•
Elementos de Apoio í Manual teórico da disciplina. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 3. - I/O Ports, página 29. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 5. - Timer 0 Module, página 47. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 12. - Special Features Of Tje Cpu, secção 12.10 - Interrupts, página 129. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 13 - Instrution Set Summary, página 135.
105
Guia prático sobre microcontroladores PIC
5 5.1
Implementação em Assembly do PIC Ponto 1
; Trabalho nº 7p1 ; Implementação de relógio de 60 segundos V.II com start/stop ; ; Objectivos: ; Introdução á Programação de Timers ; Com Interrupt_SR para Botão Start/stop ; ;******************************************************************** ; * ; Nome ficheiro: trab7p1.asm * ; Data: 1/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; Orientador: José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2005 * ; * ;******************************************************************** ; * ; Ficheiro necessário: p16f876.lkr * ; * ;******************************************************************** list p=16f876 radix decimal
; list directive to define ; processor
#include "p16f876.inc"
; ; ; ;
errorlevel -302
processor specific variable definitions Turn off banking message known tested (good) code
;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RA0 RA1 RA2 RA3 RA4 RA5
EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5
TMR0_HW_VAL1 EQU 60 ; 10ms aprox. TMR0_HW_VAL2 EQU 120 ; 5ms aprox. TMR0_SFW_VAL EQU 100 ; ;-------------------------------------------------------------------; Displays de 7seg -|gfedcba-| ;-------------------------------------------------------------------seg7_0 seg7_1 seg7_2 seg7_3
EQU EQU EQU EQU
b’01111110’ b’00001100’ b’10110110’ b’10011110’
106
; ; ; ;
Valor Valor Valor Valor
0 1 2 3
TP7 - 60 segundos, versão III seg7_4 seg7_5 seg7_6 seg7_7 seg7_8 seg7_9 seg7_A seg7_B seg7_C seg7_D seg7_E seg7_F seg7_n seg7_null
EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU
b’11001100’ b’11011010’ b’11111000’ b’00001110’ b’11111110’ b’11001110’ b’11101110’ b’11111000’ b’01110010’ b’10111100’ b’11110010’ b’11100010’ b’10101000’ b’00000000’
; ; ; ; ; ; ; ; ; ; ; ; ; ;
Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor
4 5 6 7 8 9 A B C D E F n Null
;---------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) ;---------------------------------------------------------------------seg70 seg71 seg72 seg73 seg74 seg75 seg76 seg77 seg78 seg79 seg7A seg7B seg7C seg7D seg7E seg7F
EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU EQU
0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor Valor
0 1 2 3 4 5 6 7 8 9 A B C D E F
endereço endereço endereço endereço endereço endereço endereço endereço endereço endereço endereço endereço endereço endereço endereço endereço
seg7n seg7null
EQU EQU
0x30 0x31
; Valor n endereço ; Valor null endereço
timer0_cnt bcd_in disp_7seg aux counter start_stop w_save status_save pclath_save
EQU EQU EQU EQU EQU EQU EQU EQU EQU
0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39 0x3A
; Software timer0_count Value ; endereço de entrada BCD ; seleção do display de 7_seg ; valor a ser decrementado ; SAVE W ; SAVE STATUS REG ; SAVE PCLATH REG
;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf
; Macro to select data RAM Bank 3 STATUS,RP0
107
Guia prático sobre microcontroladores PIC bsf ENDM
STATUS,RP1
;******************************************************************** ORG clrf goto ORG goto
0x00 PCLATH main 0x04
; Processor reset vector ; Ensure page bits are cleared ; Go to beginning of program ; Processor Interrupt Vector interrupt_start ; Go to interrupt servi ; rotine ;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG
0x20
call
InitCfg
btfss goto bcf
INTCON,T0IF $-1 INTCON,T0IF
movlw movwf
TMR0_HW_VAL1 ; TMR0 ; Set Hardware timer0 Value
if_main
btfsc goto movfw andlw movwf goto
disp_7seg,0 else_main counter 0x0F bcd_in display_main
else_main
; ; ; ; ; movwf call display ; incf disp_7seg,w ; andlw 0x01 ; movwf disp_7seg ; btfsc start_stop,0 ; goto do_main ; decfsz timer0_cnt,f ; goto do_main ; movlw TMR0_SFW_VAL ; movwf timer0_cnt ; call countdown ; btfss STATUS,Z ; goto do_main ; ; ; clrf disp_7seg ;
} else
movlw call movlw call movlw call
0x0d prt_disp7seg 0x10 prt_disp7seg 0x0e prt_disp7seg
Val_disp0 prt_disp7seg(W(reg)) Val_disp1 prt_disp7seg(W(reg)) Val_disp2 prt_disp7seg(W(reg))
goto
loop
main do_main
swapf andlw btfsc goto
display_main
loop
; ; ; ; ; ;
Programa principal. rotina de configuração do{ while(TOIF == 0) {} T0IF = 0;
; if(disp_7seg == 0) ; { ; w = counter ; w = w & 0x0F ; bcd_in = counter & 0x0F
counter,w 0x0F STATUS,Z $+3
; ; ; ; ; ;
if (STATUS,Z==1) bcd_in ; bcd_in = counter >> 4 display(bcd_in,disp_7seg); disp_7seg = (++disp_7seg) & 0x01;
if((timer0_cnt--) == 0 ) timer0_cnt = 100; countdown(counter) }while(STATUS,Z == 0); Yes, repeat COUNT No, TIME OUT while(1){ disp_7seg = 0
; }
;******************************************************************** ;************************** ROTINAS ********************************* ;******************************************************************** ;********************************************************************
108
TP7 - 60 segundos, versão III ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O, Timer0. ; ; ; ; Retorna em Bank0 ; ; ; ; Notas: ; ;===================================================================; InitCfg Bank1 ; memoria do programa em Bank1 movlw movwf movlw movwf movlw movwf movlw movwf
0x06 ADCON1 0xf1 TRISA 0x01 TRISB 0x47 OPTION_REG
; ; ; ; ; ; ; ;
W = 0x06 ADCON1 (PORTA I/O digital)
Bank0 movlw movwf
0x90 INTCON
; memoria do programa em Bank0 ; GIE=1, INTE = 1 ; Global Interrupts enable
clrf clrf
disp_7seg start_stop
; ;
movlw movwf
0x59 counter
; ; Valor Inicial do contador seg
RA<3:1> outputs RB<7:1> outputs INTEDG = 1 RBPU/TOCS/PSA=0, PS2:PS0=111
;-------------------------------------------------------------------; Inicialização dos registros associados aos displays 7seg ;-------------------------------------------------------------------movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw
seg7_0 seg70 seg7_1 seg71 seg7_2 seg72 seg7_3 seg73 seg7_4 seg74 seg7_5 seg75 seg7_6 seg76 seg7_7 seg77 seg7_8 seg78 seg7_9 seg79 seg7_A seg7A seg7_B seg7B seg7_C seg7C seg7_D seg7D seg7_E seg7E seg7_F seg7F seg7_n seg7n seg7_null
109
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Set 7segment Save valor 0 Set 7segment Save valor 1 Set 7segment Save valor 2 Set 7segment Save valor 3 Set 7segment Save valor 4 Set 7segment Save valor 5 Set 7segment Save valor 6 Set 7segment Save valor 7 Set 7segment Save valor 8 Set 7segment Save valor 9 Set 7segment Save valor A Set 7segment Save valor B Set 7segment Save valor C Set 7segment Save valor D Set 7segment Save valor E Set 7segment Save valor F Set 7segment Save pattern Set 7segment
valor 0 valor 1 valor 2 valor 3 valor 4 valor 5 valor 6 valor 7 valor 8 valor 9 valor A valor B valor C valor D valor E valor F pattern N N pattern NULL
Guia prático sobre microcontroladores PIC movwf
seg7null
; Save pattern N
;--------------------------------------------------------------------------; Programação do Timer0 ;--------------------------------------------------------------------------movlw movwf
TMR0_HW_VAL1 ; Set Hardware timer0 Value TMR0 ; Set TMR0
movlw movwf
TMR0_SFW_VAL ; Set Software timer0_count Value timer0_cnt ; Save time0_count adjust
return ;===================================================================; ; Input: BCD_IN - valor BCD de entrada ; ; Input: DISP_7SEG - seleção do display a ser refrescado ; ; Output: ; ; ; ; Resumo: Subroutina de Controlo dos displays ; ;===================================================================; display movf PORTA,w ; w = PORTA andlw 0xF1 ; movwf aux ; aux = w & 0xf1 disp_0
disp_1
disp_2 break
movfw sublw btfss goto movfw iorlw goto
disp_7seg 0x00 STATUS,Z disp_1 aux 0x08 break
; ; ; ; ; ; ;
switch(disp_7seg)
movfw sublw btfss goto movfw iorlw goto movfw iorlw
disp_7seg 0x01 STATUS,Z disp_2 aux 0x04 break aux 0x02
; ; ; ; ; ; ; ; ;
switch(dis_7seg)
movwf PORTA call bcd_7seg
case_0 w = aux | 0x08 break
case_1 w = aux | 0x04 break case_2 w = aux | 0x02
; escrita na porta ; bcd_7seg(bcd_in);
return ;===================================================================; ; Input: bcd_in - valor BCD de entrada ; ; Output: ; ; ; ; Resumo: Subroutina => BCD to 7segment display, envia o valor ; ; passado em bcd_in para a PORTB ; ;===================================================================; bcd_7seg movlw seg70 ; Início da tabela de valores addwf bcd_in,w ; & do val a mostrar da tabela movwf FSR ; Set do endereço da tabela movf INDF,w ; leitura do valor de 7seg movwf PORTB ; envio do valor para o PORTB return ;===================================================================; ; Input: W(reg) = BCD_IN - valor BCD de entrada ; ; Output: ; ; ; ; Resumo: ;
110
TP7 - 60 segundos, versão III ;===================================================================; prt_disp7seg movwf bcd_in ; bcd_in = w call display ; display(bcd_in,disp_7seg); btfss goto bcf movlw movwf
INTCON,T0IF $-1 INTCON,T0IF 120 TMR0
; ; ; ; ;
while(TOIF == 0) {}
incf
disp_7seg,f
; disp_7seg ++;
T0IF = 0; Set Hardware timer0 Value Set TMR0
return ;===================================================================; ; Input: COUNTER - valor de entrada ; ; Output: COUNTER - valor decrementado ; ; Flag de Zero afectada: Z=0 if COUNTER != FF ; ; Z=1 if COUNTER == FF ; ; Resumo: ; ; ; ; ; ;===================================================================; countdown decf counter,f ; counter-movfw counter ; w = counter sublw 0xFF ; btfsc STATUS,Z ; if( w == 0xFF ) return ; return (Z flag ON) movfw counter ; w = counter andlw 0x0F ; w = w & 0x0F sublw 0x0F ; btfss STATUS, Z ; if( w != 0x0F) goto dif_xf ; goto dif_xf movfw counter ; w = counter andlw 0xF0 ; w = w & 0xF0 iorlw 0x09 ; w = w | 0x09 movwf counter ; counter = w dif_xf: bcf STATUS,Z ; reset ZERO flag return ;====================================================================; ;teste_sw ; ; ; ; Subrotina de teste do SW start/stop ; ; ; ;====================================================================; teste_sw bcf INTCON,INTF incf start_stop,w ; andlw 0x01 movwf start_stop ; start_stop = (++start_stop) & 0x01 return ;******************************************************************** ;************************** ISR ************************************* ;******************************************************************** ;******************************************************************** interrupt_start movwf w_save ;Salvaguarda W register swapf STATUS,W clrf STATUS movwf status_save ;Salvaguarda do STATUS reg movf PCLATH,W movwf pclath_save clrf PCLATH
111
Guia prático sobre microcontroladores PIC call
teste_sw
movf movwf swapf movwf swapf swapf retfie
pclath_save,w PCLATH status_save,w STATUS ;Recover STATUS reg w_save,f ;Read saved W register w_save,w ;Recover W register
interrupt_end
END
112
TP7 - 60 segundos, versão III 5.2
Ponto 2
; Trabalho nº 7p2 ; Implementação de relógio de 60 segundos c/ timer interrupts ; ; Observações: ; Implementado com com Timers a gerar interrupção a cada 10ms. ; ;******************************************************************** ; * ; Nome ficheiro: trab7p2_3.asm * ; Data: 1/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2005 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.INC * ; * ;******************************************************************** list radix
p=16f876 decimal
; list directive to define ; processor
#include "p16f876.inc"
; ; ; ;
errorlevel -302
processor specific variable definitions Turn off banking message known tested (good) code
;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RA0 RA1 RA2 RA3 RA4 RA5
EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5
RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
TMR0_HW_VAL1 TMR0_HW_VAL2 TMR0_SFW_VAL
EQU EQU EQU
60 120 100
; 10ms aprox. ; 5ms aprox. ;
113
Guia prático sobre microcontroladores PIC ;-------------------------------------------------------------------;Displays de 7 segementos -|gfedcba-| ;-------------------------------------------------------------------seg7_0 EQU b’01111110’ ; Valor 0 seg7_1 EQU b’00001100’ ; Valor 1 seg7_2 EQU b’10110110’ ; Valor 2 seg7_3 EQU b’10011110’ ; Valor 3 seg7_4 EQU b’11001100’ ; Valor 4 seg7_5 EQU b’11011010’ ; Valor 5 seg7_6 EQU b’11111000’ ; Valor 6 seg7_7 EQU b’00001110’ ; Valor 7 seg7_8 EQU b’11111110’ ; Valor 8 seg7_9 EQU b’11001110’ ; Valor 9 seg7_A EQU b’11101110’ ; Valor A seg7_B EQU b’11111000’ ; Valor B seg7_C EQU b’01110010’ ; Valor C seg7_D EQU b’10111100’ ; Valor D seg7_E EQU b’11110010’ ; Valor E seg7_F EQU b’11100010’ ; Valor F seg7_n EQU b’10101000’ ; Valor n seg7_null EQU b’00000000’ ; Valor Null ;---------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) ;---------------------------------------------------------------------variaveis UDATA 0x20 seg70 RES 1 ; Valor 0 endereço seg71 RES 1 ; Valor 1 endereço seg72 RES 1 ; Valor 2 endereço seg73 RES 1 ; Valor 3 endereço seg74 RES 1 ; Valor 4 endereço seg75 RES 1 ; Valor 5 endereço seg76 RES 1 ; Valor 6 endereço seg77 RES 1 ; Valor 7 endereço seg78 RES 1 ; Valor 8 endereço seg79 RES 1 ; Valor 9 endereço seg7A RES 1 ; Valor A endereço seg7B RES 1 ; Valor B endereço seg7C RES 1 ; Valor C endereço seg7D RES 1 ; Valor D endereço seg7E RES 1 ; Valor E endereço seg7F RES 1 ; Valor F endereço seg7n RES 1 ; Valor n endereço seg7null RES 1 ; Valor null endereço timer0_cnt bcd_in counter disp_7seg aux start_stop
RES RES RES RES RES RES
1 1 1 1 1 1
; ; ; ;
Software timer0_count Value endereço de entrada BCD valor a ser decrementado seleção do display de 7_seg
w_save status_save pclath_save
RES RES RES
1 1 1
; SAVE W ; SAVE STATUS REG ; SAVE PCLATH REG
;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
114
TP7 - 60 segundos, versão III
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG clrf goto ORG goto
0x0000 ; Processor reset vector PCLATH ; Ensure page bits are cleared main ; Go to beginning of program 0x04 ; Interrupt vector interrupt_start ; Go to interrupt Service ; Rotine ;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG
0x0005
call
InitCfg
; Programa principal. ; rotina de configuração
movf btfss goto
counter,w STATUS,Z do_main
; ; ; ; ;
clrf
INTCON
main do_main
do{ leitura da flag Z }while(STATUS,Z == 0); Z = 0, Jump to do_main Z = 1, Time OUT
; Interruption disable
loop clrf disp_7seg movlw 0x0d call prt_disp7seg movlw 0x10 call prt_disp7seg movlw 0x0E call prt_disp7seg
; print - ’d’ ; print - ’n’ ; print - ’E’
goto loop ;******************************************************************** ;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O, Timer0. ; ; ; ; Retorna em Bank0 ; ; ; ; Notas: ; ;===================================================================; InitCfg ;----------------- Analog 2 Digital - InitCfg ----------------------; Bank1 ; DATA memory (RAM) Bank1 movlw 0x06 ; W = 0x06 movwf ADCON1 ; ADCON1 (PORTA I/O digital) ;----------------- I/O - InitCfg -----------------------------------; movlw b’11110001’ ; RA[3:1] outputs movwf TRISA ; RA[7:4 & 0] inputs movlw b’00000001’ ; RB[7:1] outputs
115
Guia prático sobre microcontroladores PIC movwf
TRISB
; RB[0]
input
;----------------- TRM0 - InitCfg ----------------------------------; clrf OPTION_REG ; clear OPTION_REG bsf OPTION_REG,INTEDG ; INTEDG = 1 bsf OPTION_REG,PS2 ; bsf OPTION_REG,PS1 ; TMR0 Rate bsf OPTION_REG,PS0 ; 1:256 Bank0 movlw movwf
; DATA memory (RAM) Bank0 TMR0_HW_VAL1 ; Set Hardware timer0 Value TMR0 ; Set TMR0
movlw movwf
TMR0_SFW_VAL ; Set Software timer0_count Value timer0_cnt ; Save time0_count adjust
;----------------- Interrupts enable bits --------------------------; clrf INTCON bsf INTCON,GIE ; Global Int. Enable bit bsf INTCON,T0IE ; TMR0 Overflow Int. enable bsf INTCON,INTE ; External Int. enable bit clrf
disp_7seg
;
movlw movwf
0x59 counter
; ; Valor Inicial do contador seg
;-------------------------------------------------------------------; Inicialização dos registros associados aos displays 7seg ;-------------------------------------------------------------------movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf
seg7_0 seg70 seg7_1 seg71 seg7_2 seg72 seg7_3 seg73 seg7_4 seg74 seg7_5 seg75 seg7_6 seg76 seg7_7 seg77 seg7_8 seg78 seg7_9 seg79 seg7_A seg7A seg7_B seg7B seg7_C seg7C seg7_D seg7D seg7_E seg7E seg7_F seg7F seg7_n seg7n seg7_null seg7null
return
116
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Set 7segment Save valor 0 Set 7segment Save valor 1 Set 7segment Save valor 2 Set 7segment Save valor 3 Set 7segment Save valor 4 Set 7segment Save valor 5 Set 7segment Save valor 6 Set 7segment Save valor 7 Set 7segment Save valor 8 Set 7segment Save valor 9 Set 7segment Save valor A Set 7segment Save valor B Set 7segment Save valor C Set 7segment Save valor D Set 7segment Save valor E Set 7segment Save valor F Set 7segment Save pattern Set 7segment Save pattern
valor 0 valor 1 valor 2 valor 3 valor 4 valor 5 valor 6 valor 7 valor 8 valor 9 valor A valor B valor C valor D valor E valor F pattern N N pattern NULL N
TP7 - 60 segundos, versão III ;===================================================================; ; Input: W(reg) - valor BCD de entrada ; ; Input: DISP_7SEG - seleção do display a ser refrescado ; ; Output: não têm parâmetro de saída ; ; ; ; Resumo: Subroutina de Controlo dos displays ; ; Protótipo em Linguagem C ; ; void display(unsigned char bcd_in, unsigned char disp_7seg) ; ;===================================================================; display movwf bcd_in ; movf PORTA,w ; w = PORTA andlw 0xF1 ; movwf aux ; aux = w & 0xf1 disp_0
disp_1
disp_2 break
movfw sublw btfss goto movfw iorlw goto
disp_7seg 0x00 STATUS,Z disp_1 aux 0x08 break
; ; ; ; ; ; ;
switch(disp_7seg)
movfw sublw btfss goto movfw iorlw goto movfw iorlw
disp_7seg 0x01 STATUS,Z disp_2 aux 0x04 break aux 0x02
; ; ; ; ; ; ; ; ;
switch(dis_7seg)
movwf PORTA call bcd_7seg
case_0 w = aux | 0x08 break
case_1 w = aux | 0x04 break case_2 w = aux | 0x02
; escrita na porta ; bcd_7seg(bcd_in);
return ;===================================================================; ; Input: bcd_in - valor BCD de entrada ; ; Output: ; ; ; ; Resumo: Subroutina => BCD to 7segment display, envia o valor ; ; passado em bcd_in para a PORTB ; ;===================================================================; bcd_7seg movlw seg70 ; Início da tabela de valores addwf bcd_in,w ; & do val a mostrar da tabela movwf FSR ; Set do endereço da tabela movf INDF,w ; leitura do valor de 7seg movwf PORTB ; envio do valor para o PORTB return ;===================================================================; ; Input: W(reg) = BCD_IN - valor BCD de entrada ; ; Output: ; ; ; ; Resumo: ; ;===================================================================; prt_disp7seg call display ; display(bcd_in,disp_7seg); btfss goto bcf movlw movwf
INTCON,T0IF $-1 INTCON,T0IF 120 TMR0
117
; ; ; ; ;
while(TOIF == 0) {} T0IF = 0; Set Hardware timer0 Value Set TMR0
Guia prático sobre microcontroladores PIC incf
disp_7seg,f
; disp_7seg ++;
return ;===================================================================; ; Input: COUNTER - valor de entrada ; ; Output: COUNTER - valor decrementado ; ; Flag de Zero afectada: Z=0 if COUNTER != FF ; ; Z=1 if COUNTER == FF ; ; Resumo: ; ; ; ; ; ;===================================================================; countdown decf counter,f ; counter-movfw counter ; w = counter sublw 0xFF ; btfsc STATUS,Z ; if( w == 0xFF ) return ; return movfw counter ; w = counter andlw 0x0F ; w = w & 0x0F sublw 0x0F ; btfss STATUS, Z ; if( w != 0x0F) goto dif_xf ; goto dif_xf movfw counter ; w = counter andlw 0xF0 ; w = w & 0xF0 iorlw 0x09 ; w = w | 0x09 movwf counter ; counter = w dif_xf: bcf STATUS,Z ; reset ZERO flag return ;******************************************************************** ;************************** ISR ************************************* ;******************************************************************** ;******************************************************************** interrupt_start movwf w_save ;Salvaguarda W register swapf STATUS,W clrf STATUS movwf status_save ;Salvaguarda do STATUS reg movf PCLATH,W movwf pclath_save clrf PCLATH ;**************** timer_int
Timer0 interruption process bcf
INTCON,T0IF
movlw movwf
TMR0_HW_VAL1 ; Set Hard timer value TMR0 ; Set TMR0
btfsc goto movfw andlw movwf goto
disp_7seg,0 else_isr counter 0x0F bcd_in display_isr
; if(disp_7seg == 0) ; { ; w = counter ; w = w & 0x0F ; bcd_in = counter & 0x0F
swapf andlw btfsc goto movwf call incf andlw
counter,w 0x0F STATUS,Z $+3 bcd_in display disp_7seg,w 0x01
; } else ; ; ; ; if (STATUS,Z==1) ; bcd_in = counter >> 4 ; ; display(bcd_in,disp_7seg); ; ;
else_isr
display_isr
*********************
118
; Clear timer0 int flag
TP7 - 60 segundos, versão III movwf
disp_7seg
; disp_7seg = (++disp_7seg) & 0x01;
btfsc goto
start_stop,0 ; if (start_stop == 1) interrupt_end; {
decfsz goto movlw movwf call
;************ interrupt_end
timer0_cnt,f ; if((timer0_cnt--) == 0 ) interrupt_end; { TMR0_SFW_VAL ; timer0_cnt ; timer0_cnt = 100; countdown ; countdown(counter); ; } ; } FIM do processo de Interrupt ************************ movf movwf swapf movwf swapf swapf retfie
pclath_save,w PCLATH status_save,w STATUS ;Recover STATUS reg w_save,f ;Read saved W register w_save,w ;Recover W register
END
119
Guia prático sobre microcontroladores PIC 5.3
Ponto 3
; Trabalho nº 7p3 ; Implementação de relógio de 60 segundos c/ timer interrupts ; e interrupção de start stop apartir de (RB0) ; distinção da interrupção gerada dentro da rotina de serviço ; à interrupção ; ; Observações: ; Implementado com com Timers a gerar interrupção a cada 10ms. ; ;******************************************************************** ; * ; Nome ficheiro: trab7p2_3.asm * ; Data: 1/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2005 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.LKR * ; * ;******************************************************************** list radix
p=16f876 decimal
; list directive to define ; processor
#include "p16f876.inc"
; ; ; ;
errorlevel -302
processor specific variable definitions Turn off banking message known tested (good) code
;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RA0 RA1 RA2 RA3 RA4 RA5
EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5
RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
TMR0_HW_VAL1
EQU
60
; 10ms aprox.
120
TP7 - 60 segundos, versão III TMR0_HW_VAL2 TMR0_SFW_VAL
EQU EQU
120 100
; ;
5ms aprox.
;-------------------------------------------------------------------;Displays de 7 segementos -|gfedcba-| ;-------------------------------------------------------------------seg7_0 EQU b’01111110’ ; Valor 0 seg7_1 EQU b’00001100’ ; Valor 1 seg7_2 EQU b’10110110’ ; Valor 2 seg7_3 EQU b’10011110’ ; Valor 3 seg7_4 EQU b’11001100’ ; Valor 4 seg7_5 EQU b’11011010’ ; Valor 5 seg7_6 EQU b’11111000’ ; Valor 6 seg7_7 EQU b’00001110’ ; Valor 7 seg7_8 EQU b’11111110’ ; Valor 8 seg7_9 EQU b’11001110’ ; Valor 9 seg7_A EQU b’11101110’ ; Valor A seg7_B EQU b’11111000’ ; Valor B seg7_C EQU b’01110010’ ; Valor C seg7_D EQU b’10111100’ ; Valor D seg7_E EQU b’11110010’ ; Valor E seg7_F EQU b’11100010’ ; Valor F seg7_n EQU b’10101000’ ; Valor n seg7_null EQU b’00000000’ ; Valor Null ;---------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) ;---------------------------------------------------------------------variaveis UDATA 0x20 seg70 RES 1 ; Valor 0 endereço seg71 RES 1 ; Valor 1 endereço seg72 RES 1 ; Valor 2 endereço seg73 RES 1 ; Valor 3 endereço seg74 RES 1 ; Valor 4 endereço seg75 RES 1 ; Valor 5 endereço seg76 RES 1 ; Valor 6 endereço seg77 RES 1 ; Valor 7 endereço seg78 RES 1 ; Valor 8 endereço seg79 RES 1 ; Valor 9 endereço seg7A RES 1 ; Valor A endereço seg7B RES 1 ; Valor B endereço seg7C RES 1 ; Valor C endereço seg7D RES 1 ; Valor D endereço seg7E RES 1 ; Valor E endereço seg7F RES 1 ; Valor F endereço seg7n RES 1 ; Valor n endereço seg7null RES 1 ; Valor null endereço timer0_cnt bcd_in counter disp_7seg aux start_stop
RES RES RES RES RES RES
1 1 1 1 1 1
; ; ; ;
Software timer0_count Value endereço de entrada BCD valor a ser decrementado seleção do display de 7_seg
w_save status_save pclath_save
RES RES RES
1 1 1
; SAVE W ; SAVE STATUS REG ; SAVE PCLATH REG
;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO
; Macro to select data RAM Bank 1
121
Guia prático sobre microcontroladores PIC bsf bcf ENDM
STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG clrf goto ORG goto
0x0000 ; Processor reset vector PCLATH ; Ensure page bits are cleared main ; Go to beginning of program 0x04 ; Interrupt vector interrupt_start ; Go to interrupt Service ; Rotine ;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG
0x0005
call
InitCfg
; Programa principal. ; rotina de configuração
movf btfss goto
counter,w STATUS,Z do_main
; ; ; ; ;
clrf
INTCON
main do_main
do{ leitura da flag Z }while(STATUS,Z == 0); Z = 0, Jump to do_main Z = 1, Time OUT
; Interruption disable
loop clrf disp_7seg movlw 0x0d call prt_disp7seg movlw 0x10 call prt_disp7seg movlw 0x0E call prt_disp7seg
; print - ’d’ ; print - ’n’ ; print - ’E’
goto loop ;******************************************************************** ;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O, Timer0. ; ; ; ; Retorna em Bank0 ; ; ; ; Notas: ; ;===================================================================; InitCfg ;----------------- Analog 2 Digital - InitCfg ----------------------; Bank1 ; DATA memory (RAM) Bank1 movlw 0x06 ; W = 0x06 movwf ADCON1 ; ADCON1 (PORTA I/O digital) ;----------------- I/O - InitCfg -----------------------------------;
122
TP7 - 60 segundos, versão III movlw movwf movlw movwf
b’11110001’ TRISA b’00000001’ TRISB
; ; ; ;
RA[3:1] outputs RA[7:4 & 0] inputs RB[7:1] outputs RB[0] input
;----------------- TRM0 - InitCfg ----------------------------------; clrf OPTION_REG ; clear OPTION_REG bsf OPTION_REG,INTEDG ; INTEDG = 1 bsf OPTION_REG,PS2 ; bsf OPTION_REG,PS1 ; TMR0 Rate bsf OPTION_REG,PS0 ; 1:256 Bank0 movlw movwf
; DATA memory (RAM) Bank0 TMR0_HW_VAL1 ; Set Hardware timer0 Value TMR0 ; Set TMR0
movlw movwf
TMR0_SFW_VAL ; Set Software timer0_count Value timer0_cnt ; Save time0_count adjust
;----------------- Interrupts enable bits --------------------------; clrf INTCON bsf INTCON,GIE ; Global Int. Enable bit bsf INTCON,T0IE ; TMR0 Overflow Int. enable bsf INTCON,INTE ; External Int. enable bit clrf
disp_7seg
;
movlw movwf
0x59 counter
; ; Valor Inicial do contador seg
;-------------------------------------------------------------------; Inicialização dos registros associados aos displays 7seg ;-------------------------------------------------------------------movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf
seg7_0 seg70 seg7_1 seg71 seg7_2 seg72 seg7_3 seg73 seg7_4 seg74 seg7_5 seg75 seg7_6 seg76 seg7_7 seg77 seg7_8 seg78 seg7_9 seg79 seg7_A seg7A seg7_B seg7B seg7_C seg7C seg7_D seg7D seg7_E seg7E seg7_F seg7F seg7_n seg7n seg7_null seg7null
123
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Set 7segment Save valor 0 Set 7segment Save valor 1 Set 7segment Save valor 2 Set 7segment Save valor 3 Set 7segment Save valor 4 Set 7segment Save valor 5 Set 7segment Save valor 6 Set 7segment Save valor 7 Set 7segment Save valor 8 Set 7segment Save valor 9 Set 7segment Save valor A Set 7segment Save valor B Set 7segment Save valor C Set 7segment Save valor D Set 7segment Save valor E Set 7segment Save valor F Set 7segment Save pattern Set 7segment Save pattern
valor 0 valor 1 valor 2 valor 3 valor 4 valor 5 valor 6 valor 7 valor 8 valor 9 valor A valor B valor C valor D valor E valor F pattern N N pattern NULL N
Guia prático sobre microcontroladores PIC
return ;===================================================================; ; Input: W(reg) - valor BCD de entrada ; ; Input: DISP_7SEG - seleção do display a ser refrescado ; ; Output: não têm parâmetro de saída ; ; ; ; Resumo: Subroutina de Controlo dos displays ; ; Protótipo em Linguagem C ; ; void display(unsigned char bcd_in, unsigned char disp_7seg) ; ;===================================================================; display movwf bcd_in ; movf PORTA,w ; w = PORTA andlw 0xF1 ; movwf aux ; aux = w & 0xf1 disp_0
disp_1
disp_2 break
movfw sublw btfss goto movfw iorlw goto
disp_7seg 0x00 STATUS,Z disp_1 aux 0x08 break
; ; ; ; ; ; ;
switch(disp_7seg)
movfw sublw btfss goto movfw iorlw goto movfw iorlw
disp_7seg 0x01 STATUS,Z disp_2 aux 0x04 break aux 0x02
; ; ; ; ; ; ; ; ;
switch(dis_7seg)
movwf PORTA call bcd_7seg
case_0 w = aux | 0x08 break
case_1 w = aux | 0x04 break case_2 w = aux | 0x02
; escrita na porta ; bcd_7seg(bcd_in);
return ;===================================================================; ; Input: bcd_in - valor BCD de entrada ; ; Output: ; ; ; ; Resumo: Subroutina => BCD to 7segment display, envia o valor ; ; passado em bcd_in para a PORTB ; ;===================================================================; bcd_7seg movlw seg70 ; Início da tabela de valores addwf bcd_in,w ; & do val a mostrar da tabela movwf FSR ; Set do endereço da tabela movf INDF,w ; leitura do valor de 7seg movwf PORTB ; envio do valor para o PORTB return ;===================================================================; ; Input: W(reg) = BCD_IN - valor BCD de entrada ; ; Output: ; ; ; ; Resumo: ; ;===================================================================; prt_disp7seg call display ; display(bcd_in,disp_7seg); btfss goto bcf
INTCON,T0IF $-1 INTCON,T0IF
124
; while(TOIF == 0) {} ; ; T0IF = 0;
TP7 - 60 segundos, versão III movlw movwf
120 TMR0
; Set Hardware timer0 Value ; Set TMR0
incf
disp_7seg,f
; disp_7seg ++;
return ;===================================================================; ; Input: COUNTER - valor de entrada ; ; Output: COUNTER - valor decrementado ; ; Flag de Zero afectada: Z=0 if COUNTER != FF ; ; Z=1 if COUNTER == FF ; ; Resumo: ; ; ; ; ; ;===================================================================; countdown decf counter,f ; counter-movfw counter ; w = counter sublw 0xFF ; btfsc STATUS,Z ; if( w == 0xFF ) return ; return movfw counter ; w = counter andlw 0x0F ; w = w & 0x0F sublw 0x0F ; btfss STATUS, Z ; if( w != 0x0F) goto dif_xf ; goto dif_xf movfw counter ; w = counter andlw 0xF0 ; w = w & 0xF0 iorlw 0x09 ; w = w | 0x09 movwf counter ; counter = w dif_xf: bcf STATUS,Z ; reset ZERO flag return ;====================================================================; ;teste_sw ; ; ; ; Subrotina de teste do SW start/stop ; ; ; ;====================================================================; teste_sw bcf INTCON,INTF incf start_stop,w ; andlw 0x01 movwf start_stop ; start_stop = (++start_stop) & 0x01 return ;******************************************************************** ;************************** ISR ************************************* ;******************************************************************** ;******************************************************************** interrupt_start movwf w_save ;Salvaguarda W register swapf STATUS,W clrf STATUS movwf status_save ;Salvaguarda do STATUS reg movf PCLATH,W movwf pclath_save clrf PCLATH btfsc call ;**************** timer_int
INTCON,INTF teste_sw
; if ( INTF == 1 ) ; call teste_sw ; else
Timer0 interruption process bcf
INTCON,T0IF
125
*********************
; Clear timer0 int flag
Guia prático sobre microcontroladores PIC
movlw movwf
TMR0_HW_VAL1 ; Set Hard timer value TMR0 ; Set TMR0
btfsc goto movfw andlw movwf goto
disp_7seg,0 else_isr counter 0x0F bcd_in display_isr
; if(disp_7seg == 0) ; { ; w = counter ; w = w & 0x0F ; bcd_in = counter & 0x0F
swapf andlw btfsc goto movwf call incf andlw movwf
counter,w 0x0F STATUS,Z $+3 bcd_in display disp_7seg,w 0x01 disp_7seg
; } else ; ; ; ; if (STATUS,Z==1) ; bcd_in = counter >> 4 ; ; display(bcd_in,disp_7seg); ; ; ; disp_7seg = (++disp_7seg) & 0x01;
btfsc goto
start_stop,0 ; if (start_stop == 1) interrupt_end; {
else_isr
display_isr
decfsz goto movlw movwf call
;************ interrupt_end
timer0_cnt,f ; if((timer0_cnt--) == 0 ) interrupt_end; { TMR0_SFW_VAL ; timer0_cnt ; timer0_cnt = 100; countdown ; countdown(counter); ; } ; } FIM do processo de Interrupt ************************ movf movwf swapf movwf swapf swapf retfie
pclath_save,w PCLATH status_save,w STATUS ;Recover STATUS reg w_save,f ;Read saved W register w_save,w ;Recover W register
END
126
TP8 - USART do PIC
1
Tema a desenvolver
Duração
Comunicação série assíncrona (USART)
2 aulas
Resumo
Neste trabalho prático, será explorada a USART (Universal Synchronous Asynchronous Receiver Transmitter) do PIC16F876, no modo assíncrono full duplex, na comunicação série entre o PIC e o computador do laboratório, através de um programa que implementa um terminal série.
2
Objectivos • Compreensão dos passos de programação da USART, para recepção e transmissão de dados. • Elaboração de rotinas para transmissão e recepção de um carácter. • Elaboração de uma rotina para transmissão de um array de caracteres (strings).
3
Descrição
A USART, é uma das duas portas de comunicação integradas no PIC16F876. Este circuito permite a configuração para comunicação síncrono ou assíncrono, embora neste trabalho apenas estejamos interessados no modo de comunicação assíncrona. Na comunicação com a USART cada bloco de dados é composto por 8 bits (contudo pode ser utilizado um bit adicional para implementar um esquema de detecção de erros, de comunicação por verificação de paridade). O funcionamento da USART, é definido através da programação de dois registos de controlo, TXSTA (registo de controlo/estado de transmissão) e RCSTA (registo de controlo/estado de recepção), mais detalhes ver páginas 131 e 132 respectivamente.
127
Guia prático sobre microcontroladores PIC 3.1
Configuração dos pinos de transmissão/recepção
No modo assíncrono, usa-se o pino (17) RC6 / TX / CK para transmissão de dados, sendo o pino (18) RC7 / RX / DT usado para recepção de dados. Para a USART funcionar correctamente, a entrada (linha RX), e a saída (linha TX) têm de ser definidos no registo TRISC, (ver configuração de um porto página 16). Assim, o bit 6 do porto C, é deFigura 34: Atribuição do porto série
finido em modo saída valor ‘0’ e o bit 7 é
definido em modo entrada valor ‘1’. Usando, RC6 e RC7 como porto para a USART, o bit SPEN do registo RCSTA, deve ser activado a ‘1’.
3.2
Taxa de transmissão da USART
A taxa de transmissão da USART, é controlada pelo BRG (Baud Rate Generator). Esta é definida pelo valor a colocar no registo SPBRG, este registo controla o período do sinal de saída de um free run timer de 8 bits. Em modo assíncrono, o bit BRGH no registo TXSTA, é usado para controlar a taxa de transmissão entre low speed e high speed, usar high speed na maioria dos casos é vantajoso, uma vez que reduz a taxa de erro. As taxas de transmissão disponíveis, para o PIC com uma FOSC de 20MHz estão descritas na tabela 5.
Taxa de transmissão (BAUD RATE)
Valor (decimal) a colocar em SPBRG
9600
129
19200
64
28800
42
33600
36
57600
20
115200
10
Tabela 5: Taxa de transmissão em modo assíncrono (BRGH = 1)
128
TP8 - USART do PIC 3.3
Operação de transmissão
É no registo TXREG que são carregados os dados a transmitir, estes são depois enviados de forma automática para o registo interno TSR e posteriormente transmitidos pelo porto TX. A transmissão de dados é activada pelo bit TXEN do registo TXSTA. O bit menos significativo (LSB, Least Significant Bit), é transferido em primeiro lugar. Uma vez transmitido o conteúdo do registo TXREG para TSR, o TXIF (bit indicador do estado do buffer em PIR1) sinaliza que o registo de transmissão da USART está vazio, tomando o valor ‘1’. Os dados podem ser continuamente transmitidos, se primeiro fôr detectada a sinalização de TXIF, e de seguida fôr efectuada uma escrita no registo TXREG. O TXIF não pode ser apagado por programação: é automáticamente forçado a ‘0’ quando os dados são movidos para TXREG;
Figura 35: Operação de transmissão assíncrona Passos a seguir na configuração de uma Transmissão Assíncrona.
1. Inicializar o registo SPBRG com a taxa de transferência apropriada (ver tabela 5); 2. Activação da porta série em modo assíncrono, pondo a ’0’ o bit SYNC do registo TXSTA e a ’1’ o bit SPEN do registo RCSTA; 3. Por forma activar a transmissão o bit TXEN (registo TXSTA) é activo a ‘1’. Nessa altura o registo TXREG está em condições de ser escrito e o bit TXIF do registo PIR1 vem a ‘1’; 4. Enviar os dados para o TXREG e começar a transmissão.
129
Guia prático sobre microcontroladores PIC 3.4
Operação de recepção
Os dados recebidos pela porta RX são recolhidos no registo RSR, através do circuito de recolha de dados (Data Recovery). Os dados são recolhidos pelo registo RSR, de acordo com a taxa de transmissão especificada pelo registo SPBRG e pelo bit BRGH do registo TXSTA (ver página 131). Aquando da detecção do stop bit, o conteúdo do registo RSR é transferido para o registo RCREG. O bit RCIF do registo PIR1, toma o valor ‘1’ quando os dados são escritos no registo RCREG, (sinalizando a recepção de nova informação). Os dados podem ser continuamente recebidos, se primeiro fôr detectada a sinalização e de seguida efectuar-se uma leitura do registo RCREG. O RCIF não pode ser apagado por programação, este é ‘0’ quando os dados são lidos de RCREG.
Figura 36: Operacão de recepcção assíncrona Passos a seguir na configuração na Recepção Assíncrona.
1. Inicializar o registo SPBRG com a taxa de transmissão apropriada; 2. Activação da porta série em modo assíncrono, pondo a ‘0’ o bit SYNC do registo TXSTA e a ‘1’ o bit SPEN do registo RCSTA; 3. Permitir a recepção, activando o bit CREN do registo RCSTA; 4. Quando a recepção estiver terminada, a flag RCIF do registo PIR1 é activado; 5. Para ler os oito bits recebidos, deverá ser lido o registo RCREG.
130
TP8 - USART do PIC 3.5
Registo TXSTA
bit 7
CSRC: Selecção da origem do relógio. Modo Assíncrono: Dont´t care. Modo Síncrono: 1 = Modo master (relógio gerado internamente por BRG). 0 = Modo slave (relógio gerado externamente).
bit 6
TX9: Transmissão com 9 bits. 1 = Activa a transmissão a 9 bits. 0 = Desactiva a transmissão a 9 bits.
bit 5
TXEN: Activa transmissão. 1 = Activa transmissão. 0 = Desactiva transmissão.
bit 4
CREN: Modo de comunicação da USART. 1 = Modo Assíncrono. 0 = Modo Síncrono.
bit 3
Não Implementado: leitura a ’0’.
bit 2
BRGH: Bit de selecção de HIGH Baud Rate. Modo Assíncrono: 1 = HIGH SPEED. 0 = LOW SPEED. Modo Síncrono: Não usado neste modo
bit 1
TRMT: Transmit Shift Register, bit de estado. 1 = TSR vazio. 0 = TSR cheio.
bit 0
TX9D: Nono bit, na transmissão de dados, (usado para paridade).
131
Guia prático sobre microcontroladores PIC 3.6
Registo RCSTA
bit 7
SPEN: Activação da porta série do PIC. 1 = Porta série activada (configura RC7/RX/DT e RC6/TX/CK pinos como portos série) . 0 = Porta série desactivada.
bit 6
RX9: Recepção com 9 bits. 1 = Activa a recepção a 9 bits. 0 = Desactiva a recepção a 9 bits.
bit 5
SREN: Activa recepção única. Modo Assíncrono: Dont´t care. Modo Síncrono - master: 1 = Activa recepção única. 0 = Desactiva recepção única. NOTA: Este bit é apagado, após uma recepção completa. Modo Síncrono - slave: Dont´t care.
bit 4
CREN: Activa a recepção contínua. Modo Assíncrono: 1 = Activa recepção contínua. 0 = Desactiva recepção contínua. Modo Síncrono: 1 = Activa recepção contínua, até bit CREN activo ser desactivado (CREN supra sucede SREN). 0 = Desactiva recepção contínua.
bit 3
ADDEN: Activa a detecção de endereço. Modo Assíncrono 9-bit (RX9 = 1): 1 = Activa detecção de endereço, activa interrupção e carga do buffer de recepção, quando RSR<8> activo. 0 = Desactiva detecção de endereço, todos os bytes são recebidos, e o nono bit pode ser usado como bit de paridade.
bit 2
FERR: Indicação de erro de frame (leitura apenas). 1 = Indicação de framing error. NOTA: Pode ser actualizado lendo o registo RCREG e efectuando a recepção do próximo byte válido). 0 = Não ocorreu framing error.
bit 1
OERR: Indicação de erro do bit overrun (leitura apenas). 1 = Ocorreu um erro de overrun (reposição a 0 por reposição a zero de CREN). 0 = Não ocorreu erro de overrun.
bit 0
RX9D: Nono bit, na recepção de dados (usado para paridade).
132
TP8 - USART do PIC
4
Trabalho a realizar 1. Implementar um programa em assembly que permita a transmissão de 1 carácter, para o programa terminal do computador anfitrião (host computer terminal). 2. Implementar um programa em assembly que permita a recepção de 1 carácter, e posterior transmissão (através da rotina criada anteriormente) para o host computer terminal. 3. Implementar um programa em assembly que permita o envio de um array de caracteres, para o host computer terminal. Inicialmente o programa deve enviar para o terminal a string "Digite -> (p,i,e,x)?", e consoante o carácter seleccionado (premido), será enviada para o terminal a string correspondente: (a) Quando recebido o carácter ‘p’ é enviada a mensagem "PIC - Ola, Mundo"; (b) Se recebido o carácter ‘i’ ou ‘e’ serão enviadas as strings respectivas ás mensagens ora em Inglês ora em Espanhol. (c) Quando recebido o carácter ‘x’, será enviada a mensagem "PIC - BYE BYE user". No entanto se um outro carácter for recebido, deverá ser enviada para o terminal a mensagem seguinte "Caracter Invalido".
Figura 37: Ligação série entre o PIC e o Computador
•
Elementos de Apoio í Manual teórico da disciplina. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 10. - Addressable Universal synchronous Asyncronous Receiver Transmiter (USART), página 95. í DataSheet PIC16F876(DS30292C) Microchip, capítulo 13 - Instrution Set Summary, página 135.
133
Guia prático sobre microcontroladores PIC
5 5.1
Implementação em Assembly do PIC Ponto 1
; Trabalho nº 8p1 ; Comunicação Série (USART) ; ; Objectivos: ; ; - Compreensão dos passos de programação da USART, para recepção e transmissão ; - Elaboração de rotinas para transmissão e recepção de um caracter. ; - Elaboração de uma rotina para transmissão de um array de caracteres (string ; ; ;******************************************************************** ; * ; Nome ficheiro: trab8.asm * ; Data: 1/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2005 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.LKR * ; * ;******************************************************************** list radix
p=16f876 decimal
; list directive to define ; processor
#include "p16f876.inc"
; processor specific variable ; definitions errorlevel -302 ; Turn off banking message ; known tested (good) code ;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RA0 EQU 0 RA1 EQU 1 RA2 EQU 2 RA3 EQU 3 RA4 EQU 4 RA5 EQU 5 ;--------------------------------------------------------------------
134
TP8 - USART do PIC ; Variáveis (REGISTOS DE USO GERAL) ;-------------------------------------------------------------------variaveis UDATA 0x20 ptr_pos RES 1 ptr_count RES 1 retrive_char RES 1 ;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG 0x00 ; Processor reset vector clrf PCLATH ; Ensure page bits are cleared goto main ; Go to beginning of program ;==================================================================== ORG 0x20 main
; Aqui começa o programa principal ; rotina de configuração
call
InitCfg
movlw call movlw call
’P’ tx_char ’ ’ tx_char
; ; envio do caracter "P"
goto
while_1
; loop infinito
while_1
; envio de 1 espaço
;****************************************************************** ;************************** ROTINAS ******************************* ;****************************************************************** ;****************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O, USART ; ; ; ; ; ; Notas: ; ;===================================================================; InitCfg ;----------------- Config USART ------------------------------------; Bank1 ; memoria do programa em Bank1 movlw 10 ; 115.2 Kbaud @ 20MHz
135
Guia prático sobre microcontroladores PIC movwf
SPBRG
clrf bsf bsf
TXSTA TXSTA,TXEN TXSTA,BRGH
Bank0 clrf bsf bsf
RCSTA RCSTA,SPEN RCSTA,CREN
; memoria do programa em Bank0 ; SPEN = 1 ; CREN = 1
;----------------- I/O Config --------------------------------------; Bank1 bcf TRISC,RC6 ; RC6 = TX output Bank0 clrf ptr_pos clrf ptr_count clrf retrive_char return ;===================================================================; ; Transmit Char = tx_char ; ; Input: W(reg) - Character ASCII a transmitir ; ; Output: não devolve nada ; ; ; ; Resumo: ; ; A rotina tx_char, aguarda que a FLAG TXIF de PIR1 seja 1, ; ; sinalizando assim a autorização de envio de um char através de ; ; TXREG. ; ; Protótipo em Linguagem C ; ; void tx_char(char c) ; ;===================================================================; tx_char btfss goto movwf
PIR1,TXIF $-1 TXREG
return END
136
; while( TXIF == 0) {} ; ;
TP8 - USART do PIC 5.2
Ponto 2
; Trabalho nº 8 ; pergunta 2 ; Comunicação Série (USART) ; ; Objectivos: ; ; - Compreensão dos passos de programação da USART, para recepção e transmissão ; - Elaboração de rotinas para transmissão e recepção de um caracter. ; - Elaboração de uma rotina para transmissão de um array de caracteres (string ; ; ;******************************************************************** ; * ; Nome ficheiro: trab8.asm * ; Data: 1/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2005 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.LKR * ; * ;******************************************************************** list radix
p=16f876 decimal
; list directive to define ; processor
#include "p16f876.inc"
; processor specific variable ; definitions errorlevel -302 ; Turn off banking message ; known tested (good) code ;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RA0 EQU 0 RA1 EQU 1 RA2 EQU 2 RA3 EQU 3 RA4 EQU 4 RA5 EQU 5 ;-------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) ;-------------------------------------------------------------------variaveis UDATA 0x20
137
Guia prático sobre microcontroladores PIC ptr_pos ptr_count retrive_char
RES RES RES
1 1 1
;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG 0x00 ; Processor reset vector clrf PCLATH ; Ensure page bits are cleared goto main ; Go to beginning of program ;==================================================================== ORG 0x20 main
; Aqui começa o programa principal ; rotina de configuração
call
InitCfg
call call movlw call
rx_char tx_char ’ ’ tx_char
; recepção de 1 caracter ; envio do caracter recebido
goto
while_1
; loop infinito
while_1
; envio de 1 espaço
;****************************************************************** ;************************** ROTINAS ******************************* ;****************************************************************** ;****************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O, USART ; ; ; ; ; ; Notas: ; ;===================================================================; InitCfg ;----------------- Config USART ------------------------------------; Bank1 ; memoria do programa em Bank1 movlw 10 ; 115.2 Kbaud @ 20MHz movwf SPBRG clrf
TXSTA
138
TP8 - USART do PIC bsf bsf
TXSTA,TXEN TXSTA,BRGH
Bank0 clrf bsf bsf
RCSTA RCSTA,SPEN RCSTA,CREN
; memoria do programa em Bank0 ; SPEN = 1 ; CREN = 1
;----------------- I/O Config --------------------------------------; Bank1 bcf TRISC,RC6 ; RC6 = TX output Bank0 clrf ptr_pos clrf ptr_count clrf retrive_char return ;===================================================================; ; Transmit Char = tx_char ; ; Input: W(reg) - Character ASCII a transmitir ; ; Output: não devolve nada ; ; ; ; Resumo: ; ; A rotina tx_char, aguarda que a FLAG TXIF de PIR1 seja 1, ; ; sinalizando assim a autorização de envio de um char através de ; ; TXREG. ; ; Protótipo em Linguagem C ; ; void tx_char(char c) ; ;===================================================================; tx_char btfss goto movwf
PIR1,TXIF $-1 TXREG
; while( TXIF == 0) {} ; ;
return ;===================================================================; ; Receive Char = rx_char ; ; Input: não têm parâmetro de entrada ; ; Output: W(reg) - Character ASCII recebido através da USART ; ; ; ; Resumo: ; ; A rotina rx_char, aguarda que a FLAG RCIF de PIR1 seja 1, ; ; sinalizando assim a chegada de um char ao registo RCREG. ; ; Protótipo em Linguagem C ; ; char rx_char(void) ; ;===================================================================; rx_char btfss goto movfw
PIR1,RCIF $-1 RCREG
return END
139
; while( RCIF == 0) {}
Guia prático sobre microcontroladores PIC 5.3
Ponto 3
; Trabalho nº 8 pergunta 3 ; Comunicação Série (USART) ; ; Objectivos: ; ; - Compreensão dos passos de programação da USART, para recepção e transmissão ; - Elaboração de rotinas para transmissão e recepção de um caracter. ; - Elaboração de uma rotina para transmissão de um array de caracteres (string ; ; ;******************************************************************** ; * ; Nome ficheiro: trab8.asm * ; Data: 1/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2005 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.LKR * ; * ;******************************************************************** list radix
p=16f876 decimal
; list directive to define ; processor
#include "p16f876.inc"
; processor specific variable ; definitions errorlevel -302 ; Turn off banking message ; known tested (good) code ;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RA0 EQU 0 RA1 EQU 1 RA2 EQU 2 RA3 EQU 3 RA4 EQU 4 RA5 EQU 5 ;-------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) ;-------------------------------------------------------------------variaveis UDATA 0x20
140
TP8 - USART do PIC ptr_pos ptr_count retrive_char
RES RES RES
1 1 1
;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG 0x00 ; Processor reset vector clrf PCLATH ; Ensure page bits are cleared goto main ; Go to beginning of program ;==================================================================== ORG 0x20 stan_table ;table for standard code addwf PCL,f ; "XXXXXXXXXXXXXXXXXXXX" ; ptr: dt "Digite -> (p,i,e,x)?" ;0 dt "PIC - Ola, Mundo " ;20 dt "PIC - Hola, Mundo " ;40 dt "PIC - Hello, World " ;60 dt "Caracter Invalido " ;80 dt "PIC - BYE BYE user " ;100 main
; Aqui começa o programa principal call
InitCfg
movlw movwf call
0 ptr_pos ptr_string
call movwf sublw btfsc goto movfw sublw btfsc goto movfw sublw btfsc goto movfw sublw btfsc goto
rx_char retrive_char ’p’ STATUS,Z PORTUGUES retrive_char ’e’ STATUS,Z ESPANHOL retrive_char ’i’ STATUS,Z INGLES retrive_char ’x’ STATUS,Z EXIT
while_1
141
Guia prático sobre microcontroladores PIC movlw movwf call goto
80 ptr_pos ptr_string while_1
movlw movwf call goto
20 ptr_pos ptr_string while_1
movlw movwf call goto
40 ptr_pos ptr_string while_1
movlw movwf call goto
60 ptr_pos ptr_string while_1
movlw movwf call goto
100 ptr_pos ptr_string SAIDA
PORTUGUES
ESPANHOL
INGLES
EXIT
;****************************************************************** ;************************** ROTINAS ******************************* ;****************************************************************** ;****************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O, USART ; ; ; ; ; ; Notas: ; ;===================================================================; InitCfg ;----------------- Config USART ------------------------------------; Bank1 ; memoria do programa em Bank1 movlw 10 ; 115.2 Kbaud @ 20MHz movwf SPBRG clrf bsf bsf
TXSTA TXSTA,TXEN TXSTA,BRGH
Bank0 clrf bsf bsf
RCSTA RCSTA,SPEN RCSTA,CREN
; memoria do programa em Bank0 ; SPEN = 1 ; CREN = 1
;----------------- I/O Config --------------------------------------; Bank1 bcf TRISC,RC6 ; RC6 = TX output Bank0 clrf ptr_pos clrf ptr_count clrf retrive_char return ;===================================================================; ; Transmit Char = tx_char ; ; Input: W(reg) - Character ASCII a transmitir ; ; Output: não devolve nada ; ; ;
142
TP8 - USART do PIC ; Resumo: ; ; A rotina tx_char, aguarda que a FLAG TXIF de PIR1 seja 1, ; ; sinalizando assim a autorização de envio de um char através de ; ; TXREG. ; ; Protótipo em Linguagem C ; ; void tx_char(char c) ; ;===================================================================; tx_char btfss goto movwf
PIR1,TXIF $-1 TXREG
; while( TXIF == 0) {} ; ;
return ;===================================================================; ; Receive Char = rx_char ; ; Input: não têm parâmetro de entrada ; ; Output: W(reg) - Character ASCII recebido através da USART ; ; ; ; Resumo: ; ; A rotina rx_char, aguarda que a FLAG RCIF de PIR1 seja 1, ; ; sinalizando assim a chegada de um char ao registo RCREG. ; ; Protótipo em Linguagem C ; ; char rx_char(void) ; ;===================================================================; rx_char btfss goto movfw
PIR1,RCIF $-1 RCREG
; while( RCIF == 0) {}
return ;===================================================================; ; print_string - prt_string ; ; Input: prt_pos - localização do caracter na tabela ; ; Output: não têm parametro de saída ; ; ; ; Resumo: ; ; Esta rotina imprime no ecra 20 caracteres, posicionadas na ’dt’ ; ; (tabela de dados) através do parametro ’prt_pos’. ; ; ; ; Protótipo em Linguagem C ; ; void prt_string(unsigned char prt_pos) ; ;===================================================================; ptr_string movlw movwf
20 ptr_count
; print 20 character / line
movlw movwf movf call call incf decfsz goto
HIGH stan_table PCLATH ptr_pos,w ; character table location stan_table ; retrieve 1 character tx_char ; send character to USART ptr_pos,f ; get next character to send ptr_count,f ; move pointer to next char prt_next_char
prt_next_char
movlw ’\r’ call tx_char movlw ’\n’ call tx_char return SAIDA END
143
Guia prático sobre microcontroladores PIC
NOTAS:
144
TP9 - Conversor A/D do PIC
1
Tema a desenvolver
Duração
Conversão Analógia -> Digital (ADC)
4 aulas
Resumo
Conversão A/D de valores de tensão (analógicos) provenientes de diferentes dispositivos. Interface através de sensor infravermelhos e potenciómetro com visualização de resultados em displays de 7 segmentos ou através do PC (terminal série).
2
Objectivos • Introdução ao estudo do conversor A/D (ADC) do PIC. • Implementação de um voltímetro digital básico. • Medição de distâncias através de um sensor de infravermelhos.
3
Descrição
No processamento de sinais-analógicos há, muitas vezes, vantagem em os converter para sinais digitais, de modo a que possam se processados por um microprocessador. Os elemento que efectua a conversão de um sinal analógico num digital (um valor numa determinada voltagem) é designado por "conversor analógico digital"’ ADC. O PIC16F876 dispõe de uma ADC de 10 bits, o que significa que o resultado pode ser representado com uma resolução de 1/1024 gama máxima. É possível distinguir valores com cerca de 5mV de resolução aproximadamente (5/1024 = 0.004883), supondo que a gama máxima de valores a medir é de 5V, ou seja toda a gama entre 0V..5V.
3.1
Entrada Analógica
No PIC16F876, podemos seleccionar como entrada analógica, por programação 1 dos 5 canais disponíveis (entradas RA0 - RA5, excepto RA4). O registo ADCON1 configura as linhas RA0 - RA5 (execpção RA4) do PIC como entradas analógicas/digitais ou referência; a entrada seleccionada deve
145
Guia prático sobre microcontroladores PIC ser programada como entrada afectando o bit correspondente no registo TRISA. Mais detalhes ver configuração de um porto com entradas analógicas, página 16. À ligação da entrada analógica com o conversor A/D, dá-se o nome de canal (channel), a selecção do canal a ser activado é feita pelo registo ADCON0 (bits CHS2-CHS0), ver página 149.
Figura 38: ADC, entradas analógicas
3.2
Resultado da conversão A/D
O par de registos ADRESH e ADRESL de 8 bits cada, forma o local onde são colocados os 10 bits do resultado da conversão, estes registos formam assim em conjunto um registo de 16 bits. A ADC, implementa duas formas no modo como formata o resultado de 10 bits nos registos ADRESH e ADRESL, justificado este ora à esquerda ou à direita (restantes bits extra são carregados a ’0’), ver figura 39. A selecção do formato é feita pelo bit ADFM do registro ADCON1, os bits , .
Figura 39: Formato do resultado de 10 bits
146
TP9 - Conversor A/D do PIC 3.3
Mecanismo de aquisição da ADC
O condensador de amostragem (CHOLD) do módulo conversor A/D, é carregado pela tensão aplicada à entrada analógica. A tensão de CHOLD é convertida para valores digitais através do conversor A/D. Uma vez que o condensador não carrega instantaneamente, é necessário aguardar um certo tempo, designado por tempo de HOLD, após a selecção da entrada analógica pretendida nos bits CHS0-3 do ADCON0 (ver página 149). Uma vez que este tempo não é implementado por hardware, é da responsabilidade do programador implementar no programa um tempo de espera de aproximadamente 20µs, entre a selecção da entrada analógica e o inicio da conversão A/D. Durante este tempo, o CHOLD está desligado da entrada analógica. A conversão A/D é iniciada quando o bit GO do registo ADCON0 é activado a ‘1’. Quando a conversão acaba o bit GO é reposto a ‘0’ por hardware. Existem duas maneiras de detectar o fim de conversão da ADC, a primeira é através de polling ao bit GO até este ser ‘0’, a segunda mais elegante, é através de uma interrupção global. No caso de usar interrupções, o bit ADIE do registo PIE, assim como o bit do GIE do registo INTCON, devem estar activos a ‘1’. Quando o fim de conversão for detectado, o bit ADIF do registo PIR1 é activo ‘1’ e a interrupção global ocorre. A figura 147 mostra o circuito no qual o condensador CHOLD é carregado por VA. CHOLD é carregado quando o interruptor (SS) é fechado. O díodo foi colocado por protecção no sentido de evitar situações de tensão superiores a VDD ou inferiores a VSS na entrada analógica.
Figura 40: Mecanismo de aquisição da ADC
• Legenda: í í í í
CHOLD: Condensador de amostragem / retenção ( 120pF ) RSS: Resistência de amostragem ( cerca de 7K-ohm a VDD=5V ) SS: Interruptor RIC: Resistência de ligação ( =<1K-ohm )
147
Guia prático sobre microcontroladores PIC í í í í
3.4
CPIN: Condensador de entrada ( 5pF ) ANx: Entrada Analógica RS: Impedância da entrada analógica ( =<10K-ohm ) VA: Fonte de tensão analógica
Etapas na programação da ADC (polling)
1. Configuração do conversor A/D ( Processo inicial) • Configuração das entradas analógicas / tensão de referência / I/0 digital ADCON1/PCFG0-3. • Selecção do clock de conversão da ADC, ADCON0/ADCS0-1 • Ligar o conversor A/D, ADCON0/ADON 2. Configuração do canal de entrada • Selecção do canal de entrada, ADCON0/CHS0-2 3. Tempo guarda de carga do condensador CHOLD • Aguardar até o CHOLD esteja completamente carregado, aprox. 20µs 4. Início da conversão • Activar o bit GO, ADCON0/GO = ‘1’ 5. Aguardar o fim de conversão da ADC • Fazer polling ao bit GO até que este seja ‘0’ 6. Leitura do resultado da conversão A/D • Ler o resultado no par de registos, ADRESH,ADRESL 7. Para a próxima conversão, ir para item 1 ou 2 como desejado
148
TP9 - Conversor A/D do PIC 3.5
Registo ADCON0
bit 7-6
ADCS1,ADCS0: Bits de selecção do clock do conversor A/D. 00 = FOSC/2. 01 = FOSC/8. 10 = FOSC/32. 11 = FRC (clock derivado do oscilador interno da ADC).
bit 5-3
CH2: Bits de selecção do canal analógico . 000 = canal 0, (RA0/AN0). 001 = canal 1, (RA1/AN1). 010 = canal 2, (RA2/AN2). 011 = canal 3, (RA4/AN3). 100 = canal 4, (RA5/AN4).
bit 2
GO/DON E: Bit de estado da conversão A/D. 1 = Conversão A/D a decorrer ( activar a ’1’ inicia a conversão A/D). 0 = conversão A/D a parada ( este bit é automaticamente reset pelo PIC quando a conversão
A/D é completada).
bit 1
Não Implementado: leitura a ’0’.
bit 0
ADON: Conversor A/D ligado. 1 = Conversor A/D ligado e em actividade. 0 = Conversor A/D desligado, não consome corrente.
149
Guia prático sobre microcontroladores PIC 3.6
Registo ADCON1
bit 7
ADFM: Selecção do formato da conversão A/D. 0 = Justificado à direita. 6 bits mais significativos do ADRESH colocados a ‘0’. 1 = Justificado à esquerda. 6 bits menos significativos do ADRESL colocados a ‘0’.
bit 6
ADCS2: Bit de selecção do clock de conversão. ADCON1 0 0 0 0 1 1 1 1
ADCON0 00 01 10 11 00 01 10 11
Clock de conversão Fosc/2 Fosc/8 Fosc/32 Frc (clock derivado do oscilador RC, interno da ADC) Fosc/4 Fosc/16 Fosc/64 Frc (clock derivado do oscilador RC, interno da ADC)
bit 5-4
Não Implementado: leitura a ’0’.
bit 3-0
PCFG3:PCFG0: Bits de controlo das entradas analógicas do PIC. PCFG <3:0> 0000 0001 0010 0011 0100 0101 011x 1000 1001 1010 1011 1100 1101 1110 1111
RA5
RA3
RA2
RA1
RA0
A A D D D D D A A A A D D D D
A Vref+ A Vref+ A Vref+ D Vref+ A Vref+ Vref+ Vref+ Vref+ D Vref+
A A A A D A D VrefA A VrefVrefVrefD Vref-
A A A A A A D A A A A A A D D
A A A A A A D A A A A A A A A
A = entrada analógica, D = entrada ou saída, digital, Vref± = tensão de referência
150
TP9 - Conversor A/D do PIC
4
Trabalho a realizar 1. Construção de um voltímetro digital simples. Este voltímetro faz a leitura de uma tensão eléctrica entre 0V e 5V apresentando o resultado da conversão A/D, nos displays de 7 segmentos. O valor convertido é afixado com um casa decimal (0.0 a 5.0V). De modo a implementar esta funcionalidade, deve-se programar a ADC com os seguintes parâmetros: entrada analógica RA0, selecção do clock do conversor A/D = FOSC/32, resolução de 8 bits na saída. NOTA: Uma vez que a escala de valores retornados da ADC é [0..255], deve implementar uma mudança de escala para valores entre [0..50]. Implementação de uma rotina de hexadecimal + decimal, de modo a poder afixar nos displays de 7 segmentos o valor convertido.
Figura 41: Diagrama do circuito do voltímetro digital, visualização com displays 7 segmentos 2. Finda a parte 1 do trabalho prático, o passo seguinte é alterar o programa anterior, de modo a que seja possível o envio dos valores de tensão através da porta série, para o PC.
Figura 42: Diagrama do circuito do voltímetro digital, visualização terminal série
151
Guia prático sobre microcontroladores PIC 3. Neste ponto do trabalho, pretende-se medir distâncias com o auxílio a um sensor de infravermelhos, com visualização da distância nos displays de 7 segmentos. O sistema de medição deve efectuar medições entre [10..40cm] com uma resolução de 1 cm. Fora desta gama deve indicar, através das mensagens, OFF e End que se encontra entre 0..10cm e entre 40..∞, respectivamente. Sugestão: Implementar uma rotina de cálculo da distancia, tendo em conta os valores de calibração do sensor fornecidos. NOTA: Os valores de calibração do sensor estão disponíveis para consulta no site da disciplina.
152
TP9 - Conversor A/D do PIC
5 5.1
Implementação em Assembly do PIC Ponto 1
; Trabalho nº 9 PARTE_I ; Voltimetro digital ; ; Resumo: ; Voltimetro digital 0..5 Volts ; visualização através dos displays de 7 segmentos ; ;******************************************************************** ; * ; Nome ficheiro: trab9Volt.asm * ; Data: 1/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2005 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.INC * ; * ;******************************************************************** list radix
p=16f876 decimal
; list directive to define ; processor
#include "p16f876.inc"
; ; ; ;
errorlevel -302
processor specific variable definitions Turn off banking message known tested (good) code
;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RA0 RA1 RA2 RA3 RA4 RA5
EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5
TMR0_HW_VAL1
EQU
255
; 25us aproximadamente
153
Guia prático sobre microcontroladores PIC TMR0_HW_VAL2 ANALOG_CHANNEL N_SHIFTS
EQU EQU EQU
0 0 5
; 6ms aproximadamente ; Analog Channel 0(AN0)
;-------------------------------------------------------------------;Displays de 7 segementos -|gfedcba-| ;-------------------------------------------------------------------seg7_0 EQU b’01111110’ ; Valor 0 seg7_1 EQU b’00001100’ ; Valor 1 seg7_2 EQU b’10110110’ ; Valor 2 seg7_3 EQU b’10011110’ ; Valor 3 seg7_4 EQU b’11001100’ ; Valor 4 seg7_5 EQU b’11011010’ ; Valor 5 seg7_6 EQU b’11111000’ ; Valor 6 seg7_7 EQU b’00001110’ ; Valor 7 seg7_8 EQU b’11111110’ ; Valor 8 seg7_9 EQU b’11001110’ ; Valor 9 seg7_A EQU b’11101110’ ; Valor A seg7_B EQU b’11111000’ ; Valor B seg7_C EQU b’01110010’ ; Valor C seg7_D EQU b’10111100’ ; Valor D seg7_E EQU b’11110010’ ; Valor E seg7_F EQU b’11100010’ ; Valor F seg7_n EQU b’10101000’ ; Valor n seg7_null EQU b’00000000’ ; Valor Null ;---------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) ;---------------------------------------------------------------------variaveis UDATA 0x20 seg70 RES 1 ; Valor 0 endereço seg71 RES 1 ; Valor 1 endereço seg72 RES 1 ; Valor 2 endereço seg73 RES 1 ; Valor 3 endereço seg74 RES 1 ; Valor 4 endereço seg75 RES 1 ; Valor 5 endereço seg76 RES 1 ; Valor 6 endereço seg77 RES 1 ; Valor 7 endereço seg78 RES 1 ; Valor 8 endereço seg79 RES 1 ; Valor 9 endereço seg7A RES 1 ; Valor A endereço seg7B RES 1 ; Valor B endereço seg7C RES 1 ; Valor C endereço seg7D RES 1 ; Valor D endereço seg7E RES 1 ; Valor E endereço seg7F RES 1 ; Valor F endereço seg7n RES 1 ; Valor n endereço seg7null RES 1 ; Valor null endereço ;-------------------------------------------------------------------aux RES 1 valor_tensao RES 1 dig_high RES 1 dig_low RES 1 divdo RES 1 disp_7seg RES 1 bcd_in RES 1 i RES 1 j RES 1 value_xg_high RES 1 value_xg_low RES 1 value_low RES 1 value_high RES 1 buffer_32
RES
32
;-------------------------------------------------------------------; Macros to select the register Banks ;--------------------------------------------------------------------
154
TP9 - Conversor A/D do PIC Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG clrf goto
0x00 PCLATH main
; Processor reset vector ; Ensure page bits are cleared ; Go to beginning of program
;==================================================================== ORG 0x20 main ;Aqui começa o programa principal call InitCfg while_1 movlw buffer_32 ; inicialize pointer call write_buff_32; void write_buffer(char* buff) movlw buffer_32 ; char media_32(char* buff) call media_32 ; call xg_scale ; call h2d ;
if_main
movwf
valor_tensao ;
btfss goto bcf movlw movwf
INTCON,T0IF $-1 INTCON,T0IF TMR0_HW_VAL2 TMR0
btfsc goto movfw andlw goto
disp_7seg,0 else_main valor_tensao 0x0F display_main
else_main
display_main
swapf andlw btfsc goto call incf andlw movwf goto
; while(TOIF == 0) {} ; ; T0IF = 0; ; ; Set Hardware timer0 Value
; ; ; ; ; ; valor_tensao,w 0x0F ; STATUS,Z ; $+3 ; display ; disp_7seg,w ; 0x01 ; disp_7seg ; while_1 ;
if(disp_7seg == 0) { w = valor_tensao w = w & 0x0F } else
if (STATUS,Z==1) display(bcd_in,disp_7seg); disp_7seg = (++disp_7seg) & 0x01;
;****************************************************************** ;************************** ROTINAS ******************************* ;****************************************************************** ;****************************************************************** ;===================================================================; ; InitCfg ;
155
Guia prático sobre microcontroladores PIC ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O, Timer0, ADC. ; ; ; ; ; ; Notas: ; ;===================================================================; InitCfg ;--------------- Analog 2 Digital - Config -------------------------; Bank1 clrf bsf bsf bsf bcf
ADCON1 ADCON1,PCFG3 ADCON1,PCFG2 ADCON1,PCFG1 ADCON1,PCFG0
; DATA memory (RAM) Bank1
Bank0 clrf bsf bcf bsf
ADCON0 ADCON0,ADCS1 ; ADCON0,ADCS0 ; FOSC / 32 ADCON0,ADON ; ADC ON
; ; ; ; ; ;
PCFG3 = 1 PCFG2 = 1 PCFG1 = 1 PCFG0 = 0 RA0 = input analógico DATA memory (RAM) Bank0
;---------------- I/O - Config -------------------------------------; Bank1 movlw movwf movlw movwf
b’11110001’ TRISA b’00000001’ TRISB
; ; ; ; ;
memoria do programa em Bank1 RA[3:1] outputs RA[7:4 & 1] inputs RB[7:1] outputs RB[1] input
;----------------- TRM0 - Config ------------------------------------; clrf bsf bsf bsf bcf Bank0 movlw movwf
OPTION_REG ; clear OPTION_REG OPTION_REG,INTEDG ; INTEDG = 1 OPTION_REG,PS2 ; OPTION_REG,PS1 ; TMR0 Rate OPTION_REG,PS0 ; 1:128 ; DATA memory (RAM) Bank0 TMR0_HW_VAL1 ; Set Hardware timer0 Value TMR0 ; Set TMR0
;----------------- OTHER - Config ----------------------------------; clrf PORTA ; clrf PORTB ; clrf disp_7seg ; clear registers ;-------------------------------------------------------------------; ; Inicialização dos registros associados aos displays 7seg ; ;-------------------------------------------------------------------; movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf
seg7_0 seg70 seg7_1 seg71 seg7_2 seg72 seg7_3 seg73 seg7_4 seg74 seg7_5 seg75 seg7_6 seg76 seg7_7 seg77 seg7_8 seg78 seg7_9 seg79
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
156
Set 7segment Save valor 0 Set 7segment Save valor 1 Set 7segment Save valor 2 Set 7segment Save valor 3 Set 7segment Save valor 4 Set 7segment Save valor 5 Set 7segment Save valor 6 Set 7segment Save valor 7 Set 7segment Save valor 8 Set 7segment Save valor 9
valor 0 valor 1 valor 2 valor 3 valor 4 valor 5 valor 6 valor 7 valor 8 valor 9
TP9 - Conversor A/D do PIC movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf
seg7_A seg7A seg7_B seg7B seg7_C seg7C seg7_D seg7D seg7_E seg7E seg7_F seg7F seg7_n seg7n seg7_null seg7null
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Set 7segment Save valor A Set 7segment Save valor B Set 7segment Save valor C Set 7segment Save valor D Set 7segment Save valor E Set 7segment Save valor F Set 7segment Save pattern Set 7segment Save pattern
valor A valor B valor C valor D valor E valor F pattern N N pattern NULL N
return ;===================================================================; ; Input: W(reg) - ponteito para o endereço de buffer_32 ; ; Output: - não têm parametro de saída ; ; Resumo: ; ; Recolhe 32 valores da ADC[0..255], escrevendo os mesmos em 32 ; ; posições consecutivas de memória RAM ; ; ; ; Protótipo em Linguagem C ; ; void write_buff_32(char* buffer_32) ; ;===================================================================; write_buff_32 movwf FSR ; initialize pointer write_again movlw ANALOG_CHANNEL ; w(reg) = analog_channel call analog2digital ; analog2digital(char W(reg)) movwf INDF ; write INDF register incf FSR,f ; inc pointer btfss FSR,5 ; all done? goto write_again ; no write again ; yes return return ;===================================================================; ; Input: W(reg) - Canal de entrada AN<X> em que X[0:7] ; ; Output: W(reg) - valor de saída convertido pela ADC ; ; (formato digital) escala (0..255) em que 0 = gnd ; ; e 255 = VREF+ = 5V ; ; Resumo: ; ; Devolve em W(reg) valor digital convertido pela ADC. ; ; ; ; Protótipo em Linguagem C ; ; char analog2digital(unsigned char canal_ADC) ; ;===================================================================; analog2digital andlw 0x07 ; movwf aux ; aux = 0x07 & w bcf STATUS,C ; rlf aux,f ; rlf aux,f ; rlf aux,f ; movlw 0xC7 ; andwf ADCON0,w ; iorwf aux,w ; movwf ADCON0 ; btfss goto bcf movlw movwf
INTCON,T0IF $-1 INTCON,T0IF TMR0_HW_VAL1 TMR0
; ; ; ; ;
bsf
ADCON0,GO
; início da conversão
157
while(TOIF == 0) {} T0IF = 0; Set Hardware timer0 Value Set TMR0
Guia prático sobre microcontroladores PIC btfsc goto movfw
ADCON0,GO $-1 ADRESH
return
; ; ; ; ;
;===================================================================; ; Input: W(reg) - ponteiro para o buffer ; ; Output: W(reg) - média aritmética das 32 amostras ; ; ; ; Resumo: ; ; Soma os 32 resultados de conversão da ADC, presentes no buffer de ; ; de 32 posições, devolvendo a sua média aritmética. ; ; ; ; Protótipo em Linguagem C ; ; char media_32(char* buffer_32) ; ;===================================================================; media_32 clrf value_low ; initialize register clrf value_high ; initialize register read_again
divide_again
movwf movfw call incf btfss goto
FSR INDF soma FSR,f FSR,5 read_again
; ; ; ; ; ; ; movlw N_SHIFTS ; movwf aux ; bcf STATUS,C ; rrf value_high,f ; rrf value_low,f ; decfsz aux,f ; goto divide_again ; movfw value_low ;
initialize pointer read INDF register to W(reg) soma(char W(reg)) inc pointer all done? no read again yes continue next - > Carry = flag = 0 msb_value_high = 0 all done? no divide again yes return (value_low in W)
return ;===================================================================; ; Input: W(reg) - valor de 8 bits a somar com os 8 bits menos ; ; significativos de value low ; ; Output: não têm parâmetro de saída ; ; Resumo: ; ; Soma o valor actual com o anterior se existir CARRY, incrementa ; ; o valor de value_high de uma unidade. ; ; ; ; Protótipo em Linguagem C ; ; void soma(unsigned char val_buffer_32) ; ;===================================================================; soma addwf value_low,f ; value_low + W(reg) btfsc STATUS,C ; exist CARRY? incf value_high,f ; yes, inc value_high return ; no, return ;===================================================================; ; Input: W(reg) - valor hex na escala de (0..255) ; ; Output: W(reg) - valor hex na escala de (0..50) ; ; Resumo: ; ; Mudança de escala [0..255] -> [0..50] ; ; ; ; Protótipo em Linguagem C ; ; char xg_scale(unsigned char val) ; ;===================================================================; xg_scale movwf value_xg_low ; movlw 0x32 ; movwf i ; i = 0x32 movfw value_xg_low ; clrf value_xg_high ;
158
TP9 - Conversor A/D do PIC add_again
addwf btfsc incf decfsz goto movfw
value_xg_low,w ; STATUS,C ; value_xg_high,f; i,f ; add_again ; value_xg_high ;
return
;
w = w + value_xg_low exist CARRY? yes, inc value_xg_high no, decrement i if ( i != 0 ) if ( i == 0 )
;===================================================================; ; Input: W(reg) - valor de 8 bits em hexadecimal 0x?? ; ; Output: W(reg) - valor de 8 bits equivalente em decimal ; ; Resumo: ; ; ; ; Equivalente em Linguagem C ; ; char h2d (char value_low) ; ; { ; ; return((value_low/10 << 4) + (value_low % 10); ; ; } ; ;===================================================================; h2d movwf divdo ; temp = w = value_low ; clrf j ; j = 0; movlw 10 ; while( divdo >= 10) next_sub subwf divdo,f ; se o subtraendo >= ao subtractor => CY ; se o subtraendo < ao subtractor => CY btfss STATUS,C ; divdo -=divdo; goto fwd ; } incf j,f ; goto next_sub ; fwd addwf divdo,f ; swapf j,w addwf
divdo,w
return
; w = temp + count w => valor ; decimal correspondente a ; value_low(hex)
;===================================================================; ; Input: W(reg) - valor BCD de entrada ; ; Input: DISP_7SEG - seleção do display a ser refrescado ; ; Output: não têm parâmetro de saída ; ; ; ; Resumo: Subroutina de Controlo dos displays ; ; Protótipo em Linguagem C ; ; void display(unsigned char bcd_in, unsigned char disp_7seg) ; ;===================================================================; display movwf bcd_in ; movf PORTA,w ; w = PORTA andlw 0xF1 ; movwf aux ; aux = w & 0xf1 disp_0
disp_1
disp_2
movfw sublw btfss goto movfw iorlw goto
disp_7seg 0x00 STATUS,Z disp_1 aux 0x08 break
; ; ; ; ; ; ;
switch(disp_7seg)
movfw sublw btfss goto movfw iorlw goto movfw iorlw
disp_7seg 0x01 STATUS,Z disp_2 aux 0x04 break aux 0x02
; ; ; ; ; ; ; ; ;
switch(dis_7seg)
159
case_0 w = aux | 0x08 break
case_1 w = aux | 0x04 break case_2 w = aux | 0x02
Guia prático sobre microcontroladores PIC
break
movwf PORTA call bcd_7seg
; escrita na porta ; bcd_7seg(bcd_in);
return ;===================================================================; ; Input: bcd_in - valor BCD de entrada ; ; Output: não têm parâmetro de saída ; ; ; ; Resumo: Subroutina => BCD to 7segment display, envia o valor ; ; passado em bcd_in para a PORTB ; ;===================================================================; bcd_7seg movlw seg70 ; Início da tabela de valores addwf bcd_in,w ; & do val a mostrar da tabela movwf FSR ; Set do endereço da tabela movf INDF,w ; leitura do valor de 7seg movwf PORTB ; envio do valor para o PORTB return END
; directive ’end of program’
160
TP9 - Conversor A/D do PIC 5.2
Ponto 2
; Trabalho nº 9 PARTE_II ; Voltimetro digital ; ; Resumo: ; Voltimetro digital 0..5 Volts ; visualização através da USART do PIC ; ;******************************************************************** ; * ; Nome ficheiro: trab9VoltUart.asm * ; Data: 1/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2005 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.INC * ; * ;******************************************************************** list radix
p=16f876 decimal
; list directive to define ; processor
#include "p16f876.inc"
; ; ; ;
errorlevel -302
processor specific variable definitions Turn off banking message known tested (good) code
;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RA0 RA1 RA2 RA3 RA4 RA5
EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5
TMR0_HW_VAL1 ANALOG_CHANNEL N_SHIFTS
EQU EQU EQU
255 0 5
; 25us aproximadamente ; Analog Channel 0(AN0) ;
161
Guia prático sobre microcontroladores PIC
;---------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) ;---------------------------------------------------------------------variaveis UDATA 0x20 aux RES 1 valor_tensao RES 1 dig_high RES 1 dig_low RES 1 divdo RES 1 i RES 1 j RES 1 value_xg_high RES 1 value_xg_low RES 1 value_low RES 1 value_high RES 1 prt_count RES 1 prt_pos RES 1 buffer_32
RES
32
;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG clrf goto
0x0000 PCLATH main
; Processor reset vector ; Ensure page bits are cleared ; Go to beginning of program
;==================================================================== ORG 0x0005 data_table ;table for strings addwf PCL,f ; "XXXXXXXXXXXXXXXXXXXX" ; ptr_string: dt "Valor U digite ’v’ ";posição - 0 dt " - Volts ";posição - 20 ; "XXXXXXXXXXXXXXXXXXXX" main
;Aqui começa o programa principal call
InitCfg
movlw call
0 prt_string
movlw call movlw
buffer_32 ; inicialize pointer write_buff_32; void write_buffer(char* buff) buffer_32 ; char media_32(char* buff)
; posição 0 da ’dt’
while_1
162
TP9 - Conversor A/D do PIC call call call
media_32 xg_scale itoa
; ; ;
call sublw btfss goto
rx_char ’v’ STATUS,Z $-3
; ; ; ;
movfw call
dig_high tx_char
; unidades de tensão ;
movlw call
’.’ tx_char
; ’.’ ;
movfw call
dig_low tx_char
; decimas de tensao ;
movlw call
20 prt_string
; posição 20 da ’dt’
goto
while_1
;******************************************************************** ;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTS I/O, Timer0, ADC, USART ; ; ; ; Retorna em Bank0 ; ; ; ;===================================================================; InitCfg ;----------------- Config USART ------------------------------------; Bank1 ; DATA memory (RAM) Bank1 movlw 10 ; 115.2 Kbaud @ 20MHz movwf SPBRG clrf bsf bsf
TXSTA TXSTA,TXEN TXSTA,BRGH
Bank0 clrf bsf bsf
RCSTA RCSTA,SPEN RCSTA,CREN
; DATA memory (RAM) Bank0 ; SPEN = 1 ; CREN = 1
;--------------- Analog 2 Digital - Config -------------------------; Bank1 clrf bsf bsf bsf bcf
; DATA memory (RAM) Bank1 ADCON1 ADCON1,PCFG3 ADCON1,PCFG2 ADCON1,PCFG1 ADCON1,PCFG0
; ; ; ; ; ;
PCFG3 = 1 PCFG2 = 1 PCFG1 = 1 PCFG0 = 0 RA0 = input analógico DATA memory (RAM) Bank0
Bank0 clrf ADCON0 bsf ADCON0,ADCS1 ; bcf ADCON0,ADCS0 ; FOSC / 32 bsf ADCON0,ADON ; ADC ON ;---------------- I/O - Config -------------------------------------; Bank1 movlw
b’00000001’
163
; memoria do programa em Bank1 ; RA[7:1] outputs
Guia prático sobre microcontroladores PIC movwf
TRISA
; RA[0]
input
;----------------- TRM0 - Config ------------------------------------; clrf bsf bsf bsf bcf Bank0 movlw movwf
OPTION_REG ; clear OPTION_REG OPTION_REG,INTEDG ; INTEDG = 1 OPTION_REG,PS2 ; OPTION_REG,PS1 ; TMR0 Rate OPTION_REG,PS0 ; 1:128 ; DATA memory (RAM) Bank0 TMR0_HW_VAL1 ; Set Hardware timer0 Value TMR0 ; Set TMR0
return ;===================================================================; ; Transmit Char = tx_char ; ; Input: W(reg) - Character ASCII a transmitir ; ; Output: não devolve nada ; ; ; ; Resumo: ; ; A rotina tx_char, aguarda que a FLAG TXIF de PIR1 seja 1, ; ; sinalizando assim a autorização de envio de um char através de ; ; TXREG. ; ; Protótipo em Linguagem C ; ; void tx_char(char c) ; ;===================================================================; tx_char btfss PIR1,TXIF ; while( TXIF == 0) {} goto $-1 ; movwf TXREG ; return ;===================================================================; ; Receive Char = rx_char ; ; Input: não têm parâmetro de entrada ; ; Output: W(reg) - Character ASCII recebido através da USART ; ; ; ; Resumo: ; ; A rotina rx_char, aguarda que a FLAG RCIF de PIR1 seja 1, ; ; sinalizando assim a chegada de um char ao registo RCREG. ; ; Protótipo em Linguagem C ; ; char rx_char(void) ; ;===================================================================; rx_char btfss PIR1,RCIF ; while( RCIF == 0) {} goto $-1 movfw RCREG return ;===================================================================; ; print_string - prt_string ; ; Input: prt_pos - localização do caracter na tabela ; ; Output: não têm parametro de saída ; ; ; ; Resumo: ; ; Esta rotina imprime no ecra 20 caracteres, posicionadas na ’dt’ ; ; (tabela de dados) através do parametro ’prt_pos’. ; ; ; ; Protótipo em Linguagem C ; ; void prt_string(unsigned char prt_pos) ; ;===================================================================; prt_string movwf prt_pos movlw 20 ; print 20 character / line movwf prt_count prt_next_char movlw HIGH data_table; initialize PCLATH reg
164
TP9 - Conversor A/D do PIC movwf
PCLATH
movfw call call incf decfsz goto
prt_pos data_table tx_char prt_pos,f prt_count,f prt_next_char
; ; ; ; ; ; ;
before using addwf PCL,f when returning from routine character table location retrieve 1 character send character to USART get next character to send move pointer to next char
movlw ’\r’ call tx_char movlw ’\n’ call tx_char return ;===================================================================; ; Input: W(reg) - ponteito para o endereço de buffer_32 ; ; Output: - não têm parametro de saída ; ; Resumo: ; ; Recolhe 32 valores da ADC[0..255], escrevendo os mesmos em 32 ; ; posições consecutivas de memória RAM ; ; ; ; Protótipo em Linguagem C ; ; void write_buff_32(char* buffer_32) ; ;===================================================================; write_buff_32 movwf FSR ; initialize pointer write_again movlw ANALOG_CHANNEL ; w(reg) = analog_channel call analog2digital ; analog2digital(char W(reg)) movwf INDF ; write INDF register incf FSR,f ; inc pointer btfss FSR,5 ; all done? goto write_again ; no write again ; yes return return ;===================================================================; ; Input: W(reg) - Canal de entrada AN<X> em que X[0:7] ; ; Output: W(reg) - valor de saída convertido pela ADC ; ; (formato digital) escala (0..255) em que 0 = gnd ; ; e 255 = VREF+ = 5V ; ; Resumo: ; ; Devolve em W(reg) valor digital convertido pela ADC. ; ; ; ; Protótipo em Linguagem C ; ; char analog2digital(unsigned char canal_ADC) ; ;===================================================================; analog2digital andlw 0x07 ; movwf aux ; aux = 0x07 & w bcf STATUS,C ; rlf aux,f ; rlf aux,f ; rlf aux,f ; movlw 0xC7 ; andwf ADCON0,w ; iorwf aux,w ; movwf ADCON0 ; btfss goto bcf movlw movwf
INTCON,T0IF $-1 INTCON,T0IF TMR0_HW_VAL1 TMR0
; ; ; ; ;
bsf btfsc goto movfw
ADCON0,GO ADCON0,GO $-1 ADRESH
; início da conversão ; ; ;
165
while(TOIF == 0) {} T0IF = 0; Set Hardware timer0 Value Set TMR0
Guia prático sobre microcontroladores PIC ; ;
return
;===================================================================; ; Input: W(reg) - ponteiro para o buffer ; ; Output: W(reg) - média aritmética das 32 amostras ; ; ; ; Resumo: ; ; Soma os 32 resultados de conversão da ADC, presentes no buffer de ; ; de 32 posições, devolvendo a sua média aritmética. ; ; ; ; Protótipo em Linguagem C ; ; char media_32(char* buffer_32) ; ;===================================================================; media_32 clrf value_low ; initialize register clrf value_high ; initialize register read_again
divide_again
movwf movfw call incf btfss goto
FSR INDF soma FSR,f FSR,5 read_again
; ; ; ; ; ; ; movlw N_SHIFTS ; movwf aux ; bcf STATUS,C ; rrf value_high,f ; rrf value_low,f ; decfsz aux,f ; goto divide_again ; movfw value_low ;
initialize pointer read INDF register to W(reg) soma(char W(reg)) inc pointer all done? no read again yes continue next - > Carry = flag = 0 msb_value_high = 0 all done? no divide again yes return (value_low in W)
return ;===================================================================; ; Input: W(reg) - valor de 8 bits a somar com os 8 bits menos ; ; significativos de value low ; ; Output: não têm parâmetro de saída ; ; Resumo: ; ; Soma o valor actual com o anterior se existir CARRY, incrementa ; ; o valor de value_high de uma unidade. ; ; ; ; Protótipo em Linguagem C ; ; void soma(unsigned char val_buffer_32) ; ;===================================================================; soma addwf value_low,f ; value_low + W(reg) btfsc STATUS,C ; exist CARRY? incf value_high,f ; yes, inc value_high return ; no, return ;===================================================================; ; Input: W(reg) - valor hex na escala de (0..255) ; ; Output: W(reg) - valor hex na escala de (0..50) ; ; Resumo: ; ; Mudança de escala [0..255] -> [0..50] ; ; ; ; Protótipo em Linguagem C ; ; char xg_scale(unsigned char val) ; ;===================================================================; xg_scale movwf value_xg_low ; movlw 0x32 ; movwf i ; i = 0x32 movfw value_xg_low ; clrf value_xg_high ; add_again addwf value_xg_low,w ; w = w + value_xg_low btfsc STATUS,C ; exist CARRY? incf value_xg_high,f; yes, inc value_xg_high
166
TP9 - Conversor A/D do PIC decfsz i,f goto add_again movfw value_xg_high
; no, decrement i ; if ( i != 0 ) ; if ( i == 0 )
return
;
;===================================================================; ; Input: W(reg) - valor de 8 bits em hexadecimal 0x?? ; ; Output: W(reg) - valor de 8 bits equivalente em decimal ; ; Resumo: ; ; ; ; Equivalente em Linguagem C ; ; char h2d (char value_low) ; ; { ; ; return((value_low/10 << 4) + (value_low % 10); ; ; } ; ;===================================================================; h2d movwf divdo ; temp = w = value_low ; clrf j ; j = 0; movlw 10 ; while( divdo >= 10) next_sub subwf divdo,f ; se o subtraendo >= ao subtractor => CY ; se o subtraendo < ao subtractor => CY btfss STATUS,C ; divdo -=divdo; goto fwd ; } incf j,f ; goto next_sub ; fwd addwf divdo,f ; swapf j,w addwf
divdo,w
return
; w = temp + count w => valor ; decimal correspondente a ; value_low(hex)
;===================================================================; ; Input: w = valor de entrada em decimal a converter ASCII ; ; Output: dig_high = unidades ; ; dig_low = decimas ; ; Resumo: ; ; Devolve o valor ascii das unidades e das decimas ; ; do valor em tensão ; ; Protótipo em Linguagem C ; ; char* itoa( char val) ; ;===================================================================; itoa call h2d ; movwf dig_low ; digito = w = val; movwf dig_high ; movlw 0x0f ; andwf dig_low,f ; movlw ’0’ ; addwf dig_low,f ; dig_low +=’0’; swapf dig_high,f ; movlw 0x0f ; andwf dig_high,f ; movlw ’0’ ; addwf dig_high,f ; return
;
END
; directive ’end of program’
167
Guia prático sobre microcontroladores PIC 5.3
Ponto 3
; Trabalho nº 9 PARTE III ; Medição de distancias com sensor IV - SHARP ; ; Resumo: ; Medição de distâncias com sensor valores entre [10...40] cm ; ;******************************************************************** ; * ; Nome ficheiro: trab9.asm * ; Data: 1/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2005 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.INC * ; * ;******************************************************************** list radix
p=16f876 decimal
; list directive to define ; processor
#include "p16f876.inc"
; ; ; ;
errorlevel -302
processor specific variable definitions Turn off banking message known tested (good) code
;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RA0 RA1 RA2 RA3 RA4 RA5
EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5
RB0 RB1 RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
ANALOG_CHANNEL TMR0_HW_VAL1 TMR0_HW_VAL2 N_SHIFTS
EQU EQU EQU EQU
0 255 0 5
; Analog Channel 0(AN0) ; 25us aproximadamente ; 6ms aproximadamen
;--------------------------------------------------------------------
168
TP9 - Conversor A/D do PIC ;Displays de 7 segementos -|gfedcba-| ;-------------------------------------------------------------------seg7_0 EQU b’01111110’ ; Valor 0 seg7_1 EQU b’00001100’ ; Valor 1 seg7_2 EQU b’10110110’ ; Valor 2 seg7_3 EQU b’10011110’ ; Valor 3 seg7_4 EQU b’11001100’ ; Valor 4 seg7_5 EQU b’11011010’ ; Valor 5 seg7_6 EQU b’11111000’ ; Valor 6 seg7_7 EQU b’00001110’ ; Valor 7 seg7_8 EQU b’11111110’ ; Valor 8 seg7_9 EQU b’11001110’ ; Valor 9 seg7_A EQU b’11101110’ ; Valor A seg7_B EQU b’11111000’ ; Valor B seg7_C EQU b’01110010’ ; Valor C seg7_D EQU b’10111100’ ; Valor D seg7_E EQU b’11110010’ ; Valor E seg7_F EQU b’11100010’ ; Valor F seg7_n EQU b’10101000’ ; Valor n seg7_null EQU b’00000000’ ; Valor Null ;---------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) ;---------------------------------------------------------------------variaveis UDATA 0x20 seg70 RES 1 ; Valor 0 endereço seg71 RES 1 ; Valor 1 endereço seg72 RES 1 ; Valor 2 endereço seg73 RES 1 ; Valor 3 endereço seg74 RES 1 ; Valor 4 endereço seg75 RES 1 ; Valor 5 endereço seg76 RES 1 ; Valor 6 endereço seg77 RES 1 ; Valor 7 endereço seg78 RES 1 ; Valor 8 endereço seg79 RES 1 ; Valor 9 endereço seg7A RES 1 ; Valor A endereço seg7B RES 1 ; Valor B endereço seg7C RES 1 ; Valor C endereço seg7D RES 1 ; Valor D endereço seg7E RES 1 ; Valor E endereço seg7F RES 1 ; Valor F endereço seg7n RES 1 ; Valor n endereço seg7null RES 1 ; Valor null endereço aux dig_high dig_low divdo disp_7seg bcd_in i j value_low value_high val_adc value_dist_hex value_decimal buffer_32
RES RES RES RES RES RES RES RES RES RES RES RES RES RES
1 1 1 1 1 1 1 1 1 1 1 1 1 32
;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf
; Macro to select data RAM Bank 1 STATUS,RP0
169
Guia prático sobre microcontroladores PIC bcf ENDM
STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG clrf goto
0x0000 PCLATH main
; Processor reset vector ; Ensure page bits are cleared ; Go to beginning of program
;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG 0x0005 adc_table ;table for adc values default val addwf PCL,f dt 126,116,108,100,94,88,83,79,75,71,67,63,61,58,56,54,51,5 main
;Aqui começa o programa principal call
InitCfg
movlw call movlw call call movwf
buffer_32 ; write_buff_32; buffer_32 ; media_32 ; calc_dist ; value_dist_hex
sublw btfsc goto
0x00 STATUS,Z OFF_SCALE
movfw sublw btfsc goto
value_dist_hex 0x32 STATUS,Z END_SCALE
movfw call movwf
value_dist_hex h2d value_decimal
andlw call swapf andlw call movlw call
0x0f ; bcd_in = unidades de cm prt_disp7seg value_decimal,w 0x0f ; bcd_in = dezenas de cm prt_disp7seg 0x11 ; bcd_in = null prt_disp7seg
goto
while_1
movlw call movlw call movlw call
0x0d prt_disp7seg 0x10 prt_disp7seg 0x0E prt_disp7seg
goto
while_1
while_1
END_SCALE
OFF_SCALE
170
inicialize pointer void write_buffer(char* buff) char media_32(char* buff) char calc_dist(char val_adc)
TP9 - Conversor A/D do PIC movlw call movlw call movlw call
0x0f prt_disp7seg 0x0f prt_disp7seg 0x00 prt_disp7seg
goto
while_1
;******************************************************************* ;************************** ROTINAS ******************************** ;******************************************************************* ;******************************************************************* ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O, Timer0, ADC, ; ; ; ; ; ; Notas: ; ;===================================================================; InitCfg ;--------------- Analog 2 Digital - Config -------------------------; Bank1 movlw movwf Bank0 movlw movwf
b’00001110’ ADCON1 b’10000001’ ADCON0
; DATA memory (RAM) Bank1 ; RA0 = input analógico ; DATA memory (RAM) Bank0 ; FOSC / 32
;---------------- I/O - Config -------------------------------------; Bank1 ; DATA memory (RAM) Bank1 movlw b’11110001’ ; RA[3:1] outputs movwf TRISA ; RA[7:4 & 0] inputs movlw b’00000001’ ; RB[7:1] outputs movwf TRISB ; RB[0] input ;----------------- TRM0 - Config ------------------------------------; clrf OPTION_REG ; clear OPTION_REG bsf OPTION_REG,INTEDG ; INTEDG = 1 bsf OPTION_REG,PS2 ; bsf OPTION_REG,PS1 ; TMR0 Rate bsf OPTION_REG,PS0 ; 1:256 Bank0 movlw movwf
; DATA memory (RAM) Bank0 TMR0_HW_VAL1 ; Set Hardware timer0 Value TMR0 ; Set TMR0
;----------------- OTHER - Config ----------------------------------; clrf PORTA ; clrf PORTB ; clrf disp_7seg ; clear registers ;-------------------------------------------------------------------; ; Inicialização dos registros associados aos displays 7seg ; ;-------------------------------------------------------------------; movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf
seg7_0 seg70 seg7_1 seg71 seg7_2 seg72 seg7_3 seg73 seg7_4 seg74
; ; ; ; ; ; ; ; ; ;
171
Set 7segment Save valor 0 Set 7segment Save valor 1 Set 7segment Save valor 2 Set 7segment Save valor 3 Set 7segment Save valor 4
valor 0 valor 1 valor 2 valor 3 valor 4
Guia prático sobre microcontroladores PIC movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf movlw movwf
seg7_5 seg75 seg7_6 seg76 seg7_7 seg77 seg7_8 seg78 seg7_9 seg79 seg7_A seg7A seg7_B seg7B seg7_C seg7C seg7_D seg7D seg7_E seg7E seg7_F seg7F seg7_n seg7n seg7_null seg7null
; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ;
Set 7segment Save valor 5 Set 7segment Save valor 6 Set 7segment Save valor 7 Set 7segment Save valor 8 Set 7segment Save valor 9 Set 7segment Save valor A Set 7segment Save valor B Set 7segment Save valor C Set 7segment Save valor D Set 7segment Save valor E Set 7segment Save valor F Set 7segment Save pattern Set 7segment Save pattern
valor 5 valor 6 valor 7 valor 8 valor 9 valor A valor B valor C valor D valor E valor F pattern N N pattern NULL N
return ;===================================================================; ; Input: W(reg) - ponteito para o endereço de buffer_32 ; ; Output: - não têm parametro de saída ; ; Resumo: ; ; Recolhe 32 valores da ADC[0..255], escrevendo os mesmos em 32 ; ; posições consecutivas de memória RAM ; ; ; ; Protótipo em Linguagem C ; ; void write_buff_32(char* buffer_32) ; ;===================================================================; write_buff_32 movwf FSR ; initialize pointer write_again movlw ANALOG_CHANNEL ; w(reg) = analog_channel call analog2digital ; analog2digital(char W(reg)) movwf INDF ; write INDF register incf FSR,f ; inc pointer btfss FSR,5 ; all done? goto write_again ; no write again ; yes return return ;===================================================================; ; Input: W(reg) - Canal de entrada AN<X> em que X[0:7] ; ; Output: W(reg) - valor de saída convertido pela ADC ; ; (formato digital) escala (0..255) em que 0 = gnd ; ; e 255 = VREF+ = 5V ; ; Resumo: ; ; Devolve em W(reg) valor digital convertido pela ADC. ; ; ; ; Protótipo em Linguagem C ; ; char analog2digital(unsigned char canal_ADC) ; ;===================================================================; analog2digital andlw 0x07 ; movwf aux ; aux = 0x07 & w bcf STATUS,C ; rlf aux,f ; rlf aux,f ; rlf aux,f ; movlw 0xC7 ; andwf ADCON0,w ;
172
TP9 - Conversor A/D do PIC iorwf movwf
aux,w ADCON0
; ;
btfss goto bcf movlw movwf
INTCON,T0IF $-1 INTCON,T0IF TMR0_HW_VAL1 TMR0
; ; ; ; ;
bsf btfsc goto movfw
ADCON0,GO ADCON0,GO $-1 ADRESH
; início da conversão ; ; ; ; ;
return
while(TOIF == 0) {} T0IF = 0; Set Hardware timer0 Value Set TMR0
;===================================================================; ; Input: W(reg) - ponteiro para o buffer ; ; Output: W(reg) - média aritmética das 32 amostras ; ; ; ; Resumo: ; ; Soma os 32 resultados de conversão da ADC, presentes no buffer de ; ; de 32 posições, devolvendo a sua média aritmética. ; ; ; ; Protótipo em Linguagem C ; ; char media_32(char* buffer_32) ; ;===================================================================; media_32 clrf value_low ; initialize register clrf value_high ; initialize register read_again
divide_again
movwf movfw call incf btfss goto
FSR INDF soma FSR,f FSR,5 read_again
; ; ; ; ; ; ; movlw N_SHIFTS ; movwf aux ; bcf STATUS,C ; rrf value_high,f ; rrf value_low,f ; decfsz aux,f ; goto divide_again ; movfw value_low ;
initialize pointer read INDF register to W(reg) soma(char W(reg)) inc pointer all done? no read again yes continue next - > Carry = flag = 0 msb_value_high = 0 all done? no divide again yes return (value_low in W)
return ;===================================================================; ; Input: W(reg) - valor de 8 bits a somar com os 8 bits menos ; ; significativos de value low ; ; Output: não têm parâmetro de saída ; ; Resumo: ; ; Soma o valor actual com o anterior se existir CARRY, incrementa ; ; o valor de value_high de uma unidade. ; ; ; ; Protótipo em Linguagem C ; ; void soma(unsigned char val_buffer_32) ; ;===================================================================; soma addwf value_low,f ; value_low + W(reg) btfsc STATUS,C ; exist CARRY? incf value_high,f ; yes, inc value_high return
; no, return
;===================================================================; ; Input: W(reg) - valor de 8 bits em hexadecimal 0x?? ; ; Output: W(reg) - valor de 8 bits equivalente em decimal ; ; Resumo: ;
173
Guia prático sobre microcontroladores PIC
; ; ; Equivalente em Linguagem C ; ; char h2d (char value_low) ; ; { ; ; return((value_low/10 << 4) + (value_low % 10); ; ; } ; ;===================================================================; h2d movwf divdo ; temp = w = value_low ; clrf j ; j = 0; movlw 10 ; while( divdo >= 10) next_sub subwf divdo,f ; se o subtraendo >= ao subtractor => CY ; se o subtraendo < ao subtractor => CY btfss STATUS,C ; divdo -=divdo; goto fwd ; } incf j,f ; goto next_sub ; fwd addwf divdo,f ; swapf j,w addwf
divdo,w
; w = temp + count w => valor ; decimal correspondente a return ; value_low(hex) ;===================================================================; ; Input: W(reg) - Valor da ADC - 0..255 em Hexadecimal ; ; Output: W(reg) - VALOR DECIMAL convertido para cm ; ; ; ; ; ; Resumo: ; ; ; ; ; ;===================================================================; ; unsigned char calc_dist(unsigned char val_adc) ; ;{ ; ; if (val_adc > adc_table[0]) ; ; return(0); // Obst. muito perto ; ; ; ; if (val_adc =< adc[31]) ; ; return(0xff); // Obst. muito longe ; ; ; ; for(val_adc <= adc_table[i] && val_adc > adc_table[i+1]){ ; ; return (i+10); ; ; } ; ;} ; ;-------------------------------------------------------------------; calc_dist movwf val_adc ; val_adc = w; movlw 127 ; andwf val_adc,f ; 0 =< val_adc =< 127 movlw HIGH adc_table movwf PCLATH movlw 0 ; adc_table[0] call adc_table ; retrieve, w = adc_table[0] subwf val_adc,w ; val_adc - adc_table[0]; btfsc STATUS,C ; if (val_adc > adc_table[0]) goto ret_0x00 ; return (0x00); movlw HIGH adc_table ; movwf PCLATH ; movlw 31 ; adc_table[31] call adc_table ; retrieve adc_table[31] subwf val_adc,w ; btfss STATUS,C ; if (val_adc =< adc_table[31]) goto ret_0xff ; return (0xff) clrf i ; i = 0; next_value movlw HIGH adc_table movwf PCLATH ; movfw i ; call adc_table ; subwf val_adc,w ; if(val_adc =< adc_table[i]) btfss STATUS,C ;
174
TP9 - Conversor A/D do PIC
if_false
goto movlw movwf incf call subwf btfss goto goto incf goto
if_false ; HIGH adc_table ; PCLATH ; i,w ; adc_table ; val_adc,w ; if (val_adc > adc_table[i+1]) STATUS,C ; if_false ; ret_dist ; return (i+10); i,f ; next_value ;
ret_0x00
movlw 0x00 return
ret_0xff
movlw 0x32 return
ret_dist
movlw 10 addwf i,w return
;===================================================================; ; Input: W(reg) - valor BCD de entrada ; ; Input: DISP_7SEG - seleção do display a ser refrescado ; ; Output: não têm parâmetro de saída ; ; ; ; Resumo: Subroutina de Controlo dos displays ; ; Protótipo em Linguagem C ; ; void display(unsigned char bcd_in, unsigned char disp_7seg) ; ;===================================================================; display movwf bcd_in ; movf PORTA,w ; w = PORTA andlw 0xF1 ; movwf aux ; aux = w & 0xf1 disp_0
disp_1
disp_2 break
movfw sublw btfss goto movfw iorlw goto
disp_7seg 0x00 STATUS,Z disp_1 aux 0x08 break
; ; ; ; ; ; ;
switch(disp_7seg)
movfw sublw btfss goto movfw iorlw goto movfw iorlw
disp_7seg 0x01 STATUS,Z disp_2 aux 0x04 break aux 0x02
; ; ; ; ; ; ; ; ;
switch(dis_7seg)
movwf PORTA call bcd_7seg
case_0 w = aux | 0x08 break
case_1 w = aux | 0x04 break case_2 w = aux | 0x02
; escrita na porta ; bcd_7seg(bcd_in);
return ;===================================================================; ; Input: bcd_in - valor BCD de entrada ; ; Output: não têm parâmetro de saída ; ; ; ; Resumo: Subroutina => BCD to 7segment display, envia o valor ; ; passado em bcd_in para a PORTB ; ;===================================================================; bcd_7seg movlw seg70 ; Início da tabela de valores
175
Guia prático sobre microcontroladores PIC addwf movwf movf movwf
bcd_in,w FSR INDF,w PORTB
; ; ; ;
& do val a mostrar da tabela Set do endereço da tabela leitura do valor de 7seg envio do valor para o PORTB
return ;===================================================================; ; Input: W(reg) = BCD_IN - valor BCD de entrada ; ; Output: ; ; ; ; Resumo: ; ;===================================================================; prt_disp7seg call display ; display(bcd_in,disp_7seg); btfss goto bcf movlw movwf btfss goto clrf return incf
INTCON,T0IF $-1 INTCON,T0IF TMR0_HW_VAL2 TMR0
; ; ; ; ;
while(TOIF == 0) {} T0IF = 0; Set Hardware timer0 Value Set TMR0
disp_7seg,1 ; if(disp_7seg == 2) $+3 disp_7seg ; disp_7seg = 0; disp_7seg,f ; else disp_7seg ++;
return END
; directive ’end of program’
176
Apendix A
Figura 43: Mapa de memória RAM, registos do PIC e registos de uso geral
177
Guia prático sobre microcontroladores PIC
178
Apendix B ; Título : ; MPLAB IDE programa de demonstração ; ; Resumo: ; Led pisca-pisca (DUTTY CYCLE variável) ; ; ___________ ; | | ; | PIC16F876 | ; | | ; | | /-----\ RES ; | |->-- RB0 ------| LED |------\/\/\/---- 0V ; | | \-----/ ; |___________| ; ; figura 1. esquema de ligação PIC. ; ; ON (T1)| OFF (T2) | ON (T1) ; _______ _______ ; | | | | ; led _______| |_____________| |__________________ ; ; ; figura 2. diagrama temporal da saída. ; ;******************************************************************** ; * ; Nome ficheiro: exemplo.asm * ; Última alteração: 24/Junho/2005 * ; * ; Autor: Prof. José Luís Azevedo * ; * ; Modificado por: José Miguel Oliveira Gaspar * ; Olímpia Rodrigues * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2005 * ; * ;******************************************************************** ; *
179
Guia prático sobre microcontroladores PIC ; Ficheiro necessário: 16f876.lkr * ; * ;******************************************************************** list
p=16f876
radix
decimal
; - directiva ’list’, define ; o processor a usar ; - directiva ’radix’ especifica ; definição das variáveis ; - directiva ’include’ inclui ; ficheiro adicional
#include "p16f876.inc"
errorlevel -302
; Turn off banking message ; known tested (good) code ;-------------------------------------------------------------------; Constantes ;-------------------------------------------------------------------RA0 EQU 0 RA1 EQU 1 RA2 EQU 2 RA3 EQU 3 RA4 EQU 4 RA5 EQU 5 RB0 EQU 0 RB1 EQU 1 RB2 EQU 2 RB3 EQU 3 RB4 EQU 4 RB5 EQU 5 RB6 EQU 6 RB7 EQU 7 RC0 EQU 0 RC1 EQU 1 RC2 EQU 2 RC3 EQU 3 RC4 EQU 4 RC5 EQU 5 RC6 EQU 6 RC7 EQU 7 T1 EQU 50 ; Gama [1..255] = [10ms..2,5s] T2 EQU 100 ; ;---------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) Bank0 ;---------------------------------------------------------------------group1 iDATA ; dados inicializados delay_mult RES 1 ; Variaveis de controlo delay_k50 RES 1 ; dos loops da rotina Delay delay_k200 RES 1 ; ;--------------------------------------------------------------------
180
Apendix B ; Macros to select the register Banks ;-------------------------------------------------------------------Bank0 MACRO ; Macro to select data RAM Bank 0 bcf STATUS,RP0 bcf STATUS,RP1 ENDM Bank1
MACRO bsf STATUS,RP0 bcf STATUS,RP1 ENDM
; Macro to select data RAM Bank 1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** Reset_vector ORG 0x0000 ; - directiva "ORG" origem do ; programa "ORG 0x0000" vector ; de reset clrf PCLATH ; - instrução "clrf PCLATH" apaga ; todos os bits do registo garante ; que a memória do programa ; é iniciada na página 0 goto main ; - instrução "goto main" salta para ; o endereço de memória do programa ; principal ;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG 0x0005 ; Program Memory PAGE 0 main ; Programa principal. Bank1 ; DATA memory (RAM) Bank1 movlw b’11111110’ ; RB[0] output movwf TRISB ; RB[7:1] inputs ; Bank0 ; DATA memory (RAM) Bank0 clrf PORTB ; Inicialização PORTB. loop ; while(1) { bsf PORTB,RB0 ; Set (ON) LED in RB0 ON movlw call
T1 Delay
; W(reg) = 50 ; delay( 0,5 seg )
181
Guia prático sobre microcontroladores PIC bcf movlw call goto
PORTB,RB0 T2 Delay loop
; ; ; ;
Set (OFF) LED in RB0 W(reg) = 100 delay( 1 seg ) }
;********************************************************************
;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; Delay ; ; Pode gerar delays entre 10 mS e 2,5 S ; ; O valor de entrada e’ passado em W (1..255) ; ; Retorna em Bank0 ; ; ; ; Notas: o loop base e’ de 1 uS (T=200 nS <=> 4*1/20MHz) ; ; ; ;===================================================================; Delay movwf delay_mult ; Carrega o valor multiplo Del_m10 movlw 50 ; de 10 mS movwf delay_k50 ; 50 => 10 mS Del_50 movlw 200 ; 200 => 200 uS movwf delay_k200 ; Carrega o valor Del_200 nop ; correspondente a 200 uS nop decfsz delay_k200,f ; Decrementa "delay_k200". ; O resultado é colocadao em ; "delay_k200" goto Del_200 ; while( delay_k200 > 0 ) decfsz delay_k50,f ; goto Del_50 ; while( delay_k50 > 0 ) decfsz delay_mult,f ; Decrementa "delay_mult". ; O resultado é colocadao ; em "delay_mult" goto Del_m10 ; while( delay_mult > 0 ) return
;
;******************************************************************** END
; directive ’end of program’
182
Apendix B ; Trabalho nº 1 ; Implementação de um led pisca-pisca, em RB1 ; com botão on/off por INTERRUPÇÂO ; ; Objectivos: ; Introdução às Interrupções EXEMPLO ; ; Observações: ; ;******************************************************************** ; * ; Nome ficheiro: trab1Int.asm * ; Data: 1/Junho/2005 * ; Versão: 1.0 * ; * ; Autores: José Miguel Gaspar * ; Olímpia Rodrigues * ; Orientador: Prof. José Luís Azevedo * ; * ; Universidade de Aveiro * ; Seminário EEI 2004/2005 * ; * ;******************************************************************** ; * ; Ficheiro necessário: P16F876.LKR * ; * ;******************************************************************** list radix
p=16f876 decimal
; list directive to define ; processor
#include "p16f876.inc"
; ; ; ;
errorlevel -302
processor specific variable definitions Turn off banking message known tested (good) code
;-----------------------------------------------------------------------------; Constantes ;-----------------------------------------------------------------------------RA0 RA1 RA2 RA3 RA4 RA5
EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5
RB0 RB1
EQU EQU
0 1
183
Guia prático sobre microcontroladores PIC RB2 RB3 RB4 RB5 RB6 RB7
EQU EQU EQU EQU EQU EQU
2 3 4 5 6 7
RC0 RC1 RC2 RC3 RC4 RC5 RC6 RC7
EQU EQU EQU EQU EQU EQU EQU EQU
0 1 2 3 4 5 6 7
;---------------------------------------------------------------------; Variáveis (REGISTOS DE USO GERAL) ;---------------------------------------------------------------------variaveis UDATA 0x20 delay_mult RES 1 ; Variaveis de controlo dos loops delay_k50 RES 1 ; da rotina Delay delay_k200 RES 1 ; start_stop
RES
1
w_save status_save pclath_save
RES RES RES
1 1 1
; SAVE W ; SAVE STATUS REG ; SAVE PCLATH REG
;-------------------------------------------------------------------; Macros to select the register Banks ;-------------------------------------------------------------------Bank0
MACRO bcf bcf ENDM
; Macro to select data RAM Bank 0 STATUS,RP0 STATUS,RP1
Bank1
MACRO bsf bcf ENDM
; Macro to select data RAM Bank 1 STATUS,RP0 STATUS,RP1
Bank2
MACRO bcf bsf ENDM
; Macro to select data RAM Bank 2 STATUS,RP0 STATUS,RP1
184
Apendix B Bank3
MACRO bsf bsf ENDM
; Macro to select data RAM Bank 3 STATUS,RP0 STATUS,RP1
;******************************************************************** ORG clrf goto ORG goto
0x0000 PCLATH main 0x0004 interrupt_start
; Processor reset vector ; Ensure page bits are cleared ; Go to beginning of program ; Processor Interrupt Vector ; Go to interrupt service ; rotine ;-------------------------------------------------------------------; Rotina Main ;-------------------------------------------------------------------ORG 0x0005 main ;Aqui começa o programa principal call InitCfg while_1 ; while(1) { btfsc start_stop,0 ; while (start_stop == 1) {} goto $-1 ; bsf movlw call
PORTB,RB1 25 Delay
; Set RB1 ON ; ; delay( 0,25 seg )
bcf movlw call
PORTB,RB1 25 Delay
; Set RB1 OFF ; ; delay( 0,25 seg )
goto
while_1
; }
;********************************************************************
;************************** ROTINAS ********************************* ;******************************************************************** ;******************************************************************** ;===================================================================; ; InitCfg ; ; Configuração inicial dos registros associados ; ; ao programa principal, PORTOS I/O, Timer0, INTERRUPTS. ; ; ; ; Retorna em Bank0 ; ; ; ; Notas: ; ;===================================================================; InitCfg
185
Guia prático sobre microcontroladores PIC ;----------------- I/O - InitCfg -----------------------------------; Bank1 ; DATA memory (RAM) Bank1 movlw 0x01 ; RB[1] output movwf TRISB ; RB[7:2 & 0] inputs ;----------------- Interrupts enable bits --------------------------; Bank0 ; DATA memory (RAM) Bank0 bsf INTCON,GIE ; Global Int. Enable bit bsf INTCON,INTE ; External Int. enable bit ;-------------------------------------------------------------------; clrf PORTB ; Inicialização PORTB. clrf start_stop ; return ;===================================================================; ; Delay ; ; Pode gerar delays entre 10 mS e 2,5 S ; ; O valor de entrada e’ passado em W (1..255) ; ; ; ; Notas: o loop base e’ de 1 uS (T=200 nS <=> 4*1/20MHz) ; ; ; ;===================================================================; Delay movwf delay_mult ; Carrega o valor multiplo Del_m10 movlw 50 ; de 10 mS movwf delay_k50 ; 50 => 10 mS Del_50 movlw 200 ; 200 => 200 uS movwf delay_k200 ; Carrega o valor Del_200 nop ; correspondente a 200 uS nop decfsz delay_k200,f ; Decrementa "delay_k200". ; O resultado é colocadao em ; "delay_k200" goto Del_200 ; while( delay_k200 > 0 ) decfsz delay_k50,f ; goto Del_50 ; while( delay_k50 > 0 ) decfsz delay_mult,f ; Decrementa "delay_mult". ; O resultado é colocadao ; em "delay_mult" goto Del_m10 ; while( delay_mult > 0 ) return ;********************************************************************
;************************** ISR *************************************
186
Apendix B ;******************************************************************** ;******************************************************************** interrupt_start movwf w_save ; salvaguarda do W reg. swapf STATUS,W ; clrf STATUS ; DATA memory (RAM) Bank0 movwf status_save ; salvaguarda do STATUS reg. movf PCLATH,W ; movwf pclath_save ; salvaguarda do PCLATH reg. clrf PCLATH ; página 0, de memória de ; programa bcf INTCON,INTF ; reset, do bit INTF incf start_stop,w ; andlw 0x01 ; movwf start_stop ; toggle do start_stop (0/1) ; interrupt_end movf pclath_save,w; restauro do PCLATH reg. movwf PCLATH ; swapf status_save,w; restauro da DATA memory (RAM) ; Bank? inicial movwf STATUS ; swapf w_save,f ; restauro do W reg. swapf w_save,w ; retfie END
187