基于STM32F401RET6智能锁项目(BS82166A_3触摸按键)

一、BS81x 特征

• 工作电压:2.2V~5.5V
• 低待机电流
• 自动校准功能
• 可靠的触摸按键检测
• 自动切换待机 / 工作模式
• 最长按键输出时间检测
• 具备抗电压波动功能
• Level Hold,可选高有效或低有效
• NMOS 输出内建上拉电阻 /CMOS 直接 输出
• 支持串行和并行输出
• 外接电容调整感度
• 极少的外围组件

二、BS81x 概述

BS81x 系列芯片具有 2~16 个触摸按键,可用来检测外部触摸按键上人手的触摸动作。该系列的芯片具有较高的集成度,仅需极少的外部组件便可实现触摸按键的检测。
BS81x 系列提供了串行及并行输出功能,可方便与外部 MCU 之间的通讯,实现设备安装及触摸引脚监测目的。芯片内部采用特殊的集成电路,具有高电源电压抑制比,可减少按键检测错误的发生,此特性保证在不利环境条件的应用中芯片仍具有很高的可靠性。
此系列的触摸芯片具有自动校准功能,低待机电流,抗电压波动等特性,为各种触摸按键的应用提供了一种简单而又有效的实现方法。

三、BS8166介绍

我们这里使用的是BS8166A-3,下图所示:
a0065fed70b14783a1a21773d34d76b7.png

1、引脚特征

91dfe1c89be94300a6bec7f94d3a8ef1.png
按键:16个触摸按键
通信方式:IIC

2、接口电气特征

c866c7de3b4b40238136963fb4e4fa2a.png

3、读写时序流程

f19a6670711b491b97611493ea1ca28f.png

4a9e40d25f2b4ea8bcd1c1b4ef1dbb41.png

写设置:起始条件+一个字节(触摸芯片器件地址+W)+从机回响应信号+主机发送命令字节+从机回响应信号+主机发送起始信号+一个字节(触摸芯片器件地址+R)+从机回响应信号+读取输出(从机发送)+主机发送停止信号

6d22ba7a10af44bc9a6abae4c674693b.png

读1个字节设置:起始条件+一个字节(触摸芯片器件地址+R)+从机回响应信号+主机发送命令字节+从机回响应信号+主机发送起始信号+一个字节(触摸芯片器件地址+R)+从机回响应信号+读取输出(从机发送)+主机发送停止信号

4、IRQ功能

5ae42916a55c4f63a59673aab86c4784.png

a0a4145702eb49f3b02683e34140045d.png

输出模式:IRQ_OMS = 0 (Level hold,低有效)主机在 IRQ 低电平时读取按键数据,当按键数据为 0 时停止读取。

c2ae9ffc48624b948a54eb23d5a1d1ae.png

输出模式:IRQ_OMS = 1 (One-shot,低有效 )按键状态发生改变时,发一脉冲信号。
9c098255c5cc463aa29cac65fbe9ee76.png

不使用 IRQ 功能时:Key16 (BS8116A-3) 是触摸按键
当主机读取所有按键为松键 (KeyStatus=0x00) 后,主机可以降低读取速度,使功耗降低,降低读取速度时按键反应速度会变慢。
最长按键持续时间:为尽量减少如不小心碰触到感应电极等此类的无意按键检测,芯片内部设置了最长按键持续时间功能。当某个触摸按键按下时,内部定时器开始计时,一旦按键按下的时间过长,超过大约 64s 后,触摸芯片会忽略该被触摸键的状态,重新校准,获取新的基准值,同时输出状态重置为初始状态。
自动校准功能:上电后,芯片会进行初始化,取得第一次基准值,接下来,若在正常模式下 1s 内,待机模式下 32s 内,没有按键被按下,触摸芯片在固定的时间周期到后,将自动校准基准值,使得基准值可以根据外界环境进行动态的变化。

四、代码例程

1、硬件原理图

ce6fbcc56b5c401b8a38db45b8d0cdd8.png

dc3e8976014a4616972f85b7fe508474.png

2、完整代码

main.c

#include "led.h"
#include "delay.h"
#include "key.h"
#include "usart.h"
#include "stdio.h"
#include "myiic.h"
#include "at24c0x.h"
#include "BS8116_IIC1.h"
#include "BS8116.h"


