复旦微FM33LC046N评测+ADC采集报警
[复制链接]
本帖最后由 逆夏的流年 于 2021-3-11 17:11 编辑
一、ADC概述
FM33LC0XX 带有 1Msps 12bit SAR-ADC,可实现温度、电池电压或其他直流信号的测量功能。 主要特点为:
1、工作电压 1.8~5.5V
2、输入信号幅度 0~VDDA
3、最高采样率 1Msps(FADC=16Mhz)
4、16 个单端输入通道,包含温度传感器、内部基准电压、运放输出 x2、 12 个外部通道
5、8 个外部快速通道, 8 个低速通道
6、可配置的采样保持时间
7、支持单次转换和连续转换
8、支持 DMA
9、支持过采样硬件平均,最高 16bit 输出(256 次平均)
二、结构框图
三、输入通道
四、功能描述之采样值与实际电压的转换
ADC一般使用电源电压作为基准电压,在电源电压发生变化时,特定输入信号电平对应的转换值也会发送变化,为了能够得到准确的绝对电压,文档中接收的解决方案如下:
芯片出厂时在Vdd=3V的情况下,测量VREFINT的电压并保存在Flash中
1、以上条件下,使用ADC转换VREFINT输出,得到转换值VREFINT_CAL并保存在芯片中;
2、芯片实际应用中,由于不知道当前VDDA电压,ADC先测量VREFINT得到转换值VREFINT_DATA;通过以下公式可以得到当前实际的VDDA;
假设ADC对某个输入通道的采样值为ADC_DATA,通过以下公式可以得到当前某个输入通道的实际电压(12bit 输出)
采用这个方式,不需要知道每颗芯片VREFINT的实际电压值,仅需计算当前VREFINT采样值和出厂测试值的比例;
VREF1p2 采样的软件配置方法
1、软件使用 ADC 采样 VREF1p2 时,需要按照以下步骤:
2、置位 VREF_EN 寄存器,使能 VREF1p2 模块
3、置位 BUFFERCTRL.VREFBUFFER_EN,使能 VREF 输出 BUFFER
4、等待 VREF 建立,通过查询 VREF_RDY 寄存器,或通过 VREF_IF 中断
5、使能 ADC 的 REFCH 通道
6、使能 ADC 开始转换
五、软件实现步骤
1、ADC初始化
void MF_ADC_Init(void)
{
FL_GPIO_InitTypeDef GPIO_InitStruct;
FL_ADC_InitTypeDef defaultInitStruct;
GPIO_InitStruct.pin = FL_GPIO_PIN_9;
GPIO_InitStruct.mode = FL_GPIO_MODE_ANALOG;
GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.pull = DISABLE;
GPIO_InitStruct.remapPin = DISABLE;
FL_GPIO_Init( GPIOC, &GPIO_InitStruct );
defaultInitStruct.conversionMode = FL_ADC_CONV_MODE_SINGLE;
defaultInitStruct.autoMode = FL_ADC_SINGLE_CONV_MODE_AUTO;
defaultInitStruct.waitMode = ENABLE;
defaultInitStruct.overrunMode = ENABLE;
defaultInitStruct.scanDirection = FL_ADC_SEQ_SCAN_DIR_BACKWARD;
defaultInitStruct.externalTrigConv = FL_ADC_TRIGGER_EDGE_NONE;
defaultInitStruct.triggerSource = FL_ADC_TRGI_PA8;
defaultInitStruct.fastChannelTime = FL_ADC_FAST_CH_SAMPLING_TIME_4_ADCCLK;
defaultInitStruct.lowChannelTime = FL_ADC_SLOW_CH_SAMPLING_TIME_192_ADCCLK;
defaultInitStruct.oversamplingMode = ENABLE;
defaultInitStruct.overSampingMultiplier = FL_ADC_OVERSAMPLING_MUL_16X;
defaultInitStruct.oversamplingShift = FL_ADC_OVERSAMPLING_SHIFT_4B;
FL_ADC_Init(ADC,&defaultInitStruct );
}
void MF_ADC_Common_Init(void)
{
FL_ADC_CommonInitTypeDef CommonInitStruct;
CommonInitStruct.clockSource = FL_RCC_ADC_CLK_SOURCE_RCHF;
CommonInitStruct.clockPrescaler = FL_RCC_ADC_PSC_DIV8;
FL_ADC_CommonInit(&CommonInitStruct );
FL_ADC_EnableIT_EndOfConversion(ADC );
}
void MF_NVIC_Init(void)
{
InterruptConfigStruct.preemptPriority = 1;
NVIC_Init(&InterruptConfigStruct,ADC_IRQn );
}
2、ADC转换函数
#define ADC_VREF (*((uint16_t *)(0x1FFFFB08)))
static uint32_t GetVREF1P2Sample_IT(void)
{
uint16_t ADCRdresult;
uint8_t i=0;
FL_RCC_SetADCPrescaler(FL_RCC_ADC_PSC_DIV8);
FL_VREF_EnableVREFBuffer(VREF);
FL_ADC_EnableSequencerChannel(ADC, FL_ADC_INTERNAL_VREF1P2);
FL_ADC_ClearFlag_EndOfConversion(ADC);
FL_ADC_Enable(ADC);
FL_ADC_EnableSWConversion(ADC);
while (ADCComplete == 0)
{
if(i>=5)
{
break;
}
i++;
DelayMs(1);
}
ADCComplete = 0;
FL_ADC_ClearFlag_EndOfConversion(ADC);
ADCRdresult =FL_ADC_ReadConversionData(ADC);
FL_ADC_Disable(ADC);
FL_ADC_DisableSequencerChannel(ADC, FL_ADC_INTERNAL_VREF1P2);
FL_VREF_DisableVREFBuffer(VREF);
return ADCRdresult;
}
static uint32_t GetSingleChannelSample_IT(uint32_t channel)
{
uint16_t ADCRdresult;
uint8_t i=0;
FL_RCC_SetADCPrescaler(FL_RCC_ADC_PSC_DIV1);
FL_ADC_EnableSequencerChannel(ADC, channel);
FL_ADC_ClearFlag_EndOfConversion(ADC);
FL_ADC_Enable(ADC);
FL_ADC_EnableSWConversion(ADC);
while (ADCComplete == 0)
{
if(i>=5)
{
break;
}
i++;
DelayMs(1);
}
ADCComplete = 0;
FL_ADC_ClearFlag_EndOfConversion(ADC);
ADCRdresult =FL_ADC_ReadConversionData(ADC);
FL_ADC_Disable(ADC);
FL_ADC_DisableSequencerChannel(ADC, channel);
return ADCRdresult;
}
uint32_t GetSingleChannelVoltage_IT(uint32_t channel)
{
uint32_t Get122VSample,GetChannelVoltage;
uint64_t GetVSample;
Get122VSample = GetVREF1P2Sample_IT();
GetVSample =GetSingleChannelSample_IT(channel);
GetChannelVoltage = (GetVSample *3000*(ADC_VREF))/(Get122VSample*4095);
return GetChannelVoltage;
}
3、数据采集报警处理
GetVoltage = GetSingleChannelVoltage_IT(FL_ADC_EXTERNAL_CH0 );
if(uc_secondflag==1)
{
uc_secondflag=0;
if(GetVoltage>0xA00)
{
printf("警告:AD值大于0xA00=2560 当前AD值 = %x\n",GetVoltage);
FL_GPIO_ResetOutputPin(GPIOC,FL_GPIO_PIN_0);
}
else
{
printf("PC9 ADC =%x\n",GetVoltage);
FL_GPIO_SetOutputPin(GPIOC,FL_GPIO_PIN_0);
}
}
|