Microcontroladores

Introdução a Linguagem C
O conteúdo e estrutura da linguagem C serão 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 saída //coloca nível lógico 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 comentário. Os comentários são importantes para documentar o programa. Podemos adicionar comentários em nosso programa de duas maneiras: Através de comentários de linhas simples: quando queremos comentar apenas uma linha de programa, iniciamos os comentários com os caracteres "//" (igual a linha do programa anterior). Esses tipos de comentário não faz parte da padronização ANSI original, mas atualmente é encontrado em vários compiladores. Através de comentários de múltiplas linhas: podemos comentar linhas ou blocos de código de programa utilizando a sequência de caracteres "/*" para iniciar o comentário e a sequência "*/" para terminar o comentário.

1

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 - Programação em C */ Na próxima linha temos: void main() A declaração main()especifica o nome da função. A função main(), na linguagem C, é sempre a primeira a ser executada e deve ser a única no programa. O programa termina quando for encerrada a execução da função main(). Uma função, em C, nada mais é do que um conjunto de instruções que pode ser executada a partir de qualquer ponto do programa. Utilizamos o sinal de abertura de chave "{" para iniciar uma função e o sinal de fechamento de chave "}" para finalizar a função. Todas as instruções devem estar dentro das chaves que iniciam e terminam a função e são executadas na ordem em que as escrevemos No caso deste programa exemplo, ela não recebe nenhum parâmetro e também não retorna parâmetro nenhum. Isto fica explícito através da palavra-chave void, escrita na frente do programa. As funções e as suas características serão apresentadas em detalhes mais adiante.

Na próxima linha de programa encontramos: trisb = 0; portb = 0; //define portb como saída //coloca nível lógico 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 saída. Se a instrução fosse trisb=1, o PORTB seria configurado como entrada. O comando portb = 0 coloca nivél lógico 0 em RB0 a RB7. As instruções em C são sempre encerradas por um ponto-e-vírgula ( ; ). O ponto-e-vírgula é parte da instrução e não um simples separador, portanto, devemos ao final de cada instrução colocar um ponto-vírgula “;”.

Na próxima linha temos: while(1)

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

2

Microcontroladores
Os comandos a seguir pertencem ao bloco da instrução 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 não temos nenhum comando que interrompa o laço while, os blocos de comandos apresentados serão executados indefinidamente até que o processador seja desligado ou reiniciado. A operação portb.f0 = 1 faz com que o pino RB0 do PORTB seja colocado em nível lógico 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 número 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 função 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 operação portb.f0 = 0 faz com que o pino RB0 do PORTB seja colocado em nível lógico 0;

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

3

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 características são parecidas com a do programa anterior, a única diferença 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 saída //coloca nível lógico 0 em todos os pinos do portb //define portb como saída //coloca nível lógico 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 binário corresponde à (1111 1111)2 e em hexadecimal (FF)16.

Formas e representação numéricas e de caracteres
No compilador mikroC podemos manipular dados do tipo: decimal, binário, hexadecimais e octal. Podemos representar um valor numérico de diversas formas. Para exemplificar, vamos supor que desejamos carregar o valor 187 no registrador PORTB no PIC utilizando o mikroC, acompanhe:

4

Exempo: portb = 25 (25 é representado em decimal) é diferente de portb = 025 (025 é representado em octal) Representação Hexadecimal: Para representar um número em hexadecimal devemos colocar o prefixo 0x (ou 0X) antes do número hexadecimal. POIS O MIKROC INTERPRETARÁ O NÚMERO COMO OCTAL. o RB0 corresponde ao bit menos significativo (LSB) e o RB7 corresponde ao bit mais significativo (MSB).F5 = 0. ou portb = 0B10111011.Microcontroladores Representação decimal: Para representarmos um número em decimal basta colocar seu valor sem nenhuma abreviatura. //representação binária do número 187 decimal //representação binária do número 187 decimal Nos ports. 0 - B - 1 0 1 1 1 0 1 1 RB7 RB6 RB5 RB4 RB3 RB2 RB1 RB0 MSB LSB Manipulação de registradores bit no mikroC Podemos manipular os bits de registradores do PIC de diversas formas no compilador mikroC Exemplo de Manipulação de bits de registradores: Podemos manipular os bits dos registradores do PIC da seguinte maneira: PORTA. portb = 0b10111011. conforme a linha abaixo: portb = 187. 5 . //representação decimal ATENÇÃO: NUNCA DEVEMOS REPRESENTAR UM NÚMERO DECIMAL INICIANDO COM 0 (ZERO). // -->> faz referência ao pino RA5 do PIC. Desta forma. ou portb = 0Xbb. portb = 0xBB. //representação hexadecimal do numero 187 decimal //representação hexadecimal do numero 187 decimal Representação binária: Para representarmos um número em binário devemos colocar o prefixo 0b (ou 0B) antes do número em binário.

F7 = 1. //-->> faz referencia ao bit 0 do registrador TRISB TRISB. Obedeça as representações numéricas solicitadas: Representação decimal: portb = X. ? Representação hexadecimal: portb = X. // --->> faz referência ao pino 0 do PORTB RA2 = 1. RB0 = 0 RB1 = 1 BR2 = 1 RB3 = 0 RB4 = 0 RB5 = 1 RB6 = 0 RB7 = 0 Qual o valor numérico que devemos colocar na instrução abaixo para representar os estados dos pinos do PORTB. ? Representação binária: portb = X.Microcontroladores PORTD.RB0 = 1. Ou acessá-los dessa maneira: obs: não são todos os registradores que permitem acesso direto dos seus bits: RB0 = 0. // --->> faz referência ao pino 0 do PORTA Exercícios 1) Gostaríamos de enviar aos pinos do PORTB os seguintes estados. ? 6 . //-->> faz referência ao pino RD7 do PIC.

