Programando o 8051

Existem várias linguagens/compiladores disponíveis para o 8051 como Asm, Pascal, C, Basic. O assembler é uma linguagem de baixo nível permitindo ter controle sobre cada registrador, cada posição de memória. A programação em assembler torna possível explorar toda a capacidade do microcontrolador de maneira mais eficiente. Programando em linguagem de alto nível como o C, fica mais fácil criar programas mais complexos, não é necessário ter controle de cada registrador, cada posição de memória, simplesmente utilize variáveis, realize operações matemáticas, lógicas, subrotinas. Atribua valores negativos às variáveis, valores maiores que 255, textos.

Assembler ASEM-51

O ASEM-51 é um macro assembler para a família 8051 que roda em Linux, Windows e DOS. Sua sintaxe é igual ao assembler da Keil. Tem suporte à outros modelos como o Atmel 89S8252. Está disponível no site http://plit.de/asem-51/ (freeware).

Compilador SDCC

O SDCC é um compilador C ANSI para 8051 que roda em Linux, MAC OSX e Windows. Suporta variáveis do tipo char (8 bits, 1 byte), short (16 bits, 2 bytes), int (16 bits, 2 bytes), long (32 bit, 4 bytes) e float (4 bytes), possui otimizador interno, inline assembler, memória externa (model-large), 256 bytes ram (128+128 indireta).  É um excelente compilador freeware, suporta modelos como os da Atmel. Seu código gerado é maior que em comparação ao compilador da Keil.  Para fazer o download visite a página: http://sdcc.sourceforge.net/ (é freeware).

Rotinas para 8051


LCD Gráfico 128x64

Clique no link abaixo para fazer o download do programa em assembler para display gráfico KS0108. Possui rotinas para escrever texto com fonte 8x8 e 7x5, e rotina para desenhar pontos. À partir dessa rotina é possível implementar outras mais complexas como desenhar círculos, retas e retângulos. O programa funciona em qualquer família 8051 rodando à 12Mhz.

> lcdgrafc.asm  (em assembler)

Rotina LCD gráfico para 8051 em C (compila no SDCC): (rotinas de texto, ponto, linha, retângulo)

> lcdgrafic.zip   (em C)

EEPROM do AT89S8252


Leitura e gravação da eeprom

;****************************************************************************
; Le dado da EEprom
;****************************************************************************
; Entrada: DPTR (posicao de 000h a 7FFh)
; Saida: A (dado)
; Regs alterados: A

le_eeprom:
  mov 96h,#00001000b ; habilita leitura da EEprom (seleciona bit EEMEN do reg. WMCON)
  movx A,@DPTR       ; Le eeprom
  mov 96h,#00000000b ; desabilita o acesso a eeprom
ret
;****************************************************************************

;****************************************************************************
; Grava dado na EEprom
;****************************************************************************
; Entrada: DPTR (posicao de 000h a 7FFh), A (dado)
; Regs alterados:

grava_eeprom:
  mov 96h,#00011000b ;Habilita gravacao da eeprom
  movx @DPTR,A       ;Grava eeprom
  grava_eeprom_espera: ;Espera a eeprom ser gravada
  mov A,#00000010b     ; bit RDY/BSY
  anl A,96h            ; verifica o bit RDY/BSY do registrador WMCON (96h)
  jz grava_eeprom_espera   ; se o bit for "0", continua no loop.
  mov 96h,#00000000b   ;Desabilita o acesso a eeprom
ret
;****************************************************************************

Rotina SPI via hardware do 89S8252
Exemplo de inicialização e uso do canal SPI

$NOMOD51
$INCLUDE (Asem51\MCU\89S8252.MCU)

SPIF EQU 10000000b   ; bit numero 7 obs: a interrupcao SPI deve permanecer desligada

SPI_init:            ; inicializacao do hardware SPI
  setb SS
  setb MOSI
  setb MISO
  setb SCK
  mov SPCR, #01110011b  ; spi master, sem interrupcao, pin enable, lsb first, polar 0, phase 1, clock/64 ret

masterSPI:
;Envia e recebe pela porta SPI.
;Entrada: A , Saida: A
  mov SPDR, A
  masterSPI_loop:
  mov A, SPSR           ; le registrador de status
  anl A,#SPIF           ; compara bit SPIF
  jz masterSPI_loop
  mov A, SPDR
ret

ex:                     ; exemplo de uso
  clr SS
  mov a, #55h
  call masterSPI
  setb SS

 

Serial com Timer 2
Exemplo de utilização da serial com timer 2 no 89S8252 e com o assembler ASEM-51

$NOMOD51
$INCLUDE (Asem51\MCU\89S8252.MCU)

LF EQU 0AH
CR EQU 0DH

BAUDL EQU 0D9H ;taxa de transmissao de 9600 com 12 Mhz
BAUDH EQU 0FFH ;taxa de transmissao de 9600 com 12 Mhz
;BAUDL EQU 0F3H ;taxa de transmissao de 28800 com 12 Mhz
;BAUDH EQU 0FFH ;taxa de transmissao de 28800 com 12 Mhz
;BAUDL EQU 0F6H ;taxa de transmissao de 38400 com 12 Mhz
;BAUDH EQU 0FFH ;taxa de transmissao de 38400 com 12 Mhz

ORG 00H
LJMP INICIO

ORG 0023H
LJMP SERI

INICIO:

mov SCON, #01010000b
mov RCAP2L, #BAUDL
mov RCAP2H, #BAUDH
mov T2CON, #00110100b

SETB TR2
mov A,#30h
call transmite
call transmite

loop2:
lcall RECEBE
sjmp loop2

RECEBE:
JNB RI,NAORECEBEU
CLR RI
LCALL TRANSMITE
NAORECEBEU:
RET

TRANSMITE:
CLR TI
MOV SBUF,A
JNB TI,$
RET

SERI:
JB RI,LER
RETI

LER:
mov A,SBUF
RETI

END
 

 

Rotina I2C via software para 8051
Compila no SDCC. Fácil de converter para assembler

#define i2c_EscEnd(d) _i2c_send(d,0)    // Envia endereco I2C para escrita
#define i2c_LeEnd(d) _i2c_send(d,1)     // Envia endereco I2C para leitura
#define i2c_Escreve(d) _i2c_send(d,0xff)  // Escreve um byte para o periferico
#define i2c_LeByte() _i2c_read(0)         // Le um byte do periferico
#define i2c_LeUltimoByte() _i2c_read(1)   // Le o ultimo byte do periferico
#define i2c_Fim() _i2c_send(0,0xfe);      // Finaliza a comunicacao

#define _sda _P2_5  // Pino SDA do barramento I2C
#define _scl _P2_4  // Pino SCL do barramento I2C

#define I2CEXT 0x42   // Endereco I2C do chip PCF8574
#define I2CMEM 0xAC   // Endereco I2C do chip eeprom AT24C32
#define I2CTIMER 0xA0 // Endereco I2C do chip de timer PCF8583

unsigned char _i2c_send(unsigned char endr, unsigned char modo);
unsigned char _i2c_read(unsigned char ack);


unsigned char _i2c_send(unsigned char endr, unsigned char modo)
{

  tmp = endr;
  tmp2 = modo;

_asm
  mov a,_tmp2
  inc a
  clr c
  jz 0$
  inc a
  clr c
  jz 2$

  mov a,_tmp
  add a,_tmp2
  mov _tmp,a

;inic
09$:
  setb _sda
  setb _scl
  nop
  nop
  nop
  nop
 
  nop
  nop
  nop
  nop
;star
; mov a,_tmp
  clr _sda
  nop
  nop
  nop
  clr _scl
;send
0$: mov a,_tmp
  mov _tmp,#8
1$: rlc a
  mov _sda,c
  setb _scl
  nop
  nop
  nop
  clr _scl
  nop
  nop
  djnz _tmp,1$
  setb _sda
  nop
  nop
  setb _scl
  nop
  nop
; mov c,_sda
  nop
  nop
  mov c,_sda
  clr _scl
  nop
  mov _tmp,#0
  jnc 3$
; sjmp 3$
;stop
2$:
  clr _sda
  nop
  setb _scl
  nop
  nop
  nop
  nop
  setb _sda
  nop
  nop
  nop
  inc _tmp

3$:
_endasm;
return tmp;
}

// se ack = 1, ultimo byte
unsigned char _i2c_read(unsigned char ack)
{
  tmp2 = ack;
_asm
;read
  mov _tmp,#8
  clr a
0$: setb _sda
  nop
  nop
  setb _scl
  nop
  nop
  mov c,_sda
  nop
  nop
  clr _scl
  rlc a
  djnz _tmp,0$
  mov _tmp,a
  nop
  nop
  nop
  nop
;ack
  mov a,_tmp2
  jnz 1$
  clr _sda
  sjmp 2$
1$: setb _sda
2$: setb _scl
  nop
  nop
  nop
  nop
  nop
  nop
  clr _scl
_endasm;

return tmp;
}


/*
exemplos de uso:

//escreve em memoria externa:
 i2c_EscEnd(I2CMEM);
 i2c_Escreve(0);       // endereco da memoria (high) (16bits)
 i2c_Escreve(0);       // endereco (low)
 i2c_Escreve(16);      // dado
 i2c_Escreve(0);       // dado
 i2c_Fim();

//le memoria externa
 i2c_EscEnd(I2CMEM);
 i2c_Escreve(0);      // endereco
 i2c_Escreve(0);      // endereco
 i2c_LeEnd(I2CMEM);
 valor = i2c_LeByte();
 valor2 = i2c_LeUltimoByte();    // precisa chamar esta funcao no ultimo byte lido
 i2c_Fim();

//le a entrada do I/O externo
 i2c_LeEnd(I2CEXT);
 valor = i2c_LeUltimoByte();
 i2c_Fim();

//le somente a hora do relogio i2c
 i2c_EscEnd(I2CTIMER);
 i2c_Escreve(0x04);      // 0x04 = hora
 i2c_LeEnd(I2CTIMER);
 hora = i2c_LeUltimoByte(); 
 i2c_Fim();

*/

Referências

http://plit.de/asem-51/
http://sdcc.sourceforge.net/
http://www.microcontrolador.com.br/


Voltar

>    © 2013 Rafael Ferrari (RafaelBF)   >    rafa.eng.br   >    email