触摸控制芯片MPR121驱动移植(STM32)

  • 本文记录将arduino下的mpr121触摸板驱动程序移植到stam32f1

1、触摸板简介

之前买了块mpr121做主控的触摸控制板(如下图),卖家给的驱动是arduino的,最近做项目需要移植到stm32上。看了mpr121的用户指南和arduino的程序,其实要移植要做的工作也不是特别多,主要就是iic和外部中断。
mpr121触摸板

2、移植思路

mpr121采用中断方式与MCU通信,协议用的是IIC。移植要做的就是做好stm32的iic和外部中断初始化,然后按照mpr121的通信要求封装IIC的几个基本函数就行了,步骤整理如下。
1、stm32下的外部中断配置和IIC通信配置
2、按照用户手册的要求封装基本的IIC函数
3、移植初始化函数和按键读取函数

3、移植

3.1、stm32的IIC和外部中断配置

这里问我直接用的正点原子的模拟IIC例程和野火的外部中断例程。外部中断初始化后就是中断服务函数的编写,这个放在后面按键读取函数那说明。IIC使用模拟的,这个点原子的例程里提供了几个基本的通信函数。

//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口				 
void IIC_Start(void);				//发送IIC开始信号
void IIC_Stop(void);	  			//发送IIC停止信号
void IIC_Send_Byte(u8 txd);			//IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); 				//IIC等待ACK信号
void IIC_Ack(void);					//IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送ACK信号

其中IIC_Read_Byte(unsigned char ack)这个函数的说明如下

//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)

3.2、IIC通信函数的封装

卖家给的例程里跟mpr121通信的函数有两个,一个是 unsigned char mpr121Read(uint8_t address)另一个是void mpr121Write(unsigned char address, unsigned char data)(这里原本的程序读取是分成两步的,我把它合并成一步了)。我们只要按照mpr121的通信要求实现这两个函数就行。

这里我对stm32的iic通信函数又做了一次封装为的是少打代码(笑),如下:
/*********************
 ****I2C Functions****
 *********************/ 

void i2cInit(void)   //iic引脚初始化
{ 
	IIC_Init();
}


void i2cSendStart(void)  // 发送起始信号
{  
	IIC_Start();

}

void i2cSendStop(void)   //发送终止信号
{    
	// transmit stop condition
       IIC_Stop();
}

void i2cWaitForComplete(void)   //等待应答信号
{
	IIC_Wait_Ack();
} 

void i2cSendByte(unsigned char data)  //发送一个字节
{ 
	IIC_Send_Byte(data);
}

unsigned char i2cReceiveByte(unsigned char ackFlag)   //接收一个字节,ackFlag=1:应答,ackFlag=0:不应答
{
	return IIC_Read_Byte(ackFlag);
}

·发送函数

mpr121用户手册中接收数据的时序要求如下图
mpr121接收

例程中使用的是上图第二个通信时序,我们照搬就成,程序实现如下



void mpr121Write(unsigned char address, unsigned char data)
{
  i2cSendStart();
  
  i2cSendByte(MPR121_W);// write 0xB4
  i2cWaitForComplete();
  
  i2cSendByte(address);	// write register address
  i2cWaitForComplete();
  
  i2cSendByte(data);
  i2cWaitForComplete();
  
  i2cSendStop();

}
  • 读取函数
    mpr121用户手册中对读取的时序要求如下
    读mpr121
    函数实现如下
unsigned char mpr121Read(uint8_t address)
{
  unsigned char  data;
  
  i2cSendStart();
 
  
  i2cSendByte(MPR121_W);	// write 0xB4
  i2cWaitForComplete();
  
  i2cSendByte(address);	// write register address
  i2cWaitForComplete();
  
  i2cSendStart();
  
  i2cSendByte(MPR121_R);	// write 0xB5
  i2cWaitForComplete();
  data =i2cReceiveByte(TRUE);
  
  
  i2cSendStop();
  
  return data;
}

其中有关地址的说明如下,设备地址左移一位,最低位为1或0表示读或者写(具体参考mpr121数据手册)


#define MPR121_R 0xB5	// ADD pin is grounded
#define MPR121_W 0xB4	// So address is 0x5A

3.3、 移植初始化函数和按键读取函数

实现了与mpr121通信之后就是对mpr121的初始化了,这里我直接用的例程中的初始化序列,如果是后期自己做touchpad的话还得自己去看数据手册并且更改相应的参数,这里就不深入探讨了。

  • 初始化序列如下(外部中断的初始化也放在了这里)
void mpr121QuickConfig(void)
{
	
	 mpr121_irqInit();//interrupt set
  // Section A
  // This group controls filtering when data is > baseline.
  mpr121Write(MHD_R, 0x01);
  mpr121Write(NHD_R, 0x01);
  mpr121Write(NCL_R, 0x00);
  mpr121Write(FDL_R, 0x00);

  // Section B
  // This group controls filtering when data is < baseline.
  mpr121Write(MHD_F, 0x01);
  mpr121Write(NHD_F, 0x01);
  mpr121Write(NCL_F, 0xFF);
  mpr121Write(FDL_F, 0x02);
  
  // Section C
  // This group sets touch and release thresholds for each electrode
  mpr121Write(ELE0_T, TOU_THRESH);
  mpr121Write(ELE0_R, REL_THRESH);
  mpr121Write(ELE1_T, TOU_THRESH);
  mpr121Write(ELE1_R, REL_THRESH);
  mpr121Write(ELE2_T, TOU_THRESH);
  mpr121Write(ELE2_R, REL_THRESH);
  mpr121Write(ELE3_T, TOU_THRESH);
  mpr121Write(ELE3_R, REL_THRESH);
  mpr121Write(ELE4_T, TOU_THRESH);
  mpr121Write(ELE4_R, REL_THRESH);
  mpr121Write(ELE5_T, TOU_THRESH);
  mpr121Write(ELE5_R, REL_THRESH);
  mpr121Write(ELE6_T, TOU_THRESH);
  mpr121Write(ELE6_R, REL_THRESH);
  mpr121Write(ELE7_T, TOU_THRESH);
  mpr121Write(ELE7_R, REL_THRESH);
  mpr121Write(ELE8_T, TOU_THRESH);
  mpr121Write(ELE8_R, REL_THRESH);
  mpr121Write(ELE9_T, TOU_THRESH);
  mpr121Write(ELE9_R, REL_THRESH);
  mpr121Write(ELE10_T, TOU_THRESH);
  mpr121Write(ELE10_R, REL_THRESH);
  mpr121Write(ELE11_T, TOU_THRESH);
  mpr121Write(ELE11_R, REL_THRESH);
  
  // Section D
  // Set the Filter Configuration
  // Set ESI2
  mpr121Write(FIL_CFG, 0x04);
  
  // Section E
  // Electrode Configuration
  // Enable 6 Electrodes and set to run mode
  // Set ELE_CFG to 0x00 to return to standby mode
  mpr121Write(ELE_CFG, 0x0C);	// Enables all 12 Electrodes
  //mpr121Write(ELE_CFG, 0x06);		// Enable first 6 electrodes
  
  // Section F
  // Enable Auto Config and auto Reconfig
  /*mpr121Write(ATO_CFG0, 0x0B);
  mpr121Write(ATO_CFGU, 0xC9);	// USL = (Vdd-0.7)/vdd*256 = 0xC9 @3.3V   mpr121Write(ATO_CFGL, 0x82);	// LSL = 0.65*USL = 0x82 @3.3V
  mpr121Write(ATO_CFGT, 0xB5);*/	// Target = 0.9*USL = 0xB5 @3.3V

}

然后就是按键读取了,这里的思路是在外部中断的中断服务程序中将按键标志置位,然后在主程序中检测到标志置位后再读取键值,当然也可以在中断服务程序中就完成这些工作。代码如下

  • 中断服务程序
void KEY1_IRQHandler(void)
{
  //确保是否产生了EXTI Line中断
	if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) 
	{
		key_pressed=0;
		LED0=!LED0;
    //清除中断标志位
		EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);     
	}  
}
  • 键值读取