Microcontroladores Estrutura de um programa em C Todo programa escrito em C consiste em uma ou mais funções. A seguir veremos um modelo de escrita de um programa em C. [blocos de comentários de grande importância na documentação do programa] [<definições de pre-processamento . O programa principal escrito em C é uma função.finaliza ou fecha o corpo da função A função main() é a principal instrução a ser considerada em um programa escrito na linguagem C e deve estar presente em algum lugar do programa. tendo como particularidade deste fato a possibilidade de construir programas modulares e estruturados. com todas as definições e comentários. Esta função pode ser chamada de sub-rotina do programa.é a primeira e principal função a ser executada . pois é ela que marca o ponto de inicialização do processo de execução do programa. seus comandos e funções de trabalho. void main([<parâmetros>]) { 7 . com a declaração de suas variáveis */ [return ou return() ou return(valor)] } locais.cabeçalhos>] [<declaração das variáveis globais>] [<tipo>] nome_da_funcao([<parâmetros>]) [<declaração de parâmentros>] { /* Este trecho é reservado para o corpo da função_nome. Veja a seguir.inicia ou abre o corpo da função . O C é uma linguagem extremamente estruturada e exige do programador domínio adequado de tal conceito. o menor programa possível de ser escrito em C: main( ) { } em que: main() { } .

h" // inclui o arquivo de cabeçalho . Aqui estão os primeiros comandos que serão executados no programa.h. seus comandos e funções de trabalho. é importante colocarmos sempre os cabeçalhos nos programas.Microcontroladores /* Este trecho é reservado para o corpo da função. Vamos comentar cada bloco de programa: O primeiro bloco: Os comentários gerais [ blocos de comentários de grande importância na documentação do programa] O programador poderá inserir ou não comentários em seu programa. pois é a apresentação do programa.h int a. Exemplo de cabeçalho: /* incluimos em nosso programa as bibliotecas de funções que estão no arquivo minhas_funcoes. int b. O segundo bloco: O cabeçalho [<definições de pre-processamento .*/ #include "minhas_funcoes. */ } Toda a informação situada entre colchetes "[" e "]" indica informações que podem ou não estar presentes em um programa.cabeçalhos>] [<declaração das variáveis globais>] Neste trecho do programa podemos declarar todo o cabeçalho do nosso programa assim como definir variáveis globais que poderão ser utilizadas em todas as funções do nosso programa. //definimos a variável a como inteiro e como sendo global //definimos a variável b como inteiro e como sendo global 8 . com a declaração de suas variáveis locais. Por convenção.

caso não precisemos retornar nenhum valor na função. Esta função pode ser chamada de sub-rotina do programa. Caso não seja. qualquer função será do tipo int por default. cujo objetivo é retornar a função que a chamou um valor de retorno da função. Seu tipo pode ou não ser explicitado. No final da função. Esta função não faz parte da função main() e deverá ser chamada em algum momento pelas função main() ou por outra função para seja executados seus comandos. seus comandos e funções de trabalho. } 9 . com a declaração de suas variáveis */ [return ou return() ou return(valor)] } locais. Podemos no momento da chamada da função enviar parâmetros (estudaremos mais sobre as funções a seguir). Este último bloco trata-se de uma função que carrega o nome nome_da_funcao. return. encontramos o comando return.Microcontroladores O terceiro bloco: As funções de subrotinas [<tipo>] nome_da_funcao([<parâmetros>]) [<declaração de parâmentros>] { /* Este trecho é reservado para o corpo da nome_da_funcao. Não é obrigatório o uso do comando return. Exemplo de função de subrotina: void funcao(void) { portb = ~portb.

Exemplo de função main(): void main() { PORTB = 0. com a declaração de suas variáveis locais. CUJO OBJETIVO É MOSTRAR AO COMPILADOR O TIPO. Nos microcontroladores. PARA COLOCARMOS FUNÇÕES ABAIXO DA FUNÇÃO MAIN() FAZ NECESSÁRIO UTILIZAR OS PROTÓTIPOS DE FUNÇÕES. Para este caso. devemos sempre iniciar a função main() com o modificador de tipo nulo void. como não possuímos um sistema operacional rodando em paralelo com o programa. pois nos computadores PC's existem o sistema operacional que receberá o retorno da função main(). não podemos retornar nenhum valor na função main(). */ } A função main() será a primeira a ser executada pelo processador. A manipulação de programas em linguagem C para microcontroladores é diferente de trabalharmos com programas para PC's. } IMPORTANTE: AS FUNÇÕES DE SUBROTINAS DEVEM SER COLOCADAS ANTES DA FUNÇÃO MAIN().Microcontroladores O quarto bloco: A função main() void main([<parâmetros>]) { /* Este trecho é reservado para o corpo da função. temos o modificador de tipo void que tem a função de declarar que a função main() não deve retornar nenhum valor. PORTB = ~PORTB. Delay_ms(1000). TRISB = 0. NOME E PARÂMETROS DA FUNÇÃO DAS SUBROTINAS. Junto a função main(). seus comandos e funções de trabalho. ISSO OCORRE PORQUE não podemos usar uma função sem declará-la previamente. 10 . Aqui estão os primeiros comandos que serão executados no programa. CASO CONTRÁRIO OCORRERÁ ERRO DE COMPILAÇÃO DO PROGRAMA.

