Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9396180
  • 博文数量: 1747
  • 博客积分: 12961
  • 博客等级: 上将
  • 技术积分: 20060
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-09 11:25
个人简介

偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.

文章分类

全部博文(1747)

文章存档

2024年(23)

2023年(26)

2022年(112)

2021年(217)

2020年(157)

2019年(192)

2018年(81)

2017年(78)

2016年(70)

2015年(52)

2014年(40)

2013年(51)

2012年(85)

2011年(45)

2010年(231)

2009年(287)

分类: LINUX

2010-08-23 10:44:17

整体流程。
初始化配置后,检测状态,打出点击点。

Ads7846_Init();
Ads7846_Config(0x80);

while(1) {
if(Ads7846_MouseIsDown() == 0) continue;

if(Ads7846_GetPoint(&x,&y) == 0) {
printf("(%d,%d)\n",x,y);
printf("Please Press The Touch: ");
}
}

初始化Ads7846_Init();

gpio_set_pin(S3C_GPN10, S3C_GPN10_OUTP);     //ncs
gpio_set_pin(S3C_GPM0, S3C_GPM0_OUTP);     //dclk
gpio_set_pin(S3C_GPE1, S3C_GPE1_OUTP);     //dout
gpio_set_pin(S3C_GPN11, S3C_GPN11_INP);        //busy
gpio_set_pin(S3C_GPN12, S3C_GPN12_INP);        //din
gpio_set_pin(S3C_GPN8, S3C_GPN8_INP);     //irq
//void spi_set_ncs(void){
    gpio_set_value(S3C_GPN10, 1);
}
//void spi_clr_dclk(void){
    gpio_set_value(S3C_GPM0, 0);
}
//void spi_clr_dout(void){
    gpio_set_value(S3C_GPE1, 0);
}


配置 Ads7846_Config(0x80);


unsigned int Ads7846_Config(unsigned char ucControl)
{
    int iReturn;
    gControlByte = ucControl & ~(0x7 << POS_A)

    Ads7846_Get(ADS7843_MODE_DEFAULT, 0, &iReturn);
    
    return 1;
}

状态 Ads7846_MouseIsDown()

unsigned int Ads7846_MouseIsDown(void)
{  
    return (gpio_get_value(S3C_GPN8)==0);
}


取点 Ads7846_GetPoint(&x,&y)

int Ads7846_GetPoint(unsigned int *x,unsigned int*y)
{
  uiErrCodeX = Ads7846_Get(ADS7843_MODE_DFR_12BITS, 1, &PX);
  uiErrCodeY = Ads7846_Get(ADS7843_MODE_DFR_12BITS, 5, &PY);
}







unsigned int Ads7846_Get(uint uiMode, uint uiChunnel, int *iReturn)
{
    uchar ucControl;
    int iVolue;
    
    if((uiChunnel > 7) || ((gControlByte & (0x3 << POS_PD)) == (0x2 << POS_PD)))
    {
        return 0;
    }
    switch(uiMode)
    {
        case ADS7843_MODE_DEFAULT:
            ucControl = gControlByte;
            break;
        case ADS7843_MODE_SER_8BITS:
            ucControl = (gControlByte & ~((1 << POS_SER_NDIF) | (1 << POS_MODE)))\
                        | ((1 << POS_SER_NDIF) | (1 << POS_MODE));
            break;
        case ADS7843_MODE_SER_12BITS:
            ucControl = (gControlByte & ~((1 << POS_SER_NDIF) | (1 << POS_MODE)))\
                        | ((1 << POS_SER_NDIF) | (0 << POS_MODE));
            break;
        case ADS7843_MODE_DFR_8BITS:
            ucControl = (gControlByte & ~((1 << POS_SER_NDIF) | (1 << POS_MODE)))\
                        | ((0 << POS_SER_NDIF) | (1 << POS_MODE));
            break;
        case ADS7843_MODE_DFR_12BITS:
            ucControl = (gControlByte & ~((1 << POS_SER_NDIF) | (1 << POS_MODE)))\
                        | ((0 << POS_SER_NDIF) | (0 << POS_MODE));
            break;
        default:
            ucControl = gControlByte;
            break;
    }

    spi_start();
    spi_write_byte((ucControl & ~(0x7 << POS_A)) | (uiChunnel << POS_A));
    if(spi_wait_ready() == 0)
    {
        spi_stop();
        return 0;
    }
    iVolue = spi_read_byte();
    iVolue <<= 8;
    iVolue |= spi_read_byte();
    spi_stop();


    if(ucControl & (1 << POS_MODE))
    {
        iVolue >>= 8;
    }
    else
    {
        iVolue >>= 4;
    }

    *iReturn = iVolue;
    return 1;
}



