STM32 STC15系列单片机的APDS-9960手势识别模块代码实现
一、硬件连接配置
| APDS-9960引脚 | STC15引脚 | 功能说明 |
|---|---|---|
| VCC | 3.3V | 电源供电 |
| GND | GND | 地线 |
| SDA | P1.0 | I2C数据线 |
| SCL | P1.1 | I2C时钟线 |
| INT | INT0 | 手势中断 |
二、核心代码实现
1. I2C底层驱动
#include <STC15F2K60S2.h>
#define APDS9960_ADDR 0x39 << 1 // 7位地址左移1位
sbit SDA = P1^0;
sbit SCL = P1^1;
// I2C延时函数
void I2C_Delay() {
unsigned char i;
for(i=0; i<100; i++);
}
// 产生起始信号
void I2C_Start() {
SDA = 1;
SCL = 1;
I2C_Delay();
SDA = 0;
I2C_Delay();
SCL = 0;
}
// 产生停止信号
void I2C_Stop() {
SDA = 0;
SCL = 1;
I2C_Delay();
SDA = 1;
I2C_Delay();
}
// 发送一个字节
unsigned char I2C_WriteByte(unsigned char dat) {
unsigned char i;
for(i=0; i<8; i++) {
SDA = (dat & 0x80) ? 1 : 0;
SCL = 1;
I2C_Delay();
SCL = 0;
dat <<= 1;
}
SDA = 1; // 释放SDA线
SCL = 1;
i = SDA; // 读取ACK
SCL = 0;
return ~i; // 返回ACK状态
}
// 读取一个字节
unsigned char I2C_ReadByte(unsigned char ack) {
unsigned char i, dat=0;
SDA = 1;
for(i=0; i<8; i++) {
SCL = 1;
I2C_Delay();
dat <<= 1;
dat |= SDA;
SCL = 0;
}
if(ack) SDA = 0; // 发送ACK
else SDA = 1; // 发送NACK
SCL = 1;
I2C_Delay();
SCL = 0;
return dat;
}
2. APDS-9960驱动
#define GESTURE_NONE 0
#define GESTURE_UP 1
#define GESTURE_DOWN 2
#define GESTURE_LEFT 3
#define GESTURE_RIGHT 4
// 寄存器地址定义
#define APDS9960_ENABLE 0x80
#define APDS9960_ATIME 0x81
#define APDS9960_WTIME 0x83
#define APDS9960_GCONF4 0xAB
#define APDS9960_GPENTH 0xA0
#define APDS9960_GEXTH 0xA1
#define APDS9960_GFIFO_U 0xFC
// 初始化APDS-9960
bit APDS9960_Init() {
I2C_Start();
if(I2C_WriteByte(APDS9960_ADDR) != 0) return 0; // 检测ACK
I2C_WriteByte(0x00); // 复位所有寄存器
I2C_Stop();
// 基础配置
APDS9960_WriteReg(APDS9960_ENABLE, 0x00); // 关闭所有功能
APDS9960_WriteReg(APDS9960_ATIME, 0xC0); // 103ms积分时间
APDS9960_WriteReg(APDS9960_WTIME, 0xF9); // 27ms等待时间
// 手势配置
APDS9960_WriteReg(APDS9960_GCONF4, 0x01); // 4方向手势检测
APDS9960_WriteReg(APDS9960_GPENTH, 0x28); // 进入阈值40
APDS9960_WriteReg(APDS9960_GEXTH, 0x1E); // 退出阈值30
APDS9960_WriteReg(APDS9960_GCONF1, 0x40); // 手势数据FIFO深度
// 使能手势检测
APDS9960_WriteReg(APDS9960_ENABLE, 0x41); // 使能手势+电源
return 1;
}
// 读取手势数据
unsigned char APDS9960_ReadGesture() {
unsigned char fifo_data[128];
unsigned char gstatus;
APDS9960_ReadReg(APDS9960_GSTATUS, &gstatus, 1);
if(!(gstatus & 0x01)) return GESTURE_NONE; // 无手势
APDS9960_ReadReg(APDS9960_GFLVL, &fifo_len, 1);
APDS9960_ReadReg(APDS9960_GFIFO_U, fifo_data, fifo_len*4);
// 简单手势判断算法
int16_t ud_diff = 0, lr_diff = 0;
for(int i=0; i<fifo_len; i++) {
ud_diff += fifo_data[i*4] - fifo_data[i*4+1];
lr_diff += fifo_data[i*4+2] - fifo_data[i*4+3];
}
if(abs(ud_diff) > abs(lr_diff)) {
return (ud_diff > 0) ? GESTURE_UP : GESTURE_DOWN;
} else {
return (lr_diff > 0) ? GESTURE_RIGHT : GESTURE_LEFT;
}
}
// 寄存器操作函数
bit APDS9960_WriteReg(unsigned char reg, unsigned char dat) {
I2C_Start();
if(I2C_WriteByte(APDS9960_ADDR) != 0) return 0;
if(I2C_WriteByte(reg) != 0) return 0;
if(I2C_WriteByte(dat) != 0) return 0;
I2C_Stop();
return 1;
}
bit APDS9960_ReadReg(unsigned char reg, unsigned char *dat, unsigned char len) {
I2C_Start();
if(I2C_WriteByte(APDS9960_ADDR) != 0) return 0;
if(I2C_WriteByte(reg) != 0) return 0;
I2C_Start();
if(I2C_WriteByte(APDS9960_ADDR|0x01) != 0) return 0;
while(len--) *dat++ = I2C_ReadByte(0);
I2C_Stop();
return 1;
}
三、主程序设计
#include <STC15F2K60S2.h>
// 全局变量
unsigned char gesture;
void main() {
// 硬件初始化
P1M1 = 0x00; // 设置P1口为准双向
P1M0 = 0x00;
// 初始化APDS-9960
if(!APDS9960_Init()) {
while(1); // 初始化失败
}
// 配置外部中断
IT0 = 1; // 下降沿触发
EX0 = 1; // 使能外部中断0
EA = 1; // 总中断使能
while(1) {
// 主循环处理其他任务
gesture = APDS9960_ReadGesture();
if(gesture != GESTURE_NONE) {
// 执行手势对应操作
switch(gesture) {
case GESTURE_UP: // 向上手势处理
break;
case GESTURE_DOWN: // 向下手势处理
break;
case GESTURE_LEFT: // 向左手势处理
break;
case GESTURE_RIGHT:// 向右手势处理
break;
}
}
}
}
// 外部中断0服务函数
void EX0_ISR() interrupt 0 {
gesture = APDS9960_ReadGesture(); // 中断读取手势
}
四、关键配置说明
- I2C配置: 时钟频率:100kHz(通过I2C_Delay函数控制) 地址模式:7位地址(左移1位) 数据格式:8位数据+1位ACK
- 手势检测参数: 积分时间:103ms(ATIME=0xC0) 等待时间:27ms(WTIME=0xF9) 进入阈值:40(GPENTH=0x28) 退出阈值:30(GEXTH=0x1E)
- 中断配置: 触发方式:下降沿触发(INT0) 中断优先级:最高优先级
参考代码 APDS9960模块基于STM32 STC15的代码 www.youwenfan.com/contentcnn/73283.html
五、调试与优化建议
-
硬件调试要点: 检查3.3V供电稳定性 确认I2C上拉电阻(建议4.7kΩ) 使用逻辑分析仪验证I2C通信波形
-
软件优化方向:
// 提高手势识别精度 #define GESTURE_FILTER_SIZE 5 static int gesture_buffer[GESTURE_FILTER_SIZE] = {0}; // 滑动平均滤波 void Gesture_Filter() { static int index = 0; gesture_buffer[index++] = gesture; if(index >= GESTURE_FILTER_SIZE) index = 0; int sum = 0; for(int i=0; i<GESTURE_FILTER_SIZE; i++) { sum += gesture_buffer[i]; } gesture = (sum >= GESTURE_FILTER_SIZE/2) ? gesture : GESTURE_NONE; } -
功耗优化:
// 低功耗模式配置 void Enter_LowPower() { APDS9960_WriteReg(APDS9960_ENABLE, 0x00); // 关闭所有功能 PCON |= 0x01; // 进入空闲模式 }

浙公网安备 33010602011771号