今天给大家带来的是模数转换器(ADC)资源验证。首先让我简要的介绍一下航芯这块开发板上板载的ADC资源。(下面的数据来自于航芯ACM32G103_datasheet.pdf)
航芯这块ACM32G103开发板具有两个ADC外设,分别是ADC1和ADC2,这两个ADC 支持 2 路 12 位 3Msps 采样率。 同时内部集成了转换电路可以实现内嵌温度传感器实现温度检测。
ADC 主要特性如下:
— 内建 BGR 连接到 ADC1
— 温度传感器连接到 ADC1
— VBAT 连接到 ADC1
— The OPA1/2 内部输出连接到 ADC1 输入通道
— The OPA2/3 内部输出连接到 ADC2 输入通道
那么如何来使用这块开发板上的ADC功能呢? 首先我们需要确定的是ADC1或者ADC2的板载PIN, 其次确认ADC被挂载到了系统的哪一个总线上.
确认ADC_PIN
打开航芯ACM32G103_Datasheet_V1.5.pdf(page34),RCT6采用的是LQFP64的封装。
在明确封装之后,查看数据手册中的引脚概述, 我们找到如下ADC功能PIN, PA1是ADC的输入通道1
那么ADC是挂载在哪一个外设总线下的呢?根据功能框图得知, ADC是被挂载到APB bridg2 上的。所以我们可以像上一个帖子一样来初始化ADC的时钟。
众所周知, hal_rcc.h 这个库是负责板载上时钟的控制的,我们可以在1023行找到这个宏定义__HAL_RCC_ADC12_CLK_ENABLE() 我们可以调用这个方法来初始化ADC的时钟
但是其实上述的时钟并不需要我们自己手动初始化,我们只需要配置好对应的ADC_ChannelConfTypeDef, 在调用对应的HAL初始化方法的时候,库会自动为我们初始化时钟(下面代码参考的来源于官方demo)
初始化ADC,并且通道选择通道一即PA1, 我这里移除了其他多余的通道。
void ADC_Init_Polling_Nchannels(void)
{
ADC_ChannelConfTypeDef ADC_ChannelConf;
ADC_Handle.Init.ClockPrescaler = ADC_CLOCK_DIV16; //ADC_CLK分频选择
ADC_Handle.Init.Resolution = ADC_RESOLUTION_12B; //分辨率
ADC_Handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; //数据对齐
ADC_Handle.Init.ConConvMode = DISABLE; //连续转换模式
ADC_Handle.Init.DiscontinuousConvMode = DISABLE; //间断模式
ADC_Handle.Init.NbrOfDiscConversion =1; //间断模式通道计数
ADC_Handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; //触发模式:外部触发或软件触发
ADC_Handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;//外部触发边沿选择
ADC_Handle.Init.DMAMode = ADC_DMAMODE_DISABLE; //DMA选择
ADC_Handle.Init.OverMode = ADC_OVERMODE_DISABLE; //溢出时是否保留上次采样数据
ADC_Handle.Init.OverSampMode = ADC_OVERSAMPMODE_DISABLE;//过采样使能
ADC_Handle.Init.Oversampling.Ratio =ADC_OVERSAMPLING_RATIO_2;//过采样率
ADC_Handle.Init.Oversampling.RightBitShift =ADC_RIGHTBITSHIFT_2;//过采样移位系数
ADC_Handle.Init.Oversampling.TriggeredMode =0; //过采样触发模式
ADC_Handle.Init.AnalogWDGEn = ADC_ANALOGWDGEN_DISABLE; //模拟看门狗
ADC_Handle.Init.ChannelEn = ADC_CHANNEL_1_EN;
ADC_Handle.Instance = ADC1; //ADC2
HAL_ADC_Init(&ADC_Handle);
/* The total adc regular channels number */
ADC_Handle.ChannelNum = 1;
ADC_ChannelConf.Channel = ADC_CHANNEL_1;
ADC_ChannelConf.Sq = ADC_SEQUENCE_SQ1;
ADC_ChannelConf.Smp = ADC_SMP_CLOCK_320;
ADC_ChannelConf.SingleDiff = ADC_SINGLE_ENDED;
ADC_ChannelConf.OffsetNumber = ADC_OFFSET_NONE;
ADC_ChannelConf.Offset = 0;
HAL_ADC_ConfigChannel(&ADC_Handle,&ADC_ChannelConf);
}
获取参考电压:
uint32_t ADC_GetVrefP(void)
{
ADC_HandleTypeDef ADC_Handle_Vrefp;
ADC_ChannelConfTypeDef ADC_ChannelConf;
uint32_t TrimValue_3v, AdcValue_VrefP[1], VrefP,temp;
//PMU CLK Enable
RCC->APB1ENR |= 1<<27;
//VBG1P2
*(__IO uint32_t*)(0x400070C0) = 0x05;
HAL_SimpleDelay(2000);
ADC_Handle_Vrefp.Init.ClockPrescaler = ADC_CLOCK_DIV16; //ADC_CLK分频选择
ADC_Handle_Vrefp.Init.Resolution = ADC_RESOLUTION_12B; //分辨率
ADC_Handle_Vrefp.Init.DataAlign = ADC_DATAALIGN_RIGHT; //数据对齐
ADC_Handle_Vrefp.Init.ConConvMode = DISABLE; //连续转换模式
ADC_Handle_Vrefp.Init.DiscontinuousConvMode = DISABLE; //间断模式
ADC_Handle_Vrefp.Init.NbrOfDiscConversion = 1; //间断模式通道计数
ADC_Handle_Vrefp.Init.ExternalTrigConv = ADC_SOFTWARE_START; //触发模式:外部触发或软件触发
ADC_Handle_Vrefp.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;//外部触发边沿选择
ADC_Handle_Vrefp.Init.DMAMode = ADC_DMAMODE_DISABLE; //DMA选择
ADC_Handle_Vrefp.Init.OverMode = ADC_OVERMODE_DISABLE; //溢出时是否保留上次采样数据
ADC_Handle_Vrefp.Init.OverSampMode = ADC_OVERSAMPMODE_DISABLE;//过采样使能设置
ADC_Handle_Vrefp.Init.Oversampling.Ratio =ADC_OVERSAMPLING_RATIO_2;//过采样率
ADC_Handle_Vrefp.Init.Oversampling.RightBitShift =ADC_RIGHTBITSHIFT_2;//过采样移位系数
ADC_Handle_Vrefp.Init.Oversampling.TriggeredMode =0; //过采样触发模式
ADC_Handle_Vrefp.Init.AnalogWDGEn = ADC_ANALOGWDGEN_DISABLE; //模拟看门狗
ADC_Handle_Vrefp.Init.ChannelEn = ADC_CHANNEL_VBGR_EN;
ADC_Handle_Vrefp.Instance = ADC1;
HAL_ADC_Init(&ADC_Handle_Vrefp);
/* The total adc regular channels number */
ADC_Handle_Vrefp.ChannelNum = 1;
/* Add adc channels */
ADC_ChannelConf.Channel = ADC_CHANNEL_VBGR;
ADC_ChannelConf.Sq = ADC_SEQUENCE_SQ1;
ADC_ChannelConf.Smp = ADC_SMP_CLOCK_320;
ADC_ChannelConf.SingleDiff = ADC_SINGLE_ENDED;
ADC_ChannelConf.OffsetNumber = ADC_OFFSET_NONE;
ADC_ChannelConf.Offset = 0;
HAL_ADC_ConfigChannel(&ADC_Handle_Vrefp,&ADC_ChannelConf);
HAL_ADC_Polling(&ADC_Handle_Vrefp, AdcValue_VrefP, ADC_Handle_Vrefp.ChannelNum, 0);
printfS("The adc convert result : 0x%08x[ %d ], VBGR = %dmV\r\n", AdcValue_VrefP[0], AdcValue_VrefP[0] & 0xFFF, ((AdcValue_VrefP[0] & 0xFFF) * 3300 / 4095));
//VBG1P2
*(__IO uint32_t*)(0x400070C0) &= ~0x05;
TrimValue_3v = *(volatile uint32_t*)(0x00080240); //Read the 1.2v trim value in 3.0v vrefp.
printfS("The adc 1.2v trim value is : 0x%08x \r\n", TrimValue_3v);
if(((~TrimValue_3v&0xFFFF0000)>>16) == (TrimValue_3v&0x0000FFFF))
{
temp = TrimValue_3v & 0xFFF;
VrefP = (uint32_t)(temp * 3000 / (AdcValue_VrefP[0] & 0xFFF));
return VrefP;
}
return 0;
}
从DAC buffer中获取转换后的电压
void ADC_Test_Polling_Nchannels(void)
{
uint32_t i, VrefP, Voltage;
uint32_t lu32_COM_OK = 0;
printfS("The ADC test ADC_Test_Polling_Nchannels start.");
VrefP = ADC_GetVrefP();
printfS("The VrefP value is : %d \r\n", VrefP);
ADC_Init_Polling_Nchannels();
while(1)
{
for (i = 0; i < BUFFER_LENGTH; i++)
{
gadcBuffer[i] = 0;
}
HAL_ADC_Polling(&ADC_Handle, gadcBuffer, ADC_Handle.ChannelNum, 0);
for (i = 0; i < ADC_Handle.ChannelNum; i++)
{
printfS("The adc convert result : Channel %d = %d\r\n", gadcBuffer[i]>>16 & 0xFF,gadcBuffer[i]&0xFFF);
Voltage = (gadcBuffer[i]&0xFFF)*VrefP/4095;
printfS("The Voltage is: %d mV \r\n", Voltage);
}
HAL_DelayMs(1000);
}
}
我这里直接用杜邦线将PA1连接到了板载的3v3,如下为串口的转换结果输出
上述代码可以在官方提供的demo中的dac_polling 中找到。原本打算自己写这个dac的代码的,但是结构体内的一些定义自己搞不明白。所以无奈只好借鉴了官方的demo,少做修改便完成了这次测试。
杂牌万用表的测试结果:
本帖最后由 御坂10032号 于 2024-1-2 23:14 编辑
楼主大佬,我跑例程是可以,移植到任务系统里面就不行,什么时候帮我看看怎么回事。
引用: lugl4313820 发表于 2024-1-3 20:29 楼主大佬,我跑例程是可以,移植到任务系统里面就不行,什么时候帮我看看怎么回事。
我没那么厉害,我建议你可以示波器看看输出