Ir ao conteúdo
  • Cadastre-se

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


Ir à solução Resolvido por aphawk,

Posts recomendados

Eita 4 canais :) você hackeou ele né? Pra mim o DS1052E já estaria de bom tamanho mas a Farnell vazou do Brasil (não sei como eles conseguiam vender ele por R$1K) e para importar é mais 100% de imposto... Eita vida HAHAHA

 

Se todas as suas imagens mudarem... UAHuHAuHauHUaUAH Melhor nem imaginar!! :lol:

 

Mas beleza, valeu ai.

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

  • mês depois...

Lendo sobre servo motores encontrei várias coisas interessantes sobre RC... Na hora pensei: "Com certeza o Paulo mexeu ou mexe com essas coisas..." :)

 

Caraca! 2,20Mts? Vixi... Você é profissional então!

 

Daqui há um tempo vou arrumar um helicóptero pra fazer ele voar de cabeça para baixo e de ré balançando nas laterais igual eu vi nos vídeos.

HAHHAhahahHAhha. :lol:

 

õ/

Link para o comentário
Compartilhar em outros sites

  • Coordenador
11 minutos atrás, test man*~ disse:

Daqui há um tempo vou arrumar um helicóptero pra fazer ele voar de cabeça para baixo e de ré balançando nas laterais igual eu vi nos vídeos.

HAHHAhahahHAhha. :lol:

 

õ/

Totalmente OFF-Topic!!!

Ai o Padre Quevedo vai dizer:

200px-Chirac.jpg

KKKKK!!!!...

 

Legal Paulo! Aeromodelismo era minha segunda opção depois do Autorama! Mas é um hobby muito caro!!! :( Hehehehe!!!...

 

Essa mensagem será explodida/deletada em breve......

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

28 minutos atrás, test man*~ disse:

Lendo sobre servo motores encontrei várias coisas interessantes sobre RC... Na hora pensei: "Com certeza o Paulo mexeu ou mexe com essas coisas..." :)

 

Caraca! 2,20Mts? Vixi... Você é profissional então!

 

Daqui há um tempo vou arrumar um helicóptero pra fazer ele voar de cabeça para baixo e de ré balançando nas laterais igual eu vi nos vídeos.

HAHHAhahahHAhha. :lol:

 

õ/

 

Hehehe eu fiz mais de 20 horas de curso intensivo de voo com aviões RC com motores a gasolina..... então comprei um avião Bixler, de isopor reforçado, muito legal, só que com motor elétrico, e quando me senti mais "confiante" , conversei com o meu instrutor, ele me indicou um profissional de montagem de aviões RC grandes, fui até ele e me indicou o que ele precisava para montar, eu comprei todo o material nos USA, trouxe para ele, e em 20 dias ele me entregou um belo avião..... mas ainda não tive coragem de voar com ele, ficou tão bonito que tenho medo de destruir logo de cara !

 

Só para ter ele montado, SEM O SISTEMA DE RC, custou quase R$ 5.000,00, isso que um amigo me trouxe isso tudo dos USA, pagando apenas o custo do peso/volume embracado como bagagem !

 

Agora, tem muita coisa legal que pode ser feita com servos !!!! Tenho uma GO PRO , com um sistema de controle de movimento com 2 servos, usei uma vez para controlar à distância o que eu queria que fosse filmado, e controlava tudo com o meu radiocontrole a mais de 500 metros !

 

 

adicionado 5 minutos depois

@Bcpetronzio ,

 

Hehehe legal, mas existem opções não tão caras hoje em dia !

 

Você pode dar uma olhada em um avião tipo Bixler 2, e um simples rádio-controle de 4 canais para começar, tem muita gente que vende isso usado baratinho, e já dá para brincar muito com esse aviãozinho !

 

bixler2-main(2).jpg

 

Ele tem mais de 1,5 metros de envergadura, e plana muito bem !

Já consegui voar quase 40 minutos com ele, em um dia quente, onde tinha muita corrente de ar subindo, foi muito legal !

 

Paulo

 

 

 

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

  • 2 meses depois...
  • Solução

GERADOR SÍNCRONO DE FREQUÊNCIAS

 

Um amigo precisou de um pequeno circuito que gerasse com precisão as frequências de 9.600 Hz, 480 Hz, 240 Hz, 120 Hz e 60 Hz, de preferência que esses sinais não apresentassem nenhuma diferença de fases entre eles. E feito com componentes de baixo custo.

 

Ou seja, é uma espécie de contador síncrono, onde todos os sinais comutam exatamente no mesmo nanosegundo, sem nenhuma pequena diferença de tempo entre eles.

 

A maneira tradicional de fazer isso envolve uma interrupção de um Timer, de preferência que possa ser programado para gerar o tempo necessário sem nenhum erro.

 

Reparei que todas essas frequências são múltiplas de 60 Hz. Então, a primeira coisa que me passou pela cabeça  foi programar um Timer para gerar os 9600 Hz, e a partir daqui, contaria os ciclos dessa interrupção para ir gerando as outras frequências, por exemplo a frequência de 480 Hz seria gerada a partir de 20 interrupções de 9600 Hz. Ideia simples !

 

