《电子技术应用》
您所在的位置:首页 > 嵌入式技术 > 设计应用 > Linux下基于MCU的触摸传感系统设计
Linux下基于MCU的触摸传感系统设计
2015年微型机与应用第8期
常孟芝1,白雪飞1,方 毅2
(1.中国科学技术大学 电子科学与技术系,安徽 合肥230027;2.中国科学技术大学 信息科学实验中心,安徽 合肥230027)
摘要: 给出一种在三星S5PV210处理器的Linux系统下基于PIC24F单片机实现的触摸传感系统的设计方案。利用PIC24F充电时间测量单元(CTMU)和ADC实现触摸信息采集,S5PV210通过I2C总线与触摸传感器通信,读取传感器触摸状态信息;设计了PIC24F固件程序和其在主控S5PV210处理器Linux系统下的I2C设备驱动程序。测试结果表明,在主控Linux系统下可以精确获得触摸状态信息。
Abstract:
Key words :

  摘  要: 给出一种在三星S5PV210处理器的Linux系统下基于PIC24F单片机实现的触摸传感系统的设计方案。利用PIC24F充电时间测量单元(CTMU)和ADC实现触摸信息采集,S5PV210通过I2C总线与触摸传感器通信,读取传感器触摸状态信息;设计了PIC24F固件程序和其在主控S5PV210处理器Linux系统下的I2C设备驱动程序。测试结果表明,在主控Linux系统下可以精确获得触摸状态信息。
  关键词: 触摸传感;CTMU;I2C;Linux驱动
0 引言
  随着科技的进步,各种形式的触摸传感器被应用于机器人、家电、便携式消费电子等领域。
  常用触摸传感器主要有电阻式和电容式两种,电容式以灵敏度高、抗损性好的特点得到广泛应用。一般电容传感器由专用ASIC实现,本文基于PIC24F MCU(微控制器)实现电容触摸传感器,由于传感器只是MCU外接的金属片,具有成本低、形状灵活、外围电路简单的特点,主控端可在嵌入式Linux下通过I2C总线获得多个传感器状态。
1 系统组成
  如图1所示,触摸传感系统由多个电容触摸传感器端(由PIC24F MCU实现)和S5PV210主控端(运行Linux系统)两部分组成。电容传感器端处理触摸信息,主控端通过I2C总线与传感器通信,得到其处理好的传感器数据(包含传感器ID和是否触摸状态)。一片PIC24F最多可实现16个触摸传感器。

Image 001.png

2 功能实现
  2.1 基于PIC24F CTMU方式实现触摸检测
  图2为PIC24F CTMU框图。

Image 002.png

  PIC24F的CTMU是由一个可调节恒流源和逻辑控制块构成的可配置模拟单元。触摸检测采用CTMU恒流源与A/D转换器的连接[1]如图3所示。

Image 003.png

  通过CTMU在传感器上施加恒流源实现触摸检测。
  I×T=C×V(1)
  其中,I是CTMU恒流源电流,T是CTMU充电的固定周期,C是触摸电路的电容,V是充电完成后经A/D转换器读取的电压值。
  由于CTMU恒流源I是恒定的,设置充电周期T保持恒定,则电路中电容C的变化将表现为电压V的变化,当人手指接触到传感器时,总电容将增加,A/D转换器读取的电压减小。
  图4为传感器电压采集子程序,它由CTMU单元和ADC单元配合完成[2]。传感器电容与ADC的保持电容并联,每次测量电压前使两个电容接地放电至0 V,随后控制CTMU的恒流源对两个电容注入一定量的电荷,再通过ADC读取电压。可以计算触摸前后电压差值ST5I`A3_Y%$7}L@UX(~F@%D.jpg为:V@KOM8JOG~S5L)V8P`JKQ_P.png

  其中,CF是手指电容,CB是金属片基础电容,CA/D是ADC保持电容,I是CTMU恒流源的电流,t是充电时间。

