找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 35377|回復(fù): 13
收起左側(cè)

STM32 ADC電壓采集代碼與原理講解

  [復(fù)制鏈接]
ID:330311 發(fā)表于 2018-12-2 00:36 | 顯示全部樓層 |閱讀模式
秉火的STM32 ADC電壓采集的資料:
0.png

0.png

電壓輸入范圍
輸入電壓:VREF- ≤ VIN ≤ VREF+
決定輸入電壓的引腳:VREF-、 VREF+ 、 VDDA 、 VSSA
VSSA 和 VREF-接地,把 VREF+和 VDDA 接 3V3,
得到ADC 的輸入電壓范圍為: 0~3.3V。

超出0~3.3V的電壓怎么測?

ADC可以測量:-10V~10V  
0.png

根據(jù)基爾霍夫定律(KCL),節(jié)點(diǎn)流入的電流等于流出的電流
(Vint – Vout)/R2 + (3V3-Vout)/R1 = Vout / R3
Vout = (Vint + 10) /6  

R1 / R2 / R3 的值怎么確定?

每個(gè)ADC具有18個(gè)通道,其中外部通道16個(gè)
0.png

每個(gè)ADC具有18個(gè)通道,其中外部通道16個(gè)
0.png

外部的 16 個(gè)通道在轉(zhuǎn)換的時(shí)候又分為規(guī)則通道和注入通道,其中規(guī)則通道最多有 16路,注入通道最多有 4 路。那這兩個(gè)通道有什么區(qū)別?在什么時(shí)候使用?

規(guī)則通道:顧名思意,規(guī)則通道就是很規(guī)矩的意思,我們平時(shí)一般使用的就是這個(gè)通道。
注入通道:注入,可以理解為插入,插隊(duì)的意思,是一種不安分的通道。它是一種在規(guī)則通道轉(zhuǎn)換的時(shí)候強(qiáng)行插入要轉(zhuǎn)換的一種。這點(diǎn)跟中斷程序很像,都是不安分的主。所以,注入通道只有在規(guī)則通道存在時(shí)才會(huì)出現(xiàn)。

0.png

1、軟件觸發(fā):ADC_CR2 :ADON/SWST ART/JSWSTART
2、外部事件觸發(fā):內(nèi)部定時(shí)器/外部IO
選擇:ADC_CR2 :EXTSEL[2:0]和 JEXTSEL[2:0]
激活:ADC_CR2 :EXTEN 和 JEXTEN

ADC_CLK:ADC模擬電路時(shí)鐘,最大值為14M,由PCLK2提供,還可分頻,2/4/6/8,RCC_CFGR 的 ADCPRE[1:0]設(shè)置。PCLK2=72M。
轉(zhuǎn)換時(shí)間:Tconv = 采樣時(shí)間 + 12.5 個(gè)周期
數(shù)字時(shí)鐘:RCC_APB2ENR,用于訪問寄存器

采樣時(shí)間:ADC 需要若干個(gè) ADC_CLK 周期完成對輸入的模擬量迚行采樣,采樣的周期數(shù)可通過ADC 采樣時(shí)間寄存器
ADC_SMPR1 和 ADC_SMPR2 中的 SMPx[2:0]位設(shè)置,
ADC_SMPR2控制的是通道 0~9, ADC_SMPR1 控制的是通道 10~17。每個(gè)通道可以分別用不同的時(shí)間采樣。其中采樣周期最小是 1.5 個(gè),即如果我們要達(dá)到最快的采樣,那么應(yīng)該設(shè)置采樣周期為 31.5個(gè)周期,這里說的周期就是 1/ADC_CLK。

最短的轉(zhuǎn)換時(shí)間:Tconv = 采樣時(shí)間 + 12.5 個(gè)周期

PCLK2 = 72M,ADC_CLK = 72/6 = 12M
Tconv = 1.5+12.4 = 14周期 = 14/12us=1.17us

一切準(zhǔn)備就緒后, ADC 轉(zhuǎn)換后的數(shù)據(jù)根據(jù)轉(zhuǎn)換組的不同,規(guī)則組的數(shù)據(jù)放在ADC_DR 寄存器,注入組的數(shù)據(jù)放在 JDRx。

0.png

1-16位有效,用于存放獨(dú)立模式轉(zhuǎn)換完成數(shù)據(jù)
2- ADC_CR2 :ALIGN
3-只有一個(gè),多通道采集的是最好使用DMA

0.png

1-16位有效,用于存放注入通道轉(zhuǎn)換完成數(shù)據(jù)
2- ADC_CR2 :ALIGN
3-有4個(gè)這樣的寄存器

0.png

1-電壓輸入范圍為:0~3.3V
2-分辨率為12位
3-最小精度為:3.3/2^12
4-設(shè)數(shù)字量為X,則有模擬量 Y = (3.3 / 2^12)*X
怎么根據(jù)數(shù)據(jù)量算出模擬量

