在无感的BLDC方波控制中,AC7811没办法再直接通过PWDT模块检测霍尔信号了。
所以需要先进行ACMP模块的初始化配置,使能ACMP模块正常工作后,ACMP会对输入的三相反电动势与电机中电电压进行轮询模拟,得到各相反电动势过零点,进而模拟霍尔信号通过CTU输出至PWDT采集。
模块简介
ACMP 模块包括 ACMP0 和 ACMP1。
ACMP0 和 ACMP1 都包含一个比较器和一个 6 位数字模拟转换器(DAC)。模拟多路复用器(MUX)提供一个用于从六个通道中选择模拟输入信号的电路。一个通道由 6 位数字模拟转换器(DAC)提供,其他通道由外部输入提供。
ACMP0 的轮询模式和霍尔输出(Hall)功能专为电机应用而设计。ACMP1 没有轮询和霍尔(Hall)输出功能。
功能框图
普通模式
电路
检测引脚:PA8
被测引脚:PB10
软件
IO口配置
/**
* GPIO_Init
*
* @param[in] void
* @return void
*
* @brief GPIO端口初始化
*/
void GPIO_Init(void)
{
GPIO_SetFunc(GPIO_PA8, 1);//PA8作为功能1 ADC_IN1
GPIO_SetFunc(GPIO_PB10, 0);//PB10作为功能0,
GPIO_SetDir(GPIO_PB10,1);//输出
GPIO_SetPinValue(GPIO_PB10, 0);//输出低电平
}
ACMP初始化
/**
* ACMP_Init
*
* @param[in] void
* @return void
*
* @brief ACMP0模块初始化,
*/
void ACMP0_Normal_Init(void)
{
ACMP_InitType acmpConfig;
ACMP_DACType acmpDACConfig;
acmpConfig.posPin = ACMP_INPUT_EXT1;//正输通道选择
acmpConfig.negPin = ACMP_INPUT_DAC ;//负输入通道选择
acmpConfig.pollEn = 0;//不使能轮询模式
acmpConfig.intEn = ENABLE;//使能中断
acmpConfig.hyst = ACMP_HYST_20MV;//迟滞挡位选择
acmpConfig.edgeType = ACMP_INTERRUPT_EDGE_FALLING_RISING;//中断触发模式
acmpConfig.moduleEnable = ENABLE;//使能ACMP模块
ACMP_Init(ACMP_CHANNEL0,&acmpConfig);
NVIC_EnableIRQ(ACMP0_IRQn );
ACMP_SetCallBack(ACMP_CHANNEL0 , ACMP_CallBack);
acmpDACConfig.val = 63;//dac范围0-63 输出电压值:(val/64)*ref
acmpDACConfig.ref = ACMP_DAC_REFERENCE_VDDA;//DAC参考源选择
acmpDACConfig.enable = ENABLE;//DAC输出使能
ACMP_SetDacValue(ACMP_CHANNEL0, &acmpDACConfig);
}
ACMP0的中断回调
/**
* ACMP_Callback
*
* @param[in] none
* @return none
*
* @brief ACMP0中断回调函数,读出数据输出,并翻转PB10端口
*/
uint8_t ACMPData =0;
void ACMP_CallBack(void)
{
if(ACMP_GetFlag(ACMP_CHANNEL0, ACMP0_OUTPUT_FLAG)!=0) //正常模式中断标志
{
ACMP_ClrFlag(ACMP_CHANNEL0, ACMP0_OUTPUT_FLAG);//清中断标志
ACMPData = (ACMP_GetOutputValue(ACMP_CHANNEL0, ACMP0_OUTPUT_FLAG))>>7;//读出ACMP0正常模式的输出值,正输入大于负输入,输出1,正输入小于负输入,输出1
printf("data is %d\n",ACMPData );
GPIO_SetPinValue(GPIO_PB10, ACMPData);//修改PB10输出电平
}
}
实测
ACMP+:PA8-ACMP_IN1-ADC_IN1
ACMP-:内部的DAC 配置成63 代表5V
也就是说ADC_IN1通道采集到的电压>5V时,则输出为1
ACMPData = (ACMP_GetOutputValue(ACMP_CHANNEL0, ACMP0_OUTPUT_FLAG))>>7;//读出ACMP0正常模式的输出值,正输入大于负输入,输出1,正输入小于负输入,输出1
对于为什么要>>7右移7位,和ACMP0的数据寄存器有关,正常模式输出在第7位上,而读到的是整个DR寄存器的值,所以要进行移位。
发现板子引脚不对
历程中引脚和demo板不对应,进行修改
PA8改成了PC4,对应LED2,让其根据ACMP0采集到的信号进行翻转,点亮或者熄灭LED2。
ACMP-,内部DAC参考电压val修改成30,对应30/64*5V=2.34V
这样就可以使用GND和5V进行测试,观察输出的数值。
接5V时,5>2.34 输出为1;
接GND时,GND<2.34输出为0;
小结
普通模式,重点在于:正输入与负输入的选择;DAC输出电平的设置。
轮询模式
和普通模式相比,有以下区别:
ACMP0模块初始化
/**
* ACMP_Init
*
* @param[in] void
* @return void
*
* @brief ACMP0模块初始化,
*/
void ACMP0_Polling_Init(void)
{
ACMP_InitType acmpConfig;
ACMP_DACType acmpDACConfig;
ACMP_PollingType acmpPollingConfig;
acmpConfig.negPin = ACMP_INPUT_DAC ;//负输入通道选择
acmpConfig.pollEn = 1;//使能轮询模式
acmpConfig.intEn = ENABLE;//使能中断
acmpConfig.hyst = ACMP_HYST_20MV;//迟滞挡位选择
acmpConfig.edgeType = ACMP_INTERRUPT_EDGE_FALLING_RISING;//中断触发模式
acmpConfig.moduleEnable = ENABLE;//使能ACMP模块
ACMP_Init(ACMP_CHANNEL0,&acmpConfig);
NVIC_EnableIRQ(ACMP0_IRQn );
ACMP_SetCallBack(ACMP_CHANNEL0 , ACMP_CallBack);
acmpDACConfig.val = 63;//dac范围0-63 输出电压值:(val/64)*ref
acmpDACConfig.ref = ACMP_DAC_REFERENCE_VDDA;//DAC参考源选择
acmpDACConfig.enable = ENABLE;//DAC输出使能
ACMP_SetDacValue(ACMP_CHANNEL0, &acmpDACConfig);
acmpPollingConfig.posPollingEnable = ENABLE;//正输入通道轮询模式使能
acmpPollingConfig.negPollingEnable = DISABLE;//负输入通道轮询模式关闭
acmpPollingConfig.pollingDiv = ACMP0_POLLING_FREQ_DIVIDER_256;//轮询分频值
acmpPollingConfig.pollingChannelSeq = 7;//轮询通道序列设置,禁用/使能相应的通道
acmpPollingConfig.hallOutEn = DISABLE;
ACMP_PollingModeInit(ACMP_CHANNEL0, &acmpPollingConfig);
}
多了轮询的结构第参数配置:
正输入通道轮询模式使能;负输入通道轮询模式关闭;轮询分频值(就是几个通道之间切换的频率);轮询通道序列设置,禁用7通道;HALL输出禁止。
还有读取ACMP0数据寄存器DR相应位的数值时,所处位置不同要移不同的位数。
/**
* ACMP_Callback
*
* @param[in] none
* @return none
*
* @brief ACMP0中断回调函数,读出数据输出,并翻转PB10端口
*/
uint8_t ACMPData =0;
void ACMP_CallBack(void)
{
if(ACMP_GetFlag(ACMP_CHANNEL0, ACMP0_OUTPUT_FLAG )!=0) //轮询模式通道0中断标志
{
ACMP_ClrFlag(ACMP_CHANNEL0, ACMP0_OUTPUT_FLAG);//清中断标志
}
if(ACMP_GetFlag(ACMP_CHANNEL0, ACMP0_POLLING_OUTPUT_CHANNEL0_FLAG )!=0) //轮询模式通道0中断标志
{
ACMP_ClrFlag(ACMP_CHANNEL0, ACMP0_POLLING_OUTPUT_CHANNEL0_FLAG);//清中断标志
ACMPData = (ACMP_GetOutputValue(ACMP_CHANNEL0, ACMP0_POLLING_OUTPUT_CHANNEL0_FLAG))>>0;//读出ACMP0正常模式的输出值,正输入大于负输入,输出1,正输入小于负输入,输出1
printf("data is %d\n",ACMPData );
GPIO_SetPinValue(GPIO_PB10, ACMPData);//修改PB10输出电平
}
else if(ACMP_GetFlag(ACMP_CHANNEL0, ACMP0_POLLING_OUTPUT_CHANNEL1_FLAG )!=0) //轮询模式通道1中断标志
{
ACMP_ClrFlag(ACMP_CHANNEL0, ACMP0_POLLING_OUTPUT_CHANNEL1_FLAG);//清中断标志
ACMPData = (ACMP_GetOutputValue(ACMP_CHANNEL0, ACMP0_POLLING_OUTPUT_CHANNEL1_FLAG))>>1;//读出ACMP0正常模式的输出值,正输入大于负输入,输出1,正输入小于负输入,输出1
printf("data is %d\n",ACMPData );
GPIO_SetPinValue(GPIO_PB10, ACMPData);//修改PB10输出电平
}
else if(ACMP_GetFlag(ACMP_CHANNEL0, ACMP0_POLLING_OUTPUT_CHANNEL2_FLAG )!=0) //轮询模式通道2中断标志
{
ACMP_ClrFlag(ACMP_CHANNEL0, ACMP0_POLLING_OUTPUT_CHANNEL2_FLAG);//清中断标志
ACMPData = (ACMP_GetOutputValue(ACMP_CHANNEL0, ACMP0_POLLING_OUTPUT_CHANNEL2_FLAG))>>2;//读出ACMP0正常模式的输出值,正输入大于负输入,输出1,正输入小于负输入,输出1
printf("data is %d\n",ACMPData );
GPIO_SetPinValue(GPIO_PB10, ACMPData);//修改PB10输出电平
}
else
{}
}