找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 9570|回復(fù): 5
打印 上一主題 下一主題
收起左側(cè)

基于STM32F4的多通道ADC采集,采用DMA的形式,親測有效

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:499190 發(fā)表于 2019-10-11 08:46 | 只看該作者 回帖獎勵(lì) |倒序?yàn)g覽 |閱讀模式
基于STM32F4的多通道ADC采集

單片機(jī)源程序如下:
  1. #include "sys.h"
  2. #include "delay.h"
  3. #include "usart.h"
  4. #include "led.h"
  5. #include "fliter.h"
  6. #include "adc.h"
  7. #include "oled.h"

  8. extern u8 AD_Flag;   //AD轉(zhuǎn)換完成標(biāo)志位
  9. extern u16  ADC_ConvertedValue[NOFCHANEL];    //用于存放ADC的轉(zhuǎn)換值
  10. extern float ADC_Final_DisplayValue[NOFCHANEL];        //用于存放最終顯示值
  11. extern u16 ADC_filter_Value[NOFCHANEL];       


  12. int main()
  13. {

  14.        
  15.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設(shè)置系統(tǒng)中斷優(yōu)先級分組2
  16.         delay_init(168);    //初始化延時(shí)函數(shù)
  17.         uart_init(115200);        //初始化串口波特率為115200
  18.         ADC_X_Init();        //ADC初始化
  19.         LED_Init();          //LED燈初始化
  20.         OLED_Init();         //OLED初始化

  21.   
  22.         /************一開始的顯示*************/
  23.   OLED_ShowCHinese(12,0,0,1);    //輸
  24.   OLED_ShowCHinese(24,0,1,1);    //入
  25.   OLED_ShowCHinese(36,0,4,1);    //電
  26.   OLED_ShowCHinese(48,0,5,1);    //壓
  27.   OLED_ShowCHinese(60,0,10,1);   //:
  28.   OLED_ShowCHinese(12,12,2,1);   //輸
  29.   OLED_ShowCHinese(24,12,3,1);   //出
  30.   OLED_ShowCHinese(36,12,6,1);   //電
  31.   OLED_ShowCHinese(48,12,7,1);   //流
  32.   OLED_ShowCHinese(60,12,10,1);  //:
  33.   OLED_ShowString(12,24,"DAC:",12);
  34.   OLED_Refresh_Gram();//更新顯示到OLED         
  35.        
  36.         while(1)
  37.         {
  38.                 AD_Flag=AD_voltage;  ADC_filter_Value[0]=middleValueFilter();
  39.                 AD_Flag=AD_current;  ADC_filter_Value[1]=middleValueFilter();
  40.                 AD_Flag=AD_DAC;                 ADC_filter_Value[2]=middleValueFilter();                       
  41.                 ADC_Final_DisplayValue[0] =(double) ADC_filter_Value[0]/4096*3.3*6;   //電壓檢測
  42.                 ADC_Final_DisplayValue[1] =(double) ADC_filter_Value[1]/4096*3.3;         //電流檢測
  43.            ADC_Final_DisplayValue[2] =(double) ADC_filter_Value[2]/4096*3.3;         //DAC檢測
  44.                 OLED_ShowFloatNum_12(72,0,ADC_Final_DisplayValue[0],2,12);
  45.            OLED_ShowFloatNum_12(72,12,ADC_Final_DisplayValue[1],2,12);
  46.                 OLED_ShowFloatNum_12(72,24,ADC_Final_DisplayValue[2],2,12);
  47.                 OLED_Refresh_Gram();//更新顯示到OLED       
  48.                
  49.                 delay_ms(500);
  50.        
  51.         }
  52. }
