Chinaunix首页 | 论坛 | 博客
  • 博客访问: 17989
  • 博文数量: 6
  • 博客积分: 491
  • 博客等级: 下士
  • 技术积分: 90
  • 用 户 组: 普通用户
  • 注册时间: 2009-05-02 14:30
文章分类
文章存档

2011年(1)

2010年(5)

我的朋友
最近访客

分类: 嵌入式

2010-11-24 17:38:16

TLC1549数据采集程序设计
2008-12-14 18:57
[原创]    主题词:TLC1549;数据采集;AD转换;

根据TLC1549(以下简称1549)的datasheet,1549可有六种工作时序.TI将1549的工作时序分成六种,主要是考虑到硬件SPI接口的速度,因为硬件实现的SPI必须按字节读写,而1549是10位AD转换器,所以要读取转换结果必须按两个字节即16位操作,故出现了那么多工作模式.当采用软件模拟SPI时序时,就不必考虑区分这六种模式了.

采用GPIO产生控制时序通常采用10(时钟)周期模式,如下图所示,\CS下降沿和第一个周期的下降沿读取高两位,其余8个周期用于读取低8位.从第3个周期下降沿到第10个周期下降沿为片内采样周期,从第10个周期下降沿开始后的21us为转换周期.片选信号\CS通常采用转换期间无效模式,在转换过程中拉高\CS,这是考虑到芯片的功耗问题,因为使能芯片比禁止芯片功耗要多出许多,这一点可直接从1549的datasheet中看出.
从控制时序图中可以看出,一个完整AD转换周期包括读取,采样和量化(转换)三个过程周期,而且读取周期和采样周期部分是重叠的.另外,1549转换的一个重要特点是读取的数据是上次启动AD转换的结果,这就带来一个问题,1549上电后第一次转换如何处理?显然芯片上电复位后,输出寄存器内容并非某次AD转换结果,可能是一个随机数或某个常数,若直接进行转换,首次读出的数据当然是错误的.不过,可以采用初始化的方法确保首次读出的数据为第一次启动AD转换的结果.具体方法是,在上电后首先执行一个初始化函数ADCInit(),在函数中输出10个周期脉冲,在第10个脉冲的下降沿,AD转换被启动,然后等待21us,最后才进入正常的AD转换程序,以后的读取的数据就可以确定是AD转换的真实值了.

在实际数据采集过程中,往往每隔一段时间进行一次数据采集,而且每次采集多数情况下都是采用多次测量取平均的方法,假设N次采样取平均.问题出现了,在第i次数据采集时,第一个数据是第i-1次数据采集过程中最后一次采样即第N次采样转换的结果,显然这个数据不是当前输入电压的AD转换结果.若按前述的初始化方法,可以解决这一问题,但是每次数据采集相当于进行了N+1次数据采样,都丢弃了最后一次AD采样转换结果,CPU做了无用功.

考虑到:
① 虽然AD时序周期为10个,但\CS下降沿输出了最高位数据,再需要9个时钟周期即可完成10位数据读入,因此读取AD转换数据不需要第10个周期;
② 由datasheet知,AD采样需要7个完整时钟周期,在最后一个周期的下降沿才结束采样,若最后一个周期没来到,则继续进行采样.
我们可以将第10个周期看作AD启动脉冲,从第10个时钟脉冲,到21us的转换周期,再到读AD转换数据的9个脉冲作为一个完整AD转换周期,每次数据采集都对当前输入电压进行采样并转换,这就避免了前述方法必须丢弃AD转换结果现象的发生.需要指出的是,在第9个时钟脉冲后,不能拉高\CS,否则将终止采样过程,下一个脉冲起不到启动的作用.也就是说,在数据采集间隔期间\CS必须保持低电平有效状态.但在等待中的21us转换期间,\CS仍可以被拉高,以尽可能降低功耗.

编程其它注意事项:
① 根据1549的控制时序,最高位输出是在时钟线为低电平且\CS的下降沿过后产生,如果在送出\CS下降沿前,时钟为高电平,在完成\CS下降沿后必须延时1.425us,再拉低时钟线,最后才读取数据线.但不建议这样做.
② 在\CS无效阶段,时钟线被禁止,应始终保持低电平.
③ 1549采用充电电容对输入电压进行采样,在上电复位后需要等待一定的充电时间,在datasheet中有详细描述.

附:TLC1549 AD转换51汇编程序

    ADCInit:
    CLR    SPI_CLK
    CLR    ADC_EN    ;Enable ADC
    NOP        ;tsu,MIN 1.425us
    NOP
    MOV    R7,#9    ;9 clocks
        ADCInit_LP:
        SETB    SPI_CLK
        CLR    SPI_CLK
        DJNZ    R7,BatteryADCInit_LP
    RET
    
    GetVoltage:
    SETB    SPI_CLK        ;Start conversion
    CLR    SPI_CLK
    SETB    ADC_EN        ;Disable ADC
    MOV    R7,#30
    DJNZ    R7,$        ;delay 21us
    CLR    ADC_EN        ;Enable ADC
    SETB    SPI_DAT        ;quasibidirectional port 准双向口
    CLR    A
    NOP            ;MSB valid output delay,tsu,MIN 1.425us
    NOP
    MOV    C,SPI_DAT    ;B9
    RLC    A
    SETB    SPI_CLK
    CLR    SPI_CLK
    MOV    C,SPI_DAT    ;B8
    RLC    A
    MOV    R6,A        ;High 2 bits
    
    CLR    A
    MOV    R5,#8        ;8 data bits
        GetVoltage_LP:
        SETB    SPI_CLK
        CLR    SPI_CLK
        MOV    C,SPI_DAT
        RLC    A
        DJNZ    R5,GetVoltage_LP
    MOV    R7,A        ;Low byte
    RET

以上引自:
http://hi.baidu.com/huangfaqian/blog/item/18583f44cd6b794b500ffe62.html

自己根据网上的TLC1549驱动程序,写有:

uint TLC1549_Read()
{
    uint temp=0;
    uchar i;
    TLC1549_CS = 0;
    TLC1549_CLK = 0;
    for(i=0;i<10;i++)   
    {
temp <<=1;
temp |= TLC1549_DO;
TLC1549_CLK = 1;
TLC1549_CLK = 0;
    }
    TLC1549_CS = 1;
    delay(12);  //延迟>17us
    return temp;
}

,在main.c里的Init里面加入一次该函数,算作预读一次,丢弃
阅读(1426) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~