TRISA = 255. 2005. oj. Pwm_Init(5000).Microcontroladores Exercícios Vamos analisar um exemplo de programa em linguagem C disponível no próprio compilador mikroC como exemplo. void InitMain() { PORTB = 0. while (1) P18F8520 BIGPIC3 HS. 10. * Test configuration: MCU: Dev.Board: Oscillator: Ext. oj= 0.00 11 . /********************************************************************************* * Project name: PWM_Test_01 (PWM library Demonstration) * Copyright: (c) MikroElektronika. Pwm_Start(). procure prestar atenção na identificação dos principais blocos de funções desse programa. PORTA = 255. Em princípio. TRISC = 0. *********************************************************************************/ unsigned short j. ADCON1 |= 0x0F. TRISB = 0.0 MHz mikroC v5. Modules: SW: * NOTES: None. PORTC = 0x00. } void main() { initMain(). j= 127. não se preocupe com o funcionamento do programa.

0 MHz mikroC v5.1)) j-. esses textos serão descartados pelo compilador. oj = j.1. Modules: SW: * NOTES: None. 12 . PORTB = oj.Microcontroladores { if (Button(&PORTA. if (Button(&PORTA. 0. 10. No momento da compilação.1. 1.Board: Oscillator: Ext. 2005. * Test configuration: MCU: Dev.. if (oj != j) { Pwm_Change_Duty(j). *********************************************************************************/ P18F8520 BIGPIC3 HS.1)) j++ .00 Este bloco do programa são comentários e são responsável pela parte "documental do programa". } Delay_ms(200). } } /*******************************************************************************/ Resposta: Primeiro bloco: Os comentários /********************************************************************************* * Project name: PWM_Test_01 (PWM library Demonstration) * Copyright: (c) MikroElektronika.

Pwm_Init(5000).1)) j++ .1. if (Button(&PORTA. j oj = 127. } Esta função é uma subrotina do programa. while (1) { if (Button(&PORTA. 0. oj. TRISB = 0.. ADCON1 |= 0x0F. PORTC = 0x00. e nele foram declaradas as variável globais do programa.Microcontroladores Segundo Bloco: O cabeçalho unsigned short j. TRISA = 255. if (oj != j) { Pwm_Change_Duty(j). 1. } 13 .1. Neste trecho do programa é definido o cabeçalho. PORTB = oj. Quarto Bloco: as função main() void main() { initMain(). oj = j. TRISC = 0. PORTA = 255. Pwm_Start(). e foi chamada pelo programador de InitMain(). = 0. Terceiro Bloco: as subrotinas void InitMain() { PORTB = 0.1)) j-.

Com o uso de uma função é preciso alterar apenas dentro da função que se deseja. Para permitir a alteração de um trecho de código de uma forma mais rápida. //. } } Apesar da função main() ser a última na ordem de escrita do programa. void main() { //protótipo de função. obrigatoriamente antecedendo a definição e a chamada da função. Dicas: Porque usar funções de subrotinas ?       Para permitir o reaproveitamento de código já construído(por você ou por outros programadores).Microcontroladores Delay_ms(200). Trata-se de uma instrução geralmente colocada no início do programa ou do arquivo.. Abaixo. um exemplo do uso da declaração do protótipo da função: void minha_rotina (). esta linha de programa deve ser //colocada no topo do programa. O protótipo informa ao compilador o tipo que a função retorna. Para que os blocos do programa não fiquem grandes demais e. por consequência.. Para separar o programa em partes(blocos) que possam ser logicamente compreendidos de forma isolada. Para evitar que um trecho de código que seja repetido várias vezes dentro de um mesmo programa. Para facilitar a leitura do programa-fonte de uma forma mais fácil. o nome da função. mais difíceis de entender. ela será a primeira função a ser executada pelo processador. // aqui esta meu programa principal } //***************** função de subrotina ******************** void minha_rotina() { //aqui esta os comandos da sua subrotina } 14 . bem como os parâmetros que ela recebe. junto com as declarações. Protótipos de Funções Não podemos usar uma função sem declará-la previamente..

Microcontroladores Conforme podemos ver no programa acima. O tipo int é utilizado para representar números inteiros de 8 bits (0 a 255). também chamado de ponto flutuante. ~. etc. Em C. sendo que. ^. O primeiro caractere deve ser uma letra ou um sublinha (_) e os caracteres subsequentes devem ser letras. Para isso. 15 . As palavras reservadas usadas para declarar variáveis desse tipo são char. para identificadores internos.4E-38 a 3. ) valor-total Um identificador não pode conter símbolos (-) Isto quer dizer que se duas variáveis têm em comum os 31 primeiros caracteres e diferem apenas a partir do trigésimo segundo. devemos colocar o protótipo de função (linha de programa com o cabeçalho da função de subrotina) no topo do programa. float/double e void. esses dois identificadores são 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. deve ser utilizado o tipo float. Estes tipos de dados são amplamente usados em programação C. O tipo char e int representam números inteiros e não podem ser utilizados para representar números fracionários. os 31 primeiros são significativos. inteiro. a função de subrotina minha_rotina() ficou depois da função main(). caso contrário teremos erro de compilação pois não podemos utilizar nenhuma função antes de declará-la. nunca por um número. TIPO char int float void TAMANHO EM BITS 8 8 32 0 INTERVALO 0 a 255 0 a 255 3. Cada variável do tipo char pode representar um caractere ASCII. rótulos. Os indetificadores A linguagem C define identificadores como sendo nomes usados para se fazer referência a entidades do programa (variáveis. Por exemplo. não precisamos declarar os protótipos de funções no programa. A tabela a seguir representa o valor e a escala de cada tipo de dado em C. ponto flutuante (float e double) e sem valor. respectivamente.) definidas pelo programador. números ou sublinhas.4E+38 Nenhum Valor O tipo char é utilizado para representação de caracteres ASCII de 8 bits. No caso de colocarmos as funções de subrotinas antes da função main() no programa. Um identificador não pode conter acentos (´. o compilador C não será capaz de distingui-Ias. nesse caso. funções. um identificador é composto de um ou mais caracteres. Eis aqui alguns exemplos de identificadores corretos e incorretos: Corretos cont valor23 totalGeral Incorretos 1cont alô Descrição Um identificador deve sempre começar com uma letra do alfabeto. necessariamente. int.

short.bit 8 .6.bit 32 .bit 32 .bit 16 . é uma região de memória previamente identificada que tem por finalidade armazenar os dados ou informações de um programa por um determinado espaço de tempo.80564774407E38 +/.bit 32 .bit 32 . ou seja. Variável. Esses comandos especiais são chamados de modificadores de tipo e são os seguintes: signed. double e long double são considerados do mesmo tipo no mikroC.bit Nulo 0 à 255 -128 à +127 -128 à +127 0 à 255 -32768 à 32767 0 à 65535 RANGER -2147483648 à 2147483647 0 à 4294967295 +/. e long. Modificadores de Tipo Podemos utilizar comandos especiais do C para obter outros tipos de dados.bit 32 . 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 . 16 .1.1. Declaração de variáveis Definir uma variável é criá-la na memória (alocá-la).17549435082E-38 à +/.80564774407E38 Sem Valor Obs: tipos de float.80564774407E38 +/. unsigned.Microcontroladores O tipo float deve ser evitado ao máximo e restrito apenas às operações que realmente necessitarem de um tipo de dados como este.17549435082E-38 à +/. O modificador short é utilizado para definir uma variável com tamanho menor que o tipo modificado. uma versão reduzida do tipo especificado.bit 16 .1.6.17549435082E-38 à +/. O modificador long é utilizado para ampliar a magnitude de representação do tipo especificado.6. do ponto de vista da área de programação. dar a ela um nome e especificar o tipo de dado que nela vai armazenar. O modificador de tipo signed pode ser utilizado para modificar um tipo base de dados para que ele possa representar um número positivo ou negativo. Uma variável limita-se a armazenar apenas um valor por vez.

bastando apenas separá-las por vírgulas. O tipo deve ser um tipo de dado válido em C tais como: char. unsigned char i. float. com ou sem seus modificadores. Em C. short int y. <tipo> nome_da_variavel. int soma . char a. podemos declarar várias variáveis do mesmo tipo em uma única linha de programa. Basicamente. short e long. Essas variáveis estão fora de qualquer função do programa. unsigned int idade. Exemplo: int contador. Outro aspecto importante da declaração das variáveis é o local onde são declaradas. uma variável pode ser declarada em dois pontos distintos do programa: Variáveis globais: No corpo principal do programa: variáveis declaradas no corpo principal do programa são variáveis globais que podem se acessadas por qualquer função do programa. long caminho. int.j. E nome_da_variavel é o nome da variável adotada pelo programador. unsigned. estado. inclusive a função main(). unsigned valor. signed. void main() { //define a variável global "contador" como inteiro //define a variável global "a" como char //função principal do programa contador = contador + 10 } 17 .Microcontroladores Sintaxe para criação de uma variável em C.k . float salário.

inclusive a função main()). as variáveis locais são descartadas. char a. Variáveis locais: Ao contrário das variáveis globais. Este tipo de manipulação de variáveis somente é possível se declararmos como sendo do tipo GLOBAIS. uma variável local somente existe dentro da função em que foi declarada. necessariamente devemos defini-las no corpo do programa (fora de qualquer função do programa.20.Microcontroladores Repare que as variáveis "contador" e "a" foram definidas fora de qualquer função do programa. } //função principal do programa //define a variável local "contador" como int contador = contador + 10 18 . Mais um exemplo de programa utilizando as variáveis globais: int contador. No momento que ocorre o retorno da função. essas variáveis serão tratadas como variáveis globais e seus dados poderão ser manipulados por qualquer função do programa. } void main() { //define a variável global "contador" como inteiro //define a variável global "a" como char //função de sub-rotina qualquer do programa = contador . void subrotina () { contador a = 100. a = 55. //função principal do programa contador = contador + 10. Isto significa que uma variável local somente existe enquanto a função esta sendo executada. } Repare no programa exemplo acima que as variáveis "contador" e "a" estão sendo manipuladas no corpo da função main() e na função subrotina(). ou seja. Acompanhe o exemplo abaixo: void main() { int contador.

pois esquecem que uma variável local somente tem validade dentro da função que a declarou.. tempo = tempo/2. as variável locais somente terão validade dentro da função que as declaram. certamente o compilador apresentará um erro de compilação nos informando que a variável "tempo" não foi definida. Dentro de cada uma dessas funções foi criada uma variável chamada "tempo" do tipo int. Ao compilarmos este programa. a variável "tempo" da função subrotina() NÃO tem nenhuma ligação com a variável "tempo" da função main(). essa variável é locais e somente tem validade dentro da função que a declarou. "contador" somente poderá ser manipulada no programa dentro da função main(). ou seja. um erro foi cometido. Esse é um erro comum que muitos programadores inexperientes cometem na linguagem C. Acompanhe mais um exemplo de variável local: void subrotina () { int tempo. void subrotina () { tempo = tempo * 2. } //função de sub-rotia qualquer do programa //função principal do programa Repare que a variável "tempo" foi declarada unicamente dentro da função main() e que seus dados estão sendo manipuladas por outra função chamada subrotina(). } void main() { int tempo. } void main() { int tempo. pois são variáveis locais. Veja o código abaixo. neste caso.. a função main() e a função subrotina(). } //função de sub-rotia qualquer do programa //função principal do programa Repare no programa exemplo acima que temos duas funções. 19 .Microcontroladores Repare que a variável "contador" foi declarada (criada) dentro da função main(). tempo = tempo * 2.

trisd = 0. determine quais são as variáveis locais e quais são as variáveis globais: Defina a diferença entre variável local e global: //programa exemplo char contador. portd = 0. } 20 .Microcontroladores EXERCÍCIOS 1. portb = limite. int limite. No programa seguinte. portb = 0. limite = a + contador. Suponhamos que precisamos criar uma variável no programa que assumirá valores de 0 a 100 durante toda a execução do programa. Qual é a diferença entre uma variável unsigned e signed? 3. void funcao(void) { int a. trisb = 0. Qual o tipo de variável que devemos declarar em nosso programa para armazenar o valor apresentado? Obs: Procure definir o tipo de variável mais adequado pois sabemos que se tratando de microcontroladores nossos recursos de memória são limitados 2. utilizaremos o compilador mikroC. portd = b. funcao2(). } void main() { int c. } void funcao2(void) { signed char b. funcao() .

relacionais. portb = a. O operador “=” é utilizado então para atribuir um valor a variável indicada. já que a variável representa uma posição de memória ou um registrador do microcontrolador. adição e subtração. Os unários atuam na inversão de valores. Tipos de Operadores A linguagem C faz uso de diversos operadores. Os operadores Aritméticos: Os operadores aritméticos são utilizados para efetuar determinadas operações matemáticas entre dados e são classificados em duas categorias. portd = a. a = 256. lógicos bit a bit . Os operadores binários atuam em operações de exponenciação. lógicos. sendo binário ou unário. Operador + * / % ++ -adição subtração ou menos unário Multiplicação Divisão Resto da divisão inteira Incremento Decremento Ação 21 . outros. Podemos classifica-los em algumas categoria principais: aritméticos. atribuindo o sinal de positivo ou negativo. } void tempo(void) { int a. divisão. { int a. A linha abaixo mostra a atribuição de um valor decimal à variável “a”.Microcontroladores 4. } Analise o trecho do programa abaixo e descreva as diferenças entre as variáveis int a: void limite(void) Atribuição de valores às variáveis. A linha pode ser interpretada como: a variável “a” recebe o valor 256.

o valor de “variavel_b” é incrementado em 1 unidade: Isso também é válido para o comando de decremento --. são de fácil assimilação. Observe que o valor da variável “variavel _b” é atribuido a variável “variavel_a”. d--. Vejamos um exemplo: 7 / 3 = 2. acompanhe: c = a + b. d = d * d. c = c / a. Exemplo: c = c + 1. O operador de Incremento ++ e decremento --: O operador de incremento e decremento são utilizados para somar 1 ou subtrair 1 de uma variável. sendo o resto igual a 1. Assim. c = a * b. o valor de 7 / 3 = 2 e o valor de 7 % 3 = 1. em uma divisão inteira. em C. a = d . a = (d * a) / c.a. c++. c++. e logo após isso. variavel _a = variavel_b --.Microcontroladores Adição e Subtração Os operadores de adição e subtração são muito simples de serem utilizados. Multiplicação e Divisão Os operadores de multiplicação e de divisão.) //incrementa em 1 unidade o valor da variável c //incrementa em 1 unidade o valor da variável d Acompanhe o exemplo abaixo: variavel_a = variavel_b++.a + c. c = c . O operador % O operador % é utilizado para retornar o resto de uma operação de divisão inteira. 22 . Podemos ter o mesmo resultado da operação acima através do operador de incremento ++. d = d + b. //(equivale a c = c + 1. No exemplo acima a variável C foi incrementada em 1 unidade.

Operador > >= < <= == != Operação realizada maior que maior ou igual a menor que menor ou igual a igual a diferente de Estes operadores serão muito utilizados para construir expressões condicionais. Note que na primeira linha de comando. o valor da variável "b" será igual a 0 e o valor da variável "c" será igual a 2. o valor de "a" será igual a 2. b. Exemplo: int a. b = a ++. o valor de “variavel _b” é decrementado em 1 unidade: Devemos tomar alguns cuidados em C com relação aos operadores de incremento e decremento: vejam. Operadores Relacionais. após a execução dos três comandos. Neste caso. variavel_a = variavel_b ++. c = ++ a. o valor da “variavel_b” é incrementada em 1 antes de ter seu valor atribuído a variável “variavel_a”. Os operadores relacionais servem para comparar expressões. 23 . é diferente de variavel_a = ++ variavel_b. e logo após isso. São muito utilizados para comparar condições de controle do fluxo de execução de programas.Microcontroladores Observe que o valor da variável “variavel _b” é atribuido a variável “variavel _a”. Operadores lógicos ou Booleanos Os operadores lógicos ou booleanos são de grande importância para construções de testes condicionais. Operador && || ! Operação realizada AND (E) OR (OU) NOT (NÃO) Com esses operadores podemos relacionar diversas condições diferentes em um mesmo teste lógico. como veremos mais adiante. a = 0. “variavel_b” é incrementada em 1 depois que atribuiu seu valor a variável “variavel _a”. Na segunda linha. c.

//condição verdadeira de teste: se a variável "c" //for igual a 10 E a variável “b” = 5 então "c" //assumirá o valor 5. //condição verdadeira de teste: se a variável "a" for //igual a 0 (falso). a = 100. Utilizamos muito este o operando AND como "máscara" de um byte. //condição verdadeira de teste: se a variável "c" //for maior que 0 OU "a" for igual a 0 //será igual a variável "a". Operador & | ^ ~ >> << O Operador AND (E) Operação realizada AND (E) OR (OU) XOR (OU exclusiva) NOT (complemento de um) deslocamento à direita deslocamento à esquerda O operador lógico AND realiza operação separadamente para cada bit dos operandos. if (c>0 || a==0) b = a.Microcontroladores Exemplos: if (c = 10 && b = 5) c = 5. a variável "b" assumirá o valor //da variável "c". então "b" Os operadores Bit a Bit Os operadores Bit a Bit são utilizados para realizar operações lógicas entre elementos ou variáveis. Note que estamos utilizando o //operador de negação “!” NOT. para habilitar ou desabilitar somente os bits que desejamos. A operação AND ocorrerá da seguinte maneira: a = 100 ----> AND (&) b = 28 ----> Resultado= 00011100 ___________________ 00000100 //ou 4 decimal 01100100 24 . if (!a) b = c. Veja um exemplo: int a. b = 28. b. a = a & b. por esse motivo a //condição será verdadeira já que a variável "a" //possui valor igual a 0.

b. A operação 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 operação. sua operação também é realizada para cada bit do operando. b. NOT de "a" ----> b = 0b00000001. a = 1. a = a | b. Exemplo: int a. Exemplo: int a. a = 100. b = 28. 0b11111110 25 . pois em uma operação lógica. A operação 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 funções de comparação de valores. b = 28. b = ~a c = ~b A operação NOT ocorrerá da seguinte maneira: a = 0b00000001. NOT de "b" ----> 0b11111110. Exemplo: int a. b. c. o resultado somente será verdadeiro (nível lógico 1) se um e somente um deles for verdadeiro ( nível 1).Microcontroladores O Operador OR (|) O operador OR é muito similar ao operador AND. a = a ^ b. a = 100. b = 1.

enquanto os bits da variável b foram deslocados 5 vezes para a esquerda.valor 10 em binário >> // ----> 00000101 . Exemplo Com sinal (signed) 0xFF56 >> 4. de acordo com o segundo operando da expressão e os bits mais a esquerda são descartados. é atribuído o valor do sinal. No deslocamento para a esquerda (<<) os bits são deslocados de n posições. O deslocamento para a direita de n posições. Teremos como resultado: variável a. /* equals 0x8010. os bits mais a direita são substituídos por zero. a = 10. c. /* equals 0xFFF5 */ n 0b1111111101010110 >> 4. exemplo: int a. //igual a 0b1000000000010000 No deslocamento para a direita (>>) os bits são movidos para a direita tantas vezes quanto indicado pelo segundo operando da expressão. b. // igual a 0b0000000000100000 0x3801 << 4. O bit mais a direita é descartado e é atribuído 0 (zero) ao bit mais a esquerda se o primeiro operando for do tipo sem sinal (unsigned). os valores dos bits da variável "a" foram deslocados 1 vez para a direita. No exemplo acima. // ----> 00001010 . /* equals 0x0020*/ 0b0000000000000001 << 5. b = a >> 1. Deslocar um número n vezes para a esquerda equivale a multiplicar o número por 2 . equivale a dividir o número por 2 . /* equals 0x0FF5 */ 0b1111111101010110 >> 4. //igual a 0b1111111111110101 Sem sinal (unsigned) 0xFF56 >> 4. b = 10. c = b << 5. Exemplo n 0x0001 << 5.valor 5 em binário Observe que o valor após deslocamento passa a ser agora 5 decimal = 00000101 em binário. overflow! */ 0b0011100000000001 << 4.Microcontroladores O Operador de deslocamento << e >> O operador >> desloca para a direita os bits de uma variável um determinado número de vezes e o operador << faz o mesmo para a esquerda. //igual a 0b0000111111110101 26 . caso o tipo seja com sinal (signed).

ou blocos de comandos serão executados. O que significa que uma condição em C só é falsa. } A variável à "a". char b = 0 . Em C. O comando IF (SE) O IF (SE. em português) é uma estrutura de tomada de decisão baseada no resultado lógico de um teste. Qualquer outro valor. o comando. Também é possível executar outro comando ou bloco de comandos no caso da condição ser avaliada como falsa. No comando If. que é diferente de zero (0). é considerado como verdadeiro ou não zero. ou if (condição) { blocos de comandos}. Acompanhe seu formato geral (sintax): if (expressão) comando 1 else comando 2 27 . quando a condição for falsa (0 zero) o comando será ignorado. ( if (a) b--. Consequentemente. qualquer número diferente de zero é tido como verdadeiro. caso a condição seja verdadeira (diferente de zero).else. if (a) b--. ).Microcontroladores Estruturas de Controle As estruturas de controle são usadas nos programas em lugares em que necessitamos que a máquina faça repetidas operações ou necessite de tomadas de decisões. quando o resultado da operação utilizada para testar a condição for igual a zero (0). Sua forma geral é: if (condição) comando. caso contrário. foi atribuído o valor 10. para isso utilizamos os recursos do comando if . Exemplo: void main() { char a = 10. mesmo negativo. a o comando if será executado e a condição de decremento da variável b será executado.

//se a expressão (a + b) > (b + d) for //verdadeira. //se a expressão a!=b (diferente) for //verdadeira. então a linha de comando z = 20 será executada. 28 . a //variável "b" assume o valor 10 if (a != b) b = 55. else z = 20.Microcontroladores Exemplo: if (x > 5) z = 10. Todos os operadores do C podem ser incluídos no teste de uma condição. caso a condição seja verdadeira. A linha de comando if (x > 5) tem por função verificar se condição x>5 é verdadeira. Para testar a condição de uma variável qualquer. Caso a condição do comando if seja falsa. //se a expressão a < b for verdadeira. a //variável "b" assume o valor da "a" if (b < a) b = 10. expressões válidas da linguagem C podem ser avaliadas para a geração de um resultado booleano na estrutura if. c = 10. caso seja verdadeira. a variável "b" assume o //valor 55 if ( (a + b) > (b + d) ) b++. //se a expressão a > b for verdadeira. Acompanhe: if (a == b) é diferente de if (a = b) c = 10. Exemplo: if (a > b) b = a. a variável "b" será //incrementada em uma unidade. a variável "c" assumirá o valor 10. ou seja. A condição (a == b) faz uma comparação entre as duas variáveis. a linha de programa z = 10 será executada. se "x" for menor que 5. utilizamos o operador relacional de igualdade (==). Observações importantes: O operador de atribuição de igualdade em C (=) é diferente do operador relacional de igualdade (==). As expressões seguintes são válidas e seus resultados dependerão do valor de suas variáveis.

Os arranjos são criados bastando colocar estruturas if aninhadas com outras estruturas if. else if (condição4) declaração 4. Exemplo: if (portb == portc) { a++. else if (condição3) declaração 3. irá primeiramente atribuir a variável "a" o valor contido em "b". else. Exemplo: void main() { int contador = 10. faz necessário o uso dos símbolos abre. O compilador ao compilar este comando.chaves ({) efecha-chaves (}). else if (condição2) declaração 2.f0 = 1. possui uma expressão de atribuição de igualdade (a = b). caso seja verdadeiro o resultado (diferente de zero). verificará se condição não é zero. if. else. No comando If para adicionarmos blocos de programas. if (contador > sinal) sinal++. else if (contador == sinal) sinal = 0. a variável "c" assumirá o valor 10. Seu formato geral é: if (condição1) declaração 1. e depois disso. } //blocos de comandos A estrutura if. else if (contador < sinal) sinal--.Microcontroladores O comando If seguinte. int sinal = 5. if Podemos criar arranjos (nesting) de comandos através da estrutura if. } 29 . portb. d = c + e.

Microcontroladores Podemos também executar blocos de comandos utilizando os recursos das chaves ( { e } ). Forma geral do comando switch switch (variável) { case constante1: declaração1A. só aceita constante. case constante2: 30 . declaração1N. declaração1B. int sinal = 5. O comando Switch O comando switch é uma forma mais clara e elegante de tomar decisão dentro de um programa em C. break. Iremos utilizá-la em vários programas que desenvolveremos durante o curso. contador } else if (contador == sinal) sinal = 0. contador = 20. Diferente do comando if. a estrutura switch não aceita expressão para a tomada de decisão. if (contador > sinal) { sinal++. //utilização de blocos de comando na estrutura if-else-if A estrutura if é uma das mais utilizadas para tomada de decisões lógicas. } = 15. } else if (contador < sinal) { sinal--. Exemplo: void main() { int contador = 10.

break. então os comandos especificados pela cláusula default serão executados. A cláusula default é o último comando switch. } O valor da variável no comando switch é comparada com as constantes especificadas pela cláusula case. default. (decrementa a variável contador). A cláusula Break possui a função de encerrar uma sequencia de comandos de uma cláusula case. Caso não tenha nenhuma constante com o mesmo valor da variável. consequentemente o comando que será executado no exemplo acima é case 10: contador--. default: sinal = 0. case 1: sinal = 2. case 10: contador--. declaração2B. declaração_default.Microcontroladores declaração2A. break. break. switch(contador) { case 2: sinal++. int sinal = 5. a variável contador será comparada às constantes 2. Como a variável contador possui o valor 10. 1 e 10. os comandos seguinte à cláusula case serão executados. declaração2N. Caso a variável e a constante possuam valores iguais. } } No exemplo de acima. 31 . Exemplo: void main() { int contador = 10. break.

O comando For O laço for é utilizado quando necessitamos de um ciclo de repetições controlado. Existem basicamente três tipos de estruturas de repetição na linguagem C: for while do . a variável de controle será incrementada ou decrementada no valor programado no incremento.incremento ) comando. A cada ciclo que é executado o laço for. diferenciando apenas o momento que é analisado a condição. incremento: valor incrementado em a cada repetição do laço for. Antes de serem executados os comandos do laço for-next. 32 . condição . } Onde: inicialização: expressão válida utilizada normalmente para inicialização da variável de controle do laço for. o laço for permanecerá em execução. são executados os comandos do laço. enquanto esta condição foi verdadeira . O comando do . pois em sua declaração podemos inicializar e incrementar ou decrementar a variável de controle. primeiramente é avaliada a condição do teste.Microcontroladores Estruturas de repetição Os laços de repetição servem para repetir uma ou mais vezes determinada instrução ou blocos de instruções. normalmente utilizando uma variável de controle da contagem. Caso seja verdadeira. comandoA1 comandoA2 .. incremento ) { ..while é similar à estrutura while.. condição: condição que decide pela continuidade ou não do laço de repetição..while A estrutura for basicamente é utilizada para laços finitos de contagem. A estrutura while basicamente é utilizada para repetição de um determinado conjunto de instrução enquanto uma condição for verdadeira. Veja a estrutura do comando for : for (inicialização. ou for (inicialização .condição.

A estrutura de repetição for termina quando a condição “contador <= 10” for falsa. caso seja verdadeira. atraso < 1000 . O grande benefício do laço for é sua flexibilidade. Na estrutura anterior. Observe o fragmento de programa seguinte válido dentro do loop for: 33 . a variável contador inicialmente é carregada com o valor 0 (zero). que no nosso exemplo é 1 unidade. Um exemplo simples de aplicação do laço for é a criação de pequenos tempos de atrasos (delays).Microcontroladores Exemplo: int contador. v == d . mesmo que essas expressões não tenham relacionamento com o laço de repetição diretamente. A condição “v<d” é verificada 3. { Comando A Comando B } v++) Este exemplo funciona da seguinte maneira: 1. for (contador = 0 . contador ++ ) portb = contador. Volta ao passo 2. e mais uma vez a condição “contador <= 10” é verificada. o bloco de comandos “Comando A e Comando B” é executado. contador <= 10 . Se a condição for falsa. 5. 4. for (atraso = 0 . O laço for acima faz com que o processamento fique incrementando constantemente a variável atraso de 1 até que esta variável seja igual ao valor 1000. a variável contador assume um valor maior do que 10. os comandos do laço for são executados novamente. os comandos do laço for são executados (o valor da variável contador é escrita no registrador portb). ou seja. Após a execução de todos os comandos presentes no laço for. atraso++). int atraso. 2. for (v = 0 . pois aceita qualquer expressão válida em C. A variável v tem seu valor incrementado em 1 unidade. d. Se a condição for verdadeira. a variável contador é incrementada no passo do valor do incremento. A variável v recebe o valor 0. 6. se for verdadeira (a variável contador for menor ou igual a 10). em seguida a condição é verificada. o laço de repetição for é finalizado. Exemplo: int v.

34 . Exemplo: Aproveitando que estamos estudando as estruturas do laço de repetição for. poderíamos ter utilizado uma variável tipo “long”. (n < 100) && portb.contador2<1000.Microcontroladores for (n = 0 . Se o pino RB0 em algum momento do laço cair para nível lógico baixo. * //****************************************************************** void atraso(void) { int contador1. mas optamos pela uma variável do tipo “int” para que você entenda a construção de dois laços for encadeados. Para acomodar um número dessa grandeza. Para contar até 100. o loop será imediatamente encerrado. vamos elaborar um programa que pisca um LED conectado ao pino RB0 do PIC utilizando os recursos do laço for. n++) No exemplo acima a variável n será incrementada 100 vezes. //****************************************************************** //* programa de perda de tempo utilizando o laço de repetição for.contador1<100.000.contador2++). for(contador1=0. contador2.contador1++) } //fim da rotina de atraso //laço de repetição for for(contador2=0. desde que o pino RB0 permaneça em estado lógico alto.000 é necessário termos uma variável que conte até 100 e outra até 1000 (100 * 1000 = 100. 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). // rotina de perda de tempo(atraso).f0 .

portb. pois. declaração 2.f0 = ~port. o programa do PIC não tem para onde sair. Caso a expressão seja verdadeira. } } //chama rotina de perda de tempo // inverte os estados do bit 0 do portb do PIC O comando while Muitos dos programadores iniciantes não sabem do que iremos comentar agora. declaração n. A sintax do comando while é: while (expressão) declaração A estrutura while verifica inicialmente se a condição de teste (expressão) é verdadeira. Os microcontroladores no geral não possuem sistemas operacionais. se for verdadeira. pois não tem quem receba os valores de retorno da função principal main(). o laço while é finalizado. Exemplo: void main() { while (1) { declaração 1. se for falsa.Microcontroladores void main() { trisd = 0. } } //condição a ser testada. Esse é um dos motivos da função principal main() dos programa para microcontroladores serem tipo void (valor nulo). é executada novamente a expressão ou o bloco de comandos. //verdadeira (1). Isso é necessário.f0. os programas que desenvolvemos para os microcontroladores PIC devem rodar eternamente. é verificado novamente se a condição de teste é verdadeira. devendo ficar em operação. while(1) { atraso(). a declaração poderá ser também um bloco de comandos delimitados por chaves ( { } ). Neste exemplo a condição sempre será 35 . ou possuírem mecanismos que paralise a operação da CPU em alguns momentos. por não possuir sistema operacional. O comando while é o comando ideal criar loops infinitos no nosso programa. a declaração será executada. de preferência eterna. Ao retornar para o início do laço.

while sejam executadas ao menos uma vez. formato geral: do declaração while (condição). 36 . que testam as condições no início de cada ciclo. Isso faz com que as instruções contidas no interior do laço do.while O comando do-while forma uma estrutura de repetição diferente dos comandos while e for estudado anteriormente. Caso a condição teste seja falsa (igual a zero).Microcontroladores Veja outro exemplo de programa: void main() { int a = 25. O comando do . while (a == 5) { a++. contrário dos outros laços que estudamos. comando 2. a não ser que em algum momento esta condição se torne verdadeira. Na estrutura do-while a condição de teste é efetuada somente na parte final do loop. } while (condição de teste). portb = a. o laço de repetição é finalizado. Sua diferença fundamental com relação aos tradicionais laços while e for esta no fato da avaliação da condição de teste ser no final do laço de repetição. neste caso os comandos do laço nunca serão executados. ou do { comando 1. caso contrário o bloco que está na estrutura seria novamente executado até que a condição teste seja atendida. } } Repare que no exemplo acima o valor da condição do laço while é falsa. ou seja. até que a = 5.

é utilizado para interromper (quebrar) qualquer laço de repetição instantaneamente. } //enquanto a variável a for menor que 100 //a rotina do-while será executada. while. do { a++. portb = ~portb. 37 . //incrementa a variável A em uma unidade //interrompe a execução do laço de repetição do-while //inverte os estados dos portd O comando break é valido para os laços do-while. o laço de repetição é finalizado. break. Exemplo: void main() { int a = 0. //incrementa a variável “a” de uma unidade //inverte os estados do portb //declara a variável “a” como inteiro com o valor 0 O comando break e continue break O comando break. } while(a < 100). ao encontrar o comando break. No momento da execução do loop.Microcontroladores Exemplo: void main() { int a = 0. for e case. portd = ~portd. } while(a < 100). do { a++. } //enquanto a < 100 permanece no loop do-while. na linguagem C.

38 . //incrementa a variável “a” de uma unidade //retorna para o inicio do laço de repetição //inverte os estados dos portd No exemplo de programa acima. pois. os comandos abaixo de continue não serão executados. } //enquanto a variável “a” for menor que 100 a rotina //do-while será executada. automaticamente o programa será redirecionado para o cabeçalho do laço de repetição independente de qualquer estado de variáveis. continue.Microcontroladores continue O comando continue reinicia novamente o teste da condição do laço de repetição. Exemplo: void main() { int a = 0. for e case. do { a++. toda a vez que for executado o comando continue. os comandos seguintes não serão executados no laço. O comando continue é valido para os laços do-while. Toda a vez que no laço for encontrado o comando continue. } while(a < 100). while. portd = ~portd.

ou através de software (rotina de “debouncing”). o bouncing. através da inclusão de um circuito de “dedouncing” (latch) juntamente com o teclado. e servem para manter definido o nível lógico nas entradas como “um”.f7=0. 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. que pode ser efetuado por hardware. então. ao pressionarmos uma das teclas que se encontra ligada entre o terminal do PIC e o terra do circuito. No caso do PIC16F268A. toda tecla sofre de um mal. //habilita os pull-ups internos do portb Voltando às teclas. o portb possui resistores internos de pull-up que podem ser habilitados ou desabilitados através do bit 7 do registrador “OPTION_REG”. são denominados resistores de pull-up. 39 . ao utilizarmos teclas nos projetos devemos levar em conta a possibilidade da existência do bouncing e providenciarmos sua eliminação.Microcontroladores Utilização 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 é indispensável a utilização de teclas como ilustrado na figura acima. Os resistores ligados entre os terminais do PIC e o positivo da fonte. o nível lógico muda de “um” para “zero”.

isto é. pode ser de 0 a 7. estado_de_ativação). evitando assim a leitura falsa dela.Microcontroladores Boucing é o efeito mecânico de rebatimento que a tecla sofre logo após ser pressionada. 1. 10. Esse intervalo permite que o fenômeno do rebatimento termine naturalmente. o qual provoca a leitura falsa da tecla. pin = é o pino onde esta ligado a tecla no PIC. pin. Função button A função button tem como sintaxe: Button(&port. 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. delay de debounce de 10 milisegundos e é acionada em nível lógico 0 (zero). pode ser PORTA. onde: &port = port onde esta ligado a tecla. O retorno da função button é: valor 0 (tecla não pressionada) ou 1 (tecla pressionada). A função button automaticamente configura os respectivo port como entrada. PORTD ou PORTE. timer = tempo de debounce em escala de milisegundos. 0) A partir da configuração da função button acima. estado_de_ativação = determina se a tecla vai ser ativada em nível 0 ou em 1. PORTB. descobrimos que a tecla que será lida está conectada ao portb. Tempo aproximado de 25 ms. pino RB0. Exemplo: button (&portb. PORTC. Vejamos um exemplo de programa utilizando a função 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 . o rebatimento faz com que a tecla seja lida mais de uma vez. No MikroC podemos manipular teclados através de uma simples função chamada button. time.

f4 = ~porb. 0) Porta onde está ligada a tecla Pino onde esta ligada a tecla. A função button foi programada da seguinte forma: button(&PORTB. 20.Microcontroladores Primeiro Programa: Conectado ao PIC temos uma tecla (push-button) e um led. Delay de 20ms para correção do efeito mecânico da tecla (ricochete). iremos fazer um programa bem simples utilizando a função button. o led será apagado. portb. } } while(1). e ao pressionar a tecla novamente. 0. ou seja. //configura portb como saída (leds) Criamos um laço de repetição através do comando do-while. trisb. 20. neste caso é o pino RB0 Tecla acionada com nível lógico zero Debouncing de 20ms. do { if (button(&PORTB. pois tráta-se de um led. o led será acesso.f4 = 0. cujo objetivo é fazer com que o microcontrolador sempre esteja executando os comandos do laço.f4. 41 . trisb. o led 1 deverá alterar seu estado lógico.f0 = 1. veja: void main() { trisb.f4 = 0. se o led estiver acesso. Para realizar essa tarefa. 0)) { delay_ms(200). ao pressionar e soltar a tecla S1. } //delay de 200 milisegundos //inverte o estado do led //se a tecla S1 estiver pressionada o comando //if será executado //configura pino RB4 como saída (leds) //configura pino RB0 (tecla) como entrada No programa acima configuramos o pino RD0 como saída. Repare que o led é ligado com nivel lógico 1. 0. Devemos programar delay para correção de bouncing de 20 milisegundos. Desejamos que toda vez que pressionarmos e soltemos a tecla S1.