單片機(jī)源程序如下:
  1. /**
  2.   ******************************************************************************
  3.   * @file    main.c
  4.   * @author  fire
  5.   * @version V1.0
  6.   * @date    2013-xx-xx
  7.   * @brief   串口中斷接收測試

  8.   ******************************************************************************
  9.   */


  10. #include "stm32f10x.h"
  11. #include "bsp_usart.h"
  12. #include "bsp_adc.h"


  13. extern __IO uint16_t ADC_ConvertedValue[NOFCHANEL];

  14. // 局部變量,用于保存轉(zhuǎn)換計(jì)算后的電壓值         
  15. float ADC_ConvertedValueLocal[NOFCHANEL];        

  16. // 軟件延時(shí)
  17. void Delay(__IO uint32_t nCount)
  18. {
  19.   for(; nCount != 0; nCount--);
  20. }

  21. /**
  22.   * @brief  主函數(shù)
  23.   * @param  無
  24.   * @retval 無
  25.   */
  26. int main(void)
  27. {        
  28.   /*初始化USART 配置模式為 115200 8-N-1,中斷接收*/
  29.   USART_Config();
  30.         printf("歡迎使用秉火STM32開發(fā)板\n\n\n\n");
  31.         
  32.         ADCx_Init();

  33.         while (1)
  34.         {   
  35.                         ADC_ConvertedValueLocal[0] =(float) ADC_ConvertedValue[0]/4096*3.3;
  36.                         ADC_ConvertedValueLocal[1] =(float) ADC_ConvertedValue[1]/4096*3.3;
  37.                         ADC_ConvertedValueLocal[2] =(float) ADC_ConvertedValue[2]/4096*3.3;
  38.                         ADC_ConvertedValueLocal[3] =(float) ADC_ConvertedValue[3]/4096*3.3;
  39.                         ADC_ConvertedValueLocal[4] =(float) ADC_ConvertedValue[4]/4096*3.3;
  40.                         ADC_ConvertedValueLocal[5] =(float) ADC_ConvertedValue[5]/4096*3.3;
  41.                
  42.                         printf("\r\n CH0 value = %f V \r\n",ADC_ConvertedValueLocal[0]);
  43.                         printf("\r\n CH1 value = %f V \r\n",ADC_ConvertedValueLocal[1]);
  44.                         printf("\r\n CH2 value = %f V \r\n",ADC_ConvertedValueLocal[2]);
  45.                         printf("\r\n CH3 value = %f V \r\n",ADC_ConvertedValueLocal[3]);
  46.                         printf("\r\n CH4 value = %f V \r\n",ADC_ConvertedValueLocal[4]);
  47.                         printf("\r\n CH5 value = %f V \r\n",ADC_ConvertedValueLocal[5]);
  48.                
  49.                         printf("\r\n\r\n");
  50.                         Delay(0xffffee);                 
  51.         }
  52. }

  53. /*********************************************END OF FILE**********************/
