一 STC32G系列单片机寄存器简介
STC32G系列单片机内部集成了一个比较器,其正极可以在P3.7、P5.0、P5.1、或者ADC的模拟输入通道间切换;而负极可以是P3.7或者内部BandGap经过OP的REF电压。通过配置分时复用可以实现多个比较器的应用。
STC32G系列单片机的比较器有模拟、数字两级可编程滤波。模拟滤波可消除信号毛刺。通过设置数字滤波的CPU时钟数,等信号稳定后再比较。
STC32G系列单片机的比较器的比较结果可以从寄存器中读出,也可让其在单片机的端口输出,如从P3.4或P4.l输出。 STC32G系列单片机的中断源中包含比较器中断,比较器的比较结果由0变1,或者由1变0,皆可产生中断请求,可在比较器控制寄存器1中设置。
STC32G系列单片机比较器的内部结构图如下:

STC32G系列单片机比较器输出脚选择控制位寄存器为P_SW2的B3位,如下:

与STC32G系列单片机比较器相关的寄存器共有3个如下:

控制寄存器1的各bit位的作用如下:

控制寄存器2的各bit位的作用如下:


比较器扩展配置寄存器各bit位的作用如下:

二 STC32G系列单片机比较器相关寄存器配置编程
要使用STC32G系列单片机内部集成比较器,就离不开对其相关寄存器配置操作编程。最好的办就是将常用的配置操作做成库函数,供以后使用时调用。下面是STC32G比较器库函数的头文件与源文件的示例。
头文件
/*STC32G_Comparator.h
Designed by Bill Liu
Version 0.0
Modified last by Bill Liu,07/12/2022
enum
STC32G_CMP_PSOURCE // comparator positive input source
STC32G_CMP_NSOURCE // comparator negtive source
///struct//
STC32G_ComparatorDef
///macro function/
CMP_OUTPINSELP34();
CMP_OUTPINSELP41();
CMP_ENABLE();
CMP_DISABLE();
CMP_CLEARFLAG();
CMP_PEDGEINTENABLE(); //compare result change to positive Int enable
CMP_PEDGEINTDISABLE(); //compare result change to positive Int disable
CMP_NEDGEINTENABLE(); //compare result change to negtive Int enable
CMP_NEDGEINTDISABLE(); //compare result change to negtive Int disable
CMP_RESULTOUENABLE();
CMP_RESULTOUDISABLE();
CMP_GETRESULT(res);
CMP_AFILTERENABLE(); //0.1uS analog filter enable
CMP_AFILTERDISABLE();
CMP_INVERTRESOUTENABLE();
CMP_INVERTRESOUTDISABLE();
CMP_NSOURCEP36(); //set P3.6 as coparator negative input source
CMP_NSOURCEINREF(); //set inner bandgap viltage as coparator negative input source
CMP_PSOURCEP37(); //set P3.7 as compraror positive input source
CMP_PSOURCEP50(); //set P5.0 as compraror positive input source
CMP_PSOURCEP51(); //set P5.1 as compraror positive input source
CMP_PSOURCEADCIN();
Function
CMP_ConfiguDigFilter(ui8 nData); //configure digital filter data, return void
CMP_HysVoltageSel(ui8 mSel); //configure comparator DC input hysteresis voltage, return void
CMP_NSource(STC32G_CMP_NSOURCE mSel); //configure comparator negtive input source, return void
CMP_PSource(STC32G_CMP_PSOURCE mSel); //configure comparator negtive input source, return void
CMP_InitDef(STC32G_ComparatorDef* mStruct); // return void
CMP_StructInit(STC32G_ComparatorDef mStruct); //return void
*/
#ifndef __STC32G_COMPARATOR_H
#define __STC32G_COMPARATOR_H
#include "config.h"
#include "mtype.h"
#include "STC32G.h"
#define CMP_OUTPINSELP34() {CMPO_S = 0;}
#define CMP_OUTPINSELP41() {CMPO_S = 1;}
#define CMP_ENABLE() {CMPEN = 1;} //comparator enable(switch on)
#define CMP_DISABLE() {CMPEN = 0;} //comparator disable(switch off)
#define CMP_CLEARFLAG() {CMPIF = 0;}
#define CMP_PEDGEINTENABLE() {PIE = 1;} //compare result change to positive Int enable
#define CMP_PEDGEINTDISABLE() {PIE = 0;} //compare result change to positive Int disable
#define CMP_NEDGEINTENABLE() {NIE = 1;} //compare result change to negtive Int enable
#define CMP_NEDGEINTDISABLE() {NIE = 0;} //compare result change to negtive Int disable
#define CMP_RESULTOUDISABLE() {CMPOE = 0;}
#define CMP_RESULTOUENABLE() {CMPOE = 1;}
#define CMP_GETRESULT(res) {(res) = CMPRES;}
#define CMP_AFILTERENABLE() {DISFLT = 0;} //0.1uS analog filter enable
#define CMP_AFILTERDISABLE() {DISFLT = 1;} //0.1uS analog filter disable
#define CMP_INVERTRESOUTENABLE() {INVCMPO = 1;} //invert compare result out enable
#define CMP_INVERTRESOUTDISABLE() {INVCMPO = 0;} //invert compare result out disable
#define CMP_NSOURCEP36() {CMPEXCFG &= 0xFB;} //Negtive source is inner P36
#define CMP_NSOURCEINREF() {CMPEXCFG |= 0x04;} //Negtive source is inner Ref voltage
#define CMP_PSOURCEP37() {CMPEXCFG &=0xFC;} //positve source is P37
#define CMP_PSOURCEP50() {CMPEXCFG &= 0xFC; CMPEXCFG |= 0x01;}
#define CMP_PSOURCEP51() {CMPEXCFG &= 0xFC; CMPEXCFG |= 0x01;}
#define CMP_PSOURCEADCIN() {CMPEXCFG &= 0xFC; CMPEXCFG |= 0x03;}
//*******************************************************
typedef enum
{
PS_P37 = 0,
PS_P50,
PS_P51,
PS_ADCIN
}STC32G_CMP_PSOURCE; // comparator positive input source
//*******************************************************
typedef enum
{
NS_P36 = 0,
NS_BAND //inner bandgap reference voltage
}STC32G_CMP_NSOURCE; // comparator negtive source
//*******************************************************
typedef enum
{
O_P34 = 0, //compare result output at P34
O_P41 //compare result output at P41
}STC32G_CMPO_PIN; // comparator output pin
//*******************************************************
typedef struct
{
STC32G_CMP_PSOURCE pSource;
STC32G_CMP_NSOURCE nSource;
BOOL outAble;
STC32G_CMPO_PIN oPin;
BOOL pIntAble;
BOOL nIntAble;
BOOL rInvAble; //invert compare result eanble/disable
BOOL aFilter;
ui8 dFilterCycles;
ui8 dcInputHys; //DC input hysteresis valtage
}STC32G_ComparatorDef;
/***********************************************************
Function: CMP_ConfiguDigFilter(ui8 nData);
Return value: void
nData: digital filter data,digital filter time: nData+2 system cycle times
Discription: configure digital filter data
Example:
CMMP_ConfiguDigFilter(0);
***********************************************************************/
void CMP_ConfiguDigFilter(ui8 nData);
/***********************************************************
Function: CMP_HysVoltageSel(ui8 mSel);
Return value: void
mSel: selected hysteresis voltage,0: 0mV, 1: 10mV, 2: 20mV, 3: 30mV
Discription: configure comparator DC input hysteresis voltage
Example:
CMP_HysVoltageSel(0x01); //selected: 10mV
***********************************************************************/
void CMP_HysVoltageSel(ui8 mSel);
/***********************************************************
Function: CMP_NSource(STC32G_CMP_NSOURCE mSel);
Return value: void
mSel: negtive input source
Discription: configure comparator negtive input source
Example:
CMP_NSource(0x00); //ngeive sourve:P36
***********************************************************************/
void CMP_NSource(STC32G_CMP_NSOURCE mSel);
/***********************************************************
Function: CMP_PSource(STC32G_CMP_PSOURCE mSel);
Return value: void
mSel: positve input source
Discription: configure comparator negtive input source
Example:
CMP_PSource(0x00); //ngeive sourve:P36
***********************************************************************/
void CMP_PSource(STC32G_CMP_PSOURCE mSel);
/***********************************************************
Function: CMP_InitDef(STC32G_CompareDef* mStruct);
Return value: void
mStruct: STC32G_CompareDef pointer variable
Discription: init comparator struct to default
Example:
STC32G_CompareDef mSruct;
CMP_InitDef(&mSruct); //init comparator struct to default
***********************************************************************/
void CMP_InitDef(STC32G_ComparatorDef* mStruct);
/***********************************************************
Function: CMP_Init(STC32G_CompareDef mStruct);
Return value: void
mStruct: struct STC32G_CompareDef variable
Discription: configure comparator by mStruct
Example:
STC32G_CompareDef mStruct;
CMP_InitDef(&mSruct);
mSruct.pSource = PS_P37;
mSruct.nSource =NS_P36;
CMP_Init(mStruct); //configure comparator by mStruct
***********************************************************************/
void CMP_Init(STC32G_ComparatorDef mStruct);
#endif
源文件
/*STC32G_Comparator.c
Designed by Bill Liu
Version 0.0
Modified last by Bill Liu, 07/12/2022
*/
#include "STC32G_Comparator.h"
//***********************************************************************
void CMP_ConfiguDigFilter(ui8 nData)
{
CMPCR2 &= 0xC0;
CMPCR2 |= nData;
}
//End of CMP_ConfiguDigFilter(ui8 nData)
//***********************************************************************/
void CMP_HysVoltageSel(ui8 mSel)
{
//SysInit();
CMPEXCFG &= 0x07;
CMPEXCFG |= (mSel << 6);
}
//End of CMP_HysVoltageSel(ui8 mSel)
//***********************************************************************
void CMP_NSource(STC32G_CMP_NSOURCE mSel)
{
//SysInit();
if(mSel)
CMPEXCFG |= 0x01 << 2;
else
CMPEXCFG &= 0xF3;
}
//End of CMP_NSource(STC32G_CMP_NSOURCE mSel)
//***********************************************************************/
void CMP_PSource(STC32G_CMP_PSOURCE mSel)
{
//SysInit();
CMPEXCFG &= 0xFC;
CMPEXCFG |= mSel;
}
//End of CMP_PSource(STC32G_CMP_PSOURCE mSel)
//***********************************************************
void CMP_InitDef(STC32G_ComparatorDef* mStruct)
{
mStruct -> pSource = PS_P37;
mStruct -> nSource = NS_P36;
mStruct -> outAble = 0; //disable
mStruct -> oPin = O_P34;
mStruct -> pIntAble = 0; // INT disable
mStruct -> nIntAble = 0; // INT disable
mStruct -> rInvAble = 0; // compare result invert disable
mStruct -> aFilter = 1; //0.1uS analog filter enable
mStruct -> dFilterCycles = 0;
mStruct -> dcInputHys = 0;
}
//End of CMP_InitDef(STC32G_CompareDef* mStruct)
//***********************************************************************
void CMP_Init(STC32G_ComparatorDef mStruct)
{
//SysInit();
CMP_PSource(mStruct.pSource);
CMP_NSource(mStruct.nSource);
CMPOE = mStruct.outAble;
CMPO_S = mStruct.oPin;
PIE = mStruct.pIntAble;
NIE = mStruct.nIntAble;
INVCMPO = mStruct.rInvAble;
DISFLT = mStruct.aFilter;
CMP_ConfiguDigFilter(mStruct.dFilterCycles);
CMP_HysVoltageSel(mStruct.dcInputHys);
}
//End of CMP_StructInit(STC32G_CompareDef mStruct)
三 STC32G单片机比较器的常见用法及其编程
启动掉电保护
下面是STC官方提供的掉电保护启动电路