int main(void)
{
	uint8_t key;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	SysTick_Config(SystemCoreClock/1000);   //配置1ms的中断
	Led_Config();
	USART1_Config();
//	At24c02_Config();
	BS8116_Config();



	while(1)
	{	
//		if(LED_Period[0]>=LED_Period[1])
//		{
//			LED_Period[0]=0;
//			led3_T();
//			led4_T();
//		}
			if(!BS8116_IRQ)//判断按键是否按下
			{
				key=BS8116ReadKey();
				if(key&&key!=0xFF)
				{
					printf("%c\r\n",key);
				}	
					while(!BS8116_IRQ);
			}
	}
}

IIC1.c

#include "BS8116_IIC1.h"
#include "delay.h"



/***************

SCL  PB6  开漏输出
SDA  PB7  开漏输出
***************/
void I2C1_config(void)
{
	//开启GPIOB的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
	
	//定义结构体
	GPIO_InitTypeDef GPIO_InitStruct;
	//给结构体内容赋值
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;   //输出模式
	GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;  //开漏模式
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStruct.GPIO_Speed = GPIO_Fast_Speed;
	
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	/*设置默认电平*/
	GPIO_SetBits(GPIOB, GPIO_Pin_6);
	GPIO_SetBits(GPIOB, GPIO_Pin_7);
}

/*
****************************************************************************************
* Function: IIC1_Start
* Description: 起始条件
* Input: None
* Output: None
* Return: None
* Author: weihaoMo
* Others: None
* Date of completion: 2019-11-29
* Date of last modify: 2019-11-29
****************************************************************************************
*/
void IIC1_Start(void)
{
	IIC1_SCL(0);
	Delay_us(6);
	IIC1_SDA_OUT(1);
	
	IIC1_SCL(1);
	Delay_us(6);//延时---起始条件的建立时间
	IIC1_SDA_OUT(0);//---产生起始条件
	Delay_us(6);//延时---起始条件的保持时间
	IIC1_SCL(0); //---结束起始条件
}

/*
****************************************************************************************
* Function: IIC1_Stop
* Description: 停止条件
* Input: None
* Output: None
* Return: None
* Author: weihaoMo
* Others: None
* Date of completion: 2019-11-29
* Date of last modify: 2019-11-29
****************************************************************************************
*/
void IIC1_Stop(void)
{
	IIC1_SDA_OUT(0);
	IIC1_SCL(1);
	Delay_us(6);//延时---停止条件的建立时间
	IIC1_SDA_OUT(1); //---产生了停止条件
	Delay_us(6);//延时---本次通信结束到下次通信开始的时间

}

/*
****************************************************************************************
* Function: IIC1_Send_Ack
* Description: 主机发送应答信号
* Input: ack--0表示有应答  1表示非应答
* Output: None
* Return: None
* Author: weihaoMo
* Others: None
* Date of completion: 2019-11-29
* Date of last modify: 2019-11-29
****************************************************************************************
*/
void IIC1_Send_Ack(uint8_t ack)
{

	IIC1_SCL(0);
	if(ack)//(主机准备数据)
		IIC1_SDA_OUT(1);
	else
		IIC1_SDA_OUT(0);
	Delay_us(6);//延时(数据稳定在数据线上)
	IIC1_SCL(1);//(从机在时钟线上升沿从SDA上采集数据)
	Delay_us(6);//延时(给时间从机读取数据)
	
//	IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
}

/*
****************************************************************************************
* Function: IIC1_Revice_Ack
* Description: 主机读取应答信号
* Input: None
* Output: None
* Return: 0--有应答  1--非应答
* Author: weihaoMo
* Others: None
* Date of completion: 2019-11-29
* Date of last modify: 2019-11-29
****************************************************************************************
*/
uint8_t IIC1_Revice_Ack(void)
{
	uint8_t ack=0;
	

	IIC1_SCL(0);//(从机准备数据)
	IIC1_SDA_OUT(1);//读模式-----让输出电路与管脚断开!!!!!!!!!!
	Delay_us(6);//延时(给时间从机准备数据并且数据稳定在数据线上)
	IIC1_SCL(1);
	Delay_us(6);//延时 (给时间主机读取数据)
	if(IIC1_SDA_IN)//主机读取SDA线上的数据
		ack=1;
	
	//IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
	
	return ack;
}

