STM32 (STM32F107) ile LIS302DL ivme ölçer kullanımı

| Haziran 19, 2023 Tarihinde güncellendi
STM32 (STM32F107) ile LIS302DL ivme ölçer kullanımı

Arkadaşlar Merhaba C ve ARM ile tanıştıktan sonra artık Pic leri gözüm görmez oldu 🙂 Bende hazır ARM ye ısınmışken bir proje daha yapayım dedim. Bu Yazımda LIS302DL 3 eksen ivme ölçer kullanımına biraz göz attım. Kısaca kullanımından bahsedeceğim.

Bu uygulamamda LIS302DL ‘den eksen bilgilerini okuyup TFT ekranda Bargraph olarak olarak gösterip ardından Bilgisayar Arayüzünde Ve X, Y, Z eksenlerinin değişimini grafik olarak gösterip ayrıca açılarını hesapladım.

LIS302DL Sensörü ST firmasının ürettiği, 3 eksen bir ivme ölçerdir. 2.3g ve9.2g olmak üzere iki adet çalışma modu vardır. Ayrıca SPI ve I2C ile haberleşebilmektedir. Benim elimdeki MCBSTM32C board üzerindeki ivme sensörü STM32F107 ye I2C hattı üzerinden bağlanmış. Dolayısıyla bende STM32F107 nin I2C donanımını kullanarak sensörle haberleştim.

Sensörün Datasheetine Buradan ulaşabilirsiniz.

LIS302DL nin kullanımı gerçekten çok basit. Kendi içerisinde çok fazla register yok. Biz sadece CONTROL_REG1 registeri üzerinde ayarlamalar yaparak sensörü kullanıma hazır hale getiriyoruz.

CONTROL_REG1 Registerinin içeriği aşağıdaki tabloda gösterilmiş.

stm32-lis302dl-control_reg1

Burada ;

DR biti, veri hızı seçim bitidir. “1″ Olursa 400Hz, “0″ olursa 100Hz Modunda çalışır. Biz 100Hz modunda kullanıyoruz.

PD biti, Power Down Control diye adlandırılmış. Anladığım kadarıyla Gerektiğinde sensörün ölçüm işlemi durdurulmak istendiğinde Bu bit “0″ yapılarak Sensör Power Down Moduna sokuluyor. Normade biz bu biti “1″ Yapmamız gerekiyor.

FS biti “Full Scale Select” bitidir. Bu bit “0″ Olursa sensör 2.3g modunda, “1″ olursa 9.2g modunda çalışıyor. Ben çıkıştaki değişimleri daha rahat görebilmem için sensörü 2.3g modunda çalıştırıyorum.

STP, STM Bitleri Self Test Enable olarak geçiyor. Normal çalışmada bu iki bit “0″ olması gerekiyor

Xen, Yen, Zen Bitleri X, Y, Z eksenlerinin Enable Bitleridir “1″ olursa Aktif, “0″olursa Pasif olur.

Sensörü kullanıma hazır hale getirmek için min. yapılması gereken ayarlar bunlardır.

Şimdi işin yazılım kısmına bakalım

Sensör yukarıda Bahsettiğim gibi MCBSTM32C Deney board’ın da STM32F107 nin I2C1 (PB8, PB9) Donanımına Bağlandığı için bende I2C donanımını kullanmak zorunda kaldım. Bu vesileyle Favori işlemcim olan STM32F10X serisinde I2C haberleşmesi üzerinede tecrübe sahibi olmuş oldum.

STM32F10X serisinde I2C donanımını çalıştırmak açıkçası çok uğraştırdı. İlk başta ST kütüphanesiyle yapayım dedim. Nerden baksanız 3-4 gün ST kütüphanesi kullanılarak yazılmış Farklı I2C rutinlerini çalıştırmak için uğraştım. ST kütüphanesini çalıştıramayınca bende kütüphane kullanılmadan yazılmış olan (Bu Arada bunun adı Low Level miş. 🙂 ) I2C Rutinlerini buldum. Bu kodlar sayesinde işlemcinin I2C donanımını çalıştırıp sensör ile haberleşebildim.

Şuan kullandığım I2C koları I2C.h

/******************************************************************************/
/* I2C.h: I2C function prototypes */
/******************************************************************************/
/* This file is part of the uVision/ARM development tools. */
/* Copyright (c) 2005-2009 Keil Software. All rights reserved. */
/* This software may only be used under the terms of a valid, current, */
/* end user licence from KEIL for a compatible version of KEIL software */
/* development tools. Nothing else gives you the right to use this software. */
/******************************************************************************/

#include "stm32f10x_lib.h"
#include <stdint.h>

#ifndef _I2C_H
#define _I2C_H

extern void I2C_Setup (void);
extern void I2C_Start (void);
extern void I2C_Stop (void);
extern void I2C_Addr (unsigned char adr);
extern void I2C_Write (unsigned char c);
extern unsigned char I2C_Read (int ack);
extern unsigned char I2C_getbyte(unsigned char address, unsigned char cmd);
extern void I2C_putbyte(unsigned char address, unsigned char cmd, unsigned char data);
extern unsigned short int I2C_getword(unsigned char address, unsigned char cmd);
#endif /* _I2C_H */

I2C.c

/******************************************************************************/
/* I2C_STM32.c: STM32 low level I2C routines */
/******************************************************************************/
/* This file is part of the uVision/ARM development tools. */
/* Copyright (c) 2005-2009 Keil Software. All rights reserved. */
/* This software may only be used under the terms of a valid, current, */
/* end user licence from KEIL for a compatible version of KEIL software */
/* development tools. Nothing else gives you the right to use this software. */
/******************************************************************************/

#include "I2C.h"

/************************ Local auxiliary functions ***************************/

/*******************************************************************************
* I2C communication status *
* Parameter: *
* Return: status *
*******************************************************************************/

static __inline unsigned int I2C_sr (void) {
unsigned int sr;

sr = I2C1->SR1;
sr |= I2C1->SR2 << 16;
return (sr);
}

/************************ Exported functions **********************************/

/*******************************************************************************
* Initialize I2C interface in master mode *
* Parameter: *
* Return: *
*******************************************************************************/

void I2C_Setup (void) {
unsigned int tout;

/* Enable clock for I2C1, GPIOB and AFIO */
RCC->APB2ENR |= (1 << 3) | (1 << 0); //
RCC->APB1ENR |= (1 << 21);

/* I2C1 pins remapped, use PB8, PB9 */
AFIO->MAPR |= 0x00000002; // Remap=1: (SCL/PB8, SDA/PB9)
GPIOB->CRH |= 0x000000FF; // Alternate IO PB8 and PB9

I2C1->CR1 = 0x8000; /* Reset I2C peripheral */
for (tout = 1000000; tout; tout--);
I2C1->CR1 = 0x0000;

/* Configure I2C peripheral */
I2C1->CR1 = 0x0001; // PE - Peripheral Enable
I2C1->CR2 = 0x0024; // Freq 36 MHz
I2C1->CR1 = 0x0000; // PE Disable
I2C1->TRISE = 0x0025; //Time Rise - program when PE=0
I2C1->CCR = 0x00B4; // 0x005A = 400 KHz (36MHz / 90) 0x00B4 = 200 KHz
I2C1->CR1 |= 0x0401;
I2C1->OAR1 = 0x40A0;
}
/*******************************************************************************
* Generate start condition on I2C bus *
* Parameter: *
* Return: *
*******************************************************************************/

void I2C_Start (void) {
if ( I2C1->CR1 & ( 1 << 10 ) ) {
I2C1->CR1 &= ~(1 << 10 );
}
I2C1->CR1 |= 0x0100; //start genneration when bus free
while (!(I2C_sr() & 0x0001));
}

/*******************************************************************************
* Generate stop condition on I2C bus *
* Parameter: *
* Return: *
*******************************************************************************/

void I2C_Stop (void) {

I2C1->CR1 |= 0x0200;
while (I2C_sr() & 0x00020000); /* Wait until BUSY bit reset */
}
/*******************************************************************************
* Write address on I2C interface *
* Parameter: adr: address to be written *
* Return: *
*******************************************************************************/

void I2C_Addr (unsigned char adr) {

I2C1->DR = adr;
while (!(I2C_sr() & 0x0002)); //Addr sent
}
/*******************************************************************************
* Write a byte to I2C interface *
* Parameter: c: data to be written *
* Return: *
*******************************************************************************/

void I2C_Write (unsigned char c) {

I2C1->DR = c;
while (!(I2C_sr() & 0x00000004)); /* Wait until BTF bit set */
}
/*******************************************************************************
* Read a byte from I2C interface *
* Parameter: *
* Return: read data *
*******************************************************************************/

