Você está na página 1de 46

Microcontroladores

Introduo a Linguagem C
O contedo e estrutura da linguagem C sero abordados baseando-se em exemplos de programas, pois dessa forma ficar mais claro para o aluno entender a linguagem.

Veja o exemplo de programa em C a seguir

//Primeiro Programa /* Programa Pisca-Pisca (1 segundo) Este programa tem por objetivo ascender e apagar um led conectado no pino RB0 do PIC em intervalos de 1 segundo aproximadamente; */ void main() { trisb = 0; portb = 0; while(1) { portb.f0 = 1; Delay_ms(1000); portb.f0 = 0; Delay_ms(1000); } } //seta pino RB0 //aguarda 1000ms (1s) //resseta pino RB0 //aguarda 1 segundo //define portb como sada //coloca nvel lgico 0 em todos os pinos do portb //inicia um loop infinito

Vejamos o significado de cada linha de programa:

A primeira linha de programa: //Primeiro Programa

chamada de comentrio. Os comentrios so importantes para documentar o programa. Podemos adicionar comentrios em nosso programa de duas maneiras: Atravs de comentrios de linhas simples: quando queremos comentar apenas uma linha de programa, iniciamos os comentrios com os caracteres "//" (igual a linha do programa anterior). Esses tipos de comentrio no faz parte da padronizao ANSI original, mas atualmente encontrado em vrios compiladores. Atravs de comentrios de mltiplas linhas: podemos comentar linhas ou blocos de cdigo de programa utilizando a sequncia de caracteres "/*" para iniciar o comentrio e a sequncia "*/" para terminar o comentrio.

Microcontroladores
/* Programa Pisca -Pisca Este programa tem por objetivo ascender e apagar um led conectado no pino RB0 do PIC em intervalos de 1 segundo aproximadamente; Curso Online: Microcontroladores PIC - Programao em C */ Na prxima linha temos: void main() A declarao main()especifica o nome da funo. A funo main(), na linguagem C, sempre a primeira a ser executada e deve ser a nica no programa. O programa termina quando for encerrada a execuo da funo main(). Uma funo, em C, nada mais do que um conjunto de instrues que pode ser executada a partir de qualquer ponto do programa. Utilizamos o sinal de abertura de chave "{" para iniciar uma funo e o sinal de fechamento de chave "}" para finalizar a funo. Todas as instrues devem estar dentro das chaves que iniciam e terminam a funo e so executadas na ordem em que as escrevemos No caso deste programa exemplo, ela no recebe nenhum parmetro e tambm no retorna parmetro nenhum. Isto fica explcito atravs da palavra-chave void, escrita na frente do programa. As funes e as suas caractersticas sero apresentadas em detalhes mais adiante.

Na prxima linha de programa encontramos: trisb = 0; portb = 0; //define portb como sada //coloca nvel lgico 0 em todos os pinos do portb

O comando trisb define o sentido de acionamento do PORTB do PIC. Neste exemplo, trisb = 0, logo o PORTB foi configurado como sada. Se a instruo fosse trisb=1, o PORTB seria configurado como entrada. O comando portb = 0 coloca nivl lgico 0 em RB0 a RB7. As instrues em C so sempre encerradas por um ponto-e-vrgula ( ; ). O ponto-e-vrgula parte da instruo e no um simples separador, portanto, devemos ao final de cada instruo colocar um ponto-vrgula ;.

Na prxima linha temos: while(1)

Este um comando de controle utilizado na repetio de um determinado bloco de instruo. O bloco de instruo ser executado repetidamente enquanto a condio for verdadeira, ou seja, for diferente de zero. No nosso exemplo, o valor 1 utilizado no comando while garante que a condio seja sempre verdadeira. Estudaremos mais sobre o comando while mais adiante no curso;

Microcontroladores
Os comandos a seguir pertencem ao bloco da instruo while; { portb.f0 = 1; Delay_ms(1000); portb.f0 = 0; Delay_ms(1000); } //seta pino RB0 //aguarda 1000 ms (1s) //resseta pino RB0 // aguarda 1 segundo

Como no temos nenhum comando que interrompa o lao while, os blocos de comandos apresentados sero executados indefinidamente at que o processador seja desligado ou reiniciado. A operao portb.f0 = 1 faz com que o pino RB0 do PORTB seja colocado em nvel lgico 1; Para se referir a um pino das portas do PIC, PORTA e PORTB, devemos apresentar o nome do porta, mais o ponto ".", mais a inicial "f" e o nmero do pino correspondente.

Exemplo:
portb.f0 = 0; porta.f5 = 1; // estamos nos referindo ao pino RB0 do portb // estamos nos referindo ao pino RA5 do porta

A linha de programa seguinte, Delay_ms(1000), uma funo interna do compilador mikroC utilizada para gerar atrasos em escala de milissegundos. No nosso exemplo, o comando ir gerar atraso de 1000ms, ou seja, 1 segundo. A operao portb.f0 = 0 faz com que o pino RB0 do PORTB seja colocado em nvel lgico 0;

Desta forma, ao programarmos o PIC com o programa acima, o pino RB0 ficar mudando entre os estados lgicos 1 e 0 a cada 1 segundo.

Microcontroladores
Vejamos um segundo programa:

//Segundo Programa /* Programa Pisca -Pisca (100 milisegundos) Este programa tem por objetivo acender e apagar leds conectados os pinos dos portes A e B do PIC em intervalos de 100ms; */ void main() { trisb = 0; portb = 0; trisa = 0; porta = 0; while(1) { portb = 255; porta = 255; porta = 0; porta = 0; } } O programa acima tem por objetivo piscar indefinidamente leds ligados ao portb e porta do PIC em intervalos de 100 milissegundos. Suas caractersticas so parecidas com a do programa anterior, a nica diferena esta no tratamento dos ports; portb = 255; porta = 255; //seta todos os pinos do portb //seta todos os pinos do porta //seta todos os pinos do portb //seta todos os pinos do porta //resseta todos os pinos do portb //resseta todos os pinos do porta //define portb como sada //coloca nvel lgico 0 em todos os pinos do portb //define portb como sada //coloca nvel lgico 0 em todos os pinos do porta

Delay_ms(100); //aguarda 100 ms (milisegundos)

Delay_ms(100); //aguarda 100 ms (milisegundos)

O valor 255 est representado na forma decimal este valor em binrio corresponde (1111 1111)2 e em hexadecimal (FF)16.

Formas e representao numricas e de caracteres


No compilador mikroC podemos manipular dados do tipo: decimal, binrio, hexadecimais e octal. Podemos representar um valor numrico de diversas formas. Para exemplificar, vamos supor que desejamos carregar o valor 187 no registrador PORTB no PIC utilizando o mikroC, acompanhe:

Microcontroladores

Representao decimal:
Para representarmos um nmero em decimal basta colocar seu valor sem nenhuma abreviatura, conforme a linha abaixo: portb = 187; //representao decimal

ATENO: NUNCA DEVEMOS REPRESENTAR UM NMERO DECIMAL INICIANDO COM 0 (ZERO), POIS O MIKROC INTERPRETAR O NMERO COMO OCTAL. Exempo: portb = 25 (25 representado em decimal) diferente de portb = 025 (025 representado em octal)

Representao Hexadecimal:
Para representar um nmero em hexadecimal devemos colocar o prefixo 0x (ou 0X) antes do nmero hexadecimal. portb = 0xBB; ou portb = 0Xbb; //representao hexadecimal do numero 187 decimal //representao hexadecimal do numero 187 decimal

Representao binria:
Para representarmos um nmero em binrio devemos colocar o prefixo 0b (ou 0B) antes do nmero em binrio. portb = 0b10111011; ou portb = 0B10111011; //representao binria do nmero 187 decimal //representao binria do nmero 187 decimal

Nos ports, o RB0 corresponde ao bit menos significativo (LSB) e o RB7 corresponde ao bit mais significativo (MSB). Desta forma.

0 -

B -

RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 MSB LSB

Manipulao de registradores bit no mikroC


Podemos manipular os bits de registradores do PIC de diversas formas no compilador mikroC

