项目经历:基于TM4C LaunchPad的电能质量分析仪

一、任务要求

设计一个电能分析仪和一个测试用三相信号源,能实现以下功能。

1.测量各项电能质量参数,包括:三相电压、三相电流、频率、有功、无
功、视在功率,功率因数、电压偏差、三相电压谐波、三相电流谐波、电压不平衡度、电流不平衡度。
2.在 LCD 上显示各测量值和电压和电流的频谱图。
3.与 PC 机通过无线通信连接,将测量数据传到串口助手上显示。
4.设计一个测试用三相信号源,用 3 路 PWM 模拟三相电压信号, 3 路 PWM模拟三相电流信号。(这个要求在本次项目中鸽了)

二、实现思路

0.参考博文

基于TM4C LaunchPad的电能质量分析仪

1.思路概述

本次采用的方案为:
通过ADC采样获得10个周期内的三相电流和电压值,记录在6个数组中,并对该十个数组中的数据进行计算获得大部分目标参数;
通过定时器计数捕获的方式测量 信号频率;
蓝牙及LCD等功能的思路不难,不在此进行阐述

2.ADC采样

利用单个ADC6个通道分别采样三组电压电流瞬时值并记录在原始数据数组中,当记录10组后进行相关计算及下一组记录(时序安排见“4.数据运算的时序设计”)

3.频率测量

设置两个计时器,计时器1(利用外部方波触发)周期计时2秒,计时器2记录输入信号上升沿个数,计算信号频率。

参考博文:TIVA 123GXL的边沿计数模式测量低频PWM

4.数据运算的时序设计

使用两个定时器,每两秒将flag “two_s_judge_calculate”和flag “two_s_judge_bluetooth”置1;每10s秒将flag “ten_s_judge”置1;

adc一直运行采样程序并实时记录在原始数据数组中,当10组采样完毕时将flag “data_get_ready”置1;

在while(1)中一直监视flag “data_get_ready”,当置1时将原始数据数组中的数据进行计算并得到初步计算的数据并记录在初步计算结果数组中,将flag “data_get_ready”置0;

在flag “data_get_ready”置0后判断flag “two_s_judge_calculate”是否为1;若为1,计算初步计算结果数组平均值并将结果记录在变量目标输出量中,将flag “two_s_judge_calculate”置0

在while(1)中一直监视flag “two_s_judge_bluetooth”,当其置1时,将目标输出量通过蓝牙发送。

三、实现代码

1.ADC采样

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "driverlib/timer.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_adc.h"
#include "driverlib/adc.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include <math.h>

uint32_t pui32ADC0Value[8] = {0};
uint32_t pui32ADC1Value[8] = {0};
extern float U_a[640];
extern float U_b[640];
extern float U_c[640];

extern float I_a[640];
extern float I_b[640];
extern float I_c[640];
extern int data_get_ready;
extern int i_num;
extern int u_num;



void ADC0Sequence0Handler(void) {

	float offset = 1.65;
//	float ratio1 = 333.5;
//	float ratio2 = 0.93;
//	float ratio_i_b = 0.93;
//	float ratio_i_c = 0.93;
	float ratio1 = 334.2;
	float ratio2 = 1.254901960;
	float ratio_i_b = 1.254901960;
	float ratio_i_c = 1.254901960;
	ADCIntClear(ADC0_BASE, 0);
	ADCSequenceDataGet(ADC0_BASE, 0, pui32ADC0Value);

	if (u_num < 640) {
		U_a[u_num] = ratio1*(pui32ADC0Value[0]*3.3/4095 - offset);
		U_b[u_num] = ratio1*(pui32ADC0Value[1]*3.3/4095 - offset);
		U_c[u_num] = ratio1*(pui32ADC0Value[2]*3.3/4095 - offset);
		I_a[u_num] = ratio2*(pui32ADC0Value[3]*3.3/4095 - offset);
		I_b[u_num] = ratio_i_b*(pui32ADC0Value[4]*3.3/4095 - offset);
		I_c[u_num] = ratio_i_c*(pui32ADC0Value[5]*3.3/4095 - offset);
		u_num++;
	}
	if (u_num > 639)
	{
		u_num = 0;
		data_get_ready = 1;
	}

}


void ADC01Init(void) {
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
	GPIOPinTypeGPIOInput(GPIO_PORTF_BASE, GPIO_PIN_4);
	GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_STRENGTH_2MA,GPIO_PIN_TYPE_STD_WPU); 
	GPIOIntTypeSet(GPIO_PORTF_BASE, GPIO_PIN_4, GPIO_FALLING_EDGE); 
	IntMasterEnable();

	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_1);
	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2);
	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
	GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_5);
	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);
	GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_3);

	ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_EXTERNAL, 0);
	GPIOADCTriggerEnable(GPIO_PORTF_BASE, GPIO_PIN_4);
	ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0);
	ADCSequenceStepConfigure(ADC0_BASE, 0, 1, ADC_CTL_CH1);
	ADCSequenceStepConfigure(ADC0_BASE, 0, 2, ADC_CTL_CH2);
	ADCSequenceStepConfigure(ADC0_BASE, 0, 3, ADC_CTL_CH4);
	ADCSequenceStepConfigure(ADC0_BASE, 0, 4, ADC_CTL_CH5);
	ADCSequenceStepConfigure(ADC0_BASE, 0, 5, ADC_CTL_CH8 | ADC_CTL_IE | ADC_CTL_END);
	ADCIntRegister(ADC0_BASE, 0, ADC0Sequence0Handler);    //注册中断函数
	ADCIntEnable(ADC0_BASE, 0);
	IntEnable(INT_ADC0SS0);
	ADCSequenceEnable(ADC0_BASE, 0);
	ADCIntClear(ADC0_BASE, 0);

}

2.频率测量

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_timer.h"
#include "inc/hw_ints.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/udma.h"
#include "driverlib/fpu.h"
#include "driverlib/rom.h"


#define GPIO_LOCK_KEY           0x4C4F434B
#define GPIO_O_CR               0x00000524  // GPIO Commit
#define GPIO_O_LOCK             0x00000520  // GPIO Lock

extern float f;
extern unsigned long count;
extern unsigned long tmp;
extern unsigned long cur, pre;
extern unsigned short i;
extern float freq;
extern int time_count;
extern float time_sum;
extern float ten_count;
extern float time_pre;
extern float time_cur;

void Timer0AIntHandler(void);
void Time_10s_IntHandler(void);
void freq_get_init(void);
void Calc_Freq(void)
{
   TimerIntClear(TIMER0_BASE, TIMER_CAPA_MATCH);
   tmp = cur - pre;

   time_sum = time_cur - time_pre;
   freq = tmp *2 / time_sum;
   f = freq;
}

void Timer0AIntHandler(void)
{
   TimerIntClear(TIMER0_BASE, TIMER_CAPA_MATCH);
   count++;
   time_count = TimerValueGet(TIMER1_BASE, TIMER_A);

}

void Time_10s_IntHandler(void)
{
   TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
   pre = cur;
   cur = count;
   time_pre = time_cur;
   time_cur = (ten_count * 10.0 )+ ((time_count * 10.0) /500000000.0);
   Calc_Freq();
   ten_count++ ;
}

void Time_10s_Init()
{
   uint32_t ui32Period;
   SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
   TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC);
   ui32Period = SysCtlClockGet();
   TimerLoadSet(TIMER1_BASE, TIMER_A, ui32Period *10 - 1);//涓婂彞瑁呰浇鍊艰鍏�
   TimerIntRegister(TIMER1_BASE, TIMER_A, Time_10s_IntHandler);
   IntEnable(INT_TIMER1A);
   TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);//閰嶇疆Timer1涓鸿秴鏃朵腑鏂�
   TimerEnable(TIMER1_BASE, TIMER_A);
}

void Timer0Init()
{
   SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
   SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
	HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
	HWREG(GPIO_PORTF_BASE + GPIO_O_CR) |=  0x01;
	HWREG(GPIO_PORTF_BASE + GPIO_O_LOCK) = 0;
   GPIOPinConfigure(GPIO_PF0_T0CCP0);
   GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_0);
   GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_0, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
   TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_COUNT_UP);
   TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_NEG_EDGE);
   TimerMatchSet(TIMER0_BASE, TIMER_A, 2-1);
   TimerIntRegister(TIMER0_BASE, TIMER_A, Timer0AIntHandler);
   TimerIntEnable(TIMER0_BASE, TIMER_CAPA_MATCH);
   IntEnable(INT_TIMER0A);
   TimerEnable(TIMER0_BASE, TIMER_A);
}


void freq_get_init()
{
	   Time_10s_Init();
	   Timer0Init();
}

3.数据运算

这里声明一下,在刚开始计算的时候,误认为大部分输出结果应该取若干秒内计算值的平均值,故大部分最终输出结果命名均采用xxx_average的形式,实际上有一部分并不是做平均计算得出的结果


# include <math.h>

extern float U_N;

//检测量
extern float U_a[640];
extern float U_b[640];
extern float U_c[640];

extern float I_a[640];
extern float I_b[640];
extern float I_c[640];

extern float U_I_copy[640];

extern float f;

//计算量
extern int i_2s;
extern int i_10s;//计数

extern float U_e_a[12];
extern float U_e_b[12];
extern float U_e_c[12];
extern float I_e_a[12];
extern float I_e_b[12];
extern float I_e_c[12];
extern float P[12];
extern float Q[12];
extern float S[12];
extern float PF[12];
extern float THDu_a;
extern float THDu_b;
extern float THDu_c;
extern float THDi_a;
extern float THDi_b;
extern float THDi_c;
//2s一刷

extern float unbalance_degree_U[12];
extern float unbalance_degree_I[12];
extern float dealt_U[12];//10s一刷

//平均量

extern float U_e_a_average;
extern float U_e_b_average;
extern float U_e_c_average;
extern float I_e_a_average;
extern float I_e_b_average;
extern float I_e_c_average;
extern float P_average;
extern float Q_average;
extern float S_average;
extern float PF_average;
//2s一刷

extern float unbalance_degree_U_average;
extern float unbalance_degree_I_average;
extern float dealt_U_a_average;
extern float dealt_U_b_average;
extern float dealt_U_c_average;
//10s一刷

void caculate_average_2s();
void caculate_average_10s();
void data_transform();
void calculate_data_2s(int num_2s);
void calculate_data_10s(int num_10s);
float caculate_average(float* data,int i);
void data_transform_U(float* U);
float calculate_U_I(float* U_I);
float calculate_P(float* U_a,float* U_b,float* U_c,float* I_a,float* I_b,float* I_c);
float calculate_S(float U_e_a,float U_e_b,float U_e_c,float I_e_a,float I_e_b,float I_e_c);
float calculate_Q(float P,float S);
float calculate_PF(float P,float S);
float caculate_dealt_U(float* arr);
float calculate_unbalance_degree(float U_I_e_a,float U_I_e_b,float U_I_e_c);