unsigned char I2C_Read (int ack) {

/* Enable/disable Master acknowledge */
if (ack) I2C1->CR1 |= 0x0400;
else I2C1->CR1 &= ~0x0400;

while (!(I2C_sr() & 0x00000040)); /* Wait until RxNE bit set */
return (I2C1->DR);
}

/******************************************************************************/

unsigned char I2C_getbyte(unsigned char address, unsigned char cmd) {
unsigned char uc;
I2C_Start(); // Initial Start bit sequence
I2C_Addr(address); // Address I2C Device. (Base address is Write Address)
I2C_Write(cmd); // Transfer Command to I2C Device (Register to be Read)
I2C_Start(); // Repeated start bit sequence
I2C_Addr(address+1); // Address I2C Device. (Base address + 1 is Read Address)
uc = I2C_Read(0); // Read 1 byte without Acknowledge
I2C_Stop(); // Stop I2C transfer
return( uc );
}

unsigned short int I2C_getword(unsigned char address, unsigned char cmd) {
unsigned short int uw;
//unsigned short int uw2;
I2C_Start(); // Initial Start bit sequence
I2C_Addr(address); // Address I2C Device. (Base address is Write Address)
I2C_Write(cmd); // Transfer Command to I2C Device (Register to be Read)
I2C_Start(); // Repeated start bit sequence
I2C_Addr(address+1); // Address I2C Device. (Base address + 1 is Read Address)
uw = I2C_Read(1) << 8; // Read MSB without Acknowledge
uw |= I2C_Read(0); // Read LSB with Acknowledge
I2C_Stop(); // Stop I2C transfer
return( uw );
}
void I2C_putbyte(unsigned char address, unsigned char cmd, unsigned char data) {
I2C_Start(); // Initial Start bit sequence
I2C_Addr(address); // Address I2C Device. (Base address is Write Address)
I2C_Write(cmd); // Transfer Command to I2C Device (Register to be Read)
I2C_Write(data); // Transfer Data to I2C device
I2C_Stop(); // Stop I2C transfer
}

int I2C_getbytearray(unsigned char address, unsigned char cmd, int number, unsigned char *data) {
int count;
I2C_Start(); // Initial Start bit sequence
I2C_Addr(address); // Address I2C Device. (Base address is Write Address)
I2C_Write(cmd); // Transfer Command to I2C Device (Register to be Read)
I2C_Start(); // Repeated start bit sequence
I2C_Addr(address+1); // Address I2C Device. (Base address + 1 is Read Address)
// Read number - 1 bytes with Acknowledge
for ( count=0; count < number - 2; count++ ) {
data[count] = I2C_Read(1); // Read with Acknowledge
}
data[count] = I2C_Read(0); // Last byte without Acknowledge
I2C_Stop(); // Stop I2C transfer
return( count+1 );
}

Kütüphanenin kullanımı çok basit zaten.

Şimdi Main programına bakalım main.c

////////////////////////////////////////////////////////////////////////////////
// Author : [Ferhat YOL] /
// Notice : Copyright (c) 2012 /
// : All Rights Reserved /
// Date : 08-03-2013 /
// Version : 1.0.0 /
// Board : MCBSTM32C /
// MCU : STM32F107VC /
// Notes : LCD Controller SPFD5408 /
// Accelerometer LIS302DL /
////////////////////////////////////////////////////////////////////////////////

#include "stm32f107.h"
#include "string.h"
#include "stdint.h"
#include "stdlib.h"
#include "stdio.h"

signed char xaxis;
signed char yaxis;
signed char zaxis;
signed char xaxis_old;
signed char yaxis_old;
signed char zaxis_old;
uint16_t xbar_value;
uint16_t ybar_value;
uint16_t zbar_value;
uint8_t temp_data;
uint8_t delay=10;
unsigned int Sensor_Data;

BOOL tempx;
BOOL tempy;
BOOL tempz;
BOOL Tx_En=0;

char buffer[10];
char ubuffer[20];

