|
我們經(jīng)常會(huì)使用STM32 ADC功能測(cè)試外部電壓,在一些精度不高的場(chǎng)合,我們一般就用3.3V作為參考電壓來計(jì)算測(cè)到的電壓值。不過,這種情況很少見,可能只有單片機(jī)學(xué)習(xí)板才會(huì)這樣使用。因?yàn)槲覀兪褂玫?.3V穩(wěn)壓芯片,很少有標(biāo)準(zhǔn)的3.300V輸出,有可能是3.270V,也可能是3.345V,而且,還存在個(gè)體差異,這個(gè)板子上的電壓是3.294V,另外一個(gè)板子上面,就可能是3.312V。如果我們都用3.300來計(jì)算的話,同樣的電壓,測(cè)出來的結(jié)果就會(huì)存在mV級(jí)別的差異。
在實(shí)際使用中,我們一般使用外部基準(zhǔn)電壓芯片,例如,100腳的STM32一般都有VREF引腳,就是用來接外部基準(zhǔn)電壓芯片,例如REF3133,輸出的電壓是標(biāo)準(zhǔn)的3.300V。
為什么不用基準(zhǔn)電壓芯片作為電源供電芯片?
因?yàn)榛鶞?zhǔn)電壓芯片的輸出電流都是小于25mA的,對(duì)于一般的電路板應(yīng)用,這么點(diǎn)輸出電流不足以讓電路板工作。
不同的STM32 如何使用基準(zhǔn)電壓芯片?
對(duì)于100腳及其以上的芯片,把基準(zhǔn)電壓芯片連接到VREF芯片即可。
對(duì)于100腳以下的芯片,STM32沒有把VREF引腳引出來,所以,我們只能把基準(zhǔn)電壓芯片連接到VDDA引腳。注意,STM32單片機(jī)上面有好多電源引腳,其中有若干VDD引腳,只有一個(gè)VDDA引腳,VDDA引腳就是模擬供電引腳。不過,需要注意,VDDA的電壓不是隨便定義的。例如,STM32F051系列單片機(jī)就規(guī)定,VDDA必須要大于或者等于VDD才可以正常工作,所以這時(shí)候,最好是給單片機(jī)3.0V供電,再給VDDA采用一個(gè)3.3V的基準(zhǔn)電壓芯片供電。
0.png (27.59 KB, 下載次數(shù): 204)
下載附件
2015-11-10 15:03 上傳
不用電壓基準(zhǔn)電壓芯片可以嗎?
如果在你的應(yīng)用中,VDDA引腳和VDD引腳連在一起,都是由電源芯片供電,這時(shí)候,如果你能知道VDDA的實(shí)際電壓,也可以得到精確的ADC結(jié)果。例如,你可以用萬用表測(cè)到VDDA電壓,例如,是3.286V,你就可以使用3286來計(jì)算。不過,這也只能是在實(shí)驗(yàn)的時(shí)候,在實(shí)際使用中,如果你做了1萬個(gè)板子,然后需要用萬用表量1萬個(gè)板子的電源電壓,然后再給每個(gè)板子修改程序,顯示是不可能的。
所以,STM32給我們又一個(gè)解決方案,STM32在內(nèi)部都有一個(gè)參考電壓引腳,可以通過配置,把這個(gè)腳連接到ADC輸入引腳,是內(nèi)部連接。然后再計(jì)算實(shí)際的VDDA值。不過,STM32也存在個(gè)體差異,所以,它并沒有在手冊(cè)上給出我們這個(gè)參考電壓是多大。而是用出廠時(shí)調(diào)教好的校準(zhǔn)值和得到的參考電壓值一起使用。如下圖:
1.png (48.18 KB, 下載次數(shù): 192)
下載附件
2015-11-10 15:03 上傳
VREFINT_CAL是校準(zhǔn)值,這個(gè)值,每個(gè)單片機(jī)都不一樣,被存儲(chǔ)到了0X1FFFF7BA和0X1FFFF7BB,使用的時(shí)候,需要先讀出來。
說多了都是眼淚,不說了,給你個(gè)程序看吧,程序當(dāng)中,有讀取VREFINT_CAL和VREFINT_DATA值的語句。你可以看個(gè)究竟。這個(gè)程序已經(jīng)實(shí)踐驗(yàn)證過了,不會(huì)有問題,下面是實(shí)驗(yàn)結(jié)果:
2.png (10.74 KB, 下載次數(shù): 188)
下載附件
2015-11-10 15:03 上傳
我把測(cè)到的VDDA值,發(fā)送到了串口查看。然后我用萬用表測(cè)了一下實(shí)際的VDDA值,由于我的萬用表精度有限,只能測(cè)到小數(shù)點(diǎn)后2位數(shù)字,萬用表得到的是3.32V和3.31V之間跳動(dòng)。串口發(fā)送的值,小數(shù)點(diǎn)后第三位四舍五入之后,結(jié)果也是3.32V和3.31V。結(jié)果是一致的。說明這種方法也是可取的。
點(diǎn)擊下載源程序:
stm32f051計(jì)算VDDA測(cè)試程序.7z
(781.2 KB, 下載次數(shù): 360)
2020-4-8 22:23 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
(程序使用KEIL 5)
- /****************************************************/
- // 程序用途:用來測(cè)試通過內(nèi)部基準(zhǔn)電壓計(jì)算外部VDDA的值
- // 程序作者:孟瑞生
- // 微信公眾號(hào):科技老頑童
- /****************************************************/
- #include "stm32f0xx.h"
- #include "stdio.h"
- __IO uint16_t VREFINT_CAL;
- __IO uint16_t VREFINT_DATA;
- __IO float VDDA_VAL;
- // 下面三個(gè)延時(shí)函數(shù),是用示波器試出來的,非精確延時(shí)(48MHz)
- void delay_1us(void)
- {
- volatile uint16_t i=1;
-
- while(i--);
- }
- void delay_us(uint16_t us)
- {
- while(us--)
- {
- delay_1us();
- }
- }
- void delay_ms(uint16_t ms)
- {
- while(ms--)
- {
- delay_us(995);
- }
- }
- /**
- * @brief ADC Configuration
- * @param None
- * @retval None
- */
- static void ADC_Config(void)
- {
- ADC_InitTypeDef ADC_InitStructure;
- GPIO_InitTypeDef GPIO_InitStructure;
-
- /* GPIOC Periph clock enable */
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
-
- /* ADC1 Periph clock enable */
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
-
- /* Configure ADC Channel 0 as analog input */
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
-
- /* ADCs DeInit */
- ADC_DeInit(ADC1);
-
- /* Initialize ADC structure */
- ADC_StructInit(&ADC_InitStructure);
- ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
- ADC_Init(ADC1, &ADC_InitStructure);
-
- /* Convert the ADC1 Channel 0 with 239.5 Cycles as sampling time */
- ADC_ChannelConfig(ADC1, ADC_Channel_Vrefint , ADC_SampleTime_239_5Cycles);
- ADC_VrefintCmd(ENABLE);
-
- /* 得到基準(zhǔn)電壓校準(zhǔn)值 */
- VREFINT_CAL = *(__IO uint16_t *)(0X1FFFF7BA);
-
- /* ADC Calibration */
- ADC_GetCalibrationFactor(ADC1);
-
- /* Enable the ADC peripheral */
- ADC_Cmd(ADC1, ENABLE);
-
- /* Wait the ADRDY flag */
- while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY));
-
- /* ADC1 regular Software Start Conv */
- ADC_StartOfConversion(ADC1);
- }
- /**
- * @brief UART1 Configuration
- * @param None
- * @retval None
- */
- void UART1_Init()
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
- USART_InitTypeDef USART_InitStructure;
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
- /* Enable USART1 Clock */
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
-
- /* USART1 Pins configuration ************************************************/
- /* Connect pin to Periph */
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
- GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
-
- /* Configure pins as AF pushpull */
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- /* USART1 IRQ Channel configuration */
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPriority = 0x01;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
-
- /* USART1 configured as follow:
- - BaudRate = 9600 baud
- - Word Length = 8 Bits
- - One Stop Bit
- - No parity
- - Hardware flow control disabled (RTS and CTS signals)
- - Receive and transmit enabled
- */
- USART_InitStructure.USART_BaudRate = 115200;
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;
- USART_InitStructure.USART_StopBits = USART_StopBits_1;
- USART_InitStructure.USART_Parity = USART_Parity_No;
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
- USART_Init(USART1, &USART_InitStructure);
-
- /* Enable the USART1 */
- USART_Cmd(USART1, ENABLE);
- }
- int fputc(int ch, FILE *f)
- {
- /* Place your implementation of fputc here */
- /* e.g. write a character to the USART */
- USART_SendData(USART1, (uint8_t) ch);
- /* Loop until transmit data register is empty */
- while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
- return ch;
- }
- // 主函數(shù)
- int main(void)
- {
- delay_ms(200);
- ADC_Config();
- UART1_Init();
-
- while(1)
- {
- VREFINT_DATA =ADC_GetConversionValue(ADC1);
- VDDA_VAL = (3.3*VREFINT_CAL)/VREFINT_DATA;
- printf("\n\rVDDA:%.3fV\n\r",VDDA_VAL);
- while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
- delay_ms(1000);
- }
- }
復(fù)制代碼
|
評(píng)分
-
查看全部評(píng)分
|