Ir ao conteúdo
  • Cadastre-se

Estruturas de dados em assembly, PIC16F628A


Posts recomendados

Pessoal, é o seguinte, preciso montar uma estrutura de dados, uma especie de tabela que armazenara um valor em cada posição (0 ou 1 mais especificamente no momento), mas não tenho ideia de como eu poderia fazer isso. Tem alguma maneira de se montar uma estrutura indexada em Assembly ?
Quais maneira eu tenho para organizar meus dados ? Ou a unica manira é criando variáveis avulsas ?

Agradeço muito se alguém tiver algum exemplo de como poderia criar uma estrutura qualquer de dados em Assembly (OBS: Não serve outra linguagem, preciso fazer isso necessariamente em Assembly).

Link para o comentário
Compartilhar em outros sites

@Vicente Cesar,

Implementar um vetor indexado em assembly para PIC, pode não parecer mas é uma tarefa trivial se souberes como funciona o par de registros INDF e FSR, usando a capacidade de endereçamento direto basta que você reserve a quantidade de bytes que sua tabela deve ocupar em memoria (ou seja numero de posições x numero de bytes que cada posição ocupa), com isso, basta carregar o FSR com o endereço inciial da tabela e adicionar um offset a posição que desejas.

Veja esse exemplo beeem genérico, o processo de leitura vou deixar sem implementar pra você pensar um pouco e entender o conceito.

Segue:

;;;Simples exemplo de tabela em assembly:;;cblock 0x20...reg0			;registros de uso geralreg1reg2reg3tabela : 16		;reserva dados para uma tabela de 16bytes....mais vaiaveis suas aquiendc;; exemplo de escrita na sua tabela em ram space:; passa o o indice a ser escrito em reg0, valor em reg1;escreveTabelaIndice:	movlw Tabela	;toma o endereco base da tabela	movwf FSR		;FSR aponta ao inicio da tabela		movf  reg0,w	;toma o indice que vai acessar	addwf FSR,f		;faz FSR apontar para a posicao a escrever	movf  reg1,w	;	movwf INDF		;escreve na posicao desejada		return			;pronto, dado escrito, o processo del eitura eh analogo			

Abs

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

@Felipe Electronic, eu sou bem iniciante em assembly ainda, não conheço muito do que você falou, mas pelos seus comentários consegui ver é uma maneira relativamente lenta de acesso olhando o que eu preciso. Eu vi que você comentou o meu post de geração de sinal de vide com pic e lá eu expliquei o que eu precisava, e um problema adicional que acho que não avia mencionado é que tenho 1 microssegundo para colocar cada pixel na tela,  e posso realizar 3 instruções por microssegundo, e pelo que eu analisei esta estrutura é bem lenta. Acho que eu terei de arruma outra maneira de colocar os pixels na tela sem ser lendo o valor dele e colocando na tela. A não ser que saiba uma maneira de fazer isso em 3 instruções, algo mais ou menos assim:

_Seleciona o índice do vetor
_Pega seu valor
_Joga no port A

Entende ? 

Estou meio confuso com o seu codigo, eu conseguiria realizar o que eu quero ? Se sim, poderia explica-lo melhor ? 

Link para o comentário
Compartilhar em outros sites

então, o que fiz foi o metodo para uma leitura byte a byte, mais elementar possível.

veja que você nao especificou por exemplo, onde estará a imagem, na RAM? Memoria de programa? veja ainda que acesso indireto pelo FSR, é um dos métodos mais eficientes para leitura de stream de dados na RAM.

 

 

 

não conheço muito do que você falou, mas pelos seus comentários consegui ver é uma maneira relativamente lenta de acesso olhando o que eu preciso.

Veja que o lento é relativo, você por exemplo não cogitou, elevar o clock do seu microcontrolador por exemplo. E vale lembrar que pelo baixo custo do PIC seria pedir muito instruções de um unico ciclo de máquina para endereçamento indireto.