int main()
{
SystemInit(); // Sistem Ayarlari yapiliyor..
initRS232(9600); // RS232 Ayarlamalari yapiliyor
setTimer1(1000,0,0); // Timer Ayarlamalari yapiliyor..
GLCD_Init(); // Grafik LCD Ayarlamalari Yapiliyor
I2C_Setup(); // I2C Donanim Ayarlari Yapiliyor.

setOutMode(portE,0xFFFF); // PortE Çikis Yapildi

Sensor_Data = I2C_getbyte(0x38, 0x0f); // Sensör Kimligi Tanimlaniyor.
I2C_putbyte(0x38,0x20,0x47); // Xen=1, Yen=1, Zen=1, Pd=1
/****************Giris**************************************************/
GLCD_Clear(White);
GLCD_SetBackColor(Cyan);
GLCD_SetTextColor(Black);
GLCD_DisplayString(0,0,1,"STM32F107VC CortexM3");
GLCD_DisplayString(1,0,1,"LIS302 Accelerometer");
GLCD_SetTextColor(Red);
GLCD_SetBackColor(Black);
GLCD_DisplayString(9,0,1,"Baglanti Bekleniyor!");

while(1){

xaxis=I2C_getbyte(0x38,0x29); //X Ekseni okunuyor..
yaxis=I2C_getbyte(0x38,0x2b); //Y Ekseni okunuyor..
zaxis=I2C_getbyte(0x38,0x2d); //Z Ekseni okunuyor..

/* **Text Basim Rutini** */
GLCD_SetBackColor(White);
GLCD_SetTextColor(Red);
sprintf( buffer,"X: %2hd ",(short int)xaxis);
GLCD_DisplayString(3,0,1,buffer);
GLCD_SetTextColor(Blue);
sprintf( buffer,"Y: %2hd ",(short int)yaxis);
GLCD_DisplayString(5,0,1,buffer);
GLCD_SetTextColor(Green);
sprintf( buffer,"Z: %2hd ",(short int)zaxis);
GLCD_DisplayString(7,0,1,buffer);

/* **Bar Olusturma Rutini** */
if(xaxis>=0) //X Ekseni Basiliyor.
{
if(tempx==0)
{
tempx=1;
GLCD_SetBackColor(Red);
GLCD_SetTextColor(White);
GLCD_Bargraph(120,72,90,20,1024);
}
GLCD_SetBackColor(White);
GLCD_SetTextColor(Red);
xbar_value=(xaxis*256)/15;
GLCD_Bargraph(210,72,90,20,xbar_value);
}else if(xaxis<0)
{ if(tempx==1)
{
tempx=0;
GLCD_SetBackColor(White);
GLCD_SetTextColor(Red);
GLCD_Bargraph(210,72,90,20,0);
}
GLCD_SetBackColor(Red);
GLCD_SetTextColor(White);
xbar_value=((abs(xaxis))*256)/15;
GLCD_Bargraph(120,72,90,20,(1024-xbar_value));
}
if(yaxis>=0) //Y Ekseni Basiliyor.
{
if(tempy==0)
{
tempy=1;
GLCD_SetBackColor(Blue);
GLCD_SetTextColor(White);
GLCD_Bargraph(120,120,90,20,1024);
}
GLCD_SetBackColor(White);
GLCD_SetTextColor(Blue);
ybar_value=(yaxis*256)/15;
GLCD_Bargraph(210,120,90,20,ybar_value);
}else if(yaxis<0)
{ if(tempy==1)
{
tempy=0;
GLCD_SetBackColor(White);
GLCD_SetTextColor(Blue);
GLCD_Bargraph(210,120,90,20,0);
}
GLCD_SetBackColor(Blue);
GLCD_SetTextColor(White);
ybar_value=((abs(yaxis))*256)/15;
GLCD_Bargraph(120,120,90,20,(1024-ybar_value));
}
if(zaxis>=0) //Z Ekseni Basiliyor.
{
if(tempz==0)
{
tempz=1;
GLCD_SetBackColor(Green);
GLCD_SetTextColor(White);
GLCD_Bargraph(120,168,90,20,1024);
}
GLCD_SetBackColor(White);
GLCD_SetTextColor(Green);
zbar_value=(zaxis*256)/20;
GLCD_Bargraph(210,168,90,20,zbar_value);
}else if(zaxis<0)
{ if(tempz==1)
{
tempz=0;
GLCD_SetBackColor(White);
GLCD_SetTextColor(Green);
GLCD_Bargraph(210,168,90,20,0);
}
GLCD_SetBackColor(Green);
GLCD_SetTextColor(White);
zbar_value=((abs(zaxis))*256)/20;
GLCD_Bargraph(120,168,90,20,(1024-zbar_value));
}
if(temp_data>9 && temp_data<201) delay=temp_data;
if(temp_data==5)
{
Tx_En=1; // Data Gönderimi Aktif...
GLCD_SetBackColor(Black);
GLCD_SetTextColor(Green);
GLCD_DisplayString(9,0,1," Baglanti Kuruldu ");
}
if(temp_data==6)
{
Tx_En=0; // Data Gönderimi Pasif...
GLCD_SetBackColor(Black);
GLCD_SetTextColor(Red);
GLCD_DisplayString(9,0,1," Baglanti Kesildi ");
}

if(Tx_En)
{
sprintf(ubuffer,"X%03hdY%03hdZ%03hd;",(short int)xaxis,(short int)yaxis,(short int)zaxis);
Rs232_SendData(ubuffer);
}

delayMs(delay);
}
}