void caculate_average_2s()
{
	U_e_a_average= caculate_average(U_e_a,i_2s);
	U_e_b_average= caculate_average(U_e_b,i_2s);
	U_e_c_average= caculate_average(U_e_c,i_2s);
	I_e_a_average= caculate_average(I_e_a,i_2s);
	I_e_b_average= caculate_average(I_e_c,i_2s);
	I_e_c_average= caculate_average(I_e_b,i_2s);
	P_average= caculate_average(P,i_2s);
	Q_average= caculate_average(Q,i_2s);
	S_average= caculate_average(S,i_2s);
	PF_average= caculate_average(PF,i_2s);

}

void caculate_average_10s()
{
	unbalance_degree_U_average= calculate_unbalance_degree(U_e_a_average,U_e_b_average,U_e_c_average);
	unbalance_degree_I_average= calculate_unbalance_degree(I_e_a_average,I_e_b_average,I_e_c_average);
	dealt_U_a_average= caculate_dealt_U(U_e_a);
	dealt_U_b_average= caculate_dealt_U(U_e_b);
	dealt_U_c_average= caculate_dealt_U(U_e_c);
}

void calculate_data_2s(int num_2s)
{
	int num_2s_copy = num_2s;
	U_e_a[num_2s_copy] = calculate_U_I(U_a);
	U_e_b[num_2s_copy] = calculate_U_I(U_b);
	U_e_c[num_2s_copy] = calculate_U_I(U_c);
	I_e_a[num_2s_copy] = calculate_U_I(I_a);
	I_e_b[num_2s_copy] = calculate_U_I(I_b);
	I_e_c[num_2s_copy] = calculate_U_I(I_c);
	P[num_2s_copy] = calculate_P(U_a,U_b,U_c,I_a,I_b,I_c);
	S[num_2s_copy] = calculate_S(U_e_a[num_2s_copy],U_e_b[num_2s_copy],U_e_c[num_2s_copy],I_e_a[num_2s_copy],I_e_b[num_2s_copy],I_e_c[num_2s_copy]);
	Q[num_2s_copy] = calculate_Q(P[num_2s_copy],S[num_2s_copy]);
	PF[num_2s_copy] = calculate_PF(P[num_2s_copy],S[num_2s_copy]);
}


float caculate_average(float* data,int i)
{
	int i_copy = i;
	int j = 0;
	float result = 0;
	for(j = 0;j<i_copy;j++)
	{

		result = result + data[j]/i_copy;
	}
	return result;
}



float calculate_U_I(float* U_I)
{

	float U_I_e_2_sum = 0;
	float U_I_e;
	int j = 128;
	for(j = 128;j<640;j++)
	{
		U_I_e_2_sum = U_I_e_2_sum +(U_I[j]*U_I[j])/512.0;
	}
	U_I_e = sqrt(U_I_e_2_sum);
	return U_I_e;
}

float calculate_P(float* U_a,float* U_b,float* U_c,float* I_a,float* I_b,float* I_c)
{
	float P = 0;
	int j = 128;
	for (j = 128;j<640;j++)
	{
		P = P + (U_c[j]*I_c[j])/512;
	}
	return P;
}

float calculate_S(float U_e_a,float U_e_b,float U_e_c,float I_e_a,float I_e_b,float I_e_c)
{
	float S;
	S = U_e_c*I_e_c;
	return S;
}

float calculate_Q(float P,float S)
{
	float Q;
	Q = sqrt(abs(S*S - P*P));
	return Q;
}

float calculate_PF(float P,float S)
{
	float PF;
	PF = P/S;
	if(PF>1)
		PF = 1;
	return PF;
}

float caculate_dealt_U(float* arr)
{
	int SIZE =  50;
	int flag,n,j,t;
	for(n=0;n<SIZE;n++)
	{
		flag=1;
		for(j=SIZE;j>n;j--)
		{
			if(arr[j-1]<arr[j])
			{
				t=arr[j-1]; arr[j-1]=arr[j]; arr[j]=t;
				flag=0;
			}
		}
		if(flag) break;
	}
	float dealt_U;
	dealt_U = (arr[2] - U_N)*100/U_N;
	return dealt_U;
}

float calculate_unbalance_degree(float U_I_e_a,float U_I_e_b,float U_I_e_c)
{
	float unbalance_degree = 0;
	float L;
	float U_I_e_a_4,U_I_e_b_4,U_I_e_c_4,U_I_e_a_2,U_I_e_b_2,U_I_e_c_2;
	U_I_e_a_4 = pow(U_I_e_a,4);
	U_I_e_b_4 = pow(U_I_e_b,4);
	U_I_e_c_4 = pow(U_I_e_c,4);
	U_I_e_a_2 = pow(U_I_e_a,2);
	U_I_e_b_2 = pow(U_I_e_b,2);
	U_I_e_c_2 = pow(U_I_e_c,2);
	L = (U_I_e_a_4 + U_I_e_b_4 + U_I_e_c_4)/((U_I_e_a_2 +U_I_e_b_2 + U_I_e_c_2)*(U_I_e_a_2 +U_I_e_b_2 + U_I_e_c_2));
	float unbalance_degree_2 = 0;
	float sqrt_3_6_L;
	sqrt_3_6_L = sqrt(abs(3-6*L));
	unbalance_degree_2 = (1-sqrt_3_6_L)/(1+sqrt_3_6_L);
	unbalance_degree = sqrt(unbalance_degree_2);
	return unbalance_degree;
}

FFT和主要运算是分开在两个模块里的

#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/fpu.h"
#include "driverlib/sysctl.h"
#include "driverlib/rom.h"

#define SERIES_LENGTH 512
#define CALC_LENGTH 8
#define PI 3.1415926535

