ADXL345 是一種常見、便宜、簡單、好用的 3 軸加速度計。我這片 ADXL345 模組是我在露天拍賣買的,約台幣 110 元...,比起之前買的 LSM303DLH 就要台幣 6、7 百元要來的便宜多了...Orz

實際接線圖 (右邊小塊板子就是 ADXL345 )

開發板:ST 官方的 STM32VL Discovery
微控制器:STM32F100R8T6 (下面程式碼相容 F100、F103 、F105、F107 等所有 F1 系列)
三軸加速度器:ADXL345

DSC_0157[1]

特寫 ADXL345 模組:

2

執行結果:

1  

★ 可以直接複製貼上到 C 語言開發環境中,此程式碼可以直接編譯執行(只要你配置好開發環境與硬體)。

程式碼:

#include "stm32f10x.h"
#include "stdio.h"
 
#define I2C_ADDRESS 0xA7 // ADXL345 I²C 地址
 
void Init_I2C() { 
    I2C_InitTypeDef I2C_InitStructure; 
    GPIO_InitTypeDef GPIO_InitStructure;
 
    /* 啟用 I2C */  
    I2C_Cmd(I2C1,ENABLE);
    /* 啟用 I2C1 RCC 時鐘 */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
 
    /* 設定 I2C1 的 SDA 與 SCL 腳位 */
    /* PB6 = SCL ,PB7 = SDA */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);    
 
    /* 設定 I2C1 */
    I2C_InitStructure.I2C_Mode = I2C_Mode_SMBusHost;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = 0x00; // STM32 自己的 I2C 地址
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 100000 ; // 設定 I2C 時鐘速度為 100K 
    I2C_Init(I2C1, &I2C_InitStructure);
}
 
/* 發送開始信號
 * 發送到 "從設備 (Slave Device)" 地址 + R/W bit
 * 
 * 參數:
 * I2Cx --> I2C 外設,例如:I2C1
 * address --> 7 bit 的 "從設備 (Slave Device)" 地址
 * direction --> 設定方向,例如:
 * I2C_Direction_Tranmitter 為 主發送模式
 * I2C_Direction_Receiver 為 主接收模式
 */
void I2C_start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction){
    // 等待 I2C1 不忙的時候...
    while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
 
    // 對 I2C1 發送啟動信號
    I2C_GenerateSTART(I2Cx, ENABLE);
 
    // 等待 I2C1 EV5 --> 從 從設備 (Slave Device) 確認啟動信號 
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
 
    // Send slave Address for write 
    I2C_Send7bitAddress(I2Cx, address, direction);
 
    /* 等待 I2C1 EV6, 並判斷 I2C 方向:
    * 如果是 I2C_Direction_Tranmitter 則設定為 主發送模式
    * 如果是 I2C_Direction_Receiver 則設定為 主接收模式
    */ 
    if(direction == I2C_Direction_Transmitter){
        while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    } else if(direction == I2C_Direction_Receiver){
        while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    }
}
 
/* 發送一個 byte 到 "從設備 (Slave Device)"
 *
 * 參數:
 *I2Cx --> I2C 的外設,例如:I2C1 
 *data --> 要發送的 byte 資料
 */
void I2C_write(I2C_TypeDef* I2Cx, uint8_t data)
{
    I2C_SendData(I2Cx, data);
    // 等待 I2C1 EV8_2 --> 已發送一個 byte
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
 
/* 從 "從設備 (Slave Device)" 讀取一個 byte
 * 並請求後面一個 byte
 */
uint8_t I2C_read_ack(I2C_TypeDef* I2Cx){
    uint8_t data;
    // 啟用 確認設定接收資料
    I2C_AcknowledgeConfig(I2Cx, ENABLE);
    // 等待接收到一個 byte
    while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
    // 從 I2C 佔存器讀取一個 byte 並回傳
    data = I2C_ReceiveData(I2Cx);
    return data;
}
 
/* 從 "從設備 (Slave Device)" 讀取一個 byte
 * 且之後就不再接收資料
 */
uint8_t I2C_read_nack(I2C_TypeDef* I2Cx){
    uint8_t data;
    // disabe acknowledge of received data
    // nack also generates stop condition after last byte received
    // see reference manual for more info
    I2C_AcknowledgeConfig(I2Cx, DISABLE);
    I2C_GenerateSTOP(I2Cx, ENABLE);
    // 等待收到一個 byte
    while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
    // 從 I2C 佔存器讀取一個 byte 並回傳
    data = I2C_ReceiveData(I2Cx);
    return data;
}
 
/* 發送停止信號
 * 釋放 I2C 匯流排
 */
void I2C_stop(I2C_TypeDef* I2Cx){
    // 停止 I2C1
    I2C_GenerateSTOP(I2Cx, ENABLE);
}
 
/*
 * 將字串由 UART 送至 PC
 */
void My_Usart1_Send(char *string){
    while(*string){
        /* 傳送訊息至 USART1 */
        USART_SendData(USART1, (unsigned short int) *string++);
 
        /* 等待訊息傳送完畢 */
        while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
    }
}
 
/*
 * 初始化 UART
 */
void Init_UART(){
    /******** 宣告 USART、GPIO 結構體 ********/
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
 
    /******** 啟用 GPIOA、USART1 的 RCC 時鐘 ********/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);
 
    /******** 設定 PA9 為 Tx 覆用 ********/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
 
    GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化 PA9
 
    /******** 設定 PA10 為 Rx 覆用 ********/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
 
    GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化 PA10
 
 
    /******** USART 基本參數設定 ********/
 
    USART_InitStructure.USART_BaudRate = 9600;
    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(USART1, &USART_InitStructure); // 初始化 UART1
 
    USART_Cmd(USART1, ENABLE); // 啟用 USART1
}
 
 
/************************************************************* 
* 寫入佔存器:writeReg(int reg, int value)
* reg:佔存器地址
* value:要寫入的值
*/
void writeReg(int reg, int value){
    I2C_start(I2C1, I2C_ADDRESS, I2C_Direction_Transmitter); // 在 主發送 模式中 準備開始 發送
    I2C_write(I2C1, reg); // 指定佔存器
    I2C_write(I2C1, value); // 寫入佔存器的值
    I2C_stop(I2C1); // 停止發送
}
 