temos que pressionar e soltar a tecla para executar a inversão do estado do led. a condição if sempre será verdadeira e então os comandos contidos no bloco logo após o if serão executados. e isso ocorrerá quando a tecla for pressionada. pois caso deixemos a tecla pressionada. cujo objetivo //é armazenar um estado. pois iremos //ligar/desligar o led. Programa: /* Programa de leitura de tecla. Este programa tem por objetivo ler o estado de uma tecla para ligar/desligar um led. 0)) { delay_ms(200).f4 int estado_antigo.f0 = 1. o estado lógico do led somente mudará um vez. } //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. se deixarmos a tecla pressionada. Segundo Programa: Para corrigir o problema do programa anterior.Microcontroladores Acompanhe o trecho de programa seguinte: if (button(&PORTB. O tempo de debouncing programado deverá ser de 20 milisegundos.f4 = ~porb. a função button nos retornará o valor 0 (falso). //define uma variável de controle. trisb. 42 . portb. //configura o pino Rb4 como saida. O programa apresentado acima possui um problema. 20.f4. vamos elaborar um novo programa que acenda e apague o led 1 da figudo circuito anterior para cada toque que dermos no teclado. A partir disso concluímos que a condição if somente será verdadeira caso o retorno da função button for verdadeiro.f4 = 0. */ #define led1 portb. fazendo com que o led acenda e apague enquanto a tecla estiver pressionada. //configura pino RB0 (tecla) como entrada //a diretiva define atribui ao pino RB4 o nome led1. 0. e caso não venhamos a pressionar a tecla. ou seja. ao executar a função button. void main() { trisb. teremos como retorno valor 1 (verdadeiro).

