使用Platformio平台的libopencm3开发框架来开发STM32G0,以下使用ADC进行NTC温度采集。

1 新建项目

  • 建立ntc_temp项目

在PIO的Home页面新建项目,项目名称ntc_temp,选择开发板为 MonkeyPi_STM32_G070RB,开发框架选择libopencm3;

  • 项目建立完成后在src目录下新建main.c主程序文件;
  • 修改下载和调试方式,这里开发板使用的是DAPLink仿真器,因此修改platformio.ini文件如下:
1
2
upload_protocol = cmsis-dap
debug_tool = cmsis-dap
  • 为了能使用printf的浮点功能,可以加入如下配置:
1
2
build_flags = 
-Wl,-u,_printf_float

2 编写程序

2.1 ADC设置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void adc_setup()
{
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_ADC);

gpio_mode_setup(GPIOA,GPIO_MODE_ANALOG,GPIO_PUPD_NONE,GPIO0);

adc_power_off(ADC1);
adc_set_clk_prescale(ADC1,ADC_CCR_PRESC_DIV2);
adc_set_single_conversion_mode(ADC1);
adc_set_right_aligned(ADC1);
adc_set_sample_time_on_all_channels(ADC1,ADC_SMPTIME_160DOT5);
uint8_t channel = 0;
adc_set_regular_sequence(ADC1,1,&channel);
adc_set_resolution(ADC1,ADC_CFGR1_RES_12_BIT);

adc_power_on(ADC1);

delay_ms(10);

}

ADC设置按照之前文章介绍的方法设置PA0为ADC输入;

2.2 ADC读取
1
2
3
4
5
uint16_t adc_sample()
{
adc_start_conversion_regular(ADC1);
return adc_read_regular(ADC1);
}
2.3 ADC与NTC的温度转换
  • 首先根据所选的NTC规格的温度-电阻对应表得到其ADC值的关系表:

这里的NTC分压电阻为10K,ADC分辨率为12位,因此ADC采集值为:(NTC电阻 x 4095) ÷ (NTC电阻 + 10K),即可得到如下所示的表格:

在EXCEL中计算出ADC采样数值-温度对应表,为了简单ADC进行取整,就可以得到电阻-55到125摄氏度的ADC对应表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const uint16_t ntcDATA[] = {
4040,4038,4035,4031,4027,4023,4018,4013,4007,4001,3994,3987,3980,3972,3964,3956,

3947,3937,3928,3917,3907,3896,3884,3872,3860,3847,3833,3819,3804,3789,3773,3757,

3740,3722,3703,3684,3664,3644,3622,3600,3577,3553,3528,3502,3475,3448,3419,3390,

3360,3329,3297,3264,3230,3195,3160,3123,3086,3048,3010,2970,2930,2889,2848,2806,

2763,2720,2676,2633,2588,2544,2499,2454,2408,2363,2317,2272,2226,2181,2136,2091,

2048,2001,1957,1913,1869,1826,1783,1741,1699,1658,1617,1576,1537,1498,1459,1422,

1385,1348,1312,1277,1243,1209,1176,1144,1112,1081,1051,1022,993,965,937,910,

884,859,834,810,786,764,741,720,699,679,659,639,621,602,585,568,

551,535,519,504,490,475,461,448,435,422,410,398,387,376,365,355,

345,335,325,316,307,299,290,282,274,267,259,252,245,239,232,226,

220,214,208,202,197,192,187,182,177,172,168,163,159,155,151,146,

143,139,135,132,129
};
  • 然后根据表格获取温度,即每个ADC对应的索引即为温度值,如4040为索引0,对应第一个温度-55℃;
  • 表格中数据是有序的,因此这里可以使用二分法查找,对于两个数中间值则取其相近的那个值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

#define TEMP_HEADER_VALUE -55 //the first temp in table

#define ITEM_NUM(items) sizeof(items) / sizeof(items[0])

/**
* @brief search the table, return a midium value if not found
*
* @param table the data to search
* @param len the table length
* @param up if data is min to max
* @return int32_t -1 -> if not found
*/
int32_t bsearch_ret_mid(const uint16_t *table, uint16_t len, bool up, uint16_t key)
{
uint16_t bot;
uint16_t mid;
uint16_t check;
uint16_t top;

if (len == 0) {
return -1;
}

if (up) {
//the first data will be min
if (key < table[0]) {
return -1;
}

//bigger then the last data
if (key > table[len - 1]) {
return -1;
}
} else {
if (key > table[0]) {
return -1;
}

if (key < table[len - 1]) {
return -1;
}
}

bot = 0;
top = len - 1;

if (up) {
while (bot < top) {
mid = top - (top - bot) / 2;

if (key < table[mid]) {
top = mid - 1;
} else {
bot = mid;
}
}
} else {
while (bot < top) {
mid = top - (top - bot) / 2;

if (key > table[mid]) {
top = mid - 1;
} else {
bot = mid;
}
}
}

if (key == table[top]) {
return top;
}

//not equal the data in table
if (up) {
if (key > table[top]) {
return top;
}
} else {
if (key < table[top]) {
return top;
}
}

return -1;
}
  • 然后根据索引得到温度:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

//get temperature , x10
int16_t ntc2tem(uint16_t adc)
{
int32_t index = 0;
int16_t temperature = 0;

index = bsearch_ret_mid(ntcDATA, ITEM_NUM(ntcDATA),false,adc);

//max, the first value
if(index==0){
temperature = TEMP_HEADER_VALUE*10;
}
//min, the last value
else if(index>= ITEM_NUM(ntcDATA)){
temperature = 10*(TEMP_HEADER_VALUE + ITEM_NUM(ntcDATA));
}
else{
//just get integer number
// temperature = TEMP_HEADER_VALUE + index;

//get approximation data
temperature = TEMP_HEADER_VALUE + index;

//at middle
temperature = (temperature+1)*10 - 10.0 * (adc-ntcDATA[index+1])/(ntcDATA[index]-ntcDATA[index+1]);
}

return temperature;

}

表格中的温度是1度进行变化的,如果需要稍微精确的,这里在1度中间的值近似看做线性进行计算;

这里为了减小计算误差,先对其扩大十倍计算,显示时候再转为小数:

1
2
3
4
5
6
uint16_t adc = adc_sample();

int16_t temp_int = ntc2tem(adc);
float temp = temp_int/10.0;

printf("adc: %d, temp: %.1f\r\n",adc, temp);

3 连接硬件并测试

3.1 连接硬件

按照如下图,将NTC和10K电阻连接到PA0脚:

3.2 测试

打开串口,当手放在NTC上可以看到温度变化: