stm32 AD模數轉換[操做寄存器+庫函數]

stm32f103最少有2個AD模數轉換器,每一個ADC都有18個通道,能夠測量16個外部和2個內部模擬量。最大轉換頻率爲1Mhz,也就是轉換時間爲1us(在 ADCCLK = 14Mhz,採樣週期爲1.5個時鐘週期時)。最大時鐘超過14Mhz,將致使ADC轉換準確度下降。stm32的ADC是12位精度的。
 
stm32的ADC轉換有兩種通道,規則通道和注入通道,注入通道能夠搶佔式地打斷規則通道的採樣,執行注入通道採樣後,再執行以前的規則通道採樣,和中斷相似。本例只使用規則通道實現獨立模式的中斷採樣,這裏再也不贅述兩種通道區別。
 
stm32的ADC能夠由外部事件觸發(例如定時器捕獲,EXTI線)和軟件觸發(即在配置相關寄存器時,直接開啓採樣)。
 

本例實現AD採樣PB0口,使用串口輸出PB0口電壓值。PB0口接變阻器以改變調整電壓。
效果以下:
                                     ADValue = 1.39v
                                     ADValue = 1.38v
                                     ADValue = 1.40v
                                     ADValue = 1.38v
                                     ADValue = 1.39v
 

直接操做寄存器
 
首先須要配置ADC的時鐘分頻值,在RCC->CFGR的[15:14]位:
  • 00:PCLK2 2分頻後做爲ADC時鐘         01:PCLK2 4分頻後做爲ADC時鐘
  • 10:PCLK2 6分頻後做爲ADC時鐘         11:PCLK2 8分頻後做爲ADC時鐘
設定各通道的採樣時間ADCx->SMPR,該寄存器給每一個通道3位來選擇8種採樣週期:
  • 000:1.5週期               100:41.5週期
  • 001:7.5週期               101:55.5週期
  • 010:13.5週期             110:71.5週期
  • 011:28.5週期             111:239.5週期
採樣時間算法爲: (採樣週期+12.5)/分頻後的時鐘
 
ADC採樣獲得的只是一個相對值,將 轉換值/4096*參考電壓 便可獲得採樣電壓 這裏的4096是由於stm32的adc爲12位精度,表示參考電壓時即爲 2^12=4096
 