復(fù)制代碼

  1. #include "usart.h"
  2. #include "adc.h"
  3. #include "delay.h"
  4. #include "fliter.h"
  5. #include "led.h"

  6. extern u8 AD_Flag;   //AD轉(zhuǎn)換完成標(biāo)志位
  7. extern u16  ADC_ConvertedValue[NOFCHANEL];    //用于存放ADC的轉(zhuǎn)換值
  8. extern float ADC_Final_DisplayValue[NOFCHANEL];        //用于存放最終顯示值
  9. u16 ADC_filter_Value[NOFCHANEL];               


  10. extern u16 ADC_ConvertedValue[NOFCHANEL];
  11. // 軟件延時(shí)
  12. void Delay_ruan(__IO uint32_t nCount)
  13. {
  14.   for(; nCount != 0; nCount--);
  15. }
  16. //中位值濾波
  17. //方法:連續(xù)采樣N次(N取奇數(shù))把N次采樣值按大小排列取中間值為本次有效值
  18. //優(yōu)點(diǎn):能有效克服因偶然因素引起的波動干擾;對溫度、液位等變化緩慢的被測參數(shù)有良好的濾波效果
  19. //缺點(diǎn):對流量,速度等快速變化的參數(shù)不宜

  20. #define N 30
  21. u16 middleValueFilter()      //會獲取30個(gè)ADC轉(zhuǎn)換值,然后取中間的一個(gè)作為本次采樣周期的輸出值
  22. {
  23.     u16 value_buf[N];
  24.     u16 i,j,k,temp;
  25.     for( i = 0; i < N; ++i)
  26.     {
  27.         value_buf[i] = getValue();
  28.                                
  29.     }
  30.     for(j = 0 ; j < N-1; ++j)
  31.     {
  32.         for(k = 0; k < N-j-1; ++k)
  33.         {
  34.             //從小到大排序,冒泡法排序
  35.             if(value_buf[k] > value_buf[k+1])
  36.             {
  37.                 temp = value_buf[k];
  38.                 value_buf[k] = value_buf[k+1];
  39.                 value_buf[k+1] = temp;
  40.             }
  41.         }
  42.     }
  43.                
  44.     return value_buf[(N-1)/2];
  45. }



  46. /*******************獲得ADC轉(zhuǎn)換的值*******************/
  47. u16 getValue()
  48. {
  49.         Delay_ruan(5);                     //軟件延時(shí)一下再獲取ADC的值,但是這個(gè)時(shí)間怎么確定呢?
  50.        
  51.         if(AD_Flag==AD_voltage)           //獲取ADC電壓的值
  52.         {
  53.                 return ADC_ConvertedValue[0];  //因?yàn)锳DC1的數(shù)據(jù)數(shù)據(jù)寄存器地址連接到了ADC_ConvertedValue數(shù)組上,所以ADC1采集到的值會傳輸?shù)綌?shù)組中,
  54.         }
  55.        
  56.         if(AD_Flag==AD_current)                                //獲取ADC采集電流的值
  57.         {
  58.                 return ADC_ConvertedValue[1];
  59.                
  60.         }
  61.        
  62.         if(AD_Flag==AD_DAC)                                //獲取DAC的值
  63.         {
  64.                 return ADC_ConvertedValue[2];
  65.                
  66.         }
  67. }


  68. //**************疑問*************//
  69. //ADC1用了兩個(gè)通道,我怎么知道什么時(shí)候電流或者電壓的值存放到數(shù)組里?是否存到了對應(yīng)的位置?
  70. //因?yàn)榇鎯Φ刂肥沁B續(xù)的,所以ADC采集獲得的值會根據(jù)順序存入到數(shù)組中