E mais um fator de complexidade que você não especificou, como vai ler os pixels(indices), sequencialmente? ou aplicando offsets, isso tambéem deixa a leitura mais lenta.

Basicamente se fosse pra transmitir diretamente um vetor de dados que esta na memoria RAM para um POrt daria pra fazer assim:

 

;; Transmissao de uma tabela inteira de dados; Possui um pequeno overhead:;;cblock 0x20tabelaPixel:24  ;reserva 24 bytes para uma tabela de 24 posiçõesindice			;endc;; FrameTrans; Essa rotina transfere um vetor de dados ao portA;;FrameTrans:		movlw tabelaPixel 		;toma o enderreço base da tabela	movwf FSR				;prepara o apontador de dados		movlw .24				;numero de indices que vai transmitir	movwf indice			;	LoopTbl:	movf  INDF,w			;	mowvf PORTA				;2 instruções para leitura e carga no PORTA	incf  FSR,f				;	decfz indice,f			;repete até transferir tudo	goto  LoopTbl	return	

 

 

Tem um pequeno overhead, mas a leitura da RAM para o PORTA é feita em 2 instruções, veja que todo tipo de rotina que envolvam vetores de dadosm voce deve nao apenas colocar os tempos de leitura ou escrita, mas também deve reservar um adicional para overhead ou seja atualização dos pontos de leitura e escrita, nao sei se a rotina acima resolve o seu problema.

Se a imagem estiver alocada na memoria de programa, ai sim, prepare se pra aumentar o clock pois o acesso em flash é mais lento ainda.


Uma sugestão veja essa discussão que explica sobre endereçamento com os registros FSR e INDF:
http://www.piclist.com/techref/microchip/fsr.htm

Abs

Link para o comentário
Compartilhar em outros sites

Legal isso resolve meu problema com algumas pequenas alterações, o problema quando aumentar o clock é que na minha cidade não tem lojas de eletrônica e o frete sai muito caro kkk, então eu deixo para meus pai comprar para mim nas viagens dele a trabalho, mas enquanto isso, estou me virando com o que tenho, até porque se eu fizer com um clock mais baixo, quando eu tiver um clock alto sera simples reimplementar. Mas antes que eu comesse a implementar esse seu método quero tirar algumas duvidas, que poderiam me ajudar muito na hora de criar algo mais rápido:
 

1 - tabelaPixel:24 ;reserva 24 bytes para uma tabela de 24 posições

 

Esse é um valor decimal ? É que aonde aprendi assembly para representar um valor decimal você coloca ".valor", então isso me confundiu um pouco (O valor 24).

 

2 -     incf FSR,f          ;

Está linha eu aponto para o próximo endereço da tabela certo ? Etão porque eu movo INDF para o port A? Esse registrador possui sempre o valor que FSR aponta ?

 

3 - movf INDF,w é o mesmo que a intrução movfw INDF (Uso o MPLAB) ?

 

4 - Uma ultima duvida, acho que não teria como, mas um registrador qualquer poderia ficar se incrementando enquanto o programa é executado ou apenas o registrador do Timer tem essa capacidade?

Me desculpe por tantas perguntas, mas o meu inglês não é muito bom e dificulta a entender. Agradeço pelas perguntas que puder responder.

OBS: Quanto a onde a imagem vai estar salva, pretendo coloca-la na RAM e indo atualizando por comunicação serial ou paralela (Para ser um pouco mais rápido). 

Link para o comentário
Compartilhar em outros sites

 

 

Esse é um valor decimal ? É que aonde aprendi assembly para representar um valor decimal você coloca ".valor", então isso me confundiu um pouco (O valor 24).

Sim é um valor decimal, estou reservando exatos 24 bytes da RAm para sua tabela.

 

 

 

Está linha eu aponto para o próximo endereço da tabela certo ? Etão porque eu movo INDF para o port A? Esse registrador possui sempre o valor que FSR aponta ?

