Prévia do material em texto
DISCIPLINA: SISTEMAS MICROPROCESSADOS - DAE01228 - SEMESTRE / ANO 2021, SEMESTRE - 2020-II Roteiro No 2 INTRODUÇÃO AO ASSEMBLY EGOAVIL, C. J.1, MEDEIROS, J. C.2 1Professor do Curso de Engenharia Elétrica - DAEE, Fundação Universidade Federal de Rondônia, Sala 314 - 4H, Porto Velho, Rondônia, Brasil (e-mail: ciro.egoavil@unir.br). 2Monitor voluntário. RESUMO Este roteiro faz uma introdução da programação em linguagem assembly para microcontrolado- res PIC. É apresentada a maneira de ler e escrever nas portas do microcontrolador, e também é apresentado a construção de rotinas de delay. 1 INTRODUÇÃO A linguagem Assembly, que possui como extensão o sufixo “.asm”, é uma linguagem de programação de baixo nível, (é bom que se entenda que baixo nível aqui não seja associado a qualidade que é precária e sim uma linguagem que se aproxima mais da funcionalidade real que as máquinas ope- ram), por isso, o estudo dela torna-se muito interessante para estudantes de Engenharia ainda em nosso dias, pois, permite detidamente o funcionamento exercido pelos Microcontrola- dores através de ferramentas de debbuger. Cada linguagem assembly é específica da arquitetura de um microcontrolador. Normalmente, em uma linguagem assembly, cada linha do programa é executada em um ciclo de máquina o que ocasiona rapidez a depender do clock utilizado. O código criado em assembly é convertido para linguagem de máquina por meio de um assembler (um compilador transforma cada linha de código com instruções em Assembly, neste caso, para sequência de “zeros e uns1”) que possibilita que as máquinas realizem tarefas complexas [1]. 2 OBJETIVOS O objetivo deste roteiro é introduzir no processo de apren- dizado e formação do estudante a programação em lingua- gem assembly para microcontroladores PIC, especificamente para o PIC16F877A. Para esse desígnio, um código em linguagem assembly será desenvolvido para realizar a leitura do estado de um botão. Se o botão estiver pressionado, um LED deve ser ligado, caso contrário desligado. Um outro código será ela- borado para fazer com que um LED pisque com intervalos específicos. 1uma tensão ou a falta dela, 5V ou 0V 3 SOFTWARES UTILIZADOS • MPLAB X • PICSimLab 4 EXEMPLO 1 Um projeto no MPLAB x deve ser criado como mostrado no roteiro anterior, mas na janela para selecionar o compila- dor mpasm deve ser selecionado Figura 1. Figura 1: Janela de seleção de compilador. No menu esquerdo, clique com o botão direito do mouse em Source e em New clique em pic_8b_simple.asm. Este é o arquivo principal que possui extensão do tipo “.asm”, como pode-se vê na Figura 2. Dê um nome e clique em Finish. Roteiro 2, Ano 2021, Semestre 2020.2 1 Figura 2: Inserindo o arquivo principal do tipo .asm. Apague todo o código nativo no arquivo criado. Como no roteiro anterior, os bits de configuração do Microcontrolador devem ser configurados. Faça a configuração como mostrado na figura 3 e clique em Generate Source Code to Output. Copie o código gerado e cole no começo do arquivo principal. Figura 3: Configuration bits. Para facilitar os chaveamentos para os bancos de memória apropriados durante a elaboração dos códigos, pode-se criar mnemônicos para acessar o respetivo banco de memória de forma mais sucinta do que por padrão são realizadas, isso agiliza o processo na elaboração dos códigos. A partir da definição como será demonstrado a seguir, sempre que for ne- cessário o chamamento de um banco quaisquer basta chamá- lo pelo mnemônico respectivo. É necessário que o usuário veja o datasheet do Microcontrolador que será utilizado para compreender as duas linhas de código que define a seleção do banco 0 e do banco 1 de memória. Neste caso, o datasheet é do PIC 16F877A que é especificado pelo fabricante através do tópico MEMORY ORGANIZATION. Nesse tópico, o fa- bricante utiliza o Registrador de Função Especial STATUS. A análise detida desse registrador possibilitará a compreensão efetiva. #define bank0 bcf STATUS,RP0 #define bank1 bsf STATUS,RP0 Em seguida, os pinos que serão utilizados também podem ser pre-definidos. As linhas de códigos seguintes poderão ser melhores compreendias se o usuário realizar a análise que fora exposta para as duas primeiras linhas de código, atentando-se simplesmente para o registrador apropriado. Um fato interessante é o usuário não use carácter da língua portuguesa para a crianção desses mnemônicos, pois, não serão compreendido pelo compilador ocasionando erros de sintaxe. Neste caso, veja que botão está sem o til. #define botao PORTB,RB0 #define led PORTB,RB1 O Vetor de Reset equivale a posição “H ’0000’ ”, em he- xadecimal, a origem ou início da memória. Isto significa que sempre que o Microcontrolador for reiniciado externamente o processamento, necessariamente, é retomado a partir desse endereço da memória. As linhas de códigos seguintes pode- rão ser melhores compreendias se o usuário realizar a análise que fora exposta para as duas primeiras linhas de código, atentando-se simplesmente para o registrador apropriado. org H’00’ goto inicio O código não traz uma rotina de interrupção, mas caso o usuário deseje inserir, basta acrescentar as duas linhas de código a seguir, logo após o bloco de código do Vetor de Reset, para uma boa organização do código. org H’0004’ goto retfie Isso implica que sempre que o Microcontrolador for inter- rompido, ele armazenará na pilha o endereço de memória onde fora interrompido e retornará a posição de memória “H ’0004’ ”, veja no datasheet a organização de memória do Microcontrolador utilizado, e retornará ao endereço de memória da interrupção através da “instrução” retfie. Aqui aparece a instrução “goto” (vá para, em português), neste caso, o usuário criou a label “inicio”, mas poderia ser uma label de quaisquer outro nome, interessante ressaltar que a linguagem Assembly não é CASE SENTIVE [2]2. E por está na mesma linha do “goto”, implica-se para o microcontrola- dor realizar a rotina “inicio”. A rotina “inicio” poderia ter quaisquer nome, como já explicado. Será nela que serão realizadas as configurações iniciais do microcontrolador como, por exemplo, o modo de operação das portas. Isso chama-se paginação de memória. Em assembly, cada registrador pertence a um determi- nado banco de memória, veja no datasheet a organização de memória do Microcontrolador utilizado. Para manipu- lar o Registrador TRISB o banco de memória 1 deve ser acessado, veja no datasheet a organização de memória do Microcontrolador utilizado. E para manipular o PORTB o banco de memória 0 deve ser acessado, veja no datasheet a organização de memória do Microcontrolador utilizado. Assim, a rotina inicio fica: inicio bank1 2Não faz diferença entre letras maiúsculas e minúsculas. 2 Roteiro 2, Ano 2021, Semestre 2020.2 movlw H’FD’ movwf TRISB bank0 movlw H’00’ movwf PORTB Para uma boa compreensão do que fora realizado no código, é bom que usuário atente-se aos porquês do chamamento oportuno de cada banco de memória. Isto está a atrelado a como o fabricante dispôs seus registradores através do que- sito organização de memória. veja no datasheet a organização de memória do Microcontrolador utilizado. O Registrador TRISB é um registrador que realiza a direção do fluxo de dados, entradas ou saídas digitais, e o Registrador PORTB é o que controla os estados lógicos dos bits correlatos. Os va- lores em hexadecimal proporcionam ao registrador específico seu modo de atuação. Após a rotina “inicio”, o laço infinito deve ser executado. As instruções serão: loop btfsc botao goto apaga_led bsf led goto loop A instrução btfsc testa se o botão foi pressionado ou não. No caso, se botao for igual a “0” a linha goto apaga_led é pulada e o LED é ligado pela intrução bsf e depois a rotina loop é chamada novamente. Se botao for “1”, a rotina para apagar o led (apaga_led) é chamada. apaga_led bcf led goto loop end Os Microcontroladores operam através de linhas de có- digos estruturadas, ou seja, executam o código linha após linha a depender de um desvio incondicional.Sabendo disso, fica fácil criar uma rotina qualquer bastando para isso que o usuário decida o que deseja que se realize em um projeto prático. Basicamente, na rotina apaga_led, o LED é apagado e depois a execução retorna para a rotina de loop. Todo código assembly deve terminar com end. O projeto pode agora ser compilado. O código completo e comentado está no Apêndice. Após compilado, o arquivo .hex pode ser carregado no PICSimLab, bastando clicar na tecla ICSP. Ao clicar no botão S1, o LED L2 deve acender. 5 EXEMPLO 2 Crie um novo projeto em Assembly e faça a configuração dos bits como mostrado no exemplo anterior. Faça também as definições dos bancos de memória “0” e 1”, e defina o LED1 no bit “0” do PORTB. Defina também o vetor de reiniciali- zação. Neste exemplo, serão utilizados dois registradores de uso geral, “uma variável”, em outras palavras; que contarão os ciclos de máquina. Segundo o datasheet do PIC16F877A, no tópico Organi- zação de Memória, no subtópico Organização de Memória de Dados, para o banco de memória 0, os registrados de uso geral (espaço na memória onde o usuário pode utilizar para criar suas “variavéis” que serão utilizadas no código) estão disponíveis do endereço 0x20 ao 0x7F. Para este exemplo, serão necessários dois desses registradores. veja no datasheet a organização de memória do Microcontrolador utilizado. No código, definiremos a localização dos registradores após a definição dos bancos de memória como. Qualquer uma das formas de declaração a seguir é aceito em Assembly: #define contador1 H’20’ #define contador2 H’21’ cblock contador1 contador2 endc contador1 equ H‘20’ contador1 equ H‘21’ Na rotina de início temos que definir o modo de operação dos pinos do PORTB. Faremos: inicio bank1 movlw H’FE’ movwf TRISB bank0 A rotina de loop é simples, porém, o usuário precisa saber como o Microcontrolador realiza esse processo. Após a ins- trução bsf PORT,RB0 o Microcontrolador, obrigatoriamente, entra na linha de código call, execução estruturada - linha após linha, e guarda esse endereço de memória na pilha, pois saiu do modo da sequência de estruturação padrão, e retor- nará exatamente nesse endereço para continuação sequencial do código. Basicamente, o LED será ligado, passarão 500ms em nível alto aí o LED será desligado e passarão mais 500ms em nível baixo. Para que o usuário segure o Microcontrolador por um tempo qualquer, (delay), em uma função de tempori- zação, será necessário que se tenha a compreensão de quanto tempo o Microcontrolador leva para completar cada ciclo de máquina. A matemática do cálculo do tempo dos 500ms será explicado e deixado como comentário no código específico. A rotina será: loop bsf PORTB,RB0 Roteiro 2, Ano 2021, Semestre 2020.2 3 call delay500ms bcf PORTB,RB0 call delay500ms goto loop A instrução call serve para chamar uma subrotina, que no caso é a subrotina de delay apresentada abaixo. O código anteriormente apresentado é auto-explicativo, bastando para tal conhecer o significado de cada “palavra” utilizada. delay500ms movlw D’200’ movwf contador1 aux1 movlw D’250’ movwf contador2 _aux2 nop nop nop nop nop nop nop decfsz contador2 goto _aux2 decfsz contador1 goto _aux1 return As rotinas “_aux1” e “_aux2” são rotinas auxiliares para a rotina de delay principal (delay500ms). Isso se faz necessário para que se consiga prender o Microcontrolador em um trecho de código especifico através do chamado delas. A instrução decfsz executa a linha subsequente se o regis- trador atribuído que está sendo decrementado não seja zero e salto uma única linha, imediatamente a ele, caso o registrador atribuído seja zero. Caso o “contador2” seja zero a linha goto _aux2 é saltada e em seguida o “contador1” é decre- mentado e retorna a _aux1 recarregando o do “contador2” . A instrução nop é utilizada para gastar um ciclo de máquina sem que exerça qualquer função. Dentro da rotina “_aux2”, do primeiro nop ao goto _aux2 são gastos 10 ciclos de máquina. Quando “contador2” chega a zero, são gastos 2500 ciclos de máquina vezes os 10 ciclos explicados anteriormente. E até que “contador1” chegue a zero são gastos aproximadamente 500.000 ciclos de máquina. Usando um cristal oscilador de 4 MHz, esses ciclos equiva- lem a 500ms aproximadamente. A instrução return encerra uma rotina e reconduz o Microcontrolador ao endereço armazenado na pilha. Não podemos esquecer de finalizar o código com end. Após isso, ao carregar o arquivo .hex no PICSimLab, veremos o LED L1 aceso por 500ms e apagado pelo mesmo tempo, 500ms. 6 EXERCÍCIOS 1) Fazer, de duas formas diferentes, os LEDs L2 e L3 alterarem seus estados de forma complementar quando o botão for pressionado (L2 ligar e L3 desligar quando o botão for pressionado, e o contrário quando o botão não for acionado). Dica: fazer alterando o valor do PORTB, e também alterando os bits específicos do PORTB. 2) Fazer que o LED L1 acenda e permaneça aceso quando o botão for pressionado. Se o botão for pressionado novamente, o LED deve apagar. Dica: utilizar delay para evitar bouncing effect. 3) Entregar os códigos comentados. Referências [1] J. D. de Souza, Desbravando o Pic - Baseado no Microcontrolador Pic16f84. Saraiva Educação SA, Érica, 2006. [2] E. W. Rambo, “Wrkits channel: Curso de assembly para pic.” 4 Roteiro 2, Ano 2021, Semestre 2020.2 APÊNCICE A - CÓDIGO COMPLETO DO EXEMPLO 1 ; --- Arquivos incluídos no projeto --- #include <p16f877a.inc> ; Inclui o arquivo do microcontrolador ; CONFIG ; __config 0x3F3A __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _BOREN_OFF & _LVP_OFF & _CPD_OFF & _WRT_OFF & _CP_OFF ; --- Paginação de memória --- #define bank0 bcf STATUS,RP0 ; Cria mneumônico para o banco 0 de memória #define bank1 bsf STATUS,RP0 ; Cria mneumônico para o banco 1 de memória ; --- Entradas --- #define botao PORTB,RB0 ; Botão 1 ligado em RB0 ; --- Saidas --- #define led PORTB,RB1 ; LED 1 no RB1 ; --- Vetor de RESET --- org H’00’ ; Origem no endereço 0000h de memória goto inicio ; Desvia do vetor de interrupção ; --- Programa principal --- inicio bank1 ; Seleciona Banco 1 movlw H’FD’ ; W = 0b11111101 movwf TRISB ; Passa W para TRISB bank0 ; Seleciona o banco 0 de memória movlw H’00’ ; W = 0b00000000 movwf PORTB ; Passa W para PORTB loop btfsc botao ; Botao foi pressionado? ; (Testa se bit é 0, se sim, pula linha) goto apaga_led ; Não, desvia para apagar led1 bsf led ; Sim, liga led1 goto loop ; volta para label loop apaga_led bcf led ; Apaga led1 goto loop ; Volta para a label loop end ; Final do programa Roteiro 2, Ano 2021, Semestre 2020.2 5 APÊNDICE B - CÓDIGO COMPLETO DO EXEMPLO 2 ; --- Arquivos incluídos no projeto --- #include <p16f877a.inc> ; Inclui o arquivo do microcontrolador ; CONFIG ; __config 0x3F3A __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _BOREN_OFF & _LVP_OFF & _CPD_OFF & _WRT_OFF & _CP_OFF ; --- Paginação de memória --- #define bank0 bcf STATUS,RP0 ; Cria mneumônico para o banco 0 de memória #define bank1 bsf STATUS,RP0 ; Cria mneumônico para o banco 1 de memória ; --- Registradores de uso geral --- #define temp1 H’20’ #define temp2 H’21’ ; --- Saidas --- #define led PORTB,RB0 ; LED 1 no RB1 ; --- Vetor de RESET --- org H’00’ ; Origem no endereço 0000h de memória goto inicio ; Desvia do vetor de interrupção] inicio bank1 ; Seleciona Banco 1 movlw H’FE’ ; W = 0b11111110 movwf TRISB ; Passa W para TRISB bank0 ; Seleciona o banco 0 de memória loop bsf PORTB,RB0 ; Liga LED call delay500ms bcf PORTB,RB0 ; Desliga LED call delay500ms goto loop delay500ms movlw D’200’ movwf temp1 ; Armazena o valor 200 delay_aux1 movlw D’250’ movwf temp2 ; Armazena o valor 250 delay_aux2 nop ; Gasta 1 ciclo de máquina nop nop nop nop nop nop decfsz temp2 ; Decrementa temp2 e testa se é zero ; Se for zero, pula a próxima instrução goto delay_aux2 ; Total de 2500 ciclos decfsz temp1 ; Decrementa temp1 e testa se é zero ; Se for zero, pula a próxima instrução goto delay_aux1 ; Ao final 500000 ciclos return end 6 Roteiro 2, Ano 2021, Semestre 2020.2 Introdução ObjetivosSoftwares Utilizados Exemplo 1 Exemplo 2 Exercícios Referências