復(fù)制代碼
  1. #include "adc.h"
  2. #include "delay.h"                 

  3. u8    AD_Flag;                                                                    //AD轉(zhuǎn)換完成標(biāo)志位
  4. u16   ADC_ConvertedValue[NOFCHANEL]={0}; //用于存放ADC的轉(zhuǎn)換值
  5. float ADC_Final_DisplayValue[NOFCHANEL]; //用于存放最終顯示值


  6. /*********************IO口復(fù)用為ADC******************/

  7.         void ADC_GPIO_Config(void)
  8.         {
  9.                 GPIO_InitTypeDef GPIO_InitStructure;                      //結(jié)構(gòu)體定義
  10.                 /*=====================通道1======================*/       
  11.                                         /********** 使能 GPIO 時(shí)鐘****/
  12.                 RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK1,ENABLE);                
  13.                                   /********配置 IO************/
  14.                 GPIO_InitStructure.GPIO_Pin =  ADC_GPIO_PIN1;                
  15.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;        //引腳復(fù)用時(shí),作為ADC或者DAC,不能選復(fù)用,必須選模擬輸入,其他的都是復(fù)用
  16.                 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  17.                                 /*******初始化IO口*********/
  18.                 GPIO_Init(ADC_GPIO_PORT1, &GPIO_InitStructure);

  19.                 /*=====================通道2======================*/
  20.                          /********** 使能 GPIO 時(shí)鐘****/
  21.                 RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK2,ENABLE);                
  22.                                   /********配置 IO************/
  23.                 GPIO_InitStructure.GPIO_Pin = ADC_GPIO_PIN2;                
  24.                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;        //引腳復(fù)用時(shí),作為ADC或者DAC,不能選復(fù)用,必須選模擬輸入,其他的都是復(fù)用
  25.                 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  26.                                 /*******初始化IO口*********/
  27.                 GPIO_Init(ADC_GPIO_PORT2, &GPIO_InitStructure);
  28.        
  29.        

  30. ////        /*=====================通道3=======================*/
  31.             /********** 使能 GPIO 時(shí)鐘****/
  32.           RCC_AHB1PeriphClockCmd( ADC_GPIO_CLK3,ENABLE);                
  33.                 /********配置 IO************/
  34.           GPIO_InitStructure.GPIO_Pin =ADC_GPIO_PIN3;                
  35.           GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;        //引腳復(fù)用時(shí),作為ADC或者DAC,不能選復(fù)用,必須選模擬輸入,其他的都是復(fù)用
  36.      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  37.                         /*******初始化IO口*********/
  38.           GPIO_Init(ADC_GPIO_PORT3, &GPIO_InitStructure);
  39. }

  40. /***********配置ADC和DMA*************/
  41. void ADC_Mode_Config(void)
  42. {
  43.    DMA_InitTypeDef DMA_InitStructure;                                        // DMA初始化結(jié)構(gòu)體
  44.         ADC_InitTypeDef ADC_InitStructure;              // ADC初始化結(jié)構(gòu)體
  45.    ADC_CommonInitTypeDef ADC_CommonInitStructure;

  46.   /*-------------------DMA Iint 結(jié)構(gòu)體參數(shù) 初始化---------------------*/
  47.   /************開啟DMA時(shí)鐘*************************/
  48.   RCC_AHB1PeriphClockCmd(DMAX_CLK, ENABLE);
  49.         // 外設(shè)基址為:ADC 數(shù)據(jù)寄存器地址
  50.         DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)&ADC_X->DR;                //外設(shè)的數(shù)據(jù)寄存器地址怎么確定,(u32)&name->DR(name為外設(shè)名)
  51.   // 存儲器地址,實(shí)際上就是一個(gè)內(nèi)部SRAM的變量       
  52.         DMA_InitStructure.DMA_Memory0BaseAddr =(u32)ADC_ConvertedValue;    //存放ADC轉(zhuǎn)換值的數(shù)組地址(可以理解為存放ADC轉(zhuǎn)換值的寄存器與這個(gè)數(shù)組直接連接在一起)
  53.   // 數(shù)據(jù)傳輸方向?yàn)橥庠O(shè)到存儲器       
  54.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;                   //確定方向很重要
  55.         // 緩沖區(qū)大小為,指一次傳輸?shù)臄?shù)據(jù)量
  56.         DMA_InitStructure.DMA_BufferSize = NOFCHANEL;                            //存放ADC轉(zhuǎn)換值的數(shù)組的數(shù)據(jù)量
  57.         // 外設(shè)寄存器只有一個(gè),地址不用遞增
  58.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  59.   // 存儲器地址固定(這里明明寫的是增加,為什么還說固定,是錯(cuò)誤了么)
  60.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;             //(這里應(yīng)該是增加,因?yàn)橐讯鄠(gè)數(shù)據(jù)存到一個(gè)數(shù)組里,地址應(yīng)該是變化的)
  61.   // // 外設(shè)數(shù)據(jù)大小為半字,即兩個(gè)字節(jié)
  62.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  //這里指的是一個(gè)數(shù)據(jù)的大小,STM32是32位的,所以一個(gè)字是32位,半字是16位
  63.   //        存儲器數(shù)據(jù)大小也為半字,跟外設(shè)數(shù)據(jù)大小相同
  64.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                //外設(shè)數(shù)據(jù)大小是不是要和存儲器數(shù)據(jù)大小相同?是的
  65.         // 循環(huán)傳輸模式 (ADC要不斷采集數(shù)據(jù),所以要循環(huán)模式)
  66.         DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  67.   // DMA 傳輸通道優(yōu)先級為高,當(dāng)使用一個(gè)DMA通道時(shí),優(yōu)先級設(shè)置不影響
  68.         DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  69.   // 禁止DMA FIFO        ,使用直連模式
  70.   DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;  
  71.   
  72.   // FIFO 大小,F(xiàn)IFO模式禁止時(shí),這個(gè)不用配置       
  73.   DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  74.   DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  75.   DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;  
  76.        
  77.         // 選擇 DMA 通道,通道存在于流中
  78.         DMA_InitStructure.DMA_Channel =DMA_Channel__x;
  79.         //初始化DMA流,流相當(dāng)于一個(gè)大的管道,管道里面有很多通道
  80.         DMA_Init(DMA_Stream__x, &DMA_InitStructure);
  81.        
  82.         /****使能DMA流*********/
  83.         DMA_Cmd(DMA_Stream__x, ENABLE);
  84.        
  85.         /*-------------ADC_X 初始化------------------*/
  86.         /***************使能ADC時(shí)鐘*****************************/
  87.         RCC_APB2PeriphClockCmd(ADC_CLK_ENABLE, ENABLE);
  88.   
  89.   /*-------------------ADC Common 結(jié)構(gòu)體 參數(shù) 初始化---------------*/
  90.         // 獨(dú)立ADC模式
  91.   ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  92.   // 時(shí)鐘為fpclk x分頻       
  93.   ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
  94.   // 禁止DMA直接訪問模式       
  95.   ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  96.   // 采樣時(shí)間間隔       
  97.   ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;  
  98.    //初始化ADC Common 結(jié)構(gòu)體
  99.   ADC_CommonInit(&ADC_CommonInitStructure);       
  100.   
  101.    /* -------------------ADC Init 結(jié)構(gòu)體 參數(shù) 初始化-----------------*/
  102.   // ADC 分辨率
  103.   ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  104.   // 掃描模式,多通道采集需要       
  105.   ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  106.   // 連續(xù)轉(zhuǎn)換       
  107.   ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  108.   //禁止外部邊沿觸發(fā)
  109.   ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  110.   //外部觸發(fā)通道,本例子使用軟件觸發(fā),此值隨便賦值即可
  111.   ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  112.   //數(shù)據(jù)右對齊       
  113.   ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  114.   //轉(zhuǎn)換通道NOFCHANEL個(gè)
  115.   ADC_InitStructure.ADC_NbrOfConversion = NOFCHANEL;
  116.   
  117.   /******ADC 結(jié)構(gòu)體初始化*********/  
  118.   ADC_Init(ADC_X, &ADC_InitStructure);
  119.   
  120. /*----------------配置 ADC 通道轉(zhuǎn)換順序和采樣時(shí)間周期-----------------*/
  121.   // 配置 ADC 通道轉(zhuǎn)換順序和采樣時(shí)間周期
  122.   ADC_RegularChannelConfig(ADC_X,ADC_CHANNEL1, 1, ADC_SampleTime_56Cycles);  //ADC通道1引腳是GPIOB_Pin_0
  123.   ADC_RegularChannelConfig(ADC_X,ADC_CHANNEL2, 2, ADC_SampleTime_56Cycles);   //ADC通道2引腳是GPIOB_Pin_1
  124.   ADC_RegularChannelConfig(ADC_X,ADC_CHANNEL3, 3, ADC_SampleTime_56Cycles); //ADC通道3引腳是GPIOA_Pin_6

  125.   // 使能DMA請求 after last transfer (Single-ADC mode)
  126.   ADC_DMARequestAfterLastTransferCmd(ADC_X, ENABLE);
  127.   
  128.   /*************使能ADC DMA*************/
  129.   ADC_DMACmd(ADC_X, ENABLE);       
  130. /*************使能ADC******************/
  131.   ADC_Cmd(ADC_X, ENABLE);  
  132.   
  133.   //開始adc轉(zhuǎn)換,軟件觸發(fā)
  134.   ADC_SoftwareStartConv(ADC_X);
  135.   
  136. }


  137. void ADC_X_Init(void)
  138. {
  139.         ADC_GPIO_Config();
  140.         ADC_Mode_Config();
  141. }
復(fù)制代碼

所有資料51hei提供下載:
STM32F4 多通道DMAADC.7z (644.37 KB, 下載次數(shù): 278)


評分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵(lì)!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏11 分享淘帖 頂1 踩

相關(guān)帖子

回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:701882 發(fā)表于 2020-3-13 08:31 | 只看該作者
終于找到407的了
回復(fù)

使用道具 舉報(bào)

板凳
ID:477269 發(fā)表于 2020-5-20 11:12 | 只看該作者
真的是感謝樓主的無私,先研究一下
回復(fù)

使用道具 舉報(bào)

地板
ID:759611 發(fā)表于 2020-6-5 21:23 | 只看該作者
樓主請問有電路圖嗎?可以分享一下嗎
回復(fù)

使用道具 舉報(bào)

5#
ID:939607 發(fā)表于 2021-7-27 10:47 | 只看該作者
感謝,先研究下
回復(fù)

使用道具 舉報(bào)

6#
ID:923825 發(fā)表于 2021-7-28 14:26 | 只看該作者
可以用來電池電壓采集使用
回復(fù)

使用道具 舉報(bào)

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

本版積分規(guī)則

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

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

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