O endereçamento direto do PIC é composto por FSR:INDF, ao passo que FSR aponta ao endereço, para ler ou escrever nesse endereço é necessario escrever por INDF.

 

 

 

3 - movf INDF,w é o mesmo que a intrução movfw INDF (Uso o MPLAB) ?

sim, a mesma coisa. So que o movfw nada mais que que movf x, w emulado.

 

 

 

4 - Uma ultima duvida, acho que não teria como, mas um registrador qualquer poderia ficar se incrementando enquanto o programa é executado ou apenas o registrador do Timer tem essa capacidade?

No Pic16 nao existe quase nada a suporte de endereçamento, não sei nesses novos PIC16 enhanced core, a turma que conheço que trabalha com eles me falou que melhorou muito. A partir do PIC18 a coisa melhora pois voce possui tres FSRs que endereçam até 64KB de memoria RAM, alem de modos de incremento e decremento automático e acesso indexado sem alterar o endereço base.

Tudo respondido?

Abs.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Tudo certo, agora é tentar implementar kkk.


@Felipe Electronic, Eu comecei a implementar o código, e cara me deparei com um problema, minha tabela tem mais de 255 posições, como faço para passar o índice dela (Já que o pic só tem registradores de 8 bits)?
O pic tem Algum registrador de mais de 8 bits ? Porque não entendi como eu posso ter tantas variáveis com uma estrutura de 8 bits. Como o pic trata isso ?

Link para o comentário
Compartilhar em outros sites

 

 

Eu comecei a implementar o código, e cara me deparei com um problema, minha tabela tem mais de 255 posições, como faço para passar o índice dela (Já que o pic só tem registradores de 8 bits)?

O pic tem Algum registrador de mais de 8 bits ? Porque não entendi como eu posso ter tantas variáveis com uma estrutura de 8 bits. Como o pic trata isso ?

Então, imaginei que a memoria RAM seria pouca. o problema é que esse recurso é limitado (e muito) nos PIC16, principalmente essese mais antigos como o 628A. Esse PIC se me lembro bem tem 256B de RAM, ou seja não só sua tabela esta limitada como também você esgotou toda a RAM do processador :)

Para PICs com mais que esse valor de RAM, você pode terá que fazer acesso banco a banco, o que é um verdadeiro saco, e é capaz de ainda por cima esgotar a RAM de novo.

Tem certeza que nao vale investir em um microcontrolador mais moderno, até o PIC18 vale. Uma opção como ja citada antes seria colocar uma memória RAM externa, e por o PIC16 para controla-la, não é uma tarefa fácil, o acesso pode ficar bem leeeeento visto que todos os sinais de sincronismo vão ficar a cargo do processador.

Além disso tem o outro problema que você acabou de enfrentar, endereçar mais que 256B de memória, muitos micros de 8Bits possuem alternativas para endereçamentode 16bits permitindo acesso linear a 64KB de memoria, no caso do pic a coisa deve ser feita na mão, ou seja concatenar dois registradores de 8bits e implementar aritmética básica de 16bits para controlar os ponteiros. o Problema é que o PIC16 nao oferece nada de suporte para 16bits, então é tudo na mão, veja como ficaria pra incrementar um ponteiro de 16bits:

;;Exemplo de incremento de endereço de 16bits;;cblock 0x20		reg0		;registros de uso geral	reg1	reg2	reg3			Adr:2	endc;;Incremento16bits;Inc16:	  incf Adr,f	;incrementa byte menos significativo	  movf STATUS,w ;toma o status          andlw 0x01	  addlw .0		;soma dummy, pois a parte alta do segundo operando é semrpe 0	  addwf Adr+1,f ;soma a parte alta	  					;nesse momento Adr0:1 foi incrementado por 1 unidade.

melhor pensar bem qual caminho vai tomar a partir de agora que seu projeto esta ficando mais complexo.}

Abs.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

