Ir ao conteúdo
  • Cadastre-se

Projetos com Avr : Design, Programação em Basic e Assembly


Ir à solução Resolvido por aphawk,

Posts recomendados

Vocês que mexem com ASM AVR onde é que eu consigo um boa literatura explicando detalhadamente a linguagem e detalhando as instruções de máquina (livro ou internet) ?

E um bom debuger, qual eu uso ?

No tempo do turbo pascal e do delphi eu estava muito bem servido, mas com o AVR estou totalmente perdido.

Link para o comentário
Compartilhar em outros sites

@MOR,

1 - Em quase todos os Avrs, cada Timer/counter possui o seu próprio Prescaler. E em cada família de chips, os valores de Prescalers disponíveis podem variar para cada um dos Timers..... ! Só mesmo conferindo no Datasheet.

Agora entendi!

O meu micro é o Atmega8a, que possui, com certeza, apenas um prescaler comum aos Timers 0 e 1. Já para o Timer2 não encontrei no datasheet algo que pudesse esclarecer se ele possui um prescaler exclusivo, ou não.

2 - Na família Atmega 48/88/168/328 não é possível trabalharmos com dois cristais ao mesmo tempo.

Mas existem outras famílias, como o Atmega16 ou Atmega32, que permitem um cristal como clock principal e um cristal de 32768 ligado no Timer2, que possui um oscilador próprio para isto. Veja no datasheet deles.

Ok!

3 - Nos Fórums do Bascom, existe uma rotina maluca, muito interessante, que faz este ajuste preciso baseado no baud rate da porta serial ! Basta ligar a um micro e teclar uma tecla determinada e pronto ! Ajuste perfeito !

Ok! Imaginei algo assim.

4 - Em várias famílias de Avrs, o timer2 pode operar no modo assincrono, independente do clock principal. Isto é perfeito para um RTC !

Então o diferencial entre os timers seria, que operando no modo assíncrono, não haveria a perda de alguma transição do sinal, para sincroniza-lo com o clock principal do sistema. Correto?.

5 - Sim, tem de alterar os Fuses, para permitir o uso de um cristal oscilador, em vez do clock interno.

Ok!

Quanto aos cristais, existem valores que são utilizados em televisõoes, para fazer NTSC ou PAL, ou para fazer batimento com outras frequências. E existem cristais que são multiplos de 2, para facilitar a geração de bases de tempo. E ainda tem cristais que permitem gerar com excelente precisão velocidades seriais ( baud rate ) ....

Quando vi os cristais na sucata de uma loja, pensei que eles seriam para RTCs, mas me enganei.

Pode perguntar à vontade !

 

Paulo

Pode perguntar à vontade !

Grato Paulo!

Minha política é semelhante.

Gosto de responder quando percebo que o interessado fez a sua parte. Procurou sanar a dúvida sozinho, mas não conseguiu.

MOR_AL

Link para o comentário
Compartilhar em outros sites

@MOR,

 

Muitas vezes as nossas dúvídas já foram resolvidas por outros, e assim ganhamos tempo ! E ainda como voce falou, quando a gente vê o interesse em aprender, respondemos com uma satisfação ainda maior !

 

Vamos lá :

 

1 - Embora o módulo do Atmega8A seja compartilhado, voce pode sim usar valores de Prescalers diferentes para ambos !!!!  Ou seja, se usar no modo Timer, voce pode obter duas temporizações totalmente diferentes para ambos ( Timer0 e Timer1 ) !!!! Mesmo com esse chip, pode-se obter 3 bases de tempo diferentes, sem nenhuma interferir com a outra, usando os 3 Timers !

 

4 - Sim, esse é o motivo, os outros timer são SINCRONOS, e os eventos só são "percebidos" no momento da transição do clock.

     E esse Timer2/Counter é totalmente assíncrono, ajuda nos casos mais "críticos" de temporização.

 

Quanto aos cristais, eu recomendo a compra de um "pacote" no Ebay, recebí 100 cristais com valores muito interessantes, já numa caixinha plástica, 5 de cada valor, por US$ 7 .... E vieram valores perfeitos para gerar baud rate, e valores multiplos de 2 também....  

 

Se precisar eu vejo no meu histórico e te passo o vendedor, ok ?

 

Está gostando do brinquedo novo ??? Aguarde mais uma semana, eu vou postar um artigo sobre a integração do Bascom e o Assembler, estou tirando leite de pedra agora kkkkk !

 

Paulo

Link para o comentário
Compartilhar em outros sites

@MOR,

 

Muitas vezes as nossas dúvídas já foram resolvidas por outros, e assim ganhamos tempo ! E ainda como voce falou, quando a gente vê o interesse em aprender, respondemos com uma satisfação ainda maior !

 

Vamos lá :

 

1 - Embora o módulo do Atmega8A seja compartilhado, voce pode sim usar valores de Prescalers diferentes para ambos !!!!  Ou seja, se usar no modo Timer, voce pode obter duas temporizações totalmente diferentes para ambos ( Timer0 e Timer1 ) !!!! Mesmo com esse chip, pode-se obter 3 bases de tempo diferentes, sem nenhuma interferir com a outra, usando os 3 Timers !

Sim! Mas somente alterando o valor dos contadores dos timers ( acho que são os registros TCNT0 e TCNT1). O valor do prescaler TEM que ser o mesmo, caso ambos os timers tenham que funcionar ao mesmo tempo, certo?

Ainda não ficou claro para mim se o timer2 possui um prescaler exclusivo. Caso não possua, ele se enquadra nas mesmas condições do parágrafo anterior. Prescaler fixo, TCNT2 dedicado,e operando ao mesmo tempo.

Observei um pequeno parágrafo do manual, que trata do cristal de 32.768Hz. Ele menciona o timer2 e assincronia.

 

4 - Sim, esse é o motivo, os outros timer são SINCRONOS, e os eventos só são "percebidos" no momento da transição do clock.

     E esse Timer2/Counter é totalmente assíncrono, ajuda nos casos mais "críticos" de temporização.

Ok!

Observei, que existem dois retângulos tracejados denominados "Sincronização" (um para cada entrada externa T0 e T1). Este estágio pode introduzir um delay de 2,5 a 3,5 clocks do sistema. Isso arruinaria o uso dos timers 0 e 1 como RTC.

 

Quanto aos cristais, eu recomendo a compra de um "pacote" no Ebay, recebí 100 cristais com valores muito interessantes, já numa caixinha plástica, 5 de cada valor, por US$ 7 .... E vieram valores perfeitos para gerar baud rate, e valores multiplos de 2 também....  

 

Se precisar eu vejo no meu histórico e te passo o vendedor, ok ?

Realmente acho que não seja necessário. Possuo muitos cristais com diversas frequências. Só não tenho os tais para 32.768Hz. Não tive necessidade ainda deles. A única exceção foi para o seu exercício.

 

Está gostando do brinquedo novo ??? Aguarde mais uma semana, eu vou postar um artigo sobre a integração do Bascom e o Assembler, estou tirando leite de pedra agora kkkkk !

 

Eu havia me comprometido a não aprender assembly nos AVRs. Agora vou reformular minha decisão. Assembly em AVRs somente em pequena escala e dentro de linguagem com maior nível de compactação (C ou Basic).

Fiz quase todos os meus projetos com PIC, com a linguagem assembly. Parece que queria provar, que se podia fazer algo com alguma complexidade, com micros com pouca memória.

Ainda não terminei dois projetos.

• Gerador e Frequencímetro com AD9850. Este está me deixando louco. Só no layout já perdi a conta de quantas horas investi. Acho que mais de 100 horas. Sempre tem alguma melhoria no layout, ou algum detalhe que só percebi depois de alterá-lo.

• FLC Meter. Neste estou usando assembly com ponto flutuante.

Quando chegar a hora vou disponibilizar todos os meus projetos. Não somente o firmware e o layout, mas o próprio projeto, com todas as suas etapas.

Mas isso é papo para outro tópico.

Paulo

 

Mais uma vez, agradeço pelo seu auxílio.

MOR_AL

Link para o comentário
Compartilhar em outros sites

@MOR,

 

Eu ví em algum lugar um medidor FLC em Basic. Vou ver aonde que eu ví isso e depois te falo. Mas agora que consigo integrar fácil o ASM, dá prá fazer esse seu projeto de modo mixado, fica muito mais simples e rápido.

 

Vamso lá :

 

1 - Nada te impede de usar valores diferentes para os prescalers e para os timers !!!  Por exemplo, Timer0 com prescaler de 8 e TCNT0 de 100 ; e ao mesmo tempo Timer1 com prescaler de 1 e TCNT1 de 10000 !!!! Vai funcionar direitinho, eu mesmo já usei isso desta maneira.

 

http://www.atmel.com/images/atmel-8159-8-bit-avr-microcontroller-atmega8a_datasheet.pdf

 

Veja no Capítulo 16, específicamente o parágrafo 16.1 e mais embaixo a figura 16.2 !

 

A única coisa que é compartilhada é a eletrônica que gera as diferentes divisões, que caso tenha o valor zerado pelo bit mostrado em 16.2 , pode influenciar na contagem de AMBOS os prescalers !

 

Mas se voce definir os valores de ambos e não ficar mais mudando eles no seu programa, isso não tem nenhuma importância, ok ?

 

Leia mais abaixo sobre isto aqui :

 

 Bit 0 – PSR10: Prescaler Reset Timer/Counter1 and Timer/Counter0

 

 

4 - Esse é o motivo de ocorrer isso também nos Pics !!!
 
 
Paulo
Link para o comentário
Compartilhar em outros sites

 

@MOR,

 

Eu ví em algum lugar um medidor FLC em Basic. Vou ver aonde que eu ví isso e depois te falo. Mas agora que consigo integrar fácil o ASM, dá prá fazer esse seu projeto de modo mixado, fica muito mais simples e rápido.

Não sei como poderia fazer. Pelo menos o frequencímetro.

O FLC incorpora um frequencímetro de um outro projeto meu (o Frequencímetro, hehe).

No PIC fiz tudo em assembly.

Usei o Timer0 para contagem dos pulsos. Ele aceita pulsos em uma taxa de até 40MHz.

Ele possui um registrador com 8 bits para as contagens e um prescaler de 8 bits também. Isso permite contagens até 65k.

Para eliminar o erro por usar um período de contagem submúltiplo de 1s, usei um período de contagem de 1s. Por exemplo. Se usasse um período de contagem de 100ms poderia ter um erro de 1 pulso a cada 100ms, simplesmente por não haver sincronismo entre o primeiro pulso e o início da contagem. Nesse caso o erro poderia ser de 10 unidades.

Claro que um contador de 8 bits e um prescaler de 8 bits não permitem colocar contagens maiores que 65k. Tive que acrescentar mais dois registros para permitir uma contagem de 40MHz em 1 segundo, ou 40M pulsos.

Agora com 4 bytes (prescaler, contador do timer0, registro 1 e registro 0) posso contar até 4,3 bilhões.

Com isso também criei um problema. Os dois registros extras só podem ser atualizados por programação. Dependendo do valor sendo contado, estes dois registros devem ou não serem atualizados. Esta atualização possui diversos (muitos) percursos e cada um deles possui um número diferente de instruções e algumas instruções possuem diferentes números de clocks. Conclusão. É imperativo que o número total de clocks usados na contagem do período de 1 segundo possua um número fixo de clocks, independente do valor a ser contado.

Com um clock máximo possível do cristal (20MHz), existem 5 milhões de clocks em 1 segundo. A frequência do cristal nos PICs é dividida por 4.

Sendo assim, seria bem difícil controlar o número exato de 5M clocks, qualquer que fosse o valor da contagem, devido a atualização por programação ou não dos 2 registros extras.

Esse foi o maior desafio do projeto.

Todos os possíveis percursos possuem exatos 5.000.000 ciclos de clock. Com isso a acurácia do período de contagem é de uma em 5 milhões.

Para melhorar um pouco mais a precisaão do frequencímetro, incluí um "ajuste da frequência do cristal". Se fosse disponível algum frequencímetro profissional com melhor precisaão, a frequência do cristal pode ser alterada para a precisaão do frequencímetro profissional.

A seguir encontra-se o vídeo que fiz sobre o projeto.

 

 

Vamso lá :

 

1 - Nada te impede de usar valores diferentes para os prescalers e para os timers !!!  Por exemplo, Timer0 com prescaler de 8 e TCNT0 de 100 ; e ao mesmo tempo Timer1 com prescaler de 1 e TCNT1 de 10000 !!!! Vai funcionar direitinho, eu mesmo já usei isso desta maneira.

 

http://www.atmel.com/images/atmel-8159-8-bit-avr-microcontroller-atmega8a_datasheet.pdf

 

Veja no Capítulo 16, específicamente o parágrafo 16.1 e mais embaixo a figura 16.2 !

 

A única coisa que é compartilhada é a eletrônica que gera as diferentes divisões, que caso tenha o valor zerado pelo bit mostrado em 16.2 , pode influenciar na contagem de AMBOS os prescalers !

 

Mas se voce definir os valores de ambos e não ficar mais mudando eles no seu programa, isso não tem nenhuma importância, ok ?

 

Leia mais abaixo sobre isto aqui :

 

 Bit 0 – PSR10: Prescaler Reset Timer/Counter1 and Timer/Counter0

Ok! O pulo do gato foi disponibilizarem todos os pinos do fator de divisão do prescaler e deixar ele "rodar" sem alterá-lo e sem resetá-lo. Bem bolado.

 

4 - Esse é o motivo de ocorrer isso também nos Pics !!!
Nos PICs mais comuns existe um prescaler para o timer0 e outro para o timer1. O prescaler do timer0 também é comum ao watchdog.
 
Paulo

 

Hoje dediquei o tempo livre para o layout do Gerador com AD9850/Frequencímetro.

 

Bom trabalho com o asm dentro do Bascom. Quando você disponibilizá-lo também o usarei como consulta.

MOR_AL

Link para o comentário
Compartilhar em outros sites

@MOR,

Muito legal o seu frequencímetro !!!! Gostei da implementação, da mecânica, da calibração !

Faça um post separado sobre isso, com fotos, layout da pcb, e também a implementação física da caixa, ficou muito bom !!!

É um excelente projeto para quem está entrando no mundo de microcontroladores !

Com um fonte comentado, pelo menos no princípio de funcionamento, é um excelente aprendizado !

Quanto ao que eu disse no item 4, eu me referí à implementação de um timer Assincrono também nos Pics !

Eu estou sofrendo muito com algo muito parecido à sua dificuldade : tenho apenas 40 ciclos de clock para fazer muita coisa, e também implementei um contador "extra" de 8 bits por software. E qualquer que seja a solução, tem de ser feita sempre no mesmo numero de ciclos, não importando o caminho feito.... Já pensei 4 maneiras diferentes, implementei as 4, mas sempre penso que poderia fazer algo melhor, e volto prá prancheta.....

O gerador com o Ad9850 precisa de algebra de ponto flutuante na divisão, não é ? É um saco fazer isso em qualquer tipo de Asm, mas pode sim ser feito em Bascom, sem nenhum Asm envolvido. Já o frequencímetro, mesmo em ASM, tem a limitação de pouco mais de 20 Mhz nos AVRS. Uma solução está mostrada aí na apostila, com o uso de um contador auxiliar, que é muito engenhoso !

Vamos em frente heheheh

Paulo

Link para o comentário
Compartilhar em outros sites

@ Paulo

O gerador com o Ad9850 precisa de algebra de ponto flutuante na divisão, não é ?

 

Não necessariamente!

Até pensei em fazer com ponto flutuante, mas o erro introduzido com a operação matemática é grande.

Imagine que o número de bits a serem determinados para a frequência do AD9850 é 32.

O número de bits da mantissa do ponto flutuante é 23. Daí já tem erro de aproximação e ainda mais da operação matemática.

 

Eu fiz o seguinte.

Como já tenho pronto o frequencímetro e que teoricamente conta até 40MHz (ainda não testei até esta frequência), resolvi incorporar o frequencímetro, já que ele é preciso o suficiente.

Ao invés de calcular os bits que fornecem a frequência desejada, fiz o inverso. Por aproximações sucessivas.

Imagine que desejo estabelecer 1.000.000Hz.

Tem uma rotina que vai alterando os bits do AD do mais significativo para o menos significativo. Para cada bit eu meço a frequência e mostro no LCD. Aí minha precisão fica igual a do frequencímetro.

Apenas com dois botões aumento ou diminuo a frequência com um fator de 2. Na verdade o AD permite ajustar até frações de hertz, mas meu projeto para na unidade de hertz.

Isso também economiza os botões de 0 a 9 necessários para introduzir o valor da frequência pelo modo convencional.

Apesar de toda esta simplificação, o projeto ficou grande, pois estou introduzindo modulação AM e depois FM.