void Timer1_Interrupt()
{
temp_data=rs232ReadData();
}

Burada işlemciyi 8Mhz Dahili osilatörü ile çalıştırıyorum. Bu OSC değeri girişte 2′ye bölünüp ardında PLLMUL çarpanıyla 16 ya katlanıyor. Dolayısıyla işlemci 64Mhz de çalışıyor.

Deney bordu ile birlikte gelen TFT nin üzerinde SPDF5408 sürücü çipi bulunuyor. SPDF5408 sürücü kütüphanesini keilin örnek kodlarından aldım. Bu uygulamada görsellik açısından çok iyi oldu 🙂

Ayrıca TFT kütüphanesinde BarGraph rutuni çok iyi hazırlanmış. Bargraph için açılan pencerenin boyutu ne olursa olsun. Bargraph 0-1023 arası değer alıyor. Dolayısıyla Bar boyutu değiştiğinde Bar’ın max değeriyle uğraşmak gerekmiyor.

Sensör çıkışı +-0-127 arasında bir çıkış değeri verir. Normalde sensörden 60dan yukarı değerler almak için bayağı bir kuvvet uygulamak gerekiyor. Bu yüzden bende Sensörden 60 değeri gelince Bar değeri 1024 olacak şekilde ayarladım. Bunun için Aşağıdaki işlemi yapmak gerekiyor.

xbar_value=(xaxis*256)/15;

Normalde dünya üzerinde yer çekim ivmesi bulunan coğrafi bölgeye göre g =9,8065 m/s² (Tübitak) civarındadır. Bu sebebden ötürü sensör düz bir zeminde olmasına rağmen sürekli olarak 55-60 Arasında bir değer alınıyor. Aşağıdaki resimde yaptığım uygulamanın görüntüsünü görebilirsiniz. Buradan daha net anlaşılıyor.

lis302dl-xbar_value-x-axis25615-stm32-usart2-porta-rx-tx

Aldığım eksen bilgilerini bilgisayara göndermek için STM32 nin Usart2 modülünü kullandım. Elimdeki boardda ki Com bağlantı noktası PortD ye bağlandığı için Usart2 nin Remap Modunu aktif etmek gerekiyor. Aksi hale PortA da ki Rx ve TX pinleri aktif olur.

Ayrıca Timer1 kesmesi ile Usart Rx bufferine sürekli bakarak Bilgisayar programından gelen Dataları alıyorum. Aslında Timer1 Kesmesi bu iş için kulanılmaz Usart Recieve kesmesi daha uygun olurdu. Timer donanımım hazır olduğu için açıkçası kolaya kaçtım biraz 😀

Kullandığım Usart kütüphanesi aşağıdaki gibidir. Usart konfigürasyonu, Seri Data alım ve gönderim rutinleri bu kütüphane içerisinde gerçekleştiriliyor.

#include "stm32f10x_lib.h"
#include "main.h"

/*********************************************************//***/
void initRS232(int baud);
void Send_Data(char data);
void Rs232_SendData(char *data);
char rs232ReadData(void); //göndereci taraftan gonderilen datalari char cahar okur.
/*********************************************************//***/

vu8 TxCounter = 0x00;
char RxBuffer1[16];
vu8 RxCounter1=0;

/********************************setRS232*****************************************/
/*
* USAR1 modulunu belirtilen baud hizinda setler
* TX portA nin 9. pini, RX portA nin 10. pini olarak ayarlanmistir
* istenirse bu degerler degistirilebilir.
*/
void initRS232(int baud){

USART_InitTypeDef USART_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);