Exemplo de Manipulao de bits de registradores:

Podemos manipular os bits dos registradores do PIC da seguinte maneira: PORTA.F5 = 0; // -->> faz referncia ao pino RA5 do PIC.

Microcontroladores
PORTD.F7 = 1; //-->> faz referncia ao pino RD7 do PIC. //-->> faz referencia ao bit 0 do registrador TRISB

TRISB.RB0 = 1;

Ou acess-los dessa maneira: obs: no so todos os registradores que permitem acesso direto dos seus bits: RB0 = 0; // --->> faz referncia ao pino 0 do PORTB RA2 = 1; // --->> faz referncia ao pino 0 do PORTA

Exerccios
1) Gostaramos de enviar aos pinos do PORTB os seguintes estados; RB0 = 0 RB1 = 1 BR2 = 1 RB3 = 0 RB4 = 0 RB5 = 1 RB6 = 0 RB7 = 0

Qual o valor numrico que devemos colocar na instruo abaixo para representar os estados dos pinos do PORTB. Obedea as representaes numricas solicitadas:

Representao decimal: portb = X; ?

Representao binria: portb = X; ?

Representao hexadecimal: portb = X; ?

Microcontroladores

Estrutura de um programa em C
Todo programa escrito em C consiste em uma ou mais funes, tendo como particularidade deste fato a possibilidade de construir programas modulares e estruturados. O programa principal escrito em C uma funo. O C uma linguagem extremamente estruturada e exige do programador domnio adequado de tal conceito. Veja a seguir, o menor programa possvel de ser escrito em C: main( ) { } em que: main() { } - a primeira e principal funo a ser executada - inicia ou abre o corpo da funo - finaliza ou fecha o corpo da funo

A funo main() a principal instruo a ser considerada em um programa escrito na linguagem C e deve estar presente em algum lugar do programa, pois ela que marca o ponto de inicializao do processo de execuo do programa. A seguir veremos um modelo de escrita de um programa em C, com todas as definies e comentrios.

[blocos de comentrios de grande importncia na documentao do programa] [<definies de pre-processamento - cabealhos>] [<declarao das variveis globais>] [<tipo>] nome_da_funcao([<parmetros>]) [<declarao de parmentros>] { /* Este trecho reservado para o corpo da funo_nome, com a declarao de suas variveis */ [return ou return() ou return(valor)] } locais, seus comandos e funes de trabalho. Esta funo pode ser chamada de sub-rotina do programa.

void main([<parmetros>]) {

Microcontroladores

/* Este trecho reservado para o corpo da funo, com a declarao de suas variveis locais, seus comandos e funes de trabalho. Aqui esto os primeiros comandos que sero executados no programa. */ }

Toda a informao situada entre colchetes "[" e "]" indica informaes que podem ou no estar presentes em um programa.

Vamos comentar cada bloco de programa:

O primeiro bloco: Os comentrios gerais [ blocos de comentrios de grande importncia na documentao do programa]

O programador poder inserir ou no comentrios em seu programa. Por conveno, importante colocarmos sempre os cabealhos nos programas, pois a apresentao do programa.

O segundo bloco: O cabealho [<definies de pre-processamento - cabealhos>] [<declarao das variveis globais>]

Neste trecho do programa podemos declarar todo o cabealho do nosso programa assim como definir variveis globais que podero ser utilizadas em todas as funes do nosso programa.

Exemplo de cabealho: /* incluimos em nosso programa as bibliotecas de funes que esto no arquivo minhas_funcoes.h.*/ #include "minhas_funcoes.h" // inclui o arquivo de cabealho .h int a; int b; //definimos a varivel a como inteiro e como sendo global //definimos a varivel b como inteiro e como sendo global

Microcontroladores
O terceiro bloco: As funes de subrotinas

[<tipo>] nome_da_funcao([<parmetros>]) [<declarao de parmentros>] { /* Este trecho reservado para o corpo da nome_da_funcao, com a declarao de suas variveis */ [return ou return() ou return(valor)] } locais, seus comandos e funes de trabalho. Esta funo pode ser chamada de sub-rotina do programa.

Este ltimo bloco trata-se de uma funo que carrega o nome nome_da_funcao. Seu tipo pode ou no ser explicitado. Caso no seja, qualquer funo ser do tipo int por default. Esta funo no faz parte da funo main() e dever ser chamada em algum momento pelas funo main() ou por outra funo para seja executados seus comandos. Podemos no momento da chamada da funo enviar parmetros (estudaremos mais sobre as funes a seguir). No final da funo, encontramos o comando return, cujo objetivo retornar a funo que a chamou um valor de retorno da funo. No obrigatrio o uso do comando return, caso no precisemos retornar nenhum valor na funo.

Exemplo de funo de subrotina:

void funcao(void) { portb = ~portb; return; }

Microcontroladores
O quarto bloco: A funo main() void main([<parmetros>]) { /* Este trecho reservado para o corpo da funo, com a declarao de suas variveis locais, seus comandos e funes de trabalho. Aqui esto os primeiros comandos que sero executados no programa. */ }

A funo main() ser a primeira a ser executada pelo processador. Junto a funo main(), temos o modificador de tipo void que tem a funo de declarar que a funo main() no deve retornar nenhum valor. A manipulao de programas em linguagem C para microcontroladores diferente de trabalharmos com programas para PC's, pois nos computadores PC's existem o sistema operacional que receber o retorno da funo main(). Nos microcontroladores, como no possumos um sistema operacional rodando em paralelo com o programa, no podemos retornar nenhum valor na funo main(). Para este caso, devemos sempre iniciar a funo main() com o modificador de tipo nulo void.

Exemplo de funo main():

void main() { PORTB = 0; TRISB = 0; PORTB = ~PORTB; Delay_ms(1000); }

IMPORTANTE: AS FUNES DE SUBROTINAS DEVEM SER COLOCADAS ANTES DA FUNO MAIN(), CASO CONTRRIO OCORRER ERRO DE COMPILAO DO PROGRAMA. ISSO OCORRE PORQUE no podemos usar uma funo sem declar-la previamente. PARA COLOCARMOS FUNES ABAIXO DA FUNO MAIN() FAZ NECESSRIO UTILIZAR OS PROTTIPOS DE FUNES, CUJO OBJETIVO MOSTRAR AO COMPILADOR O TIPO, NOME E PARMETROS DA FUNO DAS SUBROTINAS.

10

Microcontroladores
Exerccios Vamos analisar um exemplo de programa em linguagem C disponvel no prprio compilador mikroC como exemplo. Em princpio, no se preocupe com o funcionamento do programa, procure prestar ateno na identificao dos principais blocos de funes desse programa.

/********************************************************************************* * Project name: PWM_Test_01 (PWM library Demonstration) * Copyright: (c) MikroElektronika, 2005. * Test configuration: MCU: Dev.Board: Oscillator: Ext. Modules: SW: * NOTES: None. *********************************************************************************/ unsigned short j, oj; void InitMain() { PORTB = 0; TRISB = 0; ADCON1 |= 0x0F; PORTA = 255; TRISA = 255; PORTC = 0x00; TRISC = 0; Pwm_Init(5000); } void main() { initMain(); j= 127; oj= 0; Pwm_Start(); while (1) P18F8520 BIGPIC3 HS, 10.0 MHz mikroC v5.00

11

Microcontroladores
{ if (Button(&PORTA, 0,1,1)) j++ ; if (Button(&PORTA, 1,1,1)) j-- ; if (oj != j) { Pwm_Change_Duty(j); oj = j; PORTB = oj; } Delay_ms(200); } } /*******************************************************************************/

Resposta:

Primeiro bloco: Os comentrios /********************************************************************************* * Project name: PWM_Test_01 (PWM library Demonstration) * Copyright: (c) MikroElektronika, 2005. * Test configuration: MCU: Dev.Board: Oscillator: Ext. Modules: SW: * NOTES: None. *********************************************************************************/ P18F8520 BIGPIC3 HS, 10.0 MHz mikroC v5.00