O PIC necessário já precisou ter mais dos 18 pinos que o PIC628 pode fornecer. Passei para o PIC876 com 28 pinos. Mesmo assim tive que usar 4 pinos multiplexados no tempo entre o LCD e o AD9850.

Na verdade nem sei se vai dar certo, mas não dá para simular e nem montar na protoboard.

O jeito é montar e testar até conseguir.

MOR_AL

Link para o comentário
Compartilhar em outros sites

  • 2 semanas depois...

@Paulo.

 

Estou fazendo o exemplo da página 54 de sua apostila.

Na verdade, como você sabe, não se aprende muito apenas copiando. Tem que pensar.

Então parti do seu enunciado para fazer o exercício.

 

Fiz um fluxograma do que suponho que seja a solução e gostaria que você comentasse.

 

O meu fluxograma não segue todas as regras comuns dos fluxogramas.

Tentei fazê-lo mais simples, de modo que ele é todo composto por retângulos. A densidade superficial de informação fica maior.

Apenas deve-se atentar para alguns detalhes:

1 - Como mencionei, ele é composto por retângulos.

2 - As chamadas às rotinas encontram-se em negrito.

3 - As rotinas acompanham o fluxograma do programa.

4 - O que deve aparecer no LCD encontra-se com o tipo "Courier New".

5 - A posição do primeiro caractere a ser incluído no LCD está no formato LCDLxCy, onde L é a linha, C a coluna, x e y é a posição do caractere.

Então LCDL2C5 significa escrito no LCD na linha 2, coluna 5.

 

Este fluxograma é ideal para a linguagem Assembly, onde dispomos do GoTo, mas para linguagem de um pouco maior nível, devemos tentar substituir por Do...While, For, If, then, else, Case, etc.

Acho que esta é a minha maior dificuldade, pois ainda não me acostumei a fazer este tipo de procedimento.

Segue o fluxograma.

 

http://www.4shared.com/office/LcJRSc9Iba/Ex_pg54.html

 

MOR_AL

Link para o comentário
Compartilhar em outros sites

@MOR,

 

Interessante, é uma maneira mais "menmônica" que voce faz ...  é uma implementação do tipo que eu aprendí usando Fortran... mas com umas idéias mais úteis !

 

Esse exercício em partícular eu fui escrevendo o código conforme ia saindo da minha cabeça, sem nenhum planejamento prévio... ficou uma bela macarronada de código que funciona, mas sem nenhum método de programação heheheh !

 

Algumas dessas  estruturas do Bascom servem justamente para "não usar o GOTO" e desta maneira fazer o tal de Basic Estruturado, mas eu acho tão prático que também não consigo viver sem elas... devem ser vícios do ASM !

 

Eu também quase nunca uso o tal de DO ... WHILE , o CASE , e hoje mesmo escreví um programa que faço vários IF .... THEN ... ELSE .... ENDIF tudo aninhados, quando fica muito mais elegante usar um DO CASE, mas só perçebo depois que vira aquele belo Spaghetti de código, aí me dá preguiça de mudar ele heheheh !

 

Estou curioso com o seu fluxograma, você escreveu o seu programa para testar no Proteus ?

 

Paulo

Link para o comentário
Compartilhar em outros sites

@MOR,

 

Interessante, é uma maneira mais "menmônica" que voce faz ...  é uma implementação do tipo que eu aprendí usando Fortran... mas com umas idéias mais úteis !

 

Esse exercício em partícular eu fui escrevendo o código conforme ia saindo da minha cabeça, sem nenhum planejamento prévio... ficou uma bela macarronada de código que funciona, mas sem nenhum método de programação heheheh !

 

Algumas dessas  estruturas do Bascom servem justamente para "não usar o GOTO" e desta maneira fazer o tal de Basic Estruturado, mas eu acho tão prático que também não consigo viver sem elas... devem ser vícios do ASM !

 

Eu também quase nunca uso o tal de DO ... WHILE , o CASE , e hoje mesmo escreví um programa que faço vários IF .... THEN ... ELSE .... ENDIF tudo aninhados, quando fica muito mais elegante usar um DO CASE, mas só perçebo depois que vira aquele belo Spaghetti de código, aí me dá preguiça de mudar ele heheheh !

 

Estou curioso com o seu fluxograma, você escreveu o seu programa para testar no Proteus ?

 

Paulo

 

É aquilo que falei antes.

Estou lendo a sua apostila. Acho que é um dos poucos tutoriais, se não o único, que apresentam a utilização do Bascom AVR em português.

No começo fui copiando os primeiros exercícios, até começar a "pegar no tranco".

Aí passei a ler o enunciado do exercício e tentar usar uma solução minha. Isso é ótimo para aprender, pois exige que o leitor passe de mero observador para se tornar atuante.

Ainda não escrevi o programa. Na verdade outras atividades me fizeram iniciar somente hoje o exercício. Fiz o fluxograma hoje.

Em asm a passagem do fluxograma para o programa é quase que imediata (quando uso o PIC).

Não quero usar goto como em asm. Usando uma linguagem de mais alto nível, notei que fica mais difícil passar do fluxograma para a programação.

São os tais Do ... While, If ... Then ... Else ... EndIf. etc.

Quando é um fluxograma sequencial, não é difícil, mas quando é um fluxograma com muitos desvios, aí a coisa fica complicada.

Só usei o Proteus uma ou duas vezes. Gosto de testar no hardware mesmo.

Vou tentar fazer o programa, baseado no fluxograma, sem usar o goto. Quando tiver algum resultado eu posto aqui.

MOR_AL

Link para o comentário
Compartilhar em outros sites

Sobre a passagem do fluxograma para o programa em alto nível.