/*
****************************************************************************************
* Function: IIC1_Send_Byte
* Description: 主机发送一个字节给从机并且读取一次应答信号
* Input: 待发送的一个字节数据
* Output: None
* Return: 应答信号 0--有应答  1--非应答
* Author: weihaoMo
* Others: None
* Date of completion: 2019-11-29
* Date of last modify: 2019-11-29
****************************************************************************************
*/
uint8_t IIC1_Send_Byte(uint8_t data)
{
	uint8_t i=0;

	
	for(i=0;i<8;i++)
	{
		IIC1_SCL(0);
		if((data<<i)&0x80)//(主机准备数据)  
			IIC1_SDA_OUT(1);            
		else
			IIC1_SDA_OUT(0);
		Delay_us(6);//延时(数据稳定在数据线上)
		IIC1_SCL(1);//(从机在时钟线上升沿从SDA上采集数据)
		Delay_us(6);//延时(给时间从机读取数据)
	}
	//IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
	
	return IIC1_Revice_Ack( );
}

/*
****************************************************************************************
* Function: IIC1_Revice_Byte
* Description: 主机读取一个字节并且发送一次应答信号
* Input: 应答信号 0--有应答  1--非应答
* Output: None
* Return: 读取的一个字节数据
* Author: weihaoMo
* Others: None
* Date of completion: 2019-11-29
* Date of last modify: 2019-11-29
****************************************************************************************
*/
uint8_t IIC1_Revice_Byte(uint8_t ack)
{
	uint8_t i=0;
	uint8_t data=0;
	
	for(i=0;i<8;i++)
	{
		IIC1_SCL(0);//(从机准备数据)
		IIC1_SDA_OUT(1);//读模式-----让输出电路与管脚断开!!!!!!!!!!
		Delay_us(6);//延时(给时间从机准备数据并且数据稳定在数据线上)
		IIC1_SCL(1);
		data = (data<<1) | (IIC1_SDA_IN);
		Delay_us(6);//延时 (给时间主机读取数据)
		
	}
	//IIC1_SCL=0;//方便后续的操作;防止意外产生了停止条件
	
	IIC1_Send_Ack(ack);
	
	return data;
}


IIC1.h

#ifndef _BS8116_IIC1_H_
#define _BS8116_IIC1_H_

#include "stm32f4xx.h"
#define IIC1_SCL(x)           GPIO_WriteBit(GPIOB,GPIO_Pin_6,(BitAction)x)
#define IIC1_SDA_OUT(x)    GPIO_WriteBit(GPIOB,GPIO_Pin_7,(BitAction)x)
#define IIC1_SDA_IN        GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)
#define IIC1_SCL_IN 		   GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)
void I2C1_config(void);
void IIC1_Start(void);
void IIC1_Stop(void);
uint8_t IIC1_Send_Byte(uint8_t data);
uint8_t IIC1_Revice_Byte(uint8_t ack);

#endif

BS8116.c

#include "BS8116.h"
#include "BS8116_IIC1.h"
#include "delay.h"
#include "stdio.h"

void BS8116_Config(void)
{
	I2C1_config();
	//打开GPIOA的时钟  BS8116_IRQ-PA1
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
	
}

uint8_t BS8116ReadKey(void)
{
	uint16_t data;
	IIC1_Start();   			 	 //起始条件
	IIC1_Send_Byte(0xA0);     //主机发送一个字节:1010 0000 前7位是从机地址 最后是‘写’
	Delay_us(5);
	while(!IIC1_SCL_IN);

	IIC1_Send_Byte(0x08);  //触摸按键的输出寄存器地址
	Delay_us(5);
	while(!IIC1_SCL_IN);

	
	IIC1_Start();   			 	 //起始条件
	IIC1_Send_Byte(0xA1);		//1010 0001
	Delay_us(5);
	while(!IIC1_SCL_IN);

	data = IIC1_Revice_Byte(0);
	data|=IIC1_Revice_Byte(1)<<8;	
	IIC1_Stop( );

	switch(data)
	{
		case 0X8081:return   '1'; 
		case 0X8480:return   '2';
		case 0X8080:return   '3';
		case 0X8082:return   '4';
		case 0X8880:return   '5';
		case 0X80C0:return   '6';
		case 0X8088:return   '7';
		case 0X8180:return   '8';
		case 0X80A0:return   '9';
		case 0X8084:return   '*';
		case 0X8280:return   '0';
		case 0X8090:return   '#';
	}
	return 0;
}


BS8116.h

#ifndef _BS8116_H_
#define _BS8116_H_

#include "stm32f4xx.h"

#define BS8116_IRQ (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1))


void BS8116_Config(void);
uint8_t BS8116ReadKey(void);

#endif

3、实验现象

按下按键会显示对应的数字。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值