char getPhoneNumber()
{
  int touchNumber;
	int j;
  uint16_t touchstatus;
	char key=-1;
  //Serial.println("Please Enter a phone number...");
  
    //while(key_pressed);//用while读取会阻塞程序运行
	if(key_pressed==0)//非阻塞方式
	{
	key_pressed=1;
    touchNumber = 0;
    
    touchstatus = mpr121Read(0x01) << 8;
    touchstatus |= mpr121Read(0x00);
    
    for (j=0; j<12; j++)  // Check how many electrodes were pressed
    {
      if ((touchstatus & (1<<j)))
        touchNumber++;
    }
    
    if (touchNumber == 1)
    {
      if (touchstatus & (1<<STAR))
        key = '*';
      else if (touchstatus & (1<<SEVEN))
        key = '7';
      else if (touchstatus & (1<<FOUR))
        key= '4';
      else if (touchstatus & (1<<ONE))
        key = '1';
      else if (touchstatus & (1<<ZERO))
        key= '0';
      else if (touchstatus & (1<<EIGHT))
        key = '8';
      else if (touchstatus & (1<<FIVE))
        key = '5';
      else if (touchstatus & (1<<TWO))
        key = '2';
      else if (touchstatus & (1<<POUND))
        key = '#';
      else if (touchstatus & (1<<NINE))
        key = '9';
      else if (touchstatus & (1<<SIX))
        key = '6';
      else if (touchstatus & (1<<THREE))
        key = '3';
        
      //Serial.print(key[i]);
      
    }
    else if (touchNumber == 0);
    else;
      //Serial.println("Only touch ONE button!");
	}
		return key;
}

到这里mpr121触控板的驱动程序就移植完成了,下面给出完整的工程文件
文章不足之处欢迎提出建议。

MPR121是一种12引脚触摸传感器,利用了IC的电容功能。 该芯片具有一个触发引脚,使您可以知道其中一个引脚已被触摸或释放,从而为您提供了出色的响应时间,并提供了使用中断而不是扫描循环状态的选项(如示例所示)唯一的缺点是,IC的所有12个IO引脚都只有一个触发引脚。可以设置I2C地址ADDR 是I2C地址选择引脚。默认情况下,使用100K电阻将其下拉至地,I2C地址为0x5A。您还可以将其连接到地址为0x5B的3Vo引脚,地址为0x5C的SDA引脚或地址0x5D的SCL引脚。此设置用于adafruit板,某些克隆板具有不同的I2C地址集和默认值。如果您不知道要使用哪种I2C扫描仪,则可以使用它。 连接电路板非常简单。 需要注意的一件事-大多数分线板电源的额定电压为3.3V,请勿使用5V为其供电。数据电平电压如何-由于i2c硬件的特性,您不会用arduino的5V损坏MPR121,但是如果您确实注意到从中读取问题,或者甚至没有在总线上找到它-尝试逻辑2之间的电平转换器 多年以来,我用这款出色的IC做了几件事。我创造的第一批产品中有2个是我的孩子的游戏,顶部的字母与2MPR121连接,每次触摸都会触发我说这封信的mp3记录名称。 同时,我还尝试了裸露的导电涂料-这很有趣,并且可以与MPR121一起使用。 硬件组成: Arduino UNO和Genuino UNO Adafruit电容式触摸传感器突破-MPR121
介绍触摸获取需要系统的几个不同部分才能检测触摸。 基线过滤器和触摸检测紧密结合。 基线过滤器的目的是“过滤掉接触”,从而形成类似于长期的系统平均,但也要考虑到一个特定的签名。 触摸必须具有与噪声不同的属性,并且关于过滤器响应的环境变化。 这是通过在不同条件下运行的四种寄存器类型完成的。 它们是最大半增量(MHD),噪声半增量(NHD),噪声计数限制(NCL)和滤波器延迟限制(FDL)。   此外,系统中有不同的条件会影响这些寄存器的工作方式。 这些是上升数据,下降数据或触摸数据。 当数据在这些条件之间变化时,当前的过滤过程将被取消,所有过滤器计数器将返回零。过滤器的操作取决于第二过滤器数据和基线过滤器值之间的关系。 触摸的发生也会改变系统的操作。 触摸生成过程在应用笔记AN3892中进行了描述。 每当第二个过滤器数据小于基线过滤器数据时,将启用下降数据系统。 每当第二个过滤器数据大于基线过滤器数据时,就会启用上升数据系统。 以下情况描述了基准系统在上述三个状态之间未更改时。   情况1   系统的小幅增量更改表示系统中的长期缓慢(环境)更改。 MHD设置通过允许小于MHD两倍的数据通过过滤器来调节这种情况。 因此,如果基线为700,且MHD为1的数据为701,则基线滤波器将增加以等于下一个周期的数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值