Eu falei com um professor de eletrônica digital hoje e ele me explicou como eu faria um "acesso manual"(como seria um codigo de baixo nível para isso) a uma RAM externa (Explicou mais ou menos porque tenho que escolher um modelo especifico antes). Em fim ... cansativo ficar procurando informação kkkk. Vou ver como faço quanto a memoria, e depois posto a solução que eu encontrar.

Link para o comentário
Compartilhar em outros sites

@Felipe Electronic, andei uns dias sem mexer no projeto mas agora voltei a programa-ló, mas agora só quero melhorar o código, eu quero fazer o seguinte, tenho uma tabela para cada linha de pixels, já que seria muito grande uma para todos, o que eu quero, é fazer uma estrutura de repetição que vai mudando de uma tabela para outra e imprimindo os pixels de cada uma, teria como fazer isso ?  As imagens são desenhos de um personagem que esta olhando hora para um lado e hora para o outro, é a mesma imagem, mas invertida horizontalmente, a ideia é usar as mesmas tabelas para fazer o sprite, hora eu leio a linha de frente para trás, hora de trás para frente. Mas ai preciso da sua informação sobre como fazer essa troca de tabelas em um loop.

Link para o comentário
Compartilhar em outros sites

Deixa eu ver se entendi:

- voce tem uma tabela de que tem a forma de cada linha, está essa tabela em qual memoria? programa ou RAM?
- A estrutura de repetição que você quer funciona escrevendo uma linha de pixels ate que passar por todas as tabelas?

No geral nao parece nada complexo de se fazer usando o metodo de "computed goto" dos PIC16, armazenando aquele conjunto de Retlw, o fator critico da sua implementação seria o correto tamanho de cada linha, afim de calcular um offset correto para pular de uma tabela a outra...

Vale lembrar, nao é o tipo de coisa feita com algumas poucas instruções, fique ciente disso.

Verei o que consigo extrair com as informações que você deu afinal fazem uns poucos anos que nao mexo com PIC16...

 

 

EDIT: Foi o melhor que conseguir pensar com as 35 instruções do PIC16 em 15 minutos que tive livre aqui no trabalho, tem que verificar a sintaxe de uma diretiva ou outra, mas esse principio creio que funciona bem, estamos chegando proximo as limitações de endereçamento indireto no PIC16. Em micros da "moda" isso em assembly (que dirá em C) seria feito com o pé nas costas. mas é o que temos.

De uma olhada:

 