Este bloco do programa so comentrios e so responsvel pela parte "documental do programa". No momento da compilao, esses textos sero descartados pelo compilador.

12

Microcontroladores
Segundo Bloco: O cabealho unsigned short j, oj;

Neste trecho do programa definido o cabealho, e nele foram declaradas as varivel globais do programa.

Terceiro Bloco: as subrotinas

void InitMain() { PORTB = 0; TRISB = 0; ADCON1 |= 0x0F; PORTA = 255; TRISA = 255; PORTC = 0x00; TRISC = 0; Pwm_Init(5000); }

Esta funo uma subrotina do programa, e foi chamada pelo programador de InitMain();

Quarto Bloco: as funo main() void main() { initMain(); j oj = 127; = 0;

Pwm_Start(); while (1) { if (Button(&PORTA, 0,1,1)) j++ ; if (Button(&PORTA, 1,1,1)) j-- ; if (oj != j) { Pwm_Change_Duty(j); oj = j; PORTB = oj; }

13

Microcontroladores
Delay_ms(200); } }

Apesar da funo main() ser a ltima na ordem de escrita do programa, ela ser a primeira funo a ser executada pelo processador.

Dicas: Porque usar funes de subrotinas ? Para permitir o reaproveitamento de cdigo j construdo(por voc ou por outros programadores); Para evitar que um trecho de cdigo que seja repetido vrias vezes dentro de um mesmo programa; Para permitir a alterao de um trecho de cdigo de uma forma mais rpida. Com o uso de uma funo preciso alterar apenas dentro da funo que se deseja; Para que os blocos do programa no fiquem grandes demais e, por consequncia, mais difceis de entender; Para facilitar a leitura do programa-fonte de uma forma mais fcil; Para separar o programa em partes(blocos) que possam ser logicamente compreendidos de forma isolada.

Prottipos de Funes

No podemos usar uma funo sem declar-la previamente. Trata-se de uma instruo geralmente colocada no incio do programa ou do arquivo, obrigatoriamente antecedendo a definio e a chamada da funo. O prottipo informa ao compilador o tipo que a funo retorna, o nome da funo, bem como os parmetros que ela recebe. Abaixo, um exemplo do uso da declarao do prottipo da funo:

void minha_rotina (); //.... void main() {

//prottipo de funo, esta linha de programa deve ser //colocada no topo do programa, junto com as declaraes;

// aqui esta meu programa principal } //***************** funo de subrotina ******************** void minha_rotina() { //aqui esta os comandos da sua subrotina }

14

Microcontroladores
Conforme podemos ver no programa acima, a funo de subrotina minha_rotina() ficou depois da funo main(), nesse caso, necessariamente, devemos colocar o prottipo de funo (linha de programa com o cabealho da funo de subrotina) no topo do programa, caso contrrio teremos erro de compilao pois no podemos utilizar nenhuma funo antes de declar-la. No caso de colocarmos as funes de subrotinas antes da funo main() no programa, no precisamos declarar os prottipos de funes no programa.

Os indetificadores
A linguagem C define identificadores como sendo nomes usados para se fazer referncia a entidades do programa (variveis, funes, rtulos, etc.) definidas pelo programador. Em C, um identificador composto de um ou mais caracteres, sendo que, para identificadores internos, os 31 primeiros so significativos. O primeiro caractere deve ser uma letra ou um sublinha (_) e os caracteres subsequentes devem ser letras, nmeros ou sublinhas. Eis aqui alguns exemplos de identificadores corretos e incorretos:

Corretos
cont valor23 totalGeral

Incorretos
1cont al

Descrio
Um identificador deve sempre comear com uma letra do alfabeto, nunca por um nmero. Um identificador no pode conter acentos (, ^, ~, )

valor-total Um identificador no pode conter smbolos (-)

Isto quer dizer que se duas variveis tm em comum os 31 primeiros caracteres e diferem apenas a partir do trigsimo segundo, o compilador C no ser capaz de distingui-Ias. Por exemplo, esses dois identificadores so iguais: isto_e_um_exemplo_de_um_nome_longo isto_e_um_exemplo_de_um_nome_longo_tambem

Tipos de dados
Existem cinco tipos primitivos de dados em C suportados no mikroC: caractere, inteiro, ponto flutuante (float e double) e sem valor. As palavras reservadas usadas para declarar variveis desse tipo so char, int, float/double e void, respectivamente. A tabela a seguir representa o valor e a escala de cada tipo de dado em C. TIPO char int float void TAMANHO EM BITS 8 8 32 0 INTERVALO 0 a 255 0 a 255 3.4E-38 a 3.4E+38 Nenhum Valor

O tipo char utilizado para representao de caracteres ASCII de 8 bits. Cada varivel do tipo char pode representar um caractere ASCII. O tipo int utilizado para representar nmeros inteiros de 8 bits (0 a 255). Estes tipos de dados so amplamente usados em programao C. O tipo char e int representam nmeros inteiros e no podem ser utilizados para representar nmeros fracionrios. Para isso, deve ser utilizado o tipo float, tambm chamado de ponto flutuante.

15

Microcontroladores
O tipo float deve ser evitado ao mximo e restrito apenas s operaes que realmente necessitarem de um tipo de dados como este.

Modificadores de Tipo
Podemos utilizar comandos especiais do C para obter outros tipos de dados. Esses comandos especiais so chamados de modificadores de tipo e so os seguintes:

signed, unsigned, short, e long.

O modificador de tipo signed pode ser utilizado para modificar um tipo base de dados para que ele possa representar um nmero positivo ou negativo; O modificador short utilizado para definir uma varivel com tamanho menor que o tipo modificado, ou seja, uma verso reduzida do tipo especificado. O modificador long utilizado para ampliar a magnitude de representao do tipo especificado.

TIPO (unsigned ) char signed char (signed) short (int) unsigned short (int) (signed) int unsigned int (signed) long int unsigned long int float double long double void

TAMANHO 8 -bit 8 -bit 8 - bit 8 - bit 16 - bit 16 - bit 32 - bit 32 - bit 32 - bit 32 - bit 32 - bit Nulo 0 255 -128 +127 -128 +127 0 255 -32768 32767 0 65535

RANGER

-2147483648 2147483647 0 4294967295 +/- 1.17549435082E-38 +/- 6.80564774407E38 +/- 1.17549435082E-38 +/- 6.80564774407E38 +/- 1.17549435082E-38 +/- 6.80564774407E38 Sem Valor

Obs: tipos de float, double e long double so considerados do mesmo tipo no mikroC.

Declarao de variveis
Definir uma varivel cri-la na memria (aloc-la), dar a ela um nome e especificar o tipo de dado que nela vai armazenar. Varivel, do ponto de vista da rea de programao, uma regio de memria previamente identificada que tem por finalidade armazenar os dados ou informaes de um programa por um determinado espao de tempo. Uma varivel limita-se a armazenar apenas um valor por vez.

16

Microcontroladores
Sintaxe para criao de uma varivel em C; <tipo> nome_da_variavel;

O tipo deve ser um tipo de dado vlido em C tais como: char, int, float, com ou sem seus modificadores, unsigned, signed, short e long. E nome_da_variavel o nome da varivel adotada pelo programador. Em C, podemos declarar vrias variveis do mesmo tipo em uma nica linha de programa, bastando apenas separ-las por vrgulas.

int soma ; unsigned char i,j,k ; float salrio; unsigned int idade; short int y; long caminho, estado; unsigned valor;

Outro aspecto importante da declarao das variveis o local onde so declaradas.

Basicamente, uma varivel pode ser declarada em dois pontos distintos do programa:

Variveis globais:

No corpo principal do programa: variveis declaradas no corpo principal do programa so variveis globais que podem se acessadas por qualquer funo do programa. Essas variveis esto fora de qualquer funo do programa, inclusive a funo main().

Exemplo:

int contador; char a; void main() {

//define a varivel global "contador" como inteiro //define a varivel global "a" como char

//funo principal do programa

contador = contador + 10 }

17

Microcontroladores
Repare que as variveis "contador" e "a" foram definidas fora de qualquer funo do programa, essas variveis sero tratadas como variveis globais e seus dados podero ser manipulados por qualquer funo do programa;

