Uncategorized

Teclado MIDI AT89S51

teclado MIDI

teclado Casio reaproveitado

Teclado construído por volta de 2009… com intuito de aprender a programação de 8051 utilizando linguagem Assembly e também de reutilizar material que iria para o lixo.

teclado MIDI

teclado Casio reaproveitado

Um teclado Casio estava para ir pro lixo sem suas placas e botões. Então veio a ideia de criar um teclado MIDI com o 8051 (AT89S51). Fiz uma placa principal já com o AT89S51 , uma fonte de 5v, cristal e  barras de pinos para facilitar projetos (seria uama espécie de Arduino pré histórico 😉 ). Inicialmente a dúvida seria como ler as 49 teclas… a solução foi ler em formato de matriz, onde temos 8 linhas e 7 colunas o que dá o máximo de 56 teclas. As teclas foram agrupadas e lidas de 8 em 8 sendo que cada uma das 7 colunas é acionada de cada vez. Sendo assim, acionando a coluna 1 podemos ler as teclas de 1 a 8 e acionando a coluna 2 teremos leitura das teclas 9 a 16 e por aí segue. Para isso, foi selecionado o circuito integrado ULN2003 para servir de buffer e selecionar a coluna que estará ativa em cada ciclo.

Esquema teclado MIDI

Esquema teclado MIDI com AT89S51

Vista interna teclado MIDI

Vista interna teclado MIDI

O programa abaixo fixa uma coluna por vez e lê linha por linha e depois seleciona a próxima coluna. O estado das teclas são armazenados e a cada loop são comparados.

  1. Se a tecla não estava pressionada e agora está? envia comando ON
  2. Se a tecla não estava pressionada e agora também não? Não faz nada
  3. Se a tecla estava pressionada e agora não está? Envia comando OFF
  4. Se a tecla estava pressionada e agora continua pressioanda? Não faz nada

;www.omecatronico.com.br
;Autor: Almir M Ventura
;Variaveis e constantes associadas——–
;R0 ponteiro dos bits!
linha   EQU R1    ;indica qual linha estamos trabalhando…
nota    EQU R2    ;byte que guarda a nota a ser tocada ou interrompida.
canal   EQU R3   ;byte que guarda o canal MIDI ( vai de 1 a 16)
coluna EQU P1    ;PORT 1 varrerá as colunas e PORT 0 serão as linhas

;************************* RESET ************************

ORG 0h               ; Diretiva de origem no endereco 0h
LJMP INICIO    ; Salto para o inicio do programa
;***INT EXTERNA_0***

ORG 03h                       ; Externa 0
LJMP EXTERNA_0   ; Salta para Rotina Externa 0

;***INT TIMER_0***

ORG 0Bh                        ; TIMER 0
LJMP TIMER_0           ; Salta para Rotina TIMER 0

;***INT EXTERNA_1***

ORG 13h                          ; EXTERNA 1
LJMP EXTERNA_1      ; Salta para Rotina EXTERNA 1

;***INT TIMER_1***

ORG 1Bh                         ; TIMER 1
LJMP TIMER_1            ; Salta para Rotina TIMER 1

;***INT SERIAL***

ORG 23h                          ; SERIAL
LJMP SERIAL_COM    ; Salta para Rotina SERIAL_COM

INICIO:
;vamos gravar nas memorias das teclas que elas estavam pressionadas…
;com isso ao ligar vamos enviar off para todas as teclas no primeiro loop!
MOV 20h, #0     ; “zera” memoria das teclas 1->8
MOV 21h, #0      ; 8->16
MOV 22h, #0     ; 17->24
MOV 23h, #0     ; 25->32
MOV 24h, #0     ; teclas 33->40
MOV 25h, #0     ; teclas 41->48
MOV 26h, #0     ; teclas 49->56
;configurando a porta serial…
;timer 1 para 19200 baud
;TH1 = 256 – ((Crystal / 192) / Baud)
;TH1 = 256 – ((11059000 / 192) / 57600)
;TH1 = 256 – ((57699) / 57600)
;TH1 = 256 – 1 = 255

MOV PCON,#128     ; seta o SMOD para dobrar o Baud Rate
MOV TMOD,#00100000B ;configurar Timer1 no modo 2 (8bits auto recarregavel)
MOV TH1,#255        ;seta para 57600 baud o timer1
MOV TL1,#255         ;
SETB TR1                  ;liga timer 1

;configurando a serial com SM0=0 SM1=1(8-bit UART Set by Timer 1 (*)) e setando a flag ;TI (de transmissao concluida) …
mov scon,#01000010B

LOOP:
;vamos ler o canal MIDI selecionado
MOV A,P2              ;salva P2 -> Acc
ANL A,#15             ;vamos cortar o nible “alto” fazedno uma AND 00001111
MOV canal, A        ; A -> canal (salvamos canal MIDI no formato 0000xxxx)
;lendo qual oitava será a primeira

;————————————————————————————-
; no loop abaixo sempre C é o estado atual e A vai com a “memoria” anterior
MOV R0,#20h       ;inicia o ponteiro R0 com o 1 byte orientado “bit a bit” 20h
MOV nota,#46       ;inicia na 3 oitava? será?? =D
MOV coluna,#1      ;ativa primeira coluna
MOV linha,#1         ;inicicamos a primeira linha…
MINI_LOOP:

MOV A, @R0         ;pega Byte da memoria das 8 teclas atuais e joga no A
ANL A, linha          ;faz um and entre a e 00000001 entao A ficará com 0000000X
MOV C, P0.0         ;copia valor do pino em C …e chama sub rotina pra resolver a bronca!
ACALL DECIDE   ;decide e resolve tudo e depois volta…

INC nota                  ;incrementa nota…
MOV linha,#2         ;indicamos a segunda linha…
MOV A, @R0          ;pega Byte da memoria das 8 teclas atuais e joga no A
ANL A, linha           ;faz um and entre a e 00000010 entao A ficará com 000000X0
MOV C, P0.1           ;copia valor do pino em C …e chama sub rotina pra resolver a bronca!
ACALL DECIDE    ;decide e resolve tudo e depois volta…

INC nota                  ;incrementa nota…
MOV linha,#4         ;indicamos a terceira linha…
MOV A, @R0          ;pega Byte da memoria das 8 teclas atuais e joga no A
ANL A, linha           ;faz um and entre a e 00000100 entao A ficará com 00000X00
MOV C, P0.2           ;copia valor do pino em C …e chama sub rotina pra resolver a bronca!
ACALL DECIDE     ;decide e resolve tudo e depois volta…

INC nota                  ;incrementa nota…
MOV linha,#8        ;indicamos a quarta linha…
MOV A, @R0         ;pega Byte da memoria das 8 teclas atuais e joga no A
ANL A, linha          ;faz um and entre a e 00001000 entao A ficará com 0000X000
MOV C, P0.3          ;copia valor do pino em C …e chama sub rotina pra resolver a bronca!
ACALL DECIDE    ;decide e resolve tudo e depois volta…

INC nota                 ;incrementa nota…
MOV linha,#16      ;indicamos a quinta linha…
MOV A, @R0         ;pega Byte da memoria das 8 teclas atuais e joga no A
ANL A, linha          ;faz um and entre a e 00010000 entao A ficará com 000X0000
MOV C, P0.4          ;copia valor do pino em C …e chama sub rotina pra resolver a bronca!
ACALL DECIDE    ;decide e resolve tudo e depois volta…

INC nota                  ;incrementa nota…
MOV linha,#32      ;indicamos a sexta linha…
MOV A, @R0          ;pega Byte da memoria das 8 teclas atuais e joga no A
ANL A, linha           ;faz um and entre a e 00100000 entao A ficará com 00X00000
MOV C, P0.5           ;copia valor do pino em C …e chama sub rotina pra resolver a bronca!
ACALL DECIDE     ;decide e resolve tudo e depois volta…

INC nota                  ;incrementa nota…
MOV linha,#64      ;indicamos a setima linha…
MOV A, @R0          ;pega Byte da memoria das 8 teclas atuais e joga no A
ANL A, linha           ;faz um and entre a e 01000000 entao A ficará com 0X000000
MOV C, P0.6           ;copia valor do pino em C …e chama sub rotina pra resolver a bronca!
ACALL DECIDE     ;decide e resolve tudo e depois volta…

INC nota                  ;incrementa nota…
MOV linha,#128    ;indicamos a oitava linha…
MOV A, @R0          ;pega Byte da memoria das 8 teclas atuais e joga no A
ANL A, linha           ;faz um and entre a e 10000000 entao A ficará com X0000000
MOV C, P0.7           ;copia valor do pino em C …e chama sub rotina pra resolver a bronca!
ACALL DECIDE     ;decide e resolve tudo e depois volta…

