Este artigo é continuação da série Intel 8051 e tem como principal objetivo apresentar o conjunto de instruções do Intel 8051. De acordo com Patterson e Hennessy, a linguagem que um computador entende é chamada de instruções e seu vocabulário é denominado conjunto de instruções. Basicamente, as instruções indicam as operações que são executadas e os operandos utilizados. Além disso, as instruções são codificadas como números binários e são armazenadas na memória principal. Assim, o formato armazenado na memória é chamado de linguagem de máquina, já sua representação simbólica é chamada de linguagem de montagem ou Assembly.
Antes de Escrever o Programa
Um programa é essencialmente uma série de instruções gravadas em memória. O desenvolvimento dos programas em Assembly consiste na declaração dessas instruções e da utilização de um montador para convertê-las para linguagem de máquina. Além disso, o programa em Assembly contém diretivas que especificam parâmetros ao montador (Assembler), isto é, são comandos passados para o montador e que não são convertidos em linguagem de máquina.
Geralmente, uma linha de um programa em Assembly possui:
- Label: Pode ser utilizado para nomear a linha do código de contém a instrução indicada.
- Mnemônico: É o nome da instrução.
- Operandos: São informações utilizadas na execução de uma instrução. Cabe ressaltar que algumas instruções não possuem operandos.
- Comentários: São opcionais. Devem ser iniciados com ‘;’ e descrever a operação realizada na respectiva linha.
ORG 00h ; endereço inicial do programa
MOV A, #1 ; move valor 1 para Acumulador
LOOP:
MOV P1, A ; move conteúdo do Acumulador para P1
SETB P1.4 ; faz P1.4 = 1 (pull-up interno) - pino de entrada
JNB P1.4, CH_PR ; testa se P1.4 é igual a zero. Se sim, vai para CH_PR
RR A ; se não, rotaciona os bits do Acumulador para direita
SJMP LOOP ; pula para LOOP
CH_PR:
RL A ; rotaciona os bits do Acumulador para esquerda
SJMP LOOP ; pula para LOOP
END
Nesse exemplo, a diretiva ORG <número> determina a posição da memória em que a próxima instrução será colocada na memória de programa. Já a diretiva END indica o fim do programa.
Modos de Endereçamento
- Direto:
- O endereço do operando é determinado pela própria instrução (endereço de 8 bits).
- Neste caso, apenas a RAM interna e os registradores especiais podem ser acessados.
- Indireto:
- O endereço do operando é determinado por um registrador.
- Um endereço de 8 bits pode ser determinado pelos registradores R0~R1 do banco de registradores atual, ou pelo Stack Pointer.
- Endereços de 16 bits só podem ser especificados pelo registrador DPTR.
- Imediato:
- O operando é a constante.
- Registrador:
- Os registradores R0~R7 do banco atual são acessados pela instrução.
- Registrador Específico:
- A operação da instrução é realizada em um registrador específico.
- Neste caso, não é necessário indicar um endereço.
- Indexado:
- Somente a memória de programa pode ser acessada.
- Apenas operações de leitura são possíveis.
- Utilizado em instruções de salto e look-up table.
No último modo, os registradores PC e DPTR podem ser usados para armazenar um endereço base. Já o acumulador é utilizado para determinar o offset.
Conjunto de Instruções
- Símbolos utilizados:
- C: Flag de carry;
- A: Acumulador;
- PC: Contador de Programa;
- DPTR: Ponteiro;
- N: Endereço de 8 bits;
- NN: Endereço de 16 bits;
- #N: Constante de 8 bits;
- Rn: Registrador Rn (R0~R7) do banco atual de registradores;
- @Ri: Endereço é determinado pelo registrador Ri (R0 ou R1);
- H: indica que o valor está na base hexadecimal;
- B: indica que o valor está na base binária;
- Instruções de Movimentação de Dados
![]() | ![]() |
De modo geral, quando o destino é o acumulador:
|
MOV |
A,Rn | Move o registro Rn para o Acumulador |
|
MOV |
A,N | Move o conteúdo da memória N para o Acumulador |
|
MOV |
A,@Ri | Move o conteúdo da RAM endereçada por Ri para o Acumulador |
|
MOV |
A,#N | Move a constante N para o Acumulador |
|
MOVC |
A,@A+DPTR | Soma A + DPTR obtendo um endereço de 16 bits na memória de programa. Carrega o acumulador com o conteúdo desta memória |
|
MOVC |
A,@A+PC | Idem ao anterior, mas soma A + PC |
|
MOVX |
A,@Ri | Move o conteúdo da RAM endereçada por Ri para o Acumulador |
|
MOVX |
A,@DPTR | Move RAM externa endereçada por DPTR (endereço 16 bits) para o Acumulador |
|
XCH |
A,Rn | Troca entre si o conteúdo do Acumulador e do Registro Rn |
|
XCH |
A,N | Troca entre si o conteúdo da memória N com Acumulador |
|
XCH |
A,@Ri | Troca entre si a RAM endereçada por Ri com Acumulador |
|
XCHD |
A,@Ri | Troca entre si o nibble menos significativo do Acumulador e da RAM endereçada por Ri |
Quando o destino é um registrador:
|
MOV |
Rn,A |
Move o Acumulador para o registro Rn |
|
MOV |
Rn,N |
Move o conteúdo da memória N para o registro Rn |
|
MOV |
Rn,#N |
Move a constante N para o registro Rn |
|
MOV |
DPTR,#NN |
Move constante NN para o DPTR |
Quando o destino é um endereço direto:
|
MOV |
N,A | Move o Acumulador para a memória N |
|
MOV |
N,Rn | Move o registro Rn para a memória N |
|
MOV |
N1,N2 | Move o conteúdo da memória N2 para a memória N1 |
|
MOV |
N,@Ri | Move RAM endereçada por Ri para a memória N |
|
MOV |
N,#N | Move a constante N para o conteúdo da memória N |
|
PUSH |
N | Incrementa o SP e então coloca a memória no Stack |
|
POP |
N |
Retira dado do Stack e coloca na memória, depois decrementa SP |
Quando o destino é um endereço indireto:
|
MOV |
@Ri,A | Move o Acumulador para a RAM endereçada por Ri |
|
MOV |
@Ri,N | Move o conteúdo da memória N para a RAM endereçada por Ri |
|
MOV |
@Ri,#N | Move a constante N para a RAM endereçada por Ri |
|
MOVX |
@DPTR,A | Move Acumulador para a RAM externa endereçada por DPTR (endereço 16 bits) |
- Instruções Aritméticas
Quando o destino é o acumulador:
|
ADD |
A,Rn |
Soma Rn ao Acumulador |
|
ADD |
A,N |
Soma o conteúdo da posição de memória N ao Acumulador |
|
ADD |
A,@Ri |
Soma o conteúdo da RAM endereçada por Ri ao Acumulador |
|
ADD |
A,#N |
Soma a constante N ao Acumulador |
|
ADDC |
A,Rn |
Soma Rn e o flag Carrry ao Acumulador |
|
ADDC |
A,N |
Soma o conteúdo da posição de memória N e o flag Carry ao Acumulador |
|
ADDC |
A,@Ri |
Soma o conteúdo da RAM endereçada por Ri e o flag Carry ao Acumulador |
|
ADDC |
A,#N |
Soma a constante N e flag Carry ao Acumulador |
|
SUBB |
A,Rn |
Subtrai Rn e o flag Carry do Acumulador |
|
SUBB |
A,N |
Subtrai o conteúdo da posição de memória N e o flag Carry do Acumulador |
|
SUBB |
A,@Ri |
Subtrai o conteúdo da RAM endereçada por Ri e o flag Carry do Acumulador |
|
SUBB |
A,#N |
Subtrai a constante N e o flag Carry do Acumulador |
|
INC |
A |
Soma 1 ao Acumulador |
|
DEC |
A |
Subtrai 1 do Acumulador |
|
DA |
A |
Ajuste decimal do Acumulador |
|
DIV |
AB |
Divide A e B, resultado: A inteiro e B resto |
|
MUL |
AB |
Multiplica A e B, resultado: BA |
Cabe ressaltar que nas operações de adição, subtração e incremento o flag de carry e de overflow são alterados. As operações de multiplicação e divisão zeram o flag de carry, e no caso da multiplicação, a flag de overflow é modificada. Além disso, a instrução de ajuste decimal também modifica a flag de carry.
Quando o destino é um registrador:
|
INC |
Rn |
Soma 1 ao Rn |
|
DEC |
Rn |
Subtrai 1 de Rn |
- Instruções Lógicas
Quando o destino é o acumulador:
| ANL | A, Rn | Operação “E” entre Rn e Acumulador |
| ANL | A,N | Operação “E” entre o conteúdo da memória N e o Acumulador |
| ANL | A,@Ri | Operação “E” entre RAM endereçada por Ri e Acumulador |
| ANL | A,#N | Operação “E” entre a constante N e Acumulador |
| ORL | A,Rn | Operação “OU” entre Rn e Acumulador |
| ORL | A,N | Operação “OU” entre memória N e Acumulador |
| ORL | A,@Ri | Operação “OU” entre RAM endereçada por Ri e Acumulador |
| ORL | A,#N | Operação “OU” entre constante N e Acumulador |
| XRL | A,Rn | Operação “OU EXCLUSIVO” entre Rn e Acumulador |
| XRL | A,N | Operação “OU EXCLUSIVO” entre o conteúdo da memória N e Acumulador |
| XRL | A,@Ri | Operação “OU EXCLUSIVO” entre RAM endereçada por Ri e Acumulador |
| XRL | A,#N | Operação “OU EXCLUSIVO” entre constante N e Acumulador |
Quando o destino é um endereço direto:
| ANL | N,A | Operação “E” entre Acumulador e memória N |
| ANL | N,#N | Operação “E” entre constante N e memória N |
| ORL | N,A | Operação “OU” entre Acumulador e conteúdo da memória N |
| ORL | N,#N | Operação “OU” entre constante N e conteúdo da memória N |
| XRL | N,A | Operação “OU EXCLUSIVO” entre Acumulador e conteúdo da memória N |
| XRL | N,#N | Operação “OU EXCLUSIVO” entre a constante N e o conteúdo da memória N |
Operação sobre o acumulador:
| RL | A | Faz A = 0 |
| CPL | A | Inverte o estado dos bits do Acumulador |
| SWAP | A | Troca os nibbles do Acumulador |
| RL | A | Rotação do Acumulador para esquerda |
| RLC | A | Rotação do Acumulador para esquerda através do flag Carry |
| RR | A | Rotação do Acumulador para direita |
| RRC | A | Rotação do Acumulador para direita através do flag Carry |
- Instruções Booleanas e de Desvio
Operações utilizando o endereçamento de bits:
| LR | bit | Zera o bit endereçado |
| SETB | bit | Seta o bit endereçado |
| CPL | bit | Inverte o estado do bit endereçado |
| MOV | bit,C | Move o flag Carry para o bit endereçado |
| JB | bit,N | Desvia se o bit endereçado estiver setado |
| JNB | bit,N | Desvia se o bit endereçado estiver zerado |
| JBC | bit,N | Desvia se o bit endereçado estiver setado e depois zera o bit |
Operações sobre o flag de Carry:
| CLR | C | Zera o flag Carry |
| SETB | C | Seta o flag Carry |
| CPL | C | Inverte o estado do flag Carry |
|
MOV |
C,bit | Move o bit endereçado para o flag Carry |
|
ANL |
C,bit |
Operação “E” entre o bit endereçado e o flag Carry |
|
ANL |
C,/bit |
Operação “E” entre o complemento do bit endereçado e o flag Carry |
|
ORL |
C,bit |
Operação “OU” entre o bit endereçado e o flag Carry |
|
ORL |
C,/bit |
Operação “OU” entre o complemento do bit endereçado e o flag Carry |
|
JC |
N |
Desvia se o flag Carry estiver setado |
|
JNC |
N |
Desvia se o flag Carry estiver zerado |
- Instruções de Salto
Instruções de salto incondicional são bastante simples. Basicamente, um endereço alvo é utilizado para alterar o fluxo de execução, isto é, o contador de programa. Na figura são mostradas as instruções capazes de alterar o fluxo de execução do programa, com exceção da instrução NOP, que não realiza nenhuma operação.

As instruções JMP e CALL possuem as seguintes variações:
| ACALL | N | Chama sub-rotina numa faixa de 2 Kbytes da atual posição |
| LCALL | NN | Chama sub-rotina em qualquer posição da memória de programa |
| AJMP | N | Desvia para outro endereço numa faixa de 2 Kbytes da atual posição. |
| LJMP | NN | Desvia para qualquer posição da memória |
| SJMP | N | Desvio curto relativo |
Outras duas instruções que alteram o valor do contador de programa são as de retorno de sub-rotina e retorno de interrupção.
| RET | Retorna da sub-rotina | |
| RETI | Retorna da interrupção |
O desvio também pode ser tomado com base no resultado de uma comparação. Nesse caso, o desvio é dito condicional.
| CJNE | A,N,N | Compara e desvia se o Acumulador for diferente do conteúdo da memória N |
| CJNE | A,#N,N | Compara e desvia se o Acumulador for diferente da constante N |
| CJNE | Rn,#N,N | Compara e desvia se o Rn for diferente da constante N |
| CJNE | @Ri,#N,N | Compara e desvia se a RAM endereçada por Ri for diferente da constante N |
| DJNZ | N,N | Decrementa o conteúdo da memória N e desvia se for diferente de “zero” |
| DJNZ | Rn, N | Decrementa Rn e desvia se for diferente de “zero” |
| JZ | N | Desvia se o Acumulador for “zero” |
| JNZ | N | Desvia se o Acumulador “não for zero” |
Cabe ressaltar que as instruções CJNE modificam a flag de carry.
- Exemplo de acesso a memória externa: Zera os elementos de um vetor que são iguais a FFH.
ORG 00h ; endereço inicial do programa
MOV DPTR, #500h ; move valor 500h para DPTR
MOV R0, #50 ; move valor 50 para R0
LOOP:
MOVX A, @DPTR ; move conteúdo apontado por DPTR para Acumulador
CJNE A, #0FFH, DIFER ; compara conteúdo do Acumulador com 0FFH. Se for diferente, vai para DIFER
MOV A, #0 ; caso contrário, move valor 0 para Acumulador
MOVX @DPTR, A ; move conteúdo do Acumulador para endereço apontado por DPTR
DIFER:
INC DPTR ; incrementa DPTR
DJNZ R0, LOOP ; decrementa R0 e compara com 0. Se for diferente, vai para LOOP
SJMP $ ; espera (LOOP)
END
- Exemplo de acesso a memória externa: Copia os dados de um vetor para outro.
ORG 00h ; endereço inicial do programa
MOV R0, #0 ; move valor 0 para R0 (endereço de origem)
MOV R1, #50 ; move valor 50 para R1 (número de elementos)
MOV DPTR, #50h ; move valor 50H para DPTR (endereço de destino)
LOOP:
MOVX A, @R0 ; move para Acumulador o conteúdo do endereço apontado por R0
MOVX @DPTR, A ; move conteúdo do Acumulador para endereço apontado por DPTR
INC R0 ; incrementa R0 (endereço de origem)
INC DPTR ; incrementa DPTR (endereço de destino)
DJNZ R1, LOOP ; decrementa R1. Se for diferente de zero, vai para LOOP
SJMP $ ; espera
END
Referências
- [1] MCS® 51 Microcontroller Family User’s Manual.
- [2] HARRIS. D. M; HARRIS. S. L. Digital Design and Computer Architecture. Elsevier. 2012.
- [3] PATTERSON. D. A.; HENNESSY. J. L. Computer Organization and Design: The Hardware/Software Interface 5th Edition. Morgan Kaufmann-Elsevier. 2013.
- Imagem Destacada.












Só uma dúvida nessa parte Fernando Deluno Garcia:
“SUB A,#N Subtrai a constante N e o flag Carry do Acumulador”
Esse SUB não deveria ser SUBB? Já que os demais acima seguiram essa lógica.
E, por curiosidade, por que não tem SUB para as mesmas que tem SUBB?
Ainda estou apanhando um pouco, mas está bem prazeroso.
Olá, Souza.
Obrigado pela correção. Faltava um B!
Na verdade, SUBB significa subtract with borrow. Nesse caso, borrow é a flag de Carry.
Obrigado pelo pronto atendimento. Quero ficar bom nesse negócio. É um mundo repleto de possibilidades. E o meu cérebro é muito inquieto. Na hora do descanso não posso simplesmente “desligar” o cérebro. Tenho que mantê-lo em atividade o tempo todo (ao menos enquanto estou acordado e, alem de tudo, durmo muito pouco). Pode parecer prejudicial (talvez seja um pouco), mas já tenho mais de 50 anos se sempre foi assim e me sinto muito bem sendo assim. Quando tentei “aquietar” a mente foi pior. Aquela coisa de família propensa a depressão é complicado. Mas, do jeito que faço tem dado… Leia mais »
Parabéns pela série Fernando. Muito legal rever algo que aprendi lá no técnico (e me lembrava vagamente).
Vou aproveitar os artigos, pegar o protoboard e brincar com assembly de 8051 novamente.
Muito obrigado, Haroldo!
É sempre bom voltar às origens ahah.