Ir ao conteúdo
  • Cadastre-se

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


Ir à solução Resolvido por aphawk,

Posts recomendados

  • 2 semanas depois...

@aphawk Opa, voltou em :D, show de bola... Ele até se move mas o software para controle ainda não está pronto, estou pensando na melhor forma de desenvolvê-lo, porém esse desenvolvimento será bem devagarzinho :) estou meio que em uma situação estranha hehe, capaz que eu tenha que postergar bastante esse projetinho :mellow:...

 

Depois posto o vídeo dele fazendo alguns movimentos!

 

Muito bom ver você de volta!!!

 

jynBQ7H.jpg

 

 

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

@Intrudera6 Estou querendo terminar ele logo, a interface será com o labVIEW tenho ele meio que na mente, comunicação, verificação de erro (CRC) :) ... mas vou ter que aguardar um pouco :( ...

 

@aphawk Show, mas Paulão, não seria melhor comprar uma cnc pronta? Tipo, já que é só placa de circuito impresso a CNC pode ser menos rígida, olha ai (você pode usar aquele tal de autoleveling que ai fica show):

 

 

 

Review:

 

Vendendo na gear best, mas você acho no Aliexpress e Ebay:

http://www./3d-printers--3d-printer-kits/pp_356128.html?lkid=10419417

 

Eu estou querendo uma para criar umas bugigangas em aluminio faí a CNC deve ser mais rígida e um monte de problema começa a aparecer HEHE...

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

@test man*~ ,

 

Pode até fazer isso.... mas o brinquedo vai custar aqui perto de US$ 300 * 1.6 = US$ 480 x 3,18 = mais de R$ 1500 reais, e se algo vier errado, vai dar um baita trabalhão prá consertar... além do que ainda vai ter de comprar a Eletrônica toda, repare que nem drivers vem nesse kit, vem apenas a parte mecânica !

 

Por cerca de R$ 1850,00 voce compra aqui mesmo um kit completo de uma Graber  I3 3D, com toda a Eletrônica e motores, e que pelo que eu estudei posso usar um adaptador para prender uma Dremel, e trocar o firmware normal por uma versão modificada que permite fazer as placas de PCB.

 

E isso é reversível, ou seja, basta tirar o adaptador e prender a cabeça extrusora original, trocar o firmware pelo original, e você volta a ter uma impressora 3D.

 

Eu comprei um kit desses, estou montando ela, e logo depois de estar tudo OK vou fazer as modificações e ver o que acontece...

 

Claro que para o seu caso, querer trabalhar com metais exige uma CNC pura... e essa que você postou o link NAO SERVE para trabalhar com metais, veja a observação ao final do anuncio !

 

Paulo

 

 

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

Um CNC era um "brinquedo" que eu gostaria de ganhar de presente do "Papai Noel", mas infelizmente custa o preço de um carro (mesmo um bem simples já custa um bom dinheiro). No meu passado distante, no meu tempo de estudante universitário, eu aprendi a programar um equipamento destes. Na década de 80 já existiam estas máquinas (até antes disso), e eu fazia miséria com um torno CNC da Romi. Ele era uma máquina com um motor de corrente contínua de 10 CV cuja rotação era variada através de  SCRs, era programado em fita perfurada e usava um processador 8086, que era um parente próximo dos processadores dos PCS atuais (na época não existiam os inversores, ou pelo menos não era uma coisa muito fácil de encontrar).

 

Mas para ter um equipamento destes é necessário ter uma boa oficina, e só um torno não é o suficiente, um fresa CNC também é interessante, e depois uma máquina de eletroerosão, e indo mais longe uma máquina de corte por jato de água. Quando eu ganhar na megasena sozinho eu compro uns "brinquedos" destes.

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

 

17 horas atrás, aphawk disse:

Claro que para o seu caso, querer trabalhar com metais exige uma CNC pura... e essa que você postou o link NAO SERVE para trabalhar com metais, veja a observação ao final do anuncio !

 

Sim @aphawk , a do link não serve... Mas se eu fosse usinar somente plásticos, MDF, e PCBs, eu acho que eu compraria uma desta, se eu quisesse comprar completa, mas acho que prefiro que ela não venha com os drivers motores e tal, dai você pode escolher um mais forte ou mais fraco de acordo com o que você quiser fazer...

 

A ideal para mim, no mundo perfeito, seria esta;

Com motores Nema 23 com 425oz.in;

Spindle AC 800W;

Inversor de frequência WEG ;

Sistema de refrigeração a água radiador, bomba;

Os drivers seriam TB6600, compraria um pronto e realizaria algumas modificações;

Controlador Arduino;

Para o  controle PID de velocidade do spindle, monitoramento de temperatura, etc. um PIC ou um AVR;

Também construiria um sistema para aspiração do pó

(a parte da montagem, quebrar cabeça e tal, é a parte que eu mais gosto =D)

 

Mas como o @Intrudera6  disse:

12 horas atrás, Intrudera6 disse:

[...] Quando eu ganhar na megasena sozinho SEM JOGAR (adicionado por mim) eu compro uns "brinquedos" destes.

 

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

@test man*~ ,

 

Concordo com você.... pena que esse negócio acaba  custando uma nota !!!

 

Mas se eu conseguir um bom resultado para PCBs por menos de R$ 2.500,00 , creio que vai viabilizar muita gente para montar !

 

Eu também adoraria um Spindle de 800 watts, mas me contento com uma Dremel para os PCbs kkkkkkk

 

Já tá duro ganhar dinheiro para ficar atualizando o Proteus, meu amigo, e como você também deixou claro, não adianta a Loteria pois também nunca joguei !!!!

 

Paulo

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

Ai está o vídeo do robô, mostrando alguns movimentos básicos e o sistema de feedback para ler a posição dos servos, que posteriormente será usado para que a pessoa possa ensinar o robô a se mover, facilitando a execução de movimentos mais complexos... Seria bom se fosse motor de passo daí daria para fazer movimentos mais suaves com aceleração, desaceleração e sem jitter...

 

Posta fotos do seu projeto CNC/3D Printer ai Paulão @aphawk...

 

 

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

Ficou realmente muito interessante, jeito e movimento de robô comercial. Como foi que você fez as conexões mecânicas? mandou cortar com laser ou foi de outra forma (jato de água por exemplo) ? Esta é realmente a parte mais complicada de montar um robô, bem mais até que o software (que dá muito trabalho mas é acessível), pois software não depende de equipamentos de alta precisão (e custo) para construir, só de esforço mental.

 

Achei a montagem muito limpa, coisa bastante profissional, PARABÉNS ! Fiquei com inveja.

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

@test man*~ ,

 

A impressora 3D deixei na casa de um amigo que está me ajudando na montagem, estou indo lá aos domingos para ir montando. 

 

Hoje quase terminamos, agora falta ajustar a corrente dos drivers para os meus motores, e montar a Ramps em cima do Arduino Mega e colocar toda a fiação.

 

Semana que vem postarei as fotos.

 

Paulo

 

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

Que legal que você gostou @Intrudera6 bacana...

 

O robô em si eu comprei pronto (por isso quero uma CNC, para construir minhas próprias bugigangas), acabei fazendo uns furos onde não havia para aumentar a rigidez, uma vantagem é que ele vem todo desmontado e assim passa pela fiscalização sem taxa alguma...


A parte traseira do robô (onde se encontra a placa) é uma extensão em acrílico essa sim foi cortada sob medida mas ficou baratinho uns 10 reais se não me engano. Agora a parte que deu mais trabalho foi a da garra com a ventosinha, o vendedor mandou com o tamanho errado (ela não faz parte do robô) dai tive que pedir meu pai para cortar tirando o excesso e então soldar mantendo a rosca =D... 

 

Outra coisa que o vendedor (esse já é outro vendedor) me ferrou foi dizer que os servos são fail safe off quando recebi vi que eles não eram HAHAHAHA dai tive que adaptar uma gambiarra para que os servos aceitem que eu os mova quando energizados... O outro vendedor (do servo pequeno em alumínio) disse que não era fail safe on e quando fui testar ele é fail safe off UahuAHuHAuH...

 

A montagem é a parte mais bacana =D
Quando você falou em montagem limpa, é meio off topic, lembrei de algo... Olha o que esse cara contruiu do zero (ele criou tudo, parafusos, engrenagens, pendulo, mesa, tudinho todas as peças foram criadas do zero):

 


 

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

@test man*~

Mesmo você não tendo usinado o robô ainda é um grande trabalho.

 

Você não imagina como é complexo o projeto de um relógio daqueles (do vídeo no youtube), mesmo tendo todo o projeto pronto ainda é algo que exige muitas horas de trabalho e algumas máquinas bastante precisas, para usinar as engrenagens por exemplo (que é o mais complexo e não foi mostrado). Eu já trabalhei em industria mecânica e sei que não é uma coisa simples (muito pelo contrário). E ainda tem o problema que após ficar pronto (depois me muitas horas de trabalho) a última coisa que você vai querer é que as peças de latão (imagino que seja feito de latão) fiquem azuis, o que vai ser bem difícil com este nosso clima (o de Salvador é devastador), só se você encapsular e injetar nitrogênio, acho que eu iria pensar seriamente em fazer nisso, e isolar permanentemente da poeira, e ainda colocaria um bom e robusto vidro blindex duplo (para ser difícil de quebrar).

 

Mas o bom mesmo é um relógio com o mecanismo de pesos pois a corda dura muito mais tempo e o mecanismo é muito mais robusto (foi um relógio desses de corda por peso que foi usado no primeiro atentado contra Hitler como mecanismo de detonação). Um relógio de pesos pode durar muito séculos em ótimas condições.

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

18 horas atrás, Intrudera6 disse:

@test man*~

[...] Eu já trabalhei em industria mecânica [...]

Legal, usinar coisas deve ser bacana =D.

 

18 horas atrás, Intrudera6 disse:

[...] para usinar as engrenagens por exemplo (que é o mais complexo e não foi mostrado) [...]

Está em outro vídeo, o cara fez tipo uma série... É bem complexo mesmo, ele faz dente por dente...

 

18 horas atrás, Intrudera6 disse:

[...] peças de latão (imagino que seja feito de latão) fiquem azuis [...]

Ele faz elas ficarem azuis por querer mesmo... 

Link para o comentário
Compartilhar em outros sites

Aê agora a resolução fica boa... O ADS1115 é muito bom ele mesmo realiza a média internamente quanto menor é a taxa de amostragem por segundo, maior é a quantidade de amostras e menor é o ruído. As leituras dele são bem estáveis...

 

Código para a mini biblioteca para o ADS1115 e BASCOM:

 

Código principal:

'$sim
$regfile = "m328pdef.dat"
$crystal = 16000000

$hwstack = 40
$swstack = 22

$framesize = 43

'----------------------------- Configurando periféricos ------------------------------'
$lib "I2C_TWI.LBX"                                          ' Será usado I²C por hardware
Config Twi = 400000                                         ' 400KHz SCL (Fast I2C)
Config Scl = Portc.5                                        ' we need to provide the SCL pin name
Config Sda = Portc.4                                        ' we need to provide the SDA pin name

Config Com1 = 9600 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
Open "com1:" For Binary As #1                               ' Será usado USART 0 (Pinos TXD0 e RXD0)

'------------------------------ Declaração de variáveis ------------------------------'
Dim Leitura As Word , Leitura2 As Word

'---------------------------- Inicialização de variáveis -----------------------------'

'------------------------- Configuração da direção dos pinos -------------------------'
Config Pinb.5 = Output

'----------------------------------- Nomeando pinos ----------------------------------'
Led0 Alias Portb.5

'------------------------ Inicialização dos estados dos pinos ------------------------'
Led0 = 0                                                    ' Inicializa o pino do Led0 com 0

'----------------------------- Declaração de constantes ------------------------------'

'------------------------------------ Sub-rotinas ------------------------------------'
Config Submode = New
$include "ADS1115_Robot_Arm.bas"

'---------------------------------- Código Principal ----------------------------------'

Waitms 500                                                  ' Espera ADS's se estabilizarem

Print #1 , Chr(12) ; "Hello World"                          ' serial teste

Call Config_ads1115(addr_ads1115_vcc)                       ' Configura ADS1115 A (com pino addr conectado ao vcc)
Waitms 100

Call Config_ads1115(addr_ads1115_gnd)                       ' Configura ADS1115 B (com pino addr conectado ao gnd)
Waitms 100                                                  ' Single Shot mode | 4,096VRef | 128 amostras por segundo (+/- 8mS de tempo conversão)

Do
  Led0 = Not Led0
  Waitms 200

  Call Start_conversion_ads1115(addr_ads1115_vcc , An0)     ' Inicia conversão do canal 0 (single shot) do ADS1115 A
  Call Start_conversion_ads1115(addr_ads1115_gnd , An0)     ' Inicia conversão do canal 0 (single shot) do ADS1115 B
  Waitms 10                                                 ' Espera a conversão terminar, aproximadamente 8,1mS (no término o pino Rdy vai para High)

  Leitura = Read_ads1115(addr_ads1115_vcc)                  ' Lê a conversão ad realizada pelo ADS1115 A
  Leitura2 = Read_ads1115(addr_ads1115_gnd)                 ' Lê a conversão ad realizada pelo ADS1115 B
  Print Chr(12) ; "AN0-A: " ; Leitura
  Print "AN0-B: " ; Leitura2 ; Chr(10) ; Chr(13)


  Call Start_conversion_ads1115(addr_ads1115_vcc , An1)     ' Inicia conversão do canal 1 (single shot) do ADS1115 A
  Call Start_conversion_ads1115(addr_ads1115_gnd , An1)     ' Inicia conversão do canal 1 (single shot) do ADS1115 B
  Waitms 10                                                 ' Espera a conversão terminar, aproximadamente 8,1mS (no término o pino Rdy vai para High)

  Leitura = Read_ads1115(addr_ads1115_vcc)                  ' Lê a conversão ad realizada pelo ADS1115 A
  Leitura2 = Read_ads1115(addr_ads1115_gnd)                 ' Lê a conversão ad realizada pelo ADS1115 B
  Print "AN1-A: " ; Leitura
  Print "AN1-B: " ; Leitura2 ; Chr(10) ; Chr(13)


  Call Start_conversion_ads1115(addr_ads1115_vcc , An2)     ' Inicia conversão do canal 2 (single shot) do ADS1115 A
  Call Start_conversion_ads1115(addr_ads1115_gnd , An2)     ' Inicia conversão do canal 2 (single shot) do ADS1115 B
  Waitms 10                                                 ' Espera a conversão terminar, aproximadamente 8,1mS (no término o pino Rdy vai para High)

  Leitura = Read_ads1115(addr_ads1115_vcc)                  ' Lê a conversão ad realizada pelo ADS1115 A
  Leitura2 = Read_ads1115(addr_ads1115_gnd)                 ' Lê a conversão ad realizada pelo ADS1115 B
  Print "AN2-A: " ; Leitura
  Print "AN2-B: " ; Leitura2 ; Chr(10) ; Chr(13)


  Call Start_conversion_ads1115(addr_ads1115_vcc , An3)     ' Inicia conversão do canal 3 (single shot) do ADS1115 A
  Call Start_conversion_ads1115(addr_ads1115_gnd , An3)     ' Inicia conversão do canal 3 (single shot) do ADS1115 B
  Waitms 10                                                 ' Espera a conversão terminar, aproximadamente 8,1mS (no término o pino Rdy vai para High)

  Leitura = Read_ads1115(addr_ads1115_vcc)                  ' Lê a conversão ad realizada pelo ADS1115 A
  Leitura2 = Read_ads1115(addr_ads1115_gnd)                 ' Lê a conversão ad realizada pelo ADS1115 B
  Print "AN3-A: " ; Leitura
  Print "AN3-B: " ; Leitura2 ; Chr(10) ; Chr(13)

Loop
'-------------------------------------------------------------------------------------'
End

 

Mini biblioteca:

Const Addr_ads1115_gnd = &H90
Const Addr_ads1115_vcc = &H92

Const An0 = &H40
Const An1 = &H50
Const An2 = &H60
Const An3 = &H70

Const Conversion_register = &H00
Const Config_register = &H01
Const Lo_thresh_register = &H02
Const Hi_thresh_register = &H03

Const Config_register_high_shadow = &H83
Const Config_register_low_shadow = &H88

Sub Config_ads1115(byval Ads1115_write_add As Byte)
   I2cstart
   I2cwbyte Ads1115_write_add
   I2cwbyte Config_register
   I2cwbyte &H43                                            ' MUX = AN0 - GND | PGA = 4,096V | Single Shot Mode
   I2cwbyte &H88                                            ' 128 Samples/Seconds | Rdy pin active high | Rdy pin enabled
   I2cstop

   I2cstart
   I2cwbyte Ads1115_write_add
   I2cwbyte Hi_thresh_register
   I2cwbyte &H80                                            ' Seting the MSB on Hi_Thresh Register in order to enable ready function on the alert/rdy pin
   I2cwbyte &H00
   I2cstop

   I2cstart
   I2cwbyte Ads1115_write_add
   I2cwbyte Lo_thresh_register
   I2cwbyte &H00                                            ' Seting the MSB on Lo_Thresh Register in order to enable ready function on the alert/rdy pin
   I2cwbyte &H00
   I2cstop

End Sub

Sub Start_conversion_ads1115(byval Ads1115_write_add As Byte , Byval Analog_input As Byte)
   'Ads1115_read_add = Ads1115_write_add + 1
   Analog_input = Analog_input Or Config_register_high_shadow

   I2cstart
   I2cwbyte Ads1115_write_add
   I2cwbyte Config_register
   I2cwbyte Analog_input                                    ' send the config reg. high with desired mux
   I2cwbyte Config_register_low_shadow                      ' send the low config reg.
   I2cstop

End Sub

Function Read_ads1115(byval Ads1115_write_add As Byte) As Word
   Local Ads1115_read_add As Byte , Leitura_high_byte As Word , Leitura_low_byte As Byte

   Ads1115_read_add = Ads1115_write_add + 1

   I2cstart
   I2cwbyte Ads1115_write_add
   I2cwbyte Conversion_register                             ' point to the conversion register
   I2cstop

   I2cstart
   I2cwbyte Ads1115_read_add                                ' then read it
   I2crbyte Leitura_high_byte , Ack
   I2crbyte Leitura_low_byte , Ack
   I2cstop

   Swap Leitura_high_byte
   Leitura_high_byte = Leitura_high_byte Or Leitura_low_byte
   Read_ads1115 = Leitura_high_byte

End Function

 

Iniciando conversão dos dois ADS1115 para ganhar tempo:

0688Rme.png

 

Lendo valores convertidos:

R5IOYMS.png

 

6c1DWW9.png

 

 

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

  • 2 semanas depois...

Ai pessoal, mais uma mini biblioteca, esta é para o calculo do Cyclic Redundancy Check de 8 bits (CRC 8) para conferir se houve algum erro durante a transmissão dos dados entre o PC e o Robô (ou qualquer outro dispositivo).

 

O calculo é feito usando um Look up Table (LUT) assim as respostas ficam pré-calculadas o que o torna mais rápido, muito mais rápido... Sem usar a LUT o AVR estava gastando 200 ~ 300mS para algumas strings agora fica na casa dos 10mS ~ 20mS.

 

Código desenvolvido totalmente baseado nesta fonte.

Link para realizar simulações.

 

Exemplo para a string "Forum Clube do Hardware!!!":

Download do Código.

 

KOWABNp.png

 

syZNHfr.png

 

 

Link para o comentário
Compartilhar em outros sites

  • mês depois...

Mais um update, está quase pronto, falta apenas implementar os botões "goto" e "limpar tabela" e a interface estará pronta.

 

Do lado do AVR falta tirar os delay "waitms 10" mas estou com dificuldade... Minha ideia seria:

> Ler a conversão ad anterior; 

> Startar a nova conversão;

> contar 10ms com o timer;

> ler a conversão ad anterior;

> Startar a nova conversão;

> e assim por diante...

 

Mas há algum problema pois ao fazer isso a comunicação (serial) apresenta muitos erros (CRC errado) e com 5 tentativas o supervisório se desconecta e vai para o modo idle (programei para fazer isso)... 

 

iZMICrj.png

 

Não faz muito sentido postar o código, mas ai está (O /spoiler não está funcionando):

'------------------------------------------ Modelo do AVR e velocidade de clock ------------------------------------------'
$regfile = "m2560def.dat"                                   ' ATmega2560
$crystal = 16000000
$hwstack = 50
$swstack = 50
$framesize = 180
'$baud = 38400
Config Submode = New

$hwcheck                                                    'hw stack check on
$framecheck
$softcheck
$lib "stackcheck.lib"

'------------------------------------------- Configuração de periféricos -------------------------------------------------'
Config Com2 = 57600 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0
Config Com3 = 115200 , Synchrone = 0 , Parity = None , Stopbits = 1 , Databits = 8 , Clockpol = 0

Open "com2:" For Binary As #2                               ' AVR <-> LABView
Open "com3:" For Binary As #3                               ' AVR <-> SSC-32U

' Serialin1 = Com2 = Computador
' Serialin2 = Com3 = SSC-32U
Config Serialout1 = Buffered , Size = 71                    ' Bufer usado para TX 70 bytes
Config Serialin1 = Buffered , Size = 10 , Bytematch = All   ' Buffer de entrada RX 3 bytes, todos caracteres geram interrupção "Serial1bytereceived"

Config Serialout2 = Buffered , Size = 60                    ' Bufer usado para TX 70 bytes
Enable Interrupts                                           ' habilita interrupções para recebimento dos dados


$lib "I2C_TWI.LBX"                                          ' I²C por hardware
Config Twi = 400000                                         ' 400KHz SCL (Fast I2C)
Config Scl = Portd.0                                        ' we need to provide the SCL pin name
Config Sda = Portd.1                                        ' we need to provide the SDA pin name

Config Timer1 = Timer , Prescale = 256                      ' Timer1 16Bits
On Timer1 Tmr1_isr Saveall                                  ' 16MHz / 256(Prescale) = 62,5KHz
Const Timer1_preload = 64911                                ' 1 / 62,5KHz = 16uS
Timer1 = Timer1_preload                                     ' 10mS (Interrupção desejada) = 625
Enable Timer1                                               ' Sendo assim 2^16 - 625 = 64911 para preload                                    ' Obtem-se exatos 10mS

On Int5 Int5_isr Saveall                                    '(Nosave')                                ' Na interrupção de borda de subida vai para o label Int5_isr
Enable Int5                                                 ' habilita a interrupção
Config Int5 = Change                                        ' Configura para as duas bordas assim detecta quando o labview conecta e desconecta

Pcmsk0 = &B00100000                                         ' Ajusta a máscara para a interrupção acontecer para o pino PB5 (PCINT0 - PCINT0,1,2,3,4,5,6 e 7)
On Pcint0 Pcint5_isr_btn_panico Saveall                     ' As interrupções de PCINT0,1 e 2 ocorrem em ambas as bordas
Enable Pcint0                                               ' habilita a interrupção PCINT5

Pcmsk2 = &B00010000                                         ' interrupção para fazer com que o labview grave o movimento na tabela
On Pcint2 Pcint20_isr_btn_gravar Saveall
Enable Pcint2                                               ' Habilita o conjunto de interrupção PCINT23:16

'----------------------------------------------- Configuração da direção dos pinos ---------------------------------------'
Config Pinb.7 = Output                                      ' Led_indicador
Config Pinb.6 = Output                                      ' Pino do buzzer (1 = Ligada | 0 = Desligado)
Config Pinb.5 = Input                                       ' Botão para uso a ser definido (1 = Apertado | 0 = Não apertado)
Config Pinb.3 = Output                                      ' relé de alimentação VS2 SSC-32U (1 = Alimentar Servos | 0 = Cortar Alimentação)
Config Pinb.2 = Output                                      ' relé de alimentação VS1 SSC-32U (1 = Alimentar Servos | 0 = Cortar Alimentação)
Config Pina.0 = Output                                      ' Mini bomba para sucção/ventosa (1 = Liga | 0 = Desligar)
Config Pink.7 = Output                                      ' DSR saída handshake AVR -> LABVIEW
Config Pink.6 = Output                                      ' CTS Pacote recebido está em tratamento AVR -> LABView
Config Pine.5 = Input                                       ' DTR quando conectado o LABView mantém este pino em 0 (asserted)
Config Portf = Input                                        ' PORTF será usada como  entradas para triggers de movimento
Portf = &HFF                                                ' habilita os pull ups das entradas de trigger
Config Portk.5 = Input                                      ' Quando em modo manual o AVR envia para o labview o estado do botão não o da bomba
Config Portk.4 = Input                                      ' botão para gravar movimento na tabela quando o robo estiver em modo manual
Portk.5 = 1                                                 ' liga o pull-up
Portk.4 = 1                                                 ' Liga o pull up

'----------------------------------------------------- Nomeando pinos ----------------------------------------------------'
Led_indicador Alias Portb.7
Buzzer Alias Portb.6
Button Alias Pinb.5
Rele_vs2 Alias Portb.3
Rele_vs1 Alias Portb.2
Bomba_succao Alias Porta.0
Dsr Alias Portk.7
Cts Alias Portk.6
Bomba_succao_manual Alias Pink.5
Botao_gravar_movimento Alias Pink.4
Dtr Alias Pine.5
Trigger0 Alias Pinf.0
Trigger1 Alias Pinf.1
Trigger2 Alias Pinf.2
Trigger3 Alias Pinf.3
Trigger4 Alias Pinf.4
Trigger5 Alias Pinf.5
Trigger6 Alias Pinf.6
Trigger7 Alias Pinf.7

'------------------------------------------ Inicialização dos estados dos pinos ------------------------------------------'
Led_indicador = 0
Buzzer = 0
Rele_vs2 = 1
Rele_vs1 = 1
Bomba_succao = 0
Dsr = 0
Cts = 1

'------------------------------------------------ Declaração de variáveis ------------------------------------------------'
Dim Tabela_movimentos(3500) As Byte                         ' Tabela que contém os movimentos a serem executados pelo robô
Dim Aux_contatdor_tab_mov As Byte                           ' Usado no laço for
Dim Linha_mov_offset As Word                                ' Usada para dar o ofset na tabela de movimentos de acordo com a linha
Dim Aux_for_tab_mov As Word
Dim I_serial_out_ssc As Byte                                ' Usada no for da construção da string de saída para a SSC32
Dim J_serial_out_ssc As Byte                                ' Usada no for da construção da string de saída para a SSC32
Dim Offset_serial_out_ssc As Byte                           ' Usada no for da construção da string de saída para a SSC32
Dim For_serial_out_ssc_target As Byte                       ' Usada no for da construção da string de saída para a SSC32
Dim Aux_for_serial_out_ssc As Byte
Dim Movimento_a_executar As Byte                            ' Proximo movimento a ser executado
Dim Movimento_em_execucao As Byte
Dim Aux_2_for_serial_out_ccs As Word
Dim Aux_3_for_serial_out_ssc_offset As Word
Dim Flag_cts_cmd6_serial As Bit
Dim Flag_iniciar_contagem_prox_mov As Bit
Dim Qtde_movimentos As Byte
Dim Tempo_proximo_movimento As Word                         '  Tempo a ser esperado para o próximo movimento ser executado
Dim Tempo_passado_prox_movimento As Word
Dim Aux_calculo_tempo As Word
Dim Teste_tipo_movimento As Byte
Dim Trigger_esperado As Byte
Dim Flag_esperar_trigger As Bit
Dim Bb_succao_calc As Byte
Dim Movimento_enviar_labview As Byte
Dim Offset_movimento_env_labview As Word
Dim Aux_contador_ajuste_string As Byte
Dim Offset_plus_aux_ajuste_string As Word
Dim Flag_existe_tabela As Bit                               ' Flag que indica que já foi recebida uma tabela de moviemntos

Const Tamanho_serial_input_buffer = 70
Dim Flag_pacote_start_recebido As Bit                       ' Indica que o char "$" início de pacote foirecebido
Dim _crc8_lookup_table(256) As Byte                         ' Table that holds the pre calculated results
Dim Crc As Byte
Dim Crc_out As Byte
Dim Char_recebido As Byte                                   ' Char recebido, enviado pelo LABView
Dim Tamanho_pacote As Byte                                  ' quantidade de byte a serem recebidos
Dim Tamanho_pacote_aux As Byte                              ' Variavel usada para que o tamanho do pacote possa ser calculado
Dim Qtde_bytes_recebidos As Byte                            ' quantidade de bytes jpa recebida
Dim Serial_input_buffer As String * Tamanho_serial_input_buffer       ' String que contém último dados revebidos
Dim Serial_input_buffer_array(tamanho_serial_input_buffer + 1) As Byte At Serial_input_buffer Overlay       '
Dim Comando As Byte                                         ' Contem o ultimo comando recebido
Dim Flag_pacote_recebido As Bit                             ' Flag que que o pacote de dados da comunicação serial chegou

Dim I2c_error As Byte                                       ' variavel indicadora de erro na comunicação I2C
Dim Contador_100ms As Byte                                  ' Conta tempo para realização das leituras analógica
Dim Flag_realizar_leituras As Bit                           ' Flag que indica que novas leituras devêm ser realizadas
Dim Posicoes_servos_raw(7) As Word                          ' Leitura analogica das posições dos servos de 1 a 7
Dim Serial_output_string As String * 75                     ' String para envio de dados solicitados pelo LABView
Dim Serial_output_string_array(76) As Byte At Serial_output_string Overlay
Dim Aux_output_string As String * 6                         ' String usado para adequar a qtd de numeros para cada posição dos servos
Dim Aux_out_buffer As Byte                                  ' variável usada para contenar as leituras dos servos em uma string
Dim Serial_output_string_ssc As String * 75                 ' String para envio de dados pra a SSC32
Dim Serial_output_string_ssc_array(71) As Byte At Serial_output_string_ssc Overlay
'Dim Dados_enviados As Bit

Dim Flag_labview_conectado As Bit                           ' Variável usada para indicar se o labVIEW está conectado
Dim Flag_cts_tmr As Bit                                     ' variável usada para verifcicar se o CTS já estava unasserted antes do tmr1 estourar
Dim Flag_cts_int5 As Bit                                    ' variável usada para verifcicar se o CTS já estava unasserted antes da ext int5 acontecer

Dim I2c_error_stratconv As Byte                             ' Variavel que contém erros durante o comando de start da conversão  bit 0,1,2,3 = adsvcc an0,1,2,3 | bit 4,5,6,7 = adsgnd an0,1,2,3
Dim I2c_error_read As Byte                                  ' Variavel que contém erros durante o comando de leitura  bit 0,1,2,3 = adsvcc an0,1,2,3 | bit 4,5,6,7 = adsgnd an0,1,2,3
Dim I2c_error_config As Byte                                ' Variavel que contém erros durante a configuração dos ads's  bit 0 = adsvcc | bit 4 = adsgnd
Dim Qtde_tentativas_config As Byte                          ' Variavel que indica que a quantidade de tentativas de configuração dos ADS115

Dim Qtde_tentativas_adsvccstart_an0 As Byte                 ' Variáveis usadas para contar a quantidade de vezes consecutivas que houve erro na comunicação i2c com os ads na parte do START CONVERSION
Dim Qtde_tentativas_adsvccstart_an1 As Byte
Dim Qtde_tentativas_adsvccstart_an2 As Byte
Dim Qtde_tentativas_adsvccstart_an3 As Byte
Dim Qtde_tentativas_adsgndstart_an0 As Byte
Dim Qtde_tentativas_adsgndstart_an1 As Byte
Dim Qtde_tentativas_adsgndstart_an2 As Byte
Dim Qtde_tentativas_adsgndstart_an3 As Byte

Dim Qtde_tentativas_adsvccread_an0 As Byte                  ' Variáveis usadas para contar a quantidade de vezes consecutivas que houve erro na comunicação i2c com os ads na parte do READ
Dim Qtde_tentativas_adsvccread_an1 As Byte
Dim Qtde_tentativas_adsvccread_an2 As Byte
Dim Qtde_tentativas_adsvccread_an3 As Byte
Dim Qtde_tentativas_adsgndread_an0 As Byte
Dim Qtde_tentativas_adsgndread_an1 As Byte
Dim Qtde_tentativas_adsgndread_an2 As Byte
Dim Qtde_tentativas_adsgndread_an3 As Byte

Dim Flag_botao_panico As Bit                                ' Variável que indica que o botao do panico foi apertado, assim o AVR deve liberar o torque dos motores e parar qualquer comando
Dim Flag_avisar_botao_panico As Bit                         ' Indica que o labview deve ser avisado sobre o botao do panico
Dim Tempo_reles_desativados As Byte                         ' variavel que conta o tempo que os reles ficaram desativados após o aperto do botao do panico
Dim Flag_cts_pcint As Bit                                   ' bit que indica se o cts já estava asserted antes da interrupção pcin5 ocorrer
Dim Flag_cts_cmd3_serial As Bit                             ' bit que indica se o cts já estava asserted antes da interrupção pcin5 ocorrer
Dim Flag_cts_read_ads1115 As Bit

Dim Modo_operacao As Byte                                   ' 0 - Ensinar via computador | 1 - Ensinar manualmente | 2 - PLay
Dim Aux_byte_serial As Byte

Dim Estado_bb_succao_manual As Bit                          ' Salva o estadoccorreto da bb de sucção quando em modo manual (por  causa do pull up é invertido)
Dim Flag_btn_gravar_movimento As Bit                        ' O botão gravar foi apertado esse flag indica a necessidade de indicar o labview
Dim Tempo_buzzer_servo_fora_sucesso As Byte                 ' Variável que conta o tempo para os apitos do buzer de forma a indicar servo fora do range
Dim Flag_apitar_buz_servo_fora As Bit                       ' Variável recebida pelo labview, indica que servo está fora do range quando em modo manual
Dim Flag_apitar_buz_sucesso As Bit                          ' Indica que o buzzer deve ser apitado duas vezes para indicar sucesso no enfileirar movimento

'---------------------------------------------- Nomenado bits de variaveis -----------------------------------------------'
I2c_error_config_adsvcc Alias I2c_error_config.0
I2c_error_config_adsgnd Alias I2c_error_config.4

I2c_error_start_adsvccan0 Alias I2c_error_stratconv.0
I2c_error_start_adsvccan1 Alias I2c_error_stratconv.1
I2c_error_start_adsvccan2 Alias I2c_error_stratconv.2
I2c_error_start_adsvccan3 Alias I2c_error_stratconv.3

I2c_error_start_adsgndan0 Alias I2c_error_stratconv.4
I2c_error_start_adsgndan1 Alias I2c_error_stratconv.5
I2c_error_start_adsgndan2 Alias I2c_error_stratconv.6
I2c_error_start_adsgndan3 Alias I2c_error_stratconv.7

I2c_error_read_adsvccan0 Alias I2c_error_read.0
I2c_error_read_adsvccan1 Alias I2c_error_read.1
I2c_error_read_adsvccan2 Alias I2c_error_read.2
I2c_error_read_adsvccan3 Alias I2c_error_read.3

I2c_error_read_adsgndan0 Alias I2c_error_read.4
I2c_error_read_adsgndan1 Alias I2c_error_read.5
I2c_error_read_adsgndan2 Alias I2c_error_read.6
I2c_error_read_adsgndan3 Alias I2c_error_read.7

'---------------------------------------------- Inicialização de variáveis -----------------------------------------------'
Qtde_bytes_recebidos = 0
Tamanho_pacote = 70
Flag_pacote_recebido = 0

Contador_100ms = 0
Flag_realizar_leituras = 0

Qtde_tentativas_config = 0
I2c_error_stratconv = 0
I2c_error_read = 0
I2c_error_config = 0

Qtde_tentativas_adsvccstart_an0 = 0
Qtde_tentativas_adsvccstart_an1 = 0
Qtde_tentativas_adsvccstart_an2 = 0
Qtde_tentativas_adsvccstart_an3 = 0
Qtde_tentativas_adsgndstart_an0 = 0
Qtde_tentativas_adsgndstart_an1 = 0
Qtde_tentativas_adsgndstart_an2 = 0
Qtde_tentativas_adsgndstart_an3 = 0

Qtde_tentativas_adsvccread_an0 = 0
Qtde_tentativas_adsvccread_an1 = 0
Qtde_tentativas_adsvccread_an2 = 0
Qtde_tentativas_adsvccread_an3 = 0
Qtde_tentativas_adsgndread_an0 = 0
Qtde_tentativas_adsgndread_an1 = 0
Qtde_tentativas_adsgndread_an2 = 0
Qtde_tentativas_adsgndread_an3 = 0

Flag_botao_panico = 0
Flag_avisar_botao_panico = 0
Tempo_reles_desativados = 0
Modo_operacao = 1                                           ' modo manualmente

Flag_cts_tmr = 0
Flag_cts_int5 = 0
Flag_cts_pcint = 0
Flag_cts_cmd3_serial = 0
Flag_cts_read_ads1115 = 0
Flag_cts_cmd6_serial = 0
Flag_apitar_buz_servo_fora = 0
Flag_pacote_start_recebido = 0
Flag_iniciar_contagem_prox_mov = 0

Movimento_a_executar = 0
Movimento_em_execucao = 99
Flag_esperar_trigger = 0
Flag_existe_tabela = 0

'------------------------------------------------------ SUB ROTINAS ------------------------------------------------------'
$include "ADS1115_Robot_Arm.bas"
$include "CRC8_Robot_Arm.bas"

'----------------------------------------------- Declaração de constantes ------------------------------------------------'
Const Servo_1_channel = _an0_ads1115                        ' ADS1115 VCC
Const Servo_2_channel = _an1_ads1115                        ' ADS1115 VCC
Const Servo_3_channel = _an2_ads1115                        ' ADS1115 VCC
Const Servo_4_channel = _an3_ads1115                        ' ADS1115 VCC
Const Servo_5_channel = _an0_ads1115                        ' ADS1115 GND
Const Servo_6_channel = _an1_ads1115                        ' ADS1115 GND
Const Servo_garra_channel = _an2_ads1115                    ' ADS1115 GND

Const Asserted = 0                                          ' para sinais da comunicação serial
Const Unasserted = 1                                        ' para sinais da comunicação serial

Const Max_tentativas_i2c = 5                                ' máxima quantidade de tentativas até que o AVR informe ao labview que a comunicação i2c não esta Ok
Const Modo_computador = 0
Const Modo_manualmente = 1
Const Modo_play = 2
Const Modo_idle = 3
Const Modo_loop = 4

'--------------------------------------------------- Código principal ----------------------------------------------------'
Waitms 200

Select Case Dtr
   Case 1:                                                  ' LABView não está conectado (conexão não foi estabelecida)
   Config Int5 = Falling
   Flag_labview_conectado = 0

   Case 0:                                                  ' LABView já está conectado (conexão foi estabelecida)
   Config Int5 = Rising
   Flag_labview_conectado = 1
End Select

'Print #3 , "SSC32"
'Print #2 , "Computador"

Call _compute_lookuptable(&Hba)                             ' Calcula e armazena a lookup table
'Serial_input_buffer = "4106031493159217931538008114701180065700"
'Crc = _compute_crc8(serial_input_buffer)

Tentar_novamente_adsvcc:
Call _config_ads1115(_addr_ads1115_vcc , I2c_error)         ' Configura o ADS1115 VCC
If I2c_error = 1 Then                                       ' se ocorreu erro durante a configuração

   Incr Qtde_tentativas_config                              ' incrementa a variavel que conta a qtde de tentativas

   If Qtde_tentativas_config < 4 Then                       ' realiza a tentativa de configuração por 3 vezes
      Goto Tentar_novamente_adsvcc
   End If
                                                            ' Se mesmo após três tentativas a configuração nao ocorreu com sucesso
   I2c_error_config_adsvcc = 1                              ' Seta o bit 0 da variavel que armazena erros na hora da configuração do ADS
End If

Waitms 50

Qtde_tentativas_config = 0                                  ' zera a variavel para dar a mesma chance para o ADSGND
Tentar_novamente_adsgnd:
Call _config_ads1115(_addr_ads1115_gnd , I2c_error)         ' Configura o ADS1115 GND
If I2c_error = 1 Then                                       ' se ocorreu erro durante a configuração

   Incr Qtde_tentativas_config                              ' incrementa a variavel que conta a qtde de tentativas

   If Qtde_tentativas_config < 4 Then                       ' realiza a tentativa de configuração por 3 vezes
      Goto Tentar_novamente_adsgnd
   End If
                                                            ' Se mesmo após três tentativas a configuração nao ocorreu com sucesso
   I2c_error_config_adsgnd = 1                              ' Seta o bit 0 da variavel que armazena erros na hora da configuração do ADS
End If

Waitms 50

'Buzzer = 1                                                  ' Testa o buzzer
'Waitms 500
'Buzzer = 0

Cts = Asserted                                              ' Libera a recepção de dados (LABView pode começar a se comunicar)
Clear Serialout1
Clear Serialin1

Do

   If Flag_realizar_leituras = 1 Then
      Flag_realizar_leituras = 0

      Disable Interrupts                                    ' desabilita as interrupções para garantir que o flag será setado
      Cts = Unasserted                                      ' desabilita o envio dados por pate do labview
      Flag_cts_read_ads1115 = Unasserted                    ' seta o flag para indicar para as outras funções que esta requer CTS unasserted e assim não é para dar assrted nele
      Enable Interrupts                                     ' reativa as interrupções

      Call _start_conversion_ads1115(_addr_ads1115_vcc , Servo_1_channel , I2c_error)
      If I2c_error = 1 Then
         Incr Qtde_tentativas_adsvccstart_an0
         If Qtde_tentativas_adsvccstart_an0 > Max_tentativas_i2c Then       ' são feitas "Max_tentativas_i2c" até  o flag de erro ser setado
            Qtde_tentativas_adsvccstart_an0 = 0
            I2c_error_start_adsvccan0 = 1                   ' Seta o bit referente a erro no start da conversão
         End If
      Else
         Qtde_tentativas_adsvccstart_an0 = 0
      End If

      Call _start_conversion_ads1115(_addr_ads1115_gnd , Servo_5_channel , I2c_error)
      If I2c_error = 1 Then
         Incr Qtde_tentativas_adsgndstart_an0
         If Qtde_tentativas_adsgndstart_an0 > Max_tentativas_i2c Then
            Qtde_tentativas_adsgndstart_an0 = 0
            I2c_error_start_adsgndan0 = 1
         End If
      Else
         Qtde_tentativas_adsgndstart_an0 = 0
      End If

      Waitms 10
      Posicoes_servos_raw(1) = _read_ads1115(_addr_ads1115_vcc , I2c_error)
      If I2c_error = 1 Then
         Incr Qtde_tentativas_adsvccread_an0
         If Qtde_tentativas_adsvccread_an0 > Max_tentativas_i2c Then       ' são feitas "Max_tentativas_i2c" até  o flag de erro ser setado
            Qtde_tentativas_adsvccread_an0 = 0
            I2c_error_read_adsvccan0 = 1                    ' Seta o bit referente a erro na leitura da conversão canal 1 ads1115 com pino adr conectado ao vcc
         End If
      Else
         Qtde_tentativas_adsvccread_an0 = 0
      End If

      Posicoes_servos_raw(5) = _read_ads1115(_addr_ads1115_gnd , I2c_error)
      If I2c_error = 1 Then
         Incr Qtde_tentativas_adsgndread_an0
         If Qtde_tentativas_adsgndread_an0 > Max_tentativas_i2c Then
            Qtde_tentativas_adsgndread_an0 = 0
            I2c_error_read_adsgndan0 = 1
         End If
      Else
         Qtde_tentativas_adsgndread_an0 = 0
      End If

      '----'

      Call _start_conversion_ads1115(_addr_ads1115_vcc , Servo_2_channel , I2c_error)
      If I2c_error = 1 Then
         Incr Qtde_tentativas_adsvccstart_an1
         If Qtde_tentativas_adsvccstart_an1 > Max_tentativas_i2c Then
            Qtde_tentativas_adsvccstart_an1 = 0
            I2c_error_start_adsvccan1 = 1
         End If
      Else
         Qtde_tentativas_adsvccstart_an1 = 0
      End If

      Call _start_conversion_ads1115(_addr_ads1115_gnd , Servo_6_channel , I2c_error)
      If I2c_error = 1 Then
         Incr Qtde_tentativas_adsgndstart_an1
         If Qtde_tentativas_adsgndstart_an1 > Max_tentativas_i2c Then
            Qtde_tentativas_adsgndstart_an1 = 0
            I2c_error_start_adsgndan1 = 1
         End If
      Else
         Qtde_tentativas_adsgndstart_an1 = 0
      End If

      Waitms 10

      Posicoes_servos_raw(2) = _read_ads1115(_addr_ads1115_vcc , I2c_error)
      If I2c_error = 1 Then
         Incr Qtde_tentativas_adsvccread_an1
         If Qtde_tentativas_adsvccread_an1 > Max_tentativas_i2c Then
            Qtde_tentativas_adsvccread_an1 = 0
            I2c_error_read_adsvccan1 = 1
         End If
      Else
         Qtde_tentativas_adsvccread_an1 = 0
      End If

      Posicoes_servos_raw(6) = _read_ads1115(_addr_ads1115_gnd , I2c_error)
      If I2c_error = 1 Then
         Incr Qtde_tentativas_adsgndread_an1
         If Qtde_tentativas_adsgndread_an1 > Max_tentativas_i2c Then
            Qtde_tentativas_adsgndread_an1 = 0
            I2c_error_read_adsgndan1 = 1
         End If
      Else
         Qtde_tentativas_adsgndread_an1 = 0
      End If

      '----'

      Call _start_conversion_ads1115(_addr_ads1115_vcc , Servo_3_channel , I2c_error)
      If I2c_error = 1 Then
         Incr Qtde_tentativas_adsvccstart_an2
         If Qtde_tentativas_adsvccstart_an2 > Max_tentativas_i2c Then
            Qtde_tentativas_adsvccstart_an2 = 0
            I2c_error_start_adsvccan2 = 1
         End If
      Else
         Qtde_tentativas_adsvccstart_an2 = 0
      End If

      Call _start_conversion_ads1115(_addr_ads1115_gnd , Servo_garra_channel , I2c_error)
      If I2c_error = 1 Then
         Incr Qtde_tentativas_adsgndstart_an2
         If Qtde_tentativas_adsgndstart_an2 > Max_tentativas_i2c Then
            Qtde_tentativas_adsgndstart_an2 = 0
            I2c_error_start_adsgndan2 = 1
         End If
      Else
         Qtde_tentativas_adsgndstart_an2 = 0
      End If

      Waitms 10

      Posicoes_servos_raw(3) = _read_ads1115(_addr_ads1115_vcc , I2c_error)
      If I2c_error = 1 Then
         Incr Qtde_tentativas_adsvccread_an2
         If Qtde_tentativas_adsvccread_an2 > Max_tentativas_i2c Then
            Qtde_tentativas_adsvccread_an2 = 0
            I2c_error_read_adsvccan2 = 1
         End If
      Else
         Qtde_tentativas_adsvccread_an2 = 0
      End If

      Posicoes_servos_raw(7) = _read_ads1115(_addr_ads1115_gnd , I2c_error)
      If I2c_error = 1 Then
         Incr Qtde_tentativas_adsgndread_an2
         If Qtde_tentativas_adsgndread_an2 > Max_tentativas_i2c Then
            Qtde_tentativas_adsgndread_an2 = 0
            I2c_error_read_adsgndan2 = 1
         End If
      Else
         Qtde_tentativas_adsgndread_an2 = 0
      End If

      '----'

      Call _start_conversion_ads1115(_addr_ads1115_vcc , Servo_4_channel , I2c_error)
      If I2c_error = 1 Then
         Incr Qtde_tentativas_adsvccstart_an3
         If Qtde_tentativas_adsvccstart_an3 > Max_tentativas_i2c Then
            Qtde_tentativas_adsvccstart_an3 = 0
            I2c_error_start_adsvccan3 = 1
         End If
      Else
         Qtde_tentativas_adsvccstart_an3 = 0
      End If

      Waitms 10

      Posicoes_servos_raw(4) = _read_ads1115(_addr_ads1115_vcc , I2c_error)
      If I2c_error = 1 Then
         Incr Qtde_tentativas_adsvccread_an3
         If Qtde_tentativas_adsvccread_an3 > Max_tentativas_i2c Then
            Qtde_tentativas_adsvccread_an3 = 0
            I2c_error_read_adsvccan3 = 1
         End If
      Else
         Qtde_tentativas_adsvccread_an3 = 0
      End If

      Flag_cts_read_ads1115 = Asserted                      ' Limpa o flag informando que está função libera o recebimento de dados
      If Flag_cts_tmr = 0 And Flag_cts_int5 = 0 And Flag_cts_pcint = 0 And Flag_cts_cmd3_serial = 0 And Flag_cts_read_ads1115 = 0 And Flag_cts_cmd6_serial = 0 Then       ' se todas as outras funções concordam em assert a linha
         Cts = Asserted                                     ' então cts é asserted
      End If

   End If

   If Modo_operacao = Modo_play Or Modo_operacao = Modo_loop Then       ' se o botão play ou loop foi apertado
      If Movimento_em_execucao <> Movimento_a_executar And Flag_iniciar_contagem_prox_mov = 0 Then
      'If Flag_iniciar_contagem_prox_mov = 0 Then
         Serial_output_string_ssc = ""
         Aux_2_for_serial_out_ccs = Movimento_a_executar * 34

         Teste_tipo_movimento = Tabela_movimentos(aux_2_for_serial_out_ccs + 1)


         If Teste_tipo_movimento = "D" Then                 ' Delay
         Tempo_proximo_movimento = 0
         Aux_calculo_tempo = Tabela_movimentos(2 + Aux_2_for_serial_out_ccs) - 48       ' calcula o tempo para espera da execução do próximo comando
         Aux_calculo_tempo = Aux_calculo_tempo * 1000

         Tempo_proximo_movimento = Tempo_proximo_movimento + Aux_calculo_tempo
         Aux_calculo_tempo = Tabela_movimentos(3 + Aux_2_for_serial_out_ccs) - 48
         Aux_calculo_tempo = Aux_calculo_tempo * 100

         Tempo_proximo_movimento = Tempo_proximo_movimento + Aux_calculo_tempo
         Aux_calculo_tempo = Tabela_movimentos(4 + Aux_2_for_serial_out_ccs) - 48
         Aux_calculo_tempo = Aux_calculo_tempo * 10

         Tempo_proximo_movimento = Tempo_proximo_movimento + Aux_calculo_tempo
         Aux_calculo_tempo = Tabela_movimentos(5 + Aux_2_for_serial_out_ccs) - 48
         Tempo_proximo_movimento = Tempo_proximo_movimento + Aux_calculo_tempo

         Tempo_proximo_movimento = Tempo_proximo_movimento + 2       ' Mais 20ms para dar tempo da SSC32 receber os dados

         Movimento_em_execucao = Movimento_a_executar

         Flag_iniciar_contagem_prox_mov = 1

         Bb_succao_calc = Tabela_movimentos(34 + Aux_2_for_serial_out_ccs)
         Bomba_succao = Bb_succao_calc

         Elseif Teste_tipo_movimento = "T" Then             ' Trigger
         Trigger_esperado = Tabela_movimentos(2 + Aux_2_for_serial_out_ccs) - 48
         Movimento_em_execucao = Movimento_a_executar
         Flag_esperar_trigger = 1
         Bb_succao_calc = Tabela_movimentos(34 + Aux_2_for_serial_out_ccs)
         Bomba_succao = Bb_succao_calc

         Else

         Bb_succao_calc = Tabela_movimentos(34 + Aux_2_for_serial_out_ccs)
         Bomba_succao = Bb_succao_calc

         Tempo_proximo_movimento = 0
         Aux_calculo_tempo = Tabela_movimentos(29 + Aux_2_for_serial_out_ccs) - 48       ' calcula o tempo para espera da execução do próximo comando
         Aux_calculo_tempo = Aux_calculo_tempo * 1000
         Tempo_proximo_movimento = Tempo_proximo_movimento + Aux_calculo_tempo
         Aux_calculo_tempo = Tabela_movimentos(30 + Aux_2_for_serial_out_ccs) - 48
         Aux_calculo_tempo = Aux_calculo_tempo * 100
         Tempo_proximo_movimento = Tempo_proximo_movimento + Aux_calculo_tempo
         Aux_calculo_tempo = Tabela_movimentos(31 + Aux_2_for_serial_out_ccs) - 48
         Aux_calculo_tempo = Aux_calculo_tempo * 10
         Tempo_proximo_movimento = Tempo_proximo_movimento + Aux_calculo_tempo
         Aux_calculo_tempo = Tabela_movimentos(32 + Aux_2_for_serial_out_ccs) - 48
         Tempo_proximo_movimento = Tempo_proximo_movimento + Aux_calculo_tempo
         Tempo_proximo_movimento = Tempo_proximo_movimento + 2       ' Mais 20ms para dar tempo da SSC32 receber os dados

         For I_serial_out_ssc = 1 To 8
            Select Case I_serial_out_ssc
            Case 1 :
            Serial_output_string_ssc = Serial_output_string_ssc + "#0P"
            Offset_serial_out_ssc = 3
            For_serial_out_ssc_target = 4
            'Aux_2_for_serial_out_ccs = Movimento_a_executar_convertido

            Case 2 :
            Serial_output_string_ssc = Serial_output_string_ssc + "#1P"
            Offset_serial_out_ssc = 10
            For_serial_out_ssc_target = 4
            Aux_2_for_serial_out_ccs = Aux_2_for_serial_out_ccs + 4

            Case 3 :
            Serial_output_string_ssc = Serial_output_string_ssc + "#16P"
            Offset_serial_out_ssc = 18
            For_serial_out_ssc_target = 4
            Aux_2_for_serial_out_ccs = Aux_2_for_serial_out_ccs + 4

            Case 4 :
            Serial_output_string_ssc = Serial_output_string_ssc + "#17P"
            Offset_serial_out_ssc = 26
            For_serial_out_ssc_target = 4
            Aux_2_for_serial_out_ccs = Aux_2_for_serial_out_ccs + 4

            Case 5 :
            Serial_output_string_ssc = Serial_output_string_ssc + "#18P"
            Offset_serial_out_ssc = 34
            For_serial_out_ssc_target = 4
            Aux_2_for_serial_out_ccs = Aux_2_for_serial_out_ccs + 4

            Case 6 :
            Serial_output_string_ssc = Serial_output_string_ssc + "#19P"
            Offset_serial_out_ssc = 42
            For_serial_out_ssc_target = 4
            Aux_2_for_serial_out_ccs = Aux_2_for_serial_out_ccs + 4

            Case 7 :
            Serial_output_string_ssc = Serial_output_string_ssc + "#2P"
            Offset_serial_out_ssc = 49
            For_serial_out_ssc_target = 4
            Aux_2_for_serial_out_ccs = Aux_2_for_serial_out_ccs + 4

            Case 8 :
            Serial_output_string_ssc = Serial_output_string_ssc + "T"
            Offset_serial_out_ssc = 54
            For_serial_out_ssc_target = 5
            Aux_2_for_serial_out_ccs = Aux_2_for_serial_out_ccs + 4

            End Select
            For J_serial_out_ssc = 1 To For_serial_out_ssc_target
               Aux_for_serial_out_ssc = J_serial_out_ssc + Offset_serial_out_ssc
               Aux_3_for_serial_out_ssc_offset = Aux_2_for_serial_out_ccs + J_serial_out_ssc
               Serial_output_string_ssc_array(aux_for_serial_out_ssc) = Tabela_movimentos(aux_3_for_serial_out_ssc_offset)
            Next

            If I_serial_out_ssc < 8 Then
               Serial_output_string_ssc_array(aux_for_serial_out_ssc + 1) = 0       ' coloca um null character
            End If

         Next

         Serial_output_string_ssc_array(aux_for_serial_out_ssc + 1) = 13       ' Adiciona um carriage return
         Serial_output_string_ssc_array(aux_for_serial_out_ssc + 2) = 0       ' Adiciona um NULL para finalizaar a string

         Print #3 , Serial_output_string_ssc;
         Movimento_em_execucao = Movimento_a_executar

         Flag_iniciar_contagem_prox_mov = 1
         'Print #3 , Tempo_proximo_movimento;
         End If
      End If
   End If

   If Flag_pacote_recebido = 1 Then                         ' Pacote enviado pelo LABView acabou de ser recebido e o CRC estava certo (Sem erro)
      Flag_pacote_recebido = 0                              ' Zera o flag indicador
      Serial_output_string = ""                             ' Limpa a string de saída

      Select Case Comando
         Case 1:                                            ' 01: LABView solicitando posição dos servos e estado da comunicação I2C

            For Aux_out_buffer = 1 To 7                     ' for para que a string seja ajustada com as posições 7 servor
               Serial_output_string = Serial_output_string + "#"       ' concatena o char separador #
               Aux_output_string = Str(posicoes_servos_raw(aux_out_buffer))       ' converte a posição raw para string
               Aux_output_string = Format(aux_output_string , "00000")       ' Adequa para sempre enviar 5 digitos
               Serial_output_string = Serial_output_string + Aux_output_string       ' concatena a posição raw do servo

               If Aux_out_buffer > 6 Then                   ' Se for o ultimo servo
                  Serial_output_string = Serial_output_string + "#"       ' adiciona o estado da ventosa/bomba de sucção

                  If Modo_operacao = Modo_manualmente Then
                     Estado_bb_succao_manual = Not Bomba_succao_manual       ' inverte por causa po pull-up
                     Serial_output_string = Serial_output_string + Str(estado_bb_succao_manual)
                  Else
                     Serial_output_string = Serial_output_string + Str(bomba_succao)
                  End If

                  Serial_output_string = Serial_output_string + "#"       ' adiciona o estado dos triggers
                  Aux_output_string = Str(pinf)             ' Converte o byte PORTBF para ser enviado os estados dos triggers
                  Aux_output_string = Format(aux_output_string , "000")       ' Formata para sempre ficar 3 dígitos
                  Serial_output_string = Serial_output_string + Aux_output_string

                  Serial_output_string = Serial_output_string + "#"       ' adiciona o estado do erro de configuração i2c
                  Aux_output_string = Str(i2c_error_config)
                  Aux_output_string = Format(aux_output_string , "000")
                  Serial_output_string = Serial_output_string + Aux_output_string

                  Serial_output_string = Serial_output_string + "#"       ' adiciona o estado do erro de start da conversao ad i2c
                  Aux_output_string = Str(i2c_error_stratconv)
                  Aux_output_string = Format(aux_output_string , "000")
                  Serial_output_string = Serial_output_string + Aux_output_string

                  Serial_output_string = Serial_output_string + "#"       ' adiciona o estado do erro de leitura da conversao ad i2c
                  Aux_output_string = Str(i2c_error_read)
                  Aux_output_string = Format(aux_output_string , "000")
                  Serial_output_string = Serial_output_string + Aux_output_string

                  Serial_output_string = Serial_output_string + "#"       ' adiciona o estado do btn do pânico
                  Aux_output_string = Str(flag_avisar_botao_panico)
                  Serial_output_string = Serial_output_string + Aux_output_string

                  Serial_output_string = Serial_output_string + "#"       ' Adiciona o estado do botao gravar
                  Aux_output_string = Str(flag_btn_gravar_movimento)
                  Serial_output_string = Serial_output_string + Aux_output_string

                  Serial_output_string = Serial_output_string + "#"       ' Adiciona o movimento atual em execução
                  Aux_output_string = Str(movimento_a_executar)
                  Aux_output_string = Format(aux_output_string , "00")
                  Serial_output_string = Serial_output_string + Aux_output_string

                  Serial_output_string = Serial_output_string + "#"       ' Adiciona o modo de operação atual
                  Aux_output_string = Str(modo_operacao)
                  'Aux_output_string = Format(aux_output_string , "00")
                  Serial_output_string = Serial_output_string + Aux_output_string

                  Disable Interrupts
                  Crc_out = _compute_crc8(serial_output_string)       ' calcula o CRC para a string de saida
                  Enable Interrupts

                  Aux_output_string = Chr(crc_out)
                  Serial_output_string = Serial_output_string + Aux_output_string       ' Adiciona o CRC a string
               End If
            Next
            I2c_error_stratconv = 0                         ' se houve algum erro na comunicação i2c zera os mesmos
            I2c_error_read = 0
            I2c_error_config = 0
            Flag_avisar_botao_panico = 0                    ' Zera o flag pois o labVIEW foi infrmado do botao do panico
            Flag_btn_gravar_movimento = 0                   ' Zera o flag pois o labview foi informado do botao gravar

         Print #2 , Serial_output_string ;                  ' Envia os dados solicitados pelo LABView
         If Crc_out = 0 Then
            Print #2 , Chr(crc_out) ;                       ' Se o CRC for zero usa um print para enviá-lo pois string é terminada em zero
         End If


      Case 2:                                               ' Labview mudando o modo de operacao
         Aux_byte_serial = Asc(serial_input_buffer , 5)
         Aux_byte_serial = Aux_byte_serial - 48             ' Converte de char para decimal
         Modo_operacao = Aux_byte_serial                    ' Atribui o novo modo de operação
         'Bomba_succao = 0                                      ' Labview já desliga no comando ir para posição

         If Modo_operacao = Modo_manualmente Then           ' Se foi mudado para o modo manual
            Rele_vs1 = 0                                    ' Desliga a alimentação dos servo motores
            Rele_vs2 = 0
            Bomba_succao = 0                                ' Desliga a bomba de sucção
            Flag_botao_panico = 1
            Tempo_reles_desativados = 0
            Print #3 , "#0P0#1P0#2P0#16P0#17P0#18P0#19P0" ; Chr(13) ;       ' envia comando para a SSC liberar o torque
         End If


      Case 3:                                               ' Labview enviado comando goto
         Aux_byte_serial = Asc(serial_input_buffer , 5)     ' pega o estado da ventosa

         If Aux_byte_serial = 48 Then                       ' se foi recebido 0
            Bomba_succao = 0                                ' Desliga a ventosa de acordo com o recebido
         Else                                               ' Caso contrário (recebido 1)
            Bomba_succao = 1                                ' Liga a bomba
         End If

         Aux_byte_serial = Len(serial_input_buffer)         ' quantidade total de bytes recebidos sem contar crc
         Aux_byte_serial = Aux_byte_serial - 5              ' retira o tamanho do pacote, comando e estado ventosa
         Serial_output_string_ssc = Right(serial_input_buffer , Aux_byte_serial)       ' pega os dados mais a direita da string que se referem ao comando para a SSC32U
         Serial_output_string_ssc = Serial_output_string_ssc + Chr(13)       ' Adiciona o CR (carrige return) para a SSC32U entender o final do comando
         Print #3 , Serial_output_string_ssc;               ' Envia o comando para CCS32U posicionar o robo

         Flag_cts_cmd3_serial = Asserted                    ' Clear o flag

         If Flag_cts_tmr = 0 And Flag_cts_int5 = 0 And Flag_cts_pcint = 0 And Flag_cts_cmd3_serial = 0 And Flag_cts_read_ads1115 = 0 And Flag_cts_cmd6_serial = 0 Then       ' Se se todos estiverem de acordo
            Cts = Asserted                                  ' Reativa recepção de dados do labview envitando receber pacotes incorretos
         End If


      Case 4:                                               ' Comando para começar a apitar ou parar de apitar
         Aux_byte_serial = Asc(serial_input_buffer , 5)     ' Pega qual a nova situação se é para apitar o buzzer ou não
         If Aux_byte_serial = 48 Then
            Flag_apitar_buz_servo_fora = 0
            Buzzer = 0                                      ' Desliga o buzzer pois se o comando foi dado bem na hora que o buzzer estava on ele continuará ON
         Else
            Flag_apitar_buz_servo_fora = 1
            'Buzzer = 1
         End If


      Case 5:                                               ' Comando do labview para apitar  servo indicando sucesso no enfileiramento do movimento
         Flag_apitar_buz_sucesso = 1
         Tempo_buzzer_servo_fora_sucesso = 0                ' zera a contadora para apitar duas vezes com 150mS cada


      Case 6:                                               ' Atualizar tabela
         Flag_existe_tabela = 1
         Serial_input_buffer_array(5) = Serial_input_buffer_array(5) - 48       ' Converte de ascii para decimal
         Serial_input_buffer_array(6) = Serial_input_buffer_array(6) - 48       ' Converte de ascii para decimal

         Linha_mov_offset = Serial_input_buffer_array(5) * 10       ' Pega a linha na qual o movimento será adicionado Dezena
         Linha_mov_offset = Linha_mov_offset + Serial_input_buffer_array(6)       ' Pega a linha na qual o movimento será adicionado Unidade
         Qtde_movimentos = Linha_mov_offset                 ' quantidade de movimentods que devem ser executados

         Aux_for_tab_mov = Linha_mov_offset * 34            ' calculando posicao do vetor linhas *34 + 1(já entra no for somando 1)
         'Incr Aux_for_tab_mov
         Linha_mov_offset = Aux_for_tab_mov

         For Aux_contatdor_tab_mov = 1 To 34                ' Atualizar a tabela de movimentos
            Aux_for_tab_mov = Linha_mov_offset + Aux_contatdor_tab_mov
            Tabela_movimentos(aux_for_tab_mov) = Serial_input_buffer_array(aux_contatdor_tab_mov + 6)       ' Já soma 1 do contador do laço for
         Next

         'If Qtde_movimentos = 3 Then
            'Modo_operacao = Modo_play
         'End If

         Flag_cts_cmd6_serial = Asserted                    ' Limpa o flag informando que está função libera o recebimento de dados
         If Flag_cts_tmr = 0 And Flag_cts_int5 = 0 And Flag_cts_pcint = 0 And Flag_cts_cmd3_serial = 0 And Flag_cts_read_ads1115 = 0 And Flag_cts_cmd6_serial = 0 Then       ' se todas as outras funções concordam em assert a linha
            Cts = Asserted                                  ' então cts é asserted
         End If


      Case 7:                                               ' Comando skip back
         Movimento_a_executar = 0
         Flag_iniciar_contagem_prox_mov = 0
         Tempo_passado_prox_movimento = 0
         Modo_operacao = Modo_computador
         Flag_esperar_trigger = 0

         If Modo_operacao = Modo_computador Then

         End If


      Case 8:                                               ' Labview solicita o envio de uma linha da tabela
         Serial_input_buffer_array(5) = Serial_input_buffer_array(5) - 48       ' Converte de ascii para decimal
         Serial_input_buffer_array(6) = Serial_input_buffer_array(6) - 48       ' Converte de ascii para decimal

         Movimento_enviar_labview = Serial_input_buffer_array(5) * 10       ' Linha/movimento a ser enviado para o labview
         Movimento_enviar_labview = Movimento_enviar_labview + Serial_input_buffer_array(6)

         Offset_movimento_env_labview = Movimento_enviar_labview * 34

         For Aux_contador_ajuste_string = 1 To 34
            Offset_plus_aux_ajuste_string = Aux_contador_ajuste_string + Offset_movimento_env_labview
            Serial_output_string_array(aux_contador_ajuste_string) = Tabela_movimentos(offset_plus_aux_ajuste_string)
         Next
         Serial_output_string_array(35) = 0                 ' Adiciona o NULL para formar a string

         Disable Interrupts
         Crc_out = _compute_crc8(serial_output_string)      ' calcula o CRC para a string de saida
         Enable Interrupts

         Aux_output_string = Chr(crc_out)
         Serial_output_string = Serial_output_string + Aux_output_string       ' Adiciona o CRC a string

         Print #2 , Serial_output_string ;                  ' Envia o movimento solicitado pelo labview
         If Crc_out = 0 Then
            Print #2 , Chr(crc_out) ;                       ' Se o CRC for zero usa um print para enviá-lo pois string é terminada em zero
         End If

         Flag_cts_cmd6_serial = Asserted                    ' Limpa o flag informando que está função libera o recebimento de dados
         If Flag_cts_tmr = 0 And Flag_cts_int5 = 0 And Flag_cts_pcint = 0 And Flag_cts_cmd3_serial = 0 And Flag_cts_read_ads1115 = 0 And Flag_cts_cmd6_serial = 0 Then       ' se todas as outras funções concordam em assert a linha
            Cts = Asserted                                  ' então cts é asserted
         End If


      Case 9:
         Aux_output_string = Str(flag_existe_tabela)
         Serial_output_string = Aux_output_string

         Aux_output_string = Str(qtde_movimentos)
         Aux_output_string = Format(aux_output_string , "00")
         Serial_output_string = Serial_output_string + Aux_output_string

         Disable Interrupts
         Crc_out = _compute_crc8(serial_output_string)      ' calcula o CRC para a string de saida
         Enable Interrupts

         Aux_output_string = Chr(crc_out)
         Serial_output_string = Serial_output_string + Aux_output_string       ' Adiciona o CRC a string

         Print #2 , Serial_output_string ;                  ' Envia o movimento solicitado pelo labview
         If Crc_out = 0 Then
            Print #2 , Chr(crc_out) ;                       ' Se o CRC for zero usa um print para enviá-lo pois string é terminada em zero
         End If


      Case 10:                                              ' Quando o labview roda ele pede o modo de operação para enable ou disables os botões
         Aux_output_string = Str(modo_operacao)
         Aux_output_string = Format(aux_output_string , "00")
         Serial_output_string = Aux_output_string

         Disable Interrupts
         Crc_out = _compute_crc8(serial_output_string)      ' calcula o CRC para a string de saida
         Enable Interrupts

         Aux_output_string = Chr(crc_out)
         Serial_output_string = Serial_output_string + Aux_output_string       ' Adiciona o CRC a string

         Print #2 , Serial_output_string ;                  ' Envia o movimento solicitado pelo labview
         If Crc_out = 0 Then
            Print #2 , Chr(crc_out) ;                       ' Se o CRC for zero usa um print para enviá-lo pois string é terminada em zero
         End If


      Case 11:                                              ' Respondendo quando o labview esta procurando a placa pelas portas seriais
         Serial_output_string = "Robot_ARM_$$4402"
         Print #2 , Serial_output_string ;


      Case 12:
         Aux_byte_serial = Asc(serial_input_buffer , 5)     ' pega o estado da ventosa

         If Aux_byte_serial = 48 Then                       ' se foi recebido 0
            Bomba_succao = 0                                ' Desliga a ventosa de acordo com o recebido
         Else                                               ' Caso contrário (recebido 1)
            Bomba_succao = 1                                ' Liga a bomba
         End If

         Aux_byte_serial = Len(serial_input_buffer)         ' quantidade total de bytes recebidos sem contar crc
         Aux_byte_serial = Aux_byte_serial - 5              ' retira o tamanho do pacote, comando e estado ventosa
         Serial_output_string_ssc = Right(serial_input_buffer , Aux_byte_serial)       ' pega os dados mais a direita da string que se referem ao comando para a SSC32U
         Serial_output_string_ssc = Serial_output_string_ssc + Chr(13)       ' Adiciona o CR (carrige return) para a SSC32U entender o final do comando
         Print #3 , Serial_output_string_ssc;               ' Envia o comando para CCS32U posicionar o robo

         Flag_cts_cmd3_serial = Asserted                    ' Clear o flag

         If Flag_cts_tmr = 0 And Flag_cts_int5 = 0 And Flag_cts_pcint = 0 And Flag_cts_cmd3_serial = 0 And Flag_cts_read_ads1115 = 0 And Flag_cts_cmd6_serial = 0 Then       ' Se se todos estiverem de acordo
            Cts = Asserted                                  ' Reativa recepção de dados do labview envitando receber pacotes incorretos
         End If


      End Select

         Serial_input_buffer = ""                           ' Limpa o buffer de entrada
   End If

Loop

'------------------------------------------------- Serial byte Recebido --------------------------------------------------'
 Serial1bytereceived:                                       ' byte recebido do LABView
   Char_recebido = Inkey(#2)
   Incr Qtde_bytes_recebidos                                ' Incrementa a variável com a atual quantidade de bytes recebidos
   Dsr = Unasserted                                         ' Desativa DSR se no final se o CRC estiver Ok o DSR é ativado
   Clear Serialin1                                          ' Ativa DSR se no final o CRC estiver Ok o DSR é desativa

   If Flag_pacote_start_recebido = 1 Or Char_recebido = "$" Then

      If Char_recebido <> "$" Or Qtde_bytes_recebidos = Tamanho_pacote Then       ' Verifica se é o início do pacote ou se é o CRC (ultimo char) pois o CRC pode ser o $
                                                                              ' Possível erro serial CRC = "$" e no ulyimo byte a transmissão do pacote ser reiniciada
         Serial_input_buffer = Serial_input_buffer + Chr(char_recebido)       ' Adiciona o char recebido a string p/ calcular CRC no fim do pacote

         Select Case Qtde_bytes_recebidos
            Case Is >= Tamanho_pacote :                     ' Se o pacote já terminou de ser recebido o ultimo dado é o CRC (Não entra no serial_input_buffer)
            Flag_pacote_start_recebido = 0                  ' Indica que o char "$" não foi recebido para o próximo pacote que virá
            Insertchar Serial_input_buffer , Tamanho_pacote , 0       ' remove o CRC da string adicionando um NULL (0b00000000) na sua posição

            Disable Interrupts
            Crc = _compute_crc8(serial_input_buffer)
            Enable Interrupts

            If Crc = Char_recebido Then                     ' Verifica o CRC se estiver correto
               Dsr = Asserted                               ' ativa a linha DSR para indicar pacote recebido sem erros - Handshake (Ack)
               Flag_pacote_recebido = 1                     ' Sinaliza que o pavote terminou de ser recebido
               If Comando = 3 Or Comando = 12 Then          ' Se foi o comando para atualizar posição  ou ir para/goto
                  Flag_cts_cmd3_serial = Unasserted         ' Seta o flag
                  Cts = Unasserted                          ' Desativa recepção de dados do labview envitando receber pacotes incorretos
               Elseif Comando = 6 Or Comando = 8 Then       ' Se o comando foi 6 ou 8
                  Flag_cts_cmd6_serial = Unasserted         ' seta o flag de cts para inibir o labview
                  Cts = Unasserted
               End If

            Else                                            ' Se houve erro
               Dsr = 1                                      ' mantém DSR desativado - No Hanshake (Nack)
               Qtde_bytes_recebidos = 0                     ' Zera qtde bytes recebidos
               Tamanho_pacote = 70                          ' e maximiza tamanho do pacote
               Serial_input_buffer = ""                     ' Limpa o buffer de entrada
            End If

            Case Is < 5 :                                   ' Os 4 primeiro byte represemtam o tamanho do pacote e comando
               Select Case Qtde_bytes_recebidos
                  Case 1 :                                  ' Primeiro e segundo bytes representam o tamanho do pacote
                  Tamanho_pacote_aux = Char_recebido - 48   ' Converte de ascii para decimal
                  Tamanho_pacote_aux = Tamanho_pacote_aux * 10       ' primeiro byte é a dezena por isso *10

                  Case 2 :
                  Char_recebido = Char_recebido - 48        ' Converte de ascii para decimal
                  Tamanho_pacote_aux = Tamanho_pacote_aux + Char_recebido       ' Segundo byte é a unidade
                  Tamanho_pacote = Tamanho_pacote_aux       ' Atribui o tamanho do novo pacote
                  If Tamanho_pacote > Tamanho_serial_input_buffer Then       ' Verifica se houve erro nos bytes do tamanho do pacote o que pode causar overflow na string
                     Tamanho_pacote = Tamanho_serial_input_buffer       ' e alterações de outras variáveis adjacentes à string
                  End If

                  Case 3 :                                  ' Terceiro e quarto bytes representam o comando do pacote
                  Comando = Char_recebido - 48              ' Converte de ascii para decimal
                  Comando = Comando * 10                    ' primeiro byte é a dezena por isso *10

                  Case 4 :
                  Char_recebido = Char_recebido - 48        ' Converte de ascii para decimal
                  Comando = Comando + Char_recebido         ' primeiro byte é a dezena por isso *10
            End Select
         End Select

      Else                                                  ' se for início do pacote
         Flag_pacote_start_recebido = 1                     ' Indica que o inicio de pacote foi recebido
         Qtde_bytes_recebidos = 0                           ' zera a variavel que indica quantidade de byte recebidos ("$" não entra na contagem)
         Serial_input_buffer = ""                           ' Limpa o buffer de entrada
      End If

   Else                                                     ' Se o start de pacote "$" não foi recebido e o char recebido não é o start
      Serial_input_buffer = ""                              ' Limpa o buffer de entrada evitando overfflow na string e alterações dos valores
      Qtde_bytes_recebidos = 0
   End If                                                   ' de variáveis adjacentes à mesma
Return

'---------------------------------------------------- Timer1 ISR 10mS ----------------------------------------------------'
Tmr1_isr:
   push r23

   Timer1 = Timer1_preload

   'Flag_cts_tmr = Cts                                       ' Pega o estado atual do CTS
   'Disable Interrupts
   Cts = Unasserted                                         ' Impede o recebimento de dados
   Flag_cts_tmr = Unasserted                                ' seta o flag indicando para outras funções o impedimento
   'Enable Interrupts                                        ' reabilita as interrupções

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

   Incr Contador_100ms                                      ' Incrementa a variável que conta 100mS
   If Contador_100ms > 9 Then                               ' Se já se passaram 100mS
      Toggle Led_indicador                                  ' Led indicaor pisaca para indicar funcionamento
      Contador_100ms = 0                                    ' Zera a variável
      Flag_realizar_leituras = 1                            ' e seta o flag para indicar que leituras dev~em ser realizadas
   End If

   If Flag_botao_panico = 1 Then                            ' Se o botao do panico foi apertado a função ensinar manualmente também usa essa rotina para desativar o torque dos servos                                         '
      Incr Tempo_reles_desativados                          ' Incrementa a variavel que conta tempo

      If Tempo_reles_desativados > 60 Then                  ' Dois apitos no buzer para indicar panico foi acionado
         Buzzer = 0
      Elseif Tempo_reles_desativados > 45 Then
         Buzzer = 1
      Elseif Tempo_reles_desativados > 30 Then
         Buzzer = 0
      Elseif Tempo_reles_desativados > 15 Then
         Buzzer = 1
      End If

      If Tempo_reles_desativados > 100 Then                 ' se ja se passaram 1000mS
         Rele_vs1 = 1                                       ' Religas os servos
         Rele_vs2 = 1
         Tempo_reles_desativados = 0                        ' Zera a variavel contador
         Flag_botao_panico = 0                              ' e zera o flag
      End If
   End If

   If Flag_apitar_buz_servo_fora = 1 Then                   ' O LABView é quem zera esse flag
      Incr Tempo_buzzer_servo_fora_sucesso

      If Tempo_buzzer_servo_fora_sucesso > 15 Then          ' 850ms buzzer desligado
         Buzzer = 0
      Else                                                  ' Tempo de 0 a 15 > 150ms buzzer ligado
         Buzzer = 1
      End If

      If Tempo_buzzer_servo_fora_sucesso > 100 Then
         Tempo_buzzer_servo_fora_sucesso = 0
      End If

   End If

   If Flag_apitar_buz_sucesso = 1 Then                      ' apitar buzzer indicando sucesso no enfileirameno do movimento
      Incr Tempo_buzzer_servo_fora_sucesso

      If Tempo_buzzer_servo_fora_sucesso > 60 Then
         Buzzer = 0
         Flag_apitar_buz_sucesso = 0                        ' se já apitou duas vezes limpa o flag para não apitar mais
      Elseif Tempo_buzzer_servo_fora_sucesso > 45 Then
         Buzzer = 1
      Elseif Tempo_buzzer_servo_fora_sucesso > 30 Then
         Buzzer = 0
      Elseif Tempo_buzzer_servo_fora_sucesso > 15 Then
         Buzzer = 1
      End If

   End If

   If Flag_iniciar_contagem_prox_mov = 1 Then               ' Verificação do tempo para execução do próximo movimento
      If Modo_operacao = Modo_loop Or Modo_operacao = Modo_play Then       ' Estava contando mais um mapós a mudança para modo computador
         Incr Tempo_passado_prox_movimento

         If Tempo_passado_prox_movimento > Tempo_proximo_movimento Then
            Tempo_passado_prox_movimento = 0
            Flag_iniciar_contagem_prox_mov = 0
            Flag_iniciar_contagem_prox_mov = 0

            nop
            Movimento_a_executar = Movimento_a_executar + 1 'Incr Movimento_a_executar
            nop

            If Movimento_a_executar > Qtde_movimentos Then  ' Se o movimento foi o último não executava novamente
               Movimento_a_executar = 0                     ' aponta para o movimento zero para quando o btn play for apertado novamente
               If Modo_operacao <> Modo_loop Then           ' Se o modo de operação for play
                  Modo_operacao = Modo_computador           ' Muda o modo de operação para computador para assim
               End If
            End If

         End If
      End If
   End If

   If Flag_esperar_trigger = 1 Then                         ' movimento atual é para esperar trigger
      If Modo_operacao = Modo_loop Or Modo_operacao = Modo_play Then
         If Pinf.trigger_esperado = 0 Then
            Flag_esperar_trigger = 0

            Incr Movimento_a_executar

            If Movimento_a_executar > Qtde_movimentos Then  ' Se o movimento foi o último não executava novamente
               Movimento_a_executar = 0                     ' aponta para o movimento zero para quando o btn play for apertado novamente
               If Modo_operacao <> Modo_loop Then           ' Se o modo de operação dor play
                  Modo_operacao = Modo_computador           ' Muda o modo de operação para computador para assim
               End If
            End If
         End If
      End If
   End If
   '-----------------------------------------------------------'

   Flag_cts_tmr = Asserted
   If Flag_cts_tmr = 0 And Flag_cts_int5 = 0 And Flag_cts_pcint = 0 And Flag_cts_cmd3_serial = 0 And Flag_cts_read_ads1115 = 0 And Flag_cts_cmd6_serial = 0 Then       ' se todas as funções concordarem
      Cts = Asserted                                        ' volta a linha para asserted
   End If

   pop r23
Return

'----------------------------------------- Interrupção externa 5 borda de subida -----------------------------------------'
Int5_isr:
   push r23

   'Flag_cts_int5 = Cts                                      ' Pega o estado atual do CTS
   'Disable Interrupts
   Cts = Unasserted                                         ' Inibi o envio de dados por parte do labview
   Flag_cts_int5 = Unasserted                               ' seta o flag indicando que está função inibiu o envio de dados
   'Enable Interrupts

   Select Case Dtr

      Case 1:                                               ' LABView não está conectado (conexão não foi estabelecida)
      Config Int5 = Falling
      Flag_labview_conectado = 0
      Serial_input_buffer = ""                              ' Zera o buffer de entrada
      Qtde_bytes_recebidos = 0                              ' Zera variável contador de bytes recebidos
      Tamanho_pacote = 70                                   ' maximiza tamanho pacote medidas tomadas visando diminuir a possibilidade de erro
      Flag_avisar_botao_panico = 0                          ' Se o labview se desconectou não avisa ele sobre o botao do panico
      Flag_apitar_buz_servo_fora = 0                        ' Se o LABView se desconeectou desliga o apito de servo fora do range
      Clear Serialout1
      Clear Serialin1

      Case 0:                                               ' LABView já está conectado (conexão foi estabelecida)
      Config Int5 = Rising
      Flag_labview_conectado = 1
      Serial_input_buffer = ""                              ' Zera o buffer de entrada
      Clear Serialout1
      Clear Serialin1

   End Select

   Flag_cts_int5 = Asserted

   If Flag_cts_tmr = 0 And Flag_cts_int5 = 0 And Flag_cts_pcint = 0 And Flag_cts_cmd3_serial = 0 And Flag_cts_read_ads1115 = 0 And Flag_cts_cmd6_serial = 0 Then       ' Se todas as funções que fazem uso do cts concordarem
      Cts = Asserted                                        ' volta a linha para asserted
   End If

   pop r23
Return

'------------------------------------------------- Botao do pânico apertado ----------------------------------------------'
Pcint5_isr_btn_panico:
   push r23

   'Flag_cts_pcint = Cts                                     ' Pega o estado atual do CTS
   'Disable Interrupts' não precisa desativar interrupções dentro de interrupções elas sao desativadas por hardware
   Cts = Unasserted
   Flag_cts_pcint = Unasserted
   'Enable Interrupts

   If Button = 1 Then                                       ' se o botão do pânico foi apertado
      If Modo_operacao <> Modo_manualmente Then             ' e se o modo de operação não é ensinar manualente
         Print #3 , "#0P0#1P0#2P0#16P0#17P0#18P0#19P0" ; Chr(13) ;       ' envia comando para a SSC liberar o torque
         Flag_botao_panico = 1                              ' Flag para contagem de tempo no timer

         If Flag_labview_conectado = 1 Then                 ' Se o labview estiver conectado
            Flag_avisar_botao_panico = 1                    ' Ativa o flag para indicar necessidade de avisar ele
         End If

         Rele_vs1 = 0                                       ' Desliga a alimentação dos servo motores
         Rele_vs2 = 0
         Bomba_succao = 0                                   ' Desliga a bomba de sucção

         Modo_operacao = Modo_manualmente                   ' Passa o modo de operação para manual
      End If
   End If

   Movimento_a_executar = 0

   Flag_cts_pcint = Asserted

   If Flag_cts_tmr = 0 And Flag_cts_int5 = 0 And Flag_cts_pcint = 0 And Flag_cts_cmd3_serial = 0 And Flag_cts_read_ads1115 = 0 And Flag_cts_cmd6_serial = 0 Then       ' Se o estado atual era asserted
      Cts = Asserted                                        ' volta a linha para asserted para que o timer1 não ative o CTS indevidamente
   End If

   pop r23
Return

'------------------------------------------------- Botao do gravar apertado ----------------------------------------------'
Pcint20_isr_btn_gravar:
   push r23

   If Botao_gravar_movimento = 0 And Modo_operacao = Modo_manualmente And Flag_btn_gravar_movimento = 0 And Flag_apitar_buz_sucesso = 0 Then       ' Somente aceita novo comando de gravar remoto se o buzzer terminou de apitar
      Flag_btn_gravar_movimento = 1
      'Tempo_buzzer_servo_fora_sucesso = 0
   End If

   pop r23
Return

End

 

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

@test man*~ ,

 

 Lí no meu Ipad , e não tive tempo de colocar esse programa para examinar no meu micro. Mas encontrei algumas coisas :

 

- Sua velocidade mínima de comunicação serial é de 57600, e imagine que a cada caractere recebido é gerada uma interrupção, a qual deve ser tratada obrigatóriamente ANTES de ser recebido um novo caractere, sob pena de se perder o primeiro deles. Então, temos uma interrupção ocorrendo a cada 17.3 microsegundos.

 

Sua base de tempo do Timer é gerada a cada 10 milisegundos, você está usando SAVEALL, o que significa que se perde cerca de 150 ciclos de clock para salvar, e mais 150 ciclos para repor, o que já consumiu 300 ciclos de clock, com um tempo de 18.75 microsegundos só para isto, que já é maior do que o tempo måximo de 17.3 microsegundos, sem executar nenhum código !!!!!!!

 

Ou seja, vai perder caractere, fazendo ocorrer os seus erros de CRC.

 

Sugestão : baixe a velocidade da comunicação serial para 1200 bauds, que já é suficiente para a sua necessidade.

 

- A mesma coisa ocorre com a sua comunicação I2C a 400 Khz ! Para quê tudo isso ???

 

Sugestão : use 10 Khz !

 

- Seu código DENTRO da interrupção do Timer é muito grande, e lembre-se de que você não habilitou as interrupções no início dela, então não vai ocorrer nenhuma interrupção enquanto não sair dessa interrupção do Timer !

 

Seria bem melhor se você apenas incrementasse as bases de tempo nela, e deixasse todo o resto do tratamento no loop principal, assim as outras interrupções poderão ocorrer normalmente.

 

- voce pode desativar e reativar as interrupções à vontade !  Eu faço muito isso quando tenho de atualizar variåveis que serão usadas em outras rotinas de interrupção, evitando que alguma situação seja mal interpretada.

 

Lembre-se de uma coisa básica : interrupções devem ser muito curtas !

 

Por fim, o ideal é salvar apenas os registradores que serão alterados dentro da interrupção, e para isto existe um programa comercial, custa se não me engano US$ 5, ele examina o seu código e já te otimiza as rotinas de interrupção, fazendo apenas os PUSH e POP necessários, o que faz ganhar bastante ciclos de clock.

 

Bom, por enquanto é isto...

 

Paulo

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

Putz Paulão @aphawk  você é o mestre mesmo... Eu fiquei sentado na frente do computador umas duas horas com lógica anylizer em uma tela o o código na outra tentando decifrar o que estava acontecendo.... Você o fez quase que instantaneamente...

 

Dentro do timer o AVR gera o sinal para o labview não enviar um novo byte CTS=0 isso não deveria evitar esse problema? Outra coisa, o FIFO buffer do AVR possui dois bytes, ou não?

 

Quero deixar o labview o mais atualizado possível, o AVR manda uma string com cerca de 70 caracteres a cada 100ms mais ou menos... Vou reajustar o labview e ver se consigo manter a alta taxa de atualização com a velocidade reduzida da serial...

 

Agora, se eu habilitar interrupções dentro da interrupção do timer o problema talvez pode ser resolvido, correto?

 

Estou em uma viagem, assim que voltar testo essas soluções.

 

Obs.: Uso as altas velocidades para levar o chip ao limite e tentar resolver os problemas que vão aparecendo, só pelo desafio mesmo... a i2c não está apresentando erros, por enquanto... Por isso estou entrando no mundo dos ARM vou começar com o M0 (STM32F072RB) e um dia chegar ao M7 (STM32H743ZI 400MHz hehe) 

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

@test man*~ ,

 

Que isso .... eu não faço nenhuma ideia de como funciona tudo isso, eu apenas procurei saber sobre as interrupções geradas pelo hardware, pois quase sempre é aí que mora o problema !

 

E eu já tive muitos problemas semelhantes, pois na minha época mais produtiva eu usava um hardware Z-80 que rodava a 1 Mhz apenas, e tinha de fazer fábricas inteiras funcionarem direito, supervisionadas por esse hardware bem menos potente.... era um tal de tirar coelho da cartola que dava gosto de ver !

 

Sobre o buffer da Fifo, sim, no Atmega2560  são dois caracteres, você tem razão. Ainda assim, eu aposto que o tempo necessário para  completar a interrupção do Timer ultrapassa o tempo de recepção de três caracteres....

 

Sobre o CTS, precisa ver se o protocolo do Labview está programado para trabalhar com RTS/CTS, senão será ignorado sim.... a grande maioria hoje usa apenas Tx/ Rx, em vez de usar todo o protocolo correto, com DSR/DTR e RTS/CTS ! Eu sou da época dos modems.... se não seguisse a Bíblia RS-232 , nada funcionava direito !

 

Sobre habilitar a interrupção novamente assim que entra na rotina, é a maneira mais fácil de resolver, mas você tem de entender tudo o que pode dar errado, ver se as outras interrupções não pode  complicar o tratamento interno. Lembre-se de que uma interrupção pode ocorrer durante uma escrita de um valor de dois bytes, sendo que apenas o primeiro foi escrito, e a outra rotina, caso dependa desse valor de dois bytes, vai ler essa variável e considerar um valor totalmente errado. É um problema bem comum com microcontroladores de 8 bits .....

 

Por último.... usar um micro bem mais potente para encobrir um programa que não foi totalmente projetado desde o início levando em conta os limites do hardware é uma solução que pode ser utilizada pelos amadores, mas não pelos profissionais, pois significa um aumento de custo que pode inviabilizar um produto no mercado !

 

Veja bem, você tem em suas mãos um hardware bem poderoso, e que pode fazer essa sua aplicação com um pé nas costas ! Basta dar uma re-pensada no seu sistema de interrupções e "bolar" o software para ser imune a isso !

 

A diferença entre um programador comum e um engenheiro programador é exatamente isso que está ocorrendo aqui !  Se você se acostumar com o funcionamento do hardware, fica fácil contornar por software os problemas de temporização. Já os programadores comuns vão dizer pros chefes deles "precisa usar uma CPU bem mais potente ! " !

 

Muitas vezes para resolver isso envolve usar alguns trechos de assembly, como no trecho em que você consulta um monte de flags seguidos para tomar uma decisão... aquela sequência de IFs .AND. pode ser substituida por uma soma de conteúdos sequenciais na memória, bastanto colocar os DIM em sequência, e usar um pequeno trecho com umas 20 instruções em Assembly que farão esse teste completo quase 50 vezes mais rápido ! O uso do Proteus é um excelente ajudante nesse aprendizado, pois você pode olhar na janela da CPU quantos ciclos de clock são gastos em cada linha de seu programa !

 

Esse tipo de insight vem com a experiência, a gente se ferra bastante antes de aprender o que poderia facilitar muito.... mas de qualquer maneira seu programa estå bem legal, e mostra que você evoluiu bastante no Bascom, meu amigo !

 

Tudo bem que você está tentando fazer tudo muito rápido por um desafio apenas, mas temos de ser práticos também, senão usava um Intel Core I7 rodando a 2.8 Ghz, com um compilador otimizado a 64 bits para ver tudo isso voar, não é ? :lol:  

 

Para mim, eu prefiro ver um cara tirando leite de pedra de um hardware baratinho, do que ver um hardware potente sendo usado para matar a formiginha com um tiro de canhão kakakakakakaka ! Pois é isso que diferencia as pessoas em sua capacidade !

 

Eu também estou viajando, mas volto no fim de semana e vou carregar no meu computador para fazer alguns testes, ok ?

 

Um abração !

 

Paulo

 

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