//a variável estado_antigo //= 1. //verifica se a tecla foi //solta Estudo detalhado do programa: Primeira parte: Comentário Nesta primeira parte do programa.20. 20. o compilador sabe que se refere ao pino portb. } } while(1). partir deste ponto do programa. acrescentamos comentário de apresentação do programa. //se a tecla fo pressionada.Microcontroladores do { if (Button(&PORTB. e substituirá na compilação este novo nome pelo endereço físico de memória do pino RB4.f4 (RB4).0. Exemplo: #define display1 portb.f0 //a diretiva define atribui ao pino RB0 o nome display1. #define led2 porta.1)) { led1 = ~led1. A diretiva #define atribui o nome led1 ao pino RD0 do PIC. */ Segunda parte: a diretiva define Até este ponto do curso não estudamos a utilização da diretiva define. 0)) estado_antigo = 1. /* Programa de leitura de tecla. 0. toda vez que utilizarmos o nome led1. Curso: Microcontroladores PIC programação em C Este programa tem por objetivo ler o estado de uma tecla para ligar/desligar um led. Veja o comando: #define led1 portb. 43 . if (estado_antigo==1&&Button(&PORTB. } //inverte o estado do led 1. estado_antigo = 0.f4 //a diretiva define atribui ao pino RB4 o nome led1. Esta diretiva tem por função atribuir a uma constante ou registrador um novo nome.f1 void main() { //a diretiva define atribui ao pino Ra1 o nome led2. //inverte o valor da variável estado_antigo para o próximo //acionamento.

