昨天DAY10講了控制GPIO口來完成協議,今天來講實際的例子,以大家最常聽過三軸感測器為例,首先介紹一下這個感測器,ADXL345 是一款低功耗三軸加速度計,非常適合移動設備應用,可以在傾斜檢測應用中測量靜態重力加速度,還可以測量動態加速度,也可檢測自由落體。
昨天說了這兩個函式(bdp_I2C_GPIO.c和bdp_I2C_GPIO.h),今天就來講解如何利用昨天寫的函式來讀取三軸感測器,
先講解我的bdp_I2C_ADXL345.h
首先,我先附上Datasheet網址:
https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf (英文版本)
https://www.analog.com/media/cn/technical-documentation/data-sheets/ADXL345_cn.pdf (簡體翻譯版本)
接下我會搭配這個手冊做部分講解,當然這手冊有中文版本了是大陸翻譯的,我不建議只看中文的,有可能會有錯誤,真的看不懂可以交叉著看,畢竟這是一間大公司ANALOG DEVICES寫出來的手冊,我是相信不會有問題,有問題就不會出產這顆感測器了。
#ifndef __BSP_I2C_adxl_H
#define __BSP_I2C_adxl_H
#include "bsp_I2C_gpio.h"
#define DEVICE_ID 0X00 //器件ID,0XE5
#define THRESH_TAP 0X1D //敲擊閥值
#define OFSX 0X1E
#define OFSY 0X1F
#define OFSZ 0X20
#define DUR 0X21
#define Latent 0X22
#define Window 0X23
#define THRESH_ACK 0X24
#define THRESH_INACT 0X25
#define TIME_INACT 0X26
#define ACT_INACT_CTL 0X27
#define THRESH_FF 0X28
#define TIME_FF 0X29
#define TAP_AXES 0X2A
#define ACT_TAP_STATUS 0X2B
#define BW_RATE 0X2C
#define POWER_CTL 0X2D
#define INT_ENABLE 0X2E
#define INT_MAP 0X2F
#define INT_SOURCE 0X30
#define DATA_FORMAT 0X31
#define DATA_X0 0X32
#define DATA_X1 0X33
#define DATA_Y0 0X34
#define DATA_Y1 0X35
#define DATA_Z0 0X36
#define DATA_Z1 0X37
#define FIFO_CTL 0X38
#define FIFO_STATUS 0X39
//如果ALT ADDRESS脚(12脚)接地,ADXL設備地址為0X53(不包含最低位).
//如果接V3.3,则ADXL設備地址为0X1D(不包含最低位).
//如果Pin12腳接3.3V,为0X3B和0X3A,如果接GND,則為0XA7和0XA6
#define ADXL_READ 0XA7 //二進制為 1010 0111
#define ADXL_WRITE 0XA6 //二進制為 1010 0110
uint8_t ADXL345_Init(void); //初始化ADXL345
void ADXL345_WR_Reg(uint8_t addr,uint8_t val); //Write_ADXL345寄存器
uint8_t ADXL345_RD_Reg(uint8_t addr); //Read_ADXL345寄存器
首先會define這麼多東西是因為,我把手冊上所有可操作的暫存器位址都記下來了,當然我這邊沒有全部使用到,可以看以下手冊第23頁的部分:
可以看到上圖我紅框的部分,這是三個軸讀取的暫存器位置部分,這個每個腳位都有對應詳細功能說明,在手冊接下去24頁後的部分,最後幾行是函式的宣告,再來講解bdp_I2C_ADXL345.c
uint8_t ADXL345_Init(void)
{
//初始化IIC
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(I2C_GPIO_CLK, ENABLE); /* 打開GPIO時鐘 */
GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; /* 開漏輸出 */
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStructure);
/* 給一個停止信號, 重定I2C匯流排上的所有設備到待機模式 */
i2c_Stop();
//------------------------------------------------
if(ADXL345_RD_Reg(DEVICE_ID)==0XE5) //ID
{
ADXL345_WR_Reg(DATA_FORMAT,0X2B); //**0x31** 低電平中斷輸出,13位元全解析度,輸出資料右對齊,16g量程
ADXL345_WR_Reg(BW_RATE,0x0A); //**0x2C** 資料輸出速度為400Hz
ADXL345_WR_Reg(POWER_CTL,0x28); //**0X2D** 連結使能,測量模式
ADXL345_WR_Reg(INT_ENABLE,0x00); //不使用中斷
//*******偏移寄存器**************
ADXL345_WR_Reg(OFSX,0x00); //00 X=FB,Y=0xF9 ___ //98 X=00,Y=FE,Z=EE
ADXL345_WR_Reg(OFSY,0x00); //算法 1LSB=15.6mg
ADXL345_WR_Reg(OFSZ,0x00); //先算偏移多少個LSB在,用2's表示負號
return 0;
}
return 1;
}
這是ADXL345的初始化函式,先對GPIO口的初始化,再來設定感測的模式ADXL345_WR_Reg為對暫存器寫數值,至於要寫數值手冊24頁後有說,這邊先不詳談,等說完這整個配置我再詳細講解,ADXL345_RD_Reg是對暫存器讀取數值
接下面是寫暫存和讀取暫存器出來的數值函式
//寫ADXL345寄存器 addr:暫存器地址 al:要寫入的值
void ADXL345_WR_Reg(uint8_t addr,uint8_t val) //void ADXL345_write(u8 addr, u8 data)
{
i2c_Start();
i2c_SendByte(ADXL_WRITE);
i2c_WaitAck();
i2c_SendByte(addr);
i2c_WaitAck();
i2c_SendByte(val);
i2c_WaitAck();
i2c_Stop();
}
//讀ADXL345寄存器 addr:寄存器地址 返回值:讀到的值
uint8_t ADXL345_RD_Reg(uint8_t addr)
{
uint8_t temp=0;
i2c_Start();
i2c_SendByte(ADXL_WRITE);
i2c_WaitAck();
i2c_SendByte(addr); //發送寄存器地址
i2c_WaitAck();
i2c_Start();
i2c_SendByte(ADXL_READ);
i2c_WaitAck();
temp=i2c_ReadByte();
i2c_NAck();
i2c_Stop();
return temp;
}
至於這時需如何觀看手冊寫入時序,我明天會再一步步講解搭配手冊講解
然後main.c可以來使用這些函式讀值啦~,附上我的主程式
#include "bsp_I2C_adxl345.h"
#include "bsp_SysTick.h" //操作MO內核暫存器使用滴答計時器來做精準計時
//參考網站:https://kknews.cc/zh-tw/news/96p52m5.html
int main(void)
{
int8_t x0,x1,y0,y1,z1,z0;//宣告3個軸的變數,1個軸有高8為和低8位
SysTick_Init(48); //配置Delay函式
DEBUG_USART_Config(); //初始化UART
ADXL345_Init(); //初始化ADXL345
while(1)
{
x0=ADXL345_RD_Reg(0xAA);// 取得 X 軸 低位元資料
x1=ADXL345_RD_Reg(0x33);// 取得 X 軸 高位元資料
x=(((short)(x1 << 8)+x0)/256.0);
y0=ADXL345_RD_Reg(0x34);// 取得 Y 軸 低位元資料
y1=ADXL345_RD_Reg(0x35);// 取得 Y 軸 高位元資料
y=(((short)(y1 << 8)+y0)/256.0);
z0=ADXL345_RD_Reg(0x36);// 取得 Z 軸 低位元資料
z1=ADXL345_RD_Reg(0x37);// 取得 Y 軸 高位元資料
z=(((short)(z1 << 8)+z0)/256.0);
printf("X=%.3f Y=%.3f Z=%.3f\r\n",x,y,z);
delay_ms(100);
}
}
以上看到的寫法,明天會再搭配手冊慢慢講解,想學嵌入式學看datasheet(數據手冊)是必經之路~~
可以先自己看看,我想信很多人都看的我這再寫什麼...,最後一行的printf是利用寫好的函是讓UART傳出數值,這樣我就可以用串口視窗來查看三個軸的數值啦~~~