16f887 SDA SCL Protokolü

Başlatan erdogan2734, 10 Şubat 2016, 18:05:42

erdogan2734

   Sevgili arkadaşlar merhaba;
Yurt dışından aldığım bir modülde volum kontrolü yapmaya çalışıyorum.
Anlayamadığım bir kaç yer var sizlere danışmak istedim. Öncelikle bu komutu ilk defa kullanacağım.
Ürün kataloğunda aşağıdaki eklemiş olduğum resimde adress verileri verilmiş.

Benim yapmam sda-scl bacaklarını belirleyip verilen adrese bilgiyi yazmakmıdır?
Datashette write komutu için 0x34 komutu, ses ayarı yapacağımız kısım için 0x00 komutu ve son olarak da değer belirtmemizi söylemiş.
Birde ACK 'dan bahsedilmiş, Burada ACK mesaj alındı komutumudur?
Örneğin:
SYMBOL SDA =PORTC.4
SYMBOL SCL=PORTC.3
BASLA:
I2CWRITE SDA,SCL,0X34,0X00[64]
END

Şeklinde bir yazım yeterlimidir.
İyi çalışmalar.

Erdoğan
İmkansızın zaman aldığı bir dünya'da bana zorluktan bahsetme!

ete

Belliki modül I2C ile haberleşiyor. Bu haberleşme şeklinde aynı hatta birden fazla cihaz olabileceği için her cihazın bir kontrol kodu olur. Senin cihazın kontrol kodu $34 . Kontrol kodundan sonra o modülün içinde birden fazla register olabileceği için ulaşmak istediğin register adresini verirsin. Ardından da yazmak istediğin değeri veya ona ait değişkeni yazarsın. Kontrol kodunun sıfır biti okuma yada yazma yapıldığını belirler. Yazma yaparken bu bit sıfır ( o yüzden senin kod $34) okuma yapılırken o bit 1 yapılır ve bu nedenle okuma yapılırken kod $35 olarak uygulanır. Ancak sen daima 34 kullan çünki basic bu işi otomatik yapar.
İşin komut şekli şöyle olmalı,
I2Cwrite SDA,SCL,$34,Adres,[Değer]

Unutmaman gerek bir başka husus da Sda ve Scl hatlarına pullup direnci bağlama zorunluluğu. Dirençler olmadan sistem çalışmaz.

Ete

erdogan2734

#2
Peki hocam bu ACK ne demek. Ben yazılımımda Ack adi altinda herhangi bir veri yollayacakmıyım?
Erdoğan
İmkansızın zaman aldığı bir dünya'da bana zorluktan bahsetme!

ete

#3
Ack  senin anlayacağın dilde alan ile verenin mutabakatı demektir.
Veren bir şey verip alındığından emin olması için data hattını çıkıştan girişe çevirip bekler hat alıcı tarafından konum değiştirilir böylece haberleşmenin sürdüğü ve sorun olmadığı anlaşılır.
Ack sinyalleride basic tarafından verilmektedir. Senin bu konuda yapman gereken bir şey yok.

Ete

erdogan2734

#4
Hocam Merhaba;
Dün akşam konuşmamıza istinaden şu anda deneme yapıyorum. 16f887 kullanıyorum.
4.2 Volt li-ion pil kullanıyorum, sda ve scl bacağına 4.7k ile direk pil gerilimini veriyorum.
SDA ve SCL bacaklarını giriş çıkış tanımlamalarında, aşağıdaki gibi çıkış olarak tanımlıyorum.
Şu anda bir sonuç elde edemedim.
Kaçırdığım bir yer varmıdır.?
İyi çalışmalar.

Program:

@ __config _CONFIG1, _MCLRE_OFF & _LVP_OFF & _PWRTE_ON &_INTRC_OSC_NOCLKOUT & _WDT_OFF
@ __config _CONFIG2, _WRT_OFF & _BOR21V & _BOR40V
'------------------------------------------------------------------
DEFINE OSC 4
OSCCON=%01101100 '4 mhz
DEFINE HSER_RCSTA 90h    'Enable serial port & continuous receive
DEFINE HSER_TXSTA 20h    'Enable transmit, BRGH = 0
DEFINE HSER_SPBRG 25     '2400 Baud @ 0,16%
DEFINE HSER_CLROERR 1    'Clear overflow automatically

DEFINE ADC_BITS 10     ' ADCIN resolution  (Bits)
DEFINE ADC_CLOCK 1     ' ADC clock source  (Fosc/8)
DEFINE ADC_SAMPLEUS 20 ' ADC sampling time (uSec)