; Exemplo de stream de linhas com PIC16;; Autor FSN =P;#define PIXEL_LINHA   .128   ;largura de cada linha em pixels #define SIZEOF_LINHA  (PIXEL_LINHA / 8) ;offset para jump computado entre tabelas#define TABELA_BASE   0x2FF ;endereco base onde ficam localizada as tabelascblock 0x20reg0 ;registros de uso geralreg1 ;reg2 ;reg3 ;pixelBCount ;contador de pixels por bytepixelLCount ;contador de pixels por linhapix ;lineCount ;contador de linhas a imprimir na tela;; WriteFrame(); Essa funcao é a mais alto nivel, escreve N linhas a partir ; do endereço definido em tabela base; reg0 - numero de linhas;;WriteFrame:movf  reg0, w ;movwf lineCount     ; toma a contagem de linhas:movlw SIZEOF_LINHA ;movwf reg2 ; prepara o tamanho de cada linhamovlw high(TABELA_BASE); toma a primeira linha a receber...movwf reg1 ;movlw low(TABELA_BASE);movwf reg0 ;call LineWrite ;escreve a linha apontada no primeiro endereçomovlw SIZEOF_LINHA ;movwf reg2 ; prepara o tamanho de cada linhamovlw high (TABELA_BASE + (SIZEOF_LINHA * 1)); toma a segunda linha a receber...movwf reg1 ;movlw low(TABELA_BASE + (SIZEOF_LINHA * 1));movwf reg0 ;call LineWrite ;escreve a linha apontada no primeiro endereçomovlw high (TABELA_BASE + (SIZEOF_LINHA * 2)); toma a segunda linha a receber...movwf reg1 ;movlw low(TABELA_BASE + (SIZEOF_LINHA * 2));movwf reg0 ;call LineWrite ;escreve a linha apontada no primeiro endereço...;repita por N linhas....nao fiz iterativo,pois precisaria;de pelo menos uma multiplicação 8x8, e no PIC isso nao;é tarefa trivial :Dreturn;; PixWrite();; Rotina que escreve um certo numero de pixels de uma linha; reg0 - pixel a ser escrito;;PixWrite:movf  reg0,w ;movwf pixmovlw .8 ;movwf pixelBCount ;inicializa contador de pixelsPixWrLoop:movf  PORTA, w ;movwf reg0 ;toma o valor corrente de PORTAbcf  reg0,0 ;Limpa RA0rlf   pix,f ;extrai pixel bit a bitmovf  STATUS,w ;andlw 0x01 ; o valor do pixel esta em Ciorwf reg0,w ;movwf PORTA ;escreve o pixel em Ra0decfz pixelBCount,f ;goto  PixWrLoop ;return ;encerra sub;; LineWrite();; Rotina que escreve uma determinada linha de pixels.; reg0:1 endereço da linha na memoria de programa; reg2   tamanho da linha em (pixels / byte);LineWrite:movf  reg2, wmovwf pixelLCount ;inicializa contador de pixels por linhamovf  reg1, w ;movwf PCLATH ;inicializa a buscamovf  reg0,w ;prepara calculo do offset:movwf reg2 ;LineWrLoop:call  GetLine ;toma o byte da linha apontada por w:mowvf reg0 ;toma o pixel da linha a ser escritocall  PixWrite ;escreve os 8 pixels empacotados no bytebcf   STATUS,C ;precisamos do carry p/ inc 16bitsincf  reg2,f ;aponta ao proximo bytemovf  STATUS,w ;andlw 0x01 ;addlw .0 ;addwf reg1,f ;movf  reg1, w ;    movwf PCLATH ;prepara para apontar ao proximo byte    movf  reg2, w ;    decfz pixelLCount,f ;goto  LineWrLoop ;repete ate transmitir toda a linhareturn ;tudo ok! ;; GetLine(); Essa rotina toma uma linha da tabela salva na flash; PCLATH ja deve estar configurado e aparte alta vai em W:;GetLine:movwf PCL ;ORG TABELA_BASE + (SIZEOF_LINHA * 0)retlw   b'00000000'retlw   b'11110000'     ...;Pixels da linha 1, cada bit é um pixel;devem conter SIZEOF_LINHAS para cada 8pixelsORG TABELA_BASE + (SIZEOF_LINHA * 1)retlw   b'00000000'retlw   b'11110000'     ...;Pixels da linha 1, cada bit é um pixel;devem conter SIZEOF_LINHAS para cada 8pixelsORG TABELA_BASE + (SIZEOF_LINHA * 2)retlw   b'00000000'retlw   b'11110000'     ...;Pixels da linha 1, cada bit é um pixel;devem conter SIZEOF_LINHAS para cada 8pixels;E por ai vai ate acabar as linhas, ou a memoria de ;programa...
 

Bem agora é com voce, se tiver duvidas, volte que vejo o que posso fazer, tem uma turma do PIC aqui que anda bem mais fera que eu pra essas coisas :P pessoal se errei algo grotesco por favor corrijam sem piedade.

 

Abs.

Link para o comentário
Compartilhar em outros sites

@Felipe Electronic Obrigado mesmo cara, vou tentar entender sozinho daqui para frente com as informações que você me passa, desculpe causar tanto incomodo, não precisar de pressa para responder kk, eu posso esperar, não quero atrapalha-lo. Eu aprendi algumas técnicas de processamento de vídeo do Atari e creio que agora conseguirei fazer tudo o que preciso com a pouca memoria que tenho, espero poder trazer logo resultados, muito abrigado.

Link para o comentário
Compartilhar em outros sites

@Vicente Cesar,é muito interessante que sai da linha 16F para tabelas grandes porque senão terá que trocar de bancos

No link abaixo eu uso a leitura continua de tabelas,são lidos 1658 bytes de dados contínuos em tabela,este exemplo usa toda a memoria disponível do PIC 16F628A;

 

 

mesmo usando linguagem C,no caso CCS,não é possível utilizar uma tabela tão grande,só consegui em ASM.

Link para o comentário
Compartilhar em outros sites

  • 7 meses depois...

Bom noite pessoal, tenho que montar em assembly um programa que vai acionar um motor de passo unipolar, sendo que terá um botão para que o mesmo gira para direita e outro para que ele gira para esquerda, e quando pressiono um dos dois botões um led deve acender, eu não estou conseguindo montar a linguagem que vai acionar as bobinas, o MPLAB da erro toda hora, gostaria de uma ajuda, de como eu poderia utilizar a tabela com RETLW para acionar esse motor. Fora que tenho que inserir no CALL uma rontina para causar um delay, e não sei como fazer isso também

Segue abaixo o que eu fiz, só que nem rodando não esta no MPLAB

 

 

LIST P=16F628A
 
#include pic16f628a.inc
 
__CONFIG _CP_OFF & _WDT_OFF & PWRTE_ON & _XT_OSC
 
#define Bank0 bcf STATUS,RP0
#define Bank1 bsf STATUS,RP0
#define Botao1 portb,4 ;a porta RB4 será usada para acionar o giro horário
#define Botao2 portb,5 ;a porta RB5 será usada para acionar o giro anti-horário 
#define Led1 portb,6 ;a porta RB6 sera usada para acionar o led
#define Bob1 portb,0 ;a bobina bob1 será acionada pela porta RBO
#define Bob2 portb,1 ;a bobina bob1 será acionada pela porta RB1
#define Bob3 portb,2 ;a bobina bob1 será acionada pela porta RB2
#define Bob4 portb,3 ;a bobina bob1 será acionada pela porta RB3
 
 
Reset org 0x00
 
goto Inicio
    org 0x00
 
 
Inicio
Bank1
movlw b'00110000'
movwf TRISB
 
Bank0
 
clrf  portb ; limpa todos os bits do PortB
goto  Main
 
Main
 
btfsc Botao1 ; se o botao estiver pressionado ele executa a proxima linha, caso contrario ele pula a linha seguinte
call Girodireito ; call chama o "sub programa"
btfsc Botao2
call Giroesquerdo
 
 
 
Girodireito
bsf led1
movlw b'0001'
movwf Bob1
movlw b'0010'
movwf Bob2
movlw b'0100'
movwf Bob3
movlw b'1000'
movwf Bob4
goto Main
 
Giroesquerdo
bsf led1
movlw b'1000'
movwf Bob1
movlw b'0100'
movwf Bob2
movlw b'0010'
movwf Bob3
movlw b'0001'
movwf Bob4
goto main
 
 
END
 
Link para o comentário
Compartilhar em outros sites

#define   Bob1   portb,0   ; a bobina bob1 será acionada pela porta RBO::movlw b'1000'movwf Bob1

 

Bob1 (os outros também) é apenas 1 bit. Use a função BSF em vez da MOVLW e MOVWF. 

 

Ou então use a MOVLW e MOVWF mas movendo o valor para a porta.

movlw   b'00001000'  ; ou b'10000000'movwf   portbcall    delay        ; Para controlar a velocidademovlw   b'00000100'  ; ou b'01000000'movwf   portb::call    delay movlw   b'00000001'  ; ou 'b00010000'movwf   portb
Link para o comentário
Compartilhar em outros sites

Visitante
Este tópico está impedido de receber novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...