首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

AVR单片机模拟比较器使用范例编程

AVR单片机模拟比较器使用范例编程

/***********************************************

****       AVR 模拟比较器使用范例              ***

****                                        ***

**** 作者:  HJJourAVR                        ***

**** 编译器:WINAVR20050214                   ***

****                                         ***

***********************************************/

/*

本程序简单的示范了如何使用ATMEGA16的模拟比较器

模拟比较器的设置

中断方式--较常用

查询方式不常用,检测ACO即可,可用作DELTA-SIGMA A/D CONVERTER,校正后精度比较高,但速度低,用汇编可以略为提高速度。



出于简化程序考虑,各种数据没有对外输出,学习时建议使用JTAG ICE硬件仿真器

*/


#Include <Avr/Io.H>

#Include <Avr/Delay.H>

#Include <Avr/Signal.H>

#Include <Avr/Interrupt.H>

/*

宏INTERRUPT 的用法与SIGNAL 类似,区别在于

    SIGNAL 执行时全局中断触发位被清除、其他中断被禁止

    INTERRUPT 执行时全局中断触发位被置位、其他中断可嵌套执

另外Avr-Libc 提供两个API 函数用于置位和清零全局中断触发位,它们是经常用到的。

分别是:Void Sei(Void) 和Void Cli(Void) 由Interrupt.H定义

*/


/*

注: 内部函数_delay_ms() 最高延时  [email=262.144mS@1MHz]262.144mS@1MHz[/email]

    该函数可以实现较精确的定时,但用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<<LED0)   //输出高电平,灯亮

#Define LED0_OFF()  PORTB&=~(1<<LED0) //输出低电平,灯灭


//常量定义

/*

模拟比较器的正输入端由 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))==0) //检测ACO

     LED0_ON();   //如果AIN0<AIN1(ACO=0),LED亮

    Else

     LED0_OFF();   //否则 LED灭

    _delay_ms(200);   //当电压差接近0V时,模拟比较器会产生临界抖动,故延时200mS令肉眼能看到   

}




Int Main(Void)

{

    //上电默认DDRx=0x00,PORTx=0x00 输入,无上拉电阻

    PORTA=0xFF;

    PORTC=0xFF;      //不用的管脚使能内部上拉电阻。

    PORTD=0xFF;

    PORTB=~((1<<AIN_P)|(1<<AIN_N)); //作模拟比较器输入时,不可使能内部上拉电阻。

    DDRB= (1<<LED0);    //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<<ACIE);

    // 使能模拟比较器中断,比较器输出变化即可触发中断,AIN0为正输入端,AIN1为负输入端。


    Sei();        //使能全局中断

    While (1); //主程序没有任务。任何情况都必须是一个无限循环。

}


/*

程序测试:


       VCC      VCC

        |        |

       | |      | |               

AIN0--|W|      |W|--AIN1  PB0---R---LED--

       | |      | |                       |

        |        |                        |

       GND      GND                      GND



两个电位器,一端接VCC,一端接地,构成电位器分压电路

    AIN0和AIN1都分别接到电位器的中心抽头。

    PBO输出串电阻驱动LED,高电平有效。

    然后分别旋转电位器,增减抽头的电压,将会发现PB0的输出(LED0)会根据 AIN0/AIN1的电压关系变动

    由于电源纹波,IO电流及外界干扰的影响,当电压差接近0V时,模拟比较器会产生临界抖动,AIN0/AIN1对地并上小电容可以改善这种情况。

   

    在使用AVR51实验板时,由于只有一个电位器,需要变通

    1 可以使能ACBG,利用1.23V内部能隙基准源代替AIN0作模拟比较器的正输入端。

     ACSR=(1<<ACIE)|(1<<ACBG);

    2 可以使能ADC的内部2.56V电压基准,然后把AIN0或AIN1连接到Pin32 AREF脚。

     ADCSRA=(1<<ADEN);  //需要打开ADC

     ADMUX=(1<<REFS1)|(1<<REFS0);

*/
返回列表