Giao tiếp I2C với cảm biến MMA8452Q

Nguyentridung

Thành Viên PIF
Em đang dùng I2C để giao tiếp với cảm biến gia tốc MMA8452Q, đoạn code em viết như sau:

#include <msp430.h>
#include "I2C.h"
#include "Basic_Config.h"

unsigned int dataxyz[6];
int x_acce, y_acce, z_acce;

/*
* main.c
*/
void main() {
WDTCTL = WDTPW | WDTHOLD;// Stop watchdog timer
Config_Clocks();
i2c_init(0x1C);// 0: write; 1: read; address 0011100
_delay_cycles(500000);

i2c_write(0x2A,1,0x18); // Output Data Rate 100KHz
i2c_write(0x0E,1,0x00); // Output buffer format Full scale (2g) 1024/g

while (1){
i2c_read(0x01,6,dataxyz);
x_acce = (dataxyz[0]<<4) + (dataxyz[1]>>4);
y_acce = (dataxyz[2]<<4) + (dataxyz[3]>>4);
z_acce = (dataxyz[4]<<4) + (dataxyz[5]>>4);

}
}
Sau khi đổ code thì không có lỗi, warning: function declared implicitly ngay chỗ cái i2c_write(,,). debug thì thấy nó không thoát được khỏi vòng lặp trong hàm i2c_write. Cả 2 hàm i2c_write và i2c_read em lấy trong driver chép hôm bữa.
Không biết code em viết sai chỗ nào, anh xem dùm em.
Em cảm ơn
 

vodanhbk

Trứng gà
Mình cũng đang tìm hiểu về cảm biến này, vẫn chưa ra đâu cả.
Mình thắc mắc code driver i2c trên câu lạc bộ dùng cho cảm biến này được không?
Mong club xem xét tình hình.
 

Tan Sy Nguyen

Cố Vấn CLB
Staff member
vodanhbk: Mọi protocol đều là chuẩn, và có quy định của nó. Nếu đã là cảm biến hỗ trợ I2C thì dùng thư viện I2C đọc đều được, bất kể là con cảm biến nào. Trên 4rum có rất nhiều sample code về I2C, các bạn xem thử và áp dụng. Các bạn khóa trước cũng đã dùng thư viện này và kết nối thành công với cảm biến trên.
Nguyentridung: trong i2c_write có mấy cái vòng lặp, ko biết bạn đang đứng ở vòng lặp nào. rất có thể là bạn gửi ko đúng request nên cảm biến ko response về, và thế là vòng lặp chờ tín hiệu response lặp vô tận luôn. Cảm biến này cũng khá nhiều người làm về nó rồi, bạn xem thử trên mạng có sample code chưa rồi áp dụng. Chúc bạn may mắn :1cool_byebye:
 

vodanhbk

Trứng gà
vodanhbk: Mọi protocol đều là chuẩn, và có quy định của nó. Nếu đã là cảm biến hỗ trợ I2C thì dùng thư viện I2C đọc đều được, bất kể là con cảm biến nào. Trên 4rum có rất nhiều sample code về I2C, các bạn xem thử và áp dụng. Các bạn khóa trước cũng đã dùng thư viện này và kết nối thành công với cảm biến trên.
Nguyentridung: trong i2c_write có mấy cái vòng lặp, ko biết bạn đang đứng ở vòng lặp nào. rất có thể là bạn gửi ko đúng request nên cảm biến ko response về, và thế là vòng lặp chờ tín hiệu response lặp vô tận luôn. Cảm biến này cũng khá nhiều người làm về nó rồi, bạn xem thử trên mạng có sample code chưa rồi áp dụng. Chúc bạn may mắn :1cool_byebye:

Em cũng dùng thư viện i2c mà Club chia sẻ thì bị lặp vô tận chỗ này:

Code:
void i2c_write(unsigned char AddRes,unsigned char numbyte, unsigned char *poisend)
{
    while (UCB0CTL1 & UCTXSTP);                // Loop until I2C STT is sent
    UCB0CTL1 |= UCTR + UCTXSTT;                // I2C TX, start condition
   
    while (!(IFG2&UCB0TXIFG)); 
    UCB0TXBUF = AddRes;
     
    while (!(IFG2&UCB0TXIFG));  // [COLOR=#ff0000]bị đứng mãi chỗ này.[/COLOR]
    unsigned char i;
    for( i=0;i<numbyte;i++)
      {
        UCB0TXBUF= *(poisend+i) ;
        while (!(IFG2&UCB0TXIFG)); 
      }
    UCB0CTL1 |= UCTXSTP;                      // I2C stop condition after 1st TX
    IFG2 &= ~UCB0TXIFG;                        // Clear USCI_B0 TX int flag 
}
 

vodanhbk

Trứng gà
Có anh chị nào đã làm về con này rồi share sample code với, nghiên cứu con này cả tuần rồi mà bị kẹt ngay chỗ i2c, không thể nào read hay write được
 
H

huunho

Guest
bạn phải đứ cả project lên thì anh em mới giúp được, hay thử viết trên asm để debug cho dễ
 

vodanhbk

Trứng gà
Đây là code em thử đọc giá trị 1 thanh ghi trong cảm biến để set active cho nó. Chương trình bị lặp vô hạn ờ dòng mà em post ở trên.
PHP:
#include <msp430g2553.h>
#include "I2C.h"
#include "Basic_Config.h"
 
#define MMA8452Q_ADDRESS = 0x1D;
// Breakout board defaults to 1, set to 0x1C if SA0 jumper is set
 
// Some register names
#define MMA8452Q_STATUS        (0x00)
#define MMA8452Q_OUT_X_MSB    (0x01)
#define MMA8452Q_XYZ_DATA_CFG    (0x0E)
#define MMA8452Q_OFF_X    (0x2F)
#define MMA8452Q_OFF_Y    (0x30)
#define MMA8452Q_OFF_Z    (0x31)
#define MMA8452Q_CTRL_REG1    (0x2A)
#define MMA8452Q_CTRL_REG2    (0x2B)
#define MMA8452Q_CTRL_REG3    (0x2C)
#define MMA8452Q_CTRL_REG4    (0x2D)
#define MMA8452Q_CTRL_REG5    (0x2E)
#define MMA8452Q_WHO_AM_I    (0x0D)
 
#define MMA8452Q_WHO_AM_I_VALUE    (0x2A)
 
#define MMA8452Q_ZYXDR        (0x80)    // data ready status bit
 
 
unsigned char data[];
//main
void main()
{
    Config_stop_WDT(); // stop WDT, see description in Basic_config.c
  Config_Clocks();
  P2SEL &=  ~BIT6 + ~BIT7; // 2.6,2.7 are GPIO
  P2SEL2 &=  ~BIT6 + ~BIT7;
  i2c_init(0x1D);  //slave adress (SA0 is high
 
  //set mma in active mode
  i2c_read(MMA8452Q_CTRL_REG1,1,data);
  data[0] |= 0x01;
  i2c_write(MMA8452Q_CTRL_REG1,1,data);
}
 

honghiep

Cố Vấn CLB
Staff member
~BIT6 + ~BIT7; Bạn lưu ý là dòng này khác với ~(BIT6 + BIT7)
Vì vậy việc config P2.6 và P2.7 thành GPIO là sai nhé
 

vodanhbk

Trứng gà
mà hai dòng này cũng không liên quan đến quá trình đọc i2c mà, em thử bỏ và vẫn vậy
 

nguyễn đình huân

Cố Vấn CLB
bạn xem lại phần khai báo hàm i2c_write trong file i2c.h có thể sai chính tả(lúc trước mình cũng bị :D), với lại đọc i2c bạn kiểm tra thử xem mấy byte đầu tiên của dữ liệu đọc về có phải là dữ liệu bạn cần không nhé.
 

vodanhbk

