Baixe o app para aproveitar ainda mais
Prévia do material em texto
Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 1 O Mundo dos Microcontroladores A situação que nos encontramos hoje no campo de microcontroladores teve seu início a partir do desenvolvimento da tecnologia de circuitos integrados. Esse desenvolvimento permitiu que pudéssemos instalar centenas de milhares de transistores em um único chip, que foi a precondição para a possibilidade de fabricação de microprocessadores. Os primeiros computadores foram então desenvolvidos a partir dos microprocessadores, adicionando periféricos externos, tais como memórias, linhas de entrada e saída, temporizadores e outros circuitos. Aumentando ainda mais a densidade de elementos dentro dos chips resultou no desenvolvimento de circuitos que continham ambos, processador e periféricos. Isto mostra como o primeiro chip contendo um microcomputador chamado mais tarde de microcontrolador foi desenvolvido. 1.1 Introdução Novatos em eletrônica geralmente pensam que o microcontrolador é o mesmo que microprocessador. Isso não é verdade. Eles diferem entre si em muitos aspectos. A diferença primeira e mais importante em favor do microcontrolador é a sua funcionalidade. Para que o microprocessador possa ser usado, outros componentes, como a memória por exemplo, devem ser adicionados a ele. Mesmo sendo considerada uma poderosa máquina de computação, não é capaz, por si só, de se comunicar com o ambiente externo. A fim de permitir que o microprocessador se comunique com o ambiente externo, circuitos especiais devem ser usados. Isto é como era no princípio e continua sendo até hoje. Por outro lado, o microcontrolador foi projetado para ser tudo isso em um único chip. Não são necessários outros componente externos para a sua aplicação, pois todos os circuitos necessários já estão incluídos no mesmo, dentro de um único chip. Isso economiza tempo e espaço necessários para projetar um dispositivo. Na figura 1.1 podem ser vistos os componentes periféricos inclusos no chip de um microcontrolador de uso geral. Observe que o microcontrolador é formado basicamente pelo microprocessador, responsável pelo controle de todo o funcionamento do chip, e dos circuitos periféricos como memórias, conversores A/D, circuito oscilador, etc. Capítulo 1 Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 2 Figura 1.1 – Elementos construtivos de um microcontrolador de uso geral. Dispositivos eletrônicos capazes de controlar um pequeno submarino, um guindaste ou um elevador já são construídos em um único chip. Os microcontroladores oferecem uma ampla gama de aplicações e, normalmente, apenas algumas delas são usadas. É critério do projetista decidir o que ele quer que o microcontrolador faça no seu produto. Para isso, o projetista descarrega um programa contendo instruções adequadas para que o microcontrolador execute a ação desejada. Antes de conceber o seu produto final, seu funcionamento deve ser testado por um simulador. Se tudo funcionar bem, o microcontrolador é inserido no dispositivo. Se há necessidade de alterações no comportamento do produto, melhorias ou atualizações, basta fazê-lo. Até quando? Até que sinta-se satisfeito. Na figura 1.2 pode ser observado, de uma forma cômica, o fluxo de desenvolvimento de um projeto que utiliza microcontroladores como principal elemento. A rigor, um projeto baseado em microcontroladores consiste no estudo do dispositivo a ser controlado pelo microcontrolador. Baseado nas características desse dispositivo, o projetista deve identificar as necessidades de hardware tais como número de entradas/saídas, temporizadores, conversores A/D, etc, para o seu controle. Com as necessidades de hardware identificadas, o projetista deve escolher um microcontrolador que possua aqueles requisitos e que satisfaça às suas necessidades. Usando um computador pessoal e uma linguagem de programação de alto nível, deve-se escrever um programa para rodar no microcontrolador. Enquanto programa, usa-se o computador para fazer simulações e testar o seu funcionamento. O programa escrito deve ser convertido em código que pode ser interpretado pelo microcontrolador. Com o auxílio de um programador, esse código deve ser descarregado dentro da memória do microcontrolador. Uma vez que o microcontrolador possua em sua memória as instruções a serem executadas, basta instalá-lo no dispositivo a ser controlado. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 3 Figura 1.2 – Fluxo de desenvolvimento de um projeto utilizando microcontroladores. Diga tchau para a sua família por alguns dias Alimente seus animais de estimação Estude a máquina a ser controlada pelo microcontrolador Procure pelas características disponíveis em cada microcontrolador Escolha as que atendem suas necessidades Projete e construa um hardware para conectar o microcontrolador ao mundo externo Use um computador para escrever o programa a ser executado Converta o programa em código de máquina e descarregue esse código na memória do microcontrolador Insira o microcontrolador já programado no dispositivo a ser controlado Aproveite o sucesso e comece a pensar em novos projetos Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 4 1.2 Sistemas numéricos Sistema de Numeração Decimal O sistema decimal é um sistema de numeração posicional que utiliza a base dez. Baseia-se em uma numeração de posição, onde os dez algarismos indo-arábicos: 0 1 2 3 4 5 6 7 8 9 servem para contar unidades, dezenas, centenas, etc. da direita para a esquerda. Contrariamente à numeração romana, o algarismo árabe tem um valor diferente segundo sua posição no número: assim, em 111, o primeiro algarismo significa 100, o segundo algarismo 10 e o terceiro 1, enquanto que em VIII (oito em numeração romana) os três I significam todos 1. Assim: Da direita para esquerda, o primeiro dígito representa as unidades, o segundo as dezenas, o terceiro as centenas e assim sucessivamente. No sistema decimal o símbolo 0 (zero) posicionado à esquerda do número escrito não altera seu valor representativo. Assim: 1; 01; 001 ou 0001 representam a mesma grandeza, neste caso a unidade. O símbolo zero posto à direita implica multiplicar a grandeza pela base, ou seja, por 10 (dez). Sistema de Numeração Binário O que aconteceria se apenas dois dígitos fossem usados - 0 e 1? Ou se não soubéssemos como determinar se algo é 3 ou 5 vezes maior do que qualquer outra coisa? Ou se estivéssemos restritos a comparar dois tamanhos, ou seja, se só podemos afirmar que algo existe (1) ou não existe (0)? A resposta é "nada de especial". Gostaríamos de continuar a usar os números da mesma forma como o fazemos agora, mas seria um pouco diferente. Por exemplo: 11011010. Quantas páginas de um livro são representadas pelo número 11011010? A fim de aprender isso, você apenas tem que seguir a mesma lógica que no exemplo anterior, mas em ordem inversa. Tenha em mente que tudo isso é sobre matemática apenas com dois dígitos, 0 e 1, ou seja, a base do sistema de número 2 (sistema de números binários). O sistema binário ou base 2, é um sistema de numeração posicional em que todas as quantidades se representam com base em dois números, com o que se dispõe das cifras: zero e um (0 e 1). Os computadores digitais, e também os microcontroladores trabalham internamente com dois níveis de tensão, visto que o seu sistema de numeração natural é o sistema binário (ligado, desligado). O sistema binário é a base para a Álgebra booleana (de George Boole - matemático inglês), que permite fazer operaçõeslógicas e aritméticas usando-se apenas dois dígitos ou dois estados (sim e não, falso e verdadeiro, tudo ou nada, 1 e 0, ligado e desligado). Toda a eletrônica digital e computação estão baseadas nesse sistema binário e na lógica de Boole, que permite representar por circuitos eletrônicos digitais (portas lógicas) os números, caracteres, realizar operações lógicas e aritméticas. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 5 Sistema de Numeração Hexadecimal No início do desenvolvimento dos computadores foi percebido que as pessoas tinham muitas dificuldades em lidar com números binários. Por esta razão, um novo sistema, com 16 símbolos diferentes foi criado. É chamado sistema de numeração hexadecimal, consistindo de dez dígitos que estamos acostumados a usar(0, 1, 2, 3, ... 9) e mais seis letras do alfabeto A, B, C, D, E e F. O maior número que pode ser representado por 4 dígitos binários é o número 1111. Ele corresponde ao número 15 no sistema decimal, enquanto que no sistema hexadecimal é representado por um único dígito, ‘F’. É o maior número de 1 dígito no sistema hexadecimal. O maior número escrito com oito dígitos binários é, ao mesmo tempo o maior número de 2 dígitos hexadecimais. Na figura 1.3 pode ser observado um exemplo da correlação existente entre números no sistema binário e no sistema hexadecimal. Figura 1.3 – Mesmo número sendo representado por 8 dígitos binários e 2 dois dígitos hexadecimais. Conversão entre Sistemas de Numeração O sistema numérico binário é mais comumente usado, o sistema decimal é mais compreensível, enquanto o sistema hexadecimal é algo entre eles. Portanto, é muito importante aprender como converter números de um sistema numérico para outro, ou seja, como transformar uma sequência de zeros e uns em valores compreensíveis. Conversão binário-decimal Dígitos em um número binário têm valores diferentes dependendo da posição que eles ocupam no número. Além disso, cada posição pode conter 1 ou 0 e seu valor pode ser facilmente determinado através da contagem de sua posição da direita para esquerda. Para fazer a conversão de um número binário para decimal é necessário multiplicar os valores dos dígitos correspondentes (0 ou 1) pelo seu respectivo peso na base binária e adicionar todos os resultados. Veja o exemplo abaixo: Note-se que, para representar números decimais de 0 a 3, você precisará usar apenas dois dígitos binários. Para números maiores, dígitos binários extras devem ser usados. Assim, a fim de representar números decimais 0-7 você precisa de três dígitos Binário de 8 dígitos Mesmo número no sistema hexadecimal Número binário Mesmo número no sistema decimal Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 6 binários, conforme o exemplo acima. Para os números 0-15 você precisa de quatro dígitos, etc. Com n dígitos binários é possível representar 2n valores decimais. Para saber qual o maior número decimal que pode ser representado com n dígitos binários, simplesmente calcule o valor de 2n-1. Assim, por exemplo, se n= 4: 24-1 = 16-1 = 15 Assim, usando 4 dígitos binários, é possível representar números decimais de 0 a 15, o que equivale a 16 diferentes valores no total. Conversão hexadecimal-decimal A fim de fazer a conversão de um número hexadecimal em decimal, cada dígito hexadecimal deve ser multiplicado pelo número 16 elevado pelo seu valor de posição, semelhante ao que foi feito na base binária. Após isto, somam-se os valores obtidos individualmente. Por exemplo: Conversão hexadecimal-binário Não é necessário realizar nenhum cálculo a fim de converter números de hexadecimal para binário. Os dígitos hexadecimais são simplesmente substituídos por dígitos binários adequados. Desde que o máximo valor representado por um dígito hexadecimal é equivalente ao número decimal 15, nós precisamos usar quatro dígitos binários para representar um dígito hexadecimal. Por exemplo: Um quadro comparativo a seguir contém os valores dos números de 0-255 em três diferentes sistemas numéricos. Esta é provavelmente a maneira mais fácil de entender a lógica comum aplicado a todos os sistemas. Observe que para representar os valores 0-255 nesses sistemas são necessários: * 3 dígitos decimais no sistema decimal; * 8 dígitos binários no sistema binário; * 2 dígitos hexadecimais no sistema hexadecimal. Número hexadecimal Mesmo número no sistema decimal Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 7 O sistema numérico decimal, juntamente com os sistemas binário e hexadecimal, são considerados os sistemas numéricos mais importantes para nós. É fácil fazer a conversão de um número hexadecimal em binário e também é fácil de lembrar. No entanto, essas conversões podem causar confusão. Por exemplo, o que significa a frase “É preciso contar até 110 produtos na linha de montagem”. Dependendo se tratar de um valor binário, decimal ou hexadecimal, o resultado poderia ser 6, 110 ou 272 produtos, respectivamente! Assim, a fim de evitar mal-entendidos, diferentes prefixos e sufixos são adicionados diretamente aos números. O prefixo $ ou 0x, bem como o sufixo h marcam os números no sistema hexadecimal. Por exemplo, o número hexadecimal 10AF pode ser escrito como $10AF, ou 0x10AF, ou ainda 10AFh. Da mesma forma, os números binários geralmente usam os prefixos % ou 0b. Se um número não tem nem o prefixo nem sufixo é considerado decimal. Infelizmente, esta maneira de marcar os números não é padronizada, assim, isto depende da concreta aplicação . Tabela comparativa mostrando os valores 0-255 escritos em três diferentes sistemas numéricos: decimal, binário e hexadecimal. Conceito de BIT Um bit nada mais é que um dígito binário. Semelhante ao sistema de numeração decimal em que os dígitos de um número não têm o mesmo valor (por exemplo, os dígitos do número decimal 444 são os mesmos, mas têm valores diferentes), a significância de um bit depende de sua posição no número binário . Como não há sentido falar de unidades, dezenas etc, em números binários, seus dígitos são referidos como o bit zero (bit mais à direita), primeiro bit (o segundo da direita), Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 8 segundo bit, terceiro bit, etc. Além disso, uma vez que o sistema binário utiliza dois dígitos apenas (0 e 1), o valor de um bit pode ser 0 ou 1. Conceito de BYTE Um byte é composto por oito bits agrupados. Se um bit é um dígito, é lógico dizer que bytes representam números. Todas as operações matemáticas podem ser realizadas sobre eles, os bytes, igualmente aos números decimais. Semelhante a dígitos de um número qualquer, os dígitos de um bytes não tem o mesmo significado. O bit mais à esquerda tem o maior valor, e é chamado o bit mais significativo (MSB – Most Significant Bit). O bit mais à direita tem o menor valor e por isso é chamado o bit menos significativo (LSB – Least Significant bit). Os 8 bits de um byte podem assumir valores 0 ou 1, independentemente. Assim, esses 8 bits podem ser combinados em 256 formas diferentes, o maior número decimal que pode ser representado por um byte é 255. Um nibble é referido como metade de um byte. Dependendo de que metade do byte estivermos falando (esquerdo ou direito), dizemos que há 'alto' e 'baixo' nibble, respectivamente. Os conceitos de bit, byte e nibble podem ser entendidos observando a figura 1.4. Figura 1.4 – Representação dos conceitos de bit, byte e nibble. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 9 Conceitosde Eletrônica Digital Alguma vez você já se perguntou o que há dentro de circuitos eletrônicos integrados digitais como microcontroladores e processadores? O que faz estes circuitos realizarem operações matemáticas complexas e tomar decisões? Sabia que essa aparente complexidade inclui apenas alguns elementos diferentes chamados circuitos lógicos ou portas lógicas? 2.1 Álgebra de Boole A operação dos circuitos lógicos é baseada em princípios estabelecidos por um matemático britânico, George Boole em meados do século XIX, antes mesmo da primeira lâmpada ter sido inventada. Originalmente, a idéia principal era expressar formas lógicas através de funções algébricas. Tal pensamento foi logo transformado em um produto prático, que hoje é conhecido como circuitos lógicos E (AND), OU (OR) e NÃO (NOT), ou inversor. O princípio de sua operação é conhecida como álgebra booleana. Algumas instruções encontradas nos programas de microcontroladores dão o mesmo resultado que portas lógicas. Sua operação será discutida em seguida. Porta lógica E (AND) A porta lógica “E” tem duas ou mais entradas e uma saída. Suponha que a porta usada neste exemplo tem apenas duas entradas. A lógica um (1) irá aparecer em sua saída apenas se as duas entradas (A e B) são acionadas com nível lógico alto (1). A tabela à seguir, chamada de tabela da verdade, mostra a dependência mútua entre as entradas e saída. Capítulo 2 Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 10 Quando usado em um programa, uma operação lógica E é realizada por uma instrução do programa, que será discutida posteriormente. Por ora, basta lembrar que a lógica E num programa refere-se à operação lógica AND aplicada aos bits correspondentes a dois registradores, que são posições de memória onde são armazanados valores binários, conforme se pode ver no quadro abaixo. Porta lógica OU (OR) Da mesma forma, portas lógicas “OU” também tem duas ou mais entradas e uma saída. Se a porta tem apenas duas entradas, uma lógica um (1) irá aparecer em sua saída se uma entrada (A ou B) é acionada com nível lógico alto (1). Ou seja, uma lógica um (1) aparece em sua saída, se pelo menos uma entrada é mantida alta (1). Se todas as entradas estão à lógica zero (0), a saída também apresenta lógica zero (0). Em seguida, pode ser visto a tabela da verdade para a porta lógica OU assim como uma operação OU realizada com os valores de dois registradores. Porta lógica NÃO (NOT) A porta lógica “NÃO” (not) tem apenas uma entrada e uma única saída. Ela opera de maneira extremamente simples. Quando a lógica zero (0) aparece em sua entrada, uma lógica de um (1) aparece em sua saída e vice-versa. Isso significa que esta porta inverte o sinal e é freqüentemente chamada de inversora. No programa, essa operação lógica é feita sobre um byte, ou apenas um bit. O resultado é um byte com bits invertidos. Se o byte é considerado como um número, o valor invertido na verdade é um complemento do mesmo. O complemento de um número é um valor que adicionado ao número faz com que ele alcance o maior número de 8 dígitos binários. Em outras palavras, a soma de um número de 8 dígitos e seu complemento é sempre 255. Em seguida, pode ser visto a tabela da verdade para a porta lógica NÃO assim como uma operação NÃO realizada com o valor de um registrador. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 11 Porta lógica OU-EXCLUSIVO (XOR) A porta “OU EXCLUSIVO” (XOR) é um pouco complicado em comparação com outras portas. Ela representa uma combinação de todos eles. A lógica um (1) aparece em sua saída somente quando suas entradas têm estados lógicos diferentes. No programa, esta operação é comumente usada para comparar dois bytes. A subtração pode ser utilizada para o mesmo fim (se o resultado for 0, os bytes são iguais). Ao contrário de subtração, a vantagem desta operação lógica é que não é possível a obtenção de resultados negativos. Em seguida, pode ser visto a tabela da verdade para a porta lógica OU EXCLUSIVO assim como uma operação realizada com os valores de dois registradores. Registradores Em suma, um registrador, ou uma célula de memória, é um circuito eletrônico que pode memorizar o estado de um byte. Dentro de um microcontrolador há vários registradores que são usados para armazenar as informações do programa. Essas informações podem ser variáveis de controle do programa, estado das entradas ou saídas, resultado de uma operação matemática, etc. Graficamente, podemos ver como funciona um registrador através da figura 2.1. Nessa figura, a unidade central de processamento (CPU) pode armazenar um byte numa posição de memória, ou registrador. Esse valor armazenado, pode em seguida ser utilizado pela própria CPU para um novo cálculo ou processamento. Figura 2.1 – CPU comunicando-se com um registrador. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 12 Além de registradores de uso geral como o mostrado na figura 2.1, que não tem nenhuma função específica e determinada, cada microcontrolador possui um número de registradores especiais (Special Function Registers-SFR), cuja função é pré-determinada pelo fabricante. Seus bits são conectados (literalmente) com os circuitos internos do microcontrolador, tais como temporizadores, conversores A/D, osciladores e outros, o que significa que eles são usados diretamente no comando da operação destes circuitos. O estado dos bits do registrador é alterado a partir do programa. O estado dos bits controla pequenos circuitos dentro do microcontrolador. Imagine oito interruptores que controlam o funcionamento de um pequeno circuito dentro do microcontrolador: registradores especiais fazem exatamente isso, como pode ser observado na figura 2.2. Figura 2.2 – CPU comunicando-se com um registrador de função especial. Portas de Entrada/Saída A fim de tornar o microcontrolador útil, este tem que ser ligado a uma eletrônica adicional, ou seja, aos periféricos. Cada microcontrolador tem um ou mais registradores (chamados portas) conectados aos pinos do microcontrolador. Por que entrada / saída? Porque você pode mudar a função do pino que desejar. Por exemplo, suponha que você deseja que o seu dispositivo ligue/desligue três LEDs de sinal e, simultaneamente, monitore o estado lógico de cinco sensores ou teclas. Algumas das portas precisam ser configuradas de modo que hajam três saídas (ligadas à LEDs) e cinco entradas (ligadas a sensores). Esta configuração é simplesmente realizada por software, ou seja, através do programa que o projetista escreve, o que significa que a função do pino pode ser alterada durante a operação. Podemos observar o funcionamento de uma porta de um microcontrolador através da figura 2.3. Figura 2.3 – CPU comunicando-se com uma porta de entrada/saída. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 13 Uma importante especificação dos pinos de entrada/saída (I/O) é a corrente máxima que estes podem suportar. Para a maioria dos microcontroladores atuais, a corrente obtida a partir de um pino é suficiente para ativar um LED ou algum outro dispositivo de baixa corrente (1-20 mA). Quanto mais pinos de I/O, menor corrente máxima de um pino. Em outras palavras, a corrente máxima indicada na folha de especificações de dados para o microcontrolador é compartilhada entre todas as portas de I/O. Outra função importante de um pino de I/O é que estes podem ter resistências de pull-up. Essas resistências conectam os pinos à tensão positiva de alimentaçãoque pode ser diferente daquela que é usada para alimentar o chip do microcontrolador. Isto é útil quando se deseja trabalhar com tensões distintas no mesmo circuito Cada porta de I/O está normalmente sob o controle de um registrador especial, o que significa que cada bit do registrador determina o estado do pino correspondente. Por exemplo, escrevendo uma lógica (1) para um bit do registrador de controle (SFR), o pino apropriado da porta é automaticamente configurado como entrada e a tensão presente nele pode ser lida como nível lógico 0 ou 1. Caso contrário, ao escrever zero a um bit desse SFR, o pino apropriado da porta é configurado como uma saída. Unidade de Memória A memória é a parte do microcontrolador utilizado para armazenamento de dados. A maneira mais fácil de explicar é compará-la com um armário de arquivo com muitas gavetas. Suponha-se, as gavetas estão claramente identificadas para que seu conteúdo possa ser encontrada com facilidade através da leitura da etiqueta na parte frontal da gaveta. Da mesma forma, cada endereço de memória corresponde a um local de memória. O conteúdo de qualquer lugar pode ser acessado e lido pelo seu endereçamento. Memória pode ser escrita ou lida. Na figura 2.4 temos um representação de uma memória que pode ser escrita ou lida. Do lado esquerdo, temos o endereço de cada posição de memória, do lado direito, temos os dados. Ao endereçar uma posição específica, a linha de dados apresenta o conteúdo presente naquela posição endereçada. Esse conteúdo pode ser lido para ser usado em algum processamento, ou ainda, esse conteúdo pode ser alterado mediante a escrita de um novo dado naquele endereço. Figura 2.4 – Memória de escrita/leitura de um microcontrolador. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 14 Existem vários tipos de memória dentro do microcontrolador, tais como: Memória apenas de leitura (Read Only Memory-ROM) - é usado para salvar permanentemente o programa sendo executado. O tamanho do programa que pode ser escrito depende do tamanho da memória. Microcontroladores atuais costumam usar 16 bits de endereçamento, o que significa que eles são capazes de endereçar até 64 Kb de memória, ou seja, 65.535 localidades. Para iniciantes, o programa irá raramente exceder o limite de várias centenas de instruções. Existem vários tipos de ROM. Memória Flash - Este tipo de memória foi inventado nos anos 80 nos laboratórios da Intel e foi apresentada como o sucessor da EPROM UV (tipo de memória ROM que usa luz ultravioleta para ser apagada). Como o conteúdo dessa memória pode ser escrito e apagado praticamente um número ilimitado de vezes, microcontroladores com memória Flash ROM são ideais para a aprendizagem, experimentação e produção em pequena escala. Devido à sua grande popularidade, a maioria dos microcontroladores são fabricados com tecnologia flash. Então, se você estiver pensando em comprar um microcontrolador, o tipo é definitivamente o Flash! Memória de acesso aleatório (Random Access Memory-RAM) - Uma vez que a alimentação é desligada, o conteúdo da RAM é apagado. Ela é usada para armazenar dados temporários e resultados intermediários criados e utilizados durante a operação do microcontrolador. Por exemplo, se o programa realiza uma adição (de tudo), é necessário ter um registro que representa o que na vida cotidiana é a chamada "soma". Por esta razão, podemos ter um dos registros de memória RAM chamado de 'soma' e usado para armazenar os resultados da adição. Memória ROM eletricamente apagável e programável (Electrically Erasable Programable ROM-EEPROM) – Lê-se E 2 PROM. O conteúdo da EEPROM pode ser alterado durante a operação (semelhante à RAM), mas é permanente, mesmo após a perda de alimentação (similar a ROM). Assim, EEPROM é freqüentemente usado para armazenar valores, criados durante a operação, que deve ser permanentemente guardados. Por exemplo, se você criar uma fechadura eletrônica ou um alarme, seria ótimo que este permitisse ao usuário criar e digitar uma senha. Mas é inútil se essa senha for perdida cada vez que a alimentação se apaga. A solução ideal é um microcontrolador com uma EEPROM embutida. Interrupções A maioria dos programas usam interrupções em sua execução normal. O objetivo do microcontrolador é principalmente responder às mudanças no seu entorno. Em outras palavras, quando um evento ocorre, o microcontrolador faz alguma coisa. Por exemplo, quando você aperta um botão em um controle remoto, o microcontrolador irá registrá-lo e responder pela alteração de um canal, aumentar o volume para cima ou para baixo, etc. Se o microcontrolador passasse a maior parte de seu tempo infinitamente verificando alguns botões por horas ou dias, isso não seria prático. É por isso que o microcontrolador possui uma técnica de resposta a certos estímulos. Em vez de verificar cada pino ou bit constantemente, o microcontrolador delega essa função a circuitos específicos que só responderão quando algo específico acontece, por exemplo, o pressionamento de um botão. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 15 O sinal que informa a unidade de processamento central quando um evento como esse ocorre é chamado de uma interrupção. Quando a interrupção ocorre, o microcontrolador para de executar o programa e atende aquele evento em especial. As interrupções são recursos extremamente poderosos e práticos para o desenvolvimento de sistemas microcontrolados. Unidade Central de Processamento (CPU) Como o próprio nome sugere, esta é uma unidade que monitora e controla todos os processos dentro do microcontrolador. É constituída por várias subunidades, das quais as mais importantes são: • Decodificador de Instruções (Instruction Decoder) é uma parte da eletrônica embutida no microcontrolador que decodifica as instruções do programa e ativa outros circuitos com base nisso. O "conjunto de instruções" que é diferente para cada família de microcontroladores expressa a capacidade do circuito; • Unidade Lógica Aritmética (ULA) realiza todas as operações matemáticas e lógicas sobre os dados; • Acumulador é um registrador de uso especial intimamente relacionada com a operação da ULA. É uma espécie de mesa de trabalho usada para armazenar todos os dados em que uma operação deve ser realizada (transferência, adição/mover etc.) Ele também armazena os resultados prontos para uso no tratamento posterior. Um dos SFR, chamado de Registrador de Status (Status Register), está intimamente relacionado com o acumulador. Ele mostra, em determinado momento o 'status' de um número armazenado no acumulador (se número é maior ou menor que zero, etc.). O acumulador é também chamado de registrador de trabalho e está marcado como registrador W, ou apenas W. Na figura 2.5 podem ser vistas as subunidades da CPU citadas. Figura 2.5 – Unidade Central de Processamento e suas subunidades. Na figura 2.5, temos setas representando os fios que levam a informação de endereçamento de memória (Address), dos dados (Data) e das linhas de controle (Control Line). Cada seta, dependendo do tipo de microcontrolador, pode conter 8, 16 fios ou até mais. Cada conjunto de fios que carregam uma informação do mesmo tipo é chamado de Barramento. Assim, temos os barramentos de endereço, de dados e de controle. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 16 Oscilador Para que o microcontrolador execute as instruções armazenadas em sua memória, é necessário a presença de um sinal pulsante, normalmente uma onda quadrada, para que as instruções sejam executadas a cada pulso. Esse sinal é chamado de sinal de relógio (clock), e é provenientede um circuito oscilador. O circuito oscilador é normalmente configurado de modo a utilizar um cristal de quartzo ou ressonador cerâmico, conectado a dois pinos do microcontrolador, para a estabilidade de freqüência, mas também pode operar como um circuito stand-alone (como um oscilador RC interno). É importante dizer que as instruções não são executadas ao ritmo imposto pelo oscilador em si, mas várias vezes mais lento. Isso acontece porque cada instrução é executada em várias etapas. Em alguns microcontroladores, o mesmo número de ciclos é necessário para executar todas as instruções, enquanto em outros, o número de ciclos é diferente para diferentes instruções. Assim, se o sistema usa um cristal de quartzo com uma frequência de 20 Mhz, o tempo de execução de uma instrução não é 50ns, mas 200, 400 ou 800 ns, dependendo do tipo de microcontrolador! Circuito de alimentação Há duas coisas que merecem atenção sobre o circuito de alimentação do microcontrolador: • Brown out é uma condição potencialmente perigosa que ocorre no momento em que o microcontrolador é desligado ou quando a tensão cai para um valor mínimo devido a ruído elétrico. Como o microcontrolador é composto por vários circuitos, com diferentes níveis de tensão de funcionamento, este estado pode provocar um funcionamento fora de controle. Para evitar isso, normalmente o microcontrolador possui um circuito de reset que reinicia todos os circuitos assim que o microcontrolador incorre em um estado de emergência. • Pino de reset é normalmente marcado como MCLR (Master Clear Reset). É utilizado para reiniciar o microcontrolador através da aplicação de uma lógica de zero (0) ou um (1) nesse pino, o que depende do tipo do microcontrolador. Temporizadores/Contadores O oscilador do microcontrolador utiliza cristal de quartzo para o seu funcionamento. Mesmo não sendo a solução mais simples para a obtenção de um sinal de relógio, existem muitas razões para usá-lo. A freqüência do oscilador é precisamente definida e muito estável, de modo que gera pulsos sempre da mesma largura, o que os torna ideais para a medição do tempo. Tais osciladores também são usados em relógios de quartzo. Se é necessário medir o tempo entre dois eventos, basta contar os pulsos gerados por este oscilador. Isto é exatamente o que o temporizador, ou timer, faz. A maioria dos programas usam este cronômetro eletrônico em miniatura. Estes são geralmente registradores de funções especiais de 8 ou 16-bits, cujo conteúdo é automaticamente incrementado por cada impulso vindo do circuito oscilador. Uma vez que um registrador é completamente carregado, uma interrupção pode ser gerada. Se o timer usa um oscilador de quartzo para o seu funcionamento interno, então ele pode ser usado para medir o tempo entre dois eventos (se o valor do registrador é T1 Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 17 no momento em que se inicia a medição, e T2, no momento em que termina, então o tempo decorrido é igual a o resultado da subtração T2-T1). Se os registradores usam pulsos provenientes de fontes externas conectados a um pino do microcontrolador, então o timer é transformado em um contador. Esta é apenas uma explicação simples da operação em si. No entanto, é um pouco mais complicado na prática. Conversor Analógico/Digital (A/D) Sinais externos normalmente são fundamentalmente diferentes daqueles que o microcontrolador entende (zeros e uns) e têm de ser convertidos em valores compreensíveis para o microcontrolador. Um conversor analógico/digital é um circuito eletrônico que converte os sinais contínuos para discretos números digitais. Em outras palavras, este circuito converte um valor analógico em um número binário e o transfere para a CPU para processamento adicional. Este módulo é utilizado para a medição de tensão analógica em um pino de entrada (valor analógico). Na figura 2.6, por exemplo, temos uma representação do conversor A/D sendo controlado pela CPU. O gráfico ao lado mostra a relação de conversão de sinais analógicos de 0V até 5V em números binários que vão de 0x000 a 0x3FF. Figura 2.6 – Operação de um conversor analógico/digital. Arquitetura Interna Todos os microcontroladores usam um dos dois modelos de projeto básicos chamados arquitetura Harvard e arquitetura von-Neumann. Eles representam duas formas diferentes de troca de dados entre a CPU e a memória. Os microcontroladores com a arquitetura von-Neumann tem apenas um bloco de memória e um barramento de 8 bits de dados. Como todos os dados são trocados através dessas 8 linhas, o barramentos fica sobrecarregado e a comunicação é muito lenta e ineficiente. A CPU pode apenas executar uma instrução de leitura ou gravação de dados para a memória. Ambas não podem ocorrer ao mesmo tempo, uma vez que instruções e dados usam o mesmo barramento. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 18 Figura 2.7 – arquitetura Von-Neumann. Os microcontroladores com arquitetura Harvard tem dois barramentos diferentes. Um deles conecta a CPU com a memória RAM. O outro consiste em linhas de 12, 14 ou 16 bits e conecta a CPU com a memória ROM. Assim, a CPU pode ler uma instrução e ter acesso a dados da memória, ao mesmo tempo. Como todos os registradores da memória RAM são de 8 bits, todos os dados sendo trocados são da mesma largura. Durante o processo de escrita, um programa apenas manipula os dados de 8 bits. Em outras palavras, tudo o que você pode mudar a partir do programa e tudo o que pode influenciar é de 8 bits. Todos os programas escritos para estes microcontroladores serão armazenado na ROM do microcontrolador interno depois de serem compilados em código de máquina. No entanto, posições de memória ROM não tem 8, mas 12, 14 ou 16 bits. O resto dos bits 4, 6 ou 8 representa a instrução especificando para a CPU o que fazer com os dados de 8 bits. Figura 2.8 – arquitetura Harvard. O Conjunto de Instruções Todas as instruções compreensíveis para o microcontrolador são chamadas de o conjunto (Set) de instruções. Quando você escreve um programa em linguagem assembly, na verdade você especifica instruções na ordem em que devem ser executadas. A principal restrição aqui é o número de instruções disponíveis. Os fabricantes costumam considerar uma das duas abordagens abaixo: Conjunto reduzido de instruções (RISC-Reduced Instruction Set Computer) Neste caso, o microcontrolador reconhece e executa apenas as operações básicas (adição, subtração, cópia, etc.) Outras operações mais complicadas são realizadas através da combinação delas. Por exemplo, a multiplicação é feita através da realização de sucessivas adições. Os microcontroladores da linha PIC são do tipo RISC. Conjunto complexo de instruções (CISC-Complex Instruction Set Computer) CISC é o oposto ao RISC. Microcontroladores concebidos para reconhecer mais de 200 instruções diferentes, podendo realizar inúmeras tarefas em alta velocidade. No entanto, Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 19 é preciso entender como aproveitar tudo o que estas instruções oferecem, o que não é nada fácil. Processadores, como Pentium, Core 2 Duo são do tipo CISC. Modelo genérico de um microcontrolador Todos os elementos de hardware vistos até agora, e tantos outros não apresentados aqui, fazem parte da eletrônica embutida em um microcontrolador. Esses elementos estão todos interligados para desempenhar diferentes tarefas, dependendo das necessidades do projetista. A figura 2.9 mostra como esses elementos estão interligados para potencializar o uso de um microcontrolador Figura 2.9 – Elementosde um microcontrolador. Como fazer a escolha certa? Ok, você é novato e tomou a decisão de se aventurar em trabalhar com os microcontroladores. Parabéns pela sua escolha! No entanto, não é tão fácil escolher o correto microcontrolador, como pode parecer. O problema não é um número limitado de dispositivos, mas o oposto! Antes de começar a projetar um dispositivo baseado no microcontrolador, pense o seguinte: quantas linhas de entrada/saída eu preciso para a operação? Deve realizar algumas operações além de simplesmente acionar relés? Será que preciso de algum módulo especializado, tal como comunicação serial, etc. Um conversor A/D? Quando você cria uma imagem clara do que você precisa, o intervalo de selecção é bastante reduzido e é hora de pensar em preços. Se você pensar em todas essas coisas pela primeira vez, então, tudo parece um pouco confuso. Primeiro, selecione o fabricante, ou seja, a família do microcontrolador. Estude um modelo específico. Saiba quanto você precisa, não entre em detalhes. Resolva um problema específico por vez. Em seguida, você vai perceber que aprendendo um modelo daquela família, você estará apto a trabalhar com qualquer outro modelo. Os microcontroladores PIC, desenvolvidos pela Microchip Technology provavelmente são a melhor escolha para iniciantes. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 20 O Microcontrolador PIC 16F877 O PIC16F877 é um produto bem conhecido da Microchip. Ele possui todos os componentes que os microcontroladores modernos normalmente têm. Por seu baixo preço, ampla gama de aplicações de alta qualidade e fácil acesso, é uma solução ideal em aplicações como o controle de diferentes processos na indústria, dispositivos de controle de máquinas, a medição de valores de tensão, etc. Algumas de suas principais características estão listadas abaixo. 3.1 Introdução O PIC16F877 é um microcontrolador que teve suas origens no ano de 1965, quando a companhia GI (General Instruments), formou a Divisão de Microeletrônica. Na década de 70, a GI criou um dos primeiros processadores de 16 bits, chamado CP16000. Como este microprocessador tinha uma certa deficiência no processamento de entradas/saídas, a GI projetou e construiu um Controlador de Interface Periférica (em inglês, Peripheral Interface Controller, ou PIC). Este controlador foi projetado tendo em vista a rapidez, pois devia processar as operações de E/S de uma máquina de 16 bits, e tinha um conjunto de instruções muito pequeno. O CP16000 não teve muito sucesso, porém o PIC evoluiu para a arquitetura PIC16C5x. Como era disponível somente nas versões em ROM, permaneceu como uma boa solução para grandes usuários, que podiam encomendar diretamente da fábrica um grande volume de circuitos já pré- programados. Na década de 80, a divisão de microeletrônica da GI foi reestruturada e se transformou na GI Microeletrônica, uma empresa subsidiária. Esta empresa foi vendida para investidores e transformada na Arizona Microchip Technology, dedicada especificamente ao desenvolvimento de produtos utilizados em sistemas dedicados. Como parte desta estratégia, grande esforço da companhia foi direcionado ao desenvolvimento de várias versões do PIC, sendo que a versão com EEPROM (eprom apagável eletricamente) é a mais indicada para o desenvolvimento rápido de aplicações, devido ao baixo custo do sistema de desenvolvimento necessário e do hardware de processamento. O dispositivo mais flexível disponível hoje da série PIC de 14 bits de palavra de controle, e que ao mesmo tempo reúne um conjunto de características adequadas ao uso em pequenas séries de produtos e estudo de microcontroladores é o PIC16F877A. Na Capítulo 3 Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 21 figura 3.1 pode-se ver o encapsulamento DIP de 40 pinos, um dos encapsulamentos disponíveis para esse microcontrolador. Como o microcontrolador PIC16F877A se utiliza da arquitetura Harvard, isto possibilita que as palavras de instruções tenham um número de bits (14 bits de comprimento) diferente do tamanho da palavra de dados (8 bits para este microcontrolador). Com este tamanho de palavra de instrução é possível codificar todas as instruções, com exceção dos desvios para outras posições de programas, como instruções de uma única palavra, resultando em uma grande velocidade de execução, como 200ns para a versão de 20Mhz. Figura 3.1 – Microcontrolador PIC 16F877A com encapsulamento DIP de 40 pinos. Estes dispositivos podem endereçar direta e indiretamente seus arquivos de registros ou memória de dados. O conjunto de instruções foi projetado de tal forma que se pode realizar qualquer operação em qualquer registro utilizando qualquer modo de endereçamento. A unidade lógica aritmética do PIC16F877 pode realizar operações de adição, subtração, deslocamento e operações lógicas. Os microcontroladores da série PIC16F877 são dispositivos computacionais extremamente adequados para experimentação e pequenos projetos. Devido ao seu baixo custo e facilidade de programação, podem ser empregados em aplicações onde até recentemente se utilizavam componentes discretos, como por exemplo, os temporizadores e controladores de temperatura, adicionando novas funções até então não implementadas devido a complexidade do circuito necessário. O projeto com microcontroladores traz uma diferença fundamental de paradigma para o projetista de circuitos. Ao invés de um bem sortido estoque de componentes discretos que realizam várias funções diferentes cada um, e de um conceito de projeto que consiste em interligar estas diferentes funções de forma que o sistema como um todo tenha o comportamento adequado, utilizamos agora praticamente um mesmo tipo de hardware para todas as aplicações. A diferença de funcionalidade fica por conta do software. Alterações de funcionalidade podem ser feitas, em grande parte das vezes, através da modificação apenas do software, sem ser necessária alteração do hardware. Os microcontroladores da série PIC16F87X são máquinas RISC. Isto significa que são máquinas com um reduzido conjunto de instruções. Para ser exato, são apenas 35 instruções para serem compreendidas, cada uma ocupando uma palavra (14 bits ). O PIC16F877 possui as seguintes características básicas: • 5 conjuntos de portas de entrada e saída (total de 33 entradas/saídas); • Conversor analógico/digital de 10 bits de resolução e 8 canais de entrada; • Periférico de comunicação paralela e serial (USART e MSSP); Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 22 • 2 Módulos CCP (Comparação, Captura e PWM); • 3 Timers (1 de 16 bits e 2 de 8 bits); • Watchdog timer (temporizador especial). Na figura 3.2 temos uma representação da arquitetura interna do PIC16F877, ou seja, uma representação da forma como os recursos estão ligados internamente no chip. Figura 3.2 – Arquitetura interna do PIC microcontrolador PIC 16F877. Na figura 3.3 temos a descrição dos pinos no encapsulamento. Observe que alguns pinos apresentam mais de uma função. Isso significa que o projetista deve escolher qual a função que o pino vai assumir quando estiver fazendo a sua programação. A descrição de cada pino do microcontrolador é mostrada na tabela que segue: Figura 3.3 – Pinagem do microcontrolador PIC 16F877. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 23 Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 24 A fim de que o microcontrolador funcione adequadamente é necessário fornecer: • Alimentação elétrica; • Sinal de reset, e • Sinal de clock. Mesmo que o PIC16F877possa operar em tensões de alimentação diferentes, uma fonte de alimentação DC de 5V é a mais adequada. O circuito mostrado na figura 3.4 utiliza um circuito integrado de três terminais LM7805, um regulador positivo que oferece alta qualidade de estabilidade de tensão e corrente suficiente para permitir que o microcontrolador e periféricos eletrônicos funcionem normalmente (o suficiente, aqui, significa 1A). Para que o microcontrolador possa operar corretamente, uma lógica (VCC) deve ser aplicado sobre o pino de reset (pino 1). O botão conectando o pino MCLR ao GND não é necessário. No entanto, é quase sempre fornecido, pois permite que o microcontrolador seja resetado manualmente, fazendo com que este retorne às condições normais de funcionamento, caso algo dê errado. Ao pressionar este botão, o pino é levado a 0V, o microcontrolador é reiniciado e começa a execução do programa desde o início. Um resistor de 10K é usado para permitir que o pino MCLR vá a 0V, através do botão, sem curto-circuitar com o nível de 5V DC. Esse resistor é chamado de resistor de “pull-up”, pois é conectado entre o VCC e o pino. Mesmo que o microcontrolador possua um oscilador interno, ele não pode operar sem componentes externos que estabilizam o seu funcionamento e determinem sua freqüência (velocidade de operação do microcontrolador). Dependendo do elemento em uso para estabilizar a frequência, bem como suas freqüências, o oscilador pode operar em quatro modos diferentes: LP - Cristal de Baixa Potência; XT - Cristal/Ressonador; HS - Cristal de Alta Velocidade e RC - Resistor/Capacitor. Quando o cristal de quartzo é utilizado para a estabilização da freqüência, o oscilador funciona com uma frequência precisa, que não é afetado por mudanças na temperatura e tensão de alimentação. Esta frequência é geralmente indicada na embalagem do crysal. Além do cristal, os capacitores C1 e C2 também devem ser conectados conforme esquema abaixo. Os valores previstos para C1 e C2 na tabela a seguir devem ser considerados como uma recomendação e não como uma regra rígida. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 25 Figura 3.4 – Circuito de alimentação, reset e oscilador para o PIC 16F877. Como visto na figura acima, trata-se de um circuito simples, mas nem sempre é assim. Se o dispositivo de destino é utilizado para controlar grandes máquinas ou dispositivos de suporte a vida, tudo fica cada vez mais complicado. No entanto, esta solução é suficiente por enquanto. Independentemente do fato de que o microcontrolador é um produto de tecnologia moderna, este é inútil se não estiver ligado a alguns componentes adicionais. Simplificando, o aparecimento de tensões nos pinos do microcontrolador não significa nada se não for utilizado para a realização de determinadas operações, tais como ligar ou desligar LEDS, relés, ler botões ou chaves, exibir dados em um display de 7 segmentos ou display de LCD etc. Nos capítulos que se seguem, serão abordadas as técnicas de programação em linguagem C, bem como a utilização do micocontrolador para realizar tarefas que vão desde acender/apagar um LED, até tarefas mais complexas como escrita em um LCD ou mesmo a comunicação entre dois microcontroladores. No final desta apostila, encontra-se o datasheet resumido do PIC16F877, contendo as principais informações necessárias para o desenvolvimento de aplicações utilizando esse microcontrolador. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 26 Introdução à Linguagem C Assim como o uso de uma linguagem não está limitada apenas a livros e revistas, as Linguagens de Programação não estão estritamente relacionadas com algum tipo especial de computador, processador ou Sistema Operacional. C é atualmente uma linguagem de programação de alto nível e de uso geral. Entretanto, o fato da não associatividade da linguagem C a nenhuma máquina pode causar problemas durante a sua utilização, dependendo das peculiaridades de cada máquina em que está se programando (isto poderia ser comparado ao uso de diferentes dialetos de uma linguagem). 4.1 Introdução A idéia associada a escrever um programa na linguagem C é quebrar um grande problema em vários problemas menores, mais simples de serem resolvidos. Suponha, por exemplo, que é necessário escrever um programa para o microcontrolador para realizar a medição de temperatura e mostrar o resultado em um display de cristal líquido. O processo de medir é feito com o uso de um sensor apropriado, que converte a temperatura em uma tensão proporcional. O microcontrolador usa seu conversor A/D para converter essa tensão (analógica) em um número (digital) que é então enviado para o LCD através de vários fios. Assim, o programa é dividido em quatro partes que precisam ser executadas na ordem correta, como seguem: 1. Ativar e ajustar o conversor A/D; 2. Realizar a medição do valor analógico; 3. Calcular a temperatura; 4. Enviar os dados de forma apropriada para o display. Capítulo 4 Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 27 Para facilitar a compreensão da linguagem C, vejamos primeiramente um exemplo de programa: Vejamos o significado de cada linha do programa. A primeira linha do programa: // Primeiro exemplo é chamada de comentário. Os comentários não são interpretados pelo compilador, mas são apenas descrições inseridas no código-fonte pelo programador com o intuito de documentar o programa e para facilitar o seu entendimento por parte de outros programadores que eventualmente farão alterações ou atualizações no programa original. Os comentários podem ser de linha simples, como foi mostrado no exemplo anterior, e são iniciados por uma barra dupla. Os comentários de linha simples podem ser iniciados em qualquer ponto de uma linha e são muito utilizados para descrever o funcionamento ao final de cada linha de código. Os comentários também podem ser de múltiplas linhas. Nesse caso, são compostos por uma ou mais linhas. Iniciam sempre com os caracteres “/*” para iniciar o comentário, e a sequência “*/” para terminar o comentário, como mostra o exemplo abaixo: /* Este é um exemplo de comentário de múltiplas linhas */ Na próxima linha temos: #include <16F877A.h> O comando #include é uma diretiva do compilador. Neste caso, está determinando ao compilador que anexe ao programa o arquivo especificado: “16F877A.h”, que é um arquivo que contém todas as informações sobre o microcontrolador utilizado, no caso, o PIC 16F877A. Arquivos com extensão do tipo “.h” são chamados de arquivos de cabeçalho e são utilizados em C para definir variáveis, tipos, símbolos e funções úteis ao programa. // Primeiro exemplo #include <16F877A.h> #fuses HS #use delay(clock=20M) main() { output_high(pin_b0); //seta o pino rb0 delay_ms(500); //aguarda 500ms output_low(pin_b0); //reseta o pino rb0 } Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 28 Na próxima linha encontramos: #fuses HS Esta é uma diretiva que especifica o estado dos “fusíveis” da palavra de configuração do dispositivo. No caso, estamos indicando ao processador que opere com a opção HS ou High Speed, isto é, com um cristal de alta velocidade. Existem várias outras opções para configurar os fuses, como por exemplo, proteger o código gravado no microcontrolador contra leitura, modos de programação, proteção para evitar travamentos no caso de uma queda de tensão, etc. Em seguida temos: #usedelay(clock=20M) Esta é outra diretiva do compilador. Esta diretiva especifica o clock, ou a velocidade do cristal usado para sincronizar as operações dentro do dispositivo. No caso, estamos indicando ao compilador que o dispositivo opera com um cristal de 20MHz. Este valor é utilizado para a geração de códigos de atraso e outras rotinas que dependam do tempo. Na próxima linha do programa encontramos: main() A declaração main( ) especifica o nome de uma função. No caso, a função main( ) é padronizada na linguagem C e é utilizada para definir a função principal, ou o corpo principal do programa. Uma função em C é um conjunto de instruções que pode ser executado a partir de qualquer ponto do programa. O sinal de abertura da chave “{“ é utilizado para delimitar o início da função e o sinal de fechamento da chave ”}” indica o final da função. Na realidade, as chaves delimitam o que chamamos de bloco de programa ou bloco de código. O bloco de programa dentro da função main( ) é formado por 3 instruções. Cada instrução é terminada por um ponto e vírgula (;). A instrução output_high(pin_b0) é uma chamada a uma função interna do compilador. Esta função é utilizada para setar (ou seja, colocar em nível lógico ‘1’) um pino do microcontrolador, identificado entre os parênteses. Isto significa que o pino rb0 (da porta B) será setado. Note que (pin_b0) é um símbolo predefinido para especificar o pino rb0. Este símbolo está localizado no arquivo de cabeçalho do processador utilizado, e que foi adicionado com a diretiva #include. O conteúdo presente entre os parênteses de uma função é chamado de argumento da função. Assim, pin_b0 é o argumento da função output_high( ). A próxima função a ser executada é: delay_ms(500); Esta também é uma função interna do compilador e é utilizada para gerar um atraso de X milissegundos, indicado entre os parênteses. No caso, o atraso será igual a 500ms. A instrução output_low(pin_b0) é uma chamada a uma outra função interna do compilador. Esta função é utilizada para resetar (ou seja, colocar em nível lógico ‘0’) um pino do microcontrolador, identificado entre os parênteses. Isto significa que o pino rb0 (da porta B) será resetado. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 29 Desta forma, ao programarmos o PIC com o programa anterior e se tivermos conectado um LED (com o devido resistor de limitação de corrente) ao pino rb0, nós o veremos acender, permanecer aceso por 500ms, apagar e depois permanecer apagado. Obviamente este é um programa bem simples, mas que é útil para o entendimento inicial da estrutura de um programa escrito em linguagem C. Podemos dizer que um programa em C é constituído por um ou mais dos seguintes elementos: *Operadores são elementos utilizados para comandar interações entre variáveis e dados em C; *Variáveis que são usadas para armazenamento temporário ou permanente de dados. A linguagem C dispõe de uma variedade de tipos de variáveis e dados; *Comandos de controle são elementos essenciais à escrita de programas em C. São utilizados para controlar, testar e manipular dados e informações dentro de programas em C; *Funções são estruturas de programa utilizadas para simplificar, otimizar ou apenas tornar mais claro o funcionamento do programa. Vejamos outro exemplo de programa em C: As quatro primeiras linhas do programa acima constituem o que podemos chamar de cabeçalho do programa, onde temos alguns comentários acerca do programa e também as diretivas de controle do compilador. Observe que as diretivas não necessitam (e nem permitem) o uso do ponto e vírgula como delimitador. O primeiro comando, int tempo, é chamado de declaração de variável. Este comando determina que o compilador crie uma variável do tipo inteira int chamada tempo. Esta operação, na realidade irá reservar uma posição de memória no microcontrolador para o armazenamento do valor relativo à variável. O tipo inteiro int especifica um tipo de dados de 8 bits com valores compreendidos entre 0 e 255 decimal. Veremos mais sobre variáveis e tipos de dados em seguida. // Segundo exemplo #include <16F877A.h> #fuses HS #use delay(clock=20M) main() { int tempo; tempo=100; output_high(pin_b0); //seta o pino rb0 delay_ms(tempo); //aguarda 100ms output_low(pin_b0); //reseta o pino rb0 delay_ms(tempo); } Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 30 O nome dado à variável é um identificador e pode ser composto de letras, números e o caractere sublinhado “_”. Veremos mais sobre identificadores válidos na linguagem C. Em seguida, temos a linha tempo=100 que constitui em uma operação de atribuição. As atribuições em C são executadas pelo operador de igualdade “=”. Desta forma, a linha tempo=100 fará com que o compilador gere uma sequência de instruções para fazer com que o valor 100 decimal seja armazenado na variável tempo. As linhas com output_high( ) e output_low( ) são funções internas ao compilador e são utilizadas para setar e resetar, respectivamente, algum pino do microcontrolador, nesse caso, o pino b0 (da porta B). As outras duas linhas restantes são as linhas com a instrução delay_ms(tempo). Esta também é uma função interna do compilador e é utilizada para gerar um atraso de X milissegundos. O valor X é o parâmetro dessa função, no caso, X é igual ao conteúdo da variável tempo, que foi previamente carregada com o valor 100. Logo, o atraso gerado será de 100ms. Maiores detalhes sobre o funcionamento das funções internas do compilador podem ser vistas no manual do usuário do compilador PIC C (CCS). 4.2 Palavras reservadas na Linguagem C Toda linguagem de programação possui um conjunto de palavras ou comandos para os quais já existe interpretação interna prévia. Tais palavras não podem ser utilizadas para outras finalidades que não as definidas pela linguagem. A linguagem C ANSI estipula as seguintes palavras reservadas: auto break case char const continue default do double else enum extern float for goto if int long register static return short signed sizeof struct switch typedef union void volatile while unsigned 4.3 Identificadores Identificadores são nomes dados pelo programador a variáveis, funções e outros elementos da linguagem C. Não é permitido utilizar palavras reservadas como identificadores. Um identificador pode ser composto de caracteres numéricos e alfanuméricos, além do caractere sublinhado “_”. Além disso, um identificador somente pode ser iniciado por uma letra ou sublinhado, nunca por um número, como nos exemplos: variável variavel1 _teste _teste1 _13_abc abc_def Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 31 4.4 Variáveis e tipos de dados Variáveis e constantes são os elementos básicos que um programa manipula. Uma variável é um espaço reservado na memória do microcontrolador para armazenar um tipo de dado determinado. Variáveis devem receber nomes para poderem ser referenciadas e modificadas quando necessário. Muitas linguagens de programação exigem que os programas contenham declarações que especifiquem de que tipo são as variáveis que ele utilizará e às vezes um valor inicial. Tipos podem ser, por exemplo: inteiros, reais, caracteres, etc. As expressões combinam variáveis e constantes para calcular novos valores. Os dados podem assumir cinco tipos básicos em C que são: Tipo Tamanho em bits Intervalo char 8 0 a 255 int 8 0 a 255 float 32 3.4*10-38 a 3.4*1038 void 0 Nenhum valor char: (Caractere) O valor armazenado é umcaractere (letras dígitos e símbolos especiais). Caracteres geralmente são armazenados em códigos (usualmente o código ASCII). int: Número inteiro é o tipo padrão e o seu tamanho normalmente depende da máquina em que o programa está rodando. No caso do PIC16F877, seu tamanho é de 8 bits. float: Número em ponto flutuante de precisão simples. São conhecidos normalmente como números reais. void: Este tipo serve para indicar que um resultado não tem um tipo definido. Uma das aplicações deste tipo em C é criar um tipo vazio que pode posteriormente ser modificado para um dos tipos anteriores. O intervalo especifica qual a faixa de valores que podem ser representados por uma variável daquele tipo. Modificadores podem ser aplicados a estes tipos. Estes modificadores são palavras que alteram o tamanho do intervalo de valores que o tipo pode representar. Por exemplo, um modificador permite que possam ser armazenados números inteiros maiores. Outro modificador obriga que só números sem sinal possam ser armazenados pela variável. Deste modo não é necessário guardar o bit de sinal do número e somente números positivos são armazenados. O resultado prático é que o conjunto praticamente dobra de tamanho. A Tabela abaixo mostra todos os tipos básicos definidos no compilador CCS Tipo Tamanho em bits Intervalo short int, int1, boolean 1 0 ou 1 char 8 0 a 255 signed char 8 -128 a 127 unsigned char 8 0 a 255 int, int8, byte 8 0 a 255 signed int, signed byte 8 -128 a 127 unsigned int, unsigned 8 0 a 255 long int, int16 16 0 a 65535 signed long int 16 -32768 a 32767 Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 32 unsigned long int 16 0 a 65535 int32 32 0 a 4294967295 signed int32 32 -2147483648 a unsigned int32 32 0 a 4294967295 float 32 3.4*10-38 a 3.4*1038 4.4 Declaração de variáveis Para serem usadas, as variáveis precisam ser declaradas de modo que o compilador possa reservar espaço na memória para o valor a ser armazenado. Declarar uma variável nada mais é do que informar ao compilador o nome dessa variável, através de um identificador e o seu tipo, conforme a tabela anterior. A forma geral de uma declaração é: tipo lista_de_variaveis ; Exemplos: int i; unsigned int a, b, c; unsigned long int dia, mes, ano; float salario; Outro aspecto importante da declaração de variáveis é o local onde elas são declaradas. A importância do local onde a variável é declarada relaciona-se à acessibilidade ou não dessa variável por outras partes do programa. Basicamente, podemos declarar as variáveis em dois pontos distintos do programa, a saber: • No corpo principal do programa, (fora de qualquer função, inclusive da função main() . Variáveis declaradas dessa forma são chamadas de variáveis globais, porque podem ser acessadas de qualquer ponto do programa; • Dentro de uma função. As variáveis declaradas dentro de um função somente podem ser acessadas de dentro da função em que foram declaradas. Variáveis declaradas dessa forma são chamadas de variáveis locais. Isto significa que uma variável local somente existe enquanto a função está sendo executada. Em seguida, temos um exemplo de um programa com variáveis locais e globais. // terceiro exemplo (variáveis locais e globais) #include <16F877A.h> #fuses HS #use delay(clock=20M) int var_global; //declaração de variável global (fora das funções) main() { int tempo, var_local; var_global=3; var_local=5; } Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 33 O programa, apesar de não produzir nenhum efeito sobre os pinos do microcontrolador, ilustra a forma de declaração de uma variável global e local. Abaixo da diretiva #use delay temos a declaração de uma variável do tipo inteiro cujo nome atribuído foi var_global. Essa é uma variável do tipo global, pois está fora de qualquer função. Dentro da função main( ) temos a declaração de duas variáveis do tipo inteiras, cujos nomes são tempo e var_local. Essas variáveis são locais, pois foram declaradas dentro do corpo da função main( ). As variáveis locais devem sempre ser declaradas no início de cada função, antes do chamado a qualquer comando. No final da função main( ) as variáveis local e global são carregadas pela atribuição do valor 3 à variável global e do valor 5 à variável local. 4.5 Operadores Operadores são elementos da linguagem que realizam ações sobre variáveis. Podemos classificar os operadores da linguagem C nas categorias principais que seguem abaixo: Operador de atribuição (igualdade): comum à maioria das linguagens, este operador (=) faz a variável da esquerda assumir o valor da variável, constante ou expressão da direita. Exemplo: var = var + 2; Portanto, o conteúdo de var é aumentado de 2. Operadores aritméticos: realizam operações aritméticas sobre os valores das variáveis, constantes ou expressões associadas. Operador Descrição * Multiplicação / Divisão % Resto + Adição - Subtração Exemplo: var = 10 % 3; (o valor de var será 1). Operadores relacionais Eles avaliam o relacionamento entre duas expressões e dão o resultado 1 se verdadeiro ou 0 se falso. Operador Descrição < Menor que <= Menor ou igual > Maior que >= Maior ou igual == Igual != Diferente Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 34 Exemplo: var = 2; if( var>2 ) var = 3; Ou seja, o valor de var continua 2. Um lapso comum é confundir o operador de comparação (= =) com o operador de igualdade (=). Exemplo: var = 1; if( var=2 ) var = 3; E o valor de var será 3, o que certamente não era esperado. Isso ocorre porque var=2 atribui 2 a var e, desde que foi executado, a expressão retornará um valor verdadeiro para a declaração if, permitindo a execução da linha seguinte. Portanto, o correto seria if( var==2 ) Deve ser lembrado que, mesmo sem operadores, a linguagem C considera verdadeiro qualquer valor não nulo. Por exemplo, após a execução das linhas var = 2; if( -50 ) var = 3; o valor de var será 3. Operadores de incremento e decremento São dois operadores bastante úteis para simplificar expressões: ++ (incremento de 1) -- (decremento de 1) Podem ser colocados antes ou depois da variável a modificar. Se inseridos antes, modificam o valor antes de a expressão ser usada e, se inseridos depois, modificam depois do uso. Alguns exemplos: x = 2; var = ++x; No caso acima, o valor de var será 3 e o de x será 3. Operadores de bits Manipulam bits em valores inteiros. Nos exemplos a seguir, são considerados dados de 8 bits de valores inteiros e sem sinal. Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 35 ~ (complemento): Atuando em apenas um valor, muda os bits de valor 1 para 0 e vice- versa. Exemplo: se a variável var tem o valor 170 (10101010), após ~var, ela terá 85 (01010101). << (deslocamento à esquerda): Desloca, para a esquerda, os bits do operando esquerdo no valor dado pelo operando direito. Equivale à multiplicação pela potência de 2 dada por este último. Exemplo: se a variável var tem o valor 3 (00000011), após var << 2, ela será 12 (00001100). >> (deslocamento à direita): Desloca, para a direita, os bits do operando esquerdo no valor dado pelo operando direito. Equivale à divisão pela potência de 2 dada por este último. Exemplo: se a variável var tem o valor 12 (00001100), após var >> 2, terá 3 (00000011).& (E): Faz o valor do bit igual a 1 se ambos os bits correspondentes nos operandos são 1 e 0 nos demais casos. Exemplo: se a variável var tem o valor 12 (00001100) e fazendo a operação com 6 (00000110), o resultado, var & 6, será 4 (00000100). ^ (OU exclusivo): Faz o valor do bit igual a 1 se apenas um dos bits correspondentes nos operandos é 1 e 0 nos demais casos. Exemplo: se a variável var tem o valor 12 (00001100) e fazendo a operação com 6 (00000110), o resultado, var ^ 6, será 10 (00001010). | (OU inclusivo): Faz o valor do bit igual a 1 se um ou ambos os bits correspondentes nos operandos é 1 e 0 nos demais casos. Exemplo: se a variável var tem o valor 12 (00001100) e fazendo a operação com 6 (00000110), o resultado, var | 6, será 14 (00001110). Operadores lógicos Usados normalmente com expressões booleanas, isto é, expressões que retornam verdadeiro ou falso (1 ou 0), para fins de testes em declarações condicionais. && (E lógico): Retorna verdadeiro se ambos os operandos são verdadeiros e falso nos demais casos. Exemplo: if( a>3 && b<4). || (OU lógico): Retorna verdadeiro se um ou ambos os operandos são verdadeiros e falso se ambos são falsos. Exemplo: if( a>3 || b<4). ! (NÃO lógico): Usado com apenas um operando. Retorna verdadeiro se ele é falso e vice-versa. Exemplo: if( !var ). Notar que essa expressão é equivalente a if( var = =0 ). Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 36 4.6 Declarações de controle As declarações ou comandos de controle são uma parte muito importante de uma linguagem de programação. Podemos classificar as declarações de controle em duas categorias básicas: 1. Declarações de teste condicional: são utilizadas para testar determinadas condições/variáveis e executar um código para cada caso. A linguagem C dispõe de dois tipos de declarações condicionais: o comando if-else e o comando switch; 2. Declarações de estrutura de repetição: são utilizadas para provocar a execução de um bloco de comandos enquanto uma determinada condição for verdadeira. Em C dispomos de três declarações de repetição: for, while e do-while. 4.7 O laço While O comando while é um comando de repetição. Ele possui a seguinte forma geral: while(condição) { Comando1; Comando2; ... } A filosofia de funcionamento do comando while é: primeiramente a condição é avaliada, caso seja verdadeira, então o comando ou o bloco de comandos associado é executado e a condição é novamente avaliada, reiniciando o laço. Caso a condição seja falsa, o comando ou o bloco de comandos não é executado e o programa tem sequência a partir da declaração seguinte ao bloco while. A condição testada pelo comando while pode ser qualquer expressão da linguagem C que possa ser avaliada como verdadeira ou falsa. Podemos alterar o programa visto no início do capítulo a fim de fazer com que o LED fique piscando indefinidamente. Para isso, basta introduzir os comandos que estão dentro da função main( ) em um laço do tipo while. Para que o laço seja indefinidamente repetido, o teste da condição deve resultar sempre num valor verdadeiro. Assim, o programa fica como segue abaixo: // quarto exemplo #include <16F877A.h> #fuses HS #use delay(clock=20M) main() { while(true) //laço de repetição { output_high(pin_b0); //seta o pino rb0 delay_ms(500); //aguarda 500ms output_low(pin_b0); //reseta o pino rb0 delay_ms(500); //aguarda 500ms } } Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 37 A palavra true usada entre os parênteses do laço while garante que a condição sempre é verdadeira, uma vez que a palavra true, em inglês, significa verdadeiro. A palavra true é definida como tendo o valor “1” no arquivo de cabeçalho ”.h” do dispositivo usado. Assim, os comandos dentro do laço while serão sempre executados na ordem em que aparecem. Imaginemos agora que não desejamos mais que o LED fique piscando indefinidamente, mas gostaríamos que ele piscasse apenas uma quantidade de vezes definida, digamos, dez vezes, e em seguida ele deve permanecer aceso. O programa que executa esta função é mostrado abaixo, e uma explicação é dada em seguida. Na linha: int contador; temos uma declaração de variável. Este comando determina que o compilador crie uma variável do tipo inteiro int chamada contador. Esta operação irá na realidade reservar uma posição na memória RAM do PIC para armazenar valores relativos a essa variável. Durante a execução do programa, esse valor pode ser alterado pelo programa, daí essa posição ser chamada de variável. O tipo inteiro int especifica um tipo de dado de 8 bits com valores compreendidos entre 0 e 255 decimal. Em seguida temos a linha: contador=0; que se constitui numa operação de atribuição. As atribuições em C são executadas pelo operador de igualdade “=”. Desta forma, essa linha fará com que o compilador gere uma sequência de instruções para fazer com que o valor zero decimal seja armazenado na posição de memória do PIC nomeada como “contador”. No laço while, a condição agora é que a variável contador seja menor que dez. Isso é verdadeiro, já que a variável contador possui o valor zero. Assim, o bloco de // Quinto exemplo #include <16F877A.h> #fuses HS #use delay(clock=20M) main() { int contador; //definição da variável contador contador=0; //inicialização da variável com zero while(contador<10) //laço de repetição { output_high(pin_b0); //seta o pino rb0 delay_ms(500); //aguarda 500ms output_low(pin_b0); //reseta o pino rb0 delay_ms(500); //aguarda 500ms contador=contador+1; } output_high(pin_b0); //seta o pino rb0 } Curso – Microcontroladores PIC e Linguagem C Prof. Fagner de Araujo Pereira 38 comandos dentro das chaves é executado, fazendo com que o LED acenda, espere 500ms, apague, espere mais 500ms e, depois de feito isso, temos a linha: contador=contador+1; que é uma operação de atribuição, fazendo com que a variável contador seja modificada para o valor atual do contador mais uma unidade, ou seja, o contador agora passa a ter o valor de 1, já que antes possuía o valor zero. Após essa instrução, a condição do laço while é mais uma vez testada. Nesse caso, o contador possui o valor 1, e é menor do que 10, fazendo com que o teste da condição seja verdadeiro (contador<10). Então, mais uma vez o bloco dentro das chaves é executado, fazendo o LED acender e piscar mais uma vez. No final, a variável contador é novamente incrementada, passando a ter o valor 2, já que deve assumir o valor atual mais uma unidade. O teste da condição do laço while é feito mais uma vez, resultado em verdadeiro, já que 2<10, e o processo se repete até que a variável contador assuma o valor 9. Quando a variável contador assume o valor 10, o teste da condição while não é mais verdadeiro, ou seja, 10 não é menor do que 10. Com isso, o bloco de comandos dentro do laço while não é mais executado, e o programa passa direto para o comando que vem em seguida, que no caso é o comando output_high(pin_b0), que seta o pino rb0, fazendo com que o LED se acenda e fique permanentemente aceso. O LED então piscou dez vezes e em seguida ficou permanentemente aceso, como era o nosso interesse. 4.4 O laço For O laço for é uma das mais comuns estruturas de repetição, sendo a versão em C considerada uma das mais poderosas e flexíveis dentre todas as linguagens de programação.
Compartilhar