/************************************************************* 
* 讀取佔存器:readReg(int reg)
* reg:要讀取的佔存器地址
*/
int readReg(int reg){
    int value;
    
    I2C_start(I2C1, I2C_ADDRESS, I2C_Direction_Transmitter); // 在 主發送 模式中 準備開始 發送
    I2C_write(I2C1, reg); // 指定佔存器    
    I2C_stop(I2C1); // 停止發送
       
    I2C_start(I2C1, I2C_ADDRESS, I2C_Direction_Transmitter); // 在 主發送 模式中 準備開始 發送
    value = I2C_read_ack(I2C1); // 從 TC74 讀取一個 byte 並請求後面一個 byte
    I2C_read_nack(I2C1); // 讀取一個 byet 後,就不再讀取後面一個 byte (停止傳輸)
    
    return value;
}
 
/*
 *  讀 ADXL345 佔存器中的 x , y, z 的值
 */
int xla, xha, yla, yha, zla, zha;
float x, y, z;
 
void readValue(){
    
    I2C_start(I2C1, I2C_ADDRESS, I2C_Direction_Transmitter); // 在 主發送 模式中 準備開始 發送
    I2C_write(I2C1, 0x32 | (1 << 7)); // 指定佔存器
    I2C_stop(I2C1); // 停止發送
    
    I2C_start(I2C1, I2C_ADDRESS, I2C_Direction_Receiver); // 在 主發送 模式中 準備開始 發送
    
    xla = I2C_read_ack(I2C1); // 從 ADXL345 讀取一個 byte 並請求後面一個 byte
    xha = I2C_read_ack(I2C1); // 從 ADXL345 讀取一個 byte 並請求後面一個 byte
    yla = I2C_read_ack(I2C1); // 從 ADXL345 讀取一個 byte 並請求後面一個 byte
    yha = I2C_read_ack(I2C1); // 從 ADXL345 讀取一個 byte 並請求後面一個 byte
    zla = I2C_read_ack(I2C1); // 從 ADXL345 讀取一個 byte 並請求後面一個 byte
    zha = I2C_read_ack(I2C1); // 從 ADXL345 讀取一個 byte 並請求後面一個 byte
        
    I2C_read_nack(I2C1); // 讀取一個 byet 後,就不再讀取後面一個 byte (停止傳輸)
    
    
    /* 一定要強制轉成 short 型別,因為有些數字向左移動八位後
     * 會超過 short 大小,進而變成負數。
     * 例如:65535 + 1 = -65536
     *       65535 + 2 = -65535
     *       65535 + 3 = -65534
     */
    x = (((short)(xha << 8)) + xla) / 256.0F;
    y = (((short)(yha << 8)) + yla) / 256.0F;
    z = (((short)(zha << 8)) + zla) / 256.0F;
}
 
 
 
int main(){
    int i;
    char buff [] = "";
    
    Init_I2C(); // 初始化 I2C
    Init_UART(); // 初始化 UART      
    
    My_Usart1_Send(" Start \n");
    My_Usart1_Send("---------------------------------------------- \n");
    My_Usart1_Send("Open ADXL345 Power ... \n");
    
    writeReg(0x2D, 0x0A); // 打開三軸加速計的電源 ,設定每秒讀取 100 次,啟用 X Y Z 軸
        
    My_Usart1_Send("Read Value ... \n");    
    
    while(1){
        readValue(); // 讀 x , y, z 的值
        sprintf (buff, "X : %f    Y : %f    Z : %f \n", x, y, z); // 格式化字串
        My_Usart1_Send(buff); // 經由 UART 將結果 buff 發送至 PC      
        
        for(i=0; i<100000; i++); // 延遲 
    }
}
 



arrow
arrow
    全站熱搜

    黃彥霖 發表在 痞客邦 留言(2) 人氣()