Mais um exemplo de programa utilizando as variveis globais:

int contador; char a; void subrotina () { contador a = 100; } void main() {

//define a varivel global "contador" como inteiro //define a varivel global "a" como char

//funo de sub-rotina qualquer do programa

= contador - 20;

//funo principal do programa

contador = contador + 10; a = 55; }

Repare no programa exemplo acima que as variveis "contador" e "a" esto sendo manipuladas no corpo da funo main() e na funo subrotina(). Este tipo de manipulao de variveis somente possvel se declararmos como sendo do tipo GLOBAIS, ou seja, necessariamente devemos defini-las no corpo do programa (fora de qualquer funo do programa, inclusive a funo main()).

Variveis locais:

Ao contrrio das variveis globais, uma varivel local somente existe dentro da funo em que foi declarada. Isto significa que uma varivel local somente existe enquanto a funo esta sendo executada. No momento que ocorre o retorno da funo, as variveis locais so descartadas;

Acompanhe o exemplo abaixo:

void main() { int contador; }

//funo principal do programa //define a varivel local "contador" como int

contador = contador + 10

18

Microcontroladores
Repare que a varivel "contador" foi declarada (criada) dentro da funo main(), as varivel locais somente tero validade dentro da funo que as declaram, neste caso, "contador" somente poder ser manipulada no programa dentro da funo main().

Acompanhe mais um exemplo de varivel local:

void subrotina () { int tempo; tempo = tempo * 2; } void main() { int tempo; tempo = tempo/2; }

//funo de sub-rotia qualquer do programa

//funo principal do programa

Repare no programa exemplo acima que temos duas funes, a funo main() e a funo subrotina(). Dentro de cada uma dessas funes foi criada uma varivel chamada "tempo" do tipo int, essa varivel locais e somente tem validade dentro da funo que a declarou, ou seja, a varivel "tempo" da funo subrotina() NO tem nenhuma ligao com a varivel "tempo" da funo main(), pois so variveis locais;

Veja o cdigo abaixo, um erro foi cometido...

void subrotina () { tempo = tempo * 2; } void main() { int tempo; }

//funo de sub-rotia qualquer do programa

//funo principal do programa

Repare que a varivel "tempo" foi declarada unicamente dentro da funo main() e que seus dados esto sendo manipuladas por outra funo chamada subrotina(). Ao compilarmos este programa, certamente o compilador apresentar um erro de compilao nos informando que a varivel "tempo" no foi definida. Esse um erro comum que muitos programadores inexperientes cometem na linguagem C, pois esquecem que uma varivel local somente tem validade dentro da funo que a declarou.

19

Microcontroladores
EXERCCIOS 1. Suponhamos que precisamos criar uma varivel no programa que assumir valores de 0 a 100 durante toda a execuo do programa, utilizaremos o compilador mikroC. Qual o tipo de varivel que devemos declarar em nosso programa para armazenar o valor apresentado? Obs: Procure definir o tipo de varivel mais adequado pois sabemos que se tratando de microcontroladores nossos recursos de memria so limitados

2.

Qual a diferena entre uma varivel unsigned e signed?

3.

No programa seguinte, determine quais so as variveis locais e quais so as variveis globais: Defina a diferena entre varivel local e global:

//programa exemplo char contador; int limite; void funcao(void) { int a; limite = a + contador; portb = limite; } void funcao2(void) { signed char b; portd = b; } void main() { int c; trisb = 0; portb = 0; trisd = 0; portd = 0; funcao() ; funcao2(); }

20

Microcontroladores
4. { int a; portb = a; } void tempo(void) { int a; portd = a; } Analise o trecho do programa abaixo e descreva as diferenas entre as variveis int a:

void limite(void)

Atribuio de valores s variveis. A linha abaixo mostra a atribuio de um valor decimal varivel a. a = 256; A linha pode ser interpretada como: a varivel a recebe o valor 256, j que a varivel representa uma posio de memria ou um registrador do microcontrolador. O operador = utilizado ento para atribuir um valor a varivel indicada.

Tipos de Operadores
A linguagem C faz uso de diversos operadores. Podemos classifica-los em algumas categoria principais: aritmticos, relacionais, lgicos, lgicos bit a bit , outros.

Os operadores Aritmticos:
Os operadores aritmticos so utilizados para efetuar determinadas operaes matemticas entre dados e so classificados em duas categorias, sendo binrio ou unrio. Os operadores binrios atuam em operaes de exponenciao, diviso, adio e subtrao. Os unrios atuam na inverso de valores, atribuindo o sinal de positivo ou negativo. Operador + * / % ++ -adio subtrao ou menos unrio Multiplicao Diviso Resto da diviso inteira Incremento Decremento Ao

21

Microcontroladores
Adio e Subtrao

Os operadores de adio e subtrao so muito simples de serem utilizados, acompanhe: c = a + b; d = d + b; c = c - a; a = d - a + c;

Multiplicao e Diviso Os operadores de multiplicao e de diviso, em C, so de fcil assimilao; c = a * b; d = d * d; c = c / a; a = (d * a) / c;

O operador %

O operador % utilizado para retornar o resto de uma operao de diviso inteira. Vejamos um exemplo: 7 / 3 = 2, em uma diviso inteira, sendo o resto igual a 1. Assim, o valor de 7 / 3 = 2 e o valor de 7 % 3 = 1.

O operador de Incremento ++ e decremento --: O operador de incremento e decremento so utilizados para somar 1 ou subtrair 1 de uma varivel. Exemplo: c = c + 1; No exemplo acima a varivel C foi incrementada em 1 unidade. Podemos ter o mesmo resultado da operao acima atravs do operador de incremento ++; c++; c++; d--; //(equivale a c = c + 1;) //incrementa em 1 unidade o valor da varivel c //incrementa em 1 unidade o valor da varivel d

Acompanhe o exemplo abaixo: variavel_a = variavel_b++; Observe que o valor da varivel variavel _b atribuido a varivel variavel_a, e logo aps isso, o valor de variavel_b incrementado em 1 unidade:

Isso tambm vlido para o comando de decremento --. variavel _a = variavel_b --;

22

Microcontroladores
Observe que o valor da varivel variavel _b atribuido a varivel variavel _a, e logo aps isso, o valor de variavel _b decrementado em 1 unidade:

Devemos tomar alguns cuidados em C com relao aos operadores de incremento e decremento: vejam; variavel_a = variavel_b ++; diferente de variavel_a = ++ variavel_b; Note que na primeira linha de comando, variavel_b incrementada em 1 depois que atribuiu seu valor a varivel variavel _a. Na segunda linha, o valor da variavel_b incrementada em 1 antes de ter seu valor atribudo a varivel variavel_a. Exemplo: int a, b, c; a = 0; b = a ++; c = ++ a; Neste caso, aps a execuo dos trs comandos, o valor de "a" ser igual a 2, o valor da varivel "b" ser igual a 0 e o valor da varivel "c" ser igual a 2.

Operadores Relacionais;
Os operadores relacionais servem para comparar expresses. So muito utilizados para comparar condies de controle do fluxo de execuo de programas. Operador > >= < <= == != Operao realizada maior que maior ou igual a menor que menor ou igual a igual a diferente de

Estes operadores sero muito utilizados para construir expresses condicionais, como veremos mais adiante.

Operadores lgicos ou Booleanos


Os operadores lgicos ou booleanos so de grande importncia para construes de testes condicionais. Operador && || ! Operao realizada AND (E) OR (OU) NOT (NO)

Com esses operadores podemos relacionar diversas condies diferentes em um mesmo teste lgico.

23

Microcontroladores
Exemplos: if (c = 10 && b = 5) c = 5; //condio verdadeira de teste: se a varivel "c" //for igual a 10 E a varivel b = 5 ento "c" //assumir o valor 5. if (c>0 || a==0) b = a; //condio verdadeira de teste: se a varivel "c" //for maior que 0 OU "a" for igual a 0 //ser igual a varivel "a". if (!a) b = c; //condio verdadeira de teste: se a varivel "a" for //igual a 0 (falso), a varivel "b" assumir o valor //da varivel "c". Note que estamos utilizando o //operador de negao ! NOT, por esse motivo a //condio ser verdadeira j que a varivel "a" //possui valor igual a 0. ento "b"

