STM32 – HAL Kütüphanesi ile ADXL345 Kullanımı
Herkese merhabalar , bu yazımızda HAL Kütüphanesi ile ADXL345 İvme Sensörünün kodlarını açıklayarak yazacağız. ADXL345 den gelen verileri I2C ile okuyacağız.
ADXL345 Datasheet:
[button text=”ADXL345″ new_tab=”yes” size=”medium” icon=”” url=”https://www.analog.com/media/en/technical-documentation/data-sheets/adxl345.pdf”]
1- Kütüphaneyi ekliyoruz.
#include "main.h"
2- Gerekli olan değişkenleri tanımlıyoruz.
uint8_t i;
uint8_t data_rec[6];
int16_t x,y,z;
float xg, yg, zg;
i : sensörün adresini hafızada tutar.
data_rec[6] :
x, y, z : Hareket değerlerini tutmak için.
xg, yg, zg : Hareket ivmelerinin “G kuvvet ” değerlerini tutmak için.
3- Sistemin kendi fonksiyonlarını tanımladık.
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
4- ADXL345’e ait özel fonksiyonlarını tanımladık.
void Scan_I2C_Address();
void ADXL_Init();
void ADXL_Write(uint8_t memAddress, uint8_t value);
void ADXL_Read(uint8_t memAddress, uint8_t numberOfBytes);
Scan_I2C_Address : I2C iletişiminde kullanacağım cihazların adreslerini bulan fonksiyon.
ADXL_Init : ADXL345’e ait yapıları başlatan fonksiyon.
ADXL_Write : ADXL345’in üzerine veri yazacağımızda kullancağım fonksiyon.
ADXL_Read : ADX345 üzerinden veri okuyacağımız zaman kullanacağımız fonksiyon.
5- Main içerisinde gerekli olan fonksiyonları çağırıyoruz.
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();Scan_I2C_Address();
ADXL_Init();
6- While içerinde yapmamız gerekenler;
a- Adresi okuma
b- Hareket yönlerinin değerlerini okuma
c- Hareket yönlerindeki “G Kuvvet” değerlerini okuma.
ADXL_Read(0x32, 6);x = (data_rec[1] << 8) | data_rec[0];
y = (data_rec[3] << 8) | data_rec[2];
z = (data_rec[5] << 8) | data_rec[4];xg = x * .0078;// convert the x value g
yg = y * .0078;// convert the y value g
zg = z * .0078;// convert the z value gvoid Scan_I2C_Address(); Fonksiyonu.void Scan_I2C_Address(){
for(i=0; i<=255; i++){
if(HAL_I2C_IsDeviceReady(&hi2c1, i, 1, 10) == HAL_OK){
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_11);
break;}}
}i 0 dan 255’e kadar dönecek ve if koşulu da slave cihazın adresini kontrol edecek , mesela slave cihazın adresi 166 “Decimal : A6” , bu durumda i değeri 166 ya geldiğinde if koşulu “True” dönecek ve içeriye girecek. İçeriye giridiğinde led yanacak ve direkt olarak döngüyü break ile sonlandıracak bu sonlandırma işleminde i : 166 değerinde kalacaktır yani döngü sonlanınca i değeride en son olarak 166 sayısını alıp bünyesinde saklayacaktır , bu sayede ben adresimi bulup en yukarıya #define olarak tanımladım.void ADXL_Read(uint8_t reg, uint8_t numberOfBytes); Fonksiyonu.void ADXL_Read(uint8_t reg, uint8_t numberOfBytes){
HAL_I2C_Mem_Read(&hi2c1, ADXL_ADDRESS, memAddress, 1, data_rec, numberOfBytes, 100);
}Burada I2C protokolü ile cihazınımızın hafızasına direkt olarak işlem yapıyoruz. Cihazın hafızasındaki belli bölgelerde işlemler yapacağız bu işlemleri hafızadaki Register’lar üzerinden yazacağız.
HAL_I2C_Mem_Read ; Bu fonksiyon ile hafızaya direkt olarak erişeceğiz. Aşağıda bu fonksiyoonun içeriği hakında bilgiler verilmiştir..
&hi2c1 : Kartımızda Hal kütüphanesi ile hangi I2C portlarını kullanıysak onu seçiyoruz.
ADXL_ADDRESS : ADXL345 cihazın adresi.
memAddress : Cihazın hangi Registerına işlem yapılacksa o Registerın adresi buraya yazılır.
1 : Burada okuyacağınız Dahili Bellek adresinin boyutunu giriyoruz. (Bizim okuyacağımız adresin boyu 1 byte)
data_rec : Alınan adres bu diziye saklanır .
numberOfBytes : Gönderilen verinin boyutu.
100 : Timout.
10- void ADXL_Write(uint8_t memAddress, uint8_t value) Fonksiyonu.
void ADXL_Write(uint8_t memAddress, uint8_t value){
uint8_t data[2]={0};
data[0] = memAddress;
data[1] = value;
HAL_I2C_Master_Transmit(&hi2c1, ADXL_ADDRESS, data, 2, 100);
}
data[2]={0} : Bu diziyi direkt cihaza göndereceğiz ve içerisine aşağıdaki verileri koyacağız.
data[0] = memAddress : 0. index’e cihazın hangi Register’a gideceğini yazdık.
data[1] = value : 1. index’e cihaza gidecek değeri yazdık.
HAL_I2C_Master_Transmit ; Gönderici cihaz Master konumuda olduğu için “Master Gönderici” fonksiyonunu kullandık.
&hi2c1 : Kartımızda Hal kütüphanesi ile hangi I2C portlarını kullanıysak onu seçiyoruz.
ADXL_ADDRESS : ADXL345 cihazın adresi.
data : Oluşturduğumuz dizi.
2 : Gönderilen verinin boyutu.
100 : Timout.
11- ADXL_Init() Fonksiyonu.
void ADXL_Init(){
ADXL_Read(0x00, 1); // 0x00 Adresini oku ve geri dönen değer 0xE5 ise Çalışmaya başla
ADXL_Write(0x2D, 0); // Tüm verileri resetle
ADXL_Write(0x2D, 0x08); // Şu anlık sadece ölçü modunda başlattık.
ADXL_Write(0x31, 0x01); // Şu anlık sadece +-4g yapacağız.
}
001000 : 0x08 dir.
0x2D için;
Link : Dökümandan oku.
Auto Sleep : Otomatik Uyuklama.
Measure : Ölçüm yapar.
Sleep : Cihazı uyku moduna geçirir.
Wake up : Uyku modunda çalımaların hızını kontrol eder. Biz burda 0 yaparak 8Hz olarak ayarladık.
0x31 için;
0 0 : +-2g
0 1 : +-4g
1 0 : +-8g
1 1 : +-16g
D2,D3,D4,D5,D6,D7 verilerini Dökümandan okuyabilirsiniz.
0x2D ve 0x31 Registerındaki işlemleri daha iyi anlamak için dökümanı inceleyin ve açıklamları okuyun.
Şimdi While içerisine yazdığımız kodları detaylı inceleyelim.
a) ADXL_Read(0x32, 6); Bu fonksiyon okuma işlemi yapıyor peki nerden deyi okuyor? 0x32 Registeri bizim yön verilerimizi tutar ama sadece bu register değil , 0x32 – 0x36 arasındaki tüm registerlar bu değerleri tutar bizde bu yüzden 6 yazdık . Kısacası 0x32 adresinden başla 6 bytlık bir okuma yap buda 36 ya kadar tüm verileri oku demek bunlar oku ve verileri ADXL_Read fonksiyonu içerisindeki kodlar sayesinde ” data_rec ” adlı dizide tut.
b) Burada dikkat edilmesi gereken olaylar var;
1) x,y,z değişkenleri uint16_t cinsinden tanımlandı çünü 8 bit + 8bit toplamda 16 bitlik bir alana ihtiyacımız var .
2) x,y,z yönünde yapılan değerler yön olduğu için (+) ve (-) olarak hafızada tutulur.
3) Okunan x,y,z değerleri tek tek (+) yönde 8 bit , (-) yönde 8 bit toplamda 16 bitlik bir veri oluşturur.
4) Aşağıda görülen çizimde siyahlar(x) , kırmızılar(y) ve morlar(z) dir. Buradaki tablonun sol tarfına eksi(-) değerleri sağ tarafına artı(+) değerlerini kaydettik.
Aşağıdaki kod ile eksi değerleri 8 bit sola kaydırıp kayıt ettik ve diğerlerini olduğu gibi (veya) ile yanına yapıştırdık.
x = (data_rec[1] << 8) | data_rec[0];
y = (data_rec[3] << 8) | data_rec[2];
z = (data_rec[5] << 8) | data_rec[4];
Bu şekilde 8 bitlik eksi ve artı yönleri bir diziye kayıt ettik bu saaten sonra bu diziyi nerde kullanmak istersek kullanabiliriz.
c) Son olarak x,y,z yönlerinin “g” yi bulmak kalıyor.
Biz (+-4g) olarak işlem yapıyoruz, bu tabloda çıkış çözünürlüğümüz 11 bit ve g yi hesaplarken kullanacağımız bilgiler de ” Sensitivity Deviation from Ideal” kısmındaki sarı ile çizilmiş bölgede yer alıyor. Burada “7.8” değerinin yanında mg işareti var bunu grama çevirirsek “0.0078 ” gram olarak buluruz. Hadi bunu formüle sokalım ve “g” değerini elde edelim.
xg = x * .0078;
yg = y * .0078;
zg = z * .0078;
İlk başta bulduğumuz x,y,z değerini “0.0078” ile çarparak x,y ve z ye ait “g” değerlerini bulabiliriz.
Tüm Kod:





