OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 9994|回复: 12

遇到史上最奇怪最难解决的问题,关于电容触摸芯片MPR121,望有相关经验的朋友过来帮帮忙

[复制链接]

5

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
89
金钱
89
注册时间
2017-1-4
在线时间
23 小时
发表于 2017-1-19 21:58:00 | 显示全部楼层 |阅读模式
5金钱
情况是这样的:最近由于一个项目需要用到电容触摸按键,需要用到12个触摸按键,本来准备用原子的方法,但是通道不够用,刚好在网上看到一款能满足要求的,飞思卡尔的MPR121,IIC通讯,于是买了块板子回来实验,这款芯片网上资料不是太多,STM32的驱动目前为止目前没找到,仅有Arduino的作为参考,项目使用了STM32F103RBT6单片机,于是直接拿原子的IIC底层驱动程序来修改,一切很顺利,能够成功驱动,但是读取按键值的时候却出现了问题,下面一边看代码一边来说:原子的IIC就不往上放了,一样的,主要看MPR121这个,首先是对芯片的一系列初始化,这个直接是参考的手册给所有需要配置的寄存器一个初值,这个暂时没改,也不知道什么意思,如下:
void Touchkey_Init(void)
{
  IIC_Init();
  IIC_Write(0x5E,0x00);

  IIC_Write(0x80,0x63);                     

  IIC_Write(0x73,0xFF);                        
  IIC_Write(0x74,0xFF);
  IIC_Write(0x76,0xFF);
  IIC_Write(0x77,0xFF);
  IIC_Write(0x75,0xFF);
       
  IIC_Write(0x81,0x00);
  IIC_Write(0x82,0x00);
  IIC_Write(0x83,0x00);
  IIC_Write(0x84,0x00);

  IIC_Write(0x2B,0x01);                           //Max half delta Rising   
  IIC_Write(0x2C,0x01);                           //Noise half delta Rising  
  IIC_Write(0x2D,0x00);                           //Noise count limit Rising
  IIC_Write(0x2E,0x00);                           //Delay limit Rising

  IIC_Write(0x2F,0x01);                          //Max half delta Falling
  IIC_Write(0x30,0x01);                          //Noise half delta Falling
  IIC_Write(0x31,0xFF);                          //Noise count limit Falling
  IIC_Write(0x32,0x02);                          //Delay limit Falling

  IIC_Write(0x33,0x00);                           //Noise half delta Touched
  IIC_Write(0x34,0x00);                           //Noise count Touched
  IIC_Write(0x35,0x00);                           //Delay limit Touched
      
  IIC_Write(0x36,0x0f);                           //Max half delta Rising
  IIC_Write(0x37,0x0f);                           //Noise half delta Rising
  IIC_Write(0x38,0x00);                           //Noise count Rising
  IIC_Write(0x39,0x00);                           //Delay limit Rising

  IIC_Write(0x3A,0x01);                           //Max half delta Falling
  IIC_Write(0x3B,0x01);                           //Noise half delta Falling
  IIC_Write(0x3C,0xff);                           //Noise count Falling
  IIC_Write(0x3D,0xff);                           //Delay limit Falling

  IIC_Write(0x3E,0x00);
  IIC_Write(0x3F,0x00);
  IIC_Write(0x40,0x00);

  IIC_Write(0x41,TOU_THRESH);                    //ELE0 TOUCH THRESHOLD     
  IIC_Write(0x42,REL_THRESH);                    //ELE0 RELEASE THRESHOLD  
  IIC_Write(0x43,TOU_THRESH);                    //ELE1 TOUCH THRESHOLD
  IIC_Write(0x44,REL_THRESH);                    //ELE1 RELEASE THRESHOLD
  IIC_Write(0x45,TOU_THRESH);                    //ELE2 TOUCH THRESHOLD
  IIC_Write(0x46,REL_THRESH);                    //ELE2 RELEASE THRESHOLD
  IIC_Write(0x47,TOU_THRESH);                    //ELE3 TOUCH THRESHOLD
  IIC_Write(0x48,REL_THRESH);                    //ELE3 RELEASE THRESHOLD
  IIC_Write(0x49,TOU_THRESH);                    //ELE4 TOUCH THRESHOLD
  IIC_Write(0x4A,REL_THRESH);                    //ELE4 RELEASE THRESHOLD
  IIC_Write(0x4B,TOU_THRESH);                    //ELE5 TOUCH THRESHOLD
  IIC_Write(0x4C,REL_THRESH);                    //ELE5 RELEASE THRESHOLD
  IIC_Write(0x4D,TOU_THRESH);                    //ELE6 TOUCH THRESHOLD
  IIC_Write(0x4E,REL_THRESH);                    //ELE6 RELEASE THRESHOLD
  IIC_Write(0x4F,TOU_THRESH);                    //ELE7 TOUCH THRESHOLD
  IIC_Write(0x50,REL_THRESH);                    //ELE7 RELEASE THRESHOLD
  IIC_Write(0x51,TOU_THRESH);                    //ELE8 TOUCH THRESHOLD
  IIC_Write(0x52,REL_THRESH);                    //ELE8 RELEASE THRESHOLD
  IIC_Write(0x53,TOU_THRESH);                    //ELE9 TOUCH THRESHOLD
  IIC_Write(0x54,REL_THRESH);                    //ELE9 RELEASE THRESHOLD
  IIC_Write(0x55,TOU_THRESH);                    //ELE10 TOUCH THRESHOLD
  IIC_Write(0x56,REL_THRESH);                    //ELE10 RELEASE THRESHOLD
  IIC_Write(0x57,TOU_THRESH);                    //ELE11 TOUCH THRESHOLD
  IIC_Write(0x58,REL_THRESH);                    //ELE11 RELEASE THRESHOLD

  IIC_Write(0x59,PROX_TOU_THRESH);               //ELE12 TOUCH THRESHOLD      
  IIC_Write(0x5A,PROX_REL_THRESH);               //ELE12 RELEASE THRESHOLD  

  IIC_Write(0x5B,0x00);                     

  IIC_Write(0x5C,0x10);                          //AFES=6 samples, same as AFES in 0x7B, Global CDC=16uA
  IIC_Write(0x5D,0x24);                          //CT=0.5us, TDS=4samples, TDI=16ms

  IIC_Write(0x7B,0x0B);                          //AFES=6 samples, same as AFES in 0x5C

  IIC_Write(0x7D,0xC9);                          //AC up limit   /C9/BD/C0/9C  /3.3V/3.0V/2.8V/1.8V   
  IIC_Write(0x7E,0x82);                          //AC low limit  /82/7A/7C/65  /3.3V/3.0V/2.8V/1.8V   
  IIC_Write(0x7F,0xB5);                          //AC target     /B5/AA/AC/8C  /3.3V/3.0V/2.8V/1.8V
  IIC_Write(0x5E,0x0C);          
}

上面完成了一些寄存器的配置,然后主函数很简单
int main(void)
{                        
        SystemInit();
        delay_init();                   
        NVIC_Configuration();  
        uart_init(9600);      
        LED_Init();                            
        Touchkey_Init();
        while(1)
        {               
                Touchkey_Scan();//在这个里面调用按键触摸扫描判断       
        }       
}


下面是扫描函数
void Touchkey_Scan(void)
{
       u16 read_data = 0;
        read_data = Read_Touchkey_Data();//读取键值函数
        if(read_data)//键值不为0,将键值打印出来
        {
                  while(Read_Touchkey_Data());//等待手离开触摸面板
                  printf("x=%d\n",read_data);//键值打印到串口
        }       
}


再进一步看一下Read_Touchkey_Data();这个函数,如下,问题就出在这个函数里面
键值是存放在0x00和0x01这两个寄存器里面的,如下
未命名.JPG
其中0x00寄存器里面存放的是触摸按键0-7的状态,0x01寄存器里面存放的是触摸按键8-11的状态,哪一个按键被触摸了,那么相应的位被置1,没有被触摸就为0,0x01寄存器的高三位不起作用,都为0,下面是我读寄存器的函数
u16 Read_Touchkey_Data(void)
{
  u16 key_data=0;
  key_data = IIC_Read(0x01);
  key_data <<= 8;
  key_data |=IIC_Read(0x00);
  return key_data;
}

那么现在的问题是这样的,当我触摸的时候,是有反应的,比如我用手触摸按键0,那么从串口打印出来的值我截一段数据如下:
x=1
x=1
x=257
x=1
x=257
x=257
.
.
.其他按键的现象也是这样,理论上应该都是1才对,后来分析一下257实际上就是256+1,也就是高8位跟低8位一样时就会出现257
转换成二进制257=00000001 00000001 ,但是高8位是按键8-11,我没有触碰到任何一个按键,怎么会有值呢,而且触摸键1就会出现
x=2
x=2
x=514
x=514
x=2
x=514
.
.

而且此时触摸8-11按键,什么值都不返回,也就是没有任何反应,这个问题困扰我两天了,实在没办法,望有用过的或者有什么想法能够在这里提一提,多谢了


正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
16
金钱
16
注册时间
2017-4-18
在线时间
3 小时
发表于 2017-4-18 19:21:20 | 显示全部楼层
有没有完整的代码,最近也在用这个MPR121,搞得很烦。。
回复

使用道具 举报

558

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
164897
金钱
164897
注册时间
2010-12-1
在线时间
2100 小时
发表于 2017-4-19 21:08:45 | 显示全部楼层
帮顶
回复

使用道具 举报

6

主题

15

帖子

0

精华

新手入门

积分
6
金钱
6
注册时间
2017-5-20
在线时间
21 小时
发表于 2017-5-20 22:13:57 | 显示全部楼层
我搞的也是MPR121 ,终于搞好了
回复

使用道具 举报

558

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
164897
金钱
164897
注册时间
2010-12-1
在线时间
2100 小时
发表于 2017-5-21 18:26:41 | 显示全部楼层
h2052519 发表于 2017-5-20 22:13
我搞的也是MPR121 ,终于搞好了

可否分享下代码 ?
方便网友?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
2
金钱
2
注册时间
2017-7-4
在线时间
0 小时
发表于 2017-7-4 16:12:25 | 显示全部楼层
我也遇到同样的问题,通过从0x00地址连读两字节,就把0和1寄存器的值都读出来了
回复

使用道具 举报

34

主题

809

帖子

4

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1863
金钱
1863
注册时间
2011-3-29
在线时间
139 小时
发表于 2017-7-12 12:27:39 来自手机 | 显示全部楼层
会不会是按下时候的状态不稳定导致的?取释放按键前读取的数据试试看,不要用按下时的数据。
回复

使用道具 举报

2

主题

22

帖子

0

精华

初级会员

Rank: 2

积分
140
金钱
140
注册时间
2013-3-6
在线时间
25 小时
发表于 2017-7-23 15:52:49 | 显示全部楼层
我调是调好的,但是感应距离调不了,隔了一层亚克力板后感应就不行了,望各位帮忙下:
下面是参考别人的代码能用的:
void mpr121_init(void)
{       
  // Section A
  // This group controls filtering when data is > baseline.
  write_i2c(touch_shield,MHD_R, 0x01);
  write_i2c(touch_shield,NHD_R, 0x01);
  write_i2c(touch_shield,NCL_R, 0x00);
  write_i2c(touch_shield,FDL_R, 0x00);
  // Section B
  // This group controls filtering when data is < baseline.
  write_i2c(touch_shield,MHD_F, 0x01);
  write_i2c(touch_shield,NHD_F, 0x01);
  write_i2c(touch_shield,NCL_F, 0xFF);
  write_i2c(touch_shield,FDL_F, 0x02);

  // Section C
  // This group sets touch and release thresholds for each electrode
  write_i2c(touch_shield,ELE0_T, TOU_THRESH);
  write_i2c(touch_shield,ELE0_R, REL_THRESH);
  write_i2c(touch_shield,ELE1_T, TOU_THRESH);
  write_i2c(touch_shield,ELE1_R, REL_THRESH);
  write_i2c(touch_shield,ELE2_T, TOU_THRESH);
  write_i2c(touch_shield,ELE2_R, REL_THRESH);
  write_i2c(touch_shield,ELE3_T, TOU_THRESH);
  write_i2c(touch_shield,ELE3_R, REL_THRESH);
  write_i2c(touch_shield,ELE4_T, TOU_THRESH);
  write_i2c(touch_shield,ELE4_R, REL_THRESH);
  write_i2c(touch_shield,ELE5_T, TOU_THRESH);
  write_i2c(touch_shield,ELE5_R, REL_THRESH);
  write_i2c(touch_shield,ELE6_T, TOU_THRESH);
  write_i2c(touch_shield,ELE6_R, REL_THRESH);
  write_i2c(touch_shield,ELE7_T, TOU_THRESH);
  write_i2c(touch_shield,ELE7_R, REL_THRESH);
  write_i2c(touch_shield,ELE8_T, TOU_THRESH);
  write_i2c(touch_shield,ELE8_R, REL_THRESH);
  write_i2c(touch_shield,ELE9_T, TOU_THRESH);
  write_i2c(touch_shield,ELE9_R, REL_THRESH);
  write_i2c(touch_shield,ELE10_T, TOU_THRESH);
  write_i2c(touch_shield,ELE10_R, REL_THRESH);
  write_i2c(touch_shield,ELE11_T, TOU_THRESH);
  write_i2c(touch_shield,ELE11_R, REL_THRESH);

  //----------------------------------------

        write_i2c(touch_shield,0x10, 0xff);   //控制电流1uA~63uA,  0x10
        write_i2c(touch_shield,0x24, 0xff); //控制时间0.5uS~32uS, 0x24
      
                


  //-----------------------------------------
  // Section D
  // Set the Filter Configuration
  // Set ESI2
  write_i2c(touch_shield,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
  write_i2c(touch_shield,ELE_CFG, 0x0C);        // Enables all 12 Electrodes
  //write_i2c(touch_shield,ELE_CFG, 0x06);                // Enable first 6 electrodes
  
  // Section F
  // Enable Auto Config and auto Reconfig
/* write_i2c(touch_shield,ATO_CFG0, 0x0B);
  write_i2c(touch_shield,ATO_CFGU, 0xC9);        // USL = (Vdd-0.7)/vdd*256 = 0xC9 @3.3V   write_i2c(touch_shield,ATO_CFGL, 0x82);        // LSL = 0.65*USL = 0x82 @3.3V
  write_i2c(touch_shield,ATO_CFGT, 0xB5);*/        // Target = 0.9*USL = 0xB5 @3.3V
}

u8 get_key()
{
        u8 count=0;
        u8 i=0;
        u16 dat=0;
        u16 num;
         dat=read_i2c(touch_shield,0x01)<<8;
       
        num=read_i2c(touch_shield,0x00);
         dat=dat| num;
        for (i=0; i<12; i++)  //检测有多少按键被触摸
          {
            if ((dat & (1<<i)))
              count++;
          }
          i=0;
          if(count==1){
                  while((dat & (1<<i)) == 0)
                        i++;
                        return i;
          }
          return -1;
}
回复

使用道具 举报

558

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
164897
金钱
164897
注册时间
2010-12-1
在线时间
2100 小时
发表于 2017-7-24 00:33:50 | 显示全部楼层
wyk 发表于 2017-7-23 15:52
我调是调好的,但是感应距离调不了,隔了一层亚克力板后感应就不行了,望各位帮忙下:
下面是参考别人的代 ...

这你可能得找原厂支持下了
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

0

主题

4

帖子

0

精华

新手入门

积分
9
金钱
9
注册时间
2018-10-19
在线时间
2 小时
发表于 2018-10-19 20:26:22 | 显示全部楼层
wyk 发表于 2017-7-23 15:52
**** 作者被禁止或删除 内容自动屏蔽 ****

我参照这个改了一下,还是没有解决这个问题。
write_i2c(touch_shield,0x10, 0xff);   //控制电流1uA~63uA,  0x10
        write_i2c(touch_shield,0x24, 0xff); //控制时间0.5uS~32uS, 0x24
这里是不是还要改一下,我看mpr121datasheet里面,控制电流和控制时间的寄存器地址不是这个。
回复

使用道具 举报

0

主题

4

帖子

0

精华

新手入门

积分
9
金钱
9
注册时间
2018-10-19
在线时间
2 小时
发表于 2018-10-21 14:25:53 | 显示全部楼层
h2052519 发表于 2017-5-20 22:13
我搞的也是MPR121 ,终于搞好了

可以把初始化代码发给我参考一下吗?
回复

使用道具 举报

1

主题

6

帖子

0

精华

新手入门

积分
16
金钱
16
注册时间
2018-7-21
在线时间
1 小时
发表于 2019-4-20 17:33:15 | 显示全部楼层
CZ131 发表于 2018-10-21 14:25
可以把初始化代码发给我参考一下吗?

可以分享一下吗?我的为什么触发不了中断
回复

使用道具 举报

2

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
89
金钱
89
注册时间
2020-10-12
在线时间
29 小时
发表于 2020-12-15 12:00:14 | 显示全部楼层
我的mpr121,一直触发中断,触摸是有正确数据的,多点击几次后,无法进入中断
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-5-29 07:37

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表