Os operadores Bit a Bit


Os operadores Bit a Bit so utilizados para realizar operaes lgicas entre elementos ou variveis.

Operador & | ^ ~ >> << O Operador AND (E)

Operao realizada AND (E) OR (OU) XOR (OU exclusiva) NOT (complemento de um) deslocamento direita deslocamento esquerda

O operador lgico AND realiza operao separadamente para cada bit dos operandos. Utilizamos muito este o operando AND como "mscara" de um byte, para habilitar ou desabilitar somente os bits que desejamos. Veja um exemplo: int a, b; a = 100; b = 28; a = a & b; A operao AND ocorrer da seguinte maneira: a = 100 ----> AND (&) b = 28 ----> Resultado= 00011100 ___________________ 00000100 //ou 4 decimal 01100100

24

Microcontroladores
O Operador OR (|) O operador OR muito similar ao operador AND, sua operao tambm realizada para cada bit do operando. Exemplo: int a, b; a = 100; b = 28; a = a | b;

A operao OR ocorrer da seguinte maneira: a = 100 ----> OR ( | ) b = 28 ----> Resultado= 00011100 ___________________ 01111100 //ou 124 decimal 01100100

O Operador XOR (^) O operador XOR muito utilizado em funes de comparao de valores, pois em uma operao lgica, o resultado somente ser verdadeiro (nvel lgico 1) se um e somente um deles for verdadeiro ( nvel 1). Exemplo: int a, b; a = 100; b = 28; a = a ^ b;

A operao XOR ocorrer da seguinte maneira: a = 100 ----> XOR ( ^ ) b = 28 ----> Resultado= 00011100 ___________________ 01111000 //ou 120 decimal 01100100

O Operador NOT (~) O operador NOT inverte o estado de cada bit do operando em uma operao. Exemplo: int a, b, c; a = 1; b = 1; b = ~a c = ~b

A operao NOT ocorrer da seguinte maneira: a = 0b00000001; NOT de "a" ----> b = 0b00000001; NOT de "b" ----> 0b11111110; 0b11111110

25

Microcontroladores
O Operador de deslocamento << e >> O operador >> desloca para a direita os bits de uma varivel um determinado nmero de vezes e o operador << faz o mesmo para a esquerda. exemplo: int a, b, c; a = 10; b = 10; b = a >> 1; c = b << 5;

No exemplo acima, os valores dos bits da varivel "a" foram deslocados 1 vez para a direita, enquanto os bits da varivel b foram deslocados 5 vezes para a esquerda. Teremos como resultado: varivel a; // ----> 00001010 - valor 10 em binrio >> // ----> 00000101 - valor 5 em binrio

Observe que o valor aps deslocamento passa a ser agora 5 decimal = 00000101 em binrio.

No deslocamento para a esquerda (<<) os bits so deslocados de n posies, de acordo com o segundo operando da expresso e os bits mais a esquerda so descartados, os bits mais a direita so substitudos por zero. Deslocar um nmero n vezes para a esquerda equivale a multiplicar o nmero por 2 . Exemplo
n

0x0001 << 5;

/* equals

0x0020*/

0b0000000000000001 << 5; // igual a 0b0000000000100000 0x3801 << 4; /* equals 0x8010, overflow! */

0b0011100000000001 << 4; //igual a 0b1000000000010000

No deslocamento para a direita (>>) os bits so movidos para a direita tantas vezes quanto indicado pelo segundo operando da expresso. O bit mais a direita descartado e atribudo 0 (zero) ao bit mais a esquerda se o primeiro operando for do tipo sem sinal (unsigned), caso o tipo seja com sinal (signed), atribudo o valor do sinal. O deslocamento para a direita de n posies, equivale a dividir o nmero por 2 . Exemplo Com sinal (signed) 0xFF56 >> 4; /* equals 0xFFF5 */
n

0b1111111101010110 >> 4; //igual a 0b1111111111110101 Sem sinal (unsigned) 0xFF56 >> 4; /* equals 0x0FF5 */

0b1111111101010110 >> 4; //igual a 0b0000111111110101

26

Microcontroladores

Estruturas de Controle
As estruturas de controle so usadas nos programas em lugares em que necessitamos que a mquina faa repetidas operaes ou necessite de tomadas de decises.

O comando IF (SE)
O IF (SE, em portugus) uma estrutura de tomada de deciso baseada no resultado lgico de um teste. Sua forma geral : if (condio) comando;

ou if (condio) { blocos de comandos};

Em C, qualquer nmero diferente de zero tido como verdadeiro. O que significa que uma condio em C s falsa, quando o resultado da operao utilizada para testar a condio for igual a zero (0). Qualquer outro valor, mesmo negativo, considerado como verdadeiro ou no zero. No comando If, caso a condio seja verdadeira (diferente de zero), o comando, ou blocos de comandos sero executados, caso contrrio, quando a condio for falsa (0 zero) o comando ser ignorado.

Exemplo: void main() { char a = 10; char b = 0 ; if (a) b--; }

A varivel "a", foi atribudo o valor 10, que diferente de zero (0). Consequentemente, a o comando if ser executado e a condio de decremento da varivel b ser executado; ( if (a) b--; ). Tambm possvel executar outro comando ou bloco de comandos no caso da condio ser avaliada como falsa, para isso utilizamos os recursos do comando if - else.

Acompanhe seu formato geral (sintax): if (expresso) comando 1 else comando 2

27

Microcontroladores

Exemplo:

if (x > 5) z = 10; else z = 20;

A linha de comando if (x > 5) tem por funo verificar se condio x>5 verdadeira, caso seja verdadeira, a linha de programa z = 10 ser executada. Caso a condio do comando if seja falsa, ou seja, se "x" for menor que 5, ento a linha de comando z = 20 ser executada.

Todos os operadores do C podem ser includos no teste de uma condio, expresses vlidas da linguagem C podem ser avaliadas para a gerao de um resultado booleano na estrutura if. As expresses seguintes so vlidas e seus resultados dependero do valor de suas variveis. Exemplo:

if (a > b)

b = a;

//se a expresso

a > b for verdadeira, a

//varivel "b" assume o valor da "a" if (b < a) b = 10; //se a expresso a < b for verdadeira, a //varivel "b" assume o valor 10 if (a != b) b = 55; //se a expresso a!=b (diferente) for //verdadeira, a varivel "b" assume o //valor 55 if ( (a + b) > (b + d) ) b++; //se a expresso (a + b) > (b + d) for //verdadeira, a varivel "b" ser //incrementada em uma unidade.

Observaes importantes:

O operador de atribuio de igualdade em C (=) diferente do operador relacional de igualdade (==). Para testar a condio de uma varivel qualquer, utilizamos o operador relacional de igualdade (==). Acompanhe: if (a == b) diferente de if (a = b) c = 10; A condio (a == b) faz uma comparao entre as duas variveis, caso a condio seja verdadeira, a varivel "c" assumir o valor 10; c = 10;

28

Microcontroladores
O comando If seguinte, possui uma expresso de atribuio de igualdade (a = b). O compilador ao compilar este comando, ir primeiramente atribuir a varivel "a" o valor contido em "b", e depois disso, verificar se condio no zero, caso seja verdadeiro o resultado (diferente de zero), a varivel "c" assumir o valor 10; No comando If para adicionarmos blocos de programas, faz necessrio o uso dos smbolos abre- chaves ({) efecha-chaves (}).

Exemplo: if (portb == portc) { a++; portb.f0 = 1; d = c + e; } //blocos de comandos

A estrutura if, else, if


Podemos criar arranjos (nesting) de comandos atravs da estrutura if, else, if. Os arranjos so criados bastando colocar estruturas if aninhadas com outras estruturas if. Seu formato geral :

if (condio1) declarao 1; else if (condio2) declarao 2; else if (condio3) declarao 3; else if (condio4) declarao 4;

