本次试用基于瑞萨RA6E2开发板,通过硬件IIC协议驱动GY-85九轴传感器模块(包含ITG3205陀螺仪、ADXL345加速度计和QMC5883P磁力计),并在OLED屏幕上实时显示传感器采集的原始数据。项目直接使用现有的完整代码实现,未对传感器数据进行滤波处理,仅获取和显示基本数据,部分数据来源与AI不保证100%准确。
| 传感器 | 型号 | 通信协议 | 测量范围 |
|---|---|---|---|
| 陀螺仪 | ITG3205 | I2C | ±2000°/s |
| 加速度计 | ADXL345 | I2C | ±16g |
| 磁力计 | QMC5883P | I2C | ±8 Gauss |
基于现有代码实现的系统架构:
text
+───────────────────+ +───────────────────+ +───────────────────+
│ 传感器数据采集 │ │ 数据处理与转换 │ │ OLED显示管理 │
│ - ITG3205陀螺仪 │───▶│ - 原始数据解析 │───▶│ - 多页面显示 │
│ - ADXL345加速度计 │ │ - 单位转换 │ │ - 按键切换 │
│ - QMC5883P磁力计 │ │ │ │ - 实时刷新 │
+───────────────────+ +───────────────────+ +───────────────────+
│ │ │
└────────────────────────┼────────────────────────┘
│
+───────────────────+
│ 硬件IIC驱动层 │
│ - 多设备管理 │
│ - 回调处理 │
+───────────────────+
#include "hal_data.h"
// 类型定义简化
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
const unsigned char asc2_0806[][6] ={/* 6*8 ascii*/};
// OLED命令和数据模式定义
#define OLED_CMD 0x00
#define OLED_DATA 0x40
// I2C设备地址定义
#define OLED_ADDR 0x3C
#define ITG3205_ADDR 0xD0
#define ADXL345_ADDR 0xA6
#define QMC5883P_ADDR 0x2C
// GPIO操作宏定义
#define WRITE_GPIO_PIN(pin, level) \
R_IOPORT_PinWrite(&g_ioport_ctrl, pin, level)
#define READ_GPIO_PIN(pin) \
({ \
bsp_io_level_t level; \
R_IOPORT_PinRead(&g_ioport_ctrl, pin, &level); \
level; \
})
// I2C通信状态变量
static volatile bool g_i2c_complete = false; // I2C传输完成标志
static fsp_err_t g_i2c_result = FSP_SUCCESS; // I2C操作结果
/**
* [url=home.php?mod=space&uid=2666770]@Brief[/url] I2C主控回调函数
* [url=home.php?mod=space&uid=3142012]@param[/url] p_args 回调参数指针
* [url=home.php?mod=space&uid=1902110]@NOTE[/url] 处理I2C传输完成和错误事件
*/
void sci_i2c_master_callback(i2c_master_callback_args_t * p_args)
{
if (NULL != p_args)
{
switch (p_args->event)
{
case I2C_MASTER_EVENT_TX_COMPLETE: // 发送完成事件
case I2C_MASTER_EVENT_RX_COMPLETE: // 接收完成事件
g_i2c_complete = true;
g_i2c_result = FSP_SUCCESS;
break;
case I2C_MASTER_EVENT_ABORTED: // 传输中止事件
g_i2c_complete = true;
g_i2c_result = FSP_ERR_ABORTED;
break;
default:
break;
}
}
}
/**
* @brief OLED I2C初始化
* @note 初始化OLED的I2C通信接口
*/
void I2C_SCI_OLED_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
err = R_SCI_I2C_Open(&g_i2c_sci_oled_ctrl, &g_i2c_sci_oled_cfg);
if (FSP_SUCCESS != err)
{
while(1); // 初始化失败,进入死循环
}
}
/**
* @brief 加速度计I2C初始化
* @note 初始化ADXL345的I2C通信接口
*/
void I2C_SCI_ACCEL_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
err = R_SCI_I2C_Open(&g_i2c_sci_accel_ctrl, &g_i2c_sci_accel_cfg);
if (FSP_SUCCESS != err)
{
while(1);
}
}
/**
* @brief 陀螺仪I2C初始化
* @note 初始化ITG3205的I2C通信接口
*/
void I2C_SCI_GYRO_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
err = R_SCI_I2C_Open(&g_i2c_sci_gyro_ctrl, &g_i2c_sci_gyro_cfg);
if (FSP_SUCCESS != err)
{
while(1);
}
}
/**
* @brief 磁力计I2C初始化
* @note 初始化QMC5883P的I2C通信接口
*/
void I2C_SCI_MAG_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
err = R_SCI_I2C_Open(&g_i2c_sci_mag_ctrl, &g_i2c_sci_mag_cfg);
if (FSP_SUCCESS != err)
{
while(1);
}
}
/**
* @brief I2C写数据函数
* @param dev_addr 设备地址
* @param mode 命令/数据模式
* @param dat 要写入的数据
* @note 向指定I2C设备写入数据
*/
void IIC_Write(u8 dev_addr, u8 mode, u8 dat)
{
fsp_err_t err = FSP_SUCCESS;
uint8_t write_buffer[2] = {mode, dat}; // 数据缓冲区
g_i2c_complete = false;
// 根据设备地址选择对应的I2C控制器
if(dev_addr == OLED_ADDR)
{
I2C_SCI_OLED_Init();
err = R_SCI_I2C_Write(&g_i2c_sci_oled_ctrl, write_buffer, 2, false);
}
else if(dev_addr == ITG3205_ADDR)
{
I2C_SCI_GYRO_Init();
err = R_SCI_I2C_Write(&g_i2c_sci_gyro_ctrl, write_buffer, 2, false);
}
else if(dev_addr == ADXL345_ADDR)
{
I2C_SCI_ACCEL_Init();
err = R_SCI_I2C_Write(&g_i2c_sci_accel_ctrl, write_buffer, 2, false);
}
else if(dev_addr == QMC5883P_ADDR)
{
I2C_SCI_MAG_Init();
err = R_SCI_I2C_Write(&g_i2c_sci_mag_ctrl, write_buffer, 2, false);
}
if (FSP_SUCCESS != err)
{
while(1); // 写入失败,进入死循环
}
// 等待传输完成
while (!g_i2c_complete)
{
__NOP(); // 空操作,等待中断
}
}
/**
* @brief I2C读数据函数
* @param dev_addr 设备地址
* @param reg_addr 寄存器地址
* [url=home.php?mod=space&uid=1141835]@Return[/url] 读取到的数据
* @note 从指定I2C设备的寄存器读取数据
*/
u8 IIC_Read(u8 dev_addr, u8 reg_addr)
{
fsp_err_t err = FSP_SUCCESS;
u8 reg_data = 0;
uint8_t write_buffer[1] = {reg_addr}; // 寄存器地址缓冲区
g_i2c_complete = false;
// 先写入要读取的寄存器地址
if(dev_addr == OLED_ADDR)
{
I2C_SCI_OLED_Init();
err = R_SCI_I2C_Write(&g_i2c_sci_oled_ctrl, write_buffer, 1, false);
}
else if(dev_addr == ITG3205_ADDR)
{
I2C_SCI_GYRO_Init();
err = R_SCI_I2C_Write(&g_i2c_sci_gyro_ctrl, write_buffer, 1, false);
}
else if(dev_addr == ADXL345_ADDR)
{
I2C_SCI_ACCEL_Init();
err = R_SCI_I2C_Write(&g_i2c_sci_accel_ctrl, write_buffer, 1, false);
}
else if(dev_addr == QMC5883P_ADDR)
{
I2C_SCI_MAG_Init();
err = R_SCI_I2C_Write(&g_i2c_sci_mag_ctrl, write_buffer, 1, false);
}
if (FSP_SUCCESS != err)
{
while(1);
}
// 等待写入完成
while (!g_i2c_complete)
{
__NOP();
}
uint8_t read_buffer[1] = {0}; // 读取数据缓冲区
g_i2c_complete = false;
// 读取数据
if(dev_addr == OLED_ADDR)
{
err = R_SCI_I2C_Read(&g_i2c_sci_oled_ctrl, read_buffer, 1, false);
}
else if(dev_addr == ITG3205_ADDR)
{
err = R_SCI_I2C_Read(&g_i2c_sci_gyro_ctrl, read_buffer, 1, false);
}
else if(dev_addr == ADXL345_ADDR)
{
I2C_SCI_ACCEL_Init();
err = R_SCI_I2C_Read(&g_i2c_sci_accel_ctrl, read_buffer, 1, false);
}
else if(dev_addr == QMC5883P_ADDR)
{
I2C_SCI_MAG_Init();
err = R_SCI_I2C_Read(&g_i2c_sci_mag_ctrl, read_buffer, 1, false);
}
if (FSP_SUCCESS != err)
{
while(1);
}
// 等待读取完成
while (!g_i2c_complete)
{
__NOP();
}
reg_data = read_buffer[0];
return reg_data;
}
/**
* @brief 设置OLED显示位置
* @param x 横坐标 (0-127)
* @param y 纵坐标 (0-7,每页8行)
* @note 设置OLED的GRAM写入位置
*/
void OLED_Set_Pos(u8 x, u8 y)
{
IIC_Write(OLED_ADDR, OLED_CMD, 0xb0 + y); // 设置页地址
IIC_Write(OLED_ADDR, OLED_CMD, ((x & 0xf0) >> 4) | 0x10); // 设置列地址高4位
IIC_Write(OLED_ADDR, OLED_CMD, (x & 0x0f)); // 设置列地址低4位
}
/**
* @brief 计算幂函数
* @param m 底数
* @param n 指数
* @return m的n次方
* @note 用于数字显示时的位权计算
*/
u32 oled_pow(u8 m, u8 n)
{
u32 result = 1;
while(n--) result *= m;
return result;
}
/**
* @brief 显示单个字符
* @param x 起始横坐标
* @param y 起始纵坐标
* @param chr 要显示的字符
* @param sizey 字符高度(8或16)
* @note 在指定位置显示指定大小的ASCII字符
*/
void OLED_ShowChar(u8 x, u8 y, u8 chr, u8 sizey)
{
u8 c = 0, sizex = sizey / 2; // 字符宽度为高度的一半
u16 i = 0, size1;
// 计算字符数据大小
if(sizey == 8)
size1 = 6; // 6*8字符
else
size1 = (sizey / 8 + ((sizey % 8) ? 1 : 0)) * (sizey / 2); // 16*8字符
c = chr - ' '; // 计算字符在字库中的索引
OLED_Set_Pos(x, y);
// 逐字节写入字符数据
for(i = 0; i < size1; i++)
{
// 16像素字符需要换行
if(i % sizex == 0 && sizey != 8)
OLED_Set_Pos(x, y++);
// 根据字符大小选择字库
if(sizey == 8)
IIC_Write(OLED_ADDR, OLED_DATA, asc2_0806[c][i]);
else if(sizey == 16)
IIC_Write(OLED_ADDR, OLED_DATA, asc2_1608[c][i]);
else
return;
}
}
/**
* @brief 显示数字
* @param x 起始横坐标
* @param y 起始纵坐标
* @param num 要显示的数字
* @param len 数字长度
* @param sizey 字符高度
* @note 在指定位置显示指定长度的数字
*/
void OLED_ShowNum(u8 x, u8 y, u32 num, u8 len, u8 sizey)
{
u8 t, temp, m = 0;
u8 enshow = 0; // 前导零抑制标志
if(sizey == 8)
m = 2; // 8像素字符间距调整
// 逐位显示数字
for(t = 0; t < len; t++)
{
temp = (num / oled_pow(10, len - t - 1)) % 10; // 提取当前位数字
// 前导零抑制处理
if(enshow == 0 && t < (len - 1))
{
if(temp == 0)
{
OLED_ShowChar(x + (sizey / 2 + m) * t, y, ' ', sizey);
continue;
}
else
enshow = 1;
}
OLED_ShowChar(x + (sizey / 2 + m) * t, y, temp + '0', sizey);
}
}
/**
* @brief 显示字符串
* @param x 起始横坐标
* @param y 起始纵坐标
* @param chr 字符串指针
* @param sizey 字符高度
* @note 在指定位置显示字符串
*/
void OLED_ShowString(u8 x, u8 y, u8 *chr, u8 sizey)
{
u8 j = 0;
while (chr[j] != '\0')
{
OLED_ShowChar(x, y, chr[j++], sizey);
// 根据字符大小调整下一个字符位置
if(sizey == 8)
x += 6; // 8像素字符宽度+间距
else
x += sizey / 2; // 16像素字符宽度
}
}
/**
* @brief 清屏函数
* @note 清除OLED所有显示内容
*/
void OLED_Clear(void)
{
u8 i, n;
for(i = 0; i < 8; i++) // 遍历所有页(8页)
{
OLED_Set_Pos(0, i);
for(n = 0; n < 128; n++)
IIC_Write(OLED_ADDR, OLED_DATA, 0); // 写入0清除像素
}
}
/**
* @brief OLED初始化
* @note 初始化OLED显示控制器,配置各种显示参数
*/
void OLED_Init(void)
{
// OLED初始化命令序列
IIC_Write(OLED_ADDR, OLED_CMD, 0xAE); // 关闭显示
IIC_Write(OLED_ADDR, OLED_CMD, 0x00); // 设置低列地址
IIC_Write(OLED_ADDR, OLED_CMD, 0x10); // 设置高列地址
IIC_Write(OLED_ADDR, OLED_CMD, 0x40); // 设置起始行地址
IIC_Write(OLED_ADDR, OLED_CMD, 0x81); // 对比度设置
IIC_Write(OLED_ADDR, OLED_CMD, 0xCF); // 对比度值(0-255)
IIC_Write(OLED_ADDR, OLED_CMD, 0xA1); // 设置段重映射
IIC_Write(OLED_ADDR, OLED_CMD, 0xC8); // 设置COM扫描方向
IIC_Write(OLED_ADDR, OLED_CMD, 0xA6); // 设置正常显示
IIC_Write(OLED_ADDR, OLED_CMD, 0xA8); // 设置多路复用率
IIC_Write(OLED_ADDR, OLED_CMD, 0x3f); // 多路复用值
IIC_Write(OLED_ADDR, OLED_CMD, 0xD3); // 设置显示偏移
IIC_Write(OLED_ADDR, OLED_CMD, 0x00); // 显示偏移值
IIC_Write(OLED_ADDR, OLED_CMD, 0xd5); // 设置显示时钟分频
IIC_Write(OLED_ADDR, OLED_CMD, 0x80); // 分频比值
IIC_Write(OLED_ADDR, OLED_CMD, 0xD9); // 设置预充电周期
IIC_Write(OLED_ADDR, OLED_CMD, 0xF1); // 预充电周期值
IIC_Write(OLED_ADDR, OLED_CMD, 0xDA); // 设置COM硬件配置
IIC_Write(OLED_ADDR, OLED_CMD, 0x12); // COM配置值
IIC_Write(OLED_ADDR, OLED_CMD, 0xDB); // 设置VCOMH电平
IIC_Write(OLED_ADDR, OLED_CMD, 0x40); // VCOMH值
IIC_Write(OLED_ADDR, OLED_CMD, 0x20); // 设置内存地址模式
IIC_Write(OLED_ADDR, OLED_CMD, 0x02); // 页地址模式
IIC_Write(OLED_ADDR, OLED_CMD, 0x8D); // 电荷泵设置
IIC_Write(OLED_ADDR, OLED_CMD, 0x14); // 启用电荷泵
IIC_Write(OLED_ADDR, OLED_CMD, 0xA4); // 全部像素点开启
IIC_Write(OLED_ADDR, OLED_CMD, 0xA6); // 设置正常显示
OLED_Clear(); // 清屏
IIC_Write(OLED_ADDR, OLED_CMD, 0xAF); // 开启显示
}
/**
* @brief 开启显示
* @note 唤醒OLED显示
*/
void OLED_Display_On(void)
{
IIC_Write(OLED_ADDR, OLED_CMD, 0xAF);
}
/**
* @brief 关闭显示
* @note 进入OLED睡眠模式
*/
void OLED_Display_Off(void)
{
IIC_Write(OLED_ADDR, OLED_CMD, 0xAE);
}
/**
* @brief 颜色反转设置
* @param mode 0-正常显示, 1-颜色反转
* @note 设置OLED显示颜色模式
*/
void OLED_ColorTurn(u8 mode)
{
if(mode == 0)
IIC_Write(OLED_ADDR, OLED_CMD, 0xA6); // 正常显示
else
IIC_Write(OLED_ADDR, OLED_CMD, 0xA7); // 颜色反转
}
/**
* @brief 显示方向设置
* @param mode 0-正常方向, 1-旋转180度
* @note 设置OLED显示方向
*/
void OLED_DisplayTurn(u8 mode)
{
if(mode == 0)
{
IIC_Write(OLED_ADDR, OLED_CMD, 0xC8); // 正常扫描方向
IIC_Write(OLED_ADDR, OLED_CMD, 0xA1); // 正常段重映射
}
else
{
IIC_Write(OLED_ADDR, OLED_CMD, 0xC0); // 反转扫描方向
IIC_Write(OLED_ADDR, OLED_CMD, 0xA0); // 反转段重映射
}
}
/**
* @brief 显示BMP图片
* @param x0 起始横坐标
* @param y0 起始纵坐标
* @param x1 结束横坐标
* @param y1 结束纵坐标
* @param BMP 图片数据数组
* @note 在指定区域显示位图
*/
void OLED_DrawBMP(u8 x0, u8 y0, u8 x1, u8 y1, const u8 BMP[])
{
u16 j = 0;
u8 x, y;
// 计算页数
if(y1 % 8 == 0)
y = y1 / 8;
else
y = y1 / 8 + 1;
// 逐页逐列写入图片数据
for(y = y0; y < y1; y++)
{
OLED_Set_Pos(x0, y);
for(x = x0; x < x1; x++)
{
IIC_Write(OLED_ADDR, OLED_DATA, BMP[j++]);
}
}
}
/**
* @brief 显示中文字符
* @param x 起始横坐标
* @param y 起始纵坐标
* @param index 汉字在字库中的索引
* @param sizey 字符高度(16)
* @note 在指定位置显示16*16中文字符
*/
void OLED_ShowChinese(u8 x, u8 y, u8 index, u8 sizey)
{
u8 i;
u8 x0 = x; // 保存起始x坐标
OLED_Set_Pos(x, y);
if(sizey == 16)
{
// 显示汉字上半部分(16字节)
for(i = 0; i < 16; i++)
{
IIC_Write(OLED_ADDR, OLED_DATA, Hzk[index][i]);
x++;
if((x - x0) == 16) // 换行
{
x = x0;
y++;
OLED_Set_Pos(x, y);
}
}
OLED_Set_Pos(x, y);
// 显示汉字下半部分(16字节)
for(i = 16; i < 32; i++)
{
IIC_Write(OLED_ADDR, OLED_DATA, Hzk[index][i]);
x++;
if((x - x0) == 16) // 换行
{
x = x0;
y++;
OLED_Set_Pos(x, y);
}
}
}
}
/**
* @brief 初始化ITG3205陀螺仪
* @note 配置陀螺仪采样率、量程和滤波器等参数
*/
void Init_ITG3205()
{
// 重置设备
IIC_Write(ITG3205_ADDR, 0x3E, 0x80);
R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);
// 设置采样率分频器 - 采样率 = 1kHz / (7+1) = 125Hz
IIC_Write(ITG3205_ADDR, 0x15, 0x07);
// 配置DLPF和全量程 - 设置为最高精度配置
// Bit[4:3] = 11 (FS_SEL=3, ±2000°/s), Bit[2:0] = 010 (DLPF_CFG=2, 98Hz带宽)
// 0x1E = 00011110 -> FS_SEL=3, DLPF_CFG=2
IIC_Write(ITG3205_ADDR, 0x16, 0x1E);
// 中断配置 - 禁用中断
IIC_Write(ITG3205_ADDR, 0x17, 0x00);
// 电源管理 - 选择PLL with Z Gyro作为时钟源(最高稳定性)
// CLK_SEL = 3 (PLL with Z Gyro reference)
IIC_Write(ITG3205_ADDR, 0x3E, 0x03);
R_BSP_SoftwareDelay(50, BSP_DELAY_UNITS_MILLISECONDS); // 等待稳定
}
/**
* @brief 初始化ADXL345加速度计
* @note 配置加速度计量程、数据率和测量模式
*/
void Init_ADXL345()
{
// 设置数据格式:全分辨率模式,±16g范围
// 0x0B = 00001011: SELF_TEST=0, SPI=0, INT_INVERT=0, FULL_RES=1, Justify=0, Range=11(±16g)
IIC_Write(ADXL345_ADDR, 0x31, 0x0B);
// 设置带宽和输出数据率:100Hz(平衡精度和响应速度)
// 0x0A = 00001010: LOW_POWER=0, Rate=1010 (100Hz)
IIC_Write(ADXL345_ADDR, 0x2C, 0x0A);
// 电源控制:进入测量模式
// 0x08 = 00001000: Link=0, AUTO_SLEEP=0, Measure=1, Sleep=0, Wakeup=00
IIC_Write(ADXL345_ADDR, 0x2D, 0x08);
// 中断使能:使能数据就绪中断(可选)
IIC_Write(ADXL345_ADDR, 0x2E, 0x80);
// 偏移校准(根据实际测量调整)
IIC_Write(ADXL345_ADDR, 0x1E, 0x00); // X轴偏移
IIC_Write(ADXL345_ADDR, 0x1F, 0x00); // Y轴偏移
IIC_Write(ADXL345_ADDR, 0x20, 0x00); // Z轴偏移(先设为0,根据实际测量校准)
// 等待稳定
R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);
}
/**
* @brief 初始化QMC5883P磁力计
* @note 配置磁力计工作模式和输出数据率
*/
void Init_QMC5883P(void)
{
IIC_Write(QMC5883P_ADDR, 0x0a, 0xff); // 配置寄存器A
IIC_Write(QMC5883P_ADDR, 0x0b, 0x01); // 配置寄存器B
}
/**
* @brief 显示陀螺仪数据
* @note 读取并显示ITG3205的三轴角速度数据
*/
void oledDisplayGyro(void)
{
float gyro_x, gyro_y, gyro_z;
char disp_buf[16];
u8 BUF[6];
int16_t raw_x, raw_y, raw_z;
// 读取陀螺仪原始数据(16位有符号)
// X轴: 0x1D(高), 0x1E(低)
BUF[0] = IIC_Read(ITG3205_ADDR, 0x1D); // GYRO_XOUT_H
BUF[1] = IIC_Read(ITG3205_ADDR, 0x1E); // GYRO_XOUT_L
// Y轴: 0x1F(高), 0x20(低)
BUF[2] = IIC_Read(ITG3205_ADDR, 0x1F); // GYRO_YOUT_H
BUF[3] = IIC_Read(ITG3205_ADDR, 0x20); // GYRO_YOUT_L
// Z轴: 0x21(高), 0x22(低)
BUF[4] = IIC_Read(ITG3205_ADDR, 0x21); // GYRO_ZOUT_H
BUF[5] = IIC_Read(ITG3205_ADDR, 0x22); // GYRO_ZOUT_L
// 组合16位数据(有符号)
raw_x = (int16_t)((BUF[0] << 8) | BUF[1]);
raw_y = (int16_t)((BUF[2] << 8) | BUF[3]);
raw_z = (int16_t)((BUF[4] << 8) | BUF[5]);
// 转换为度/秒 (灵敏度: 14.375 LSB/(°/s))
gyro_x = (float)raw_x / 14.375f;
gyro_y = (float)raw_y / 14.375f;
gyro_z = (float)raw_z / 14.375f;
// 显示标题
OLED_ShowString(40, 1, (u8*)"Gyroscope", 8);
// 显示X轴数据
OLED_ShowString(0, 3, (u8*)"X-axis:", 8);
if(gyro_x >= 0)
sprintf(disp_buf, "+%07.2f dps", gyro_x);
else
sprintf(disp_buf, "%08.2f dps", gyro_x);
OLED_ShowString(50, 3, (u8*)disp_buf, 8);
// 显示Y轴数据
OLED_ShowString(0, 5, (u8*)"Y-axis:", 8);
if(gyro_y >= 0)
sprintf(disp_buf, "+%07.2f dps", gyro_y);
else
sprintf(disp_buf, "%08.2f dps", gyro_y);
OLED_ShowString(50, 5, (u8*)disp_buf, 8);
// 显示Z轴数据
OLED_ShowString(0, 7, (u8*)"Z-axis:", 8);
if(gyro_z >= 0)
sprintf(disp_buf, "+%07.2f dps", gyro_z);
else
sprintf(disp_buf, "%08.2f dps", gyro_z);
OLED_ShowString(50, 7, (u8*)disp_buf, 8);
R_BSP_SoftwareDelay(60, BSP_DELAY_UNITS_MILLISECONDS); // 显示延时
}
/**
* @brief 显示加速度计数据
* @note 读取并显示ADXL345的三轴加速度数据
*/
void oledDisplayAccel(void)
{
float accel_x, accel_y, accel_z;
char disp_buf[16];
u8 BUF[6];
int16_t raw_x, raw_y, raw_z;
// 读取加速度数据寄存器
BUF[0] = IIC_Read(ADXL345_ADDR, 0x32); // DATAX0 - X轴低字节
BUF[1] = IIC_Read(ADXL345_ADDR, 0x33); // DATAX1 - X轴高字节
BUF[2] = IIC_Read(ADXL345_ADDR, 0x34); // DATAY0 - Y轴低字节
BUF[3] = IIC_Read(ADXL345_ADDR, 0x35); // DATAY1 - Y轴高字节
BUF[4] = IIC_Read(ADXL345_ADDR, 0x36); // DATAZ0 - Z轴低字节
BUF[5] = IIC_Read(ADXL345_ADDR, 0x37); // DATAZ1 - Z轴高字节
// 组合16位数据(有符号)
raw_x = (int16_t)((BUF[1] << 8) | BUF[0]);
raw_y = (int16_t)((BUF[3] << 8) | BUF[2]);
raw_z = (int16_t)((BUF[5] << 8) | BUF[4]);
// 转换为加速度值(mg)
// 全分辨率模式,±16g范围:灵敏度 = 3.9 mg/LSB
accel_x = (float)raw_x * 3.9f;
accel_y = (float)raw_y * 3.9f;
accel_z = (float)raw_z * 3.9f;
// 显示标题
OLED_ShowString(30, 1, (u8*)"Accelerometer", 8);
// 显示X轴数据
OLED_ShowString(0, 3, (u8*)"X-axis:", 8);
if(accel_x >= 0)
sprintf(disp_buf, "+%07.1f mg", accel_x);
else
sprintf(disp_buf, "%08.1f mg", accel_x);
OLED_ShowString(50, 3, (u8*)disp_buf, 8);
// 显示Y轴数据
OLED_ShowString(0, 5, (u8*)"Y-axis:", 8);
if(accel_y >= 0)
sprintf(disp_buf, "+%07.1f mg", accel_y);
else
sprintf(disp_buf, "%08.1f mg", accel_y);
OLED_ShowString(50, 5, (u8*)disp_buf, 8);
// 显示Z轴数据
OLED_ShowString(0, 7, (u8*)"Z-axis:", 8);
if(accel_z >= 0)
sprintf(disp_buf, "+%07.1f mg", accel_z);
else
sprintf(disp_buf, "%08.1f mg", accel_z);
OLED_ShowString(50, 7, (u8*)disp_buf, 8);
R_BSP_SoftwareDelay(60, BSP_DELAY_UNITS_MILLISECONDS);
}
/**
* @brief 显示磁力计数据
* @note 读取并显示QMC5883P的三轴磁场强度数据
*/
void oledDisplayMagnetic(void)
{
float uT_x, uT_y, uT_z;
char disp_buf[16];
int16_t raw_x, raw_y, raw_z;
u8 BUF[6];
// 读取磁力计原始数据
BUF[0] = IIC_Read(QMC5883P_ADDR, 0x01);
BUF[1] = IIC_Read(QMC5883P_ADDR, 0x02);
BUF[2] = IIC_Read(QMC5883P_ADDR, 0x03);
BUF[3] = IIC_Read(QMC5883P_ADDR, 0x04);
BUF[4] = IIC_Read(QMC5883P_ADDR, 0x05);
BUF[5] = IIC_Read(QMC5883P_ADDR, 0x06);
// 组合16位数据(有符号)
raw_x = (int16_t)((BUF[1] << 8) | BUF[0]);
raw_y = (int16_t)((BUF[3] << 8) | BUF[2]);
raw_z = (int16_t)((BUF[5] << 8) | BUF[4]);
// 转换为微特斯拉 (灵敏度: 0.1 uT/LSB)
uT_x = raw_x * 0.1f;
uT_y = raw_y * 0.1f;
uT_z = raw_z * 0.1f;
// 显示标题(居中显示)
OLED_ShowString((128 - 6 * 12) / 2, 1, (u8*)"Magnetometer", 8);
// 显示X轴数据
OLED_ShowString(0, 3, (u8*)"X-axis:", 8);
if(uT_x >= 0)
sprintf(disp_buf, "+%07.1f uT", uT_x);
else
sprintf(disp_buf, "-%07.1f uT", -uT_x);
OLED_ShowString(50, 3, (u8*)disp_buf, 8);
// 显示Y轴数据
OLED_ShowString(0, 5, (u8*)"Y-axis:", 8);
if(uT_y >= 0)
sprintf(disp_buf, "+%07.1f uT", uT_y);
else
sprintf(disp_buf, "-%07.1f uT", -uT_y);
OLED_ShowString(50, 5, (u8*)disp_buf, 8);
// 显示Z轴数据
OLED_ShowString(0, 7, (u8*)"Z-axis:", 8);
if(uT_z >= 0)
sprintf(disp_buf, "+%07.1f uT", uT_z);
else
sprintf(disp_buf, "-%07.1f uT", -uT_z);
OLED_ShowString(50, 7, (u8*)disp_buf, 8);
R_BSP_SoftwareDelay(60, BSP_DELAY_UNITS_MILLISECONDS);
}
/**
* @brief 显示主界面
* @note 显示传感器数据的主界面布局,包含三轴数据的标题和占位符
*/
void oledDisplayMain()
{
// 显示标题行
OLED_ShowString(6, 1, (u8*)"Sensor", 8);
OLED_ShowString(50 + 9, 1, (u8*)"X", 8);
OLED_ShowString(50 + 9 + 4 * 6 + 3, 1, (u8*)"Y", 8);
OLED_ShowString(50 + 9 + 8 * 6 + 3 + 3, 1, (u8*)"Z", 8);
// 显示陀螺仪数据行
OLED_ShowString(0, 3, (u8*)"Gry(dps)", 8);
OLED_ShowString(50, 3, (u8*)"00.0", 8);
OLED_ShowString(50 + 4 * 6 + 3, 3, (u8*)"00.0", 8);
OLED_ShowString(50 + 8 * 6 + 6, 3, (u8*)"00.0", 8);
// 显示加速度计数据行
OLED_ShowString(3, 5, (u8*)"Acc(mg)", 8);
OLED_ShowString(50, 5, (u8*)"00.0", 8);
OLED_ShowString(50 + 4 * 6 + 3, 5, (u8*)"00.0", 8);
OLED_ShowString(50 + 8 * 6 + 6, 5, (u8*)"00.0", 8);
// 显示磁力计数据行
OLED_ShowString(3, 7, (u8*)"Mag(uT)", 8);
OLED_ShowString(50, 7, (u8*)"00.0", 8);
OLED_ShowString(50 + 4 * 6 + 3, 7, (u8*)"00.0", 8);
OLED_ShowString(50 + 8 * 6 + 6, 7, (u8*)"00.0", 8);
}
/**
* @brief 系统主初始化
* @note 初始化所有硬件模块:GPIO、OLED、传感器等
*/
void Main_Init()
{
// 初始化GPIO引脚(按键检测)
R_IOPORT_PinCfg(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_05, IOPORT_CFG_PORT_DIRECTION_OUTPUT);
WRITE_GPIO_PIN(BSP_IO_PORT_00_PIN_05, BSP_IO_LEVEL_HIGH);
// 延时等待系统稳定
R_BSP_SoftwareDelay(200, BSP_DELAY_UNITS_MILLISECONDS);
// 初始化各硬件模块
OLED_Init(); // 初始化OLED显示
Init_ITG3205(); // 初始化陀螺仪
Init_ADXL345(); // 初始化加速度计
Init_QMC5883P(); // 初始化磁力计
// 配置OLED显示参数
OLED_Display_On(); // 开启显示
OLED_ColorTurn(0); // 正常颜色模式
OLED_DisplayTurn(0); // 正常显示方向
}
/**
* @brief 主程序入口
* @note 系统主循环,处理按键切换和数据显示
*/
void hal_entry(void)
{
Main_Init(); // 系统初始化
while(1)
{
static u8 i = 0; // 显示页面索引
// 检测按键按下(低电平有效)
if(READ_GPIO_PIN(BSP_IO_PORT_00_PIN_05) == BSP_IO_LEVEL_LOW)
{
OLED_Clear(); // 清屏
i += 1; // 切换到下一页
// 等待按键释放(防抖)
while(READ_GPIO_PIN(BSP_IO_PORT_00_PIN_05) == BSP_IO_LEVEL_LOW);
}
i %= 4; // 页面循环(0-3)
// 根据页面索引显示不同内容
if(i == 0)
oledDisplayMain(); // 显示主界面
else if(i == 1)
oledDisplayGyro(); // 显示陀螺仪数据
else if(i == 2)
oledDisplayAccel(); // 显示加速度计数据
else if(i == 3)
oledDisplayMagnetic(); // 显示磁力计数据
// 主循环延时
R_BSP_SoftwareDelay(100, BSP_DELAY_UNITS_MILLISECONDS);
}
}
// 安全构建相关代码(TrustZone支持)
#if BSP_TZ_SECURE_BUILD
FSP_CPP_HEADER
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();
BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ()
{
// 非安全可调用函数模板
}
FSP_CPP_FOOTER
#endif
现有代码实现了四个I2C设备的独立管理:
每个设备都有独立的初始化函数和控制结构体,通过统一的IIC读写接口进行通信。
代码直接读取传感器原始数据并进行基本转换:
陀螺仪数据 :
度/秒 = 原始数据 / 14.375加速度计数据 :
mg = 原始数据 × 3.9磁力计数据 :
μT = 原始数据 × 0.1通过GPIO按键实现四个显示页面的切换:
| 测试项目 | 预期结果 | 实际结果 | 状态 |
|---|---|---|---|
| I2C总线初始化 | 成功识别所有设备 | 4个设备均正常识别 | ✅ |
| 陀螺仪数据采集 | 输出三轴角速度 | X/Y/Z轴数据正常输出 | ✅ |
| 加速度计数据采集 | 输出三轴加速度 | 静态1g,动态响应正常 | ✅ |
| 磁力计数据采集 | 输出三轴磁场强度 | 受地磁场影响明显 | ✅ |
| OLED多页面显示 | 按键切换显示内容 | 四个页面正常切换 | ✅ |
| 实时数据刷新 | 持续稳定显示 | 无卡顿、无数据丢失 | ✅ |
基于现有代码的实际运行表现:
由于采用简易数据读取(无滤波和校准),观察到以下现象:
现有代码充分利用了RA6E2的硬件IIC特性:
代码具有良好的模块化结构:
通过现有代码的成功运行,验证了以下能力:
基于本次试用体验,RA6E2特别适合以下应用场景:
RA6E2开发板在九轴传感器应用场景中表现优秀,硬件IIC接口稳定可靠,处理性能充足,开发环境友好。现有代码实现了基本功能需求,系统运行稳定,为更复杂的传感器应用奠定了良好基础。
更多回帖