// Configure USART2 Tx (PA.2) as alternate function push-pull
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOD, &GPIO_InitStructure);

// Configure USART2 Rx (PA.3) as input floating
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOD, &GPIO_InitStructure);

GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

USART_InitStructure.USART_BaudRate = baud;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

USART_Init(USART2, &USART_InitStructure);

/*USART2 alim-gönderim kesmeleri aktif*/
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
USART_ITConfig(USART2, USART_IT_TXE, ENABLE);

/* USART2 Aktif*/
USART_Cmd(USART2, ENABLE);
}

void Send_Data(char data){
while(!(USART2->SR & 0x80));{} //Bufferin Bosalmasini bekliyoruz
USART_ITConfig(USART2, USART_IT_TXE, ENABLE);
if(USART_GetITStatus(USART2, USART_IT_TXE) != RESET)
{
USART_SendData(USART2, data);
USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
}
}

void Rs232_SendData(char *data){
int i;
for (i=0;data[i]!=0;i++)
{
Send_Data(data[i]);
}

}
//************************************************************************************/
char rs232ReadData(){
return USART_ReceiveData(USART2);
}

Bilgisayar ile haberleşme çift yönlü olarak gerçekleşiyor. C# programı ile bağlantı gerçekleştiği zaman hemen veriler bilgisayar tarafına aktarılmaya başlanıyor. Ayrıca ekran güncelleme hızını da ayarlanabilir yaptım. Bilgisayar ile bağlantı kurulduğu zaman hemen 10 ile 200ms arasında ekran güncellemesi ayarlanabiliyor.

Son olarak biraz C# programından bahsedeceğim.

C#da seri port kullanımı çok basit.

ilk önce toolbox içerisinden serial port nesnesini formumuza sürüklüyoruz.

Ardından seri portun ayarları yapılması gerekiyor. Bizi ilgilendiren 2 ayar var. Bunların kullanımı aşağıdaki gibidir.

serialPort1.PortName =”COM1″
serialPort1.BaudRate = 9600;

Bu ayarları yaptıktan sonra Portu Kullanıma açıyoruz. Bu iş için serialPort1.Open(); komutunu kullanıyoruz.

Tabi Ben bu işlemleri programda biraz daha işlevsel yaptım. Mesela Programı ilk çalıştırdığınızda Program bilgisayara bağlı olan com portları tarayıp otomatikmen ComboBox içerisinde listeler.

Tasarlamış olduğum Formun görüntüsü aşağıdaki gibidir.

haberlesme-cift-yonlu-olarak-gerceklesiyor-c-programi

Program üzerinde Sağ üst Tarafta İvme ölçerden okunan değerler Gösterilir. Hemen Altında ise Bu okunan değerlerin açısal karşılığı yazılır. Okunan X, Y ve Z eksenlerinin açıya dönüştürmek için Aşağıdaki formülü kullanıyorum.

okunan-x-y-z-eksenlerinin-aciya-donusturmek

Fakat bu formül Bilgisayar tarafında koşuyor. Fakat bilgisayar üzerindeki Arctan ve Sqrt fonksiyonları radyan cinsinden çıkış verdiği için birde bu değerleri Dereceye çevirmek gerekiyor. Sonuç Yukarıdaki resmin koda dönüşmüş hali aşağıdaki gibidir.

Xangle = (Math.Atan(Xaxis / Math.Sqrt(Yaxis * Yaxis + Zaxis * Zaxis)) * 180) / Math.PI;
Xangle = Math.Round(Xangle, 1);
Yangle = (Math.Atan(Yaxis / Math.Sqrt(Xaxis * Xaxis + Zaxis * Zaxis)) * 180) / Math.PI;
Yangle = Math.Round(Yangle, 1);
Zangle = (Math.Atan(Zaxis / Math.Sqrt(Xaxis * Xaxis + Yaxis * Yaxis)) * 180) / Math.PI;
Zangle = Math.Round(Zangle, 1);

Elde edilen değerler çok küsüratlı oluyor.(Tahminimce virgülden sonra en az 10 hane 🙂 ) Bu yüzden alınan değerleri yuvarlamak gerekiyor. C# da Math.Round fonksiyonu bu işi yapıyor. İçeriğindeki birinci parametre Yuvarlanacak olan değer, ikinci parametre virgülden sonra kaç hanenin yuvarlanacığını belirtiyor. Sonuç olarak bize yuvarlanmış halini geri getiriyor.