其原理是:将7805稳压前的电压经分压电阻分压到一个适当的值,送入比较器+(P3.7),与单片机内部的Bandgap电压(1.19V)比较,当分压低于内部1.19V电压时,触发比较中断,在中断函数中将重要的参数写入单片机内部EEPROM,或外部存储器,这对一些测试仪器等设备十分有用。注意:如果写入的数据较多,需要在容量为104的电容器前,二极管后,再并一个容量较大的延时供电电容器。下面就写一个来实现掉电保护的测试程序。
程序头文件:
/*main.h
Designed by Bill Liu
Version 0.0
Modified last by Bill Liu ,03/25/2023
*/
#ifndef __MAIN_H__
#define __MAIN_H__
//#include "myport.h"
#include "mtype.h"
#include "config.h"
#include "STC32G_GPIO.h"
#include "STC32G_Delay.h"
#include "STC32G_UART.h"
#include "STC32G_EEPROM.h"
//#include "STC32G_PWM.h"
//#include "STC32G_ADC.h"
//#include "STC32G_EEPROM.H"
//#include "STC32G_SPI.h"
#include "STC32G_PWM.h"
//#include "STC32G_Timer.h"
#include "STC32G_comparator.h"
STC32G_ComparatorDef mstuct;
#endif
源文件:
/*main.c
Designed by Bill Liu
Version 0.0
Modified last by Bill Liu, 03/25/2023
*/
#include "main.h"
ui8 str[30] = {0};
i16 t1 = 105;
i16 t2 = 115;
i16 t3 ,t4;
void STC_CmpInt(void) interrupt 21 //comparator interrupt function
{
EEPROM_SectorErase(0x0000);
EEPROM_Write_nChar(0x0000,&t1,0x02);
EEPROM_Write_nChar(0x0002,&t2,0x02);
}
void main()
{
SysInit();
Uart1_Init(VBAUD_8BITS,G1, 0, 9600);
CMP_CLEARFLAG(); //clear comparator INT flag
CMP_InitDef(&mstuct); //init comparator struct to defaut
mstuct.nSource = NS_BAND; //set bandgap voltage as comparator negative source
mstuct.nIntAble = 1; // fall edge interrupt enbale
CMP_StructInit(mstuct); //init conparator by mstruct
CMP_ENABLE(); //comparator enable
EA =1; //interrupt enable
EEPROM_Read_nChar(0x0000,&t3, 2);
EEPROM_Read_nChar(0x0002,&t4, 2);
while(1)
{
LongToString(t3,str);
Uart1_SendString(str);
Uart1_SendString("\r\n");
LongToString(t4,str);
Uart1_SendString(str);
Uart1_SendString("\r\n");
Uart1_SendString("This a Test Program!");
Uart1_SendString("\r\n");
Delayxms(1000);
}
}
//End of main()
将程序编译后下载到单片机。重启后,打开STC-ISP中的串口调试助手,如果看到如下结果,说明掉电保护启动成功。

如果看到的是如下结果,说明你的输入分压不合适,或者延时供电电容太小。

b. 电池电量过低检测
其原理与掉电保护类似,这里不再重复
c.锂电池温度检测,过高报警
市面锂电池输出线有的有两条线,有的有三条线。有三条线的有温度监测功能,在多出的一条线与电池负(GND)之间串接了一个热敏电阻,一般是NTC,利用这个电阻,就可搭成一个分压电路,利用比较器,就可实现温度监测,防止温度过高。其原理实现与a相似,这里就不重复了。
d 比较器搭配三极管或MOS管还可实现PWM恒流恒压,由于该单片机本身就内置了PWM模块,一般不需要用比较器来实现PWM恒流恒压,这里就不再做详细介绍。