DIY编程器网

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 331|回复: 0
打印 上一主题 下一主题

AVR模拟比较器使用范例

[复制链接]
跳转到指定楼层
楼主
发表于 2012-1-27 19:42:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
  
         
    /***********************************************
****       AVR 模拟比较器使用范例          ***
**** 编译器:WINAVR20050214               ***
***********************************************/
/*
本程序简单的示范了如何使用ATMEGA16的模拟比较器
模拟比较器的设置
       中断方式--较常用
       查询方式不常用,检测ACO即可,可用作DELTA-SIGMA A/D CONVERTER,校正后精度比较高,但速度低,用汇编可以略为提高速度。
出于简化程序考虑,各种数据没有对外输出,学习时建议使用JTAG ICE硬件仿真器
*/
#include <iom16v.h>
#include <macros.h>
#include "delay.h"#include <avr/interrupt.h>   //中断函数头文件

/*
宏INTERRUPT 的用法与SIGNAL 类似,区别在于:
    SIGNAL 执行时全局中断触发位被清除、其他中断被禁止
    INTERRUPT 执行时全局中断触发位被置位、其他中断可嵌套执
另外avr-libc 提供两个API 函数用于置位和清零全局中断触发位,它们是经常用到的。
分别是:void sei(void) 和void cli(void) 由interrupt.h定义
注: 内部函数_delay_ms() 最高延时  262.144mS@1MHz
    该函数可以实现较精确的定时,但用JTAG仿真时较麻烦---会进入机器码窗口(Disassembeler).注意跳开该语段。
一旦JTAG仿真进入该内部函数语句,会变得像"死机"一样(其实在运行中),可以先[break],然后在后面的C语句设[breakpoint],[RUN]跳过
  for()/while()语句计算延时时间较麻烦。
    为了使 _delay_ms()函数的延时正确,须在makefile中设定F_CPU为实际的系统时钟频
    本范例为1MHz内部RC振荡器 即 F_CPU=1000000
*/

//管脚定义
#define LED0             0     //PB0
#define AIN_P              2     //PB2(AIN0)
#define AIN_N              3     //PB3(AIN1)

//宏定义
#define LED0_ON()             PORTB|= (1<      //输出高电平,灯亮
#define LED0_OFF()            PORTB&="(1<      //输出低电平,灯灭

//常量定义
/*
模拟比较器的正输入端由 ACBG位决定,=0选择AIN0引脚,=1选择1.23V内部能隙基准源
模拟比较器多工输入 (不常用,因为ADC将无法使用)
       可以选择ADC7..0 之中的任意一个来代替模拟比较器的负极输入端。
       ADC复用器可用来完成这个功能。
       当然,为了使用这个功能首先必须关掉ADC。
       如果模拟比较器复用器使    能位(SFIOR 中的ACME) 被置位,且ADC 也已经关掉(ADCSRA 寄存器的ADEN 为0),则可以通过ADMUX 寄存器的MUX2..0 来选择替代模拟比较器负极输入的管脚,如果ACME 清零或ADEN 置位,则模拟比较器的负极输入为AIN1。
*/
#define AC_ADC0              0x00              //ADC0
#define AC_ADC1              0x01              //ADC1
#define AC_ADC2              0x02              //ADC2
#define AC_ADC3              0x03              //ADC3
#define AC_ADC4              0x04              //ADC4
#define AC_ADC5              0x05              //ADC5
#define AC_ADC6              0x06              //ADC6
#define AC_ADC7              0x07              //ADC7

SIGNAL(SIG_COMPARATOR) //模拟比较器中断服务程序
{
    //硬件自动清除ACI标志位
    _delay_us(10);
    if ((ACSR&(1<  //检测ACO
           LED0_ON();                 //如果AIN0亮
    else
           LED0_OFF();               //否则 LED灭
    _delay_ms(200);           //当电压差接近0V时,模拟比较器会产生临界抖动,故延时200mS令肉眼能看到   
}

int main(void)
{
    //上电默认DDRx=0x00,PORTx=0x00 输入,无上拉电阻
    PORTA=0xFF;
    PORTC=0xFF;                                          //不用的管脚使能内部上拉电阻。
    PORTD=0xFF;
    PORTB="((1<   //作模拟比较器输入时,不可使能内部上拉电阻。
    DDRB= (1<                              //PB0作输出
    /*
模拟比较器控制和状态寄存器-ACSR

    Bit 7 – ACD: 模拟比较器禁用
    模拟比较器上电默认是已经工作中的,跟其他的模块有所不同
    ACD置位时,模拟比较器的电源被切断。可以在任何时候设置此位来关掉模拟比较器。
    这可以减少器件工作模式及空闲模式下的功耗。
改变ACD位时,必须清零ACSR 寄存器的ACIE位来禁止模拟比较器中断。否则ACD改变时可能会产生中断

    Bit 6 – ACBG: 选择模拟比较器的能隙基准源
       ACBG 置位后,模拟比较器的正极输入由1.23V能隙基准源所取代。否则, AIN0 连接到模拟比较器的正极输入。

       Bit 5 – ACO: 模拟比较器输出
       模拟比较器的输出经过同步后直接连到ACO。同步机制引入了1-2 个时钟周期的延时。

       Bit 4 – ACI: 模拟比较器中断标志
       当比较器的输出事件触发了由ACIS1 及ACIS0 定义的中断模式时,ACI 置位。
       如果ACIE      和SREG 寄存器的全局中断标志I 也置位,那么模拟比较器中断服务程序即得以执行,同时ACI 被硬件清零。
       ACI 也可以通过写"1” 来清零。

       Bit 3 – ACIE: 模拟比较器中断使能
       当ACIE 位被置"1” 且状态寄存器中的全局中断标志I 也被置位时,模拟比较器中断被激活。
       否则中断被禁止。

    Bit2 – ACIC: 模拟比较器输入捕捉使能
       这个功能用于检测一些微弱的触发信号源,节省一个外部运放。
    ACIC置位后允许通过模拟比较器来触发T/C1 的输入捕捉功能。
    此时比较器的输出被直接连接到输入捕捉的前端逻辑,从而使得比较器可以利用T/C1 输入捕捉中断逻辑的噪声抑制器及触发沿选择功能。
       为了使比较器可以触发T/C1 的输入捕捉中断,定时器中断屏蔽寄存器TIMSK 的TICIE1    必须置位。
ACIC 为"0” 时模拟比较器及输入捕捉功能之间没有任何联系。

       Bits 1, 0 – ACIS1, ACIS0: 模拟比较器中断模式选择
       这两位确定触发模拟比较器中断的事件。
       ACIS1 ACIS0        中断模式
         0        0 比较器输出变化即可触发中断
         0        1 保留
         1        0 比较器输出的下降沿产生中断
         1        1 比较器输出的上升沿产生中断
       需要改变ACIS1/ACIS0 时,必须清零ACSR 寄存器的中断使能位来禁止模拟比较器中断。否则有可能在改变这两位时产生中断。
*/

    ACSR=(1<
    // 使能模拟比较器中断,比较器输出变化即可触发中断,AIN0为正输入端,AIN1为负输入端。
    sei();                                                        //使能全局中断
    while (1); //主程序没有任务。任何情况都必须是一个无限循环。
}

/*
程序测试:
       两个电位器,一端接VCC,一端接地,构成电位器分压电路。
    AIN0和AIN1都分别接到电位器的中心抽头。
    PBO输出串电阻驱动LED,高电平有效。
    然后分别旋转电位器,增减抽头的电压,将会发现PB0的输出(LED0)会根据 AIN0/AIN1的电压关系变动。
    由于电源纹波,IO电流及外界干扰的影响,当电压差接近0V时,模拟比较器会产生临界抖动,AIN0/AIN1对地并上小电容可以改善这种情况。
在使用AVR51实验板时,由于只有一个电位器,需要变通:
    1、可以使能ACBG,利用1.23V内部能隙基准源代替AIN0作模拟比较器的正输入端。
           ACSR=(1<
    2、可以使能ADC的内部2.56V电压基准,然后把AIN0或AIN1连接到pin32 AREF脚。
            ADCSRA=(1<  //需要打开ADC
            ADMUX=(1<
*/



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|文字版|手机版|DIY编程器网 ( 桂ICP备14005565号-1 )

GMT+8, 2025-7-23 03:13 , 耗时 0.091964 秒, 18 个查询请求 , Gzip 开启.

各位嘉宾言论仅代表个人观点,非属DIY编程器网立场。

桂公网安备 45031202000115号

DIY编程器群(超员):41210778 DIY编程器

DIY编程器群1(满员):3044634 DIY编程器1

diy编程器群2:551025008 diy编程器群2

QQ:28000622;Email:libyoufer@sina.com

本站由桂林市临桂区技兴电子商务经营部独家赞助。旨在技术交流,请自觉遵守国家法律法规,一旦发现将做封号删号处理。

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