Terceira parte: definição da variável Definimos uma variável do tipo int chamada estado_antigo. temos um led. Conectado ao pino RB4. faz necessário enviar nível lógico 1 a este pino. o registrador TRIS do PIC. e para lermos essa tecla é necessário configurar este pino como entrada. //configura o pino RB4 como saída. A função button se encarrega de configurar esses registradores de sentido para nós. cujo objetivo é armazenar //um estado.b4 = 0. void main() { Quinta parte: programando as portas como entrada ou saida Como já vimos anteriormente. Neste programa temos uma tecla conectada ao pino RB0. pois iremos ligar/desligar o led. tem por função informar a direção (leitura ou escrita) dos pinos da porta. 44 . pois. Quarta parte: a função principal A função principal main() é a primeira a ser executada no programa em C. Repare que a função main() acompanha um modificador de tipo void que tem como objetivo informar ao compilador que esta função é nula e não possui retorno de dados. pois iremos ligar/desligar //o led. não tem pra quem retornar os dados pois tratá-se da função principal. trisd. //define uma variável de controle. } //configura o pino RA1 como saída. int estado_antigo. display1 = 0.Microcontroladores trisa = 0. Esta variável tem por função fazer com que o led seja ligado/desligado somente com um unico toque na tecla. led2 = 1. então devemos configurar este pino como sáida. evitando que ao deixarmos a tecla pressionada os comandos if sejam sempre executados. Para acionar este led.

Para lermos a tecla. a //variável estado_antigo = 1. 0. e ligar ou apagar o led 1 conectado ao pino RD0. Devemos criar um programa que "amarre" o microcontrolador a sempre executar suas funções. } } while(1). 0. if (estado_antigo && Button(&PORTB. neste caso. 1)) { led1 = ~led1. //verifica se a tecla foi //solta Repare que a condição de teste do laço de repetição do-while será sempre verdadeira (while(1)). estado_antigo = 0. Sétima parte: Rotina de tomada de decisão e função button Os comandos seguintes tem por objetivo ler o estado da tecla S1. //inverte o valor da variável estado_antigo para o próximo //acionamento. em conjunto com o comando de tomada de decisão IF. Sabemos que o comando if somente será executado se a condição de teste for verdadeira. do { if (Button(&PORTB. 0)) estado_antigo = 1. No nosso programa exemplo utilizamos os recursos do laço de repetição do while. mesmo que essa rotina seja um comando sem saída (while(1). } //inverte o estado do led 1. 20.). //se a tecla for pressionada. 45 .Microcontroladores Sexta parte: Rotina de loop Lembre-se que devemos sempre manter o microcontrolador executando alguma rotina. //se a tecla fo pressionada. 0. a variável estado_antigo somente será executada se a função button for verdadeira. para isso é necessário que a tecla seja pressionada. utilizamos a função do mikroC: Button. 20. Vejamos: if (Button(&PORTB. //a variável estado_antigo //= 1. 20. 0)) estado_antigo = 1. conectada ao pino RB0 do PIC.

//inverte o valor da variável estado_antigo //para o próximo acionamento. 20. cujo objetivo é verificar se a tecla foi solta ou não. 1)). Os comandos seguintes somente serão executados se a condição if for verdadeira. e para isso faz-se necessário que a variável estado_antigo seja igual a 1 e que o retorno da função Button seja verdadeira. //inverte o estado do led 1. 1)) { //verifica se a tecla //foi solta Nesta linha de programa efetuamos uma operação AND (E) entre a variável estado_antigo e o retorno da função Button.Microcontroladores Outro comando: if (estado_antigo == 1 && Button(&PORTB. 20. Oitava parte: Inversão do estado do led e resset de variável de estado led1 = ~led1. a tecla tem que estar solta. 0. Repare que nesta segunda função Button o estado lógico de acionamento da tecla passa a ser 1 (Button(&PORTB. 0. estado_antigo = 0. 46 . ou seja. essa alteração indica que somente teremos a condição de retorno verdadeira (1). caso a tecla não esteja pressionada. contrário da função Button da linha anterior.

Sign up to vote on this title
UsefulNot useful