Image 004.png

  实际中由手指电容引起的电容增量为pF量级,为获得较高的灵敏度,需增大ΔCTMU,由式(2)可知,减小基础电容CB和适当增加注入电荷(It)为有效方式。传感器面积会影响CB,形状不是主要影响因素,本文设计的传感器尺寸为15 mm×15 mm的正方形,配置CTMU恒流源为最大55 μA(CTMUICON=0x0300)以提高充电速度和电量。
  2.2 S5PV210与触摸传感器I2C通信
  I2C总线(Inter Integrated Circuit)是主从结构的两线式(数据线SDA,时钟线SCL)串行总线。它接口简单、互联成本低,数据的传输和时钟频率均由主机控制,因此各种传感器芯片大都采用I2C通信。
  开始通信时,由主机端S5PV210发送S,接着发送Addr(从机地址7 bit)、R/W(读写位1 bit)给PIC24F,PIC24F收到8 bit(Addr+R/W)确认是本机后,将SDA线拉低作为ACK,主机在第9个SCL采集到低电平ACK后,确认连接到从机,接着主从将根据R/W位接收或者发送1 B传感器数据。本文为2个传感器(一片PIC24F最多可实现16个传感器,多于16个时可通过I2C总线进行扩展),设置传感器1被触摸则发送0x01,传感器2被触摸发送0x02,没有触摸为0x00。单片机PORTE口接有LED将接收数据赋给PORTE做为接收测试(0-亮,1-灭)。图5为总线时序图。

Image 005.png  

       2.3 从机端电容触摸传感器固件设计
  PIC24F固件程序流程如图6所示。

Image 006.png

  系统初始化使能Time1、ADC、CTMU和I2C(slave模式),Time1中断用于触发读取传感器1和传感器2经CTMU和ADC处理的电压值,并将有无触摸(电压降低)状态保存到I2C的发送缓存里,随后利用主机端发起通信引起的中断发送触摸状态或接收数据。
  2.4 主机端Linux I2C设备驱动设计
  S5PV210 Linux下I2C驱动层次结构如图7所示。

Image 007.png

  Linux系统分为用户层和内核层,系统下应用程序访问硬件设备需要位于内核层的设备驱动提供的接口支持[3]。
  整个I2C驱动程序由I2C设备驱动和总线驱动两部分组成,Linux下对S5PV210 I2C控制器驱动即总线驱动已经支持,要做的是针对触摸传感器设计I2C设备驱动。I2C设备驱动在Linux中属于字符设备,字符设备可以以设备文件形式存在,由应用程序打开并进行读写操作,从而实现控制硬件的目的。
  S5PV210有3个I2C主控制器,触摸传感器驱动采用第一个主控制器。Linux下设备驱动可以直接编译到内核,也可以在外部编译好生成.ko文件,然后使用insmod命令动态加载到运行的内核中,为了方便开发采用动态加载方式。
  I2C设备驱动程序可分为两部分[4]:首先定义和注册I2C设备即i2c_client;然后定义和注册I2C设备驱动即i2c_driver。i2c_client即是PIC24F模块,所以要在i2c_client中设置PIC24F的设备名和地址信息,i2c_client里关键代码及结构有:
  struct i2c_board_info pic_touch_info={
  i2c_board_info("pic_touch",0x40),
  //注意PIC实际地址0x80,这里要右移1位:0x80>>1=0x40
  };//设置i2c_board_info结构体保存设备名和设备地址
  structi2c_adapter*i2c_adap;
  i2c_adap=i2c_get_adapter(0);
  //使用S5PV210第一个控制器
  pic_touch_client=i2c_new_device(i2c_adap,&pic_touch_info);
  //调用i2c_new_device创建并注册I2C
  //设备对应的i2c_client结构体
  第二部分定义和注册I2C设备驱动,其中i2c_driver为核心结构体,设置驱动所能支持的设备列表pic_touch_id_table[],提供探测函数pic_touch_probe(),当总线驱动发现i2c_client设备名与id_table中相同时,会自动发出设备地址,如果收到ACK,则确定设备存在,总线驱动会把设备挂接到此驱动并调用pic_touch_probe(),在此函数中注册字符设备创建设备访问节点,构造file_openration结构体,在此结构体中编写实际操作硬件的读写函数。
  i2c_driver关键代码及结构:
  struct i2c_device_id pic_touch_id_table
  []={{"pic_touch",0},{}};//填充与i2c_client相同的
  //设备名pic_touch,使此驱动适用于传感器设备
  //创建i2c_driver结构体对象
  struct i2c_driver pic_touch_driver={
  .driver={
  .name="pic_touchdrv",
  .owner=THIS_MODULE,
  },
  .probe=pic_touch_probe,//设置探测函数,此函数在驱动
  //与i2c_client匹配时调用,在此函数中完成字符设备的注册
  .remove=__devexit_p(pic_touch_remove),
  //去除驱动时调用
  .id_table=pic_touch_id_table,
  //在此id_table中查找本驱动支持的设备
  };
  探测函数pic_touch_probe()中关键段:
  major=register_chrdev(0,"pic_touch",
  &pic_touch_fops);//注册字符设备
  class=class_create(THIS_MODULE,"pic_touch");
  device_create(class,NULL,MKDEV(major,0),NULL,"pic_touch");
  //生成设备访问节点/dev/pic_touch
  构造file_operations结构体填充读写函数
  file_operations pic_touch_fops={
  .owner=THIS_MODULE,
  .read=pic_touch_read,
  .write=pic_touch_write,
  };
  pic_touch_read()和pic_touch_write()是实际操作硬件的函数。需要根据从机端触摸传感器I2C固件需求的时序设计。
  本文采用Linux内核提供的SMBus读写函数实现,SMBus(System Management Bus)是I2C的子集。
  读函数pic_touch_read()关键程序段:
  data=i2c_smbus_read_byte(pic_touch_client);
  //从传感器读数据存在内核缓冲data
  copy_to_user(buf,&data,1);
  //将读取的传感器数据data拷贝到用户buf空间
  写函数pic_touch_write()关键程序段:
  copy_from_user(&data,buf,1);
  //从用户空间buf拷贝1 B数据到内核缓冲区data
  i2c_smbus_write_byte(pic_touch_client,data)
  //将数据发送给传感器设备