Exemplo: void main() { int contador = 10; int sinal = 5; if (contador > sinal) sinal++; else if (contador < sinal) sinal--; else if (contador == sinal) sinal = 0; }

29

Microcontroladores
Podemos tambm executar blocos de comandos utilizando os recursos das chaves ( { e } ).

Exemplo: void main() { int contador = 10; int sinal = 5; if (contador > sinal) { sinal++; contador = 20; } else if (contador < sinal) { sinal--; contador } else if (contador == sinal) sinal = 0; } = 15; //utilizao de blocos de comando na estrutura if-else-if

A estrutura if uma das mais utilizadas para tomada de decises lgicas. Iremos utiliz-la em vrios programas que desenvolveremos durante o curso.

O comando Switch
O comando switch uma forma mais clara e elegante de tomar deciso dentro de um programa em C. Diferente do comando if, a estrutura switch no aceita expresso para a tomada de deciso, s aceita constante. Forma geral do comando switch switch (varivel) { case constante1: declarao1A; declarao1B; declarao1N; break; case constante2:

30

Microcontroladores
declarao2A; declarao2B; declarao2N; break; default; declarao_default; }

O valor da varivel no comando switch comparada com as constantes especificadas pela clusula case. Caso a varivel e a constante possuam valores iguais, os comandos seguinte clusula case sero executados. Caso no tenha nenhuma constante com o mesmo valor da varivel, ento os comandos especificados pela clusula default sero executados.

Exemplo:

void main() { int contador = 10; int sinal = 5; switch(contador) { case 2: sinal++; break; case 1: sinal = 2; break; case 10: contador--; break; default: sinal = 0; } }

No exemplo de acima, a varivel contador ser comparada s constantes 2, 1 e 10. Como a varivel contador possui o valor 10, consequentemente o comando que ser executado no exemplo acima case 10: contador--; (decrementa a varivel contador). A clusula Break possui a funo de encerrar uma sequencia de comandos de uma clusula case. A clusula default o ltimo comando switch.

31

Microcontroladores

Estruturas de repetio
Os laos de repetio servem para repetir uma ou mais vezes determinada instruo ou blocos de instrues. Existem basicamente trs tipos de estruturas de repetio na linguagem C: for while do - while A estrutura for basicamente utilizada para laos finitos de contagem, normalmente utilizando uma varivel de controle da contagem. A estrutura while basicamente utilizada para repetio de um determinado conjunto de instruo enquanto uma condio for verdadeira. O comando do - while similar estrutura while, diferenciando apenas o momento que analisado a condio.

O comando For
O lao for utilizado quando necessitamos de um ciclo de repeties controlado, pois em sua declarao podemos inicializar e incrementar ou decrementar a varivel de controle. Antes de serem executados os comandos do lao for-next, primeiramente avaliada a condio do teste. Caso seja verdadeira, so executados os comandos do lao. A cada ciclo que executado o lao for, a varivel de controle ser incrementada ou decrementada no valor programado no incremento.

Veja a estrutura do comando for : for (inicializao;condio;incremento ) comando; ou for (inicializao ; condio ; incremento ) { ... comandoA1 comandoA2 ... } Onde: inicializao: expresso vlida utilizada normalmente para inicializao da varivel de controle do lao for. condio: condio que decide pela continuidade ou no do lao de repetio, enquanto esta condio foi verdadeira , o lao for permanecer em execuo. incremento: valor incrementado em a cada repetio do lao for.

32

Microcontroladores
Exemplo: int contador; for (contador = 0 ; contador <= 10 ; contador ++ ) portb = contador;

Na estrutura anterior, a varivel contador inicialmente carregada com o valor 0 (zero), em seguida a condio verificada, se for verdadeira (a varivel contador for menor ou igual a 10), os comandos do lao for so executados (o valor da varivel contador escrita no registrador portb). Aps a execuo de todos os comandos presentes no lao for, a varivel contador incrementada no passo do valor do incremento, que no nosso exemplo 1 unidade, e mais uma vez a condio contador <= 10 verificada, caso seja verdadeira, os comandos do lao for so executados novamente. A estrutura de repetio for termina quando a condio contador <= 10 for falsa, ou seja, a varivel contador assume um valor maior do que 10.

Exemplo:

int v, d; for (v = 0 ; v == d ; { Comando A Comando B } v++)

Este exemplo funciona da seguinte maneira: 1. A varivel v recebe o valor 0. 2. A condio v<d verificada 3. Se a condio for falsa, o lao de repetio for finalizado. 4. Se a condio for verdadeira, o bloco de comandos Comando A e Comando B executado. 5. A varivel v tem seu valor incrementado em 1 unidade. 6. Volta ao passo 2.

O grande benefcio do lao for sua flexibilidade, pois aceita qualquer expresso vlida em C, mesmo que essas expresses no tenham relacionamento com o lao de repetio diretamente. Um exemplo simples de aplicao do lao for a criao de pequenos tempos de atrasos (delays). int atraso; for (atraso = 0 ; atraso < 1000 ; atraso++);

O lao for acima faz com que o processamento fique incrementando constantemente a varivel atraso de 1 at que esta varivel seja igual ao valor 1000;

Observe o fragmento de programa seguinte vlido dentro do loop for:

33

Microcontroladores

for (n = 0 ; (n < 100)

&&

portb.f0 ; n++)

No exemplo acima a varivel n ser incrementada 100 vezes, desde que o pino RB0 permanea em estado lgico alto. Se o pino RB0 em algum momento do lao cair para nvel lgico baixo, o loop ser imediatamente encerrado.

Exemplo:

Aproveitando que estamos estudando as estruturas do lao de repetio for, vamos elaborar um programa que pisca um LED conectado ao pino RB0 do PIC utilizando os recursos do lao for.

Acompanhe o esquema abaixo:

C1
22n

U1 X1
CRYSTAL 16 15 4 RA7/OSC1/CLKIN RA0/AN0 RA6/OSC2/CLKOUT RA1/AN1 RA2/AN2/VREF RA5/MCLR RA3/AN3/CMP1 RA4/T0CKI/CMP2 RB0/INT RB1/RX/DT RB2/TX/CK RB3/CCP1 RB4 RB5 RB6/T1OSO/T1CKI RB7/T1OSI PIC16F628A 17 18 1 2 3 6 7 8 9 10 11 12 13

C2
22n

D1
LED-YELLOW

R1
470R

O programa seguinte vai contar at 100.000. Para acomodar um nmero dessa grandeza, poderamos ter utilizado uma varivel tipo long, mas optamos pela uma varivel do tipo int para que voc entenda a construo de dois laos for encadeados. Para contar at 100,000 necessrio termos uma varivel que conte at 100 e outra at 1000 (100 * 1000 = 100.000).

//****************************************************************** //* programa de perda de tempo utilizando o lao de repetio for. * //****************************************************************** void atraso(void) { int contador1, contador2; for(contador1=0;contador1<100;contador1++) } //fim da rotina de atraso //lao de repetio for for(contador2=0;contador2<1000;contador2++); // rotina de perda de tempo(atraso).

34

Microcontroladores
void main() { trisd = 0; while(1) { atraso(); portb.f0 = ~port.f0; } } //chama rotina de perda de tempo // inverte os estados do bit 0 do portb do PIC

O comando while
Muitos dos programadores iniciantes no sabem do que iremos comentar agora.

Os microcontroladores no geral no possuem sistemas operacionais, os programas que desenvolvemos para os microcontroladores PIC devem rodar eternamente, ou possurem mecanismos que paralise a operao da CPU em alguns momentos. Isso necessrio, pois, por no possuir sistema operacional, o programa do PIC no tem para onde sair, devendo ficar em operao, de preferncia eterna. Esse um dos motivos da funo principal main() dos programa para microcontroladores serem tipo void (valor nulo), pois no tem quem receba os valores de retorno da funo principal main().

O comando while o comando ideal criar loops infinitos no nosso programa. A sintax do comando while : while (expresso) declarao