代碼以下:  (system.h 和 stm32f10x_it.h 等相關代碼參照  stm32 直接操做寄存器開發環境配置
User/main.c
01 #include <stm32f10x_lib.h>    
02 #include "system.h"
03 #include "usart.h"
04 #include "adc.h"
05 #include "stdio.h" 
06  
07 #define LED1 PAout(4)
08 #define LED2 PAout(5)
09  
10 #define VREF 3.3         //參考電壓
11 void Gpio_Init(void);
12  
13 int main(void)
14 {                
15     u16 ADValue;
16     float temp;
17  
18     Rcc_Init(9);             //系統時鐘設置
19     Usart1_Init(72,9600);   //設置串口時鐘和波特率
20  
21     Adc1_Init(8,7);   //使用8通道採樣,採樣時間係數爲7(111),據手冊可得采樣時間爲 (239.5+12.5)/12= 21 (us)
22     Gpio_Init();
23  
24     while(1){
25          
26         ADValue = Get_Adc(ADC_1,8);
27         temp = (float)VREF*(ADValue/4096);     //ADC精度爲12位精度,即達到 VREF電壓時爲 2^12 = 4096
28  
29         printf("\r\n ADValue = %.2fv\r\n",temp);
30  
31         LED2 = !LED2;
32  
33         delay(100000);   //延時100ms
34  
35     }      
36 }
37  
38  
39 void Gpio_Init(void)
40 {
41     RCC->APB2ENR|=1<<2;    //使能PORTA時鐘    
42     RCC->APB2ENR|=1<<3;    //使能PORTB時鐘    
43                
44  
45     GPIOA->CRL&=0xFF0FFFF0;
46     GPIOA->CRL|=0xFF3FFFF0; // PA0設置爲模擬輸入,PA4推輓輸出
47  
48     GPIOB->CRL&=0xFFFFFFF0;
49     GPIOB->CRL|=0xFFFFFFF0; // PB0設置爲模擬輸入
50  
51      
52     //USART1 串口I/O設置
53  
54     GPIOA -> CRH&=0xFFFFF00F;   //設置USART1 的Tx(PA.9)爲第二功能推輓,50MHz;Rx(PA.10)爲浮空輸入
55     GPIOA -> CRH|=0x000008B0;     
56 }
Library/src/adc.c
01 #include <stm32f10x_lib.h>        
02 #include "adc.h"
03  
04  
05 //ADC1採樣初始化
06 //獨立工做模式
07 //參數說明:
08 //          ADC_CH_x    選擇使用通道(0~17),目前暫支持0~15通道
09 //          ADC_CH_SMP  設定採樣週期(0~7)
10 //採樣週期算法:
11  
12 void Adc1_Init(u8 ADC_CH_x,u8 ADC_CH_SMP)
13 {
14     RCC -> APB2ENR |= 1<<9;        //開啓ADC1時鐘
15     RCC -> APB2RSTR |= 1<<9;       //復位ADC1
16     RCC -> APB2RSTR &= ~(1<<9);    //ADC1復位結束
17  
18     RCC -> CFGR &= ~(3<<14);       //分頻因子清零
19     RCC -> CFGR |= 2<<14;          //設定分頻因數爲2,PCLK2 6分頻後做爲ADC時鐘
20  
21     ADC1 -> CR1 &= 0xF0FFFF;     //工做模式清零
22     ADC1 ->  CR1 |= 0<<16;         //設定爲獨立模式
23     ADC1 -> CR1 &= ~(1<<8);            //非掃描工做模式
24     ADC1 -> CR2 &= ~(1<<1);            //關閉連續轉換
25  
26     ADC1 -> CR2 &= ~(7<<17);       //清除規則通道啓動事件
27     ADC1 -> CR2 |= 7<<17;          //設定規則通道啓動事件爲軟件啓動(SWSTART)
28  
29     ADC1 -> CR2 |= 1<<20;          //使用外部事件觸發 SWSTART
30     ADC1 -> CR2 &= ~(1<<11);       //設置對齊模式爲右對齊
31  
32     ADC1 -> SQR1 &= ~(0xF<<20);        //清零規則序列的數量
33     ADC1 -> SQR1 |= 15<<20;            //設置規則序列的數量爲16
34  
35     ADC1 -> SMPR2 &= 0x00000000; //清零通道採樣時間
36     ADC1 -> SMPR1 &= 0xFF000000;
37  
38     if(ADC_CH_x <= 9 ){
39         ADC1 -> SMPR2 |= 7<<(ADC_CH_x*3);          //設置通道x採樣時間,提升採樣時間能夠提升採樣精度
40     }
41  
42     if(ADC_CH_x > 9 ){
43         ADC1 -> SMPR1 |= 7<<((ADC_CH_x-10)*3);    
44     }
45      
46  
47     ADC1 -> CR2 |= 1<<0;           //開啓AD轉換
48     ADC1 -> CR2 |= 1<<3;           //使能復位校準,由硬件清零
49     while((ADC1 -> CR2)& (1<<3));  //等待校準結束
50     ADC1 -> CR2 |= 1<<2;           //開啓AD校準,由硬件清零
51     while((ADC1 -> CR2)& (1<<2));  //等待校準結束
52  
53 }
54  
55 //取得數模轉換的值
56 //參數說明:(參數定義於adc.h)
57 //       ADC_x  (0~3),選擇數模轉換器
58 //       ADC_CH_x    (0~15),選擇通道
59 u16 Get_Adc(u8 ADC_x,u8 ADC_CH_x)
60 {
61     u16 data = 0;
62  
63     switch(ADC_x)  
64     {
65         case 1 : {
66  
67             ADC1 -> SQR3 &= 0xFFFFFFE0;          //清除通道選擇
68             ADC1 -> SQR3 |= ADC_CH_x;                //選擇通道
69             ADC1 -> CR2  |= 1<<22;             //開啓AD轉換
70             while(!(ADC1 -> SR & 1<<1));           //等待轉換結束
71  
72             data = ADC1->DR;
73             break;
74         }
75         case 2 : {break;}
76         case 3 : {break;}
77     }
78  
79     return data;
80 }
Library/inc/adc.h
1 #include <stm32f10x_lib.h>   
2  
3 #define  ADC_1 0x01
4 #define  ADC_2 0x02
5 #define  ADC_3 0x03
6  
7 void Adc1_Init(u8 ADC_CH_x,u8 ADC_CH_SMP);
8 u16 Get_Adc(u8 ADC_x,u8 ADC_CH_x);
 
 
庫函數操做
 
main.c
001 #include "stm32f10x.h"
002 #include "stdio.h"
003  
004  
005 #define  PRINTF_ON  1
006 #define  VREF       3.3        // 參考電壓
007  
008  
009 void RCC_Configuration(void);
010 void GPIO_Configuration(void);
011 void USART_Configuration(void);
012 void ADC_Configuration(void);
013  
014  
015 int main(void)
016 {
017     float ADValue = 0.00;
018     u32 delayTime = 0;
019  
020     RCC_Configuration();
021     GPIO_Configuration();
022     USART_Configuration();
023     ADC_Configuration();
024  
025     while(1)
026     {
027         if(delayTime++ >=2000000)
028         {
029             delayTime = 0;
030             ADValue = VREF*ADC_GetConversionValue(ADC1)/0x0fff;
031             printf("\r\n ADValue = %.2fv\r\n",ADValue);
032          
033         }
034     }
035 }
036  
037    
038 void GPIO_Configuration(void)
039 {
040     GPIO_InitTypeDef GPIO_InitStructure;                                                                                    
041     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;
042     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;          
043     GPIO_Init(GPIOA , &GPIO_InitStructure);
044  
045  
046     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
047     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
048     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        
049     GPIO_Init(GPIOA , &GPIO_InitStructure);
050  
051     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
052     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;          
053     GPIO_Init(GPIOA , &GPIO_InitStructure);
054 }
055  
056 void ADC_Configuration(void)
057 {
058     ADC_InitTypeDef ADC_InitStructure; 
059  
060     RCC_ADCCLKConfig(RCC_PCLK2_Div4);   //配置ADC時鐘分頻
061  
062     ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
063     ADC_InitStructure.ADC_ScanConvMode = ENABLE;
064     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
065     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
066     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
067     ADC_InitStructure.ADC_NbrOfChannel = 1;
068     ADC_Init(ADC1,&ADC_InitStructure);
069      
070     ADC_RegularChannelConfig(ADC1,ADC_Channel_8,1,ADC_SampleTime_55Cycles5);
071     ADC_Cmd(ADC1,ENABLE);
072     ADC_ResetCalibration(ADC1);
073     while(ADC_GetResetCalibrationStatus(ADC1));
074     ADC_StartCalibration(ADC1);
075     while(ADC_GetCalibrationStatus(ADC1));
076     ADC_SoftwareStartConvCmd(ADC1,ENABLE);
077  
078  
079 }
080  
081  
082 void RCC_Configuration(void)
083 {
084     /* 定義枚舉類型變量 HSEStartUpStatus */
085     ErrorStatus HSEStartUpStatus;
相關文章
相關標籤/搜索