SPI总线协议的时序流程

    SPI总线在很多方面都所应用,现在我们就以SPI总线协议的具体流程过程来进行一个讲解。下面我们通过一个例子来了解一下具体的时序问题。希望通过本文的介绍,能让大家对这部分知识有所掌握。

    SPI总线协议是一个环形总线结构,由ss(cs)、sck、sdi、sdo构成,其时序其实很简单,主要是在sck的控制下,两个双向移位寄存器进行数据交换。假设下面的8位寄存器装的是待发送的数据10101010,上升沿发送、下降沿接收、高位先发送。那么第一个上升沿来的时候数据将会是sdo=1;寄存器=0101010x。下降沿到来的时候,sdi上的电平将所存到寄存器中去,那么这时寄存器=0101010sdi,这样在8个时钟脉冲以后,两个寄存器的内容互相交换一次。这样就完成里一个spi时序。

    例子:

    假设主机和从机初始化就绪:并且主机的sbuff=0xaa,从机的sbuff=0x55,下面将分步对SPI总线协议的8个时钟周期的数据情况演示一遍:假设上升沿发送数据。

    1. 脉冲 主机sbuff 从机sbuff  sdi sdo  
    2. 0    10101010  01010101   0   0   
    3. 1上  0101010x  1010101x   0   1   
    4. 1下  01010100  10101011   0   1   
    5. 2上  1010100x  0101011x   1   0   
    6. 2下  10101001  01010110   1   0   
    7. 3上  0101001x  1010110x   0   1   
    8. 3下  01010010  10101101   0   1   
    9. 4上  1010010x  0101101x   1   0   
    10. 4下  10100101  01011010   1   0   
    11. 5上  0100101x  1011010x   0   1   
    12. 5下  01001010  10110101   0   1   
    13. 6上  1001010x  0110101x   1   0   
    14. 6下  10010101  01101010   1   0   
    15. 7上  0010101x  1101010x   0   1   
    16. 7下  00101010  11010101   0   1   
    17. 8上  0101010x  1010101x   1   0   
    18. 8下  01010101  10101010   1   0  

    这样就完成了两个寄存器8位的交换,上面的上表示上升沿、下表示下降沿,sdi、sdo相对于主机而言的。其中ss引脚作为主机的时候,从机可以把它拉底被动选为从机,作为从机的是时候,可以作为片选脚用。根据以上分析,一个完整的传送周期是16位,即两个字节,因为,首先主机要发送命令过去,然后从机根据主机的名准备数据,主机在下一个8位时钟周期才把数据读回来。

    SPI 总线是Motorola公司推出的三线同步接口,同步串行3线方式进行通信:一条时钟线SCK,一条数据输入线MOSI,一条数据输出线MISO;用于CPU与各种外围器件进行全双工、同步串行通讯。SPI总线协议主要特点有:可以同时发出和接收串行数据;可以当作主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。

    SPI模块为了和外设进行数据交换,根据外设工作要求,其输出串行同步时钟极性和相位可以进行配置,时钟极性(CPOL)对传输协议没有重大的影响。如果CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。时钟相位(CPHA)能够配置用于选择两种不同的传输协议之一进行数据传输。如果CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。SPI主模块和与之通信的外设音时钟相位和极性应该一致。

    SPI功能模块的设计

    根据功能定义及SPI的工作原理,将整个IP Core分为8个子模块:uC接口模块、时钟分频模块、发送数据FIFO模块、接收数据FIFO模块、状态机模块、发送数据逻辑模块、接收数据逻辑模块以及中断形式模块。

    深入分析SPI总线协议的四种传输协议可以发现,根据一种协议,只要对串行同步时钟进行转换,就能得到其余的三种协议。为了简化设计规定,如果要连续传输多个数据,在两个数据传输之间插入一个串行时钟的空闲等待,这样状态机只需两种状态(空闲和工作)就能正确工作。


static inline
void spi_delay_tcl(void)
{
udelay(100);
}

static inline
void spi_delay_tch(void)
{
udelay(100);
}

static inline
void spi_delay_tcss(void)
{
udelay(100);
}

static inline
void spi_clr_dclk(void)
{
gpio_set_value(S3C_GPM0, 0);
}

static inline
void spi_set_dclk(void)
{
gpio_set_value(S3C_GPM0, 1);
}

static inline
void spi_set_ncs(void)
{
gpio_set_value(S3C_GPN10, 1);
}

static inline
void spi_clr_ncs(void)
{
gpio_set_value(S3C_GPN10, 0);
}

static inline
void spi_set_dout(void)
{
gpio_set_value(S3C_GPE1, 1);
}

static inline
void spi_clr_dout(void)
{
gpio_set_value(S3C_GPE1, 0);
}

static inline
int spi_get_busy(void)
{
return gpio_get_value(S3C_GPN11) ? 1 : 0;
}

static inline
int spi_get_din(void)
{
return gpio_get_value(S3C_GPN12) ? 1 : 0;
}

static inline
void spi_start(void)
{
spi_clr_dclk();
spi_delay_tcl();
spi_clr_ncs();
spi_delay_tcss();
}

static inline
void spi_stop(void)
{
spi_set_ncs();
spi_clr_dclk();
spi_clr_dout();
}

static inline
int spi_write_byte(uchar value)
{
int i = 0;

for(i = 0; i < 8; i++) {
spi_clr_dclk();
if(value & 0x80)
spi_set_dout();
else
spi_clr_dout();
value <<= 1;

spi_delay_tcl();

spi_set_dclk();
spi_delay_tch();
}

spi_clr_dclk();
spi_clr_dout();
return 0;
}

static inline
int spi_read_byte(void)
{
uchar retval = 0;
int i = 0;

for(i = 0; i < 8; ++i) {
retval <<= 1;

spi_clr_dclk();
spi_delay_tcl();
spi_set_dclk();

if(spi_get_din())retval++;

spi_delay_tch();
}

spi_clr_dclk();
return retval;
}

static inline
int spi_wait_ready(void)
{
int try_count = 10000;
spi_clr_dclk();
spi_delay_tcl();
spi_set_dclk();
spi_delay_tch();
spi_clr_dclk();

while(try_count--) {
if(!spi_get_busy())
return 1;
}

return 0;
}

触摸屏逐渐取代键盘成为嵌入式系统常选用的人机交互工具。本文以电阻式触摸屏和触摸屏控制器ADS7846为例介绍触摸屏及其控制器的原理,并以一个应用实例说明如何用触摸屏及其控制器构成嵌入式系统的输入系统。
在 便携式的电子类产品中,触摸屏由于其轻便、占用空间少、方便灵活等优点,已经逐渐取代键盘成为嵌入式计算机系统的输入设备。基于触摸屏的输入系统实际上是 由触摸屏、触摸屏控制器、微控制器及其相应软件构成的,本文从系统的硬件组成入手,分析整个系统的硬软件原理及其实现方法。

一、系统组成原理

触摸屏输入系统由触摸屏、触摸屏控制器和微控制器三部分组成。图1示出了一个实际的触摸屏输入系统,在该系统中触摸屏采用信利公司的四线电阻式触摸屏,触摸屏控制器采用BB公司的ADS7846,微控制器为Motorola M·CORE系列的MMC2107。

图1 触摸屏输入系统的组成