A estrutura while verifica inicialmente se a condio de teste (expresso) verdadeira. Caso a expresso seja verdadeira, a declarao ser executada, a declarao poder ser tambm um bloco de comandos delimitados por chaves ( { } ). Ao retornar para o incio do lao, verificado novamente se a condio de teste verdadeira, se for verdadeira, executada novamente a expresso ou o bloco de comandos; se for falsa, o lao while finalizado.

Exemplo: void main() { while (1) { declarao 1; declarao 2; declarao n; } } //condio a ser testada. //verdadeira (1); Neste exemplo a condio sempre ser

35

Microcontroladores
Veja outro exemplo de programa:

void main() { int a = 25; while (a == 5) { a++; portb = a; } }

Repare que no exemplo acima o valor da condio do lao while falsa, neste caso os comandos do lao nunca sero executados, a no ser que em algum momento esta condio se torne verdadeira, ou seja, at que a = 5.

O comando do - while
O comando do-while forma uma estrutura de repetio diferente dos comandos while e for estudado anteriormente. Sua diferena fundamental com relao aos tradicionais laos while e for esta no fato da avaliao da condio de teste ser no final do lao de repetio, contrrio dos outros laos que estudamos, que testam as condies no incio de cada ciclo.

formato geral: do declarao while (condio);

ou do { comando 1; comando 2; } while (condio de teste);

Na estrutura do-while a condio de teste efetuada somente na parte final do loop. Isso faz com que as instrues contidas no interior do lao do- while sejam executadas ao menos uma vez. Caso a condio teste seja falsa (igual a zero), o lao de repetio finalizado, caso contrrio o bloco que est na estrutura seria novamente executado at que a condio teste seja atendida.

36

Microcontroladores
Exemplo:

void main() { int a = 0; do { a++; portb = ~portb; } while(a < 100); } //enquanto a < 100 permanece no loop do-while; //incrementa a varivel a de uma unidade //inverte os estados do portb //declara a varivel a como inteiro com o valor 0

O comando break e continue


break

O comando break, na linguagem C, utilizado para interromper (quebrar) qualquer lao de repetio instantaneamente. No momento da execuo do loop, ao encontrar o comando break, o lao de repetio finalizado.

Exemplo:

void main() { int a = 0; do { a++; break; portd = ~portd; } while(a < 100); } //enquanto a varivel a for menor que 100 //a rotina do-while ser executada. //incrementa a varivel A em uma unidade //interrompe a execuo do lao de repetio do-while //inverte os estados dos portd

O comando break valido para os laos do-while, while, for e case.

37

Microcontroladores
continue

O comando continue reinicia novamente o teste da condio do lao de repetio. Toda a vez que no lao for encontrado o comando continue, os comandos seguintes no sero executados no lao.

Exemplo:

void main() { int a = 0; do { a++; continue; portd = ~portd; } while(a < 100); } //enquanto a varivel a for menor que 100 a rotina //do-while ser executada. //incrementa a varivel a de uma unidade //retorna para o inicio do lao de repetio //inverte os estados dos portd

No exemplo de programa acima, os comandos abaixo de continue no sero executados, pois, toda a vez que for executado o comando continue, automaticamente o programa ser redirecionado para o cabealho do lao de repetio independente de qualquer estado de variveis. O comando continue valido para os laos do-while, while, for e case.

38

Microcontroladores

Utilizao de teclas no MikroC


5V

U1 R3 10k R2 10k R1 10k


17 18 1 2 3 6 7 8 9 10 11 12 13 RA0/AN0 RA7/OSC1/CLKIN RA1/AN1 RA6/OSC2/CLKOUT RA2/AN2/VREF RA3/AN3/CMP1 RA5/MCLR RA4/T0CKI/CMP2 RB0/INT RB1/RX/DT RB2/TX/CK RB3/CCP1 RB4 RB5 RB6/T1OSO/T1CKI RB7/T1OSI PIC16F628A 16 15 4

Na maioria dos projetos indispensvel a utilizao de teclas como ilustrado na figura acima. Os resistores ligados entre os terminais do PIC e o positivo da fonte, so denominados resistores de pull-up, e servem para manter definido o nvel lgico nas entradas como um, ao pressionarmos uma das teclas que se encontra ligada entre o terminal do PIC e o terra do circuito, o nvel lgico muda de um para zero. No caso do PIC16F268A, o portb possui resistores internos de pull-up que podem ser habilitados ou desabilitados atravs do bit 7 do registrador OPTION_REG.

bit 7

RBPU: PORTB Pull-up Enable bit 1 = PORTB pull-ups are disabled 0 = PORTB pull-ups are enabled by individual port latch values

Exemplo option_reg.f7=0; //habilita os pull-ups internos do portb

Voltando s teclas, toda tecla sofre de um mal, o bouncing, ento, ao utilizarmos teclas nos projetos devemos levar em conta a possibilidade da existncia do bouncing e providenciarmos sua eliminao, que pode ser efetuado por hardware, atravs da incluso de um circuito de dedouncing (latch) juntamente com o teclado, ou atravs de software (rotina de debouncing).

39

Microcontroladores
Boucing o efeito mecnico de rebatimento que a tecla sofre logo aps ser pressionada, o qual provoca a leitura falsa da tecla, isto , o rebatimento faz com que a tecla seja lida mais de uma vez. A rotina de debouncing nada mais do que um pequeno intervalo de tempo entre o momento em que a tecla solta e a nova leitura do teclado. Esse intervalo permite que o fenmeno do rebatimento termine naturalmente, evitando assim a leitura falsa dela. Tempo aproximado de 25 ms.

No MikroC podemos manipular teclados atravs de uma simples funo chamada button. Funo button A funo button tem como sintaxe: Button(&port, onde: &port = port onde esta ligado a tecla, pode ser PORTA, PORTB, PORTC, PORTD ou PORTE. pin = o pino onde esta ligado a tecla no PIC, pode ser de 0 a 7. timer = tempo de debounce em escala de milisegundos. estado_de_ativao = determina se a tecla vai ser ativada em nvel 0 ou em 1. pin, time, estado_de_ativao);

Exemplo: button (&portb, 1, 10, 0)

A partir da configurao da funo button acima, descobrimos que a tecla que ser lida est conectada ao portb, pino RB0, delay de debounce de 10 milisegundos e acionada em nvel lgico 0 (zero).

O retorno da funo button : valor 0 (tecla no pressionada) ou 1 (tecla pressionada). A funo button automaticamente configura os respectivo port como entrada.

Vejamos um exemplo de programa utilizando a funo button:

5V

U1
R1
10k
17 18 1 2 3 6 7 8 9 10 11 12 13 RA0/AN0 RA7/OSC1/CLKIN RA1/AN1 RA6/OSC2/CLKOUT RA2/AN2/VREF RA3/AN3/CMP1 RA5/MCLR RA4/T0CKI/CMP2 RB0/INT RB1/RX/DT RB2/TX/CK RB3/CCP1 RB4 RB5 RB6/T1OSO/T1CKI RB7/T1OSI PIC16F628A 16 15 4

S1

R2
470R
A

D1
K LED

40

Microcontroladores
Primeiro Programa: Conectado ao PIC temos uma tecla (push-button) e um led. Repare que o led ligado com nivel lgico 1.

Desejamos que toda vez que pressionarmos e soltemos a tecla S1, o led 1 dever alterar seu estado lgico, ou seja, se o led estiver acesso, ao pressionar e soltar a tecla S1, o led ser apagado, e ao pressionar a tecla novamente, o led ser acesso. Devemos programar delay para correo de bouncing de 20 milisegundos. Para realizar essa tarefa, iremos fazer um programa bem simples utilizando a funo button, veja:

void main() { trisb.f4 = 0; trisb.f0 = 1; do { if (button(&PORTB, 0, 20, 0)) { delay_ms(200); portb.f4 = ~porb.f4; } } while(1); } //delay de 200 milisegundos //inverte o estado do led //se a tecla S1 estiver pressionada o comando //if ser executado //configura pino RB4 como sada (leds) //configura pino RB0 (tecla) como entrada