復(fù)制代碼

  1. #include "bsp_adc.h"

  2. __IO uint16_t ADC_ConvertedValue[NOFCHANEL]={0,0,0,0,0,0};

  3. static void ADCx_GPIO_Config(void)
  4. {
  5.         GPIO_InitTypeDef GPIO_InitStructure;
  6.         
  7.         // 打開 ADC IO端口時(shí)鐘
  8.         ADC_GPIO_APBxClock_FUN ( ADC_GPIO_CLK, ENABLE );
  9.         
  10.         // 配置 ADC IO 引腳模式
  11.         GPIO_InitStructure.GPIO_Pin = ADC_PIN1;
  12.         GPIO_InitStructure.GPIO_Pin = ADC_PIN2;
  13.         GPIO_InitStructure.GPIO_Pin = ADC_PIN3;
  14.         GPIO_InitStructure.GPIO_Pin = ADC_PIN4;
  15.         GPIO_InitStructure.GPIO_Pin = ADC_PIN5;
  16.         GPIO_InitStructure.GPIO_Pin = ADC_PIN6;
  17.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  18.         
  19.         // 初始化 ADC IO
  20.         GPIO_Init(ADC_PORT, &GPIO_InitStructure);        
  21. }

  22. // ANSI C標(biāo)準(zhǔn),C89 標(biāo)準(zhǔn)
  23. // C99
  24. // C11 2011

  25. static void ADCx_Mode_Config(void)
  26. {
  27.         DMA_InitTypeDef DMA_InitStructure;
  28.         RCC_AHBPeriphClockCmd(ADC_DMA_CLK, ENABLE);

  29.         DMA_DeInit(ADC_DMA_CHANNEL);
  30.         DMA_InitStructure.DMA_PeripheralBaseAddr = ( uint32_t ) ( & ( ADC_x->DR ) );
  31.         DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue;
  32.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  33.         DMA_InitStructure.DMA_BufferSize = NOFCHANEL;    // 改
  34.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  35.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  // 改
  36.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  37.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  38.         DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;        
  39.         DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  40.         DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  41.         DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure);
  42.         DMA_Cmd(ADC_DMA_CHANNEL , ENABLE);
  43. /*----------------------------------------------------------------------*/
  44.         
  45.         ADC_InitTypeDef ADC_InitStruct;        
  46.         ADC_APBxClock_FUN ( ADC_CLK, ENABLE );
  47.         ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
  48.         ADC_InitStruct.ADC_ScanConvMode = ENABLE;        // 改
  49.         ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;        
  50.         ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  51.         ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
  52.         ADC_InitStruct.ADC_NbrOfChannel = NOFCHANEL;        
  53.         ADC_Init(ADC_x, &ADC_InitStruct);
  54.         
  55.         RCC_ADCCLKConfig(RCC_PCLK2_Div8);
  56.         
  57.         ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL1, 1, ADC_SampleTime_55Cycles5);
  58.         ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL2, 2, ADC_SampleTime_55Cycles5);
  59.         ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL3, 3, ADC_SampleTime_55Cycles5);
  60.         ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL4, 4, ADC_SampleTime_55Cycles5);
  61.         ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL5, 5, ADC_SampleTime_55Cycles5);
  62.         ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL6, 6, ADC_SampleTime_55Cycles5);

  63.          // 使能ADC DMA 請求
  64.         ADC_DMACmd(ADC_x, ENABLE);

  65.         ADC_Cmd(ADC_x, ENABLE);        
  66.   // ADC開始校準(zhǔn)
  67.         ADC_StartCalibration(ADC_x);
  68.         // 等待校準(zhǔn)完成
  69.         while(ADC_GetCalibrationStatus(ADC_x));
  70.         
  71.         ADC_SoftwareStartConvCmd(ADC_x, ENABLE);
  72. }

  73. void ADCx_Init(void)
  74. {
  75.         ADCx_GPIO_Config();
  76.         ADCx_Mode_Config();
  77. }
復(fù)制代碼

全部資料51hei下載地址:
31-ADC—電壓采集.zip (6.15 MB, 下載次數(shù): 520)


回復(fù)

使用道具 舉報(bào)

ID:524338 發(fā)表于 2019-4-29 11:56 | 顯示全部樓層
感謝樓主
回復(fù)

使用道具 舉報(bào)

ID:582442 發(fā)表于 2019-7-11 16:41 | 顯示全部樓層
感謝分享
回復(fù)

使用道具 舉報(bào)

ID:593904 發(fā)表于 2019-8-2 07:12 | 顯示全部樓層
打包視頻教程
回復(fù)

使用道具 舉報(bào)

ID:160995 發(fā)表于 2019-8-3 01:17 | 顯示全部樓層
感謝分享
回復(fù)

使用道具 舉報(bào)

ID:90212 發(fā)表于 2019-8-14 11:02 | 顯示全部樓層
請教下樓主,我需要測0~60V電壓,F(xiàn)在分壓電阻只能用 (5.1k+5.1k)/470 ,不能用20K以上的電阻,否則測量15V以上就會(huì)出現(xiàn)明顯不等比例的現(xiàn)象
回復(fù)

使用道具 舉報(bào)

ID:392569 發(fā)表于 2019-8-14 12:33 | 顯示全部樓層
太詳細(xì)了
回復(fù)

使用道具 舉報(bào)

ID:85865 發(fā)表于 2019-8-14 13:11 | 顯示全部樓層
感謝分享
回復(fù)

使用道具 舉報(bào)

ID:603929 發(fā)表于 2019-9-27 14:53 | 顯示全部樓層
感謝分享
回復(fù)

使用道具 舉報(bào)

ID:686610 發(fā)表于 2020-1-16 11:38 | 顯示全部樓層
感謝樓主
回復(fù)

使用道具 舉報(bào)

ID:142383 發(fā)表于 2020-2-20 08:24 | 顯示全部樓層
感謝樓主分享,下載學(xué)習(xí)學(xué)習(xí)!
回復(fù)

使用道具 舉報(bào)

ID:416535 發(fā)表于 2020-4-2 14:52 | 顯示全部樓層
簡直變態(tài)的詳細(xì),太詳細(xì)了,感謝分享!
回復(fù)

使用道具 舉報(bào)

ID:146632 發(fā)表于 2021-3-19 15:16 | 顯示全部樓層
extern __IO uint16_t ADC_ConvertedValue  為何報(bào)錯(cuò)
回復(fù)

使用道具 舉報(bào)

ID:64366 發(fā)表于 2021-3-27 14:49 | 顯示全部樓層
感謝樓主  正在做相關(guān)的東西
回復(fù)

使用道具 舉報(bào)

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表