-
- 学习目的
- 学习比较器的作用和原理。
- 掌握比较器的应用流程包括配置、启动以及中断服务函数的编写。
- 比较器原理
STC8A8K64D4单片机片内集成了比较器(Comparator),比较器有两个输入端IN+(正端输入端)和(负端输入端),可选择其中一个输入端作为参考点来比较,通常使用负端输入端(IN-)做为参考点,当正端输入端电压小于负端输入端时比较器输出低电平,反之输出高电平。
STC8A8K64D4的比较器原理框图如下图所示,主要包含输入选择、滤波配置以及输出控制和中断选择控制。
图1:比较器原理框图
- 选择输入端
输入端选择包含正端输入端选择和负端输入端选择,正端输入端可以配置为P3.7、P5.1、P5.1端口或者ADC的模拟输入通道。负端输入端可以配置为P3.6端口或者是内部BandGap经过OP后的REFV电压(内部固定比较电压)。
正端输入和负端输入是通过“比较器扩展配置寄存器(CMPEXCFG)”的CMPNS位和CMPPS[1:0]位配置,如下图所示。
比较器扩展配置寄存器(CMPEXCFG):
- CMPNS:比较器负端输入选择
- 0: P3.6。
- 1: 选择内部 BandGap 经过 OP 后的电压 REFV 作为比较器负极输入源 (芯片在出厂时,内部参考电压调整为 1.19V)。
- CMPPS[1:0]:比较器正端输入选择
- 00:P3.7。
- 01:P5.0。
- 10:P5.1。
- 11:ADCIN,此时必须打开ADC_CONTR寄存器中的ADC电源控制位ADC_POWER和ADC通道选择位ADC_CHS。
- 滤波配置
比较器内部有可程序控制的两级滤波:模拟滤波和数字滤波。模拟滤波可以过滤掉比较输入信号中的毛刺信号,数字滤波可以等待输入信号更加稳定后再进行比较。
模拟滤波和数字滤波通过“比较器控制寄存器2(CMPCR2)”的DISFLT位和LCDTY[5:0]位配置,如下图所示。
比较器控制寄存器2(CMPCR2):
- DISFLT:模拟滤波功能控制
- 0:使能0.1us模拟滤波功能。
- 1:关闭0.1us模拟滤波功能,可略微提高比较器的比较速度。
- LCDTY[5:0]:数字滤波功能控制
数字滤波功能即为数字信号去抖动功能。当比较结果发生上升沿或者下降沿变化时,比较器侦测变化后的信号必须维持 LCDTY 所设置的 CPU 时钟数不发生变化,才认为数据变化是有效的,否则将视同信号无变化。
注意: 当使能数字滤波功能后,芯片内部实际的等待时钟需额外增加两个状态机切换时间,即若LCDTY 设置为 0 时,为关闭数字滤波功能。若 LCDTY 设置为非 0 值 n(n=1~63)时,则实际的数字滤波时间为(n+2)个系统时钟。
- 输出控制
比较结果可以通过程序读取“比较器控制寄存器 1(CMPCR1)”寄存器的CMPRES位获取,也可以将配置CMPRES位将结果输出到P3.4或者P4.1端口上,如下图所示。
比较器控制寄存器1(CMPCR1):
- CMPRES:比较器的比较结果。此位为只读。
- 0:表示CMP+的电平低于CMP-的电平。
- 1:表示CMP+的电平高于CMP-的电平。
注意:CMPRES是经过数字滤波后的输出信号,而不是比较器的直接输出结果。
- CMPOE:比较器结果输出控制位
- 0:禁止比较器结果输出
- 1:使能比较器结果输出。比较器结果输出到 P3.4 或者 P4.1(由 P_SW2 中的 CMPO_S 进行设定)
比较器结果是输出到P3.4还是输出到P4.1由“外设端口切换控制寄存器2(P_SW2)”的CMPO_S位控制,如下所示。
- CMPO_S:比较器输出引脚选择位
- 0:比较结果输出到P3.4。
- 1:比较结果输出到P4.1。
- 中断控制
比较器通过配置“比较器控制寄存器1(CMPCR1)”的PIE位或NIE位开启中断,中断开启后,若中断产生,硬件置位比较器中断标志位CMPIF(该位必须软件清零)。
比较器控制寄存器1(CMPCR1):
- PIE:比较器上升沿中断使能位。
- 0:禁止比较器上升沿中断。
- 1:使能比较器上升沿中断,比较结果由0变成1时产生中断请求。
- NIE:比较器下降沿中断使能位。
- 0:禁止比较器下降沿中断。
- 1:使能比较器下降沿中断,比较结果由1变成0时产生中断请求。
- CMPIF:比较器中断标志位。当PIE或NIE被使能后,若产生相应的中断信号,硬件自动将CMPIF置1,并向CPU发出中断请求,此标志位必须用户软件清零。(注意:没有使能比较器中断时,硬件不会置位此中断标志,即使用查询方式访问比较器时,不能查询此中断标志)。
- 软件设计
- 比较器应用步骤
- 软件设计
比较器的应用步骤如下图所示,其中配置部分主要包含输入端配置、滤波器配置、输出和中断配置。配置完成之后,使能比较器,比较器即开始按照配置的参数工作。
图2:比较器应用流程
- 配置输入端
输入端通过“比较器控制寄存器1(CMPCR1)”的PIS位和NIS位配置,下面的代码配置了比较器的正向输入端为P3.7,反向输入端为P3.6。
代码清单:输入端配置
- CMPCR1 &= ~0x08; //P3.7 为 CMP+输入脚
- CMPCR1 |= 0x04; //P3.6 为 CMP-输入脚
- 配置滤波器
使用比较器的时候,通常会开启0.1us的模拟滤波功能,以消除输入信号中的毛刺信号,模拟滤波的开启和关闭代码如下。
代码清单:模拟滤波配置
- CMPCR2 &= ~0x40; //使能 0.1us 滤波
- //CMPCR2 |= 0x40; //关闭 0.1us 滤波
数字滤波通过CMPCR2寄存器中的LCDTY[5:0]配置,LCDTY共有6位,因此取值范围是0~63。若LCDTY的值设置为0,则数字滤波关闭,若设置为1~63,则对应的实际数字滤波时间为:(LCDTY的值+2)个系统时钟。下面的代码设置了比较器结果经过 16个去抖时钟后输出。
代码清单:数字滤波配置
- CMPCR2 = 0x0E; //比较器结果经过 16个去抖时钟后输出
- 配置中断
中断可以配置为:比较结果由0变成1时产生中断请求(上升沿)或比较结果由1变成0时产生中断请求(下降沿)。通常,我们会将他们都使能,这样当正向输入电压大于反向输入电压和正向输入电压小于反向输入电压时都可以触发中断,中断配置的代码如下。
代码清单:中断配置
- CMPCR1 |= 0x30; //使能比较器边沿中断
- // CMPCR1 &= ~0x20; //关闭比较器上升沿中断
- // CMPCR1 |= 0x20; //使能比较器上升沿中断
- // CMPCR1 &= ~0x10; //关闭比较器下降沿中断
- // CMPCR1 |= 0x10; //使能比较器下降沿中断
- 注意:开启比较器中断的情况下,还需要开启总中断“EA=1”,比较器中断才能起作用。
- 使能比较器
将CMPCR1寄存器的CMPEN位置位即使能比较器的比较功能,清零则关闭比较器的比较功能,代码清单如下。
代码清单:中断配置
- CMPCR1 |= 0x80; //使能比较器的比较功能
- CMPCR1 &= ~0x80; //关闭比较器的比较功能
-
- 比较器实验
-
- 注:本节的实验是在“实验2-6-1:串口1数据收发实验”的基础上修改,本节对应的实验源码是:“实验2-9-1:比较器实验”。
-
-
- 实验内容
-
-
配置比较器的负端输入为:内部BandGap经过OP后的电压REFV(1.19V),正端输入为:P3.7。开启比较器的上升沿和下降沿中断,上升沿中断产生后点亮指示灯D1,下降沿中断产生后熄灭指示灯D1。
将P3.7用杜邦线连接到电位器抽头上,旋转电位器改变P3.7的输入电压,当P3.7的电压大于1.19V,产生上升沿中断,D1点亮。当P3.7的电压小于1.19V,产生下降沿中断,D1熄灭。
-
-
-
- 代码编写
-
-
- 新建一个名称为“cmp.c”的文件及其头文件“cmp.h”并保存到工程的“Source”文件夹,并将“cmp.c”加入到Keil工程中的“SOURCE”组。
- 引用头文件
因为在“main.c”文件中使用了“cmp.c”文件中的函数,所以需要引用下面的头文件“cmp.h”。
代码清单:引用头文件
- //引用比较器的头文件
- #include " cmp.h"
- 比较器初始化
比较器初始化代码清单如下,包含配置输入端、模拟滤波和数字滤波以及开启中断。
代码清单:比较器初始化
- /**********************************************************************************
- 功能描述:初始化比较器。正端输入:P3.7,负端输入:内部BandGap经过OP后的电压REFV(1.19V)
- :使能比较器上升沿和下降沿中断
- 参 数:无
- 返 回 值:无
- ***********************************************************************************/
- void cmp_init(void)
- {
- P_SW2 |= 0x80; //将EAXFR位置1,允许访问扩展RAM区特殊功能寄存器(XFR)
- CMPEXCFG = 0x00; //先清零再配置
- CMPEXCFG |= 0x04; //比较器负端输入:内部BandGap经过OP后的电压REFV(1.19V),正端输入:P3.7
- P_SW2 &= 0x7F; //将EAXFR位置0,禁止访问XFR
- CMPCR2 = 0x00; //先清零再配置
- CMPCR2 &= ~0x40; //使能0.1us滤波
- CMPCR2 |= 0x12; //比较器结果经过 20个去抖时钟后输出
- CMPCR1 = 0x00; //先清零再配置
- CMPCR1 |= 0x30; //使能比较器上升沿和下降沿中断
- CMPCR1 |= 0x02; //使能比较器输出
- }
4. 启动和停止比较器
比较器通过置位/清零“比较器控制寄存器1(CMPCR1)”的“CMPEN”位启动和停止,为了方便其他程序调用,我们将比较器启动和停止封装为函数,代码清单如下。
代码清单:比较器启动和停止
- /**********************************************************************************
- * 描 述 : 使能比较器比较功能
- * 入 参 : 无
- * 返回值 : 无
- **********************************************************************************/
- void cmp_start(void)
- {
- CMPCR1 |= 0x80; //使能比较器的比较功能
- }
- /**********************************************************************************
- * 描 述 : 关闭比较器比较功能
- * 入 参 : 无
- * 返回值 : 无
- **********************************************************************************/
- void cmp_stop(void)
- {
- CMPCR1 &= ~0x80; //关闭比较器的比较功能
- }
- 比较器中断服务函数
比较器中断服务函数里面读取“比较器控制寄存器1(CMPCR1)”的“CMPRES”位, “CMPRES”位为“1”表示P3.7的电压大于1.19V,点亮指示灯D1。“CMPRES”位为“0”表示P3.7的电压小于1.19V,熄灭指示灯D1。
代码清单:比较器中断服务函数
- /**********************************************************************************
- * 描 述 : 比较器中断服务函数
- * 入 参 : 无
- * 返回值 : 无
- **********************************************************************************/
- void cmp_isr() interrupt 21
- {
- CMPCR1 &= ~0x40; //清中断标志
- if (CMPCR1 & 0x01) //正向输入端电压高于反向输入端
- {
- led_on(LED_1); //点亮指示灯D1
- }
- else //正向输入端电压低于反向输入端
- {
- led_off(LED_1); //熄灭指示灯D1
- }
- }
- 主函数
主函数中调用比较器初始化和启动函数,完成对比较器的初始化和启动。之后若P3.7的输入电压由低于1.19V增加到高于1.19V,会触发比较器中断,D1指示灯点亮,反之,D1指示灯熄灭。
代码清单:主函数
- /**************************************************************************
- 功能描述:主函数
- 入口参数:无
- 返回值:int类型
- *************************************************************************/
- int main(void)
- {
- P2M1 &= 0xBF; P2M0 &= 0xBF; //设置2.6为准双向口(LED1)
- P3M1 &= 0xFE; P3M0 &= 0xFE; //设置P3.0为准双向口(UART RxD)
- P3M1 &= 0xFD; P3M0 |= 0x02; //设置P3.1为推挽输出(UART TxD)
- uart1_init(); //串口1初始化
- cmp_init(); //比较器初始化
- cmp_start(); //使能比较器
- EA = 1; //使能总中断
- printf("comparator example start! \r\n"); //串口输出程序启动信息
- while(1)
- {
- }
- }
-
-
- 硬件连接
-
-
按照下图所示,短接指示灯D1的跳线帽,并用杜邦线将J29端子的P26连接到J27端子的ADC上,即将电位器抽头连接到比较器的正端输入,方便改变正端输入的电压。
图3:跳线帽短接
-
-
-
- 实验步骤
-
-
- 解压“…\第3部分:配套例程源码”目录下的压缩文件“实验2-9-1:比较器实验”,将解压后得到的文件夹拷贝到合适的目录,如“D\STC8”(这样做的目的是为了防止中文路径或者工程存放的路径过深导致打开工程出现问题)。
- 双击“…\comparator\project”目录下的工程文件“comparator.uvproj”。
- 点击编译按钮编译工程,编译成功后生成的HEX文件“comparator.hex”位于工程的“…\comparator\Project\Object”目录下。
- 打开STC-ISP软件下载程序,下载使用内部IRC时钟,IRC频率选择:24MHz。
程序运行后,旋转电位器改变P3.7的输入电压,当P3.7的电压大于1.19V,产生上升沿中断,D1点亮。当P3.7的电压小于1.19V,产生下降沿中断,D1熄灭。