话不多说,直接上代码,注释已经很详细了
实在不行,实验课可以直接问我。
Task 2:
#include "mbed.h"
Difination part///
// 定义 SPI 引脚和常量
#define MOSI A6 // SPI 主机输出从机输入引脚 (根据实验指导图片更新)
#define MISO A5 // SPI 主机输入从机输出引脚 (根据实验指导图片更新)
#define SCLK A4 // SPI串行时钟引脚 (根据实验指导图片更新)
#define CS_PIN D12 // SPI 片选引脚 (根据实验指导图片更新)
// ADXL345 寄存器地址
#define REG_DATA_FORMAT 0x31 // 数据格式控制寄存器 (DATA_FORMAT)
#define REG_POWER_CTL 0x2D // 电源控制寄存器 (POWER_CTL)
#define REG_BW_RATE 0x2C // 数据速率和带宽控制寄存器 (BW_RATE)
#define REG_DATAX0 0x32 // X轴数据的第一个字节寄存器 (DATAX0), 后续为DATAX1, DATAY0, DATAY1, DATAZ0, DATAZ1
// ADXL345 配置值
#define DATA_FORMAT_CONFIG 0x0B // 数据格式配置 (REG_DATA_FORMAT):
// Bit D7 (SELF_TEST) = 0: 禁用自检
// Bit D6 (SPI) = 0: 4线SPI模式 (根据实验指导)
// Bit D5 (INT_INVERT) = 0: 中断高电平有效 (默认)
// Bit D4 = 0: (保留)
// Bit D3 (FULL_RES) = 1: 全分辨率模式 (根据实验指导)
// Bit D2 (Justify) = 0: 数据右对齐 (根据实验指导)
// Bits D1:D0 (Range) = 11: ±16g 量程 (根据实验指导)
// 结果: 00001011 (0x0B)
#define POWER_CTL_CONFIG 0x08 // 电源控制配置 (REG_POWER_CTL):
// 实验指导要求:
// - Link bit cleared (D5=0)
// - AUTO_SLEEP disabled (D4=0)
// - Measurement mode (D3=1)
// - Normal mode (Sleep bit D2=0)
// - 8 Hz sleep mode frequency (Wakeup bits D1:D0 = 00)
// 配置值 0x08 (二进制 00001000) 满足以上所有条件:
// D5(Link)=0, D4(AUTO_SLEEP)=0, D3(Measure)=1, D2(Sleep)=0, D1(Wakeup)=0, D0(Wakeup)=0.
#define BW_RATE_CONFIG 0x0D // 带宽速率配置 (REG_BW_RATE):
// Bit D4 (LOW_POWER) = 0: 正常功耗模式。
// Bits D3:0 (Rate) = 1101 (0x0D): 设置输出数据速率 (ODR) 为 800 Hz (带宽为 ODR/2 = 400 Hz)。
// (注意: 实验指导中提到的 "8 Hz sleep mode frequency" 是通过 POWER_CTL 寄存器设置的,与此处的正常工作 ODR 不同。)
#define Read_BIT 0x80 // SPI读取操作位: 当进行SPI读取时,寄存器地址的最高位 (MSB) 需要置1。
// SPI 通信参数
#define SPI_BIT_WIDTH 8 // SPI 数据位宽 (8位)
#define SPI_MODE 3 // SPI 模式 (CPOL=1, CPHA=1),时钟空闲时为高电平,在第二个时钟边沿采样。
#define SPI_FREQUENCY 2000000 // SPI 通信频率 (2MHz)。实验指导要求2MHz。
// 创建 SPI 对象和片选引脚对象
SPI spi(MOSI, MISO, SCLK); // SPI通信对象,参数为 MOSI, MISO, SCLK 引脚
DigitalOut chipSelect(CS_PIN); // 片选引脚数字输出对象
//Function part///
// 配置 ADXL345 加速度计
void configureAccelerometer() {
// 初始化 SPI 通信参数
chipSelect = 1; // SPI片选引脚初始状态为高电平 (ADXL345未被选中)
spi.format(SPI_BIT_WIDTH, SPI_MODE); // 设置 SPI 数据格式: 8位数据宽度,模式3
spi.frequency(SPI_FREQUENCY); // 设置 SPI 通信频率: 2MHz
// 1. 配置数据格式寄存器 (REG_DATA_FORMAT)
chipSelect = 0; // 拉低片选,选中 ADXL345 以进行通信
spi.write(REG_DATA_FORMAT); // 发送要写入的寄存器地址 (0x31)
spi.write(DATA_FORMAT_CONFIG); // 发送数据格式配置值 (0x0B)
chipSelect = 1; // 拉高片选,结束本次SPI写操作
// 2. 配置数据带宽速率寄存器 (REG_BW_RATE)
chipSelect = 0; // 拉低片选
spi.write(REG_BW_RATE); // 发送要写入的寄存器地址 (0x2C)
spi.write(BW_RATE_CONFIG); // 发送带宽速率配置值 (0x0D: 800Hz ODR, 正常功耗)
chipSelect = 1; // 拉高片选
// 3. 配置电源控制寄存器 (REG_POWER_CTL)
chipSelect = 0; // 拉低片选
spi.write(REG_POWER_CTL); // 发送要写入的寄存器地址 (0x2D)
spi.write(POWER_CTL_CONFIG); // 发送电源控制配置值 (0x08)
chipSelect = 1; // 拉高片选
}
//Main part///
int main() {
// 调用函数配置ADXL345加速度计的初始参数
configureAccelerometer();
// 主循环,无限执行
while (1) {
// 使当前线程休眠 2000 毫秒 (2秒)
// 在实际应用中,这里通常会接着调用函数来读取和处理加速度数据
ThisThread::sleep_for(2000ms);
}
return 0; // 理论上不会执行到这里,因为上面是无限循环
}
Task 3:
#include "mbed.h"
Definition part
// 定义 SPI 引脚和常量
#define MOSI A6 // SPI 主机输出从机输入引脚 (根据实验指导图片更新)
#define MISO A5 // SPI 主机输入从机输出引脚 (根据实验指导图片更新)
#define SCLK A4 // SPI串行时钟引脚 (根据实验指导图片更新)
#define CS_PIN D12 // SPI 片选引脚 (根据实验指导图片更新)
// ADXL345 寄存器地址
#define REG_DATA_FORMAT 0x31 // 数据格式控制寄存器 (DATA_FORMAT)
#define REG_POWER_CTL 0x2D // 电源控制寄存器 (POWER_CTL)
#define REG_BW_RATE 0x2C // 数据速率和带宽控制寄存器 (BW_RATE)
#define REG_DATAX0 0x32 // X轴数据的第一个字节寄存器 (DATAX0), 后续为DATAX1, DATAY0, DATAY1, DATAZ0, DATAZ1
// ADXL345 配置值
#define DATA_FORMAT_CONFIG 0x0B // 数据格式配置 (REG_DATA_FORMAT, 地址 0x31):
// 实验指导 (Task 2) 要求: 4-wire SPI, FULL_RES, right-justified, +/-16g.
// Bit D7 (SELF_TEST) = 0: 禁用自检 (默认)
// Bit D6 (SPI) = 0: 4线SPI模式 (满足实验指导)
// Bit D5 (INT_INVERT) = 0: 中断高电平有效 (默认)
// Bit D4 = 0: (保留)
// Bit D3 (FULL_RES) = 1: 全分辨率模式 (满足实验指导)
// Bit D2 (Justify) = 0: 数据右对齐 (满足实验指导)
// Bits D1:D0 (Range) = 11: ±16g 量程 (满足实验指导)
// 最终配置值: 00001011 (0x0B)
#define POWER_CTL_CONFIG 0x08 // 电源控制配置 (REG_POWER_CTL, 地址 0x2D):
// 实验指导 (Task 2) 要求:
// - Link bit cleared (D5=0)
// - AUTO_SLEEP disabled (D4=0)
// - Measurement mode (D3=1)
// - Normal mode (Sleep bit D2=0)
// - 8 Hz sleep mode frequency (Wakeup bits D1:D0 = 00)
// 配置值 0x08 (二进制 00001000) 满足以上所有条件:
// D7=0, D6=0, D5(Link)=0, D4(AUTO_SLEEP)=0, D3(Measure)=1, D2(Sleep)=0, D1(Wakeup)=0, D0(Wakeup)=0.
#define BW_RATE_CONFIG 0x0D // 带宽速率配置 (REG_BW_RATE, 地址 0x2C):
// Bit D4 (LOW_POWER) = 0: 正常功耗模式。
// Bits D3:0 (Rate) = 1101 (0x0D): 设置输出数据速率 (ODR) 为 800 Hz, 带宽为 ODR/2 = 400 Hz。
// (注意: 实验指导Task 2的配置清单中未明确指定正常工作模式的ODR,此为代码选定值。
// 实验指导中提到的 "8 Hz sleep mode frequency" 是通过 POWER_CTL 寄存器设置的睡眠模式下的唤醒频率。)
#define Read_BIT 0x80 // SPI读取操作位: 当进行SPI读取时,寄存器地址的最高位 (MSB) 需要置1。
// SPI 通信参数
#define SPI_BIT_WIDTH 8 // SPI 数据位宽 (8位) - 实验指导 (Task 2) 要求
#define SPI_MODE 3 // SPI 模式 (CPOL=1, CPHA=1) - 实验指导 (Task 2) 要求。时钟空闲时为高电平,在第二个时钟边沿采样。
#define SPI_FREQUENCY 2000000 // SPI 通信频率 (2MHz) - 实验指导 (Task 2) 要求。
// 创建 SPI 对象和片选引脚对象
SPI spi(MOSI, MISO, SCLK); // SPI通信对象,参数为 MOSI, MISO, SCLK 引脚
DigitalOut chipSelect(CS_PIN); // 片选引脚数字输出对象
// 数据缓冲区和转换变量
char buffer[6]; // 用于存储从ADXL345读取的原始6字节数据 (X,Y,Z各两字节: X0, X1, Y0, Y1, Z0, Z1)
int16_t accelData[3]; // 用于存储转换后的16位带符号原始加速度数据 [X, Y, Z]
float accel_in_G_form[3]; // 用于存储转换为 'g' (重力加速度)单位的浮点型加速度数据 [X, Y, Z]
// 转换因子,用于将原始数据转换为 'g' 单位。
// 根据ADXL345数据手册,在全分辨率模式 (FULL_RES=1) 下,所有g量程的比例因子维持在约 4 mg/LSB。
// 4 mg/LSB = 0.004 g/LSB。
const float conversionFactor = 0.004;
//Function part
// 配置 ADXL345 加速度计 (对应实验指导 Task 2)
void configureAccelerometer() {
// 初始化 SPI 通信参数 (根据实验指导 Task 2 要求)
chipSelect = 1; // SPI片选引脚初始状态为高电平 (ADXL345未被选中)
spi.format(SPI_BIT_WIDTH, SPI_MODE); // 设置 SPI 数据格式: 8位数据宽度,模式3
spi.frequency(SPI_FREQUENCY); // 设置 SPI 通信频率: 2MHz
// 1. 配置数据格式寄存器 (REG_DATA_FORMAT)
chipSelect = 0; // 拉低片选,选中 ADXL345 以进行通信
spi.write(REG_DATA_FORMAT); // 发送要写入的寄存器地址 (0x31)
spi.write(DATA_FORMAT_CONFIG); // 发送数据格式配置值 (0x0B)
chipSelect = 1; // 拉高片选,结束本次SPI写操作
// 2. 配置数据带宽速率寄存器 (REG_BW_RATE)
chipSelect = 0; // 拉低片选
spi.write(REG_BW_RATE); // 发送要写入的寄存器地址 (0x2C)
spi.write(BW_RATE_CONFIG); // 发送带宽速率配置值 (0x0D: 800Hz ODR, 正常功耗)
chipSelect = 1; // 拉高片选
// 3. 配置电源控制寄存器 (REG_POWER_CTL)
chipSelect = 0; // 拉低片选
spi.write(REG_POWER_CTL); // 发送要写入的寄存器地址 (0x2D)
spi.write(POWER_CTL_CONFIG); // 发送电源控制配置值 (0x08)
chipSelect = 1; // 拉高片选
}
// 读取加速度计数据 (对应实验指导 Task 3 部分功能)
void readAccelerometerData() {
// 拉低片选,选中 ADXL345 以准备读取数据
chipSelect = 0;
// 发送起始读取寄存器地址 (DATAX0) 并设置读操作位 (MSB为1)
// REG_DATAX0 (0x32) | Read_BIT (0x80) = 0xB2
// 为了进行多字节读取 (burst read),数据手册建议将命令字节的Bit6 (MB位, 0x40)也置1。
// 即 REG_DATAX0 | Read_BIT | 0x40。
// 但即使不显式设置MB位,许多SPI设备在CS保持低电平的情况下,连续的spi.write(0x00)也会读取后续寄存器。
// 此处采用后者的方式,依赖Mbed SPI库和ADXL345对此的支持。
spi.write(REG_DATAX0 | Read_BIT);
// 循环读取6个字节的数据 (X, Y, Z轴各2个字节)
// ADXL345会按顺序输出 DATAX0, DATAX1, DATAY0, DATAY1, DATAZ0, DATAZ1 的内容
for (int i = 0; i < 6; i++) {
buffer[i] = spi.write(0x00); // 发送虚拟字节0x00以在MISO线上接收一个字节的数据
}
// 拉高片选,结束本次SPI读操作
chipSelect = 1;
// 将接收到的高低字节合并为16位带符号整数数据 (对应实验指导 Task 3 要求)
// ADXL345的数据是低字节在前 (LSB first)
// buffer[0] = DATAX0 (LSB), buffer[1] = DATAX1 (MSB)
// buffer[2] = DATAY0 (LSB), buffer[3] = DATAY1 (MSB)
// buffer[4] = DATAZ0 (LSB), buffer[5] = DATAZ1 (MSB)
accelData[0] = (int16_t)((buffer[1] << 8) | buffer[0]); // X轴数据
accelData[1] = (int16_t)((buffer[3] << 8) | buffer[2]); // Y轴数据
accelData[2] = (int16_t)((buffer[5] << 8) | buffer[4]); // Z轴数据
// 将原始16位数据根据转换因子转换为 'g' (重力加速度)单位的浮点数值 (对应实验指导 Task 3 要求)
for (int i = 0; i < 3; i++) {
accel_in_G_form[i] = conversionFactor * accelData[i];
}
}
// 通过串口显示加速度计数据 (对应实验指导 Task 3 要求)
void displayAccelerometerData() {
// 打印格式化的加速度数据到串行控制台 (例如 Tera Term, PuTTY)
// 需要确保您的开发环境或目标板已配置好串口输出 (通常默认通过USB虚拟串口)
printf("===============\n");
printf("x = %+1.2fg\n", accel_in_G_form[0]); // %+1.2f: 带符号(+/-), 总宽度至少1, 小数点后2位, 'g'表示单位
printf("y = %+1.2fg\n", accel_in_G_form[1]);
printf("z = %+1.2fg\n", accel_in_G_form[2]);
}
//Main part//
int main() {
// 调用函数配置ADXL345加速度计的初始参数 (执行Task 2的配置)
configureAccelerometer();
// 主循环,无限执行
while (1) {
// 使当前线程休眠 2000 毫秒 (2秒)
// 这个延时控制了读取和显示数据的频率。
// 实验指导Task 3要求 "continuously read the accelerometer data",
// 可以根据需要调整或暂时移除此延时以实现更快的连续读取。为了方便观察,此处保留。
ThisThread::sleep_for(2000ms);
// 从ADXL345读取最新的加速度数据 (执行Task 3功能)
readAccelerometerData();
// 通过串口显示读取到的加速度数据 (执行Task 3功能)
displayAccelerometerData();
}
return 0; // 理论上不会执行到这里,因为上面是无限循环
}
Task4:
#include "mbed.h"
Definition part
// 定义 SPI 引脚和常量 (根据实验指导 Task 1 和 Task 2 更新)
#define MOSI A6 // SPI 主机输出从机输入引脚
#define MISO A5 // SPI 主机输入从机输出引脚
#define SCLK A4 // SPI串行时钟引脚
#define CS_PIN D12 // SPI 片选引脚
// 定义 LED 引脚 (根据实验指导 Task 1 和 Task 4 更新)
// X轴相关的LED
DigitalOut LXG1(D11); // X轴正向绿色LED 1 (LXG1: Left X Green 1 or X+ Green 1)
DigitalOut LXG2(D9); // X轴正向绿色LED 2 (LXG2: Left X Green 2 or X+ Green 2)
DigitalOut LXR1(D0); // X轴负向红色LED 1 (LXR1: Left X Red 1 or X- Red 1)
DigitalOut LXR2(D1); // X轴负向红色LED 2 (LXR2: Left X Red 2 or X- Red 2)
// Y轴相关的LED
DigitalOut LYG1(D6); // Y轴正向绿色LED 1 (LYG1: Landscape Y Green 1 or Y+ Green 1)
DigitalOut LYG2(A3); // Y轴正向绿色LED 2 (LYG2: Landscape Y Green 2 or Y+ Green 2)
DigitalOut LYR1(A2); // Y轴负向红色LED 1 (LYR1: Landscape Y Red 1 or Y- Red 1)
DigitalOut LYR2(A0); // Y轴负向红色LED 2 (LYR2: Landscape Y Red 2 or Y- Red 2)
// ADXL345 寄存器地址
#define REG_DATA_FORMAT 0x31 // 数据格式控制寄存器 (DATA_FORMAT)
#define REG_POWER_CTL 0x2D // 电源控制寄存器 (POWER_CTL)
#define REG_BW_RATE 0x2C // 数据速率和带宽控制寄存器 (BW_RATE)
#define REG_DATAX0 0x32 // X轴数据的第一个字节寄存器 (DATAX0), 后续为DATAX1, DATAY0, DATAY1, DATAZ0, DATAZ1
// ADXL345 配置值 (根据实验指导 Task 2)
#define DATA_FORMAT_CONFIG 0x0B // 数据格式配置 (REG_DATA_FORMAT, 地址 0x31):
// 实验指导 (Task 2) 要求: 4-wire SPI, FULL_RES, right-justified, +/-16g.
// Bit D7 (SELF_TEST) = 0: 禁用自检 (默认)
// Bit D6 (SPI) = 0: 4线SPI模式 (满足实验指导)
// Bit D5 (INT_INVERT) = 0: 中断高电平有效 (默认)
// Bit D4 = 0: (保留)
// Bit D3 (FULL_RES) = 1: 全分辨率模式 (满足实验指导)
// Bit D2 (Justify) = 0: 数据右对齐 (满足实验指导)
// Bits D1:D0 (Range) = 11: ±16g 量程 (满足实验指导)
// 最终配置值: 00001011 (0x0B)
#define POWER_CTL_CONFIG 0x08 // 电源控制配置 (REG_POWER_CTL, 地址 0x2D):
// 实验指导 (Task 2) 要求:
// - Link bit cleared (D5=0)
// - AUTO_SLEEP disabled (D4=0)
// - Measurement mode (D3=1)
// - Normal mode (Sleep bit D2=0)
// - 8 Hz sleep mode frequency (Wakeup bits D1:D0 = 00)
// 配置值 0x08 (二进制 00001000) 满足以上所有条件:
// D7=0, D6=0, D5(Link)=0, D4(AUTO_SLEEP)=0, D3(Measure)=1, D2(Sleep)=0, D1(Wakeup)=0, D0(Wakeup)=0.
#define BW_RATE_CONFIG 0x0D // 带宽速率配置 (REG_BW_RATE, 地址 0x2C):
// Bit D4 (LOW_POWER) = 0: 正常功耗模式。
// Bits D3:0 (Rate) = 1101 (0x0D): 设置输出数据速率 (ODR) 为 800 Hz, 带宽为 ODR/2 = 400 Hz。
// (注意: 实验指导Task 2的配置清单中未明确指定正常工作模式的ODR,此为代码选定值。
// 实验指导中提到的 "8 Hz sleep mode frequency" 是通过 POWER_CTL 寄存器设置的睡眠模式下的唤醒频率。)
#define Read_BIT 0x80 // SPI读取操作位: 当进行SPI读取时,寄存器地址的最高位 (MSB) 需要置1。
// SPI 通信参数 (根据实验指导 Task 2)
#define SPI_BIT_WIDTH 8 // SPI 数据位宽 (8位)
#define SPI_MODE 3 // SPI 模式 (CPOL=1, CPHA=1)。时钟空闲时为高电平,在第二个时钟边沿采样。
#define SPI_FREQUENCY 2000000 // SPI 通信频率 (2MHz)。
// 创建 SPI 对象和片选引脚对象
SPI spi(MOSI, MISO, SCLK); // SPI通信对象,参数为 MOSI, MISO, SCLK 引脚
DigitalOut chipSelect(CS_PIN); // 片选引脚数字输出对象
// 数据缓冲区和转换变量
char buffer[6]; // 用于存储从ADXL345读取的原始6字节数据 (X,Y,Z各两字节: X0, X1, Y0, Y1, Z0, Z1)
int16_t accelData[3]; // 用于存储转换后的16位带符号原始加速度数据 [X, Y, Z]
float accel_in_G_form[3]; // 用于存储转换为 'g' (重力加速度)单位的浮点型加速度数据 [X, Y, Z]
// 转换因子,用于将原始数据转换为 'g' 单位。
// 根据ADXL345数据手册,在全分辨率模式 (FULL_RES=1) 下,所有g量程的比例因子维持在约 4 mg/LSB。
// 4 mg/LSB = 0.004 g/LSB。
const float conversionFactor = 0.004;
// 用于存储各轴加速度值的全局变量 (方便在LED控制函数中使用)
float x_axis_g, y_axis_g, z_axis_g;
//Function part
// 配置 ADXL345 加速度计 (对应实验指导 Task 2)
void configureAccelerometer() {
// 初始化 SPI 通信参数
chipSelect = 1; // SPI片选引脚初始状态为高电平 (ADXL345未被选中)
spi.format(SPI_BIT_WIDTH, SPI_MODE); // 设置 SPI 数据格式: 8位数据宽度,模式3
spi.frequency(SPI_FREQUENCY); // 设置 SPI 通信频率: 2MHz
// 1. 配置数据格式寄存器 (REG_DATA_FORMAT)
chipSelect = 0; // 拉低片选,选中 ADXL345 以进行通信
spi.write(REG_DATA_FORMAT); // 发送要写入的寄存器地址 (0x31)
spi.write(DATA_FORMAT_CONFIG); // 发送数据格式配置值 (0x0B)
chipSelect = 1; // 拉高片选,结束本次SPI写操作
// 2. 配置数据带宽速率寄存器 (REG_BW_RATE)
chipSelect = 0; // 拉低片选
spi.write(REG_BW_RATE); // 发送要写入的寄存器地址 (0x2C)
spi.write(BW_RATE_CONFIG); // 发送带宽速率配置值 (0x0D: 800Hz ODR, 正常功耗)
chipSelect = 1; // 拉高片选
// 3. 配置电源控制寄存器 (REG_POWER_CTL)
chipSelect = 0; // 拉低片选
spi.write(REG_POWER_CTL); // 发送要写入的寄存器地址 (0x2D)
spi.write(POWER_CTL_CONFIG); // 发送电源控制配置值 (0x08)
chipSelect = 1; // 拉高片选
}
// 读取加速度计数据 (对应实验指导 Task 3 部分功能)
void readAccelerometerData() {
// 拉低片选,选中 ADXL345 以准备读取数据
chipSelect = 0;
// 发送起始读取寄存器地址 (DATAX0) 并设置读操作位 (MSB为1)
spi.write(REG_DATAX0 | Read_BIT);
// 循环读取6个字节的数据 (X, Y, Z轴各2个字节)
for (int i = 0; i < 6; i++) {
buffer[i] = spi.write(0x00); // 发送虚拟字节0x00以在MISO线上接收一个字节的数据
}
// 拉高片选,结束本次SPI读操作
chipSelect = 1;
// 将接收到的高低字节合并为16位带符号整数数据
accelData[0] = (int16_t)((buffer[1] << 8) | buffer[0]); // X轴数据
accelData[1] = (int16_t)((buffer[3] << 8) | buffer[2]); // Y轴数据
accelData[2] = (int16_t)((buffer[5] << 8) | buffer[4]); // Z轴数据
// 将原始16位数据根据转换因子转换为 'g' 单位的浮点数值
for (int i = 0; i < 3; i++) {
accel_in_G_form[i] = conversionFactor * accelData[i];
}
// 将转换后的值赋给全局变量,方便其他函数使用
x_axis_g = accel_in_G_form[0];
y_axis_g = accel_in_G_form[1];
z_axis_g = accel_in_G_form[2];
}
// 通过串口显示加速度计数据 (对应实验指导 Task 3 要求)
void displayAccelerometerData() {
// 打印格式化的加速度数据到串行控制台
printf("===============\n");
printf("x = %+1.2fg\n", x_axis_g);
printf("y = %+1.2fg\n", y_axis_g);
printf("z = %+1.2fg\n", z_axis_g);
}
// 根据X轴数据控制LED (对应实验指导 Task 4 要求)
void LED_Control_X(float x_val) {
// 首先关闭所有X轴相关的LED
LXG1 = 0; // X轴正向 Green 1
LXG2 = 0; // X轴正向 Green 2
LXR1 = 0; // X轴负向 Red 1
LXR2 = 0; // X轴负向 Red 2
// 根据X轴的加速度值点亮相应的LED
// 实验指导要求:
// If X is between -0.05 and -0.5, turn on LXR1, turn off all others
if (x_val < -0.05 && x_val > -0.5) { // 更精确的条件: (-0.5 < x_val < -0.05)
LXR1 = 1;
}
// If X is less than -0.5, turn on LXR2, turn off all others
else if (x_val < -0.5) {
LXR2 = 1;
}
// If X is between 0.05 and 0.5, turn on LXG2, turn off all others
else if (x_val > 0.05 && x_val < 0.5) { // 更精确的条件: (0.05 < x_val < 0.5)
LXG2 = 1;
}
// If X is greater than 0.5, turn on LXG1, turn off all others
else if (x_val > 0.5) {
LXG1 = 1;
}
// 如果x_val在-0.05到0.05之间 (接近0g),所有X轴LED保持熄灭状态
}
// 根据Y轴数据控制LED (对应实验指导 Task 4 要求)
void LED_Control_Y(float y_val) {
// 首先关闭所有Y轴相关的LED
LYG1 = 0; // Y轴正向 Green 1
LYG2 = 0; // Y轴正向 Green 2 (实验指导中为LYG2,代码中曾误为LYG1,已根据Task 4图示逻辑调整)
LYR1 = 0; // Y轴负向 Red 1
LYR2 = 0; // Y轴负向 Red 2
// 根据Y轴的加速度值点亮相应的LED
// 参照X轴的逻辑和Task 4对Y轴LED的命名 (LYG1, LYG2, LYR1, LYR2)
// 假设Y轴正向对应Green LED,负向对应Red LED
// If Y is between -0.05 and -0.5, turn on LYR1
if (y_val < -0.05 && y_val > -0.5) { // (-0.5 < y_val < -0.05)
LYR1 = 1;
}
// If Y is less than -0.5, turn on LYR2
else if (y_val < -0.5) {
LYR2 = 1;
}
// If Y is between 0.05 and 0.5, turn on LYG1 (Task 4图中Y正向对应LYG1/LYG2,此处选LYG1)
else if (y_val > 0.05 && y_val < 0.5) { // (0.05 < y_val < 0.5)
LYG1 = 1; // 根据用户代码中此条件对应LYG1
}
// If Y is greater than 0.5, turn on LYG2 (Task 4图中Y正向对应LYG1/LYG2,此处选LYG2)
else if (y_val > 0.5) {
LYG2 = 1; // 根据用户代码中此条件对应LYG2
}
// 如果y_val在-0.05到0.05之间 (接近0g),所有Y轴LED保持熄灭状态
}
//Main part///
int main() {
// 调用函数配置ADXL345加速度计的初始参数 (执行Task 2的配置)
configureAccelerometer();
// 主循环,无限执行
while (1) {
// 从ADXL345读取最新的加速度数据 (执行Task 3功能)
readAccelerometerData();
// 通过串口显示读取到的加速度数据 (执行Task 3功能)
displayAccelerometerData();
// 根据X轴和Y轴数据控制LED (执行Task 4功能)
LED_Control_X(x_axis_g);
LED_Control_Y(y_axis_g); // 取消注释以启用Y轴LED控制
// 使当前线程休眠。实验指导Task 3和4未指定特定延时,
// 此延时控制数据刷新和LED更新的频率。为了方便观察,可以设置为较小值或根据需要调整。
// 例如,100ms的延时可以提供较快的响应。
ThisThread::sleep_for(100ms); // 将延时从2000ms修改为100ms以获得更快的响应
}
return 0; // 理论上不会执行到这里,因为上面是无限循环
}
Task5:
#include "mbed.h"
Definition part
// 定义 SPI 引脚和常量 (根据实验指导 Task 1 和 Task 2 更新)
#define MOSI A6 // SPI 主机输出从机输入引脚
#define MISO A5 // SPI 主机输入从机输出引脚
#define SCLK A4 // SPI串行时钟引脚
#define CS_PIN D12 // SPI 片选引脚 (更正为实验指导中的 D12)
// 定义 LED 引脚 (根据实验指导 Task 1 和 Task 4 更新)
// X轴相关的LED
DigitalOut LXG1(D11); // X轴正向绿色LED 1 (LXG1: Left X Green 1 or X+ Green 1)
DigitalOut LXG2(D9); // X轴正向绿色LED 2 (LXG2: Left X Green 2 or X+ Green 2)
DigitalOut LXR1(D0); // X轴负向红色LED 1 (LXR1: Left X Red 1 or X- Red 1)
DigitalOut LXR2(D1); // X轴负向红色LED 2 (LXR2: Left X Red 2 or X- Red 2)
// Y轴相关的LED
DigitalOut LYG1(D6); // Y轴正向绿色LED 1 (LYG1: Landscape Y Green 1 or Y+ Green 1)
DigitalOut LYG2(A3); // Y轴正向绿色LED 2 (LYG2: Landscape Y Green 2 or Y+ Green 2)
DigitalOut LYR1(A2); // Y轴负向红色LED 1 (LYR1: Landscape Y Red 1 or Y- Red 1)
DigitalOut LYR2(A0); // Y轴负向红色LED 2 (LYR2: Landscape Y Red 2 or Y- Red 2)
// ADXL345 寄存器地址
#define REG_DATA_FORMAT 0x31 // 数据格式控制寄存器 (DATA_FORMAT)
#define REG_POWER_CTL 0x2D // 电源控制寄存器 (POWER_CTL)
#define REG_BW_RATE 0x2C // 数据速率和带宽控制寄存器 (BW_RATE)
#define REG_DATAX0 0x32 // X轴数据的第一个字节寄存器 (DATAX0), 后续为DATAX1, DATAY0, DATAY1, DATAZ0, DATAZ1
// ADXL345 配置值 (根据实验指导 Task 2)
#define DATA_FORMAT_CONFIG 0x0B // 数据格式配置 (REG_DATA_FORMAT, 地址 0x31):
// 实验指导 (Task 2) 要求: 4-wire SPI, FULL_RES, right-justified, +/-16g.
// Bit D7 (SELF_TEST) = 0: 禁用自检 (默认)
// Bit D6 (SPI) = 0: 4线SPI模式 (满足实验指导)
// Bit D5 (INT_INVERT) = 0: 中断高电平有效 (默认)
// Bit D4 = 0: (保留)
// Bit D3 (FULL_RES) = 1: 全分辨率模式 (满足实验指导)
// Bit D2 (Justify) = 0: 数据右对齐 (满足实验指导)
// Bits D1:D0 (Range) = 11: ±16g 量程 (满足实验指导)
// 最终配置值: 00001011 (0x0B)
#define POWER_CTL_CONFIG 0x08 // 电源控制配置 (REG_POWER_CTL, 地址 0x2D):
// 实验指导 (Task 2) 要求:
// - Link bit cleared (D5=0)
// - AUTO_SLEEP disabled (D4=0)
// - Measurement mode (D3=1)
// - Normal mode (Sleep bit D2=0)
// - 8 Hz sleep mode frequency (Wakeup bits D1:D0 = 00)
// 配置值 0x08 (二进制 00001000) 满足以上所有条件:
// D7=0, D6=0, D5(Link)=0, D4(AUTO_SLEEP)=0, D3(Measure)=1, D2(Sleep)=0, D1(Wakeup)=0, D0(Wakeup)=0.
#define BW_RATE_CONFIG 0x0D // 带宽速率配置 (REG_BW_RATE, 地址 0x2C):
// Bit D4 (LOW_POWER) = 0: 正常功耗模式。
// Bits D3:0 (Rate) = 1101 (0x0D): 设置输出数据速率 (ODR) 为 800 Hz, 带宽为 ODR/2 = 400 Hz。
// (注意: 实验指导Task 2的配置清单中未明确指定正常工作模式的ODR,此为代码选定值。
// 实验指导中提到的 "8 Hz sleep mode frequency" 是通过 POWER_CTL 寄存器设置的睡眠模式下的唤醒频率。)
#define Read_MULTIPLE_BIT (0x80 | 0x40) // SPI读取操作位组合:
// 0x80 (Read_BIT - D7=1): 表示读取操作。
// 0x40 (MB_BIT - D6=1): 表示多字节读取 (burst read) 模式。
// 用于从DATAX0开始连续读取6个字节的数据。
// SPI 通信参数 (根据实验指导 Task 2)
#define SPI_BIT_WIDTH 8 // SPI 数据位宽 (8位)
#define SPI_MODE 3 // SPI 模式 (CPOL=1, CPHA=1)。时钟空闲时为高电平,在第二个时钟边沿采样。
#define SPI_FREQUENCY 2000000 // SPI 通信频率 (2MHz)。
// 创建 SPI 对象和片选引脚对象
SPI spi(MOSI, MISO, SCLK); // SPI通信对象,参数为 MOSI, MISO, SCLK 引脚
DigitalOut chipSelect(CS_PIN); // 片选引脚数字输出对象
// 数据缓冲区和转换变量
char buffer[6]; // 用于存储从ADXL345读取的原始6字节数据 (X,Y,Z各两字节: X0, X1, Y0, Y1, Z0, Z1)
int16_t accelData[3]; // 用于存储转换后的16位带符号原始加速度数据 [X, Y, Z]
float accel_in_G_form[3]; // 用于存储转换为 'g' (重力加速度)单位的浮点型加速度数据 [X, Y, Z]
// 转换因子,用于将原始数据转换为 'g' 单位。
// 根据ADXL345数据手册,在全分辨率模式 (FULL_RES=1) 下,所有g量程的比例因子维持在约 4 mg/LSB。
// 4 mg/LSB = 0.004 g/LSB。
const float conversionFactor = 0.004;
// 用于存储各轴加速度值的全局变量 (方便在LED控制函数中使用)
float x_axis_g, y_axis_g, z_axis_g; // 在您的代码中命名为 x, y, z,这里保持一致性改为 x_axis_g 等
//Function part
// 配置 ADXL345 加速度计 (对应实验指导 Task 2)
void configureAccelerometer() {
// 初始化 SPI 通信参数
chipSelect = 1; // SPI片选引脚初始状态为高电平 (ADXL345未被选中)
spi.format(SPI_BIT_WIDTH, SPI_MODE); // 设置 SPI 数据格式: 8位数据宽度,模式3
spi.frequency(SPI_FREQUENCY); // 设置 SPI 通信频率: 2MHz
// 1. 配置数据格式寄存器 (REG_DATA_FORMAT)
chipSelect = 0; // 拉低片选,选中 ADXL345 以进行通信
spi.write(REG_DATA_FORMAT); // 发送要写入的寄存器地址 (0x31)
spi.write(DATA_FORMAT_CONFIG); // 发送数据格式配置值 (0x0B)
chipSelect = 1; // 拉高片选,结束本次SPI写操作
// 2. 配置数据带宽速率寄存器 (REG_BW_RATE)
chipSelect = 0; // 拉低片选
spi.write(REG_BW_RATE); // 发送要写入的寄存器地址 (0x2C)
spi.write(BW_RATE_CONFIG); // 发送带宽速率配置值 (0x0D: 800Hz ODR, 正常功耗)
chipSelect = 1; // 拉高片选
// 3. 配置电源控制寄存器 (REG_POWER_CTL)
chipSelect = 0; // 拉低片选
spi.write(REG_POWER_CTL); // 发送要写入的寄存器地址 (0x2D)
spi.write(POWER_CTL_CONFIG); // 发送电源控制配置值 (0x08)
chipSelect = 1; // 拉高片选
}
// 读取加速度计数据 (对应实验指导 Task 3 部分功能)
void readAccelerometerData() {
// 拉低片选,选中 ADXL345 以准备读取数据
chipSelect = 0;
// 发送起始读取寄存器地址 (DATAX0) 并设置读操作位和多字节读取位
spi.write(REG_DATAX0 | Read_MULTIPLE_BIT);
// 循环读取6个字节的数据 (X, Y, Z轴各2个字节)
for (int i = 0; i < 6; i++) {
buffer[i] = spi.write(0x00); // 发送虚拟字节0x00以在MISO线上接收一个字节的数据
}
// 拉高片选,结束本次SPI读操作
chipSelect = 1;
// 将接收到的高低字节合并为16位带符号整数数据
accelData[0] = (int16_t)((buffer[1] << 8) | buffer[0]); // X轴数据
accelData[1] = (int16_t)((buffer[3] << 8) | buffer[2]); // Y轴数据
accelData[2] = (int16_t)((buffer[5] << 8) | buffer[4]); // Z轴数据
// 将原始16位数据根据转换因子转换为 'g' 单位的浮点数值
for (int i = 0; i < 3; i++) {
accel_in_G_form[i] = conversionFactor * accelData[i];
}
// 将转换后的值赋给全局变量,方便其他函数使用 (您的代码中使用 x, y, z)
x_axis_g = accel_in_G_form[0]; // 保持与您代码中 x,y,z 变量的意图一致,但使用更明确的名称
y_axis_g = accel_in_G_form[1];
z_axis_g = accel_in_G_form[2];
}
// 通过串口显示加速度计数据 (对应实验指导 Task 3 要求)
void displayAccelerometerData() {
// 打印格式化的加速度数据到串行控制台
printf("===============\n");
printf("x = %+1.2fg\n", x_axis_g);
printf("y = %+1.2fg\n", y_axis_g);
printf("z = %+1.2fg\n", z_axis_g);
}
// 根据X轴数据控制LED (对应实验指导 Task 4 要求)
void LED_Control_X(float x_val) {
// 首先关闭所有X轴相关的LED
LXG1 = 0; LXR1 = 0;
LXG2 = 0; LXR2 = 0;
// 根据X轴的加速度值点亮相应的LED
if (x_val < -0.05 && x_val > -0.5) { // (-0.5 < x_val < -0.05)
LXR1 = 1;
} else if (x_val <= -0.5) { // 等于-0.5也应点亮LXR2
LXR2 = 1;
} else if (x_val > 0.05 && x_val < 0.5) { // (0.05 < x_val < 0.5)
LXG2 = 1;
} else if (x_val >= 0.5) { // 等于0.5也应点亮LXG1
LXG1 = 1;
}
}
// 根据Y轴数据控制LED (对应实验指导 Task 4 要求)
void LED_Control_Y(float y_val) {
// 首先关闭所有Y轴相关的LED
LYG1 = 0; LYR1 = 0;
LYG2 = 0; LYR2 = 0;
// 根据Y轴的加速度值点亮相应的LED
if (y_val < -0.05 && y_val > -0.5) { // (-0.5 < y_val < -0.05)
LYR1 = 1;
} else if (y_val <= -0.5) { // 等于-0.5也应点亮LYR2
LYR2 = 1;
} else if (y_val > 0.05 && y_val < 0.5) { // (0.05 < y_val < 0.5)
LYG1 = 1;
} else if (y_val >= 0.5) { // 等于0.5也应点亮LYG2
LYG2 = 1;
}
}
// 统一的LED控制函数 (对应实验指导 Task 5 的起点)
// Task 5 要求: "Modify the code to control the LEDs based on a combination of X and Y-axis readings."
// 当前实现是简单地分别调用X轴和Y轴的控制函数。
// 您可以在此函数中实现更复杂的组合逻辑。
void LED_Control(){
LED_Control_X(x_axis_g); // 使用全局变量 x_axis_g
LED_Control_Y(y_axis_g); // 使用全局变量 y_axis_g
}
//Main part///
int main() {
// 调用函数配置ADXL345加速度计的初始参数 (执行Task 2的配置)
configureAccelerometer();
// 主循环,无限执行
while (1) {
// 从ADXL345读取最新的加速度数据 (执行Task 3功能)
readAccelerometerData();
// 通过串口显示读取到的加速度数据 (执行Task 3功能)
displayAccelerometerData();
// 根据X轴和Y轴数据控制LED (执行Task 4 & 5 功能)
LED_Control();
// 使当前线程休眠。
// 您的代码中使用2000ms,这里改为100ms以获得更快的LED响应和数据刷新。
ThisThread::sleep_for(100ms);
}
return 0; // 理论上不会执行到这里,因为上面是无限循环
}