外观
综合案例实验
思路分析
在前面的课程中,已经将简易万用表项目的各模块电路以及代码都写好了,综合案例其实就是将之前分散的代码进行综合即可,主要是通过设备参数结构体来进行描述与实现的。
总体可分为3个页面,电阻、电流、电压测量页面,相关页面参数可以使用ec11来进行切换,同时蜂鸣器配合进行鸣叫提醒,其中电阻测量又可以延申出蜂鸣档以及二极管档测量。
功能实现
- 点击左上方文件、选择新建,选择新建MounRiver工程;
- 对工程进行修改,修改完成后点击“完成”按键,系统会自动生成好工程;
- 创建自己的工程库文件夹,将之前的库文件全部包含进来,这里新增一个myADC文件,用于将之前三个电路中的ADC初始化函数综合在一起。
- 对工程库路径进行包含;
代码实现
- 在综合案例代码中,并没有太多要改动的地方,只是将以前各个引脚初始化函数合并放置在myADC中。
ADC文件
c
#include "myADC.h"
static uint16_t Calibrattion_Val = 0;
/*
* 函数内容;初始化ADC采集相关引脚
* 函数参数:无
* 返回值:无
*/
void Init_ADC_GPIO(void)
{
ADC_InitTypeDef ADC_InitStructure = {0};
GPIO_InitTypeDef GPIO_InitStructure = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div8); //ADC时钟分频,最大14Mhz, 96/8 = 12M
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|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_Cmd(ADC1, ENABLE); //使能ADC1
ADC_BufferCmd(ADC1, DISABLE); //disable buffer
ADC_ResetCalibration(ADC1); //重置选择ADC1校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位完成
ADC_StartCalibration(ADC1); //开始ADC1校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准完成
Calibrattion_Val = Get_CalibrationValue(ADC1);
ADC_BufferCmd(ADC1, ENABLE); //enable buffer
}
/*
* 函数内容;得到对应ADC通道值
* 函数参数:无
* 返回值:无
*/
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);
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;
}
/*
* 函数内容;得到ADC采样值,经过校准后的
* 函数参数:无
* 返回值:无
*/
uint16_t Get_ConversionVal(uint16_t val)
{
if((val + Calibrattion_Val) < 0|| val==0)
return 0;
if((Calibrattion_Val + val) > 4095|| val==4095)
return 4095;
return (val + Calibrattion_Val);
}
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;
}
}
}
}
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
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
- 通过EC11旋转编码器单机进行切换界面,这里在EC11中断服务函数中进行代码汇总。
EC11中断服务函数
c
/*
* 函数内容:外部中断线5~9中断处理函数
* 函数参数;无
* 返回值:无
*/
void EXTI9_5_IRQHandler(void)
{
static uint8_t cnt = 0; //判断是否先经过下降沿触发中断
static uint8_t B_level_old = 0; //B相上一次电平
uint8_t B_level_now = 0; //B相当前电平
if(EXTI_GetITStatus(EXTI_Line7)!=RESET) //如果是中断线7触发中断
{
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_7) == RESET){ //如果是A相PA7下降沿触发中断
cnt++; //已经触发了一次中断;
B_level_old = 1; //默认B相为高
if(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_4) == RESET){ //如果为低
B_level_old = 0;
}
}
else if((GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_7) == SET) && (cnt == 1)){ //如果是A相PA7上升沿触发中断
cnt = 0;
B_level_now = GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_4);
if((B_level_old == 1) && (B_level_now == 0)){
//正转
if(device_parameter.device_page == RESISTOR_PAGE)
{
switch(device_parameter.resistor_range)
{
case RES_0_100R:
device_parameter.resistor_range = RES_100R_1K;
Resostor_Connect_1K();
break;
case RES_100R_1K:
device_parameter.resistor_range = RES_1K_10K;
Resostor_Connect_10K();
break;
case RES_1K_10K:
device_parameter.resistor_range = RES_10K_100K;
Resostor_Connect_100K();
break;
case RES_10K_100K:
device_parameter.resistor_range = RES_0_100R;
Resostor_Connect_100R();
break;
default:
Resostor_Connect_1K();
break;
}
}
}
else if((B_level_old == 0) && (B_level_now == 1)){
//反转
if(device_parameter.device_page == RESISTOR_PAGE)
{
switch(device_parameter.resistor_range)
{
case RES_0_100R:
device_parameter.resistor_range = RES_10K_100K;
Resostor_Connect_100K();
break;
case RES_100R_1K:
device_parameter.resistor_range = RES_0_100R;
Resostor_Connect_100R();
break;
case RES_1K_10K:
device_parameter.resistor_range = RES_100R_1K;
Resostor_Connect_1K();
break;
case RES_10K_100K:
device_parameter.resistor_range = RES_1K_10K;
Resostor_Connect_10K();
break;
default:
Resostor_Connect_1K();
break;
}
}
}
}
EXTI_ClearITPendingBit(EXTI_Line7); /* Clear Flag */
}
}
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
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
- 在电阻测量中,可以延申出蜂鸣档测量与二极管档测量,这里以蜂鸣器作为演示,蜂鸣档其实就是红黑表笔之前电阻很小,通常是小于10R,此时近似短路,蜂鸣器鸣叫,注意由于电阻较小,推荐使用100R分压电阻进行测量,实际代码与电阻测量一致。
EC11中断服务函数
c
/*
* 函数内容:测通断任务
* 函数参数:无
* 返回值:无
*/
static float sum_BuzValue[100] = {0};
static uint16_t BuzNum = 0;
void Buzzing_Task(void)
{
float TempVolValue = 0, Vol_Value = 0;
char showData[32]={0};
uint16_t Resistor_Value = 0,value_sum = 0,ref_vol_value = 0,i = 0;
if(device_parameter.Buzzing_first_in == 0) //如果是第一次进入电阻测量页面
{
device_parameter.Buzzing_first_in = 1;
RES_VOL_Connect_RES(); //继电器切换到电阻测量端
Connect_GND(); //黑表笔导通到GND
Resostor_Connect_100R(); //默认100R分压
device_parameter.resistor_range = RES_0_100R; //电阻量程
}
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_BuzValue[BuzNum] = TempVolValue; //记录每一个值
BuzNum++;
if(BuzNum >= 100) //计满100个
{
BuzNum = 0;
bubble_sort(sum_BuzValue,100); //冒泡排序
for(i=10;i<90;i++) //取中间80个
{
Vol_Value = Vol_Value + sum_BuzValue[i];
}
Vol_Value = Vol_Value / 80.0f; //取80个的平均值
if(Vol_Value >= 3.3f){
sum_BuzValue[89] = 0;
sum_BuzValue[10] = 0;
}
//LCD_ShowFloatNum1(0,110,Vol_Value,4,BLACK,WHITE,12); //显示电压值
LCD_ShowString(113, 49, (uint8_t *)" 0-100R", BLACK, WHITE, 12, 0);//显示量程
Resistor_Value = (uint16_t)(100 * Vol_Value)/(3.34f-Vol_Value);
if(Resistor_Value < 20){
Resistor_Value = (uint16_t)(100 * Vol_Value)/(3.34f-Vol_Value);
sprintf(showData,"%04dR ",Resistor_Value);
LCD_ShowString(8, 64, (uint8_t *)showData, BLACK, WHITE, 32, 0);//显示电压值
Open_BEEP();
}
else{
Resistor_Value = (uint16_t)(100 * Vol_Value)/(3.34f-Vol_Value);
sprintf(showData," OL.");
LCD_ShowString(8, 64, (uint8_t *)showData, BLACK, WHITE, 32, 0);//显示电压值
Close_BEEP();
}
Resistor_Value = (uint16_t)(100 * sum_BuzValue[89])/(3.34f-Vol_Value);
sprintf(showData,"%6d",Resistor_Value);
LCD_ShowString(113, 79, (uint8_t *)showData, BLACK, WHITE, 16, 0);//显示最大值
Resistor_Value = (uint16_t)(100 * sum_BuzValue[10])/(3.34f-Vol_Value);
sprintf(showData,"%6d",Resistor_Value);
LCD_ShowString(113, 111, (uint8_t *)showData, BLACK, WHITE, 16, 0);//显示最小值
for(i=0;i<100;i++) //清除计数
{
sum_BuzValue[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
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
- 最后在主函数中根据标志位进行页面显示。
EC11中断服务函数
c
#include "Res_Vol_Control.h"
#include "debug.h"
#include "beep.h"
#include "comControl.h"
#include "ec11.h"
#include "electricity.h"
#include "powerswitch.h"
#include "resistor.h"
#include "tftinit.h"
#include "tftshow.h"
#include "voltage.h"
#include "myADC.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(); //延时初始化
Init_BEEP_GPIO(); //蜂鸣器引脚初始化
Init_Com_GPIO(); //黑表笔COM端口控制柜初始化
Init_EC11_GPIO(); //EC11旋转引脚初始化
Init_Power_Con_GPIO(); //电源控制引脚初始化
Init_RES_VOL_Con_GPIO(); //继电器控制引脚初始化
Resistor_Con_GPIO(); //初始化电阻分压控制IO
Init_ADC_GPIO(); //ADC采集相关引脚初始化
LCD_Init(); //LCD显示屏幕初始化
LCD_Fill(0, 0, LCD_W, LCD_H, WHITE); //清屏
device_parameter.device_page = VOLTAGE_PAGE; //默认是测电压页面
device_parameter.Voltage_first_in = 0;
while(1)
{
key_task();
if(device_state == DEVICE_TURN_ON)
{
if(device_parameter.device_page == VOLTAGE_PAGE) //当前是测电压页面
{
Voltage_Task();
}
else if(device_parameter.device_page == RESISTOR_PAGE) //当前是测电阻页面
{
Resistor_Task();
}
else if(device_parameter.device_page == ELECTRICITY_PAGE) //当前是测电流页面
{
Electricity_Task();
}
else if(device_parameter.device_page == BUZZING_PAGE) //当前是测通断页面
{
Buzzing_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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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