一、硬件说明
引脚图:
接线:
说明:由于用到了唤醒检测,所以KEY16引脚用作IRQ中断唤醒功能,未使用引脚拉低。
二、IIC配置说明
1、最大波特率:
实际单片机配置最好不要设置波特率100Khz容易出错,50Khz就可以了。
2、从机地址:
注意:这里需要注意的是,从机地址位不包括读写位,实际使用需要右移一位,从机地址是0x50实际发送读是0xA1,写是0xA0。
3、从机忙碌
这个判断程序里面还是加一下,不加的话一般也能用,但是容易出问题。
三、读写按键寄存器
1、中断说明:
检测到IRQ引脚低电平开始读取按键状态,高电平停止读取。
2、工作模式:
这里需要注意在8秒按键没有按下时,会进入低功耗状态。两种状态下的按键唤醒速度是不同的,体验有明显差异,且无法修改进入休眠时间。
3、读取按键状态
4、读写配置寄存器
注意:最后是一个字节的校验和,只是简单的单字节累加从合泰同类型其他手册里找到说明了。
5、配置寄存器
注意:触发门槛值越低敏感度越高,门槛值数值越高敏感度越低。
免大家去查表直接复制过来了。
四、代码片段
1、配置寄存器数据结构
#define KEY_ADDR1_8 0x08
#define KEY_ADDR9_12 0x09
#define REG_CFG_ADDR 0xB0
#define REG_CFG_CNT 21
#pragma pack(1) //单字节对齐
typedef union {
uint8_t reg[REG_CFG_CNT+1];
struct {
uint8_t opt1_oms : 1;
uint8_t opt1_17_res:7;
uint8_t res1;
uint8_t res2;
uint8_t res3;
uint8_t opt2_05_res : 6;
uint8_t opt2_6_lsc : 1;
uint8_t opt2_7_res : 1;
uint8_t k1_th_val : 6;
uint8_t k1_th_res : 1;
uint8_t k1_th_wu : 1;
uint8_t k2_th_val : 6;
uint8_t k2_th_res : 1;
uint8_t k2_th_wu : 1;
uint8_t k3_th_val : 6;
uint8_t k3_th_res : 1;
uint8_t k3_th_wu : 1;
uint8_t k4_th_val : 6;
uint8_t k4_th_res : 1;
uint8_t k4_th_wu : 1;
uint8_t k5_th_val : 6;
uint8_t k5_th_res : 1;
uint8_t k5_th_wu : 1;
uint8_t k6_th_val : 6;
uint8_t k6_th_res : 1;
uint8_t k6_th_wu : 1;
uint8_t k7_th_val : 6;
uint8_t k7_th_res : 1;
uint8_t k7_th_wu : 1;
uint8_t k8_th_val : 6;
uint8_t k8_th_res : 1;
uint8_t k8_th_wu : 1;
uint8_t k9_th_val : 6;
uint8_t k9_th_res : 1;
uint8_t k9_th_wu : 1;
uint8_t k10_th_val : 6;
uint8_t k10_th_res : 1;
uint8_t k10_th_wu : 1;
uint8_t k11_th_val : 6;
uint8_t k11_th_res : 1;
uint8_t k11_th_wu : 1;
uint8_t k12_th_val : 6;
uint8_t k12_th_res : 1;
uint8_t k12_th_wu : 1;
uint8_t k13_th_val : 6;
uint8_t k13_th_res : 1;
uint8_t k13_th_wu : 1;
uint8_t k14_th_val : 6;
uint8_t k14_th_res : 1;
uint8_t k14_th_wu : 1;
uint8_t k15_th_val : 6;
uint8_t k15_th_res : 1;
uint8_t k15_th_wu : 1;
uint8_t k16_th_val : 6;
uint8_t k16_th_mod : 1;
uint8_t k16_th_wu : 1;
uint8_t checksum;
}setting;
} key_setting_t;
#pragma pack()
2、初始化配置寄存器
void TK_Module_Cfg(void)
{
int i;
rt_int32_t ret = 0;
key_setting_t write_setting = {{0x00,0x00,0x83,0xf3,0xd8,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0xf,0x4f,0},},read_setting={0};
for(i=0;i<REG_CFG_CNT;i++){
write_setting.setting.checksum += write_setting.reg[i];
}
for(i=0;i<30;i++){
TK_WriteReg(&write_setting);
rt_thread_mdelay(1);
TK_ReadReg(&read_setting);
ret = rt_memcmp(&write_setting,&read_setting,REG_CFG_CNT);
if(ret==0){
break;
}
}
}
3、寄存器读写
//写寄存器
int TK_I2c_WriteReg(uint8_t *dest,uint16_t count,uint8_t reg)
{
uint8_t u8i=0,flag[10]={0},idx=0,u8State;
uint32_t u32KeyTimer = rt_tick_get()+200;
I2C_ClearFunc(BS8116A_IIC,I2cStart_En);
I2C_ClearFunc(BS8116A_IIC,I2cAck_En);
I2C_ClearFunc(BS8116A_IIC,I2cStop_En);
I2C_SetFunc(BS8116A_IIC,I2cModule_En);
I2C_SetFunc(BS8116A_IIC,I2cStart_En);
while(u32KeyTimer > rt_tick_get())
{
while(0 == I2C_GetIrq(BS8116A_IIC) && u32KeyTimer > rt_tick_get()){;}
u8State = I2C_GetState(BS8116A_IIC);
switch(u8State)
{
case 0x08: //已发送起始条件,将发送SLA+R
flag[0]++;
I2C_ClearFunc(BS8116A_IIC,I2cStart_En);
I2C_WriteByte(BS8116A_IIC,(I2C_DEVADDR));//发送SLA+W
break;
case 0x18: //已发送SLA+W,并接收到ACK
flag[1]++;
while(!IIC_READ_SDA){}
I2C_WriteByte(BS8116A_IIC,reg); //发送内存地址
case 0x20:
flag[2]++;
I2C_WriteByte(BS8116A_IIC,reg); //发送内存地址
break;
case 0x28: //已发送 I2Cx_DATA 中的数据,已接收 ACK
flag[3]++;
I2C_WriteByte(BS8116A_IIC,dest[u8i++]); //发送内存地址
if(u8i>count){
I2C_SetFunc(BS8116A_IIC,I2cStop_En); //其他错误状态,重新发送起始条件
goto FINISH;
}
break;
default: //其他错误状态,重新发送起始条件
flag[9]++;
I2C_SetFunc(BS8116A_IIC,I2cStop_En); //其他错误状态,重新发送起始条件
goto FINISH;
}
I2C_ClearIrq(BS8116A_IIC); //清除中断状态标志位
idx++;
}
FINISH:
I2C_ClearIrq(BS8116A_IIC); //清除中断状态标志位
return 0;
}
//获取按键码
int TK_I2c_ReadReg(uint8_t *dest,uint16_t count,uint8_t reg)
{
en_result_t enRet = Error;
uint8_t u8i=0,flag[10]={0},idx=0,u8State,pu8Data[32]={0};
uint32_t u32KeyTimer = rt_tick_get()+200;
I2C_ClearFunc(BS8116A_IIC,I2cStart_En);
I2C_ClearFunc(BS8116A_IIC,I2cAck_En);
I2C_ClearFunc(BS8116A_IIC,I2cStop_En);
I2C_SetFunc(BS8116A_IIC,I2cModule_En);
I2C_SetFunc(BS8116A_IIC,I2cStart_En);
while(u32KeyTimer > rt_tick_get())
{
while(0 == I2C_GetIrq(BS8116A_IIC) && u32KeyTimer > rt_tick_get()){;}
u8State = I2C_GetState(BS8116A_IIC);
switch(u8State)
{
case 0x08: //已发送起始条件,将发送SLA+R
flag[0]++;
I2C_ClearFunc(BS8116A_IIC,I2cStart_En);
I2C_WriteByte(BS8116A_IIC,(I2C_DEVADDR));//发送SLA+W
break;
case 0x18: //已发送SLA+W,并接收到ACK
flag[1]++;
while(!IIC_READ_SDA){}
I2C_WriteByte(BS8116A_IIC,reg); //发送内存地址
break;
case 0x28: //已发送数据,接收到ACK
flag[2]++;
I2C_SetFunc(BS8116A_IIC,I2cStart_En);
break;
case 0x10: //已发送重复起始条件
flag[3]++;
I2C_ClearFunc(BS8116A_IIC,I2cStart_En);
I2C_WriteByte(BS8116A_IIC,(I2C_DEVADDR)|0x01);//读命令发送
break;
case 0x40: //已发送SLA+R,并接收到ACK
flag[4]++;
if(count>1){
I2C_SetFunc(BS8116A_IIC,I2cAck_En);
}
break;
case 0x50: //已接收数据字节,并已返回ACK信号
flag[5]++;
pu8Data[u8i++] = I2C_ReadByte(BS8116A_IIC);
if(u8i>=count)
{
I2C_ClearFunc(BS8116A_IIC,I2cAck_En); //读数据时,倒数第二个字节ACK关闭
}else{
I2C_SetFunc(BS8116A_IIC,I2cAck_En);
}
break;
case 0x58: //已接收到最后一个数据,NACK已返回
case 0x38: //在发送地址或数据时,仲裁丢失
case 0x48: //发送SLA+R后,收到一个NACK
default: //其他错误状态,重新发送起始条件
flag[9]++;
I2C_SetFunc(BS8116A_IIC,I2cStop_En); //其他错误状态,重新发送起始条件
goto FINISH;
}
I2C_ClearIrq(BS8116A_IIC); //清除中断状态标志位
idx++;
}
FINISH:
I2C_ClearIrq(BS8116A_IIC); //清除中断状态标志位
rt_memcpy(dest,pu8Data,count);
return 0;
}
void TK_ReadReg(key_setting_t * setting)
{
uint8_t * pset = (uint8_t *)setting,i=0;
TK_I2c_ReadReg(pset,REG_CFG_CNT,REG_CFG_ADDR);
}
void TK_WriteReg(key_setting_t * setting)
{
uint8_t * pset = (uint8_t *)setting,i=0;
uint16_t checksum = 0;
TK_I2c_WriteReg(pset,REG_CFG_CNT+1,REG_CFG_ADDR);
}
uint16_t TK_GetKey(void)
{
uint8_t pu8Data[2]={0};
uint16_t key_status = 0;
TK_I2c_ReadReg(pu8Data,2,KEY_ADDR1_8);
key_status = pu8Data[1];
key_status = key_status<<8 | pu8Data[0];
return key_status;
}
结束。