Como mencionei antes, uso muito o fluxograma para concatenar as diversas tarefas a serem transformadas em instruções para o microcontrolador (MC).

A explicação é simples.

O fluxograma permite visualizar o projeto todo e com muita vantagem em relação a linguagem convencional, qualquer que seja ela.

O porque é bem simples.

Cada quadradinho que forma o fluxograma encontra-se em pseudo linguagem, que é formada por mnemônicos. Isso facilita enormemente a compreensão do programa.

Outra grande contribuição é formada pelas setas que informam sobre a conexão entre os blocos.

Finalmente. Um bloco contendo um mnemônico em negrito, substituindo uma rotina, também facilita muito a compreensão.

A não inclusão de detalhes simples e que sejam intrínsecos ao programa, também auxiliam para tornar o fluxograma mais "limpo", compreensível.

Por esses fatos e ainda por permitir maior densidade superficial de informação do que qualquer linguagem formal, é que o fluxograma é apropriado em um projeto.

Afinal, como dizem, "uma imagem vale mais que mil palavras".

Uma vez esclarecido o meu pensamento, entremos nos detalhes.

Estava apresentando alguma dificuldade em passar do fluxograma para a linguagem formal (Basic), pelo fato de que a instrução GoTo ser abominada pelos programadores profissionais.

Até certo ponto concordo com eles. Mas discordo quando o programa vem acompanhado do fluxograma. Aí tudo fica mais fácil.

Devido à minha dificuldade, resolvi pesquisar sobre a passagem do fluxograma para o programa com linguagem de maior nível que a Assembly.

Encontrei pouca informação, até que consegui achar, escondido, um pequeno trecho com a explicação.

Basicamente o comentário informava, que em situações onde hajam desvios entrelaçados, fica muito difícil e complicado fazer a passagem (sem usar GoTo). Acredito mesmo, que nesses casos, a linguagem estruturada fique também difícil de ser entendida e que acaba perdendo a sua qualidade modular.

O detalhe é que no trecho onde encontrei este único comentário (também parei depois de encontrá-lo, talvez por isso é que tenha sido único, hehe), foi informado que nesses casos outra solução deveria ser utilizada, mas não fora apresentada essa tal solução, permanecendo o impasse inicial.

 

De posse desta explicação, desisti de tentar passar do fluxograma para a linguagem de alto nível SEM USAR a instrução GoTo.

Adianto que com as facilidades da linguagem de mais alto nível, o número de instruções GoTo ficam bem reduzidas. De posse do fluxograma, a listagem do programa fica perfeitamente compreensível.

Segue o novo fluxograma para o enunciado do exemplo da página 54 da apostila do Paulo. Até o momento acredito que sejam necessários apenas três instruções GoTo, identificadas pelos acessos aos rótulos P1, P2 e P3. Talvez até P3 possa ser evitado. Quando fizer o programa e constatar seu funcionamento, postarei aqui.

 

http://www.4shared.com/zip/wb_Hn73Qce/Exemplo_pg54__2_.html

 

[]'s

MOR_AL

Link para o comentário
Compartilhar em outros sites

  • mês depois...

Uma dica importante :

Muitas vezes queremos fazer com que nosso projeto possa trabalhar com velocidades bem altas ou tempos bem curtos.

Por exemplo, Pwms de alta frequência, ou Timers com baixíssimo tempo, ou até detectar variações em entradas de alta frequência costumam usar interrupções para isto.

E como toda linguagem de alto nível, nessas horas o próprio compilador torna-se um inimigo poderoso !

Quando ocorre uma interrupção, os registradores do microcontrolador tem de ser salvos no Stack , e ao final da rotina de interrupção, eles tem de ser repostos. Isto consome vários ciclos de máquina, ou seja, tempo de programa !

A grosso modo, podemos dizer que perdemos no mínimo 40 ciclos de clock, e mais o tempo que a nossa rotina de interrupção irá consumir. Afinal, o compilador prefere salvar todos os que ele usa, para garantir !

E na grande maioria das vezes, bastaria salvar apenas uns 6 registradores e já bastaria !

Imagine que nosso processador está rodando a 10 Mhz. E queremos fazer um contador que aumente uma variável tipo Word a cada vez que o pino de INT vai para zero.

Se usarmos as instruções normais do Bascom, o tempo necessário para fazer isto será de 40 + 8 + 18 = 66 ciclos de clock.

Se calcularmos 10 Mhz / 66, teremos um resultado menor do que 150Khz.

Assim, para ter segurança, podemos dizer que nosso programa só vai funcionar direitinho se o sinal que queremos capturar ir para nivel 0 no máximo umas 130.000 vezes em um segundo !

No Bascom, existe uma maneira de indicar para o compilador não fazer o salvamento automático dos registradores, que é a declaração NO SAVE ao final da instrução que começa com ON ( a que declara a rotina de interrupção ) , mas neste caso a responsabilidade de salvar os registradores será nossa, o que é muito difícil sem saber quais registradores são utilizados em cada tipo de operação.

Mas temos uma opção muito legal para isto, pois podemos misturar livremente código em Basic com código em Assembler, e desta maneira podemos controlar precisamente quais registradores usamos e que devem ser salvos.

No próximo Post vou mostrar alguns truques que podem ser utilizados para minimizar este problema de tempos envolvidos em interrupções.

Paulo

Link para o comentário
Compartilhar em outros sites

Uma dica importante :

.....

Quando ocorre uma interrupção, os registradores do microcontrolador tem de ser salvos no Stack , e ao final da rotina de interrupção, eles tem de ser repostos. Isto consome vários ciclos de máquina, ou seja, tempo de programa !

Ok!

A grosso modo, podemos dizer que perdemos no mínimo 40 ciclos de clock, e mais o tempo que a nossa rotina de interrupção irá consumir. Afinal, o compilador prefere salvar todos os que ele usa, para garantir !

Ele salva APENAS os que ele usa, ou TODOS os registros?

E na grande maioria das vezes, bastaria salvar apenas uns 6 registradores e já bastaria !

Certo!

Imagine que nosso processador está rodando a 10 Mhz. E queremos fazer um contador que aumente uma variável tipo Word a cada vez que o pino de INT vai para zero.

Se usarmos as instruções normais do Bascom, o tempo necessário para fazer isto será de 40 + 8 + 18 = 66 ciclos de clock.

Se calcularmos 10 Mhz / 66, teremos um resultado menor do que 150Khz.

Assim, para ter segurança, podemos dizer que nosso programa só vai funcionar direitinho se o sinal que queremos capturar ir para nivel 0 no máximo umas 130.000 vezes em um segundo !

Ok!

No Bascom, existe uma maneira de indicar para o compilador não fazer o salvamento automático dos registradores, que é a declaração NO SAVE ao final da instrução que começa com ON ( a que declara a rotina de interrupção ) , mas neste caso a responsabilidade de salvar os registradores será nossa, o que é muito difícil sem saber quais registradores são utilizados em cada tipo de operação.

Esse é o problema. Como saber quais registradores o Bascom está usando e como fazer o Bascom usar determinados registradores. Com isso poderíamos separar alguns para o Bascom e poucos para nossos trechos de programa, reduzindo substancialmente o tempo do tratamento de alguma rotina. Com a linguagem Assembly eu escolho e fica bem rápido, mas isso eu fazia com os PICs. Não pretendo usar o Assembly com os AVRs. Já investi muito tempo com essa linguagem.

Mas temos uma opção muito legal para isto, pois podemos misturar livremente código em Basic com código em Assembler, e desta maneira podemos controlar precisamente quais registradores usamos e que devem ser salvos.

Não entendi! Como identificar os registros usados no Bascom, para não ser necessário salvar todos os registros? Sem essa identificação, não se pode usar os outros registros não utilizados pelo Bascom.

... Ha! Você se refere a escrever pequenas rotinas em Assembly, usando alguns registradores, salvando apenas eles, certo? Mesmo que estes registradores não estejam sendo usados pelo Bascom?

No próximo Post vou mostrar alguns truques que podem ser utilizados para minimizar este problema de tempos envolvidos em interrupções.

Paulo

 

Aguardo por estes truques, pois apareceu um problema que devo controlar diversas variáveis, presentes na entrada do uC.

[]'s

MOR_AL

Link para o comentário
Compartilhar em outros sites

@MOR,

Ele salva apenas os que usa. Mas os que ele não usa são poucos....

Por exemplo, temos certeza que estes aqui não são usados :

R12,R13,R14 e R15.

Mas todos os outros podem ser usados, dependendo das instruções.

Muitas vezes dentro da interrupção apenas mudamos alguma variável, tipo incrementando ou decrementando, e desta maneira fica fácil saber, pois o Bascom sempre faz a mesma coisa quando a variável é tipo Byte ou Word. Um caso desses é bem simples de fazer com umas instruções simples em Assembler, e podemos apenas salvar alguns registros usados neste caso, ganhando muito tempo.

O que eu estou propondo é simplesmente trocar instruções simples do Basic normalmente utilizadas dentro de uma interrupção, como INCR ou DECR ou atribuir um valor a uma variável, por pequenos trechos padronizados com instruções em assembler.

Enquanto não posto estes truques, dá uma olhada aqui :

http://www.mcselec.com/index2.php?option=com_forum&Itemid=59&page=viewtopic&t=11899

Este utilitário mostra de uma maneira bem legal os códigos compilados dentro de cada instrução do Bascom, e isso ajuda a otimizar o código, pois saberemoa quais registros são usados no código.

Paulo

Link para o comentário
Compartilhar em outros sites

Como é que faz para compilar no Bascom gerando a listagem com o código em assembler ou que ferramentas que ele usa que gerar estas informações ? No meu tempo de Turbopascal eu aprendia muito sobre assembler examinando o código gerado pelo complilador (e fazendo debuger também).

 

No final na própria página (site) já tem a instrução de como fazer isto. ( objdump -S filename.obj )

 

Ver o programa compilado em Bascom em assembler é como se abrisse uma janela para o universo, e como ele é extenso.

 

 

Mas e um Debuger para o AVR ?

Link para o comentário
Compartilhar em outros sites

@aphawk

 

Taí! Veja se posso fazer assim.

Generalizando.

Quando a rotina (não necessariamente dentro de interrupção) precisar ser mais rápida e for relativamente simples, vou proceder assim:

1 - Abro a janela para códigos em assembly.

2 - Salvo os poucos registros que precisarei usar em memória definida no início do programa, independente dos registros usados ou não pelo Bascom.

3 - Escrevo a rotina em assembly usando estes registros previamente salvos.

4 - Salvo o resultado da rotina (caso haja algum) em variável definida no início do programa.

5 - Recupero os registros usados. O oposto do item 2.

6 - Fecho a janela para códigos em assembly.

 

Não acho muito confiável observar quais registros o Bascom não esteja usando e não salvá-los. Com uma atualização do programa, depois de algum tempo, fica difícil acompanhar ou lembrar dos detalhes e limitações que impusemos antes.

 

Em tempo: Continuarei sem ter que aprender o assembly a fundo. As rotinas seriam escritas em conformidade desse pensamento.

 

Como sou novato neste aplicativo, gostaria de suas opiniões sobre esse meu procedimento.

MOR_AL

Link para o comentário
Compartilhar em outros sites

@Intrudera6,

 

voce pode usar o próprio Bascom, ele tem um simulador e debugger bem poderoso. Ou pode usar o Avr Studio 4, que é bem leve e funciona muito bem para esta finalidade.

Pode também comprar um USBASP modificado para fazer o Debugger em tempo real, mas não funciona em toda a família de AVRs.

 

Ou pode comprar o debugger oficial da Atmel.......

 

 

@MOR,

 

Sim, o procedimento é esse, o código em Assembler é escrito na mesma janela que o Basic mesmo....

 

Segue abaixo um pequeno texto que escreví agora pouco para ilustrar isso tudo.

 

 

Imaginem o seguinte trecho de programa em Bascom :

On INT1 mysub

Lá no código de interrupção temos isto :

Mysub:
Incr Pulse_counter
Return


Olha o código que é gerado pelo compilador no trecho da interrupção :

Mysub:
Push R0
Push R1
Push R2
Push R3
Push R4
Push R5
Push R7
Push R10
Push R11
Push R16
Push R17
Push R18
Push R19
Push R20
Push R21
Push R22
Push R23
Push R24
Push R25
Push R26
Push R27
Push R28
Push R29
Push R30
Push R31
In   R24,0x3F
Push R24
Ldi  R26,0x60
Ld   R24, X
Subi R24,0XFF
St     X,R24
Pop  R24 
Out  0x3F,R24
Pop    R31
Pop    R30
Pop    R29
Pop    R28    
Pop    R27   
Pop    R26  
Pop    R25  
Pop    R24 
Pop    R23
Pop    R22
Pop    R21  
Pop    R20   
Pop    R19     
Pop    R18 
Pop    R17  
Pop    R16   
Pop    R11     
Pop    R10   
Pop    R7  
Pop    R5  
Pop    R4 
Pop    R3  
Pop    R1  
Pop    R0
Reti

O endereço 0x60 é onde está alocada a variável Pulse_counter.

 

Reparem a quantidade absurda de registros salvos e repostos sem necessidade.

Muita coisa para se incrementar uma simples variável tipo Byte !!!!!
Vamos agora reescrever esse trecho de programa, mas otimizando, usando um pouquinho de Assembler :

Primeiro, temos de mudar um pouco a declaração da rotina de interrupção :

On INT1 Mysub Nosave

E agora o trecho da rotina de interrupção otimizado como vai ser escrito no Bascom :
 

Mysub:
Push  R24
In    R24,Sreg
Push  R24
Lds   R24,{Pulse_counter}
Incr  R24
Sts   {Pulse_counter},R24
Pop   R24
!Out  Sreg,R24 
Pop   R24 
Reti

Agora, olhem a comparação de tamanho em ciclos de clock : a original, do Bascom, tem 116 ciclos de clock; a nova, otimizada, que mistura Assembler, tem apenas 19 ciclos de clock !

Ou seja,  executa 6 vezes mais rápida !!!!

Quando temos de incrementar uma variável tipo Word, o Bascom faz isto chamando uma sub-rotina !!!!  Além de todo o desperdício que vimos lá acima, ainda teria uma instrução Call para um endereço, com um posterior Ret, fazendo com que ficasse com  139 ciclos !

Olhem como fica o nosso mesmo código acima, caso a variável fosse do tipo Word :

Mysub:
Push  R24
In    R24,Sreg
Push  R24
Lds   R24,{Pulse_counter}
Subi  R24,$FF
Sts   {Pulse_counter},R24
Lds   R24,{ Pulse_counter + 1 }
Sbci  R24,$FF
Sts   {Pulse_counter + 1},R24
Pop   R24 
!Out  Sreg,R24
Pop   R24
Reti

Ou seja, ficou apenas um pouquinho maior relativo à versão para variável Byte.

Vou lembrar aqui o mais importante :

- Sreg é o registrador com os Flags , é sempre importante salvar e repor ao final.
- Para o Assembler saber o endereço de uma determinada variável no Basic, existe a convenção de sempre colocar o nome dela entre colchetes {} .
- Para diferenciar a instrução Out do Assembler da instrução Out do Bascom, usamos sempre !Out para deixar claro que é uma instrução em Assembler.

Embora não seja necessário, eu acho importante sempre usar uma diretiva ao compilador para dizermos onde começa e onde termina um código em Assembler. Basta fazer assim :


    $asm
    ...    ‘ instruções em assembler    
    ...    
    ...
    $end Asm

As instruções em Assembler podem ser colocadas em qualquer lugar, e quantas vezes quisermos, nos programas em Bascom. Não apenas em interrupções, mas normalmente mesmo, no corpo do programa !

Eu fiz um trecho para utilizar no meu analizador lógico que é a maneira mais rápida de capturar eventos, usando dois buffers separados, um contendo o novo dado e outro contendo o tempo decorrido desde o antigo dado.

Em Basic puro, não conseguia capturar nem 50 Khz , e com o Assembler consigo capturar 500 Khz !

Segue como exemplo, é uma subrotina que é chamada quando quero fazer a captura.
 

Faz_captura1:
$asm
push  r0
in    r0, Sreg
push  r0
push  r16
push  r17
push  r18 
push  r26 
push  r27
PUSH  r28
PUSH  r29
push  r30
push  r31
PUSH  r19
PUSH  r20 
push  r21
'pega o valor do inicio do buffer:
LDS   r26,{bCounter_leitura}
LDS   r27,{bcounter_leitura+1}
'PEGA O ENDEREÇO FINAL DO BUFFER E POE EM R29:R30
LDI   r28,$c5
LDI   r29,$03 
'CONTADOR COM R19:R20      
'E R21:R22 SENDO QUE ESTE SEMPRE É 1
LDI   r30,{bcounter_tempo}
LDI   r31,{bcounter_tempo+1}
LDI   r19,$00
LDI   r20,$00
LDI   r21,$00
LDI   r22,$01
' TUDO PRONTO ESPERA TRANSIÇÃO
IN    r16,PinC
MOV   r18,r16
Espera_0:
IN    r16,PinC
CP    r16,r18
BRNE  espera_01
SBIS  PinB,5
RJMP  espera_fim
rjmp  espera_0
Espera_01:
MOV   r18,r16  
ST    X+ ,r17
ST    Z+ ,r19 
ST    Z+ ,r16
LDI   r19,$00
LDI   r20,$00
Espera_1:
IN    r16,pinc   
CP    r16,r18    
BRNE  espera_3
SBIS  PINB,5 
RJMP  espera_fim 
ADD   r20,r22
ADC   r19,r21
BRCC  espera_1
Espera_2: 
LDI   r19,$ff
lDI   r20,$ff
Espera_3: 
MOV   r18,r16
ST    X+ ,r20
ST    Z+ ,r19
ST    Z+ ,r16
LDI   r19,$00 
LDI   r20,$01
CPSE  r26,r28
RJMP  espera_1
CPSE  r27,r29
RJMP  espera_1
Espera_fim:
STS   {bcounter_leitura},r26
STS   {bcounter_leitura+1},r27
pop   r21
POP   r20   
POP   r19
pop   r31 
pop   r30  
POP   r29   
POP   r28
pop   r27 
pop   r26   
pop   r18 
pop   r17 
pop   r16
pop   r0 
!out  Sreg,r0 
pop   r0
$end Asm
Return

Acho que dá para ter uma ideia do funcionamento disto.

Para saberem mais , procurem no Help do Bascom sobre o uso de Assembly integrado ao Basic, tem bastante dicas lá .

Paulo

Link para o comentário
Compartilhar em outros sites

No help do Bascom. No caso de interrupções, o compilador não salva os registros R6, R8 e R9.

Também os registros R12, R13, R14 e R15 não são usados, caso não se trabalhe com ponto flutuante dentro da interrupção. Aliás não recomendado pelo Bascom.

 

Isso significa que o Bascom não vai usar esses registros em nenhuma parte do código, caso haja o uso de interrupção no código do programa? Sendo assim, estes registros poderiam ser utilizados dentro de um grupo de instruções em asm, sem a necessidade de Pushs e Pops.

Parece estranho. Se ele não salva é porque não haveria perda de informação. Então não haveria o uso destes registradores.

Paulo. Você que já fez muitos programas com o Bascom, quando tiver um tempinho, poderia ver se estes registros não são utilizados pelo compilador?

Claro!

Parece que R12, R13, R14 e R15 são utilizados apenas quando há operação com ponto flutuante.

MOR_AL

Link para o comentário
Compartilhar em outros sites

@MOR,

 

Sim, sobre os R12 - R15 realmente só são usados caso tenha alguma operçação em ponto flutuante. Pode ver no primeiro exemplo que eu postei, que é o código "disassemblado", eles não foram usados.

 

E também os R6, R8 e R9 não são também ! 

 

Só não testei com ponto flutuante, farei isso hoje de noite.

 

No mínimo temos de salvar o Sreg, e para isso temos no mínimo dois Pushs e um movimento entre registradores , e na saída dois Pops e outro movimento de registradores.

 

Mas caso use algum outro comando do Bascom, seria muito interessante ver o código gerado, e salvar esses registradores também. é um trabalho em duas etapas, mas evita perder um baita tempão salvando quase tudo.

 

Paulo

Link para o comentário
Compartilhar em outros sites

  • 4 semanas depois...
  • 2 meses depois...

Pessoal!

Notei a ausência do colega Aphawk (Paulo) e enviei-lhe uma mensagem privada.

Ele respondeu e me pediu para avisar aos colegas, que esteve com problema de saúde.

No momento está convalescendo e em breve retornará ao nosso convívio.

Que você se recupere totalmente.

Saúde.

MOR_AL

PS: Procurei um local, aqui no fórum, para atender a solicitação do nosso colega. Encontrei em "Mural de Recados", porém, acredito que este tutorial com suas contribuições seja mais eficaz. Eu mesmo não conhecia o "Mural de Recados" até hoje e considero que possua um âmbito mais geral.

Caso os administradores desejem transferir esta postagem para outro local, compreenderemos perfeitamente.

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

obrigado amigo  MOR por  nos informar  e desejo  melhoras ao amigo Aphawk (Paulo) que  tem Ótimas contribuição  e não só pelas contribuições mas   como  ser humano também portanto    volte logo ! é o meu desejo e  de muitos  amigos aqui do fórum ok forte abraço  e estamos aguardando 

Link para o comentário
Compartilhar em outros sites

  • 3 semanas depois...

Aos amigos do Fórum,

Finalmente estou de volta, não com a mesma frequência que tinha, mas logo devo estar totalmente normalizado.

Agradeço a todos pelas mensagens e pela preocupação, e vou tentar recuperar o tempo perdido assim que estiver podendo me dedicar 100% novamente !

Circuit e Mor, agradeço muito à vocês também, e se posso falar alguma coisa que aprendí neste tempo em que fiquei " de castigo " , é que a Lei de Murph é implacável : embora as probabilidades sejam muito baixas de que algo dê errado, esse algo VAI dar errado... E não apenas uma vez, mas quantas forem necessárias até que resolvamos o problema. E sentir isso na própria pele dói viu !!!

Vamos em frente !

Circuit, salvo engano, a versão do Proteus que eu usei era a 7.9 ok ?

Paulo

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...