ADCON1=%10000000         '10 BITLIK ADC ICIN GEREKLI DEGER

ANSEL = %00000001 ' Make AN0-AN7 digital                       
ANSELH= %00000000 ' Make AN8-AN13 digital                     
CM1CON0=0         ' C1 Komparatör iptal                                 
CM2CON0=0         ' C2 Komparatör iptal                                 
WPUB=0            ' PORTB pullup lar kapalı 
OPTION_REG.7 = 0
ADCON0=%10000001
TRISC=%10000011
portc=0
symbol tus1=portc.0
symbol tus2=portc.1
symbol sda =portc.4
symbol scl =portc.3

basla:

if tus1=0 then
GOSUB SESARTI
while tus1=0 :Wend
pause 100
endif


if tus2=0 then
gosub seseksı
while tus2=0: wend
pause 100
endif

goto basla

SESARTI:
I2CWRITE SDA,SCL,$34,$02,[30]
I2CWRITE SDA,SCL,$34,$00,[30]
RETURN

SESEKSI:
I2CWRITE SDA,SCL,$34,$02,[00]
I2CWRITE SDA,SCL,$34,$00,[00]
RETURN

end




Program baya uzun olduğundan sadece ilgili kısmı yazdım.

Erdoğan
İmkansızın zaman aldığı bir dünya'da bana zorluktan bahsetme!

ete

Programları kod tag içinde verin lütfen !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Ben mesajını hdüzelttim ve programı kod tag içine aldım. Aynı zamanda programındaki eksikleri ilave ettim ve hatalarıda düzelttim.

Netice alamadım diyorsun ama zaten bu şekilde o programı derlemen imkansız sıfır yerine o harfini basmışsın. İlk tuş kontrolüne bir bak şimdi düzeldi ama sendeki kopyada öyledir.
Tuş kontrolleride benim yaptığım gibi olmalı.

Programda dahili OSC kullanınca hangi frekans olduğunu OSCCON registerinden belirlemen gerekir. Zira bu işlemcide birden fazla seçenek mevcut.

Diğer kodlarda hata yok. Ama bir hatırlatma yapayım. Ses seviyeleri 0-31 arasında değişiyor.
Ses açmada sen direk 30 vermişsin. Kapatmada 0 vermişsin burada bir hata yok ama 30 yerine 1-31 arasında bir değer verebiliyorsun bunu unutma.

Bu şekilde bir dene bakalım. Yine çalışmıyor ise devreni iyice kontrol et. MCLR pinini iptal ettim olurda oraya pullup direnci takmazsın belki diye. Gerekirse yine aktif edersin. Ama bu şekilde işlemci mutlaka çalışacaktır.
Yineden çalışmıyor ise o modülden şüphelenmek gerekecek.

Ete

erdogan2734

   Hocam Merhaba
   Programı tag içine almadığım için özür dilerim. Mclr bacağında pull up direnci kullandım. Ses seviyesini biliyorum. Ben en azından bir hareket görmek için direk kısmak istedim sesi, ama başaramadım. Programı kopyala yapıştır, yapmaktansa direk yazayım dedim.
Ondan dolayı yazım hatalarım olmuş. Program çalışıyor işlemci bacakları kontol ettiğimde yazma işlemi esnasında bacaklarda farklı voltajlar okuyorum. Ama yinede ses kısıp açamadım. Galiba karşı tarafta bilmem gereken farklı bir durum var. Üretici firmaya mail attım.
Bu arada SDA ve SCL bacaklarında 4.2 volt pil geriliminde 4.7k pull-up kullandım. Bu değerin sonuca etki edeceğini düşünmüyorum.
Bakalım bir değişiklik olursa yazarım tekrardan.
İyi çalışmalar.
Erdoğan
İmkansızın zaman aldığı bir dünya'da bana zorluktan bahsetme!

erdogan2734

Merhaba Hocam;
Üretici firma aşağıdaki kod örneğini yolladı bana.
C dilinde okuma,yazma yapmış. Pek bilmediğim için sizinle paylaşmak istedim.
Kaçırdığımız bir nokta olabilirmi? Yada bizim okuma,yazma yaptığımız komut dışında kullanmamız gereken bir komut varmıdır.?
Teşekkür ederim.

#include "bios.h"

#define I2C_READ  0B00110101  // I2C read command
#define I2C_WRITE 0B00110100  // I2C write command
#define IIC_SDA_LOW
#define IIC_SCL_LOW
#define IIC_SDA_HIGH
#define IIC_SCL_HIGH