图2 触摸屏的触摸示意图
1. 触摸屏原理触摸屏附着在显示器的表面,与显示器相配合使用,如果能测量出触摸点在屏幕上的坐标位置,则可根据显示屏上对应坐标点的显示内容或图符获知触摸 者的意图。触摸屏按其技术原理可分为五类:矢量压力传感式、电阻式、电容式、红外线式、表面声波式,其中电阻式触摸屏在嵌入式系统中用的较多。电阻触摸屏 是一块4层的透明的复合薄膜屏,如图2所示,最下面是玻璃或有机玻璃构成的基层,最上面是一层外表面经过硬化处理从而光滑防刮的塑料层,中间是两层金属导 电层,分别在基层之上和塑料层内表面,在两导电层之间有许多细小的透明隔离点把它们隔开。当手指触摸屏幕时,两导电层在触摸点处接触。
触摸屏的两 个金属导电层是触摸屏的两个工作面,在每个工作面的两端各涂有一条银胶,称为该工作面的一对电极,若在一个工作面的电极对上施加电压,则在该工作面上就会 形成均匀连续的平行电压分布。如图1所示,当在X方向的电极对上施加一确定的电压,而Y方向电极对上不加电压时,在X平行电压场中,触点处的电压值可以在 Y+(或Y-)电极上反映出来,通过测量Y+电极对地的电压大小,便可得知触点的X坐标值。同理,当在Y电极对上加电压,而X电极对上不加电压时,通过测 量X+电极的电压,便可得知触点的Y坐标。电阻式触摸屏有四线和五线两种。四线式触摸屏的X工作面和Y工作面分别加在两个导电层上,共有四根引出线,分别 连到触摸屏的X电极对和Y电极对上。五线式触摸屏把X工作面和Y工作面都加在玻璃基层的导电涂层上,但工作时,仍是分时加电压的,即让两个方向的电压场分 时工作在同一工作面上,而外导电层则仅仅用来充当导体和电压测量电极。因此,五线式触摸屏的引出线需为5根。
2. ADS7846触摸屏控制器的工作原理
各种类型的触摸屏均有其相应的控制器,如:ADS7846是四线式触摸屏的控制器,而ADS7845是五线式触摸屏的控制器。控制器的主要功能是分时向X、Y电极对施加电压,并把测量电极上的电压信号转换为相应触摸点的X、Y坐标。
1) 操作原理
ADS7846 内部有一个由多个模拟开关组成的供电-测量电路网络和12位的A/D转换器(参见图3)。ADS7846根据微控制器发来的不同测量命令导通不同的模拟开 关,以便向工作面电极对提供电压,并把相应测量电极上的触点坐标位置所对应的电压模拟量引入A/D转换器。在触摸点X、Y坐标的测量过程中,测量电压与测 量点的等效电路如图4所示,图中P为测量点。

图3 ADS7846的功能框图

图4 测量关系
2) 数字接口
ADS7846 与MMC2107之间通过标准的SPI口相连,由MMC2107启动3次SPI传送来完成转换,如图5所示。第一次SPI传送由MMC2107向 ADS846发控制字,包括起始位、通道选择、8/12位模式、差分/单端选择和掉电模式选择,接下来的两次SPI传送则是MMC2107从 ADS7846取A/D转换结果数据(最后四位自动补零),完成触摸屏控制器和微控制器之间的一次通信。

图5 转换时序

图6 笔中断请求
3) 笔中断(PENIRQ#)输出
ADS7846 通过笔中断请求向MMC2107表示有触摸发生。如图6所示,当没有触摸时,MOSFET①和②打开、③关闭,则笔中断输出引脚通过外加的上拉电阻输出为 高。当有触摸时,①和③打开、②关闭,则笔中断输出引脚通过③内部连接到地而输出为低,从而向MMC2107提中断请求。

二、实际应用举例

触摸屏输入系统的硬件连线如图1所示,当有触摸时ADS7846向MMC2107提中断请求,由MMC2107响应该中断请求,启动图5所示的通信 过程,读取ADS7846的转换结果,从而得到触摸点的坐标,其软件接口如图7所示,包括系统初始化(图中省略)、中断服务程序和ADS7846测量程序 三部分。在ADS7846测量程序中,完成一次MMC2107和ADS7846之间的通信过程。

图7 软件接口流程图
在 测量过程中发现ADS7846的外时钟为50KHz~60KHz时是比较适宜的。ADS7846只能作为SPI的从设备,各信号的时序是完全固定的,因此 需要配置MMC2107 SPI接口信号的时序使之完全符合ADS7846的时序,尤其是从选择信号SS#在一次通信过程中应一直为低(见图5)。
实际测量结果如表1、表2所示: 表1是在一条基本竖直的直线上等距离测量的几个点的坐标值,从表中可得X坐标的斜率为64.25/mm,表2是一条基本水平的直线上等距离测量的几个点的坐标值,可知Y坐标变化斜率为46.33/mm。
表1

表2


阅读(2839) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~