#ifndef M_PI
#define M_PI                    3.14159265358979323846//定义π
#endif
#define N 512
typedef struct{       //定义一个结构体表示复数的类型
	float real;
	float imag;
}complex;
complex x[N] = {0,0}; //定义输入序列和旋转因子
complex y[N] = {0,0};
complex W[N] = {0,0};
float m[N];

extern float U_a[640];
extern float U_b[640];
extern float U_c[640];

extern float I_a[640];
extern float I_b[640];
extern float I_c[640];

extern float THDu_a;
extern float THDu_b;
extern float THDu_c;
extern float THDi_a;
extern float THDi_b;
extern float THDi_c;

extern float U_Mag[11];
extern float U_fhi[11];

extern float I_Mag[11];
extern float I_fhi[11];

void change()
{
	complex temp;
	unsigned short i=0,j=0,k=0;
	float t;
	for(i=0;i<SERIES_LENGTH;i++)
	{
		k=i;
		j=0;
		t=(log(SERIES_LENGTH)/log(2));
		while( (t--)>0 )
		{
			j=j<<1;
			j|=(k & 1);
			k=k>>1;
		}
		if(j>i)
		{
			temp=x[i];
			x[i]=x[j];
			x[j]=temp;
		}
	}

}
void transform()
{
	int i;

	for(i=0;i<SERIES_LENGTH;i++)
	{
		W[i].real=cosf(2*M_PI /SERIES_LENGTH*i);
		W[i].imag=-1*sinf(2*M_PI /SERIES_LENGTH*i);
	}
}
void add(complex a,complex b,complex *c)
{
	c->real=a.real+b.real;
	c->imag=a.imag+b.imag;
}
void sub(complex a,complex b,complex *c)
{
	c->real=a.real-b.real;
	c->imag=a.imag-b.imag;
}
void mul(complex a,complex b,complex *c)
{
	c->real=a.real*b.real - a.imag*b.imag;
	c->imag=a.real*b.imag + a.imag*b.real;
}
void fft()
{
	transform();//变换序列顺序
	int i=0,j=0,k=0,m=0;
	complex q,y,z;
	change();
	for(i=0;i<log(SERIES_LENGTH)/log(2) ;i++)
	{
		m=1<<i;
		for(j=0;j<SERIES_LENGTH;j+=2*m)
		{
			for(k=0;k<m;k++)
			{
				mul(x[k+j+m],W[SERIES_LENGTH*k/2/m],&q);
				add(x[j+k],q,&y);
				sub(x[j+k],q,&z);
				x[j+k]=y;
				x[j+k+m]=z;
			}
		}
	}
}

void fft_back(float *data, float *Mag ,float *fhi)
{
	int i;
	for (i=0; i<=(SERIES_LENGTH-1); i++)  //将输入信号写入结构体
		    {
			x[i].real=data[i];
			x[i].imag=0;
			}
	fft();

	int j;
	for(j=0;j<11;j++)
		{//y[j].real=x[j].real;
		//y[j].imag=x[j].imag;
		Mag[j]=sqrt(x[j*8].imag*x[j*8].imag+x[j*8].real*x[j*8].real)/(256*1.414);
		fhi[j]=atanf(x[j*8].imag/x[j*8].real);
	if(x[j*8].real<0)
		{fhi[j]+=M_PI;}
		}
	Mag[0] /=2;

	}
float THD_c(float *Mag )
{
	float value = 0;
	float sum = 0;
	int i ;
	for (i = 2; i < 11;i++)
	{
		sum = sum + Mag[i]*Mag[i];
	}
    value = (sqrt(sum)/Mag[1])*100;
    return value;

}

float caculate_THD()
{
	fft_back(U_c, U_Mag, U_fhi);
	THDu_c = THD_c(U_Mag);
	fft_back(U_b, U_Mag, U_fhi);
	THDu_b = THD_c(U_Mag);
	fft_back(U_a, U_Mag, U_fhi);
	THDu_a = THD_c(U_Mag);

	fft_back(I_c, I_Mag, I_fhi);
	THDi_c = THD_c(I_Mag);
	fft_back(I_b, I_Mag, I_fhi);
	THDi_b = THD_c(I_Mag);
	fft_back(I_a, I_Mag, I_fhi);
	THDi_a = THD_c(I_Mag);
}

4.LCD

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "inc/hw_types.h"
#include "inc/hw_nvic.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/ssi.h"
#include "uc1701.h"
#include "ui.h"
#include "math.h"
#include "driverlib/rom.h"
#include "driverlib/fpu.h"
#include <stdarg.h>
#include <string.h>
#include "driverlib/pin_map.h"
#include "driverlib/systick.h"
#include "driverlib/rom.h"
#include "lcd_mc.h"

extern int page;
extern float U_e_a_average;
extern float U_e_b_average;
extern float U_e_c_average;
extern float I_e_a_average;
extern float I_e_b_average;
extern float I_e_c_average;
extern float P_average;
extern float Q_average;
extern float S_average;
extern float PF_average;
extern float unbalance_degree_U_average;
extern float unbalance_degree_I_average;
extern float dealt_U_a_average;
extern float dealt_U_b_average;
extern float dealt_U_c_average;
extern float f;
extern float THDu_a;
extern float THDu_b;
extern float THDu_c;
extern float THDi_a;
extern float THDi_b;
extern float THDi_c;

extern float U_Mag[11];
extern float U_fhi[11];

extern float I_Mag[11];
extern float I_fhi[11];

int lcd_init = 0;

void Key1IntHandler()    //pageup
{
	 uiDisplayClear();
	 uiGRAMClear();
	if (page != 1)
	{
		page--;
	}

	GPIOIntClear(GPIO_PORTD_BASE, GPIO_INT_PIN_7);
}

