STM32f103的电阻触摸屏的五点校正算法

        由于电阻式触摸屏就是一种传感器,它利用压力感应进行控制,将矩形区域中触摸点(X,Y)的物理位置转换为代表 X坐标和 坐标的电压。这里先引入两个概念,物理坐标和逻辑坐标。物理坐标指触摸屏上点的实际位置,通常以液晶上点的个数来度量。逻辑坐标指这点被触摸时A/D 转换后的坐标值。如图1,我们假定液晶最左下角为坐标轴原点,在液晶上任取一点(十字线交叉中心),方向距离A 10 个点,在方向距离A20 个点,则这点的物理坐标为(1020)。如果我们触摸这一点时得到的A/D 转换值为100A/D 转换值为200,则这点的逻辑坐标为(100200)。

       常用的电阻式触摸屏矫正方法有两点校准法和三点校准法。本文这里介绍的是结合了不同的电阻式触摸屏矫正法的优化算法:五点校正法。其中主要的原理是使用4点矫正法的比例运算以及三点矫正法的基准点运算。五点校正法优势在于可以更加精确的计算出XY方向的比例缩放系数,同时提供了中心基准点,对于一些线性电阻系数比较差电阻式触摸屏有很好的校正功能。

       校正相关的变量主要有:

       x[5] , y[5] 五点定位的物理坐标

       xl[5] , yl[5] 五点定位的逻辑坐标

       KX , KY 横纵方向伸缩系数

       XLC , YLC 中心基点逻辑坐标

       XC , YC 中心基点物理坐标(数值采用LCD显示屏的物理长宽分辨率的一半)

       触摸屏常和点阵式液晶显示(LCD)屏叠加在一起配套使用,构成一个矩形的实际物理平面而由用户触摸的触摸点集合经过 A/D 转换器,得到具体显示坐标的集合,这个集合构成了一个逻辑平面。 由于存在误差,这两个平面并不重合,校准的作用就是要将逻辑平面映射到物理平面上,即得到触点在液晶屏上的位置坐标。 校准算法的中心思想也就是要建立这样一个映射函数现有的校准算法大多是基于线性校准即首先假定物理平面和逻辑平面之间的误差是线性误差,由旋转和偏移形成。




        x[5] , y[5] 五点定位的物理坐标是已知的,其中4点分别设置在LCD的角落,一点设置在LCD正中心,作为基准矫正点。校正关键点和距离布局如图。校正步骤如下:
        1. 通过先后点击LCD的4个角落的矫正点,获取4个角落的逻辑坐标值。
        2. 计算 s1’ = xl[2] - xl[1] 、 s3’ = xl[3] - xl[4] 、 s2’ = yl[3] - yl[2] 、 s4’ = yl[4] - yl[1]
            计算 s1 = x[2] - x[1] 、 s3 = x[3] - x[4] 、 s2 = y[3] - y[2] 、 s4 = y[4] - y[1],一般取点可以人为的设定s1 = s3 和 s2 = s4,以方便运算。
            计算 KX = ( s1’ + s3’ )/2/s1 、KY = ( s2’ + s4’ )/2/s2
        3. 点击LCD正中心,获取中心点的逻辑坐标,作为矫正的基准点。
        4. 完成以上步骤则校正完成。下次点击触摸屏的时候获取的逻辑值XL和YL,可根据公式转换成物理值:
            X = ( XL - XLC ) / KX + XC
            Y = ( YL - YLC ) / KY + YC
        换算出来的X , Y即是和LCD像素相对应的物理坐标值,方便对触屏响应程序做区域判别。


以下是校正程序:

/****************************************************************************
* 名    称:void LCD_Adjustd(void)
* 功    能:校正电阻屏系数
* 入口参数:	null
* 出口参数:无
* 说    明:null
* 调用方法:LCD_Adjustd();
****************************************************************************/
u8 LCD_Adjustd(void)
{
	EXTI_InitTypeDef EXTI_InitStructure;
	
	EXTI_InitStructure.EXTI_Line    = EXTI_Line7;
	EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;	//为中断请求
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//Falling下降沿 Rising上升
	EXTI_InitStructure.EXTI_LineCmd = DISABLE;
	EXTI_Init(&EXTI_InitStructure);
	//显示停止刷屏
	TIM_Cmd(TIM3, DISABLE);  //使能TIMx外设
	
	LCD_Clear(White );
	LCD_printString(110,20, "Adjustd Begin" ,Black);
	delay_ms(5000);
	// 定第一个点
	LCD_Draw_Target(20, 20, Red);
	while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7));
	while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)))
	{
		x[0] = Read_XY(CMD_RDX);
		y[0] = Read_XY(CMD_RDY); 
		LCD_ShowNum(150,80,x[0],Black);
		LCD_ShowNum(150,110,y[0],Black);
		delay_ms(200);
		LCD_Color_Fill(150,80,200,120, White);
	}
	// 定第二个点
	LCD_Draw_Target(300, 20, Red);
	LCD_Draw_Target(20, 20, White);
	while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7));
	while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)))
	{
		x[1] = Read_XY(CMD_RDX);
		y[1] = Read_XY(CMD_RDY); 
		LCD_ShowNum(150,80,x[1],Black);
		LCD_ShowNum(150,110,y[1],Black);
		delay_ms(200);
		LCD_Color_Fill(150,80,200,120, White);
	}
	if(abs(y[1]-y[0]) >60)
	{
		LCD_Clear(White );
		LCD_printString(110,20, "Adjustd Fail" ,Black);
		delay_ms(5000);
		LCD_Clear(White );
		return 1;
	}
	// 定第三个点
	LCD_Draw_Target(20, 220, Red);
	LCD_Draw_Target(300, 20, White);
	while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7));
	while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)))
	{
		x[2] = Read_XY(CMD_RDX);
		y[2] = Read_XY(CMD_RDY); 
		LCD_ShowNum(150,80,x[2],Black);
		LCD_ShowNum(150,110,y[2],Black);
		delay_ms(200);
		LCD_Color_Fill(150,80,200,120, White);
	}
	if(abs(x[2]-x[0]) >80)
	{
		LCD_Clear(White );
		LCD_printString(110,20, "Adjustd Fail" ,Black);
		delay_ms(5000);
		LCD_Clear(White );
		return 1;
	}
	// 定第四个点
	LCD_Draw_Target(300, 220, Red);
	LCD_Draw_Target(20, 220, White);
	while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7));
	while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)))
	{
		x[3] = Read_XY(CMD_RDX);
		y[3] = Read_XY(CMD_RDY); 
		LCD_ShowNum(150,80,x[3],Black);
		LCD_ShowNum(150,110,y[3],Black);
		delay_ms(200);
		LCD_Color_Fill(150,80,200,120, White);
	}
	if((abs(y[2]-y[3]) >60) || (abs(x[1]-x[3]) >80))
	{
		LCD_Clear(White );
		LCD_printString(110,20, "Adjustd Fail" ,Black);
		delay_ms(5000);
		LCD_Clear(White );
		return 1;
	}
	// 定第五个点
	LCD_Draw_Target(160, 120, Red);
	LCD_Draw_Target(300, 220, White);
	while( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7));
	while( (1-GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_7)))
	{
		x[4] = Read_XY(CMD_RDX);
		y[4] = Read_XY(CMD_RDY);
		delay_ms(200);
	}
	//计算校正系数
