天天看點

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 view source print ?

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

085

ErrorStatus HSEStartUpStatus;

086

087

088

RCC_DeInit();

089

090

RCC_HSEConfig(RCC_HSE_ON);

091

092

HSEStartUpStatus = RCC_WaitForHSEStartUp();

093

094

if

(HSEStartUpStatus == SUCCESS)

095

{

096

097

RCC_HCLKConfig(RCC_SYSCLK_Div1);

098

099

RCC_PCLK2Config(RCC_HCLK_Div1);

100

101

RCC_PCLK1Config(RCC_HCLK_Div2);

102

103

FLASH_SetLatency(FLASH_Latency_2);

104

105

FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

106

107

RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

108

109

RCC_PLLCmd(ENABLE);

110

111

while

(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

112

113

RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

114

115

while

(RCC_GetSYSCLKSource() != 0x08);

116

}

117

118

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOB|RCC_APB2Periph_ADC1, ENABLE);

119

120

//RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);

121

122

}

123

124

125

void

USART_Configuration(

void

)

126

{

127

USART_InitTypeDef USART_InitStructure;

128

USART_ClockInitTypeDef USART_ClockInitStructure;

129

130

USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;

131

USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;

132

USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;                                                                                                                                                     

133

USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;

134

USART_ClockInit(USART1 , &USART_ClockInitStructure);

135

136

USART_InitStructure.USART_BaudRate = 9600;

137

USART_InitStructure.USART_WordLength = USART_WordLength_8b;

138

USART_InitStructure.USART_StopBits = USART_StopBits_1;

139

USART_InitStructure.USART_Parity = USART_Parity_No;

140

USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

141

USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;

142

USART_Init(USART1,&USART_InitStructure);

143

144

USART_Cmd(USART1,ENABLE);

145

}

146

147

148

#if  PRINTF_ON

149

150

int

fputc

(

int

ch,

FILE

*f)

151

{

152

USART_SendData(USART1,(u8) ch);

153

while

(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);

154

return

ch;

155

}

156

157

#endif

繼續閱讀