void Key2IntHandler()    //pagedown
{

	 uiDisplayClear();
	 uiGRAMClear();
	if (page != 9)
	{
		page++;
	}

	GPIOIntClear(GPIO_PORTA_BASE, GPIO_INT_PIN_3);
}
void init_lcd_mc(void)
{
	UC1701Init(60000);
	lcd_init = 1;
	UC1701Clear();
	lcd_init = 2;
	page1();
}
void init_k1k2(void)//初始化k1k3,设置为翻页键,注册中断为GPIO的PD7和PA3
{
    #define GPIO_LOCK_KEY           0x4C4F434B
    #define GPIO_O_CR               0x00000524  // GPIO Commit
    #define GPIO_O_LOCK             0x00000520  // GPIO Lock
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
	//SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
	/* Unlock PD7 */
	HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;
	HWREG(GPIO_PORTD_BASE + GPIO_O_CR) |= GPIO_PIN_7;
	HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = 0x00;

	GPIOPinTypeGPIOInput(GPIO_PORTD_BASE, GPIO_PIN_7);
	GPIOPinTypeGPIOInput(GPIO_PORTA_BASE, GPIO_PIN_3);

	GPIOPadConfigSet(GPIO_PORTD_BASE, GPIO_PIN_7, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
	GPIOPadConfigSet(GPIO_PORTA_BASE, GPIO_PIN_3, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);
	GPIOIntRegister(GPIO_PORTD_BASE, Key1IntHandler);
	GPIOIntRegister(GPIO_PORTA_BASE, Key2IntHandler);

	GPIOIntTypeSet(GPIO_PORTD_BASE, GPIO_PIN_7, GPIO_FALLING_EDGE);
	GPIOIntTypeSet(GPIO_PORTA_BASE, GPIO_PIN_3, GPIO_FALLING_EDGE);

	GPIOIntEnable(GPIO_PORTD_BASE, GPIO_PIN_7);
	GPIOIntEnable(GPIO_PORTA_BASE, GPIO_PIN_3);
	IntEnable(INT_GPIOD_TM4C123);
	IntEnable(INT_GPIOA_TM4C123);
}


void page1()
{

	UC1701CharDispaly(0, 1, "Ua :");
	UC1701DisplayF(0, 6, U_e_a_average, 5);
	UC1701CharDispaly(0, 14, "V");
	UC1701CharDispaly(1, 1, "Ub :");
	UC1701DisplayF(1, 6, U_e_b_average, 5);
	UC1701CharDispaly(1, 14, "V");
	UC1701CharDispaly(2, 1, "Uc :");
	UC1701DisplayF(2, 6, U_e_c_average, 5);
	UC1701CharDispaly(2, 14, "V");
	UC1701CharDispaly(3, 1, "Fre:");
	UC1701DisplayF(3, 6, f, 8);
	UC1701CharDispaly(3, 14, "Hz");
}
void page2()
{
	UC1701CharDispaly(0, 1, "Ia :");
	UC1701DisplayF(0, 6, I_e_a_average, 5);
	UC1701CharDispaly(0, 14, "A");
	UC1701CharDispaly(1, 1, "Ib :");
	UC1701DisplayF(1, 6, I_e_b_average, 5);
	UC1701CharDispaly(1, 14, "A");
	UC1701CharDispaly(2, 1, "Ic :");
	UC1701DisplayF(2, 6, I_e_c_average, 5);
	UC1701CharDispaly(2, 14, "A");
	UC1701CharDispaly(3, 1, "Fre:");
	UC1701DisplayF(3, 6, f, 8);
	UC1701CharDispaly(3, 14, "Hz");
}
void page3()
{
	UC1701CharDispaly(0, 1, "P :");
	UC1701DisplayF(0, 6, P_average, 5);
	UC1701CharDispaly(0, 14, "W");
	UC1701CharDispaly(1, 1, "Q :");
	UC1701DisplayF(1, 6, Q_average, 5);
	UC1701CharDispaly(1, 14, "W");
	UC1701CharDispaly(2, 1, "S :");
	UC1701DisplayF(2, 6, S_average, 5);
	UC1701CharDispaly(2, 14, "W");
	UC1701CharDispaly(3, 1, "PF :");
	UC1701DisplayF(3, 6, PF_average, 5);
}
void page4()
{
	UC1701CharDispaly(0, 1, "dealtUa:");
	UC1701DisplayF(0, 9, dealt_U_a_average, 5);

	UC1701CharDispaly(1, 1, "dealtUb:");
	UC1701DisplayF(1, 9, dealt_U_b_average, 5);

	UC1701CharDispaly(2, 1, "dealtUc:");
	UC1701DisplayF(2, 9, dealt_U_c_average, 5);
}
void page5()
{
	UC1701CharDispaly(0, 1, "THDu_a :");
	UC1701DisplayF(0, 9, THDu_a, 5);

	UC1701CharDispaly(1, 1, "THDu_b :");
	UC1701DisplayF(1, 9, THDu_b, 5);

	UC1701CharDispaly(2, 1, "THDu_c :");
	UC1701DisplayF(2, 9,THDu_c, 5);
}
void page6()
{

	UC1701CharDispaly(0, 1, "THDi_a :");
	UC1701DisplayF(0, 9, THDi_a, 4);

	UC1701CharDispaly(1, 1, "THDi_b :");
	UC1701DisplayF(1, 9, THDi_b, 4);

	UC1701CharDispaly(2, 1, "THDi_c :");
	UC1701DisplayF(2, 9,THDi_c, 4);
}
void page7()
{

		 int i = 0;
		 for (i = 0;i<10;i++)
		 {
			 uiDisplayDrawLine(20+10*i,45,20+10*i,45-0.1*U_Mag[i+1]);
			 uiDisplayDrawLine(0,45,128,45);//横轴
			 uiDisplayDrawLine(10,0,10,45);//纵轴
		 }
		uiDisplayerRefresh();
}
void page8()
{

	 int i = 0;
	 for (i = 0;i<10;i++)
	 {
		 uiDisplayDrawLine(20+10*i,45,20+10*i,45-20*I_Mag[i+1]);
		 uiDisplayDrawLine(0,45,128,45);//横轴
		 uiDisplayDrawLine(10,0,10,45);//纵轴
	 }

	uiDisplayerRefresh();
}
void page9()
{
	UC1701CharDispaly(0, 1, "Vol :");
	UC1701DisplayF(0, 7, THDu_a, 5);
	UC1701CharDispaly(0, 15, "%");
	UC1701CharDispaly(1, 1, "Cur :");
	UC1701DisplayF(1, 7, THDi_b, 5);
	UC1701CharDispaly(1, 15, "%");
}
void lcd_display()
{
	if (page == 1)
		{
			page1();
		}
	if (page == 2)
		{
			page2();
		}
	if (page == 3)
		{
			page3();

		}
	if (page == 4)
		{
			page4();
		}
	if (page == 5)
		{
			page5();
		}
	if (page == 6)
		{
			page6();

		}
	if (page == 7)
		{
			page7();
		}
	if (page == 8)
		{
			page8();
		}
	if (page == 9)
		{
			page9();
		}
}

5.蓝牙

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/timer.h"
#include "blueteeth_module.h"

extern float U_e_a_average;
extern float U_e_b_average;
extern float U_e_c_average;
extern float I_e_a_average;
extern float I_e_b_average;
extern float I_e_c_average;
extern float P_average;
extern float Q_average;
extern float S_average;
extern float PF_average;
extern float unbalance_degree_U_average;
extern float unbalance_degree_I_average;
extern float dealt_U_a_average;
extern float dealt_U_b_average;
extern float dealt_U_c_average;
extern float f;
extern float THDu_a;
extern float THDu_b;
extern float THDu_c;
extern float THDi_a;
extern float THDi_b;
extern float THDi_c;

char *F2S(double d,char *str);
void uart_init();
void send_1(float d, char variable);
void send_2(float d,char v1,char v2 );
void send_3(float d,char v1,char v2,char v3 );
void blueteeth_send(void);


void uart_init()
{

	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
	GPIOPinConfigure(GPIO_PB0_U1RX);
	GPIOPinConfigure(GPIO_PB1_U1TX);
	GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);
	UARTConfigSetExpClk(UART1_BASE, SysCtlClockGet(), 9600, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));

}


char *F2S(double d,char *str)
{
	char str1[40];
	int j = 0,k,i;
	i = (int)d;//浮点数的整数部分
	while(i > 0)
	{
		str1[j++] = i % 10 + '0';
		i = i / 10;
	}
	for(k = 0;k < j;k++)
	{
		str[k] = str1[j-1-k];//被提取的整数部分正序存放到另一个数组
	}


	str[j++] = '.';
	d = d - (int)d;//小数部分提取
	if(d!=0)
	{for(i = 0;i < 10;i++)
	{
		d = d*10;
		str[j++] = (int)d + '0';
		d = d - (int)d;
	}
	while(str[--j] == '0');
	str[++j] = '\0';}
	else
	{
		int num;
		for(num = j;num<40;num++)
		{
			str[num]='0';
		}
	}
	return str;
}

void send_1(float d, char variable)
{
	int i;
	char str[40];
	if(d>0)
	{
	char *p = F2S(d,str);
	UARTCharPut(UART1_BASE, variable);
	UARTCharPut(UART1_BASE, '=');
	for(i=0;i<10;i++)
	{
		UARTCharPut(UART1_BASE, str[i]);
	}
	UARTCharPut(UART1_BASE, '\r');
	UARTCharPut(UART1_BASE, '\n');
	}
	if(d==0)
	{
	UARTCharPut(UART1_BASE, variable);
	UARTCharPut(UART1_BASE, '=');
	UARTCharPut(UART1_BASE, '0');
	UARTCharPut(UART1_BASE, '\r');
	UARTCharPut(UART1_BASE, '\n');
	}
	if(d<0)
	{
	char *p = F2S(-d,str);
	UARTCharPut(UART1_BASE, variable);
	UARTCharPut(UART1_BASE, '=');
	UARTCharPut(UART1_BASE, '-');
	for(i=0;i<10;i++)
	{
		UARTCharPut(UART1_BASE, str[i]);
	}
	UARTCharPut(UART1_BASE, '\r');
	UARTCharPut(UART1_BASE, '\n');
	}
}
void send_2(float d,char v1,char v2 )
{
	int i;
	char str[40];
	if(d>0)
	{
	char *p = F2S(d,str);
	UARTCharPut(UART1_BASE, v1);
	UARTCharPut(UART1_BASE, v2);
	UARTCharPut(UART1_BASE, '=');
	for(i=0;i<10;i++)
	{
		UARTCharPut(UART1_BASE, str[i]);
	}
	UARTCharPut(UART1_BASE, '\r');
	UARTCharPut(UART1_BASE, '\n');
	}
	if(d==0)
	{
	UARTCharPut(UART1_BASE, v1);
	UARTCharPut(UART1_BASE, v2);
	UARTCharPut(UART1_BASE, '=');
	UARTCharPut(UART1_BASE, '0');
	UARTCharPut(UART1_BASE, '\r');
	UARTCharPut(UART1_BASE, '\n');
	}
	if(d<0)
	{
	char *p = F2S(-d,str);
	UARTCharPut(UART1_BASE, v1);
	UARTCharPut(UART1_BASE, v2);
	UARTCharPut(UART1_BASE, '=');
	UARTCharPut(UART1_BASE, '-');
	for(i=0;i<10;i++)
	{
		UARTCharPut(UART1_BASE, str[i]);
	}
	UARTCharPut(UART1_BASE, '\r');
	UARTCharPut(UART1_BASE, '\n');
	}
}
void send_3(float d,char v1,char v2,char v3 )
{
	int i;
	char str[40];
	if(d>0)
	{
	char *p = F2S(d,str);
	UARTCharPut(UART1_BASE, v1);
	UARTCharPut(UART1_BASE, v2);
	UARTCharPut(UART1_BASE, v3);
	UARTCharPut(UART1_BASE, '=');
	for(i=0;i<10;i++)
	{
		UARTCharPut(UART1_BASE, str[i]);
	}
	UARTCharPut(UART1_BASE, '\r');
	UARTCharPut(UART1_BASE, '\n');
	}
	if(d==0)
	{
	UARTCharPut(UART1_BASE, v1);
	UARTCharPut(UART1_BASE, v2);
	UARTCharPut(UART1_BASE, v3);
	UARTCharPut(UART1_BASE, '=');
	UARTCharPut(UART1_BASE, '0');
	UARTCharPut(UART1_BASE, '\r');
	UARTCharPut(UART1_BASE, '\n');
	}
	if(d<0)
	{
	char *p = F2S(-d,str);
	UARTCharPut(UART1_BASE, v1);
	UARTCharPut(UART1_BASE, v2);
	UARTCharPut(UART1_BASE, v3);
	UARTCharPut(UART1_BASE, '=');
	UARTCharPut(UART1_BASE, '-');
	for(i=0;i<10;i++)
	{
		UARTCharPut(UART1_BASE, str[i]);
	}
	UARTCharPut(UART1_BASE, '\r');
	UARTCharPut(UART1_BASE, '\n');
	}
}

void blueteeth_send(void)
{
	send_2(U_e_a_average,'U','a');
	send_2(U_e_b_average,'U','b');
	send_2(U_e_c_average,'U','c');
	send_2(I_e_a_average,'I','a');
	send_2(I_e_b_average,'I','b');
	send_2(I_e_c_average,'I','c');
	send_1(P_average,'P');
	send_1(Q_average,'Q');
	send_1(S_average,'S');
	send_2(PF_average,'P','F');
	send_3(unbalance_degree_U_average,'u','d','U');
	send_3(unbalance_degree_I_average,'u','d','I');
	send_3(dealt_U_a_average,'d','U','a');
	send_3(dealt_U_b_average,'d','U','b');
	send_3(dealt_U_c_average,'d','U','c');
	send_1(f,'f');
	send_3(THDu_a,'T','U','a');
	send_3(THDu_b,'T','U','b');
	send_3(THDu_c,'T','U','c');
	send_3(THDi_a,'T','I','a');


	send_3(THDi_b,'T','I','b');
	send_3(THDi_c,'T','I','c');
	UARTCharPut(UART1_BASE, '\r');
	UARTCharPut(UART1_BASE, '\n');

}

6.timer设定及main函数


#include <stdint.h>
#include <stdbool.h>
#include "inc/tm4c123gh6pm.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"

extern int two_s_judge_bluetooth;
extern int two_s_judge_calculate;
extern int ten_s_judge;


void Timer3IntHandler()
{
	TimerIntClear(TIMER3_BASE, TIMER_TIMA_TIMEOUT);
	two_s_judge_bluetooth = 1;
	two_s_judge_calculate = 1;
}

void Timer4IntHandler()
{
	TimerIntClear(TIMER4_BASE, TIMER_TIMA_TIMEOUT);
	ten_s_judge = 1;
}

void two_s_init()
{
	uint32_t ui32Period;
	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER3);
	TimerConfigure(TIMER3_BASE, TIMER_CFG_PERIODIC);
	ui32Period = SysCtlClockGet();
	TimerLoadSet(TIMER3_BASE, TIMER_A, ui32Period*2 -1);
	TimerIntEnable(TIMER3_BASE, TIMER_TIMA_TIMEOUT);
	TimerEnable(TIMER3_BASE, TIMER_A);
	TimerIntRegister(TIMER3_BASE,TIMER_A,Timer3IntHandler);
}

void ten_s_init()
{
	uint32_t ui32Period;
	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER4);
	TimerConfigure(TIMER4_BASE, TIMER_CFG_PERIODIC);
	ui32Period = SysCtlClockGet();
	TimerLoadSet(TIMER4_BASE, TIMER_A, ui32Period*10 -1);
	TimerIntEnable(TIMER4_BASE, TIMER_TIMA_TIMEOUT);
	TimerEnable(TIMER4_BASE, TIMER_A);
	TimerIntRegister(TIMER4_BASE,TIMER_A,Timer4IntHandler);
}



#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>

#include "timer_10s_2s.h"
#include "freq_get.h"
#include "calculate_data.h"
#include "blueteeth_module.h"

#include "inc/hw_memmap.h"
#include "inc/hw_ints.h"
#include "inc/hw_types.h"
#include "inc/hw_nvic.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/ssi.h"
#include "uc1701.h"
#include "ui.h"
#include "math.h"
#include "driverlib/rom.h"
#include "driverlib/fpu.h"
#include <stdarg.h>
#include <string.h>

