Ir ao conteúdo

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


Ir à solução Resolvido por aphawk,

Posts recomendados

  • 5 meses depois...
Postado

         ANALISADOR DE ESPECTRO REAL COM 10 BANDAS

 

Segue um projeto completo de um analisador de espectro de áudio de baixo custo com 10 bandas, usando os MSGEQ7, e que segue as frequências originais de utilização de um analisador de espectro clássico. Para uma visualização bem legal, utilizei dois módulos  de matriz de Leds com o ci MAX7219.

 

Estes módulos são bem baratos e voce encontra no Mercado Livre.

 

Essa maneira de usar vários MSGEQ7 com diferentes sintonias foi uma ideia que tive a partir do datasheet dele, e deu certo na bancada. Com isso, em vez de ficar preso às 7 originais , que não seguem o padrão para um analisador de espectro real, eu uso vários deles, e com isso consigo pegar as 10 frequências utilizadas na prática.

 

Como padrão em meu tutorial, o programa fonte está escrito em Basic do Bascom, e como microprocessador utilizei um Arduíno Uno.

A saída é visualizada em duas matrizes de LED 8x8 tipo catodo comum, colocadas uma ao lado da outra.
O Link para download de todo o projeto segue abaixo :

http://www.4shared.com/rar/AFjTGR8a/ANALISADOR_DE_ESPECTRO_SIMPLES.html

Boa diversão.

Paulo

post-464954-1388496631139_thumb.png

  • Curtir 2
  • 3 semanas depois...
Postado

aphawk,

Gostaria de parabeniza-lo e agradece-lo pelo excelente trabalho ao criar esse tutorial para programação de AVR's com o BASCOM.

Baixei e estou começando a programar um atmega8.

Com certeza seu trabalho é de muita ajuda para iniciantes em AVR.

Abraço

Postado

Fervolt,

Obrigado pelas suas palavras, e bem-vindo ao mundo dos AVR's !

Já ví uma questão sua em outro tópico sobre linguagem C, e sei que você pode começar pelo Basic para se familiarizar com os detalhes do hardware dos AVR.

Embora eu tenha escrito o tutorial baseado em um simples CI, é melhor voce utilizar um Arduíno Uno R3, assim você tem a vantagem de poder utilizar a porta serial para enviar dados entre o seu computador e o Arduíno.

Se tiver alguma dúvida é só postar, ok ?

Paulo

  • 2 semanas depois...
Postado
  aphawk disse:
Pessoal,

Comprei um sensor baratinho ( R$ 13,00 ) de umidade do ar e temperatura, que é o DHT-11, chegou ontem, e não tive tempo de incluir o projetinho no tutorial.

Só depois que ele chegou é que ví que embora ele seja do tipo 1-Wire, o protocolo é proprietário, isto é, não segue nenhum padrão !!! Tive de baixar o PDF dele e procurar mais dicas na NET para fazer isso funcionar.....

Só agora conseguí terminar o projetinho, ficou simples e funcional; vou postar aqui o projetinho completo com o programa para quem precisar.

O esquema eletrônico é exatamente o mesmo que eu usei no Tutorial para o Controle de Cooler com 1-Wire, a única diferença é a troca do sensor pelo DHT-11.

Eu encontrei esse programa práticamente pronto na Net, reproduzo aqui , modificando para o meu caso, e acrescentei os comentários para explicar o programa. O site que encontrei foi o AVRproject.ru .

Mais informações sobre o funcionamento do DHT-11 no link abaixo :

http://embedded-lab.com/blog/?p=4333


$regfile = "m48pdef.dat"
$crystal = 8000000


Config Lcd = 16 * 2
Config Lcdpin = Pin , Rs = Portc.0 , E = Portc.1 , Db4 = Portc.2 , Db5 = Portc.3 , Db6 = Portc.4 , Db7 = Portc.5
Cursor Off
Cls


Declare Sub Get_th(t As Byte , H As Byte)

'vamos ligar o sensor no pino B.0
Dht_put Alias Portb.0 ' aqui usamos como saída
Dht_get Alias Pinb.0 ' e aqui usamos como entrada !
Dht_io_set Alias Ddrb.0 ' aqui mudamos entrada < - > saída

Dim T As Byte 'Temperatura
Dim H As Byte 'Umidade
Dim Crc As Byte 'CRC do medidor
Dim Mybyte As Byte
Dim Sensor_data As String * 40 'buffer para os 5 bytes
Dim Tmp_str8 As String * 8 'string temporária para receber 8 bits
Dim Count As Byte 'contador para os bits recebidos

Enable Interrupts

Set Dht_io_set
Set Dht_put

Lcd "AVRproject.ru"
Lowerline
Lcd "DHT11 sensor"

Do
Waitms 1500
Call Get_th(t , H)
Cls
Lcd "TMP: " ; T ; "C"
Lowerline
Lcd "PHP: " ; H ; "%"

Loop

Sub Get_th(t As Byte , H As Byte)

Count = 0
Sensor_data = ""
Set Dht_io_set 'vira saída
Reset Dht_put 'nivel 0 na saída
Waitms 25 'tempo de espera pro dht11 25mseg

Set Dht_put 'volta nivel 1 na saída
Waitus 40 'espera 40 useg
Reset Dht_io_set 'vira entrada
Waitus 40 'espera mais 40 useg
If Dht_get = 1 Then 'se continua 1 tem algo errado
H = 1 'pois deveria estar em 0 !
Exit Sub
End If


Waitus 80 'espera 80 useg
If Dht_get = 0 Then 'agora tem de estar 1 !
H = 2 'se tiver 0 , deu erro
Exit Sub
End If


While Dht_get = 1 : Wend 'espera iniciar transmissão

Do
While Dht_get = 0 : Wend 'começou a transmissão
Waitus 30 'voltou a nivel 1, espera 30 useg
If Dht_get = 1 Then 'se apos 30 useg continua 1, então o bit é 1
Sensor_data = Sensor_data + "1" 'coloca 1 no buffer de dados
While Dht_get = 1 : Wend 'espera esse bit 1 terminar
Else 'se apos 30 useg virou 0, então o bit é 0
Sensor_data = Sensor_data + "0" 'coloca zero no buffer
End If
Incr Count ' incrementa contador de bits
Loop Until Count = 40 ' repete para 40 bits totais

Set Dht_io_set
Set Dht_put



Tmp_str8 = Left(sensor_data , 8) 'os primeiros 8 bits são a umidade
H = Binval(tmp_str8) 'Vamos transformar para valor numérico

Tmp_str8 = Mid(sensor_data , 17 , 8) 'estes 8 são a temperatura
T = Binval(tmp_str8)

Tmp_str8 = Right(sensor_data , 8) 'os ultimos 8 são o CRC
Crc = Binval(tmp_str8) '


Mybyte = T + H ' o CRC é a soma da umidade + temperatura
If Mybyte <> Crc Then ' considerando 8 bits
H = 3 ' se não bateu, erro !
End If

End Sub 'final da subrotina




Paulo

Tenho um RHT-22 que é um pouco diferente no formato dos dados que o DHT-11, e tive que fazer alguns pequenos ajustes para funcionar, abaixo a rotina num Arduino Mega 1280, espero que isto seja útil:


Sub Get_th_rht22(t_ent As Single , H_ent As Single)

Count = 0
Sensor_data = ""
Set Dht_io_set ' vira saída
Reset Dht_put ' nível 0 na saída
Waitms 25 ' tempo de espera pro dht11 25mseg
Set Dht_put ' volta nivel 1 na saída
Waitus 40 ' espera 40 useg
Reset Dht_io_set ' vira entrada
Waitus 40 ' espera mais 40 useg
If Dht_get = 1 Then ' se continua 1 tem algo errado
H_ent = 1 ' pois deveria estar em 0 !
Exit Sub
End If
'???? ?????? ??????? ? ?????? ???? ? ????? ?????????? ??????
Waitus 80 ' espera 80 useg
If Dht_get = 0 Then ' agora tem de estar 1 !
H_ent = 2 ' se tiver 0 , deu erro
Exit Sub
End If
'???? ??? ????????? ? ?????? ??????? ?????????, ????? ??????????
While Dht_get = 1 : Wend ' espera iniciar transmissão
Do
While Dht_get = 0 : Wend ' começou a transmissão
Waitus 30 ' voltou a nivel 1, espera 30 useg
If Dht_get = 1 Then ' se ápos 30 useg continua 1, então o bit é 1
Sensor_data = Sensor_data + "1" ' coloca 1 no buffer de dados
While Dht_get = 1 : Wend ' espera esse bit 1 terminar
Else ' se apos 30 uSeg virou 0, então o bit é 0
Sensor_data = Sensor_data + "0" ' coloca zero no buffer
End If
Incr Count ' incrementa contador de bits
Loop Until Count = 40 ' repete para 40 bits totais
Set Dht_io_set
Set Dht_put
'???????? ???????????? ?????????? ??????
Tmp_str16 = Left(sensor_data , 16) ' os primeiros 16 bits são a umidade
H_cal = Binval(tmp_str16) ' Vamos transformar para valor numérico
H_ent = H_cal
H_ent = H_ent / 10
Tmp_str16 = Left(sensor_data , 8)
Mybyte = Binval(tmp_str16)
Myword = Mybyte
Tmp_str16 = Mid(sensor_data , 9 , 8)
Mybyte = Binval(tmp_str16)
Myword = Myword + Mybyte

Tmp_str16 = Mid(sensor_data , 18 , 15) ' os próximos 15 são a temperatura sem o sinal.
T_cal = Binval(tmp_str16)
T_ent = T_cal
T_ent = T_ent / 10
Tmp_str16 = Mid(sensor_data , 17 , 8)
Mybyte = Binval(tmp_str16)
Myword = Myword + Mybyte
Tmp_str16 = Mid(sensor_data , 25 , 8)
Mybyte = Binval(tmp_str16)
Myword = Myword + Mybyte
Tmp_str16 = Right(sensor_data , 8) ' os últimos 8 são o CRC
Crc = Binval(tmp_str16) '
Tmp_str16 = Mid(sensor_data , 17 , 1) ' bit de sinal da temperatura
If Tmp_str16 = "1" Then
T_ent = 0 - T_ent
End If
Myword = Myword And &B11111111
Mybyte = Myword ' o CRC é a soma dos bytes da umidade e temperatura
If Mybyte <> Crc Then ' considerando 8 bits menos significativos
H_ent = 3 ' se não bateu, erro !
End If
End Sub ' final da subrotina

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

Depois coloco aqui a minha tentativa (infrutífera) de fazer a leitura de um PT100 (sensor de temperatura) usando um ADS-1115 da Texas, para ver se alguém tem ideia onde foi que eu errei.

Postado

Intrudera6,

Obrigado pelo código, e bem-vindo ao Fórum !

Mais um desses sensores com padrão esquisito.... Mas agora que você já descobriu como tratar, vai ajudar outros usuários com certeza !

Pode postar o seu código do PT100 pra gente dar uma olhada.

Paulo

Postado
  aphawk disse:
Intrudera6,

Obrigado pelo código, e bem-vindo ao Fórum !

Mais um desses sensores com padrão esquisito.... Mas agora que você já descobriu como tratar, vai ajudar outros usuários com certeza !

Pode postar o seu código do PT100 pra gente dar uma olhada.

Paulo

Este seu trabalho neste seu tutorial foi fantástico, me inspirou e inspirou muita gente, aprendi muito com este seu tutorial. Agora eu quero ajudar e dar uma pequena contribuição, e aprender um pouco mais também.

Mas para postar o código aqui, filtrei o meu código, para que não fique confuso demais pois no meio dele tem muitas outras coisas, como por exemplo o acesso a um RTC de precisão (DS3231), simulação de um RTC por código e etc, e outras coisas que fiz num Arduino MEGA para aprender a programar em Bascom, o que fez com que tenha muita coisa nele sem muita utilidade como fazer piscar LEDs e outras coisas. Por sinal o código acabou tão grande que acabei comprando o soft Bascom AVR, não aguentei mais me restringir a escrever códigos limitados a 4kb.

O ADS1115, é um ADC de 16bits I2C com 4 entradas AD de 16 bits multiplexadas com taxa máxima de 860 conversões por segundo. Encontrei vários exemplos de programação em C, o que não seria algo tão terrível assim, se o código não fizesse referência a uma biblioteca, o que faz ficar bem mais difícil entender como é que ele faz a comunicação com o controlador. Para ir mais além necessito desenhar (e postar aqui) o circuito que interfaceia com o ADS1115 (resistência de referência, PT100, portas AD usadas do ADC e etc.) para que fique entendível para as outras pessoas. A noite vou ver se consigo postar o desenho do circuito.

Abaixo vai o meu código (podado dos extras que não tem nada a ver com o PT100 ou com o ADS1115).


$regfile = "m1280def.dat" ' specify the used micro
$crystal = 16000000 ' Frequência do Cristal em Hz
$loadersize = &H1000 ' Bootloader de 4096 bytes
'$baud = 19200 ' use baud rate
$baud = 57600 ' use baud rate
$hwstack = 64 ' default use 32 for the hardware stack
$swstack = 128 ' default use 10 for the SW stack
$framesize = 256 ' default use 40 for the frame space
$map ' Informação para Debug
'$lib "stackcheck.lib"



$initmicro

Const Valor_prescale_int3 = 256
Const Interrupcoes_por_segundo_int3 = 10
Const Preload_int3 = 65535 - _xtal \(valor_prescale_int3 * Interrupcoes_por_segundo_int3) + 1

Const Valor_prescale_int4 = 256
Const Interrupcoes_por_segundo_int4 = 100
Const Tempo_aguardando = Interrupcoes_por_segundo_int4 * 2 ' Tempo em segundos
Const Preload_int4 = 65535 - _xtal \(valor_prescale_int4 * Interrupcoes_por_segundo_int4) + 1
Const T_acerta_segundos = 60 * 10 ' intervalo de tempo em segundos para acertar o relógio pelo RTC
Const T_acerta = Interrupcoes_por_segundo_int4 * T_acerta_segundos

'Endereço do ADS1115 (END=>GND), conversor ADC de 16 bits
Const Ads1115w = &B10010000 ' Endereço de escrita do ADC ADS1115
Const Ads1115r = &B10010001 ' Endereço de leitura do ADC ADS1115

Config_i2c:
'configure the scl and sda pins
Config Sda = Portd.1
Config Scl = Portd.0
Config I2cdelay = 2 ' para 500 kHz (aproximadamente)
'Config I2cdelay = 10 ' para 100 kHz
I2cinit

......
......
......


Dim I_pt100 As Double , E_pt100 As Double , R_pt100 As Double , T_pt100 As Double
Dim I_pt100_single As Single , E_pt100_single As Single , R_pt100_single As Single , T_pt100_single As Single
Dim Linha3 As String * 160

......
......
......

Gosub Getadc_pt100
If Err = 0 Then
Linha3 = ""
Else
Linha3 = "erro"
End If

If Linha3 <> "erro" Then
I_pt100_single = I_pt100
E_pt100_single = E_pt100
R_pt100_single = R_pt100
T_pt100_single = T_pt100
Linha3 = "ADS1115 (PT100)=> I = "
Linha3 = Linha3 + Fusing(i_pt100_single , "#.#########")
Linha3 = Linha3 + "A E = "
Linha3 = Linha3 + Fusing(e_pt100_single , "#.#######")
Linha3 = Linha3 + "V R = "
Linha3 = Linha3 + Fusing(r_pt100_single , "#.#####" )
Linha3 = Linha3 + "oHms T ="
Linha3 = Linha3 + Fusing(t_pt100_single , "#.###")
Linha3 = Linha3 + "ºC "
End If

Print Linha2
If Linha3 <> "erro" Then
Print Linha3
End If
If Mostra_com2 > 0 Then
Print #1 , Linha2
If Linha3 <> "erro" Then
Print #1 , Linha3
End If
End If

Pula:
End If


......
......
......


Getadc_i_pt100:
Dim Msbadc As Byte , Lsbadc As Byte
Dim Valoradc As Word At Msbadc Overlay

I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000001 ' Registrador de configuração
I2cwbyte &B01001010 ' MSB do registrador
' 0 : No effect
' 100 : AINP = AIN0 and AINN = GND
' (================ fora ============ 101 : AINP = AIN1 and AINN = GND =================)
' 101 : FS = ±0.256V
' 0 : Continuous conversion mode
I2cwbyte &B11100011 ' LSB do registrador
' 111 : 860SPS
' 0 : Traditional comparator with hysteresis (default)
' 0 : Active low (default)
' 0 : Non-latching comparator (default)
' 11 : Disable comparator (default)
Waitms 2 ' Espera 2 ms

' Lê valor do ADC
I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000000 ' Registrador de conversão
I2cwbyte Ads1115r ' Enviando endereço de leitura do ADS1115
I2crbyte Msbadc , Ack ' Valor mais significativo do ADC
I2crbyte Lsbadc , Nack ' Valor menos significativo do ADC
I2cstop
If Err = 0 Then ' Err = 0 => não houve erro na leitura do ADC (ADS1115) via i2c
I_pt100 = Valoradc
I_pt100 = I_pt100 * 7.81273842585528e-8 ' * 0.256 / (32767 * 100) => Valor da corrente no PT100 em Amperes
End If
Return


Getadc_pt100:

Gosub Getadc_i_pt100

I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita no ADS1115
I2cwbyte &B00000001 ' Registrador de configuração
I2cwbyte &B00111010 ' MSB do registrador
' 0 : No effect
' 011 : AINP = AIN2 and AINN = AIN3
' 101 : FS = ±0.256V
' 0 : Continuous conversion mode
I2cwbyte &B11100011 ' LSB do registrador
' 111 : 860SPS
' 0 : Traditional comparator with hysteresis (default)
' 0 : Active low (default)
' 0 : Non-latching comparator (default)
' 11 : Disable comparator (default)
Waitms 2 ' Espera 2 ms

' Lê valor do ADC
I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000000 ' Registrador de conversão
I2cwbyte Ads1115r ' Enviando endereço de leitura no ADS1115
I2crbyte Msbadc , Ack ' Valor mais significativo do ADC
I2crbyte Lsbadc , Nack ' Valor menos significativo do ADC
I2cstop
If Err = 0 Then ' Err = 0 => não houve erro na leitura ADC (ADS1115) via i2c
E_pt100 = Valoradc
E_pt100 = E_pt100 * 7.81273842585528e-6 ' * 0.256 / 32767 => Valor em Volts
R_pt100 = E_pt100 / I_pt100 ' Valor da resistência no PT100 em Ohms
T_pt100 = 100 - R_pt100
T_pt100 = T_pt100 * 2.32078e-4
T_pt100 = T_pt100 + 0.152726203204
T_pt100 = Sqr(t_pt100)
T_pt100 = 0.390802 - T_pt100
T_pt100 = T_pt100 / 1.16039e-4 ' Valor da temperatura no PT100 em ºC
End If
Return

O resultado foi que obtive overflow (FFFFh) nas duas leituras do ADS1115, independentemente dos valores das variáveis medidas.

Abaixo vai o circuito simplificado:

f4jo.png

No AIN0 eu leio a tensão sobre a minha resistência de referência (100 oHms +/- 0,01% de precisão) em relação ao terra.

No AIN2 e no AIN3 leio o valor sobre o PT100 que eu montei com 4 pernas sendo que 2 para circular corrente (que deve ser por volta de 1 mA), e as outras 2 pernas são para medir a tensão (praticamente sem queda de tensão).

Com estes valores seria só dividir o valor lido da tensão (entrada diferencial AIN2 e AIN3 no ADS1115) pela corrente (AIN0 no ADS1115), que nessa configuração compensa os erros na referência de tensão e na medição da resistência e tensão anulando os desvios, que tendem a se reproduzir nas duas medições (isto se tivesse dado certo e eu conseguisse ler o ADS1115 teria um erro estimado menor que +/- 0,01 °C , acho que conseguiria isso ou melhor se calibrasse o PT100).

Postado

Pessoal, segue um pequeno tutorial sobre usos do PCF8574 com o Bascom, inclusive transformando displays LCD's comuns em I2C !

 

Possui exemplos de uso, circuitos, arquivos de simulação do Proteus.

 

Um dos exemplos é o uso de dois displays em um simples ATTINY85 de 8 pinos !

 

Segue o link para download :

http://www.4shared.com/rar/HHyJbhj4/tutorial_PCF8574_BASCOM.html

 

Paulo

 

Em tempo :

 

Intrudera6,

Estou olhando o datasheet, percebí algumas coisas por enquanto :