void iic_start()
{
  IIC_SCL_HIGH;
  IIC_SDA_HIGH;
  delay_5us();
  IIC_SDA_LOW;
  delay_5us();
  IIC_SCL_LOW;
  delay_5us();
}

void iic_stop()
{
  IIC_SDA_LOW;
  IIC_SCL_HIGH;
  delay_5us();
  IIC_SDA_HIGH;
  delay_5us();
}

unsigned char ack(void)
{
    unsigned char ack;
IIC_SCL_HIGH;
delay_5us();
IIC_SDA_HIGH;
if ( IIC_SDA == 0 )
  {
   ack =  TRUE;
      }
    else
  {
   ack = FALSE;
  }
IIC_SCL_LOW;
delay_5us();
    return ack;
}

void send_byte(unsigned char s_byte) // 发送一个字符
{
  unsigned char i;
  for ( i = 0;i < 8; i++ )
     {
   
   if ( (s_byte & 0B10000000 ) > 0 )
     {
  IIC_SDA_HIGH; // BIT 1      
         }
   else
     {
  IIC_SDA_LOW;  // BIT 0
}
       IIC_SCL_HIGH;
       delay_5us();
       IIC_SCL_LOW;
   delay_5us();
   s_byte <<= 1; 

}

}

unsigned char recive_byte() // 接收一个字符
{
  unsigned char i,r_byte;
  r_byte = 0 ;
  for ( i = 0;i < 8; i++ )
     {
   if ( IIC_SDA == 1 )
      {
   r_byte |= 0B00000001; // BIT 1      
  }
   else
      {
   r_byte &= 0B11111110; // BIT 0
          }
   IIC_SCL_HIGH;
       delay_5us();
       IIC_SCL_LOW;
   delay_5us();
   r_byte <<= 1; 

}
  return r_byte;

}


unsigned char write_byte(unsigned char address,unsigned char data)
  {
    iic_start();
    send_byte(I2C_WRITE);
    if (ack() == FALSE )
   {
     iic_stop();
     return FALSE;
   }
    send_byte(address);
    if (ack() == FALSE )
   {
     iic_stop();
     return FALSE;
   }
send_byte(data);
    if (ack() == FALSE )
   {
     iic_stop();
     return FALSE;
   }
    iic_stop();
    return TRUE;
  }
Erdoğan
İmkansızın zaman aldığı bir dünya'da bana zorluktan bahsetme!

ete

C dilinden süper anlamam ama burada yazılanların çoğunu anlayabiliyorum ve anladığım kadarı ile bizim yazdıklarımız doğru.
Bence yazdıkların çalışması gerekir. Donanım da kusur araman gerek bana kalırsa.

Ancak yollanan kod sadece Start konumu, Stop konumu, ACK kontrolü, byte yollama ve byte alma işlemlerini gösteriyor.
Bu yollananlarda kontrol değeri $34 olarak kullanılmış bunu görebiliyoruz. Ancak adres değerlerini nasıl kullanmışlar onu göremiyoruz.  Bizim kullandığımız gibi olması gerek ama yinede adamlardan Volum değerini 20 yapabilecek bir kod örneği istersen o zaman daha net anlaşılır sistem.

Ete

erdogan2734

Hocam ben pek laf anlatamıyorum bu arkadaşlara, volume level 20 yapacak bir program yazıp yollayın dedim.
Yukardaki programın aynısını yollamışlar. Farklı bir durum öğrendim.
16Mghz kristal kullanıyorlarmış baud rate hızı 8khz olarak belirtmişler.
Benim kullandığım işlemcide 4 Mghz dahili osilatör kullanıyorum baud rate hızım ise 2400.
Burada bir değişiklik yapmama gerek varmıdır acaba?
İyi çalışmalar.
Erdoğan
İmkansızın zaman aldığı bir dünya'da bana zorluktan bahsetme!

ete

Bazı cihazlar, daha yavaş I2C haberleşmesi isterler. Yanlış hatırlamıyor isem normal seviye 400Khz idi.
PBP da şayet 8Mhz ve üzerinde kristal kullanılırsa haberleşme hızını yavaşlatmak üzere bir komut var oda;

DEFINE I2C_SLOW 1 'Use for >8MHz OSC with standard speed devices

Ancak senin 4 Mhz de bile hızın fazla geliyor ise bu komutu ilave edebilirsin programın başına.

Bir husus daha var. 
DEFINE I2C_HOLD 1 'Pause I2C transmission while clock held low
Haberleşme esnasında CLK low da tutulurken programın biraz bekletilmesini sağlar. Bazı cihazlar için buda gerekli olabiliyor. Bunuda dene. Yine programın başında bir yere koymalısın.

Ete


Powered by EzPortal