校准逻辑
1、单片机上报原始数据;
2、JNI实现数据传输;
3、App实现校准,计算OK的参数写到单片机上。
解释一下:为什么在应用层去实现校准?因为,计算参数的的时候有坑呢,有可能会出现计算时数据溢出,导致计算操作不准确,在App上定义一个Long就搞定了,在底层实现还需要实现结构封装,好麻烦!,其实就是偷懒了!当然有其他目的需要保密的话,最好还是NDK里面实现吧!
JNI层
JNI层实现简单的读写功能,或者就是数据传输的通道而已。在这还是附上之前《 jni数组使用及将C的char数组传递给Java》的代码:
/**********************************************************************************
*====返回串口接收的数据
*/
jcharArray
Java_com_example_serialcal_PwtsingleClass_ReturnSerialData( JNIEnv* env ){
LOGE("UPON : INTO FUNCTION [--Java_com_example_serialcal_PwtsingleClass_ReturnSerialData()--]\n");
LOGE("UPON :[--Java_com_example_serialcal_PwtsingleClass_ReturnSerialData()--]---%d\n",fd);
int i;
char bufTemp[BUF_SIZE];
read_send_to_java(fd,bufTemp);//在文件描述符fd读取BUF_SIZE个数据到bufTemp,bufTemp按照协议定义好,长度为BUF_SIZE
LOGE("UPON : bufTemp=%s\n",bufTemp);
LOGE("UPON : bufTemp=0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
bufTemp[0],bufTemp[1],bufTemp[2],bufTemp[3],bufTemp[4],bufTemp[5],bufTemp[6],bufTemp[7],bufTemp[8],bufTemp[9]);
jcharArray array = (*env)->NewCharArray(env,BUF_SIZE);//定义数据变量
if(array == NULL){
LOGE("UPON : NewCharArray error.\n");
return;
}
jchar *pArray ;
pArray = (jchar*)calloc(BUF_SIZE, sizeof(jchar));//开辟jchar类型内存空间
if(pArray == NULL){
LOGE("UPON : calloc error.\n");
return;
}
//copy buffer to jchar array
for(i = 0; i < BUF_SIZE; i++)
{
*(pArray + i) = bufTemp[i];//复制bufTemp数据元素到pArray内存空间
}
//LOGE("UPON: =============%s\n",pArray);
(*env)->SetCharArrayRegion(env,array,0,BUF_SIZE,pArray);//复制pArray的jchar数据元素到jcharArray
return array;
}
App实现三点校准:
原理:
//|-----------------------------------------------------------------------------------------------------------------------\
//|----------------------------------\ 三点 |-->| K = (X1 - X3)(Y2 - Y3) - (X2 - X3)(Y1 - Y3) |Author: UPON |
//| || U || XL1 = AX1+BY1+C | 校 |-->| A = ((XL1 - XL3)(Y2 - Y3) - (XL2 - XL3)(Y1 - Y3))/K |QQ:3075583493 |
//| || P || XL2 = AX2+BY2+C | 准 |-->| B = ((X1 - X3)(XL2 - XL3) - (XL1 - XL3)(X2 - X3))/K |-----------------|
//| \\ // XL3 = AX3+BY3+C |=======\|-->| C = (Y1(X3XL2 - X2XL3) + Y2(X1XL3 - X3XL1) + Y3(X2XL1 - X1XL2))/K |
//| // \\ YL1 = DX1+EY1+F |=======/|-->| D = ((YL1 - YL3)(Y2 - Y3) - (YL2 - YL3)(Y1 - Y3))/K |
//| || O || YL2 = DX2+EY2+F | 算 |-->| E = ((X1 - X3)(YL2 - YL3) - (YL1 - YL3)(X2 - X3))/K |
//| || N || YL3 = DX3+EY3+F | 法 |-->| F = (Y1(X3YL2 - X2YL3) + Y2(X1YL3 - X3YL1) + Y3(X2YL1 - X1YL2))/K |
//|----------------------------------/ |==>|校准之后的坐标为:x=(Xl - B*y - C)/A y=(Yl - D*Xl + C*D - F)/(E - D*B) |
//|=======================================================================================================================/
JAVA实现:
public long X1,X2,X3; //触摸屏X坐标
public long Y1,Y2,Y3; //触摸屏Y坐标
public long XL1,XL2,XL3; //显示器XL坐标
public long YL1,YL2,YL3; //显示器YL坐标
public long K,A,B,C,D,E,F; //校准算法需要计算的校准参数
public double Temp_K,Temp_A,Temp_B,Temp_C,Temp_D,Temp_E,Temp_F;//校准算法需要计算的校准参数的中间变量
int Scale=10000;//根据需要将需要处理的数据放大10000倍,Scale为缩放因子
private void doCal(){//校准计算
flag = false;
K = (X1 - X3)*(Y2 - Y3)-(X2 - X3)*(Y1 - Y3);
Temp_A = (double)((XL1 - XL3)*(Y2 - Y3)-(XL2 - XL3)*(Y1 - Y3))/(double)K;
A = (long)(Temp_A*10000);
Temp_B = (double)((X1 - X3)*(XL2 - XL3) - (XL1 - XL3)*(X2 - X3))/(double)K;
B = (long)(Temp_B*10000);
C = (Y1*(X3*XL2 - X2*XL3) + Y2*(X1*XL3 - X3*XL1) + Y3*(X2*XL1 - X1*XL2))/K;
Temp_D = (double)((YL1 - YL3)*(Y2 - Y3) - (YL2 - YL3)*(Y1 - Y3))/(double)K;
D = (long)(Temp_D*10000);
Temp_E = (double)((X1 - X3)*(YL2 - YL3) - (YL1 - YL3)*(X2 - X3))/(double)K;
E = (long)(Temp_E*10000);
F = (Y1*(X3*YL2 - X2*YL3) + Y2*(X1*YL3 - X3*YL1) + Y3*(X2*YL1 - X1*YL2))/K;
//Toast.makeText(getApplicationContext(), "K的值"+K+"A的值"+A+"B的值"+B+"C的值"+C+"D的值"+D+"E的值"+E+"F的值"+F, Toast.LENGTH_LONG).show();
DrawCalCircle.drawText(screen_w/5, screen_h/4+500, "K="+K+" A="+A+" B="+B+" C="+C+" D="+D+" E="+E+" F="+F ,15);
}
最后将校准好的参数,按照与单片机定义好的协议,写到单片机中,这样就实现了校准功能。