Trứng gà
bạn xem lại phần khai báo hàm i2c_write trong file i2c.h có thể sai chính tả(lúc trước mình cũng bị :D), với lại đọc i2c bạn kiểm tra thử xem mấy byte đầu tiên của dữ liệu đọc về có phải là dữ liệu bạn cần không nhé.
Đúng là trong i2c.h có lỗi chính tả. Chỉnh sửa vẫn bị, về việc đọc về thì không đọc được byte nào cả , chỉ mới gửi địa chỉ đã bị đứng rồi .
Hay là con sensor của mình hư rồi nhỉ :(( mới mua của thiên minh thôi :-s
 

Nguyentridung

Thành Viên PIF
vodanhbk: Sau 1 tuần loay hoay thì con của mình cũng chịu chạy rồi. Mình xin đóng góp như thế này:
hàm i2c_init(0x1C) hoặc (0x1D). Thứ hai, ngay sau đó là câu lệnh: i2c_write(0x2A,1,acce_active); với unsigned char acce_active[1] = {0x01}; (để kích con này lên active, mặc định là nó standby). Vậy là xong, sau đó bạn có thể đọc thoải mái
 

vodanhbk

Trứng gà
Nguyentridung : Mình đã thử rồi nhưng vẫn tình trạng ban đầu, trong i2c.c bạn có sửa đổi gì không?
 

vodanhbk

Trứng gà
Các anh chị ơi cho em hỏi, em debug với DS1307 thì ngay sau lệnh: UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
trong hàm i2c_write thì giá trị thanh ghi UCB0CTL1 =0x92, trong khi đó em debug với MMA8452 thì ngay sau lệnh này thì giá trị thanh ghi UCB0CTL1 = 0x90, như vậy bit thứ 2 UCTXSTT của thanh ghi này = 0, I2C không thể start được. Cờ ngắt UCNACKIFG được set lên 1 trong khi chưa gửi địa chỉ thanh ghi nào cả.
Anh chị nào có thể giải thích lỗi này là lỗi gì không?
 

locle1993

Thành Viên PIF
Bạn xem thử kết nối phần cứng có vấn đề gì không?
P1.6 -> SCL
P1.7 -> SDA
jump P1.6 trên launch pad tháo ra chưa?
 

TTQ

Thành Viên PIF
vodanhbk: Sau 1 tuần loay hoay thì con của mình cũng chịu chạy rồi. Mình xin đóng góp như thế này:
hàm i2c_init(0x1C) hoặc (0x1D). Thứ hai, ngay sau đó là câu lệnh: i2c_write(0x2A,1,acce_active); với unsigned char acce_active[1] = {0x01}; (để kích con này lên active, mặc định là nó standby). Vậy là xong, sau đó bạn có thể đọc thoải mái

Mình đã thử như bạn nói nhưng sao giá trị trả về toàn là 0xFF ko vậy Nguyentridung? Ngoài ra bạn có sửa thêm gì ko Dung ?
Code:
    uint32_t datawr[]={0x01};
    uint32_t datarev[6];
    SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |SYSCTL_XTAL_16MHZ);
    Config_I2C();
    I2C_write((uint32_t *)datawr, 1, 0x2A); // active
    SysCtlDelay(SysCtlClockGet() / 10);
   
    while(1)
    {
        I2C_read(datarev, 6, 0x01);
        SysCtlDelay(SysCtlClockGet() / 10);
    }
 

Nguyentridung

Thành Viên PIF
unsigned char acce_active[1] = {0x01};
unsigned char data_r[6];
int data_x, data_y, data_z;

i2c_init(0x1C);
i2c_write(0x2A,1,acce_active);
while(1){
i2c_read(0x01,6,data_r);
data_x = ((data_r[0]<<8)|data_r[1])>>4;
data_y = ((data_r[2]<<8)|data_r[3])>>4;
data_z = ((data_r[4]<<8)|data_r[5])>>4;
}
đây là phần code với con cảm biến của mình
 
Top