1 - Faça a comunicação a 100 Khz mesmo..... evite usar 500 Khz pois está especificado que sem ser feita nenhuma configuração especial, ele funciona até 400 Khz ! Se quiser aumentar um pouco , use I2CDELAY=6.

2 - Sua rotina Getadc_i_pt100 : antes do WAITMS 2, tem de ter um comando I2CSTOP. O mesmo vale também para Getadc_pt100 .

3 - Quando você quer ler o ADC, você acessa o poiter register,; esta operação também tem de terminar com um I2CSTOP.

4 - E para ler o register de conversão, você tem de iniciar com I2CSTART novamente.

Ou seja, para cada tipo de registro, você tem de começar e terminar ela, antes de partir para um outro tipo de registro.

Creio que o CI não estava sendo inicializado corretamente, e talvez seja isso o motivo das leituras com overflow.

Vou ver mais um pouco o código e se achar algo posto aqui.

  • Curtir 1
Postado

Mudei a velocidade do i2c para 100khz (I2CDELAY=10) e coloquei alguns I2cstop e I2cstart conforme o código abaixo, mas os valores estão variando sem sentido agora.


Getadc_i_pt100:
Dim Msbadc As Byte , Lsbadc As Byte
Dim Valoradc As Word At Msbadc Overlay

I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000001 ' Registrador de configuração
I2cwbyte &B01001010 ' MSB do registrador
' 0 : No effect
' 100 : AINP = AIN0 and AINN = GND
' (================ fora ============ 101 : AINP = AIN1 and AINN = GND =================)
' 101 : FS = ±0.256V
' 0 : Continuous conversion mode
I2cwbyte &B11100011 ' LSB do registrador
' 111 : 860SPS
' 0 : Traditional comparator with hysteresis (default)
' 0 : Active low (default)
' 0 : Non-latching comparator (default)
' 11 : Disable comparator (default)
I2cstop
Waitms 2 ' Espera 2 ms

' Lê valor do ADC
I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000000 ' Registrador de conversão
I2cstop
I2cstart
I2cwbyte Ads1115r ' Enviando endereço de leitura do ADS1115
I2crbyte Msbadc , Ack ' Valor mais significativo do ADC
I2crbyte Lsbadc , Nack ' Valor menos significativo do ADC
I2cstop
If Err = 0 Then ' Err = 0 => não houve erro na leitura do ADC (ADS1115) via i2c
I_pt100 = Valoradc
I_pt100 = I_pt100 * 7.81273842585528e-8 ' * 0.256 / (32767 * 100) => Valor da corrente no PT100 em Amperes
End If
Return

Getadc_pt100:

Gosub Getadc_i_pt100

I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita no ADS1115
I2cwbyte &B00000001 ' Registrador de configuração
I2cwbyte &B00111010 ' MSB do registrador
' 0 : No effect
' 011 : AINP = AIN2 and AINN = AIN3
' 101 : FS = ±0.256V
' 0 : Continuous conversion mode
I2cwbyte &B11100011 ' LSB do registrador
' 111 : 860SPS
' 0 : Traditional comparator with hysteresis (default)
' 0 : Active low (default)
' 0 : Non-latching comparator (default)
' 11 : Disable comparator (default)
I2cstop
Waitms 2 ' Espera 2 ms

' Lê valor do ADC
I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000000 ' Registrador de conversão
I2cstop
I2cstart
I2cwbyte Ads1115r ' Enviando endereço de leitura no ADS1115
I2crbyte Msbadc , Ack ' Valor mais significativo do ADC
I2crbyte Lsbadc , Nack ' Valor menos significativo do ADC
I2cstop
If Err = 0 Then ' Err = 0 => não houve erro na leitura ADC (ADS1115) via i2c
E_pt100 = Valoradc
E_pt100 = E_pt100 * 7.81273842585528e-6 ' * 0.256 / 32767 => Valor em Volts
R_pt100 = E_pt100 / I_pt100 ' Valor da resistência no PT100 em Ohms
T_pt100 = 100 - R_pt100
T_pt100 = T_pt100 * 2.32078e-4
T_pt100 = T_pt100 + 0.152726203204
T_pt100 = Sqr(t_pt100)
T_pt100 = 0.390802 - T_pt100
T_pt100 = T_pt100 / 1.16039e-4 ' Valor da temperatura no PT100 em ºC
End If
Return

Postado

Acho que ainda não ficou correto.

Tente separar totalmente as operações em cada registro com o I2CSTOP na rotina GETADC_I_PT100, igual você fez nas rotinas seguintes. Afinal, ela que é responsável pela inicialização do CI.

Aproveita e já faz um teste :

Tira o PT100 , tudo , e coloca um resistor de 100 ohms no lugar do pt100 naquele seu esquema que você postou.

Assim teremos um circuito série com os tres resistores, e tem de dar sempre o mesmo resultado nas leituras.

Veja o que acontece.

Paulo

Postado
  aphawk disse:
Acho que ainda não ficou correto.

Tente separar totalmente as operações em cada registro com o I2CSTOP na rotina GETADC_I_PT100, igual você fez nas rotinas seguintes. Afinal, ela que é responsável pela inicialização do CI.

Aproveita e já faz um teste :

Tira o PT100 , tudo , e coloca um resistor de 100 ohms no lugar do pt100 naquele seu esquema que você postou.

Assim teremos um circuito série com os tres resistores, e tem de dar sempre o mesmo resultado nas leituras.

Veja o que acontece.

Paulo

Liguei primeiro numa alimentação estável (fonte de 9V) que a placa do Arduino baixou para 5,02V (antes estava pela USB, o que deixa a tensão mais baixa e menos estável), e continuou oscilando (indicando 0,004A e as vezes 0,0006A, o que eu verifiquei com um multímetro Fluke 87 (4 e 1/2 dígitos) na escala de mA e estava em 1,001mA, a tensão no PT100 estava em 112,2mV. Medi a minha resistência de referência e ela estava em exatos 100 oHms. O PT100 estava com 110,19 oHms, o valor encontrado estava variando muito mais .

Troquei o PT100 por uma resistência de 100 oHms, e os resultados não alteraram muita coisa. Continuou lendo lixo.

Antes de postar a 1ª mensagem aqui no fórum eu já tinha tentado trocar o meu ADS1115 por outro por suspeita de problema, depois disso eu passei a achar que o problema é mesmo de programação.

Pelos valores retornados os valores medidos devem estar todos negativos (último bit em 1), o que o meu programa não está preparado para lidar pois não era para ocorrer valores negativos em nenhuma hipótese. Fiz um gatilho na minha rotina para trocar os valores em complemento de 2 de negativo para positivo, e os valores continuaram estranhos.

Coloquei mais Stop e Starts:


Getadc_i_pt100:
Dim Msbadc As Byte , Lsbadc As Byte
Dim Valoradc As Word At Msbadc Overlay

I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000001 ' Registrador de configuração
I2cwbyte &B01001010 ' MSB do registrador
' 0 : No effect
' 100 : AINP = AIN0 and AINN = GND
' (================ fora ============ 101 : AINP = AIN1 and AINN = GND =================)
' 101 : FS = ±0.256V
' 0 : Continuous conversion mode
I2cwbyte &B11100011 ' LSB do registrador
' 111 : 860SPS
' 0 : Traditional comparator with hysteresis (default)
' 0 : Active low (default)
' 0 : Non-latching comparator (default)
' 11 : Disable comparator (default)
I2cstop
Waitms 2 ' Espera 2 ms

' Lê valor do ADC
I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000000 ' Registrador de conversão
I2cstop
I2cstart
I2cwbyte Ads1115r ' Enviando endereço de leitura do ADS1115
' ===================== Inserido ==========================
I2cstop
I2cstart
' ===================== Inserido ==========================
I2crbyte Msbadc , Ack ' Valor mais significativo do ADC
I2crbyte Lsbadc , Nack ' Valor menos significativo do ADC
I2cstop
If Err = 0 Then ' Err = 0 => não houve erro na leitura do ADC (ADS1115) via i2c
I_pt100 = Valoradc
I_pt100 = I_pt100 * 7.81273842585528e-8 ' * 0.256 / (32767 * 100) => Valor da corrente no PT100 em Amperes
End If
Return

Getadc_pt100:

Gosub Getadc_i_pt100

I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita no ADS1115
I2cwbyte &B00000001 ' Registrador de configuração
I2cwbyte &B00111010 ' MSB do registrador
' 0 : No effect
' 011 : AINP = AIN2 and AINN = AIN3
' 101 : FS = ±0.256V
' 0 : Continuous conversion mode
I2cwbyte &B11100011 ' LSB do registrador
' 111 : 860SPS
' 0 : Traditional comparator with hysteresis (default)
' 0 : Active low (default)
' 0 : Non-latching comparator (default)
' 11 : Disable comparator (default)
I2cstop
Waitms 2 ' Espera 2 ms

' Lê valor do ADC
I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000000 ' Registrador de conversão
I2cstop
I2cstart
I2cwbyte Ads1115r ' Enviando endereço de leitura no ADS1115
' ===================== Inserido ==========================
I2cstop
I2cstart
' ===================== Inserido ==========================
I2crbyte Msbadc , Ack ' Valor mais significativo do ADC
I2crbyte Lsbadc , Nack ' Valor menos significativo do ADC
I2cstop
If Err = 0 Then ' Err = 0 => não houve erro na leitura ADC (ADS1115) via i2c
E_pt100 = Valoradc
E_pt100 = E_pt100 * 7.81273842585528e-6 ' * 0.256 / 32767 => Valor em Volts
R_pt100 = E_pt100 / I_pt100 ' Valor da resistência no PT100 em Ohms
T_pt100 = 100 - R_pt100
T_pt100 = T_pt100 * 2.32078e-4
T_pt100 = T_pt100 + 0.152726203204
T_pt100 = Sqr(t_pt100)
T_pt100 = 0.390802 - T_pt100
T_pt100 = T_pt100 / 1.16039e-4 ' Valor da temperatura no PT100 em ºC
End If
Return

Era isso que você sugeriu ?

Os valores lidos para I (tensão sobre 100 oHms) = 65483 (valor binário), e tensão sobre o PT100 = 65503 (valor binário)

Com resistência de 100 oHms no lugar do PT100

Os valores lidos para I (tensão sobre 100 oHms) = 65483 (valor binário), e tensão sobre o PT100 = 65483 (valor binário)

Eu realmente não tenho a menor ideia do que pode estar acontecendo.

Postado

Bom, com certeza falta transformar o resultado de sua leitura em complemento de 2 !

Lí atentamente o datasheet, e olha só : o resultado que você está obtendo do ADC está EM COMPLEMENTO DE 2 !!!!!!

Tem de converter para o normal , porisso que você está obtendo leituras negativas !

Não me lembro como transformar o complemento de dois de 16 bits...... vai ter de pesquisar !

E o datasheet especifica que tem de usar sempre os ACK na comunicação, logo após voce passar o endereço. Assim, modifiquei o seu programa para o que eu acho correto, só falta voce fazer a conversão do formato de complemento de 2 !


Getadc_i_pt100:
Dim Msbadc As Byte , Lsbadc As Byte
Dim Valoradc As Word At Msbadc Overlay

I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000001 ' Registrador de configuração
I2cwbyte &B01001010 ' MSB do registrador
' 0 : No effect
' 100 : AINP = AIN0 and AINN = GND
' (================ fora ============ 101 : AINP = AIN1 and AINN = GND =================)
' 101 : FS = ±0.256V
' 0 : Continuous conversion mode
I2cwbyte &B11100011 ' LSB do registrador
' 111 : 860SPS
' 0 : Traditional comparator with hysteresis (default)
' 0 : Active low (default)
' 0 : Non-latching comparator (default)
' 11 : Disable comparator (default)
I2cstop
Waitms 2 ' Espera 2 ms

' Lê valor do ADC
I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000000 ' Registrador de conversão
I2cstop
waitms 1
I2cstart
I2cwbyte Ads1115r ' Enviando endereço de leitura do ADS1115
I2crbyte Msbadc , Ack ' Valor mais significativo do ADC
I2crbyte Lsbadc , Nack ' Valor menos significativo do ADC
I2cstop

If Err = 0 Then ' Err = 0 => não houve erro na leitura do ADC (ADS1115) via i2c

' AQUI voce TEM DE TRANSFORMAR O COMPLEMENTO DE 2 EM NORMAL !

I_pt100 = Valoradc
I_pt100 = I_pt100 * 7.81273842585528e-8 ' * 0.256 / (32767 * 100) => Valor da corrente no PT100 em Amperes
End If
Return

Getadc_pt100:

Gosub Getadc_i_pt100

I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita no ADS1115
I2cwbyte &B00000001 ' Registrador de configuração
I2cwbyte &B00111010 ' MSB do registrador
' 0 : No effect
' 011 : AINP = AIN2 and AINN = AIN3
' 101 : FS = ±0.256V
' 0 : Continuous conversion mode
I2cwbyte &B11100011 ' LSB do registrador
' 111 : 860SPS
' 0 : Traditional comparator with hysteresis (default)
' 0 : Active low (default)
' 0 : Non-latching comparator (default)
' 11 : Disable comparator (default)
I2cstop
Waitms 2 ' Espera 2 ms

' Lê valor do ADC
I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000000 ' Registrador de conversão
I2cstop
waitms 1
I2cstart
I2cwbyte Ads1115r ' Enviando endereço de leitura no ADS1115
I2crbyte Msbadc , Ack ' Valor mais significativo do ADC
I2crbyte Lsbadc , Nack ' Valor menos significativo do ADC
I2cstop
If Err = 0 Then ' Err = 0 => não houve erro na leitura ADC (ADS1115) via i2c

' AQUI voce TEM DE TRANSFORMAR O COMPLEMENTO DE 2 EM NORMAL !


E_pt100 = Valoradc
E_pt100 = E_pt100 * 7.81273842585528e-6 ' * 0.256 / 32767 => Valor em Volts
R_pt100 = E_pt100 / I_pt100 ' Valor da resistência no PT100 em Ohms
T_pt100 = 100 - R_pt100
T_pt100 = T_pt100 * 2.32078e-4
T_pt100 = T_pt100 + 0.152726203204
T_pt100 = Sqr(t_pt100)
T_pt100 = 0.390802 - T_pt100
T_pt100 = T_pt100 / 1.16039e-4 ' Valor da temperatura no PT100 em ºC
End If
Return

Acerta agora o teu código, faça a conversão da leitura de complemento de 2 da sua variável VALORADC para o normal ANTES DE FAZER QUALQUER CONTA e informe os resultados.

Observação : a menos que voce tenha um layout super profissional, tipo aquele utilizado em medidores cardíacos, voce vai ter de ignorar pelo menos uns 5 bits de suas leituras !

Tem de usar uma referência de tensão super-precisa para o conversor, e mesmo assim um simples ruído de 1 milivolt em qualquer entrada já leva sua precisão no conversor para 12 bits significativos..... E olha que 1 milivolt é algo que é muito, mas muito difícil de eliminar, imagine 0,1 milivolt !!! voce mesmo já disse que a sua tensão de alimentação varia bastante, muito mais do que 1 milivolt, então adeus referência precisa !

Elimine esses 5 bits de suas contas, e veja se estabilizou.

Paulo

Postado

Consegui fazer funcionar.

O problema era a variável Valoradc que eu estava fazendo ovelay no formato invertido e com isto os valores estavam oscilando de forma bastante severa (sem ter número significativo). Foi só inverter as variáveis Lsbadc e Msbadc de ordem para que a variável Valoradc ficasse com os valores corretos (o certo era o número menos significativo vir antes).

O ADS1115 realmente fornece os resultados em complemento de 2, mas os números em complemento de 2 são exatamente iguais quando são números positivos. Eles só são diferentes quando os valores são negativos, e para convertê-los para positivo é só, no caso de variável de 16 bits, subtrair -1 do valor e inverter os bits (subtrair o valor final de 65535).

Fiz uns testes e os valores oscilam um pouco (o que era esperado), talvez de para conseguir estabilizar melhor o valor, que não precisa ser preciso em 5V para que funcione, mas tem que ser estável ou pelo menos tem que variar lentamente. Vou estudar como é que eu vou fazer isso.

Li o datasheet do ADS1115 e o tempo necessário entre um Stop e um Start é de apenas 600ns e não 1 ms.

Vai abaixo a rotina final.


Getadc_i_pt100:
Dim Lsbadc As Byte , Msbadc As Byte
Dim Valoradc As Word At Lsbadc Overlay

I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000001 ' Registrador de configuração
I2cwbyte &B01001010 ' MSB do registrador
' 0 : No effect
' 100 : AINP = AIN0 and AINN = GND
' (================ fora ============ 101 : AINP = AIN1 and AINN = GND =================)
' 101 : FS = ±0.256V
' 0 : Continuous conversion mode
I2cwbyte &B11100011 ' LSB do registrador
' 111 : 860SPS
' 0 : Traditional comparator with hysteresis (default)
' 0 : Active low (default)
' 0 : Non-latching comparator (default)
' 11 : Disable comparator (default)
I2cstop
Waitms 2 ' Espera 2 ms

' Lê valor do ADC
I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000000 ' Registrador de conversão
I2cstop
Waitus 1
I2cstart
I2cwbyte Ads1115r ' Enviando endereço de leitura do ADS1115
I2crbyte Msbadc , Ack ' Valor mais significativo do ADC
I2crbyte Lsbadc , Nack ' Valor menos significativo do ADC
I2cstop
If Err = 0 Then ' Err = 0 => não houve erro na leitura do ADC (ADS1115) via i2c
I_pt100 = Valoradc
I_pt100 = I_pt100 * 7.81273842585528e-8 ' * 0.256 / (32767 * 100) => Valor da corrente no PT100 em Amperes
End If
Return

Getadc_pt100:

Gosub Getadc_i_pt100

I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita no ADS1115
I2cwbyte &B00000001 ' Registrador de configuração
I2cwbyte &B00111010 ' MSB do registrador
' 0 : No effect
' 011 : AINP = AIN2 and AINN = AIN3
' 101 : FS = ±0.256V
' 0 : Continuous conversion mode
I2cwbyte &B11100011 ' LSB do registrador
' 111 : 860SPS
' 0 : Traditional comparator with hysteresis (default)
' 0 : Active low (default)
' 0 : Non-latching comparator (default)
' 11 : Disable comparator (default)
I2cstop
Waitms 2 ' Espera 2 ms

' Lê valor do ADC
I2cstart ' Generate start code
I2cwbyte Ads1115w ' Enviando endereço de escrita do ADS1115
I2cwbyte &B00000000 ' Registrador de conversão
I2cstop
Waitus 1
I2cstart
I2cwbyte Ads1115r ' Enviando endereço de leitura no ADS1115
I2crbyte Msbadc , Ack ' Valor mais significativo do ADC
I2crbyte Lsbadc , Nack ' Valor menos significativo do ADC
I2cstop
If Err = 0 Then ' Err = 0 => não houve erro na leitura ADC (ADS1115) via i2c
E_pt100 = Valoradc
E_pt100 = E_pt100 * 7.81273842585528e-6 ' * 0.256 / 32767 => Valor em Volts
R_pt100 = E_pt100 / I_pt100 ' Valor da resistência no PT100 em Ohms
T_pt100 = 100 - R_pt100
T_pt100 = T_pt100 * 2.32078e-4
T_pt100 = T_pt100 + 0.152726203204
T_pt100 = Sqr(t_pt100)
T_pt100 = 0.390802 - T_pt100
T_pt100 = T_pt100 / 1.16039e-4 ' Valor da temperatura no PT100 em ºC
End If

Return

Resultados observados:


12/08/13 22:08:46.07 26.75ºC TH => 26.7ºC 71.7% 1012.8mB 3.81mts 26.5ºC
ADS1115 (PT100)=> I = 0.001022274A E = 0.1126675V R = 110.21017oHms T =26.228ºC
12/08/13 22:08:47.06 26.75ºC TH => 26.7ºC 71.7% 1012.8mB 3.81mts 26.5ºC
ADS1115 (PT100)=> I = 0.001020845A E = 0.1127065V R = 110.40025oHms T =26.719ºC
12/08/13 22:08:48.07 26.75ºC TH => 26.7ºC 71.7% 1012.7mB 4.59mts 26.5ºC
ADS1115 (PT100)=> I = 0.001022337A E = 0.1126753V R = 110.20938oHms T =26.226ºC
12/08/13 22:08:49.06 26.75ºC TH => 26.7ºC 71.7% 1012.7mB 4.59mts 26.5ºC
ADS1115 (PT100)=> I = 0.001021798A E = 0.1126987V R = 110.29131oHms T =26.438ºC
12/08/13 22:08:50.07 26.75ºC TH => 26.7ºC 71.7% 1012.7mB 4.38mts 26.5ºC
ADS1115 (PT100)=> I = 0.001022396A E = 0.1126440V R = 110.17039oHms T =26.126ºC
12/08/13 22:08:51.06 26.75ºC TH => 26.7ºC 71.7% 1012.7mB 4.38mts 26.5ºC
ADS1115 (PT100)=> I = 0.001022155A E = 0.1125346V R = 110.08866oHms T =25.915ºC

Estes resultados (na linha do PT100) são influenciados pela imprecisão da tensão de referência do ADS1115 (que não é citado no datasheet) e que faz com que a corrente sobre o resistor de referência varie e também afeta a medição no PT100 (que também é afetado pela tensão sobre as resistências de 100 + 4.7k + PT100), erro do amplificador operacional interno no ganho de 16 vezes, efeito do aquecimento provocado no PT100 pela corrente de referência (1,02mA), variação da tensão de polarização (que não é muito precisa nem muito estável), e outros fatores como interferência eletromagnética que deve ser significativa com tensões baixas e outros.

Finalmente aprendi como usar o ADS1115, agora dá para brincar mais a sério. Quem sabe eu tente também com um ADS1248, que é bem mais preciso (24bits), tem mais portas AD, é mais rápido, tem recursos para compensação que permitem ler os RTDs como um PT100 com muito mais precisão, independentemente da tensão de alimentação. Mas ainda dependo de resistências de alta precisão para ter uma tensão de referência decente. Mas não dá para comunicar com ele da mesma forma que o 1115, ele não é i2c (mais um aprendizado).

  • 2 semanas depois...
Postado

Antunes,

Obrigado, eu preferí fazer desta maneira, bem pessoal, e publicar para todos poderem ver e aprender, do que fazer um livro.

O objetivo foi justamente desmitificar o uso dos microcontroladores, pois em tudo que é fórum quando um iniciante pergunta como programar um Pic ou AVR aparece a turma do " tem de ser em C" ou a do " assembler é o melhor" ..., o que acaba desencorajando um monte de gente, que poderia se divertir em poucos dias utilizando o velho e bom Basic.... E acho que é muito importante ensinar a fazer a simulação de projetos com o Isis do Proteus, afinal a gente perde um tempão gravando, testando, gravando, testando .......... Se simular, só precisaremos gravar quando estiver quase totalmente corrigido.

E sempre que tiver alguma novidade, postarei aqui para todos.

Um abraço.

Paulo

  • 3 semanas depois...
Postado

 RÁDIO FM COM CONTROLE DE TONALIDADE E AMPLIFICADOR

 

Pessoal, terminei o meu novo projeto, ficou simples e bem barato, pois os módulos principais podem ser comprados no Ebay ou no Mercado Livre.

 

Custo aproximado :

Modulo Fm TEA5767 - US$ 2,00

Amplificador stereo 10+10 W - US$ 6,50

Display LCD Backlite 4 x 20 - US$ 6,50

Atmega 328 - US$ 3,50 ( mas serve um Atmega8, Atmega88 , atmega16, Arduino, etc... )

Fonte de parede de 12v por 2A - US$ 6,50

 

Falta ainda algo muito importante : um CI controlador de Audio TDA8425 que pode ser adquirido aqui no Brasil mesmo, em SP na Santa Ifigênia sai por R$ 6,50 !!! Esse CI controla volume, graves, agudos, e ainda pode criar efeitos tipo Estéreo Espacial ou Pseudo-estéreo. E utiliza a interface I2C !

 

Ainda precisamos de alguns resistores, capacitores, regulador 7805 e 4 push-buttons, que custam mais uns R$ 20,00 tudo.

 

Como podem ver, podemos construir apenas uma plaquinha para o Atmega328 e o TDA8425, e aproveitar os outros módulos completos.

 

Ou fazer uma única placa para tudo, usando um CI amplificador de áudio tipo Classe D de baixa potência.

 

Eu montei um Frankstein usando alguns módulos que eu tinha aqui, e o resultado ficou legal.

 

O interessante é que o programa em Bascom que controla tudo com apenas 4 push-buttons de contato momentâneo e pode utilizar qualquer processador, desde um Atmega8 até um Atmega328, ou até mesmo pode ser facilmente modificado para utilizar um Arduino como controlador !

 

Segue o programa fonte em Bascom :

 

 
        '-----------------------------------------------------------------------
        ' Nome       : TEA5767 HOME AUDIO.bas
        ' Revisão    : 1.0   02.09.2013
        ' Controller : AVR ATmega16
        ' Autor      : Antonio Paulo Hawk com trechos de
        '            : Thomas Palluthe (www.tp-homesoft.de)
        ' Compilador : BASCOM-AVR   Rev. 2.0.7.6
        '
        '
        '---[ Detalhes do TEA5767 ]-------------------------------------
        '         ESCRITA
        ' Softmute : bit 3 do byte 4    1=ligado
        ' High Cut : bit 2 do byte 4    1=ligado
        ' Stereo Noise Canceler : bit 1 do byte 4    1=ligado
        ' Mute : bit 7 byte 1  1=mute
        ' Hi/Lo Injection : bit 4 do byte 3   1=hi Side Inj
        ' Stereo/Mono  :  bit 3 do byte 3    1=Mono
        '
        '          LEITURA
        ' Stereo : bit 7 do byte 3     1=stereo
        ' Freq. Intermed. : bit 6-0 do byte 3
        ' Nivel Sinal : bit 7-4 do byte 4
        ' PLL : bit 5-0 byte 1   13-8
        ' PLL : bit 7-0 byte 2    7 - 0
        '
        '---[ Detalhes do TDA8425 ]-------------------------------------
        '
        ' Endereço escrita :  082h
        ' Endereço Leitura :  083h
        ' Formato escrita =  STA/CHIP/REG/VL/VR/BA/TR/S1/STOP
        ' Registros e funções :
        ' REG :0
        ' VL = 11VL5VL4VL3VL2VL1VL0  = 2 DB ( +6 ATÉ -80(27 ATÉ 0) )
        ' VR = 11VR5VR4V33VR2VR1VR0  = 2 DB ( +6 ATÉ -80(27 ATÉ 0) )
        ' BA = 1111BA3BA2BA1BA0 = 3DB ( +15/15/15/15/12...-12/-12/-12 )
        ' TR = 1111TR3TR2TR1TR0 = 3DB ( +12/12/12/12/9....-12/-12/-12 )
        ' SW = 11/MU/EFL/STL/M1/M0/IS onde
        '      MU = Mute ( 1=ligado )
        '      EFL=0 STL=1 -  ESTEREO_NORMAL
        '      EFL=1 STL=1  -  ESTEREO_ESPACIAL
        '      EFL=1 STL=0  -  PSEUDO_ESTEREO
        '      EFL=0 STL=0  -  MONO
        '
        '      ML1=1 ML0=1 IS=0  -  STEREO CANAL 1

        '
        ' FORMATO DISPLAY
        ' LINHA 1->VLM  BAS  TRB  ST NM ( PODE SER ST SP OU MONO)
        ' LINHA 2->-30  -3   -3   RAD 1 ( pode ser AUD )
        ' LINHA 3->RA   AU   +F   -F    ( PODE SER +M -M )
        ' linha 4->F=109.2 STEREO SI=8
        '
        ' TABELAS :
        ' TB_VL VAI DE 20 ATÉ 63 ( -80 A +6 )
        ' TB_BA VAI DE 2 ATÉ 11  ( -12 A +15)
        ' TB_TR VAI DE 2 ATÉ 10  ( -12 A +12)
        '
        ' MAQUINA DE ESTADOS :
        ' MODO=0 Indica tratamento de RADIO. A cada aperto de bot1 muda a fase
        '
        ' FASE=1 Indica bot3 e bot4 mudar frequencias
        ' FASE=2 Indica bot3 muda mono/stereo
        '
        ' MODO=1 Indica tratamento de AUDIO. A cada aperto de bot2 muda a fase
        '
        ' FASE=1 Indica bot3 e bot4 a dim / aumentar o volume
        ' FASE=2 Indica bot3 e bot4 a dim / aumentar os graves
        ' FASE=3 Indica bot3 e bot4 a dim / aumentar os agudos
        ' FASE=4 Indica bot3 mudar ST/SP/MN/PS


$regfile = "m328Pdef.dat"
$crystal = 8000000                                          '8 MHz Oszillator
' SE FOR USAR UM ARDUINO, MUDAR O CRYSTAL PAR 16000000
$hwstack = 128
$swstack = 128
$framesize = 200

Config Sda = Portc.4                                        'I²C
Config Scl = Portc.5
$lib "I2C_TWI.LIB"
$lib "double.lbx"
Declare Sub Init_audio
Declare Sub Init_radio
Declare Sub Sintonia
Declare Sub Leitura_radio
Declare Sub Ajusta_audio
Declare Sub Comunica_audio
Declare Sub Aumenta_volume
Declare Sub Abaixa_volume
Declare Sub Aumenta_grave
Declare Sub Abaixa_grave
Declare Sub Aumenta_agudo
Declare Sub Abaixa_agudo


'---(LCD)-----------------------------------------------------------------------
Config Lcd = 20 * 4
Config Lcdpin = Pin , Db4 = Pd.5 , Db5 = Pd.4 , Db6 = Pd.3 , Db7 = Pd.2 , E = Pd.6 , Rs = Pd.7



'---( hardware)-----------------------------------------------------------------

Config Portb.0 = Input
Config Portb.1 = Input
Config Portb.2 = Input
Config Portc.0 = Input
                                         'Pullup
Set Portb.0
Set Portb.1
Set Portb.2
Set Portc.0

Botao1 Alias Pinb.0
Botao2 Alias Pinb.1
Botao3 Alias Pinb.2
Botao4 Alias Pinc.0


Dim Flag_mudou_radio As Bit
Dim Flag_mudou_audio As Bit
Dim Primeiro As Bit
Dim Flag_botao As Bit
Dim Pllfrequenz As Word
Dim Old_pll As Word
Dim Adresse As Byte
Dim 1st As Byte
Dim 2nd As Byte
Dim 3rd As Byte
Dim 4th As Byte
Dim 5th As Byte

Dim R1st As Byte
Dim R2nd As Byte
Dim R3rd As Byte
Dim R4th As Byte
Dim R5th As Byte
Dim State_radio As Byte

Dim Pll As Single
Dim Freq_desejada As Single
Dim Freq_temp As Single

Dim A1st As Byte
Dim A2nd As Byte
Dim A3rd As Byte
Dim A4th As Byte
Dim A5th As Byte
Dim State_audio As Byte
Dim Vl As Byte
Dim Vr As Byte
Dim Tr As Byte
Dim Ba As Byte
Dim Modo_audio As Byte
Dim Rvl As String * 3
Dim Rvr As String * 3
Dim Rtr As String * 3
Dim Rba As String * 3

Dim Modo As Byte
Dim Fase As Byte
Dim Tam As Byte
Dim Nspaces As Byte


Modo = 0                                                    ' RADIO
Fase = 1
                                                    'INICIO
'Dim Freq_memory(42) As Single
Dim Sender As Byte
Dim I As Byte
Dim W As String * 5
Dim J As Byte
Dim Sinal As Byte
Dim Flag_stereo As Bit
Dim Flag_leitura_stereo As Bit

Dim Linha1 As String * 20
Dim Linha2 As String * 20
Dim Linha3 As String * 20
Dim Linha4 As String * 20
'Dim Copia_linha1 As String * 20
'Dim Copia_linha2 As String * 20
'Dim Copia_linha3 As String * 20
'Dim Copia_linha4 As String * 20
Dim Str_rascunho As String * 4

Const Xtal_tea5767 = 32768
Const Freq_int = 225000
Const Tea5767w = &HC0
Const Tea5767r = &HC1
Const Tda8425w = &H82
Const Tda8425r = &H83
Const Estereo_normal = 1
Const Estereo_espacial = 3
Const Pseudo_estero = 2
Const Mono = 0
Const Incremento = 0.2

Modo_audio = Estereo_normal                                 'AUDIO EM ESTEREO
Flag_stereo = 1                                             ' RADIO EM ESTEREO
Freq_desejada = 87.5

'--- INICIO PROGRAMA -----------------------------------------------------------
Waitms 500
Initlcd
Cls
Cursor Off
Lcd "FM Stereo Radio"
Lowerline
Lcd "Paulo DEV.R1"
Wait 3
Cls
I2cinit
Config Twi = 70000


Init_radio
Init_audio
Waitms 50




Vl = 45
Rvl = Lookupstr(vl , Tb_vl)
Ba = 6
Rba = Lookupstr(ba , Tb_ba)
Tr = 6
Rtr = Lookupstr(tr , Tb_tr)
Ajusta_audio
Primeiro = 1
Do
Flag_botao = 1
If Botao1 = 0 Then
   Flag_botao = 1
   Goto Proc1
End If

If Botao2 = 0 Then
   Flag_botao = 1
   Goto Proc2
End If

If Botao3 = 0 Then
   Flag_botao = 1
   Goto Proc3
End If

If Botao4 = 0 Then
   Flag_botao = 1
   Goto Proc4
End If

If Flag_botao = 1 Or Primeiro = 1 Then
   Primeiro = 0
   Leitura_radio
   Goto Saida
Else
   Leitura_radio
   Linha4 = "F=" + Rtrim(w)
   If Len(linha4) = 6 Then
     Linha4 = Linha4 + " "
   End If
   If Flag_leitura_stereo = 1 Then
     Linha4 = Linha4 + " St   Si="
   Else
     Linha4 = Linha4 + " Mon  Si="
   End If
   Str_rascunho = Str(sinal)
   Linha4 = Linha4 + Trim(str_rascunho)
   Tam = Len(linha4)
   If Tam < 20 Then
     Nspaces = 20 - Tam
     Linha4 = Linha4 + Space(nspaces)
   End If
   Locate 4 , 1
   Lcd Linha4
   Goto Saida_final
End If
Saida_final:
If Modo = 1 And Fase = 1 Then
  Waitms 20
End If
If Modo = 0 And Fase = 1 Then
  Waitms 30
End If
Loop

' --------  PROCESSAMENTO DO BOTAO 1 --------------------------
Proc1:
Waitms 5
If Botao1 = 0 Then
  Waitms 15
  Goto Proc1
End If
If Modo = 1 Then
 Modo = 0
 Fase = 1
Else
 Incr Fase
 If Fase = 3 Then
   Fase = 1
 End If
End If
Goto Saida

' --------  PROCESSAMENTO DO BOTAO 2 --------------------------
Proc2:
Waitms 5
If Botao2 = 0 Then
  Waitms 15
  Goto Proc2
End If
If Modo = 0 Then
 Modo = 1
 Fase = 1
Else
 Incr Fase
 If Fase = 5 Then
   Fase = 1
 End If
End If
Goto Saida

' --------  PROCESSAMENTO DO BOTAO 3 --------------------------
Proc3:
Waitms 5
If Modo = 0 And Fase = 1 Then
  Goto Proc3a
Elseif Modo = 1 And Fase = 1 Then
  Goto Proc3a
End If
If Botao3 = 0 Then
  Waitms 15
  Goto Proc3
End If
Proc3a:
If Modo = 0 Then
   If Fase = 1 Then
      Freq_desejada = Freq_desejada - Incremento
      If Freq_desejada < 87.5 Then
         Freq_desejada = 108.1
      End If
   Else
      Toggle Flag_stereo
   End If
   Flag_mudou_radio = 1
Else
  If Fase = 1 Then
     Abaixa_volume
  Elseif Fase = 2 Then
     Abaixa_grave
  Elseif Fase = 3 Then
     Abaixa_agudo
  Elseif Fase = 4 Then
     Incr Modo_audio
     If Modo_audio > 3 Then
        Modo_audio = 0
     End If
  End If
  Flag_mudou_audio = 1
End If
Goto Saida

' --------  PROCESSAMENTO DO BOTAO 4 ---------------------------
Proc4:
Waitms 5
If Modo = 0 And Fase = 1 Then
   Goto Proc4a
Elseif Modo = 1 And Fase = 1 Then
  Goto Proc4a
End If
If Botao4 = 0 Then
  Waitms 15
  Goto Proc4
End If
Proc4a:
If Modo = 0 Then
   If Fase = 1 Then
      Freq_desejada = Freq_desejada + Incremento
      If Freq_desejada > 108.1 Then
         Freq_desejada = 87.5
      End If
   End If
   Flag_mudou_radio = 1
Else
  If Fase = 1 Then
     Aumenta_volume
  Elseif Fase = 2 Then
     Aumenta_grave
  Elseif Fase = 3 Then
     Aumenta_agudo
  End If
  Flag_mudou_audio = 1
End If
Goto Saida


'---- ROTINA DE DISPLAY -------------------------------------------------------
Saida:
If Flag_mudou_radio = 1 Then
  Sintonia
  Flag_mudou_radio = 0
  End If
If Flag_mudou_audio = 1 Then
  Ajusta_audio
  Flag_mudou_audio = 0
End If
Leitura_radio                                               ' LER O SINAL
' aqui temos de fazer o tratamento do display
Linha1 = "VLM  BAS  TRB  "
If Modo_audio = 0 Then
  Str_rascunho = "Mono"
Elseif Modo_audio = 1 Then
  Str_rascunho = "StNm"
Elseif Modo_audio = 2 Then
  Str_rascunho = "PsSt"
Else
  Str_rascunho = "StSp"
End If
Linha1 = Linha1 + Str_rascunho
Linha2 = Rvl + Space(2)
Linha2 = Linha2 + Rba
Linha2 = Linha2 + Space(2)
Linha2 = Linha2 + Rtr
Linha2 = Linha2 + Space(2)
If Modo = 0 Then
  Str_rascunho = "RAD"
Else
  Str_rascunho = "AUD"
End If
Linha2 = Linha2 + Trim(str_rascunho)
Linha2 = Linha2 + " "
Str_rascunho = Str(fase)
Linha2 = Linha2 + Trim(str_rascunho)
Linha3 = "RAD  AUD  "
If Modo = 0 Then
  If Fase = 1 Then
    Linha3 = Linha3 + "-F   +F"
  Else
    Linha3 = Linha3 + "Mo/St  "
    If Flag_stereo = 1 Then
      Str_rascunho = "St"
    Else
      Str_rascunho = "Mn"
    End If
    Linha3 = Linha3 + Trim(str_rascunho)
  End If
Else
  If Fase = 1 Then
    Linha3 = Linha3 + "-V   +V"
  Elseif Fase = 2 Then
    Linha3 = Linha3 + "-B   +B"
  Elseif Fase = 3 Then
    Linha3 = Linha3 + "-T   +T"
  Else
    Linha3 = Linha3 + "Efeito "
  End If
End If
 W = Fusing(freq_desejada , "#.#")
'Str_rascunho = Str(freq_temp)
'Linha4 = "F=" + Trim(str_rascunho)
Linha4 = "F=" + Rtrim(w)
If Len(linha4) = 6 Then
  Linha4 = Linha4 + " "
End If
If Flag_leitura_stereo = 1 Then
  Linha4 = Linha4 + " St   Si="
Else
  Linha4 = Linha4 + " Mon  Si="
End If
Str_rascunho = Str(sinal)
Linha4 = Linha4 + Trim(str_rascunho)
'agora, acertar os espacos
Tam = Len(linha1)
If Tam < 20 Then
  Nspaces = 20 - Tam
  Linha1 = Linha1 + Space(nspaces)
End If
Tam = Len(linha2)
If Tam < 20 Then
  Nspaces = 20 - Tam
  Linha2 = Linha2 + Space(nspaces)
End If
Tam = Len(linha3)
If Tam < 20 Then
  Nspaces = 20 - Tam
  Linha3 = Linha3 + Space(nspaces)
End If
Tam = Len(linha4)
If Tam < 20 Then
  Nspaces = 20 - Tam
  Linha4 = Linha4 + Space(nspaces)
End If
Locate 1 , 1
Lcd Linha1
Locate 2 , 1
Lcd Linha2
Locate 3 , 1
Lcd Linha3
Locate 4 , 1
Lcd Linha4
Goto Saida_final


'---------  SUB ROTINAS  -------------------------------------------------------
Sub Init_radio
Sintonia
End Sub

Sub Sintonia
Pll = Freq_desejada * 1000000
Pll = Pll + Freq_int
Pll = Pll * 4
Pll = Pll / Xtal_tea5767
Pllfrequenz = Int(pll)
1st = High(pllfrequenz)
Reset 1st.6
Reset 1st.7
2nd = Low(pllfrequenz)
3rd = &B00010000
If Flag_stereo = 1 Then
  3rd.3 = 1
Else
  3rd.3 = 0
End If
4th = &B00011010
5th = &B01000000
I2cstart
I2cwbyte Tea5767w
I2cwbyte 1st
I2cwbyte 2nd
I2cwbyte 3rd
I2cwbyte 4th
I2cwbyte 5th
I2cstop
End Sub

Sub Leitura_radio
I2cstart
I2cwbyte Tea5767r
I2crbyte R1st , Ack
I2crbyte R2nd , Ack
I2crbyte R3rd , Ack
I2crbyte R4th , Ack
I2crbyte R5th , Nack
I2cstop
Sinal = R4th And &B11110000
Shift Sinal , Right , 4
If R3rd.7 = 1 Then
  Set Flag_leitura_stereo
Else
  Reset Flag_leitura_stereo
End If
End Sub



Sub Init_audio
'INICIALIZA O CHIP TDA8425
'Modo = Stereo Normal
'Canal = 1
' MUTE=LIGADO
' VL=VR=-30DB 45
'TR = BA = 0DB 6
A1st = 45 Or &B11000000
A2nd = A1st
A3rd = 6 Or &B11110000
A4th = A3rd
A5th = &B11001110
Comunica_audio
End Sub

Sub Comunica_audio
I2cstart
I2cwbyte Tda8425w
I2cwbyte 0
I2cwbyte A1st
I2cstart
I2cwbyte Tda8425w
I2cwbyte 1
I2cwbyte A2nd
I2cstart
I2cwbyte Tda8425w
I2cwbyte 2
I2cwbyte A3rd
I2cstart
I2cwbyte Tda8425w
I2cwbyte 3
I2cwbyte A4th
I2cstart
I2cwbyte Tda8425w
I2cwbyte 8
I2cwbyte A5th
I2cstop
End Sub



Sub Ajusta_audio
A1st = Vl Or &B11000000
A2nd = A1st
A3rd = Ba Or &B11110000
A4th = Tr Or &B11110000
A5th = Modo_audio
Shift A5th , Left , 3
A5th = A5th Or &B11000110
Comunica_audio
End Sub

Sub Aumenta_volume
Incr Vl
If Vl > 63 Then Vl = 63
Rvl = Lookupstr(vl , Tb_vl)
End Sub

Sub Abaixa_volume
Decr Vl
If Vl < 20 Then Vl = 20
Rvl = Lookupstr(vl , Tb_vl)
End Sub

Sub Aumenta_grave
Incr Ba
If Ba > 11 Then Ba = 11
Rba = Lookupstr(ba , Tb_ba)
End Sub

Sub Abaixa_grave
Decr Ba
If Ba < 2 Then Ba = 2
Rba = Lookupstr(ba , Tb_ba)
End Sub

Sub Aumenta_agudo
Incr Tr
If Tr > 10 Then Tr = 10
Rtr = Lookupstr(tr , Tb_tr)
End Sub

Sub Abaixa_agudo
Decr Tr
If Tr < 2 Then Tr = 2
Rtr = Lookupstr(tr , Tb_tr)
End Sub


End
'----- FINAL DO PROGRAMA -------------------------------------------------------

Tb_vl:
Data "-80" , "-80" , "-80" , "-80" , "-80" , "-80" , "-80" , "-80"
Data "-80" , "-80" , "-80" , "-80" , "-80" , "-80" , "-80" , "-80" , "-80"
Data "-80" , "-80" , "-80" , "-80" , "-78" , "-76" , "-74" , "-72" , "-70"
Data "-68" , "-66" , "-64" , "-62" , "-60" , "-58" , "-56" , "-54" , "-52"
Data "-50" , "-48" , "-46" , "-44" , "-42" , "-40" , "-38" , "-36" , "-34"
Data "-32" , "-30" , "-28" , "-26" , "-24" , "-22" , "-20" , "-18" , "-16"
Data "-14" , "-12" , "-10" , "-8 " , "-6 " , "-4 " , "-2 " , "0  " , "+2 "
Data "+4 " , "+6 "

Tb_ba:
Data "-12" , "-12" , "-12" , "-9 " , "-6 " , "-3 " , "0  " , "+3 " , "+6 "
Data "+9 " , "+12" , "+15" , "+15" , "+15" , "+15" , "+15"

Tb_tr:
Data "-12" , "-12" , "-12" , "-9 " , "-6 " , "-3 " , "0  " , "+3 " , "+6 "
Data "+9 " , "+12" , "+12" , "+12" , "+12" , "+12" , "+12"

Para quem quer aprender mais sobre controles digitais em som, este projeto é uma ótima oportunidade, pois hoje em dia tudo funciona de maneira semelhante, por exemplo uma TV, um rádio moderno ( com DSP ), um home teather, etc.

 

Funcionamento :

 

O botão 1 seleciona as funções de rádio, isto é, quando apertado permite que os botões 3 e 4 façam a diminuição ou o aumento da frequência sintonizada. Se apertar novamente o botão 1, o botão 3 permite a mudança de sinal de Estéreo para Mono e vice versa.

 

O botão 2 seleciona as funções de áudio, ou seja, inicialmente permite que os botões 3 e 4 façam a diminuição do volume ou o aumento. Ao ser apertado novamente, os botões 3 e 4 fazem a diminuição ou o aumento dos graves, e se o botão 2 for apertado de novo, permite mudar o nível dos agudos. Finalmente, apertando mais uma vez o botão 2, faz com que o botão 3 mude o processamento de áudio, trocando ciclicamente de Estéreo Normal para Estéreo Espacial, em seguida Mono, e finalmente Pseudo Estéreo.

 

O display acompanha essa troca de funções, e também mostra o nível do sinal recebido, além de todas as informações sobre a frequência, nível de volume, de graves, de agudos e também o tipo de processamento de áudio.

 

Segue o esquema :

 

PROJETO.png.8334dc88d4faa2338ce2b15e379d74c5.png

 

Segue uma foto da "aranha":

 

vlcsnap-2019-06-06-22h18m15s777.png.f3c8ecc8ac8eeac6bd5a2ab4212ccca2.png

 

Para terminar, conforme prometí, segue o link com o arquivo .hex para gravar o seu ATMEGA328, e o próprio programa-fonte do Bascom :

http://www.4shared.com/rar/VUBGWpWb/radio_tea5767.html

Paulo

  • Curtir 1
Postado

Paulo,

Você já me ajudou muito com o ADS1115, agora estou com alguns problemas novos:

1. Ampliando o meu programa esbarrei neste erro.

  Citação
back jump out out of range

Não consigo entender bem o porque deste erro, o programa só está usando 15% da memoria do AVR 1280. O que eu estou fazendo de errado e o que eu devo fazer para evitar este erro de compilação ?

2. Eu estou querendo comunicar mais rápido (high speed mode) com o ADS1115. Pelo datashit diz que eu devo enviar para um endereço especial um byte 00001xxx (to activate high-speed mode, send a special address byte of 00001xxx following the START condition, where xxx are bits unique to the Hs-capable master). Texto que fica na página 17 do datashit (ADS1115.pdf).

Eu realmente não entendi o que tenho que fazer para ativar o modo high speed de comunicação I2C do ADS1115.

Ainda tenho muito que aprender com o uso do Bascom e também nos microcontroladores AVR.

Postado

Oi Intruder,

1 - Nunca ví esse erro.... mas faz o seguinte, normalmente a gente coloca as sub-rotinas no final, experimente espalhar elas no meio do programa.

Uma vez tive um problema com uma tabela no final do programa, dava um erro doido também, tive de mudar o programa, o trecho que chamava essa tabela estava bem no iníçio, mudei ele e coloquei no meio do programa e resolveu....

2 - Vou pesquisar o datasheet e posto depois.

Paulo

Postado

Pessoal,

Segue um programa bem interessante, muito útil para aqueles casos onde você quer usar vários CI's I2C's porém usam o mesmo endereço.... e claro que neste caso não tem como !

A solução é utilizar um CI demultiplex específico para I2C, mas o tal CI é naqueles formatos SMD e ainda é meio carinho e difícil de achar, porém ......

Se você tiver pinos sobrando, pode usar pares de pinos para simular novos Bus I2C e colocar um CI em cada par, e ainda assim pode controlar todos independentes !

No meu caso, onde preciso usar 3 CI's TDA8425 e dois PCF8574, tive de criar 3 novos Buses I2C, e fiquei com 4 no total, pois existe o nativo no hardware dos Atmegas e nesse eu coloquei os dois PCF8574 cada um em um endereço diferente, e pronto !

Nada impede de aumentar esse número, basta existirem pinos livres !

Como acho que esse programa pode ser útil para outros malucos , posto aqui o código :


'-------------------------------------------------------------------------------
' PROGRAMA PARA USAR 4 BUS I2C INDEPENDENTES
' VELOCIDADE DE COMUNICAÇÃO = 36 KHZ APROXIMADO para os 3 Bus por software
' e 100 Khz para o Bus nativo por hardware
'
'Fiz este programa pois estou montando uma central de som para o meu carro
'onde tenho 6 canais de áudio independentes ( 5.1 ) e gostaria de reforçar
'o áudio com 6 controles independentes de graves e agudos, além de poder
'rotear qualquer canal de entrada para qualquer saída !
'Para isto estou usando 3 TDA8425 e 6 cd4051. O problema é que os TDA's
'possuem o mesmo endereço, então não consigo colocar todos no mesmo Bus.
'
'Este programa é a solução, onde criei 3 bus independentes controlados por
'software, onde colocarei os 3 TDA's, e ainda tenho o bus nativo livre para
'usar um controlador de display com um PCF8574 e mais um PCF8574 para ler os
'botões de controle.
'Segue aqui como exemplo a quem precisar de algo semelhante.
'-------------------------------------------------------------------------------



$regfile = "m328pdef.dat"
$crystal = 16000000 '16 MHz

$hwstack = 128
$swstack = 128
$framesize = 128

Config Submode = New

'
' CONFIGURA O BUS POR HARDWARE NATIVO
Config Sda = Portc.4 'I²C
Config Scl = Portc.5
$lib "I2C_TWI.LIB"

'
' ---- CONFIGURA OS 3 BUS I2C POR SOFTWARE
Const I2c_maxdata = 10 'MAXIMO DE BYTES A RECEBER
' BUS 1
Scl1 Alias Portb.0
Sda1 Alias Portb.1
Sda1_in Alias Pinb.1
' BUS 2
Scl2 Alias Portc.0
Sda2 Alias Portc.1
Sda2_in Alias Pinc.1
' BUS 3
Scl3 Alias Portc.2
Sda3 Alias Portc.3
Sda3_in Alias Pinc.3

' CONFIGS GERAIS DOS 3 BUS POR SOFTWARE
Config Sda1 = Input
Config Sda2 = Input
Config Sda3 = Input
Config Scl1 = Input
Config Scl2 = Input
Config Scl3 = Input
Dim I_data(i2c_maxdata) As Byte '10 BYTES PARA RECEBER
Dim I_num As Byte
Dim I_type As String * 4


'-------------------------------- SUBROTINAS -------------------------
Sub Init_all_i2c
Scl1 = 1
Config Scl1 = Output
Scl2 = 1
Config Scl2 = Output
Scl3 = 1
Config Scl3 = Output
Config Sda1 = Input
Config Sda2 = Input
Config Sda3 = Input
Waitus 10
End Sub

Sub Sda_high(byval I_num As Byte)
Local T1 As Byte
T1 = I_num
Select Case T1
Case 1 : Config Sda1 = Input
Case 2 : Config Sda2 = Input
Case 3 : Config Sda3 = Input
End Select
End Sub

Sub Sda_low(byval I_num As Byte)
Local T1 As Byte
T1 = I_num
Select Case T1
Case 1
Sda1 = 0
Config Sda1 = Output
Case 2
Sda2 = 0
Config Sda2 = Output
Case 3
Sda3 = 0
Config Sda3 = Output
End Select
End Sub

Sub Scl_high(byval I_num As Byte)
Local T1 As Byte
T1 = I_num
Select Case T1
Case 1 : Config Scl1 = Input
Case 2 : Config Scl2 = Input
Case 3 : Config Scl3 = Input
End Select
End Sub

Sub Scl_low(byval I_num As Byte)
Local T1 As Byte
T1 = I_num
Select Case T1
Case 1
Scl1 = 0
Config Scl1 = Output
Case 2
Scl2 = 0
Config Scl2 = Output
Case 3
Scl3 = 0
Config Scl3 = Output
End Select
End Sub

Sub I2c_start(byval I_num As Byte)
Local T2 As Byte
T2 = I_num
Call Scl_high(t2)
Waitus 4
Call Sda_low(t2)
Waitus 5
Call Scl_low(t2)
Call Sda_high(t2)
Waitus 5
End Sub

Sub I2c_stop(byval I_num As Byte)
Local T2 As Byte
T2 = I_num
Call Scl_low(t2)
Waitus 1
Call Sda_low(t2)
Waitus 2
Call Scl_high(t2)
Waitus 4
Call Sda_high(t2)
Waitus 5
End Sub

Sub I2c_wbyte(byval I_num As Byte , Byval I_value As Byte)
Local T3 As Byte
Local I_dummy1 As Byte
Local I_dummy2 As Byte
Local I_dummy As Byte
T3 = I_num
I_dummy1 = I_value
Call Scl_low(t3)
For I_dummy = 1 To 8
I_dummy2 = I_dummy1 And &B10000000
Shift I_dummy1 , Left , 1
If I_dummy2 = 128 Then
Call Sda_high(t3)
Else
Call Sda_low(t3)
End If
Waitus 1
Call Scl_high(t3)
Waitus 6
Call Scl_low(t3)
Next I_dummy
Call Sda_high(t3)
Waitus 3
Call Scl_high(t3)
Waitus 3
Select Case T3
Case 1
I_dummy = Sda1_in
Case 2
I_dummy = Sda2_in
Case 3
I_dummy = Sda3_in
End Select
If I_dummy = 0 Then
I_type = "NACK"
Else
I_type = "ACK "
End If
Waitus 3
End Sub

Sub I2c_rbyte(byval I_num As Byte , Byval I_value As Byte , Byval I_type As String)
Local I_dummy As Byte
Local I_dummy1 As Byte
Local I_dummy2 As Byte
Local I_str As String * 4
Local I_x As Byte
Local I_read As Byte
I_dummy = I_num
I_dummy1 = I_value 'AONDE ARMAZENAR
I_read = 0
I_str = I_type
I_str = Trim(i_str)
I_dummy2 = 0
Call Scl_low(i_dummy)
Waitus 5
For I_x = 1 To 8
Shift I_dummy2 , Left , 1
Call Scl_high(i_dummy)
Waitus 3
Select Case I_dummy
Case 1
I_read = Sda1_in
Case 2
I_read = Sda2_in
Case 3
I_read = Sda3_in
End Select
I_dummy2 = I_dummy2 + I_read
Waitus 2
Call Scl_low(i_dummy)
Waitus 5
Next
If I_type = "ACK" Then
Call Sda_low(i_num)
Waitus 2
Call Scl_high(i_dummy)
Waitus 6
Call Scl_low(i_dummy)
Call Sda_high(i_num)
Waitus 6
Call Scl_high(i_dummy)
Waitus 6
Else
End If
I_data(i_dummy1) = I_dummy2
End Sub

'------------------- FINAL DAS SUBS ----------------------------------

' Aqui começa o programa mesmo....

I2cinit
'
Config Twi = 100000 ' inicializa o i2c nativo hardware
Init_all_i2c ' inicializa os 3 i2cs soft

de novo:
'o comando abaixo faz o i2cstart no bus 1
Call I2c_start(1) 'bus 1
'veja a sintaxe do comando abaixo, onde 1 é o bus e 85 é o endereço
Call I2c_wbyte(1 , 75)
'veja a sintaxe abaixo, onde 1 é o bus, 2 é o endereço na matrix i_data()
'onde o dado lido vai ser guardado, e o ACK significa que continua leitura
Call I2c_rbyte(1 , 2 , "ACK")
' abaixo veja que usamos NACK para sinalizar final de leitura
Call I2c_rbyte(1 , 3 , "NACK")
Call I2c_stop(1)
Waitms 10

Call I2c_start(2) 'bus 2
Call I2c_wbyte(2 , 73)
Call I2c_rbyte(2 , 4 , "ACK")
Call I2c_rbyte(2 , 5 , "NACK")
Call I2c_stop(2)
Waitms 10

Call I2c_start(3) 'bus 3
Call I2c_wbyte(3 , 71)
Call I2c_rbyte(3 , 6 , "ACK")
Call I2c_rbyte(3 , 7 , "NACK")
Call I2c_stop(3)
Waitms 10

I2cstart 'bus 4
I2cwbyte 69
I2crbyte I_data(8) , Ack
I2crbyte I_data(9) , Nack
I2cstop
Waitms 10
Goto de novo


End

Paulo

Postado
  aphawk disse:
Oi Intruder,

1 - Nunca ví esse erro.... mas faz o seguinte, normalmente a gente coloca as sub-rotinas no final, experimente espalhar elas no meio do programa.

Uma vez tive um problema com uma tabela no final do programa, dava um erro doido também, tive de mudar o programa, o trecho que chamava essa tabela estava bem no iníçio, mudei ele e coloquei no meio do programa e resolveu....

2 - Vou pesquisar o datasheet e posto depois.

Paulo

Já tentei alguma coisa, mas se pelo menos eu soubesse o que realmente está acontecendo e porque, seria mais fácil contornar.

Postado

Intruder,

Experimente usar o Config Submode= New , você tem de colocar todas as suas subrotinas logo no início do programa, e o compilador faz a realocação na compilação.

Se mesmo assim não funcionar, mande o fonte para mim, vou tentar dar umas mexidas.

Paulo

  • 2 semanas depois...
Postado

Opa, legal mesmo, seria muito bom contar com você também nos Avrs !

Estou fazendo mais uma atualização da apostila, com alguns exemplos dos modos de baixo consumo, expansores I2c, e pequenas correções. Tudo com o Bascom.

Se tiver alguma dúvida, não hesite, pergunte !

Um abraço e boa diversão, Mr. Nintendo !

Paulo

Postado
  aphawk disse:
Intruder,

Experimente usar o Config Submode= New , você tem de colocar todas as suas subrotinas logo no início do programa, e o compilador faz a realocação na compilação.

Se mesmo assim não funcionar, mande o fonte para mim, vou tentar dar umas mexidas.

Paulo

Eu ainda não testei, estou com tempo curto. Quando finalmente mexer no programa digo o que foi que ouve.

  • 3 semanas depois...
Postado
  aphawk disse:
Intruder,

Experimente usar o Config Submode= New , você tem de colocar todas as suas subrotinas logo no início do programa, e o compilador faz a realocação na compilação.

Se mesmo assim não funcionar, mande o fonte para mim, vou tentar dar umas mexidas.

Paulo

Expandir  

Demorei para testar, mas acabou não dando certo. O que eu quis fazer foi colocar mais umas 3 operações em ponto flutuante (para fazer um arredondamento) e passou a dar este erro (Backward jump out of range), o pior é que não acho nada na Internet que explique este erro. Tentei mudar todas as rotinas para o inicio do programa e também não deu certo.

Passo abaixo o meu programa (completo), acho que vai dar um trabalho enorme para você entender (são quase 1500 linhas). Fiz muita coisa de forma não muito eficiente mas com o objetivo de aprender a usar o Bascom AVR. Eu pendurei muita coisa do Adruino MEGA 1280, a maior parte com objetivo didático, quem sabe algum dia eu faça algo prático com ele. Se pelo menos eu soubesse que diabos de erro é este talvez desse para contornar

E imaginar que no passado distante, bem distante, já programei em assembler (Z80, 6502, 8088, e alguma coisa de co-processador aritmético) e hoje não consigo e nem tenho mais saco de aprender C, mas Bascom é simples demais, é quase brincadeira usar o Bascom. Eu já tinha perdido totalmente o tesão de programar, mas brincar com microcrontrolador é realmente divertido, pricipalmente quando se pode fazer em Basic (mesmo sendo a versão capada de basic do Bascom).

  Mostrar conteúdo oculto

 

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

Mostrar 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

Mostrar mais  
×
×
  • Criar novo...

LANÇAMENTO!

eletronica2025-popup.jpg


CLIQUE AQUI E BAIXE AGORA MESMO!