Karttan gelen Eksen bilgilerini Grafiğe basmak için aşağıdaki kodları kullanıyorum.

Grafiğin sola kayması için Her eksene 100 boyutlu bir dizi belirledim Karttan her veri geldiğinde ilk başta bu dizinin elemanlarını bir birim sola kaydırıp dizinin en son elemanına yeni gelen datayı ekliyorum. Sonra grafikteki eski noktaları silip yeni noktaları basıyorum. Bu işlem her yeni bir bilgi geldiğinde yaptığım için grafiğin kayma hızı veri akış hızıyla doğru orantılıdır.

Örneğin X ekseninden gelen verileri grafiğe basmak için aşağıdaki kodları kullandım.


for (i = 0; i < 99; i++) //Dizi elemanlarını 1 birim sola kaydırıyoruz.
{
Xdizi[i] = Xdizi[i + 1];
}
Xdizi[99] = Xaxis; //Dizinin Son elemanına yeni değer ekleniyor.
chart1.Series[0].Points.Clear();
for (i = 0; i < 99; i++)
{
chart1.Series[0].Points.Add(Xdizi[i]);
}

Görüldüğü gibi mantığı çok basit.

Birkaç video çektim.

Buradaki videoda C# programında kartın hareketiyle birlikte grafikteki değişimi görebilirsiniz.

Şimdilik yazacaklarım bu kadar. Umarım faydalı bir örnek olmuştur. İyi çalışmalar..

stm32-stm32f107-ile-lis302dl-ivme-olcer-kullanimi

Şifre-Pass: 320volt.com

Yayım tarihi: 2013/05/04 Etiketler: , , , , ,



2 Yorum “STM32 (STM32F107) ile LIS302DL ivme ölçer kullanımı

  1. Abdülkadir nohutAbdülkadir nohut

    Selam merhaba yaptığınız ivme uygulamasını ben mma7361L ile yapmaya çalıştım.Adc değerleri okuyorum ama sizin yazdığınız formüle göre açıları doğru ölçemiyorum.Benim ivme sensörüm 1,65 volt üzerine çıkınca pozitif ivme altına düşerse negatif yönde ivme oluyor.Doğru ölçme için ne yapmalıyım.

    kodlar:

    int Xaxis,Yaxis,Zaxis;
    Xaxis = Convert.ToInt32(x_str.Text);
    // digitale çevrilmiş olarak gelen veri(18f2550 içinden adc den)
    Yaxis = Convert.ToInt32(y_str.Text);
    Zaxis = Convert.ToInt32(z_str.Text);

    double Xangle, Yangle, Zangle;

    Xangle = (Math.Atan(Xaxis / Math.Sqrt(Yaxis * Yaxis + Zaxis * Zaxis))*180) / Math.PI;
    Xangle = Math.Round(Xangle, 1);
    label5.Text = Xangle.ToString() + “C”;

    Yangle = (Math.Atan(Yaxis / Math.Sqrt(Yaxis * Yaxis + Zaxis * Zaxis)) * 180) / Math.PI;
    Xangle = Math.Round(Xangle, 1);
    label6.Text = Xangle.ToString() + “C”;

    Yangle = (Math.Atan(Zaxis / Math.Sqrt(Yaxis * Yaxis + Zaxis * Zaxis)) * 180) / Math.PI;
    Xangle = Math.Round(Xangle, 1);
    label7.Text = Xangle.ToString() + “C”;

    CEVAPLA
  2. Abdülkadir NOHUTAbdülkadir NOHUT

    Xangle = (Math.Atan(Xaxis / Math.Sqrt(Yaxis * Yaxis + Zaxis * Zaxis)) * 180) / Math.PI;

    Selam merhaba Mucit23 aşağıdakidaki komut satırı bize sonuç olarak radyan veriyor.Bu sonucu açıya çevirmek için 180 ile çarptık doğru değilmi?Neden pi ye böldük anlamadım cevap yazabilirmisiniz.Çalışmanız güzel olmuş teşekkür ederim.

    (Math.Atan(Xaxis / Math.Sqrt(Yaxis * Yaxis + Zaxis * Zaxis))

    CEVAPLA

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir