打印
[应用相关]

STM32L0 12Bit ADC(硬件)过采样得到16Bit ADC数据

[复制链接]
5795|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一灯大神|  楼主 | 2017-4-18 09:19 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
过采样可以帮助避免混叠,提高分辨率以及降低噪声.理论来说,频率足够高的话,就可以获得无限位精度.根据一大堆高深理论得知..这么一条公式.反正我不懂.
通俗说,1次采样是12Bit,4次是13Bit,16次是14Bit,64次是15Bit,256次是16Bit,如果要更高精度,那么STM32的硬件过采样就无能为力了.比如说要得到20Bit的话,就要65536次,这样就算在1.14Msps下,也只能17次一秒,16777216次就可以到24Bit了,所以理论上可以无限精度,但是呢,时间嘛,十几秒一次采样率,不然的话你叫ADC0832能狂秒128Bit ADC了.
关于硬件过采样,关键的就两个.
一个是移位,一个是采样次数倍数.如果要获得16Bit的ADC,那么最高才4.5Ksps,最低 5sps.
现在试试16Bit.
这里换算用的是65535为满量程.就算SMPR为1.5Cycle.也是获得不错的精度,可惜的是只有4.5Ksps.
如果用最慢速度,用16Bit的过采样方式,那么精度359sps,这时候采样电压已经完全不变化了,只有采样的AD数值有点改变,提升了位数,也提升了精度.
如果都移位到12Bit呢?完全不跳了啊.注意看着啊,现在是Run Mode的哦.
测试代码:
#include "stm32l0xx.h"__IO uint32_t uwTick;void SysTick_Delay(__IO uint32_t Delay){uint32_t tickstart = 0U;tickstart = uwTick;while((uwTick - tickstart) < Delay){}}void RCC_Init(void){/* LSE OFF,LSI DEFAULT,MSI OFF,HSI ON,PLL ON,SYSCLK = 32MHz,CK_PWR = FCLK = HCLK = SysTick = APB1 = APB2 = 32MHz.*/FLASH->ACR = FLASH_ACR_PRE_READ | FLASH_ACR_PRFTEN;MODIFY_REG(PWR->CR, PWR_CR_VOS, (PWR_CR_VOS_0));MODIFY_REG(RCC->CR, RCC_CR_HSION | RCC_CR_HSIDIVEN , RCC_CR_HSION);while(READ_BIT(RCC->CR, RCC_CR_HSIRDY) == RESET);MODIFY_REG(RCC->ICSCR, RCC_ICSCR_HSITRIM, (uint32_t)(16) << 8U);CLEAR_BIT(RCC->CR, RCC_CR_PLLON);while(READ_BIT(RCC->CR, RCC_CR_PLLRDY) != RESET);MODIFY_REG(RCC->CFGR, RCC_CFGR_PLLMUL | RCC_CFGR_PLLDIV | RCC_CFGR_PLLSRC, (uint32_t)((RCC_CFGR_PLLMUL4) | (RCC_CFGR_PLLDIV2) | (RCC_CFGR_PLLSRC_HSI)));SET_BIT(RCC->CR, RCC_CR_PLLON);while(READ_BIT(RCC->CR, RCC_CR_PLLRDY) == RESET);MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, (uint32_t)(0x01U));MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_CFGR_HPRE_DIV1);MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_PLL);while ((uint32_t)(RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_CFGR_PPRE1_DIV1);MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, ((RCC_CFGR_PPRE1_DIV1) << 3));CLEAR_BIT(RCC->CR, RCC_CR_MSION);/* SysTick CLK = 4MHz,Reload = 1kHz. */SysTick->LOAD  = (uint32_t)0x00000F9FUL;NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);SysTick->VAL   = 0UL;SysTick->CTRL  = SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;/* SysTick->CTRL  = SysTick_CTRL_TICKINT_Msk; */}uint16_t ADC_GetVDD_Voltage(void){static uint16_t vref_vol = 0;uint16_t vdd_vol = 0;/* 第一次数值,一旦VREF电压计算后,就不会为0. */if(vref_vol == 0){/* 初始化时钟 */SET_BIT(RCC->APB2ENR, (RCC_APB2ENR_ADC1EN));/* 初始化相关寄存器 */ADC1->CFGR1 = 0x00000000;ADC1->CFGR2 = 0x4000009D; /* 16Bit 过采样,以 16Bit 表示. */ADC->CCR = 0x00400000;ADC1->SMPR = 0x00000007;         /* 采样时间寄存器,0 = 1.14Msps,1 = 1Msps,2 = 800Ksps,3 = 640Ksps,4 = 500Ksps,5 = 308Ksps,6 = 174Ksps,7 = 92ksps, @ 16MHz */ADC1->CHSELR = 0x00020000;/* 采样时间和结果区别:0 = 3625mV 1 = 3302mV 2 = 3190mV 3 = 3244mV 4 = 3317mV 5 = 3302mV 6 = 3302mV 7 = 3302mV *//* 校准ADC */SET_BIT(ADC1->CR, ADC_CR_ADCAL);while(READ_BIT(ADC1->CR, ADC_CR_ADCAL));/* 计算内部Vref电压(mV) */vref_vol =  3000.0 * (*(uint16_t *)0x1FF80078) / 4095;}/* 转换当前ADC并计算当前VDD电压 */SET_BIT(ADC1->CR, ADC_CR_ADEN | ADC_CR_ADSTART | ADC_CR_ADVREGEN);/* 等待转换完成 */while(READ_BIT(ADC1->ISR, ADC_ISR_EOC));/* 倒推VDD电压 */vdd_vol = vref_vol / ((float)(ADC1->DR) / 65535);/* 关闭ADC节能 */CLEAR_BIT(ADC1->CR, ADC_CR_ADEN | ADC_CR_ADSTART | ADC_CR_ADVREGEN);return vdd_vol;}uint16_t vdd_mv;int main(void){RCC_Init();while (1){vdd_mv = ADC_GetVDD_Voltage();SysTick_Delay(10);}}
沙发
Ketose| | 2017-4-18 09:46 | 只看该作者
学习,学习。。。
终于明白过采样是做什么用的。。。

使用特权

评论回复
板凳
Ketose| | 2017-4-18 09:56 | 只看该作者
楼主的代码看着让人揪心啊。。。

使用特权

评论回复
地板
mmuuss586| | 2017-4-18 12:46 | 只看该作者

使用特权

评论回复
5
Liang118038| | 2017-4-20 17:03 | 只看该作者
其实过采样不仅仅是降低速率,对于量程下端还会有盲区(或者死区),因为ADC的硬件分辨率是定死了的在0到|1之间所采集到的数据永远是0,不管你采样上百次上万次还是0

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

65

主题

112

帖子

2

粉丝