#include "driverlib/pin_map.h"
#include "driverlib/systick.h"
#include "driverlib/rom.h"
#include "lcd_mc.h"

#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
//#include "data_get_h"
#include "data_get_GPIO.h"
#include "fft.h"

extern int page = 1;
extern float U_N = 220;
extern float U_a[640] = {0};
extern float U_b[640] = {0};
extern float U_c[640] = {0};
extern float I_a[640] = {0};
extern float I_b[640] = {0};
extern float I_c[640] = {0};
extern float U_I_copy[640] = {0};
extern float f = 0;
extern int i_num = 0;
extern int u_num = 0;
extern int i_2s = 0;
extern int i_10s = 0;
extern float U_e_a[12] = {0};
extern float U_e_b[12] = {0};
extern float U_e_c[12] = {0};
extern float I_e_a[12] = {0};
extern float I_e_b[12] = {0};
extern float I_e_c[12] = {0};
extern float P[12] = {0};
extern float Q[12] = {0};
extern float S[12] = {0};
extern float PF[12] = {0};
extern float THDu_a = 0;
extern float THDu_b = 0;
extern float THDu_c = 0;
extern float THDi_a = 0;
extern float THDi_b = 0;
extern float THDi_c = 0;
extern float unbalance_degree_U[12] = {0};
extern float unbalance_degree_I[12] = {0};
extern float dealt_U_a[12] = {0};
extern float dealt_U_b[12] = {0};
extern float dealt_U_c[12] = {0};
extern float U_Mag[11] = {0};
extern float U_fhi[11] = {0};
extern float I_Mag[11] = {0};
extern float I_fhi[11] = {0};
extern float U_e_a_average = 0;
extern float U_e_b_average = 0;
extern float U_e_c_average = 0;
extern float I_e_a_average = 0;
extern float I_e_b_average = 0;
extern float I_e_c_average = 0;
extern float P_average = 0;
extern float Q_average = 0;
extern float S_average = 0;
extern float PF_average = 0;
//2s娑擄拷閸掞拷

extern float unbalance_degree_U_average = 0;
extern float unbalance_degree_I_average = 0;
extern float dealt_U_a_average = 0;
extern float dealt_U_b_average = 0;
extern float dealt_U_c_average = 0;
extern int two_s_judge_bluetooth = 0;
extern int two_s_judge_calculate = 0;
extern int ten_s_judge = 0;
extern int data_get_ready = 0;
extern int flag_FFT = 1;
extern unsigned long count = 0;
extern unsigned long tmp = 0;
extern unsigned long cur = 0, pre = 0;
extern unsigned short i = 0;
extern float freq = 0;
extern int time_count = 0;
extern float time_sum = 0;
extern float ten_count = 0;
extern float time_pre = 0;
extern float time_cur = 0;
int init_num = 0;

void main()

{
	SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |SYSCTL_XTAL_16MHZ);
	
	IntMasterEnable();
	two_s_init();
	ten_s_init();
	ADC01Init();
	freq_get_init();
	uart_init();
	init_num = 1;
	init_lcd_mc();

	init_num = 2;

	init_k1k2();

	while(1)
	{
		if(data_get_ready == 1)
		{
			calculate_data_2s(i_2s);
			i_2s++;
			i_10s++;
			data_get_ready = 0;
			if(two_s_judge_calculate == 1)
			{
				caculate_average_2s();
				i_2s = 0;
				two_s_judge_calculate = 0 ;
			}
		}
		if(ten_s_judge == 1)
		{
			caculate_average_10s();
			caculate_THD();
			ten_s_judge = 0 ;
			i_10s = 0;

		}
		if(two_s_judge_bluetooth == 1)
		{
			/*
			 uiDisplayClear();
			 uiGRAMClear();
            */
			blueteeth_send();
			two_s_judge_bluetooth = 0;
		}
		if(page>9|page<1)
		{
			page = 1;
		}
		lcd_display();
	}
}

四、总结及避坑指北

几个点还是值得提一下的

1.数据运算的时间并没有想象中那么短,而ADC会一直采样,并不会等这一组数据算完之后才继续采样,为了防止数据算到一半,记录原始数据的数组前半段被ADC采样所修改,这里采用的方法是舍掉640组数据中的前128组,以确保计算过程中使用的数据中途不会发生变化。
没有采用在计算前copy一组数据的理由是板子内存不够,将Uabc、Iabc六组数据全部copy下来就炸了。
但是在验收项目时指导老师认为该方法一定程度上降低了设备性能,并不妥当,有待改进。

2.慎用SysCtlDelay()函数,容易造成timer的破坏。

3.为保证ADC采样的准确性,尽量采用外接触发信号源的方式而不采用设备内部的时钟触发。

4.TM4C板的中文字库引脚比较玄学,经常和其他模块的引脚冲突,在最终方案中我们选择了弃用中文字库。

5.在硬件连接时发生了巨多的问题,这里不一一赘述,值得注意的是,当发生LCD花屏、反色、黑屏等情况时,可以有点检查按键或者ADC采样引脚与LCD所使用引脚是否冲突(尤其是挨个拔线检查ADC引脚,可能会出现查阅产品说明书发现没有引脚冲突但实际有冲突的情况)。

总的来说软件部分思路理顺了的话其实并不是很难,难点主要还是出现在软硬件联调时各种玄学问题,在敲代码的时候很多觉得理所当然的事放到板子上反而会出现各种奇奇怪怪的bug,通过这次项目也加深了我对软硬件结合难点的认识。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值