No programa acima configuramos o pino RD0 como sada, pois trta-se de um led. trisb.f4 = 0; //configura portb como sada (leds)

Criamos um lao de repetio atravs do comando do-while, cujo objetivo fazer com que o microcontrolador sempre esteja executando os comandos do lao.

A funo button foi programada da seguinte forma: button(&PORTB, 0, 20, 0)


Porta onde est ligada a tecla Pino onde esta ligada a tecla, neste caso o pino RB0 Tecla acionada com nvel lgico zero

Debouncing de 20ms. Delay de 20ms para correo do efeito mecnico da tecla (ricochete).

41

Microcontroladores
Acompanhe o trecho de programa seguinte:

if (button(&PORTB, 0, 20, 0)) { delay_ms(200); portb.f4 = ~porb.f4; }

//se a tecla S1 estiver pressionada o comando //if ser executado

//delay de 200 milisegundos //inverte o estado do led

Caso a tecla S1 seja pressionada, ao executar a funo button, teremos como retorno valor 1 (verdadeiro), e caso no venhamos a pressionar a tecla, a funo button nos retornar o valor 0 (falso). A partir disso conclumos que a condio if somente ser verdadeira caso o retorno da funo button for verdadeiro, e isso ocorrer quando a tecla for pressionada. O programa apresentado acima possui um problema, pois caso deixemos a tecla pressionada, a condio if sempre ser verdadeira e ento os comandos contidos no bloco logo aps o if sero executados, fazendo com que o led acenda e apague enquanto a tecla estiver pressionada.

Segundo Programa:

Para corrigir o problema do programa anterior, vamos elaborar um novo programa que acenda e apague o led 1 da figudo circuito anterior para cada toque que dermos no teclado, ou seja, temos que pressionar e soltar a tecla para executar a inverso do estado do led, se deixarmos a tecla pressionada, o estado lgico do led somente mudar um vez. O tempo de debouncing programado dever ser de 20 milisegundos.

Programa:

/* Programa de leitura de tecla. Este programa tem por objetivo ler o estado de uma tecla para ligar/desligar um led. */ #define led1 portb.f4 int estado_antigo; void main() { trisb.f4 = 0; trisb.f0 = 1; //configura o pino Rb4 como saida, pois iremos //ligar/desligar o led. //configura pino RB0 (tecla) como entrada //a diretiva define atribui ao pino RB4 o nome led1. //define uma varivel de controle, cujo objetivo // armazenar um estado.

42

Microcontroladores
do { if (Button(&PORTB, 0, 20, 0)) estado_antigo = 1; //se a tecla fo pressionada, //a varivel estado_antigo //= 1. if (estado_antigo==1&&Button(&PORTB,0,20,1)) { led1 = ~led1; estado_antigo = 0; } } while(1); } //inverte o estado do led 1. //inverte o valor da varivel estado_antigo para o prximo //acionamento. //verifica se a tecla foi //solta

Estudo detalhado do programa:

Primeira parte: Comentrio Nesta primeira parte do programa, acrescentamos comentrio de apresentao do programa. /* Programa de leitura de tecla. Curso: Microcontroladores PIC programao em C Este programa tem por objetivo ler o estado de uma tecla para ligar/desligar um led. */

Segunda parte: a diretiva define

At este ponto do curso no estudamos a utilizao da diretiva define. Esta diretiva tem por funo atribuir a uma constante ou registrador um novo nome. Veja o comando:

#define led1 portb.f4

//a diretiva define atribui ao pino RB4 o nome led1.

A diretiva #define atribui o nome led1 ao pino RD0 do PIC, partir deste ponto do programa, toda vez que utilizarmos o nome led1, o compilador sabe que se refere ao pino portb.f4 (RB4), e substituir na compilao este novo nome pelo endereo fsico de memria do pino RB4.

Exemplo: #define display1 portb.f0 //a diretiva define atribui ao pino RB0 o nome display1. #define led2 porta.f1 void main() { //a diretiva define atribui ao pino Ra1 o nome led2.

43

Microcontroladores
trisa = 0; display1 = 0; led2 = 1; } //configura o pino RA1 como sada, pois iremos ligar/desligar o led.

Terceira parte: definio da varivel

Definimos uma varivel do tipo int chamada estado_antigo. Esta varivel tem por funo fazer com que o led seja ligado/desligado somente com um unico toque na tecla, evitando que ao deixarmos a tecla pressionada os comandos if sejam sempre executados.

int estado_antigo;

//define uma varivel de controle, cujo objetivo armazenar //um estado.

Quarta parte: a funo principal

A funo principal main() a primeira a ser executada no programa em C. Repare que a funo main() acompanha um modificador de tipo void que tem como objetivo informar ao compilador que esta funo nula e no possui retorno de dados, pois, no tem pra quem retornar os dados pois trat-se da funo principal.

void main() {

Quinta parte: programando as portas como entrada ou saida

Como j vimos anteriormente, o registrador TRIS do PIC, tem por funo informar a direo (leitura ou escrita) dos pinos da porta. Neste programa temos uma tecla conectada ao pino RB0, e para lermos essa tecla necessrio configurar este pino como entrada. A funo button se encarrega de configurar esses registradores de sentido para ns.

Conectado ao pino RB4, temos um led. Para acionar este led, faz necessrio enviar nvel lgico 1 a este pino, ento devemos configurar este pino como sida.

trisd.b4 = 0;

//configura o pino RB4 como sada, pois iremos ligar/desligar //o led.

44

Microcontroladores
Sexta parte: Rotina de loop Lembre-se que devemos sempre manter o microcontrolador executando alguma rotina, mesmo que essa rotina seja um comando sem sada (while(1);). Devemos criar um programa que "amarre" o microcontrolador a sempre executar suas funes. No nosso programa exemplo utilizamos os recursos do lao de repetio do while.

do { if (Button(&PORTB, 0, 20, 0)) estado_antigo = 1; //se a tecla for pressionada, //a varivel estado_antigo //= 1. if (estado_antigo && Button(&PORTB, 0, 20, 1)) { led1 = ~led1; estado_antigo = 0; } } while(1); } //inverte o estado do led 1. //inverte o valor da varivel estado_antigo para o prximo //acionamento. //verifica se a tecla foi //solta

Repare que a condio de teste do lao de repetio do-while ser sempre verdadeira (while(1)).

Stima parte: Rotina de tomada de deciso e funo button

Os comandos seguintes tem por objetivo ler o estado da tecla S1, conectada ao pino RB0 do PIC, e ligar ou apagar o led 1 conectado ao pino RD0. Para lermos a tecla, utilizamos a funo do mikroC: Button, em conjunto com o comando de tomada de deciso IF.

Vejamos:

if (Button(&PORTB, 0, 20, 0)) estado_antigo = 1;

//se a tecla fo pressionada, a //varivel estado_antigo = 1.

Sabemos que o comando if somente ser executado se a condio de teste for verdadeira, neste caso, a varivel estado_antigo somente ser executada se a funo button for verdadeira, para isso necessrio que a tecla seja pressionada.

45

Microcontroladores
Outro comando:

if (estado_antigo == 1 && Button(&PORTB, 0, 20, 1)) {

//verifica se a tecla //foi solta

Nesta linha de programa efetuamos uma operao AND (E) entre a varivel estado_antigo e o retorno da funo Button, cujo objetivo verificar se a tecla foi solta ou no. Repare que nesta segunda funo Button o estado lgico de acionamento da tecla passa a ser 1 (Button(&PORTB, 0, 20, 1)), contrrio da funo Button da linha anterior, essa alterao indica que somente teremos a condio de retorno verdadeira (1), caso a tecla no esteja pressionada. Os comandos seguintes somente sero executados se a condio if for verdadeira, e para isso faz-se necessrio que a varivel estado_antigo seja igual a 1 e que o retorno da funo Button seja verdadeira, ou seja, a tecla tem que estar solta.

Oitava parte: Inverso do estado do led e resset de varivel de estado

led1 = ~led1; estado_antigo = 0;

//inverte o estado do led 1. //inverte o valor da varivel estado_antigo //para o prximo acionamento.

46