
【电压电流表训练营】基于CW32的电压电流表
简介
【电压电流表训练营】基于立创·地文星CW32的数字电压电流表
简介:【电压电流表训练营】基于立创·地文星CW32的数字电压电流表开源协议
:GPL 3.0
描述
一、设计背景
ADC(Analog-to-Digital Converter,即模拟-数字转换器)是电子系统中不可或缺的关键组件,它将连续的模拟信号转换为数字信号,为数字处理和分析提供了可能。ADC在信号转换、测量与数据采集、控制系统输入以及通信与信号处理等方面发挥着重要作用,其广泛的应用促进了各行业电子设备的智能化和精确控制,是推动现代科技进步的关键因素之一。
数字电压电流表结合了ADC的技术与电路测量原理,能够精确地将模拟的电压电流信号转换为数字显示,便于电子工程师直观读取和分析。这种设备不仅提高了电路测量的准确性和效率,还帮助工程师更好地理解电路行为,是进行电子设计和故障排查的得力助手,对电子工程师的工作具有重要的辅助作用。在产品应用上,数字电压电流表确保了电路设计的准确性和安全性,同时也为产品的质量控制和后期维护提供了有力支持。
台式数字万用表(Agilent 34401A)
二、硬件设计
1、供电电路
选择最高输入电压高达40V的SE8550K2 LDO(低压差线性稳压器)作为电源。
2、电压采样电路
本项目设计分压电阻为220K+10K,因此分压比例为22:1(ADC_IN11),在ADC参考电压为1.5V的情况下,可测量的最大电压为34.5V(1.5V * 23)。
3、电流采样电路
本项目采用低侧电流采样电路进行电流检测,采样电路的低侧与开发板表头接口共地。
本项目设计的采样电流为3A,选择的采样电阻(R0)为100mΩ。通过测量采样电阻两端电压(ADC_IN12),经过计算得到对应流入的电流大小。当通过采样电阻的电流大小为10mA时,采集到电阻两端电压为1mV。
4、数码管显示
本项目采用了数码管作为显示单元。
在本项目中使用了两颗0.28寸的三位共阴数码管作为显示器件,相较于显示屏,数码管在复杂环境中拥有更好的识别度,可以根据实际使用环境的需求,改为更小的限流电阻实现更高的数码管亮度。
5、电压、电流模拟
在该项目的官方例程中设计了电压、电流的模拟测量、标定电路,本工程由于无可调电源可用,全程的学习、测试、标定均在模拟电路上进行。电压、电流的测量均是通过采集相应的电压值,集合电路计算出测量结果,所以在模拟电路中,采用电位器实现相应的模拟。
6、核心主控板--立创·地文星CW32F030C8Tx开发板
CW32在本项目中的重要优势
宽工作温度:-40105℃的温度范围5.5V (STM32仅支持3.3V系统)
宽工作电压:1.65V
超强抗干扰:HBM ESD 8KV 全部ESD可靠性达到国际标准最高等级(STM32 ESD2KV)
本项目重点-更好的ADC:12位高速ADC 可达到±1.0LSB INL 11.3ENOB 多种Vref参考电压... ...(STM32仅支持VDD=Vref)
稳定可靠的eFLASH工艺。(Flash0等待)
三、软件设计
1、按键
本次实验采用软件消抖,消抖函数的编写思路为:设置按键检测标志位,当单片机检测到按键按下,相应IO口处为低电平时,将标志位置1;在后续的条件判断中如果标志位为1,则检测按键是否松开,若已松开则完成本次判断,认为按键已经按下过一次。这种方式可以不用延时判断,节约了软件资源。
按键功能:
K1:切换电压电流表的模式:
模式0:电压电流同测,上方橙色数码管显示电压,下方红色数码管显示电流
模式1:电压5V校准
模式2:电压10V校准
模式3:电流0.5A(对应模拟电路上分压0.05V)校准
模式4:电流1.5A(对应模拟电路上分压0.15V)校准
K2:执行校准模式下的校准流程,完成当前校准后,点亮白色LED灯进行提醒
K3:回到模式0(测量模式)
/**
* @brief 按键扫描函数
* @param void
* @return void
*/
void key_scan(void)
{
//K1
if(GPIO_ReadPin(GPIO_K1,PIN_K1) == GPIO_Pin_RESET)
{
k1_flag = 1;
}
if(k1_flag == 1)
{
if(GPIO_ReadPin(GPIO_K1,PIN_K1) == GPIO_Pin_SET)
{//松开时执行功能以达消抖目的
k1_flag = 0;
led_flag = 0;
mode_flag = (mode_flag + 1) % 5; //更换模式
}
}
//K2
if(GPIO_ReadPin(GPIO_K2,PIN_K2) == GPIO_Pin_RESET)
{
k2_flag = 1;
}
if(k2_flag == 1)
{
if(GPIO_ReadPin(GPIO_K2,PIN_K2) == GPIO_Pin_SET)
{//松开时执行功能以达消抖目的
// 校准
if(mode_flag==1)
{
X05=Mean_Value_Filter(Voltage_Buffer_High,ADC_SAMPLE_SIZE);
save_calibration();ComputeK();data_refresh();//mode_flag=2;
}
if(mode_flag==2)
{
X10=Mean_Value_Filter(Voltage_Buffer_High,ADC_SAMPLE_SIZE);
save_calibration();ComputeK();data_refresh();//mode_flag=0;
}
if(mode_flag==3)
{
IX05=Mean_Value_Filter(Current_Buffer_Num,ADC_SAMPLE_SIZE);
save_calibration();ComputeK();data_refresh();//mode_flag=4;
}
if(mode_flag==4)
{
IX15=Mean_Value_Filter(Current_Buffer_Num,ADC_SAMPLE_SIZE);
save_calibration();ComputeK();data_refresh();//mode_flag=0;
}
k2_flag = 0;
led_flag = 1; //LED灯亮起,以表示当前校准完成
if(mode_flag==0)led_flag = 0; //在测量模式下,LED灯保持熄灭
}
}
//K3
if(GPIO_ReadPin(GPIO_K3,PIN_K3) == GPIO_Pin_RESET)
{
k3_flag = 1;
}
if(k3_flag == 1)
{
if(GPIO_ReadPin(GPIO_K3,PIN_K3) == GPIO_Pin_SET)
{//松开时执行功能以达消抖目的
// 回到模式0
k3_flag = 0;
led_flag = 0;
mode_flag = 0;
}
}
}
2、数码管显示
数码管的引脚分为段码引脚、位码引脚,使用的数码管发光二极管为共阴设计,通过将相应IO口设为高电平,点亮相应的LED,,再将位码引脚设为低电平(选通相应的数码管)。动态显示时,每个数码管显示相应内容3 ms,轮番点亮,利用人眼的视觉残留,形成“所有数码管常亮”的效果
显示的数字相应段码,可通过将段码引脚从高排到低,确定对应亮起的LED段,在将二进制的段码转为十六进制。
数字“2”的段码
//数码管断码表,从高位到低分别为:E D DP C G A F B----(1表点亮该段LED,共阴码)
const unsigned smg_duanma[12] = {0xd7,0x11,0xcd,0x5d,0x1B,0x5e,0xde,0x15,0xdf,0x5f,0xd3,0x9f}; //0123456789UA
//显示内容缓存区
volatile unsigned char display[6] = {0xd7,0x11,0xcd,0x5d,0x1B,0x5e};
typedef struct
{
GPIO_TypeDef *GPIOx;
uint32_t Pins;
}smg_type;
smg_type smg[6] = {{CW_GPIOA,GPIO_PIN_8},{CW_GPIOA,GPIO_PIN_11},{CW_GPIOA,GPIO_PIN_12},{CW_GPIOA,GPIO_PIN_15},{CW_GPIOB,GPIO_PIN_3},{CW_GPIOB,GPIO_PIN_4}};
/******************************************************************
* 函 数 名 称:smg_disp
* 函 数 说 明:依次点亮每个数码管
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:
* 备 注:无
******************************************************************/
void smg_disp(void)
{
static unsigned char smg_addr = 0; //记录点亮的数码管位置,实现轮番3ms的显示
unsigned char i = 0;
GPIO_WritePin(smg[smg_addr].GPIOx,smg[smg_addr].Pins,GPIO_Pin_SET); //熄灭当前的数码管
smg_addr = (smg_addr + 1) % 6; //将点亮位置移至下一位
//按照段码设置段码引脚
for(i=0;i<8;i++)
{
if(((display[smg_addr]>>i)&0x01) == 0x01)
{
GPIO_WritePin(CW_GPIOA, GPIO_PIN_0<= ADC_SAMPLE_SIZE) //采样 20 次后从 0 开始继续
{
adc_count = 0;
}
}
3、均值滤波
均值滤波也称为线性滤波,其采用的主要方法为邻域平均法。线性滤波的基本原理是用均值代替原图像中的各个像素值,即对待处理的当前像素点(x,y),选择一个模板,该模板由其近邻的若干像素组成,求模板中所有像素的均值,再把该均值赋予当前像素点(x,y),作为处理后图像在该点上的灰度g(x,y),即g(x,y)=∑f(x,y)/m,m为该模板中包含当前像素在内的像素总个数。
这本是数字图像处理的一种方法,但也可以用在数字电压电流表的ADC采样数据上。选取二十次的ADC采样值存储在一个数组中,然后去除掉数组中的最大值和最小值后再取平均,得到的值作为结果显示,这样可以较大程度获得准确的、不易波动的数据。
uint32_t Mean_Value_Filter(uint16_t *value, uint32_t size) //均值滤波
{
uint32_t sum = 0;
uint16_t max = 0;
uint16_t min = 0xffff;
int i;
for(i = 0; i < size; i++) //遍历数组找到最大值和最小值
{
sum += value[i];
if(value[i] > max)
{
max = value[i];
}
if(value[i] < min)
{
min = value[i];
}
}
sum -= max + min; //减去最大和最小值后求平均
sum = sum / (size - 2);
return sum;
}
4、标定
标定是通过测量标准器的偏差来补偿仪器系统误差,从而改善仪器或系统准确度、精度的操作。为了提高电压电流表在测量时的测量精度和准确度,需要对电压电流进行标定校准。
常见的标定原理如下:
假设一个采样系统,AD部分可以得到数字量,对应的物理量为电压(或电流);
若在“零点”标定一个AD值点Xmin,在“最大处”标定一个AD值点Xmax,根据“两点成一条直线”的原理,可以得到一条由零点和最大点连起来的一条直线,这条直线的斜率k很容易求得,然后套如直线方程求解每一个点X(AD采样值),可以得到该AD值对应的物理量(电压值):
上图中的斜率k:
k =(Ymax-Ymin)/(Xmax-Xmin)
(因为第一点为“零点”,故上面的Ymin = 0)
所以,上图中任一点的AD值对应的物理量:
y = k×(Xad- Xmin)+0
上面的算法只是在“零点”和“最大点”之间做了标定,如果使用中间的AD采样值会带来很大的对应物理量的误差,解决的办法是多插入一些标定点。
如下图,分别插入了标定点(x1,y1)、(x2,y2)、(x3,y3)、(x4,y4) 四个点:
这样将获得不再是一条直线,而是一条“折现”(相当于分段处理),若欲求解落在x1和x2之间一点Xad值对应的电压值:
y = k×(Xad– X1)+ y1
由上看出,中间插入的“标定点”越多,得到物理值“精度”越高。
在电压电流表测量可以使用“电压电流标定板”“万用表”等配合适合,对采集的电压电流进行标定处理。标定点越多,测量越精确。
//在家里无专用可调电源使用,使用的12V电源适配器供电,因此改为5V与10V校准
//5V与10V 校准
unsigned int X05=0;
unsigned int X10=0;
unsigned int Y10=10;
unsigned int Y05=5;
float K; //斜率
//0.5A与1.5A 校准
unsigned int IX05=0;
unsigned int IX15=0;
unsigned int IY15=150;
unsigned int IY05=50;
float KI; //斜率
/******************************************************************
* 函 数 名 称:ComputeK
* 函 数 说 明:计算斜率
* 函 数 形 参:无
* 函 数 返 回:无
* 作 者:
* 备 注:无
******************************************************************/
void ComputeK(void)
{
//计算的是第二段的斜率
K=(Y10-Y05);
K=K/(X10-X05);
KI=(IY15-IY05);
KI=KI/(IX15-IX05);
}
void data_refresh(void)
{//将采集到的数据集合标定数据进行计算
float t,KT1;
if(data_refresh_flag == 1)
{
data_refresh_flag = 0;
Voltage_Buffer = Mean_Value_Filter(Voltage_Buffer_High,ADC_SAMPLE_SIZE);
Current_Buffer = Mean_Value_Filter(Current_Buffer_Num,ADC_SAMPLE_SIZE);
if(Voltage_Buffer>=X05)
{
t=Voltage_Buffer-X05;
Voltage_Buffer=(K*t+Y05)*1000;}
else
{
KT1=5000;
KT1=KT1/X05;
Voltage_Buffer=KT1*Voltage_Buffer;
}
// 四舍五入
if(Voltage_Buffer % 10 >= 5)
{
Voltage_Buffer = Voltage_Buffer / 10 + 1; //10mV为单位
}
else
{
Voltage_Buffer = Voltage_Buffer / 10;
}
if(Current_Buffer>=IX05)
{
t=Current_Buffer-IX05;
Current_Buffer=(KI*t+IY05)*10;
}
else
{
KT1=500;
KT1=KT1/IX05;
Current_Buffer=KT1*Current_Buffer;
}
if(Current_Buffer % 10 >= 5)
{
Current_Buffer = Current_Buffer / 10 + 1;
}
else
{
Current_Buffer = Current_Buffer / 10;
}
smg_data_handle(Voltage_Buffer,Current_Buffer);
/*
R = 100mr
10ma = mv/R/10=mv/0.1/10 = mv
*/
}
}
四、实物展示
五、测量展示
1、电压测量
2、“电流测量”
数码管显示的电流示数为将测量到的电压值按1 mV“对应”10 mA的转化关系对应的“电流示数”。
六、演示视频
设计图

BOM


评论