Peguei todos os cristais que conheço que são prontamente disponíveis no mercado, acima de 1Mhz, e fui vendo utilizando as fórmulas dos Timers, e cheguei a uma conclusão chata : nenhum deles permite gerar os 9600 Hz precisamente !

 

Sei que existem alguns cristais que permitem, mas quase sempre não se acha eles fácil no mercado. Teria de usar um dos cristais mais comuns.

 

Me lembrei que num projeto anterior, publicado aqui neste tópico mesmo, eu criei um gerador de frequências que utilizava dois Timers, sendo um no modo Counter , e outro como Timer mesmo, e assim conseguia gerar quase qualquer frequência.

 

Assim, após algumas contas, cheguei a um cristal de 12.288 Mhz, facilmente encontrável no mercado, e que me permite chegar aos 9.600 Hz, pois 12.288 Mhz dividido por 9600 resulta em 1280, que pode ser decomposto em duas multiplicações de várias maneiras. A utilizada foi 4 x 320 .

 

Assim, resolvi encadear a saída do Timer2 na entrada do Timer0, sendo que este ultimo funcionando como Counter.

 

Finalmente, a saída do Timer0 liguei diretamente na entrada INT0 , gerando uma interrupção a toda borda de subida.

 

Pronto, consegui gerar precisamente a interrupção 9600 vezes por segundo, de forma muito precisa, totalmente por hardware. Assim não tenho nenhum possível JITTER nesse período de interrupção.

 

Quando comecei a pensar no programa, percebi que uma maneira simples é inverter os bits da porta de saída , que escolhi como sendo o PORTC, usando a instrução Toggle, mas se isso fosse feito ao longo da rotina de interrupção, sempre existiria um pequeno delay de alguns nanosegundos entre a comutação de um sinal no início da rotina de interrupção e um outro sinal ao final da rotina.

 

Então, tive outra ideia simples :

 

Assim que começa a rotina de interrupção, a primeira coisa que faço é escrever o conteúdo de uma variável na porta de saída PORTC.

 

A seguir, vou fazendo a contagem das interrupções, e conforme for atingido o momento de comutar alguma das saídas, eu faço o Toggle no bit correspondente da variável !

 

Faço o mesmo procedimento para os 5 sinais envolvidos, e saio da rotina de interrupção.

 

Assim, quando houver uma nova interrupção, o conteúdo dessa variável é escrito no port de saída, fazendo com que todos os 5 sinais sejam atualizados no mesmo instante !

 

Ao testar o programa, o que eu obtive era exatamente A METADE da frequência que eu pensei obter, e então percebi que havia me esquecído que ocorrem duas transições no pino INT0 mas apenas uma gera interrupção ... então tive de gerar 19200 Hz em vez de 9600, para que os procedimentos de Toggle funcionassem como eu queria.

 

Então, simplesmente programei o Timer0 para contar a metade dos pulsos, e pronto, consegui gerar todas as frequências de maneira síncrona, sem nenhum JITTER entre elas.

 

Segue o programa, bem simples, que ocupa 1% da memória do Atmega328 :

 

$regfile = "m328pdef.dat"
$crystal = 12288000
$hwstack = 90
$swstack = 90
$framesize = 120

' Vamos criar contadores para cada frequencia a ser gerada
Dim X480 As Byte
Dim X240 As Byte
Dim X120 As Byte
Dim X60 As Byte

' Agora, uma variavel para manipularmos os seus bits e criarmos
' as formas de onda desejadas
Dim Saida As Byte
' Valor inicial dela será zero
Saida = 0


Config Clockdiv = 1

' Vamos tornar esses 5 pinos do PortC como SAIDA
Ddrc.0 = 1
Ddrc.1 = 1
Ddrc.2 = 1
Ddrc.3 = 1
Ddrc.4 = 1
' Esperamos um pouquinho ...
Waitms 10
' E ja colocamos 0 nos pinos de saida
Portc = 0

' Agora, configurar os dois Timer para gerarmos as frequencias necessarias
Config Timer2 = Timer , Prescale = 1 , Compare A = Toggle , Clear Timer = 1
Config Timer0 = Counter , Edge = Falling , Compare A = Toggle , Clear Timer = 1

Stop Timer0
Stop Timer2


Ocr2a = 1
Ocr0a = 79
' PRONTO, AGORA ESTAMOS GERANDO 19200 HZ SUPER PRECISOS

' E agora vamos configurar para que ocorra uma interrupcao
' na subida do pulso de clock de 19200 Hertz
Config Int0 = Rising
' E vamos chamar nossa rotina que vaigerar as formas de onda !
On Int0 Faz_onda

Enable Int0
Enable Interrupts

Start Timer2
Start Timer0



Fica_aqui:
' loop infinito sem fazer nada
Goto Fica_aqui
Stop


' SUB-ROTINA DE INTERRUPÇÃO
'
'Gera todas as frequências sem nenhum jitter

Faz_onda:
' De cara, colocamos o conteudo da variavel nas saidas
Portc = Saida
' E incrementamos todos os contadores
Incr X480
Incr X240
Incr X120
Incr X60

' Aqui geramos a saida de 9600 
Toggle Saida.0

' Agora testamos cada contador para ver se atingiu o valor
' necessario para gerar a frequencia desejada
' e se atingiu, então zeramos o contador
' e invertemos o bit correspondente na variavel

If X480 = 20 Then
  Toggle Saida.1
  X480 = 0
End If

If X240 = 40 Then
  Toggle Saida.2
  X240 = 0
End If

If X120 = 80 Then
  Toggle Saida.3
  X120 = 0
End If

If X60 = 160 Then
  Toggle Saida.4
  X60 = 0
End If

' Pronto, fizemos tudo !
Return


End

 

o Esquema de uso é este aqui :

 

gerador de frequencia cdh.jpg

 

Paulo

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

@aphawk

Paulo.

Acho que entendi. Veja se é isso.

Você usa o timer2 para gerar um tempo preciso. A cada tempo do timer2, você acessa o contador do timer0 para atualizar os registros X caso sejam necessários. 

O pulo do gato é que a atualização só é feita após ter escrito na porta c. Então, na realidade, você está escrevendo, o que já havia sido calculado, com um ciclo do timer2 de atraso. Com isso você pode escrever na porta c sempre com o período idêntico, o que garante a falta de gitter nas transições das frequências.

Se eu estiver correto, foi uma bela solução, meus parabéns.

MOR_AL

Link para o comentário
Compartilhar em outros sites

@MOR,

 

Sim, é quase isso mesmo, você pegou de cara o processo todo, mas eu não acesso o contador, eu apenas uso a interrupção do estouro do Timer0 para fazer as temporizações.

 

Mas o pulo do gato foi esse mesmo que você descreveu !

 

Eu criei uma variável auxiliar, e são os bits dessa variável que eu fico invertendo quando chega o momento exato, dentro da rotina de interrupção. E é o conteúdo dessa variável que é escrito na saída do PortC !

 

Na verdade, o Timer0 é usado com um contador de pulsos aplicados na entrada dele pela saída do Timer2 !

 

O Timer2 está apenas contando pulsos de clock. Da maneira que eu programei, ele está mudando a saída dele a cada dois ciclos de clock, ou seja, nessa saída temos uma frequência que é a frequência de clock dividida por 4.

 

Se eu pegar essa frequência e usar ela como clock de entrada no Timer0, e programar ele para funcionar como Counter, ele vai mudar a saída dele a cada 80 clocks da entrada dele , ou seja, da mesma maneira acima, teremos a frequência de entrada dividida por 160.

 

Portanto, teremos 12.880.000 / 4 / 160 = 19.200 Hertz !

 

A beleza da solução é que isso tudo é feito automaticamente pelo hardware, a precisão é total, só depende da estabilidade do cristal.

 

Na verdade, eu poderia até mesmo programar o Timer0 para gerar a interrupção diretamente no transbordo  e assim já teria a interrupção que eu precisava.

 

Mas para efeito de didática, preferi ligar a saída do Timer0 ao pino de INT0, e programei esse módulo para gerar uma interrupção a cada subida do clock.

 

Fiz isso apenas para que os iniciantes veja a quantidade de soluções possíveis em usar os vários módulos internos existentes em um microcontrolador , todos eles agindo juntos para atender o nosso objetivo !

 

Assim que entra a rotina de interrupção, a primeira coisa que faço é atualizar as saídas com o padrão que foi "preparado" pela interrupção anterior.

 

Desta forma os tempos entre as atualizações da saída serão sempre idênticos , sem nenhum jitter, até parece a saída de um contador síncrono heheh !

 

Obrigado pelo elogio, meu amigo !

 

Paulo

Link para o comentário
Compartilhar em outros sites

Aphawk, bem pelo que eu vi eu postarei aqui. Bom não sei por que o atmega 328p não emula no meu protheus, mas esse atmega 8 emula, então estou tentando fazer por ele.

Para fins de aprendizado estou tentando fazer um relogio com cronometro no virtual terminal mesmo. Se der certo tento implementar a logica num display lcd e posterior num de 7 segmentos.

 

Consegui contar os segundos por waitms, mas sempre ele reebotava quando ia pro cronometro, usando timers ele não reebota, mas ele "deixa" de calcular quando ativo o cronometro.

o cronometro ele não calcula os milesimos de segundos que eu preciso, pois com os exemplos que vi so vai segundos e frações quebradas de segundos -_-'

 

Sendo assim tava usando um cristal de 4 megahertz para emulação e finalmente segue o código:

$regfile = "m8def.dat"
$crystal = 4000000
$hwstack = 40
$swstack = 16
$framesize = 32

Config Portd.3 = Input
Config Portd.4 = Input
Config Portd.5 = Input
Config Portd.6 = Input
Config Portd.7 = Input
Config Portd.2 = Input
Config Portd.5 = Output
Config Portd.6 = Input
Config Portd.7 = Input

Portd.6 = 1
Portd.7 = 1
Portd.3 = 1
Portd.4 = 1
Portd.5 = 1
Portd.6 = 1
Portd.7 = 1
Portd.2 = 1
Portc.5 = 0
Config Timer2 = Timer , Prescale = 128 , Async = On
Timer2 = 0
Enable Interrupts
Enable Timer2
On Timer2 Pulse:
Config Timer0 = Timer , Prescale = 256 , Async = On

Enable Timer0
Stop Timer0
Dim Hora As Integer
Dim Minuto As Integer
Dim Segundo As Integer
Dim Milesimo As Integer
Dim A As Integer
Dim Cronometro As Integer
Dim Cronometro1 As Integer
Dim Cronometro2 As Integer
Dim Comeco As Integer
Dim Conta As Integer
 Do

 Continue:

  If Segundo = 20 Then
  Segundo = 0
  Minuto = Minuto + 1
  End If
  If Minuto = 60 Then
  Minuto = 0
  Hora = Hora = 1
  End If
  If Hora = 24 Then
  Hora = 0
  End If
  If Hora < 0 Then
  Hora = 0
  End If
  If Minuto < 0 Then
  Minuto = 0
  End If
  If Pind.3 = 0 Then Goto Rotina1
  If Pind.4 = 0 Then Goto Rotina2
  If Pind.5 = 0 Then Goto Rotina3
If Pind.6 = 0 Then Goto Rotina4


Print Hora ; ":" ; Minuto ; ":" ; Segundo

 Loop
 End

'-------------
Pulse:
 Segundo = Segundo + 1
 Return


 '-------------------
 Rotina1:
 Do
 Waitms 200

   If Conta = 0 Then

 Hora = Hora + 1

    End If
    If Conta = 1 Then
    Hora = Hora - 1
    End If


 Loop Until Pind.3 = 1

  Goto Continue
  '----------------------
  Rotina2:
  Do
     Waitms 200
     If Conta = 0 Then

  Minuto = Minuto + 1
                 End If
                 If Conta = 1 Then
                 Minuto = Minuto - 1
                 End If


  Loop Until Pind.4 = 1

  Goto Continue
  '-----------
      Rotina3:
      Do
       Waitms 200
      Conta = Conta + 1
      If Conta = 2 Then
      Conta = 0
      End If


      Loop Until Pind.5 = 1
      Goto Continue
      '--------------------
      Rotina4:
      Do



      Print Cronometro2 ; ":" ; Cronometro1 ; ":" ; Cronometro


      If Pind.7 = 0 Then
                          Do
                          Waitms 200

      Comeco = Comeco + 1
      End If
      Loop Until Pind.7 = 1

      If Comeco = 1 Then

     Start Timer0

      On Timer0 Pulse1
      If Cronometro >= 100 Then
      Cronometro = 0
      Cronometro1 = Cronometro1 + 1
      End If
      If Cronometro1 = 60 Then
      Cronometro1 = 0
      Cronometro2 = 1

       Print Cronometro2 ; ":" ; Cronometro1 ; ":" ; Cronometro
       Else

      End If



           End If

     If Comeco = 2 Then
          Stop Timer0
     Print Cronometro2 ; ":" ; Cronometro1 ; ":" ; Cronometro
     End If
     If Comeco = 3 Then

     Stop Timer0
     Cronometro2 = 0
     Cronometro1 = 0
     Cronometro = 0
     Print Cronometro2 ; ":" ; Cronometro1 ; ":" ; Cronometro
     End If
     If Comeco = 4 Then
     Stop Timer0

     Comeco = 1
     End If

     Print Cronometro2 ; ":" ; Cronometro1 ; ":" ; Cronometro

     Loop Until Pind.6 = 1

     If Pind.2 = 1 Then Goto Continue


  '-------------------
  Pulse1:
  Cronometro = Cronometro + 1
  Return

 

Link para o comentário
Compartilhar em outros sites

@lucianolcoa ,

 

Cara, tem tanto erro nesse seu código que eu estou faz meia hora tentando acertar tudo e ainda estou com erro na compilação !!!

 

Me diz uma coisa : afinal, o que que você quer fazer ?

Qual é o objetivo de seu programa ?

 

Vou abandonar esse seu código doido e fazer o meu mesmo.

 

Paulo

Link para o comentário
Compartilhar em outros sites

5 minutos atrás, aphawk disse:

@lucianolcoa ,

 

Cara, tem tanto erro nesse seu código que eu estou faz meia hora tentando acertar tudo e ainda estou com erro na compilação !!!

 

Me diz uma coisa : afinal, o que que você quer fazer ?

Qual é o objetivo de seu programa ?

 

Vou abandonar esse seu código doido e fazer o meu mesmo.

 

Paulo

Meu objetivo era só aprender mesmo. Estou acostumado com a linguagem arduino e estou tentando aprender o BASCOM, sei que nessa linguagem eu sou bem amador, mas se eu não "quebrar a cabeça" eu não vou melhorar -_-'. Os tutoriais que vejo são tudo em inglês e os videos no youtube ensinando são em espanhol... Não domino bem nenhum dos dois idiomas* pra ser sincero nem o portugues domino direito* então sabia que "aprender na raça" seria o metodo mais propenso a falhas, mas seria o metodo que me faria acertar também, kkkkkkk

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

@lucianolcoa ,

 

Então sugiro que começe pelo início ! Sem os fundamentos, tudo é um monte de chute sem lógica !

 

De que adianta Timers sem você fazer o cálculo dos tempos envolvidos ?

 

Um programa minimamente estruturado tem apenas um único loop Do !  Contei uns 6 aqui no seu programa !

 

Sem ter o conhecimento de para que servem os Timers, você não vai conseguir usar !

 

O que você quer fazer é um tipo de cronometro, onde quando clico um botão ele começa a contar o tempo em milisegundos, e quando clico outro botão, a contagem pára e o tempo é mostrado na porta serial, é isso ?

 

 

adicionado 1 minuto depois
9 minutos atrás, lucianolcoa disse:

Os tutoriais que vejo são tudo em inglês e os videos no youtube ensinando são em espanhol... Não domino bem nenhum dos dois idiomas* pra ser sincero nem o portugues domino direito* então sabia que "aprender na raça" seria o metodo mais propenso a falhas, mas seria o metodo que me faria acertar também, kkkkkkk

 

Ué, então por que não baixa o tutorial que eu mesmo escreví ????????????????????

 

Leia o primeiro post deste tópico com atenção, meu amigo !

 

Paulo

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

45 minutos atrás, aphawk disse:

@lucianolcoa ,

 

Então sugiro que começe pelo início ! Sem os fundamentos, tudo é um monte de chute sem lógica !

 

De que adianta Timers sem você fazer o cálculo dos tempos envolvidos ?

 

Um programa minimamente estruturado tem apenas um único loop Do !  Contei uns 6 aqui no seu programa !

 

Sem ter o conhecimento de para que servem os Timers, você não vai conseguir usar !

 

O que você quer fazer é um tipo de cronometro, onde quando clico um botão ele começa a contar o tempo em milisegundos, e quando clico outro botão, a contagem pára e o tempo é mostrado na porta serial, é isso ?

 

 

adicionado 1 minuto depois

 

Ué, então por que não baixa o tutorial que eu mesmo escreví ????????????????????

 

Leia o primeiro post deste tópico com atenção, meu amigo !

 

Paulo

Seria um relogio com cronometro, mostrando na porta serial, voce liga e reboota o cronometro e, quando aperta o botao da "hora, volta novamente a contar a hora.

Link para o comentário
Compartilhar em outros sites

Eu tenho um exemplo de relógio feito em Bascom no AVR 328P, acho que deve ser fácil adaptar o meu programa para fazer o que você quer. No caso, este programa é um relógio calendário usando 1 timer (não uso RTC neste programa).Ele tem 100 interrupções por segundo, acho que pode ser modificado para mais. Ele está com muitos comentários no código, acho que vai ser muito útil no seu aprendizado. Não sei se dá para chegar ao milissegundo sem problemas (estou meio enferrujado no momento). Neste exemplo ele mostra num display LCD  8x2 a data e a hora e é possível acertar a hora por duas teclas (isto não foi implementado num Arduino, mas deve funcionar facilmente num).

 

Este meu programa deu até vontade de voltar a programar em Bascom, estou ficando enferrujado do tempo que não meto a mão na linguagem. Quase dá vontade de fazer o cronômetro para você, não falta muito para isso.

$regfile = "m328pdef.dat"                                   ' specify the used micro
Const Frequencia = 16000000                                 ' Frequência em Hz
$crystal = Frequencia                                       ' used crystal frequency
$baud = 19200                                               ' use baud rate
$hwstack = 32                                               ' default use 32 for the hardware stack
$swstack = 10                                               ' default use 10 for the SW stack
$framesize = 40                                             ' default use 40 for the frame space

$initmicro

Const Valor_prescale = 256
Const Interrupcoes_por_segundo = 100
Const Tempo_aguardando = Interrupcoes_por_segundo * 2       ' Tempo em segundos
Const Preload = 65535 - Frequencia \(valor_prescale * Interrupcoes_por_segundo) + 1

Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 , E = Portc.1 , Rs = Portc.2
Config Lcd = 16 * 2                                         ' Configurando o LCD

Config Pinb.0 = Input                                       ' Configura porta B0 para entrada
Config Pinb.1 = Input                                       ' Configura porta B1 para entrada
Set Pinb.0                                                  ' Liga resistência interna do AVR (valor é forçado a 1 se não está apertado)
Set Pinb.1                                                  ' Liga resistência interna do AVR (valor é forçado a 1 se não está apertado)

S2 Alias Pinb.0                                             ' Define que porta B0 é S2
S1 Alias Pinb.1                                             ' Define que porta B1 é S2

Config Timer1 = Timer , Prescale = Valor_prescale           ' Valores possíveis para Prescale => 1|8|64|256|1024
On Timer1 Tim1_isr                                          ' Executa rotina Tim1_usr nas interrupções
Timer1 = Preload
Enable Timer1

Enable Interrupts                                           ' As interrupções são habilitadas

' Fornece o número máximo de dias do mês na variável Global NDias
Declare Sub Diasmes(ano_ent As Word , Mes_ent As Byte )

' Formata a saída com dois dígitos e separador retornando na variável Entrada_Texto
Declare Sub Formata(entrada As Byte , Entrada_texto As String * 8 , Complemento As string * 1)


Dim Cont As Dword
Dim Cont_ant As Dword
Dim Contador As Dword
Dim Contador_ant As Dword
Dim Var1dword As Dword
Dim Var2dword As Dword
Dim Var1word As Word
Dim Var2word As Word
Dim Var1byte As Byte
Dim Var2byte As Byte
Dim Posicao As Byte
Dim Acerta As Bit
Dim S1_apertado As Bit
Dim S2_apertado As Bit
Dim Bissexto As Bit
Dim Status_teclas As Bit
Dim S1_Aux As Bit
Dim S2_Aux As Bit
Dim Centesimo As Byte
Dim Segundo As Byte
Dim Minuto As Byte
Dim Hora As Byte
Dim Dia As Byte
Dim Mes As Byte
Dim Ano As Word
Dim Ano2 As Word
Dim Anoaux As Byte
Dim Ndias As Byte

Dim Linha1 As String * 8
Dim Linha2 As String * 8
Dim Aux As String * 1

Contador = 0
Cont = 0
Centesimo = 00
Segundo = 00
Minuto = 30
Hora = 12
Dia = 01
Mes = 01
Ano = 2012


Call Diasmes(ano , Mes)
Cont_ant = 1                                                ' força que mostre no LCD

Cls

S1_apertado = 1                                             ' = 0 se o botão esquerdo foi apertado
S2_apertado = 1                                             ' = 0 se o botão direito foi apertado
Posicao = 0
Acerta = 0                                                  ' = 0 se não está em modo de edição
Do

   S1_Aux = S1
   S2_Aux = S2
   If S1_Aux = 1 And S1_Apertado = 1 Then Status_Teclas = 0
   If Acerta = 0 And S2_Aux = 0 Then                            ' não faz nada se S2 (botão direito) está apertado
      Status_teclas = 0
   Else
      If Acerta = 0 And S1_Aux = 0 Then                         ' Botão da esquerda (S1=0) apertado entra em modo de edição (Acerta => 1)
         S1_apertado = 0
         If Status_teclas < 1 Then
            Status_teclas = 1
            Contador_ant = Contador                         ' Começa a contar o tempo até 2 segundos
         Else
            Var1Dword = Contador - Contador_ant
            If Var1Dword >= Tempo_Aguardando Then Posicao = 1 ' Até ser maior ou igual a 2 segundos
         End If
      Else
         If Acerta = 0 Then
            If Posicao = 1 And S1_Aux = 1 Then
               Acerta = 1
               S1_apertado = 1
               Status_teclas = 0
            End If
         Else
            If S1_Aux = 0 And S2_Aux = 1 Then                       ' Botão da esquerda (S1=0) apertado e Botão da direita (S2=1) não apertado
               If S1_apertado = 1 Then
                  S1_apertado = 0
                  If Posicao < 5 Then
                     Incr Posicao
                  Else
                     Posicao = 0
                     Acerta = 0
                     Status_teclas = 0
                  End If
               End If
            Elseif S1_Aux = 1 and S1_Apertado = 0 Then
               S1_Apertado = 1
            End If
         End If
      End If
   End If

   If Posicao > 0 And Posicao <= 5 Then                     ' colocar o cursor piscando na posição de edição
      If Posicao < 3 Then
         Var1byte = Posicao - 1
         Var1byte = Var1byte * 3
         Var1byte = Var1byte + 1
         Locate 1 , Var1byte                                ' Linha 1 do LCD
      Else
         Var1byte = 5 - Posicao
         Var1byte = Var1byte * 3
         Var1byte = Var1byte + 1
         Locate 2 , Var1byte                                ' Linha 2 do LCD
      End If
      Cursor On Blink
   Else
      Posicao = 0
      Acerta = 0
      Cursor Off Blink
   End If

   If S1_Aux = 1 Then                                           ' Botão da esquerda (S1=1) não apertado
      If Posicao > 0 And Acerta = 1 Then
         If S2_Aux = 0 And S2_apertado = 1 Then                 ' Botão da direita (S2=0) apertado
            S2_apertado = 0
            Select Case Posicao
               Case 1 :
                  If Hora < 23 Then
                     Incr Hora
                  Else
                     Hora = 0
                  End If
               Case 2 :
                  If Minuto < 59 Then
                     Incr Minuto
                  Else
                     Minuto = 0
                  End If
                  Timer1 = Preload
                  Centesimo = 0
                  Segundo = 0
               Case 3 To 4 :
                  If Posicao = 3 Then
                     Var1Word = Ano Mod 100
                     If Var1Word < 99 Then
                        Incr Ano
                     Else
                        Ano = Ano - Var1Word
                     End IF
                  Else
                     If Mes < 12 Then
                        Incr Mes
                     Else
                        Mes = 1
                     End If
                  End If
                  Call Diasmes(ano , Mes)
                  If Dia > Ndias Then Dia = Ndias
               Case 5 :
                  If Dia < Ndias Then
                     Incr Dia
                  Else
                     Dia = 1
                  End If
            End Select
            Cont_ant = 0
         Elseif S2_Aux = 1 And S2_apertado = 0 Then             ' Botão da direita (S2=1) não apertado
            S2_apertado = 1
         End If
      ElseIf S1_Apertado = 0 Then
         S1_Apertado = 1
      End If
   End If

   While Cont_ant <> Cont
      Cont_ant = Cont
      Home
      Linha1 = ""
      Aux = ":"
      Call Formata(hora , Linha1 , Aux)
      Call Formata(minuto , Linha1 , Aux)
      Aux = ""
      Call Formata(segundo , Linha1 , Aux)
      Lcd Linha1

      Lowerline
      Ano2 = Ano Mod 100
      Anoaux = Ano2
      Linha2 = ""
      Aux = "/"
      Call Formata(dia , Linha2 , Aux)
      Call Formata(mes , Linha2 , Aux)
      Aux = ""
      Call Formata(anoaux , Linha2 , Aux)
      Lcd Linha2

      'Locate 1 , 4
      'Cursor On Blink ' faz piscar o cursor na linha 1 e coluna 4 do LCD

   Wend

Loop

End                                                         'end program

_init_micro:
Ddrc.3 = 1
Portc.3 = 0                                                 'LCD: R/W low
Return

'------------------------------------------------------------------
' Sub-rotina de timer1, chamada 100 vezes por segundo
'
Tim1_isr:

   push r23
   Timer1 = Preload

   Incr Contador
   If Centesimo < 99 Then
      Incr Centesimo
   Else
      Centesimo = 0
      If Segundo < 59 Then
         Incr Segundo
      Else
         Segundo = 0
         If Minuto < 59 Then
            Incr Minuto
         Else
            Minuto = 0
            If Hora < 23 Then
               Incr Hora
            Else
               Hora = 0
               If Dia < Ndias Then
                  Incr Dia
               Else
                  Dia = 1
                  If Mes < 12 Then
                     Incr Mes
                  Else
                     Mes = 1
                     Incr Ano
                  End If
                  Call Diasmes(ano , Mes)
               End If
            End If
         End If
      End If
      Incr Cont
   End If

   pop r23

Return

'------------------------------------------------------------------

' Fornece o número máximo de dias do mês na variável NDias

Sub Diasmes(ano_ent As Word , Mes_ent As Byte )

   Local Div4 As Word

   Div4 = Ano_ent And 3                                     ' equivalente a Mod 4, e se é maior que 0 não é divisível

   If Div4 > 0 Then
      Bissexto = 0
   Else
      Bissexto = 1
      Var2Word = Ano_ent Mod 400                              ' se é maior que 0 não é divisível
      Var1Word = Ano_ent Mod 100                              ' se é maior que 0 não é divisível
      If Var1Word = 0 And Var2Word > 0 Then Bissexto = 0
   End If
   If Mes_ent = 2 Then
      NDias = 28 + Bissexto
   Else
      Var1Byte = Mes_ent And &B00001001
      If Var1Byte = &B00001000 Or Var1Byte = &B00000001 Then
         NDias = 31
      Else
         NDias = 30
      End If
   End If

End Sub

' ==============================================================================

' Formata a saída com dois dígitos e separador retornando na variável Entrada_Texto

Sub Formata(Entrada As byte , Entrada_Texto As String * 8 , Complemento As string * 1)

   If Entrada < 10 Then Entrada_Texto = Entrada_Texto + "0"
   Entrada_Texto = Entrada_Texto + Str(Entrada)
   Entrada_Texto = Entrada_Texto + Complemento

End sub

 

Link para o comentário
Compartilhar em outros sites

Este foi o meu primeiro Relógio Calendário que eu fiz em Bascom, um programa que imagino que esteja bastante fácil de ser intendido pela simplicidade. Acho que estudando ele você vai aprender alguma coisa. Você já deve ter visto que no Bascom você só pode fazer uma operação aritmética por vez e está limitado a um IF com apenas dois testes lógicos, para mais tem que encadear, dá mais trabalho fazer cálculos, mas fica bem mais simples para entender.

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

6 minutos atrás, lucianolcoa disse:

Uma duvida, o que seria esses push e pop r23? e o sinal operador variavel1<> variavel2?

