COMP简介
COMP作为比较器,可用于比较模拟输入电压,并集成数字滤波器,其结果可输出至I/O口或定时器。
MM32F0140的COMP包含连接外部输入的COMP正相通道1 ~ 4,连接CRV及其他外部输入的COMP反相输入通道1 ~ 4;支持多种速率和功耗,支持比较结果的滤波功能,支持通过外部事件将CPU从睡眠和停机模式唤醒,带有轮询功能。
COMP的功能框图如图1所示,COMP存在多个正相输入与多个反相输入通道,正相输入可从各外部引脚之间选取,反相输入可从外部引脚或者CRV电压分压值,CRV的电压可选择VDDA或者内部参考电压(VREFINT)的分压。当正相输入电压高于反相输入电压,输出比较结果为高输出,当正相输入电压低于反相输入电压,输出比较结果为低输出,比较结果可输出至定时器或I/O口。
图1.COMP功能框图
COMP配置
COMP的配置包含关于输出滤波、迟滞电压、输出极性、输出方向选择、正相输入选择、反相输入选择、功耗选择及比较器工作模式选择,其中在使用I/O端口用作比较器输入时,需配置对应引脚为模拟输入模式;比较器也具有锁定机制,可保证比较器的设置不会被无效寄存器访问或因程序计数器破坏而改变。
迟滞电压
迟滞电压能够防止噪声干扰,保证系统工作更加稳定,可通过操作比较器控制状态寄存器(COMPx_CSR)的HYST位,对迟滞电压进行配置。迟滞电压可配置为:90mV(HYST[1:0]=11)、30mV(HYST[1:0]=10)、15mV(HYST[1:0]=01)、0mV(HYST[1:0]=00)。
输出极性
输出极性用于设置输出为同相输出或反相输出,操作比较器控制状态寄存器(COMPx_CSR)的POL位,POL配置为1则为反相输出,POL位配置为0则为同相输出。
输出方向
通过操作比较器控制状态寄存器(COMPx_CSR)的OUT_SEL位,可配置输出结果到特定的定时器中,COMP输出方向列表如图2所示。
图2.COMP输出方向
正相输入
操作比较器控制状态寄存器(COMPx_CSR)的INP_SEL位,可对比较器的正相输入信号源进行选择,共有4种信号源,正相通道如图3所示。
- 正相通道0 COMPx_INP0(INP\_SEL[1:0]=00)
- 正相通道1 COMPx_INP1(INP\_SEL[1:0]=01)
- 正相通道2 COMPx_INP2(INP\_SEL[1:0]=10)
- 正相通道3 COMPx_INP3(INP\_SEL[1:0]=11)
图3.COMP正相输入
反相输入
操作比较器控制状态寄存器(COMPx_CSR)的INM_SEL位,可对比较器的反相输入信号源进行选择,部分反相通道如图4所示。
- 反相通道0 COMPx_INM0(INM\_SEL[2:0]=000)
- 反相通道1 COMPx_INM1(INM\_SEL[2:0]=001)
- 反相通道2 COMPx_INM2(INM\_SEL[2:0]=010)
- 反相通道3 COMPx_INM3(INM\_SEL[2:0]=011)
- 反相通道4 COMPx_INM4(INM\_SEL[2:0]=100)
图4.COMP反相输入
功耗模式
在具体应用中,可通过调整比较器功耗和响应时间得到最优的结果,功耗模式共包含四种,能够通过软件操作比较器控制状态寄存器(COMPx_CSR)的MODE位进行功耗设置。
- 高速/高功耗(MODE[1:0]=00)
- 中速/中等功耗(MODE[1:0]=01)
- 低速/低功耗(MODE[1:0]=10)
- 极低速/极低功耗(MODE[1:0]=11)
输出滤波
操作比较器控制状态寄存器(COMPx_CSR)的OFLT位,可进行输出滤波的配置,若比较结果保持n个时钟周期不变,则输出有效,"n"为图5中所例举的时钟周期数。
图5.输出滤波配置
工作模式
- 普通工作模式
COMP的输入通道可以在普通工作模式下通过软件选择,配置比较器控制状态寄存器(COMPx_CSR)的INP_SEL位和INM_SEL位选择正相输入与反相输入,将COMPx_CSR寄存器的EN位置1,使能比较器,COMP比较所选择的INP和INM端口上的信号,比较结果存放于COMPx_CSR寄存器的OUT位。若在配置COMP的INM_SEL位时选择CRV,则需要配置比较器外部参考电压寄存器(COMP_CRV)的CRV_SEL位,然后将CRV_EN置位。 - 轮询工作模式
COMP可以在轮询工作模式下通过硬件轮询的方式分时监测多个通道的比较结果,配置比较器轮询寄存器(COMPx_POLL)的PER1OD位来选择所需要的轮询等待周期,配置F1XN位决定INM端口的信号是否跟随INP端口轮询变化,配置POLL_CH位决定所需要轮询的通道是1/2/3 或者1/2,POLL_EN位置1启动轮询功能,再配置COMPx_CSR寄存器的EN位,使比较器开始上电工作,轮询比较的结果存放于COMPx\_POLL寄存器的POUT位,其中POUT[2]、POUT[1]、POUT[0]位分别存放轮询通道3/2/1的比较结果。
锁定机制
为使比较器设置不会被无效寄存器访问或因程序计数器破坏而改变,可将比较器控制状态寄存器设置为写保护。操作比较器控制状态寄存器(COMPx_CSR)的LOCK位置1,使比较器锁定,整个COMPx_CSR寄存器变成只读,该位可由系统复位清零。
实验
本实验使用COMP的0号比较器,将正相输入通道0与反相输入通道0进行比较,通过串口打印当前的比较状态。配置比较器控制状态寄存器的OFLT位,设置为若比较结果保持4个时钟周期不变,则输出有效;配置HYST位使迟滞电压为90mV,配置POL位使输出极性为同相输出,配置OUT_SEL位为0使输出结果不进入任何TIM,配置INP_SEL与INM_SEL位选择正相输入通道0与反相输入通道0,配置MODE位使功耗为高速/高功耗;通过EN位置位使能COMP,给予正相输入通道与反相输入通道电压,通过串口观察比较结果。
启用COMP外设时钟 enable_clock()
实验使用COMP进行正相输入电压与反相输入电压对比,采用串口打印的方式观察实验结果,所使用的引脚均属于GPIOA组,因此需要启用COMP、UART1及GPIOA的外设时钟。
void enable_clock()
{
/* Enable COMP clock. */
RCC->APB2ENR |= RCC_APB2_PERIPH_COMP;
/* Enable GPIOA clock. */
RCC->AHB1ENR |= RCC_AHB1_PERIPH_GPIOA;
/* Enable UART1 clock. */
RCC->APB2ENR |= RCC_APB2_PERIPH_UART1;
}
配置引脚 pin_init()
配置COMP的正相输入通道0与反相输入通道0所对应的引脚,正相通道0的对应引脚为PA1,反相通道0的对应引脚为PA5,模式配置为模拟输入;由于实验现象通过串口显示,故配置UART的TX(PA9)与RX(PA10)引脚。
void pin_init()
{
/* PA1 - COMP PInput_0. */
GPIOA->CRL &= ~GPIO_CRL_MODE1_MASK;
GPIOA->CRL |= GPIO_CRL_MODE1(GPIO_PinMode_In_Analog); /* PA1 Analog input. */
/* PA5 - COMP NInput_0. */
GPIOA->CRL &= ~GPIO_CRL_MODE5_MASK;
GPIOA->CRL |= GPIO_CRL_MODE5(GPIO_PinMode_In_Analog); /* PA5 Analog input. */
/* Setup PA9, PA10. */
GPIOA->CRH &= ~GPIO_CRH_MODE9_MASK;
GPIOA->CRH |= GPIO_CRH_MODE9(GPIO_PinMode_AF_PushPull); /* PA9 multiplexed push-pull output. */
GPIOA->AFRH &= ~GPIO_AFRH_AFR_MASK;
GPIOA->AFRH |= (GPIO_AF_1 << GPIO_CRH_MODE9_SHIFT); /* Use AF1. */
GPIOA->CRH &= ~GPIO_CRH_MODE10_MASK;
GPIOA->CRH |= GPIO_CRH_MODE10(GPIO_PinMode_In_Floating); /* PA10 floating input. */
GPIOA->AFRH |= (GPIO_AF_1 << GPIO_CRH_MODE10_SHIFT); /* Use AF1. */
}
UART初始化 uart_init()
初始化UART,配置时钟频率、波特率、数据长度、停止位、传输模式及是否使用校验。
void uart_init()
{
/* Clear the corresponding bit to be used. */
UART1->CCR &= ~( UART_CCR_PEN_MASK | UART_CCR_PSEL_MASK | UART_CCR_SPB0_MASK | UART_CCR_SPB1_MASK | UART_CCR_CHAR_MASK );
UART1->GCR &= ~( UART_GCR_AUTOFLOWEN_MASK | UART_GCR_RXEN_MASK | UART_GCR_TXEN_MASK );
/* WordLength. */
UART1->CCR |= UART_CCR_CHAR_MASK;
/* XferMode. */
UART1->GCR |= (UART_XferMode_RxTx << UART_GCR_RXEN_SHIFT);
/* Setup baudrate, BOARD_DEBUG_UART_FREQ = 48000000u, BOARD_DEBUG_UART_BAUDRATE = 9600u. */
UART1->BRR = (BOARD_DEBUG_UART_FREQ / BOARD_DEBUG_UART_BAUDRATE) / 16u;
UART1->FRA = (BOARD_DEBUG_UART_FREQ / BOARD_DEBUG_UART_BAUDRATE) % 16u;
/* Enable UART1. */
UART1->GCR |= UART_GCR_UARTEN_MASK;
}
COMP初始化 comp_init()
实验使用COMP的0号比较器,操作比较器控制状态寄存器(COMP1_CSR),配置输出滤波、迟滞电压、输出极性、输出方向选择、正相输入通道、反相输入通道及功耗模式。
void comp_init()
{
/* Output filter. */
COMP->CSR[0] |= COMP_CSR_OFLT(COMP_OutFilter_4); /* If the comparison result remains unchanged for four clock cycles, the output is valid. COMP_OutFilter_4 = 2. */
/* Hysteresis. */
COMP->CSR[0] |= COMP_CSR_HYST(COMP_Hysteresis_Alt3); /* 90mV, COMP_Hysteresis_Alt3 = 3. */
/* No invert output. */
COMP->CSR[0] |= COMP_CSR_POL(false); /* In-phase output. */
/* Not output to other peripheral input. */
COMP->CSR[0] |= COMP_CSR_OUTSEL(COMP_OutMux_None); /* COMP_OutMux_None = 0. */
/* Positive side. */
COMP->CSR[0] |= COMP_CSR_INPSEL(COMP_InMux_Alt0); /* COMP_INP[0], PA1, COMP_InMux_Alt0 = 0. */
/* Inverse side. */
COMP->CSR[0] |= COMP_CSR_INMSEL(COMP_InMux_Alt0); /* COMP_INM[0], PA5, COMP_InMux_Alt0 = 0. */
/* The faster the speed, the higher the power consumption. */
COMP->CSR[0] |= COMP_CSR_MODE(COMP_Speed_High); /* COMP_Speed_High = 0, high speed, high power. */
}
main()函数
main()函数结合上述操作,通过读取比较器控制状态寄存器(COMP_CSR)的OUT位,获取当前输出状态;本实验使对应引脚由杜邦线连接VCC或GND,从而给予正相输入通道与反相输入通道电压,每按下任意按键就获取一次当前输出状态,当正相输入高于反相输入,输出为高输出,串口打印"- positive";当正相输入低于反相输入,输出为低输出,串口打印"- inverse"。实验结果如图6所示,当PA1接VCC且PA5接GND时,当前输出状态为高输出,按下任意按键,串口显示"- positive";当PA1接GND且PA5接VCC时,当前输出状态为低输出,按下任意按键,串口显示"- inverse"。
void main()
{
enable_clock();
pin_init();
uart_init();
printf("comp_basic example.\r\n");
comp_init();
printf("press any key to get compare result ...\r\n");
while (1)
{
getchar();
if ( 0u != ( COMP_CSR_OUT_MASK & COMP->CSR[0] ) )
{
printf("- positive.\r\n"); /* The positive input voltage is higher than the negative input voltage. */
}
else
{
printf("- inverse.\r\n"); /* The positive input voltage is lower than the negative input voltage. */
}
}
}
图6.实验结果