3 测试
  无触摸ADC取值稳定,触摸后因每次触摸面积不同使得读取ADC值差别较大,本设计根据表1测试结果设置触发阈值为0x0200,实际中需根据灵敏度要求和测试结果合理设置阈值,利用Time1中断定时扫描读取2个触摸传感器值,设置的中断时间为480 OVM6}M)IBR%54@(X)_BM%19.jpg,CTMU充电时间为1.25OVM6}M)IBR%54@(X)_BM%19.jpg
  主控端Linux下读取传感器状态,先insmod加载驱动,生成设备节点/dev/pic_touch:
  #insmod pic_touch_dev.ko
  #insmod pic_touch_drv.ko
  打印调试信息:
  pic_touch_pad is probed, make chdev node:/dev/pic_touch
  #ls/dev/pic_touch
  /dev/pic_touch
  无触摸时,Linux下运行如下测试程序:
  #./pic_touch_testrw r
  readdata=0x00 touch state is:0x00
  成功返回无触摸状态0x00。
  分别触摸传感器1和传感器2,运行测试程序:
  #./pic_touch_testrw r
  readdata=0x01 touch state is:0x01
  #./pic_touch_testrw r
  readdata=0x02 touch state is:0x02
  成功读取传感器1和2被触摸状态0x01,0x02。
  发送数据0xaa给传感器接收测试LED:
  #./pic_touch_testrw w 0xaa
  cmmd=0xaa write success!,cmd=0xaa
  发送成功,LED状态正确。
  为检测传感器性能,实测时传感器表面盖一层1 mm厚的透明塑料,LED同时指示传感器状态。测试结果表明,设置的触摸传感器扫描频率和触发阈值有很好的灵敏度和稳定性,在主控端Linux I2C速率为100 kb/s下可实时精确地获取传感器触摸状态信息,达到设计目标。本文在Linux下基于MCU实现触摸传感系统也便于后续利用MCU扩展传感器功能。
  参考文献
  [1] Microchip Technology Inc.PIC24FJ256GA110 Family Data Sheet[Z]. 2010.
  [2] Microchip Technology Inc.Microchip CTMU for Capacitive Touch Applications[Z]. 2009.
  [3] 宋宝华.Linux设备驱动开发详解(第2版)[M].北京:人民邮电出版社,2010.
  [4] 韦东山.嵌入式Linux应用开发完全手册[M].北京:人民邮电出版社,2008.

此内容为AET网站原创,未经授权禁止转载。