INC nota                  ;incrementa nota…
INC R0                     ;incrementa ponteiro dos bits para um novo byte…
MOV A,coluna        ;joga em A a coluna atual
RL A                         ;rotaciona a esquerda
MOV coluna,A       ;devolve pra porta a nova coluna
MOV linha,#1        ;inicicamos a primeira linha novamente…

CJNE R0,#27h, MINI_LOOP   ;é o byte 27h ? entao continua no MINI_LOOP ate terminarem as 56 teclas…
SJMP LOOP                ;era memoria 27h…fim do teclado! reiniciar tudo!
;Continua …

;************************* SUB ROTINAS *****************************************
DECIDE:
JNC PRESSIONADA      ;testa se a tecla esta pressionada (c=0)
;nao esta pressionada (C=1)…entao ou ja estava assim ou acabou de soltar a tecla!
JZ SOLTOU    ;Acc = 0? pula pra soltou!(significa que memoria constava tecla pressionada = 0)ou seja…soltou a tecla
RET      ;Acc=1! apenas retorna… memoria era 1 (tecla estava em repouso…)
SOLTOU:
MOV A,linha    ;linha indica qual bit sera setado!
ORL A, @R0    ;vamos atualizar o bit da memoria!!! ex se xxxxxxxx OR 00100000 teremos xx1xxxxx setando o bit que queriamos…
MOV @R0, A   ;o resultado jogamos no byte o qual R0 aponta!
ACALL NOTA_OFF    ;agora mandamos o comando de desligar
RET

PRESSIONADA:
;tecla pressionada… entao vamos ver se acabou de ser pressionada ou se ja estava pressionada anteriormente!
JNZ APERTOU   ;Acc = 1? pula pra apertou!(significa que memoria constava tecla solta = 1)ou seja…apertou a tecla
RET    ;Acc=0! apenas retorna… memoria era 0 (tecla estava pressionada ja…)
APERTOU:
MOV A,linha
CPL A    ;complementa A ex se 0001 vai para 1110
ANL A, @R0    ;vamos atualizar o bit da memoria!!! ex se xxx1xxxx AND 11101111 teremos xxx0xxxx zerando o bit que queriamos…
MOV @R0, A    ;o resultado jogamos no byte o qual R0 aponta!
ACALL NOTA_ON
RET

;——————————————————————————-
NOTA_ON:

MOV A, canal    ;faz canal -> Acc ( o canal esta no fomato 0000xxxx) onde xxxx representa o numero do canal
ORL A,#90h    ;Nota ON combinada com o canal escolhido (onde ficará 1001xxxx)
ACALL ENVIA_BYTE

MOV A,nota     ;envia o numero da nota
ACALL ENVIA_BYTE

MOV A,#70      ;velocidade
ACALL ENVIA_BYTE

RET
;——————————————————————————-
NOTA_OFF:

MOV A, canal   ;faz canal -> Acc ( o canal esta no fomato 0000xxxx)
ORL A,#80h     ;Nota OFF combinada com o canal escolhido (onde ficará 1000xxxx)
ACALL ENVIA_BYTE

MOV A,nota      ;envia o numero da nota
ACALL ENVIA_BYTE

MOV A,#0         ;velocidade zero significa nota off
ACALL ENVIA_BYTE

RET
;——————————————————————————–
ENVIA_BYTE:
JNB SCON.1,ENVIA_BYTE    ;checa se ja nao existe alguma coisa sendo enviada pq a flag ta zerada…enquanto nao terminar o envio espera…
CLR SCON.1     ;tx livre! limpa flag de enviado
MOV SBUF,A   ;manda enviar o conteudo de Acc
RET

;************************* TRATAMENTO DAS INTERRUPÇÕES *************************

EXTERNA_0: NOP     ; Código de tratamento de externa0
RETI

TIMER_0: NOP ;
RETI
EXTERNA_1: NOP      ; Código de tratamento de externa1
RETI

TIMER_1: NOP            ; Código de tratamento de timer1
RETI

SERIAL_COM: NOP    ; Código de tratamento de serial
RETI
;*******************************************************************************

END ; Fim de Arquivo p/ compilação ufa ;D


Bem espero que seja útil para alguém… é arcaico mas para quem está procurando sobre 8051 é uma boa estudar o código 😉 Quem quiser um código MIDI em Arduino deixa um comentário explicando o que deseja que quando tiver tempo faço um post sobre o assunto.

 

Leave a Reply

Theme by Anders Norén