// 	KX  = ((abs(y[0]-y[2])/280+abs(y[1]-y[3])/280)/2);
// 	KY  = ((abs(x[0]-x[1])/200+abs(x[2]-x[3])/200)/2);
	KX  = (((float)(y[0]-y[2])/280+(float)(y[1]-y[3])/280)/2);
	KY  = (((float)(x[0]-x[1])/200+(float)(x[2]-x[3])/200)/2);
	XC = 160;
	YC = 120;
	XLC  = y[4];
	YLC  = x[4];
	
	// 定点完成
	LCD_Clear(White );
	LCD_printString(110,20, "Adjustd Done" ,Black);
	delay_ms(5000);
	LCD_Color_Fill(110,20,200,35, White);
	LCD_printString(110,20, "Testing" ,Black);
	
	EXTI_InitStructure.EXTI_Line    = EXTI_Line7;
	EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;	//为中断请求
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//Falling下降沿 Rising上升
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	EXTI_ClearITPendingBit(EXTI_Line7);	   //清除线路挂起位
	
	//显示开始刷屏
	TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设
	
	Add_Button();
	
	return 0;
}



### STM32F103VET6与NTC热敏电阻的应用及配置 #### NTC热敏电阻的工作原理 NTC(Negative Temperature Coefficient)热敏电阻是一种随着温度升高而阻值减小的元件。这种特性使得NTC非常适合用于温度测量电路中。当温度变化时,NTC的电阻会发生相应的变化,这个变化可以通过STM32F103VET6内置的ADC模块进行采样并转换为数字信号。 #### 硬件连接方式 为了使STM32F103VET6能够读取NTC热敏电阻的数据,通常会采用分压电路的方式将NTC接入MCU的一个ADC输入通道。具体来说,NTC的一端接地,另一端接一个固定电阻Rf并与电源相连;同时,NTC和Rf之间的节点接到STM32F103VET6的某个ADC引脚上,比如`PA0 (ADC_IN0)`或`PC9 (ADC_IN9)`等[^2]。 #### 软件编程实现 在软件方面,需要初始化ADC外设并将相应的GPIO设置为模拟输入模式。之后就可以周期性地启动一次AD转换操作来获得当前NTC两端电压对应的数值。由于NTC是非线性的器件,因此还需要根据具体的型号参数建立查表法或是利用数学模型来进行非线性校正,最终得到实际的温度值。 下面是一个简单的代码片段展示如何配置和使用ADC读取NTC数据: ```c #include "stm32f1xx_hal.h" // 定义使用的ADC通道号以及对应IO口 #define ADC_CHANNEL ADC_CHANNEL_9 // 使用PC9作为ADC输入 #define GPIO_PIN GPIO_PIN_9 // PC9对应的PIN脚 #define GPIO_PORT GPIOC // 所属PORT void setup_ntc_adc(void){ __HAL_RCC_ADC1_CLK_ENABLE(); // 开启ADC时钟 __HAL_RCC_GPIOC_CLK_ENABLE(); // 开启GPIOC时钟 ADC_ChannelConfTypeDef sConfig = {0}; /* 配置ADC */ hadc.Instance = ADC1; hadc.Init.ScanConvMode = DISABLE; // 单次扫描模式 hadc.Init.ContinuousConvMode = ENABLE;// 连续转换模式 hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; HAL_ADC_Init(&hadc); /* 配置通道 */ sConfig.Channel = ADC_CHANNEL; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; HAL_ADC_ConfigChannel(&hadc, &sConfig); /* 设置PC9为模拟输入 */ GPIO_InitTypeDef gpio_init_struct={0}; gpio_init_struct.Pin=GPIO_PIN; gpio_init_struct.Mode=GPIO_MODE_ANALOG; HAL_GPIO_Init(GPIO_PORT,&gpio_init_struct); } uint16_t read_temperature(){ uint32_t raw_value; HAL_ADC_Start(&hadc); // 启动ADC转换 HAL_ADC_PollForConversion(&hadc, HAL_MAX_DELAY);//等待转换完成 raw_value = HAL_ADC_GetValue(&hadc); // 获取转换后的结果 HAL_ADC_Stop(&hadc); // 停止ADC转换 return raw_value; // 返回原始ADC值 } ``` 此段程序实现了基本的功能框架,但要真正获取准确的温度信息,则需进一步编写算法处理所取得的ADC样本值,并将其映射回真实的物理温度单位。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值