O push r23 coloca o registrador r23 na pilha para preservar, e pop r23 retira da pilha, mas não lembro para que utilizei isso, acho que não precisava (coisa de principiante). E <> é a mesma coisa que diferente de (a mesma coisa que != no C#).

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

@lucianolcoa@Intrudera6 ,

 

Segue um aperitivo, não consegui terminar mas está 98% prontinho ....

 

Esse programa usa um recurso muito pouco explorado no Bascom : as rotinas de CLOCK do usuário !

 

Na parte de hardware do Atmega8, tem de ligar o pino 15 ao pino 4 . ( ideia muito legal minha )

 

Temos 3 botões , cada um ligando um determinado pino ao GND :

pino 5 = cronometro

pino 12 = acerto de hora

pino 13 = acerto de minuto

 

Quando você aperta o botão do cronômetro, ele começa a contar os milésimos de segundo, até você apertar ele novamente, e então o tempo decorrido é enviado pela porta serial. Se apertar novamente esse botão, ele mede o tempo de novo, e assim sucessivamente.

Não fiz a parte de enviar a hora pela serial, eu ia fazer uma rotina para mandar a cada 10 segundos... e também não fiz a rotininha que atualiza o dia quando estoura as 24 horas ...  termino elas amanhã.

 

Detalhe, embora tenha essa resolução de 1 milisegundo, um botão gera tanto Bouncing que isso é inútil na vida real, A MENOS que se use um sinal totalmente filtrado e digitalizado, ou seja, precisa de mais um circuitinho para isso.

 

Boa diversão para vocês :

 

$regfile = "m8def.dat"
$crystal = 16000000
$hwstack = 80
$swstack = 80
$framesize = 80
$baud = 19200

Dim Second_tick As Long
Dim Tick As Long
Dim Mili As Long
Dim Elapsed As Long
Dim Flag_cron As Bit

Button_cron Alias Pind.3
Button_hr Alias Pind.6
Button_min Alias Pind.7
Config Button_cron = Input
Config Button_hr = Input
Config Button_min = Input
Set Portd.3
Set Portd.6
Set Portd.7

Config Clock = User
Config Date = Dmy , Separator = .                           'Day.Month.Year
Config Timer1 = Timer , Prescale = 8 , Compare A = Toggle , Clear Timer = 1
Stop Timer1
'Ocr1a = 64536
Ocr1a = 999
Config Int0 = Rising
On Int0 1miliseg

Config Int1 = Falling
On Int1 Start_cron

Tick = 0
Mili = 0

Date$ = "01.10.16"
Time$ = "00:00:00"
Enable Timer1
Start Timer1
Enable Int0
Enable Int1
Enable Interrupts



Do
  Debounce Button_min , 0 , Setminute , Sub
  Debounce Button_hr , 0 , Sethour , Sub
Loop
End

'=== Subs ===
Setminute:
 Disable Interrupts
 Incr _min
 If _min > 59 Then _min = 0
 Gosub Settime
 Print Time$
 Enable Interrupts
Return

Sethour:
Disable Interrupts
 Incr _hour
 If _hour > 23 Then _hour = 0
 Gosub Settime
 Print Time$
 Enable Interrupts
Return


1miliseg:                                                   'Int0 IRQ (once per second)
Incr Tick
Incr Mili
If Tick = 1000 Then
   Incr Second_tick
   Time$ = Time(second_tick)
   Tick = 0
End If
Return

Settime:
Second_tick = Secofday()
Return

Getdatetime:
Return

Setdate:
Return


Start_cron:
If Flag_cron = 0 Then
  Mili = 0
  Flag_cron = 1
Else
  Elapsed = Mili
  Enable Int0
  Print Elapsed
  Flag_cron = 0
End If
Return

 

 

TESTE.jpg

 

Segue o arquivo para simulação no Proteus8 com os arquivos HEX e OBJ e o fonte do Bascom. ( que roda na versão free do Bascom... )

 

relogio.zip

 

Paulo

Link para o comentário
Compartilhar em outros sites

@alexandre.mbm ,

 

Na verdade só serve para simular no Proteus, que é o que o @lucianolcoa pediu...

 

Para ser prático, precisa de um display LCD, o que pode ser facilmente adicionado no programa.

Mas como também precisa de um hardware adicional para tirar o bouncing, concorda que manter um cronômetro com resolução de milésimo de segundo que tem de ser acionado por um botão é meio coisa sem sentido ? Afinal só os ruídos de um botão demoram uns 30 milisegundos para pararem, então a menor medida de tempo possível tem de ser acima de uns 30 milisegundos.

 

Enfim, é só um projetinho que fiz agora para o pessoal aprender algumas novidades, como essa maneira que eu ando usando de fazer a saída de um timer acionar uma interrupção de hardware tipo INT0 ou INT1, pois desta maneira eu evito ter de recarregar o valor inicial do timer dentro da rotina de interrupção, o que sempre causa um pequeno erro que vai se acumulando e após umas horas estaremos com vários segundos de erro. Esse truque novo que venho fazendo evita isto, mantendo precisão total na temporização, com erro ZERO. Na verdade, o próprio Timer continua a contar normalmente até atingir o valor do Compare, sendo então zerado instantaneamente e fazendo a saída desse COMPARE inverter o estado, o que vai acabar gerando a interrupção INT0 quando houver uma subida. 

O truque é gerar na saída uma frequência duas vezes maior do que a que precisamos interromper.

 

Ah, e também o uso dessa rotina interna de relógio, que posso acionar com o comando CONFIG CLOCK = USER , que já cria todo o mecanismo interno de incremento de variáveis de segundo, minuto, hora, dia, mes e ano !  Se você comparar com o programa do @Intrudera6 , vai perceber que esse meu é bem mais simples.

 

Amanhã eu termino ele usando serial, e se precisar eu modifico ele para usar um LCD.

 

Paulo

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

 

Este meu programa foi o meu primeiro relógio, documentei ele tanto que ficou fácil de entender mesmo depois de uns 4 anos. Mas não acho que precisa o debouce, por sinal, com um contador após a primeira transição da para fazer reagir em microssegundos e inibir por 1 segundo (por exemplo),  isto já seria suficiente, mas qualquer coisa melhor que 1 décimo de segundo já é muito para o nosso reflexo.

 

O que eu gostava dos AVR é a documentação, eu sabia quase exatamente como as interrupções funcionavam, e isto facilita muito a programação. Eu gostei tanto deste meu primeiro que o aperfeicei colocando um DS3231, a precisão dele não era ruim, mas realmente piorava um pouco quando eu aumentava a quantidade de interrupções, ele está rodando até hoje num AVR.

 

A solução do Paulo é interessante, vou estudar ela, mas agora eu mergulhei fundo nos ESP8266 e é difícil competir com o recurso de conectividade (wifi) e velocidade dele, mas o Bascon é muito mais fácil de programar do que usando o Arduino IDE, o C ainda me dá muita dor de cabeça.

 

 

 

 

 

 

 

 

 

  • Curtir 1
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...