记录每次学习的过程,总结学习的内容,希望能给到自己和别人帮助。

嵌入式学习-STC-ADC(模数转换器)

ADC

(Analog to Digital Converter 模数转换器)是一种将模拟信号转换为数字信号的电路。在电子系统中,模拟信号常常需要转换为数字信号进行处理和存储。模数转换的基本原理是将模拟信号进行采样,并将采样值量化为数字表示。

● 采样:是指在一定时间间隔内对模拟信号进行测量,并将测量值存储在数字形式的数据中

● 量化:是将这些连续的模拟信号值离散化为一系列数字值,通常使用二进制表示。

简单理解,ADC是把模拟信号转换为数字信号的工具,我们可以认为,一个信号有强弱之分,强弱的体现为电压的高低。在数字电路中,只有0和1之分,也就是高电平或低电平。那么体现不了这个强弱。ADC的作用就是体现强弱,精确化的拿到具体的值。

● 模拟信号:信号有强弱之分,强弱的体现为电压的高低

● 数字电路:只有0和1之分,也就是高电平或低电平

应用场景:

医疗设备:如心电图、血压计之类。音频信号处理:在数字音频处理中,ADC将模拟音频信号转换为数字信号,然后可以进行数字信号处理和存储。电力系统:测量电压。

总之,需要知道信号强弱的,需要将模拟信号转为数字信号的都会用到ADC。

主要功能:采集和量化

io设置模式:为了能准确采集,初始化为高阻输入

用4096表示基准电压

2.5 1.25

4096 2048

ADC为12位精度的,意思是最大值是2的12次方,值为4096.

ADC的这个最大值,表示的是最大测量范围:

数值最大为4096测量的电压值不能超过基准电压基准电压对应的值为4096

记住:我们用4096表示基准电压。

例如采集到4096的时候,证明是最大电压,这时候会是2.5伏。例如采集到2048的时候,证明当时的电压是1.25伏。

以上原理图中,基准电压由 VREF电压决定。这个电路中用到了一个芯片CJ431/CD431,这是一款电压基准芯片,会恒定的输出2.5V电压。

在我们的设计方案中,理论上可以不使用这个电压基准芯片的,直接连接3V3,但是LDO的输出稳定性不够,因此使用电压基准芯片会更为准确。

由以上我们可以得出:

基准电压为:2.5V基准电压对应的数值是4096测量的值为ADC引脚电压值的计算:

反向得到电源输入电压

将ADC_Vref+引脚接到VCC管脚MCU_Vcc = 4096 * 1.19V / 12位ADC转换结果(CH15)

计算公式:

ADC功能引脚

STC8H芯片有15个通道的ADC功能引脚:

代码流程:

配置IO工作模式

配置ADC ADC_Config();

用 函数来读取采样值

IO初始化为高阻输入

void GPIO_config(void) {

GPIO_InitTypeDef GPIO_InitStructure; //结构定义

GPIO_InitStructure.Pin = GPIO_Pin_5; //指定要初始化的IO,

GPIO_InitStructure.Mode = GPIO_HighZ; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP

GPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化

}

ADC配置逻辑

一般内容不用修改

/******************* AD配置函数 *******************/

void ADC_config(void)

{

ADC_InitTypeDef ADC_InitStructure; //结构定义

ADC_InitStructure.ADC_SMPduty = 31; //ADC 模拟信号采样时间控制, 0~31(注意: SMPDUTY 一定不能设置小于 10)

ADC_InitStructure.ADC_CsSetup = 0; //ADC 通道选择时间控制 0(默认),1

ADC_InitStructure.ADC_CsHold = 1; //ADC 通道选择保持时间控制 0,1(默认),2,3

ADC_InitStructure.ADC_Speed = ADC_SPEED_2X1T; //设置 ADC 工作时钟频率 ADC_SPEED_2X1T~ADC_SPEED_2X16T

ADC_InitStructure.ADC_AdjResult = ADC_RIGHT_JUSTIFIED; //ADC结果调整, ADC_LEFT_JUSTIFIED,ADC_RIGHT_JUSTIFIED

ADC_Inilize(&ADC_InitStructure); //初始化

ADC_PowerControl(ENABLE); //ADC电源开关, ENABLE或DISABLE

NVIC_ADC_Init(DISABLE,Priority_0); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3

}

数据读取与转换

result = Get_ADCResult(ADC_CH13);

v = result * 2.5 / 4096;

功能举例:

获取热敏电阻NTC数值

热敏电阻的特性:温度上升,电阻减少

NTC(Negative Temperature Coefficient)是指随温度上升电阻减小、具有负温度系数的热敏电阻现象和材料。

得到电阻,反推温度。

想得到电阻,要得到电压。

阻温特性表

表值过多,有兴趣的可以去浏览 相关所购买的热敏电阻的数据手册,我这里只截取部分作为例子

代码封装(转换成温度输出)

NTC.h

创建NTC.h,写入如下内容

#ifndef __NTC_H__

#define __NTC_H__

// 初始化NTC

void NTC_Initialize();

// 获取温度值

int NTC_get_temperature();

#endif

NTC.c

创建一个NTC.c文件,写入如下内容,请自行将temp_table拷贝进来(因为temp_table较长,我会放在最后面,有需要的话再复制进来这个.c文件中)

#include "NTC.h"

#include "GPIO.h"

#include "ADC.h"

#include "NVIC.h"

#include

//1.初始化数组------------------------------------------------------------------

// static标志此函数,只能在本文件使用,避免冲突

// code 关键字作用 定义的数据要放在ROM(程序代码存储区)里面,写入后不能再更改

static u16 code temp_table[] = {

58354, // -55

55464, // -54

.....//剩余的不复制,需要复制就到数组定义中复制

}

//2.初始化配置------------------------------------------------------------------

//GPIO配置

static void GPIO_config(void) {

GPIO_InitTypeDef GPIO_InitStructure; //结构定义

// P04 高阻输入 为保证数据精确 热敏电阻用的是P04引脚

GPIO_InitStructure.Pin = GPIO_Pin_4; //指定要初始化的IO,

GPIO_InitStructure.Mode = GPIO_HighZ; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP

GPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化

}

/******************* AD配置函数 *******************/

static void ADC_config(void)

{

ADC_InitTypeDef ADC_InitStructure; //结构定义

ADC_InitStructure.ADC_SMPduty = 31; //ADC 模拟信号采样时间控制, 0~31(注意: SMPDUTY 一定不能设置小于 10)

ADC_InitStructure.ADC_CsSetup = 0; //ADC 通道选择时间控制 0(默认),1

ADC_InitStructure.ADC_CsHold = 1; //ADC 通道选择保持时间控制 0,1(默认),2,3

ADC_InitStructure.ADC_Speed = ADC_SPEED_2X1T; //设置 ADC 工作时钟频率 ADC_SPEED_2X1T~ADC_SPEED_2X16T

ADC_InitStructure.ADC_AdjResult = ADC_RIGHT_JUSTIFIED; //ADC结果调整, ADC_LEFT_JUSTIFIED,ADC_RIGHT_JUSTIFIED

ADC_Inilize(&ADC_InitStructure); //初始化

ADC_PowerControl(ENABLE); //ADC电源开关, ENABLE或DISABLE

NVIC_ADC_Init(DISABLE,Priority_0); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3

}

//内部方法------------------------------------------------------------------

//3.找下标,最接近的值

static int get_pos(float re) {

//定义入参和第一个电阻值的差值为diff

float diff = abs(re - temp_table[0]);

float temp;

//获取数组长度

int n = sizeof(temp_table)/sizeof(temp_table[0]);

int i, min_idx = 0;

//因为已经将第0个电阻值拿出来比较了,所以从1开始

for(i = 1; i < n; i++) {

temp = abs(re - temp_table[i]);

if (diff > temp) {

diff = temp;

//如果有更小的差值,在获取了值之后,还要将这个值的下标记住

min_idx = i;

}

}

return min_idx;

}

//提供给外部的方法------------------------------------------------------------------

// 初始化

void NTC_Initialize() {

GPIO_config();

ADC_config();

}

// 获取温度值

int NTC_get_temperature() {

u16 adc_value;

float vol,re;

int temperature;

// ADC_CH12 ===> P04 根据15个通道的ADC功能引脚查询 我们使用的是P04脚 所以用的是ADC12

adc_value = Get_ADCResult(ADC_CH12);

//拿到采样值之后,代入公式即可算出电压值

vol = adc_value * 2.5 / 4096;

//拿到电压之后,代入公式即可算出电阻值

re = vol * 10 / (3.3 - vol);

//拿到电阻之后,调用函数即可算出温度 因为温度的下标与实际温度之间相差55,所以需要减去55

temperature = get_pos(re*100)-55;

return temperature;

}

main函数使用

int temperature;

NTC_Initialize(); //调用自写的初始化方法

temperature=NTC_get_temperature(); //调用自写的温度函数

printf("温度temperature:%d \n", (int)temperature);

数组定义

采用表的方式来记录 电阻值和温度的关系。

其中,表中记录的是阻值,下标记录的是温度。可以通过阻值比对,查询出下标,下标就是对应的温度。

● 元素是阻值,注释是温度

● code 关键字作用

○ 定义的数据要放在ROM(程序代码存储区)里面,写入后不能再更改

● code关键字: 放到一个代码存储区 ,换一个地方存放的意思

这个就是 NTC.c里面的temp_table,需要用到时候将这一段复制到 NTC.c中去

u16 code temp_table[]= {

58354, // -55

55464, // -54

52698, // -53

50048, // -52

47515, // -51

45097, // -50

42789, // -49

40589, // -48

38492, // -47

36496, // -46

34597, // -45

32791, // -44

31075, // -43

29444, // -42

27896, // -41

26427, // -40

25034, // -39

23713, // -38

22460, // -37

21273, // -36

20148, // -35

19083, // -34

18075, // -33

17120, // -32

16216, // -31

15361, // -30

14551, // -29

13785, // -28

13061, // -27

12376, // -26

11728, // -25

11114, // -24

10535, // -23

9986, // -22

9468, // -21

8977, // -20

8513, // -19

8075, // -18

7660, // -17

7267, // -16

6896, // -15

6545, // -14

6212, // -13

5898, // -12

5601, // -11

5319, // -10

5053, // -9

4801, // -8

4562, // -7

4336, // -6

4122, // -5

3920, // -4

3728, // -3

3546, // -2

3374, // -1

3211, // 0

3057, // 1

2910, // 2

2771, // 3

2639, // 4

2515, // 5

2396, // 6

2284, // 7

2177, // 8

2076, // 9

1978, // 10

1889, // 11

1802, // 12

1720, // 13

1642, // 14

1568, // 15

1497, // 16

1430, // 17

1366, // 18

1306, // 19

1248, // 20

1193, // 21

1141, // 22

1092, // 23

1044, // 24

1000, // 25

957, // 26

916, // 27

877, // 28

840, // 29

805, // 30

771, // 31

739, // 32

709, // 33

679, // 34

652, // 35

625, // 36

600, // 37

576, // 38

552, // 39

530, // 40

509, // 41

489, // 42

470, // 43

452, // 44

434, // 45

417, // 46

401, // 47

386, // 48

371, // 49

358, // 50

344, // 51

331, // 52

318, // 53

306, // 54

295, // 55

284, // 56

274, // 57

264, // 58

254, // 59

245, // 60

236, // 61

228, // 62

220, // 63

212, // 64

205, // 65

198, // 66

191, // 67

184, // 68

178, // 69

172, // 70

166, // 71

160, // 72

155, // 73

150, // 74

145, // 75

140, // 76

135, // 77

131, // 78

126, // 79

122, // 80

118, // 81

115, // 82

111, // 83

107, // 84

104, // 85

101, // 86

97, // 87

94, // 88

91, // 89

89, // 90

86, // 91

83, // 92

81, // 93

78, // 94

76, // 95

74, // 96

71, // 97

69, // 98

67, // 99

65, // 100

63, // 101

61, // 102

60, // 103

58, // 104

56, // 105

55, // 106

53, // 107

52, // 108

50, // 109

49, // 110

47, // 111

46, // 112

45, // 113

43, // 114

42, // 115

41, // 116

40, // 117

39, // 118

38, // 119

37, // 120

36, // 121

35, // 122

34, // 123

33, // 124

32, // 125

};