外观
电阻检测与显示实验
电路分析
在简易万用表的电阻测量电路上,是通过分压电路来进行检测的,除此之外还涉及COM端控制电路以及红表笔切换电路。具体的电路分析可前往第二章-电路原理分析进行查看。
这里重点要看的是各引脚的分布以及对应实现的功能,实际也就是控制对应的高低电平来实现不同分压电阻值的切换,同时通过ADC引脚来获取电压值最后进行转换即可,注意不可同时打开多个分压电阻,否则电压并联总阻值减少会使计算变复杂。
功能实现
创建工程
- 点击左上方文件、选择新建,选择新建MounRiver工程;
- 对工程进行修改,修改完成后点击“完成”按键,系统会自动生成好工程;
- 创建自己的工程库文件夹,分别创建头文件夹与源文件夹,将之前的库文件包含进来,包括蜂鸣器驱动文件、屏幕驱动文件、长按开关机文件、黑表笔公共端导通控制文件、继电器控制文件等,同时新建1个文件,用于电阻检测。
- 对工程库路径进行包含;
代码实现
电阻检测功能实现起来也非常简单,通过欧姆定律即可,目前电源电压已知,分压电阻的一端已知,分压电路的电压值也可以通过ADC来进行获取,这样通过I=U/R即可换算出被测电阻的阻值;
不过有一点需要注意,此处分压电阻的值是从100R到100K,大家在测量时应该选择一个较为合适的值去进行分压,或者也可以尝试切换分压电阻,去综合得出最终得电阻值。
电阻分压电路不可带电测量,否则如果外部电压超过自身电源电压,会导致损坏且测量不准。
控制分压电阻导通的代码与ADC初始化代码都和之前的案例没有差异,修改对应引脚即可。
初始化相关控制IO
C
#include "Res_Vol_Control.h"
#include "resistor.h"
#include "main.h"
#include "tftshow.h"
#include "comControl.h"
/*
* 函数内容:初始化电阻分压控制IO
* 函数参数:无
* 返回值:无
*/
void Resistor_Con_GPIO(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_WriteBit(GPIOA,GPIO_Pin_3,Bit_SET);
GPIO_WriteBit(GPIOA,GPIO_Pin_4,Bit_SET);
GPIO_WriteBit(GPIOA,GPIO_Pin_5,Bit_SET);
GPIO_WriteBit(GPIOA,GPIO_Pin_6,Bit_SET);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/*
* 函数内容:电阻分压控制IO连接到100R
* 函数参数:无
* 返回值:无
*/
void Resostor_Connect_100R(void)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_3,Bit_RESET);
GPIO_WriteBit(GPIOA,GPIO_Pin_4,Bit_SET);
GPIO_WriteBit(GPIOA,GPIO_Pin_5,Bit_SET);
GPIO_WriteBit(GPIOA,GPIO_Pin_6,Bit_SET);
}
/*
* 函数内容:电阻分压控制IO连接到1K
* 函数参数:无
* 返回值:无
*/
void Resostor_Connect_1K(void)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_3,Bit_SET);
GPIO_WriteBit(GPIOA,GPIO_Pin_4,Bit_RESET);
GPIO_WriteBit(GPIOA,GPIO_Pin_5,Bit_SET);
GPIO_WriteBit(GPIOA,GPIO_Pin_6,Bit_SET);
}
/*
* 函数内容:电阻分压控制IO连接到10K
* 函数参数:无
* 返回值:无
*/
void Resostor_Connect_10K(void)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_3,Bit_SET);
GPIO_WriteBit(GPIOA,GPIO_Pin_4,Bit_SET);
GPIO_WriteBit(GPIOA,GPIO_Pin_5,Bit_RESET);
GPIO_WriteBit(GPIOA,GPIO_Pin_6,Bit_SET);
}
/*
* 函数内容:电阻分压控制IO连接到100K
* 函数参数:无
* 返回值:无
*/
void Resostor_Connect_100K(void)
{
GPIO_WriteBit(GPIOA,GPIO_Pin_3,Bit_SET);
GPIO_WriteBit(GPIOA,GPIO_Pin_4,Bit_SET);
GPIO_WriteBit(GPIOA,GPIO_Pin_5,Bit_SET);
GPIO_WriteBit(GPIOA,GPIO_Pin_6,Bit_RESET);
}
void Init_Resistor_ADC_GPIO(void)
{
ADC_InitTypeDef ADC_InitStructure = {0};
GPIO_InitTypeDef GPIO_InitStructure = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div8); //ADC时钟分频,最大14Mhz, 96/8 = 12M
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_DeInit(ADC1); //复位ADC1
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC1工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //禁止扫描转换模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //禁止连续转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //规则通道组转换,不使用外部触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行转换的通道数
ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 1, ADC_SampleTime_239Cycles5 );
ADC_Cmd(ADC1, ENABLE); //使能ADC1
ADC_ResetCalibration(ADC1); //重置选择ADC1校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位完成
ADC_StartCalibration(ADC1); //开始ADC1校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准完成
}
/*
* 函数内容:得到任意通道的值
* 函数参数:uint8_t ch--通道值
* 返回值:无
*/
uint16_t Get_ADC_Val(uint8_t ch)
{
uint16_t val;
ADC_RegularChannelConfig( ADC1, ch, 1, ADC_SampleTime_239Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
val = ADC_GetConversionValue(ADC1);
ADC_ClearFlag( ADC1, ADC_FLAG_EOC);
return val;
}
uint16_t Get_ADC_Average(uint8_t ch, uint16_t num)
{
uint16_t i = 0,val = 0;
uint32_t sum_val = 0;
uint16_t max_value = 0,min_value = 9999;
for(i =0;i<num;i++)
{
val = Get_ADC_Val(ch);
if(min_value > val){
min_value = val;
}
if(max_value < val){
max_value = val;
}
sum_val = sum_val +val;
}
sum_val = sum_val - max_value - min_value;
sum_val = sum_val / (num - 2);
return sum_val;
}
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
- 在电阻测量任务中,同样是循环读取电压值,然后记录数组取平均值最后换算为电阻值,这里电源电压并不一定就是3.3V,可能会有抖动,需要自行校准,后续也可以尝试加入电压基准源来减少误差。
电阻测量任务
C
static void bubble_sort(float arr[], uint16_t len)
{
uint16_t i = 0, j = 0;
float temp = 0;
for (i = 0; i < len - 1; i++)
{
for (j = 0; j < len - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
/*
* 函数内容:测电阻任务
* 函数参数:无
* 返回值:无
*/
static uint8_t first_in = 0;
static float sum_volValue[100] = {0};
static uint16_t num = 0;
void Resistor_Task(void)
{
float TempVolValue = 0, Vol_Value = 0;
uint16_t Resistor_Value = 0,value_sum = 0,ref_vol_value = 0,i = 0;
if(first_in == 0) //如果是第一次进入电阻测量页面
{
first_in = 1;
RES_VOL_Connect_RES(); //继电器切换到电阻测量端
Connect_GND(); //黑表笔导通到GND
Resostor_Connect_1K(); //默认1K分压
device_parameter.resistor_range = RES_100R_1K; //电阻量程
LCD_ShowChinese(16, 0, "电阻模式", BLACK, WHITE, 32, 0); //显示模式
}
ADC_TempSensorVrefintCmd(DISABLE); //取消内部测量
value_sum = Get_ADC_Average(ADC_Channel_2,200); //测量外部ADC值,取200次平均值
ADC_TempSensorVrefintCmd(ENABLE); //使能内部基准测量
ref_vol_value = Get_ADC_Average(ADC_Channel_Vrefint,100); //测量内部ADC值,取100次平均值
TempVolValue = ((value_sum*1.0f) / ref_vol_value)*1.2f; //换算为电压值
if(TempVolValue<0.01){ //如果是抖动电压
TempVolValue = 0;
}
sum_volValue[num] = TempVolValue; //记录每一个值
num++;
if(num >= 100) //计满100个
{
num = 0;
bubble_sort(sum_volValue,100); //冒泡排序
for(i=10;i<90;i++) //取中间80个
{
Vol_Value = Vol_Value + sum_volValue[i];
}
Vol_Value = Vol_Value / 80.0f; //取80个的平均值
LCD_ShowFloatNum1(0,80,Vol_Value,4,BLACK,WHITE,12); //显示电压值
if(Vol_Value >=3.3f){
Vol_Value = 0;
}
if(device_parameter.resistor_range == RES_0_100R){
LCD_ShowString(0,56,"0 ~ 100R",BLACK, WHITE, 16, 0); //显示量程
Resistor_Value = (uint16_t)(100 * Vol_Value)/(3.34f-Vol_Value);
LCD_ShowIntNum(72,48,Resistor_Value,4,BLACK,WHITE,32); //显示电压值
LCD_ShowChar(142,48,'R',BLACK, WHITE, 32, 0); //显示单位
}
else if(device_parameter.resistor_range == RES_100R_1K)
{
LCD_ShowString(0,56,"100R~ 1K",BLACK, WHITE, 16, 0); //显示量程
Resistor_Value = (uint16_t)(1000 * Vol_Value)/(3.34f-Vol_Value);
LCD_ShowIntNum(72,48,Resistor_Value,4,BLACK,WHITE,32); //显示电压值
LCD_ShowChar(142,48,'R',BLACK, WHITE, 32, 0); //显示单位
}
else if(device_parameter.resistor_range == RES_1K_10K)
{
LCD_ShowString(0,56,"1K ~ 10K",BLACK, WHITE, 16, 0); //显示量程
Resistor_Value = (uint16_t)(10* Vol_Value)/(3.3f-Vol_Value);
LCD_ShowIntNum(72,48,Resistor_Value,4,BLACK,WHITE,32); //显示电压值
LCD_ShowChar(142,48,'K',BLACK, WHITE, 32, 0); //显示单位
}
else if(device_parameter.resistor_range == RES_10K_100K)
{
LCD_ShowString(0,56,"10K~100K",BLACK, WHITE, 16, 0); //显示量程
Resistor_Value = (uint16_t)(100 * Vol_Value)/(3.3f-Vol_Value);
LCD_ShowIntNum(72,48,Resistor_Value,4,BLACK,WHITE,32); //显示电压值
LCD_ShowChar(142,48,'K',BLACK, WHITE, 32, 0); //显示单位
}
for(i=0;i<100;i++) //清除计数
{
sum_volValue[i] = 0;
}
Vol_Value = 0;
}
}
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
87
88
89
90
91
92
93
94
95
96
97
98
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
87
88
89
90
91
92
93
94
95
96
97
98
- 最后在主函数中调用该电阻测量任务,当开机后开始不断进行获取计算,注意这里就有使用设备参数结构体,比如当前所处模式,以及电阻分压值大小等。该案例并没有切换分压值大小,后续可以在ec11的正反转中切换,也可以尝试直接自动切换做自动量程。
主函数
c
#include "Res_Vol_Control.h"
#include "debug.h"
#include "beep.h"
#include "comControl.h"
#include "ec11.h"
#include "powerswitch.h"
#include "resistor.h"
#include "tftinit.h"
#include "tftshow.h"
#include "main.h"
/* Global typedef */
/* Global define */
/* Global Variable */
/*********************************************************************
* @fn main
*
* @brief Main program.
*
* @return none
*/
struct DEVICE_PARAMETER device_parameter;
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
SystemCoreClockUpdate();
Delay_Init();
device_parameter.device_page = RESISTOR_PAGE;
Init_BEEP_GPIO(); //蜂鸣器引脚初始化
Init_Com_GPIO(); //黑表笔公共端控制引脚初始化
Init_EC11_GPIO(); //EC11旋转引脚初始化
Init_Power_Con_GPIO(); //电源控制引脚初始化
Init_RES_VOL_Con_GPIO();//继电器引脚初始化
Resistor_Con_GPIO(); //初始化电阻分压控制IO
Init_Resistor_ADC_GPIO();//初始化电阻采样ADC
LCD_Init(); //LCD初始化
LCD_Fill(0, 0, LCD_W, LCD_H, WHITE);
while(1)
{
key_task();
if(device_state == DEVICE_TURN_ON)
{
if(device_parameter.device_page == RESISTOR_PAGE){
Resistor_Task();
}
}
}
}
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
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
TIP
烧录代码后,接上万用表表笔到电阻测量端与COM端,进行测试,看一下实际电阻值是否正常。
在实际测试过程中,电压值与真实值肯定会有偏差,此时需要通过增加显示空载的电压值,然后去校准代码中的参数,有可能不是3.3或你的参考电压本身就不准,这些都是需要调整的。
源码&USB下载工具等软件,均在[gitee资料中](https://gitee.com/chen11232/simple-digital-multimeter)