zoukankan      html  css  js  c++  java
  • stm32 触摸屏 XPT2046

    引脚功能描述
    1

    控制字的控制位命令
    1

    控制字节各位描述
    1

    单端模式输入配置
    1

    差分模式输入配置
    1

    时序
    前8个时钟用来通过DIN引脚输入控制字节,接着的12个时钟周期将完成真正的模数转换,剩下的3个多时钟周期将用来完成被转换器忽略的最后字节(DOUT置低)

    1

    举例
    1
    2
    3

    #define TOUCH_READ_TIMES    40 //读取次数
    #define TOUCH_ERR_RANGE 20 //误差范围
    
    #define TOUCH_X_CMD 0xD0 //读取X轴
    #define TOUCH_Y_CMD 0x90 //读取Y轴
    #define TOUCH_Continue_Read 0xFF
    #define TOUCH_X_MAX 4000 //X最大值
    #define TOUCH_X_MIN 100 //X最小值
    #define TOUCH_Y_MAX 4000 //Y最大值
    #define TOUCH_Y_MIN 100 //X最小值
    
    #define LCD_CALx_MIN (10) //校准点最小值X
    #define LCD_CALx_MAX (tftlcd_data.width - LCD_CALx_MIN) //校准点最大值X
    #define LCD_CALy_MIN (10) //校准点最小值Y
    #define LCD_CALy_MAX (tftlcd_data.height - LCD_CALy_MIN) //校准点最大值Y
    
    #define LCD_CAL_X   (LCD_CALx_MAX - LCD_CALx_MIN) //方框的宽度
    #define LCD_CAL_Y   (LCD_CALy_MAX - LCD_CALy_MIN) //方框的高度
    
    #define TOUCH_CAL_OK        'Y' //校准OK标志
    #define TOUCH_CAL_ADDR  200  //校准参数在at24c02的保存地址
    
    typedef struct
    {
        u8 flag; 
        short xoffset;
        short yoffset; 
        float xFactor;
        float yFactor;
    } calibrate_t;
    
    calibrate_t calibrate = {0};
    
    u16 touchX;
    u16 touchY;
    
    void TOUCH_init()
    {
        GPIO_InitTypeDef gpioa = 
        {
            GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7,
            GPIO_Speed_50MHz,
            GPIO_Mode_AF_PP
        };
    
        GPIO_InitTypeDef gpiod6 = 
        {
            GPIO_Pin_6,
            GPIO_Speed_50MHz,
            GPIO_Mode_Out_PP
        };
        GPIO_InitTypeDef gpiod7 = 
        {
            GPIO_Pin_7,
            GPIO_Speed_50MHz,
            GPIO_Mode_IPU
        };
    
        SPI_InitTypeDef spi = 
        {
            SPI_Direction_2Lines_FullDuplex,
            SPI_Mode_Master, //0x0104
            SPI_DataSize_8b,
            SPI_CPOL_High,
            SPI_CPHA_2Edge,
            SPI_NSS_Soft,
            SPI_BaudRatePrescaler_256,
            SPI_FirstBit_MSB,
            7
        };
    
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD, ENABLE);
    
        GPIO_Init(GPIOA, &gpioa);
        GPIO_Init(GPIOD, &gpiod6);
        GPIO_Init(GPIOD, &gpiod7);
    
        SPI_Init(SPI1, &spi); //初始化SPI
    
        SPI_Cmd(SPI1, ENABLE); //使能SPI
    }
    
    u16 TOUCH_read(u16 cmd)
    {
        u8 i = 0, j = 0;
        u16 tmp;
        u16 value[TOUCH_READ_TIMES] = {0};
        u32 total_value = 0;
    
        SPI1_SetSpeed(SPI_BaudRatePrescaler_32); //设置SPI速度
    
        for(i = 0; i < TOUCH_READ_TIMES; i++) //读取次数
        {
            TOUCH_CS = 0;
    
            SPI1_read_write(cmd);
    
            value[i] = SPI1_read_write(TOUCH_Continue_Read) << 8; //详见时序
            value[i] |= SPI1_read_write(TOUCH_Continue_Read);
            value[i] >>= 3;
    
            TOUCH_CS = 1;
        }
    
        for (i = 0; i < TOUCH_READ_TIMES; i++) //排序
        {
            for (j = i + 1; j < TOUCH_READ_TIMES; j++)
            {
                if (value[i] < value[j])
                {
                    tmp = value[i];
                    value[i] = value[j];
                    value[j] = tmp;
                }
            }
        }
    
        for (i = 1; i < TOUCH_READ_TIMES - 1; i++) //去掉一个最大值,一个最小值
        {
            total_value += value[i];
        }
    
        total_value /= (TOUCH_READ_TIMES - 2); //求平均值
    
        return total_value;
    }
    
    u8 TOUCH_readXY(u16 *x, u16 *y)
    {
        u16 valueX1, valueY1, valueX2, valueY2;
    
        valueX1 = TOUCH_read(TOUCH_X_CMD); //读取触摸值
        valueY1 = TOUCH_read(TOUCH_Y_CMD);
        valueX2 = TOUCH_read(TOUCH_X_CMD);
        valueY2 = TOUCH_read(TOUCH_Y_CMD);
    
        *x = valueX1 > valueX2 ? (valueX1 - valueX2) : (valueX2 - valueX1); 
        *y = valueY1 > valueY2 ? (valueY1 - valueY2) : (valueY2 - valueY1);
        if((*x > TOUCH_ERR_RANGE) || (*y > TOUCH_ERR_RANGE)) //判断容错范围
        {
            return 0xFF;
        }
    
        *x = (valueX1 + valueX2) / 2;
        *y = (valueY1 + valueY2) / 2;
    
        if((*x < TOUCH_X_MIN || *x > TOUCH_X_MAX) || //判断边界范围
            (*y < TOUCH_Y_MIN || *y > TOUCH_Y_MAX))
        {
            return 0xFF;
        }
    
        return 0;
    }
    
    void TOUCH_start_calibrate(u16 x, u16 y, u16 *valueX,u16 *valueY) //开始校准
    {
        u8 i = 0;
    
        LCD_Clear(BACK_COLOR); //清屏
        LCD_DrowSign(x, y, BACK_COLOR); //画十字
    
        while(1)
        {
            if(TOUCH_readXY(valueX, valueY) != 0xFF)
            {
                i++;
                if(i > 10)
                {
                    LCD_DrowSign(x, y, BACK_COLOR);
                    break;
                }
            }
        }
    }
    
    void TOUCH_calibrate()
    {
        u16 px[2], py[2], valueX[4], valueY[4];
        float xFactor = 0, yFactor = 0;
    
        TOUCH_start_calibrate(LCD_CALx_MIN, LCD_CALy_MIN, &valueX[0], &valueY[0]); //第一次校准
        delay_ms(500);
    
        TOUCH_start_calibrate(LCD_CALx_MIN, LCD_CALy_MAX, &valueX[1], &valueY[1]);
        delay_ms(500);
    
        TOUCH_start_calibrate(LCD_CALx_MAX, LCD_CALy_MIN, &valueX[2], &valueY[2]);
        delay_ms(500);
    
        TOUCH_start_calibrate(LCD_CALx_MAX, LCD_CALy_MAX, &valueX[3], &valueY[3]);
        delay_ms(500);
    
        //整合成对角的两点
        px[0] = (valueX[0] + valueX[1]) / 2;
        py[0] = (valueY[0] + valueY[2]) / 2;
        px[1] = (valueX[3] + valueX[2]) / 2;
        py[1] = (valueY[3] + valueY[1]) / 2;
    
        //求出比例因子
        xFactor = (float)LCD_CAL_X / (px[1] - px[0]);
        yFactor = (float)LCD_CAL_Y / (py[1] - py[0]); 
    
        //求出偏移量
        calibrate.xoffset = (short)LCD_CALx_MAX - ((float)px[1] * xFactor);
        calibrate.yoffset = (short)LCD_CALy_MAX - ((float)py[1] * yFactor);
    
        calibrate.xFactor = xFactor ;
        calibrate.yFactor = yFactor ;
    
        printf("xoffset %d
    ", calibrate.xoffset);
        printf("yoffset %d
    ", calibrate.yoffset);
        printf("xFactor %f
    ", calibrate.xFactor);
        printf("yFactor %f
    ", calibrate.yFactor);
    
        //保存校准数据到at24c02
        calibrate.flag = TOUCH_CAL_OK;
        at24c02Write_buf((u8*)&calibrate, TOUCH_CAL_ADDR, sizeof(calibrate));   
    }
    
    u8 TOUCH_scan() //查看是否触摸
    {
        u16 valueX;
        u16 valueY; 
    
        if(TOUCH_readXY(&valueX, &valueY) == 0xFF)
        {
            return 0xFF;
        }
    
        //根据物理坐标,计算彩屏坐标
        touchX = valueX * calibrate.xFactor + calibrate.xoffset;
        touchY = valueY * calibrate.yFactor + calibrate.yoffset;
    
        if((touchX > tftlcd_data.width) || (touchY > tftlcd_data.height))
        {
            return 0xFF;
        }
    
        return 0;
    }
    
    int main(void)
    {
        I2C_init();
        TOUCH_init();
    
        at24c02Read_buf((u8*)&calibrate, TOUCH_CAL_ADDR, sizeof(calibrate));
        if(calibrate.flag != TOUCH_CAL_OK) //判断是否已经校准
        {
            TOUCH_calibrate();
        }
        LCD_ShowString(tftlcd_data.width-40,0,tftlcd_data.width,tftlcd_data.height,16,"clear");
    
        while(1)
        {
            if(TOUCH_scan() == 0)
            {
                LCD_Fill(touchX-1, touchY-1, touchX+2, touchY+2, FRONT_COLOR); //画粗线
    
                if((touchX > tftlcd_data.width-40) && (touchY < 20))
                {
                    LCD_Fill(0, 0, tftlcd_data.width,tftlcd_data.height, BACK_COLOR); //清屏
                    LCD_ShowString(tftlcd_data.width-40,0,tftlcd_data.width,tftlcd_data.height,16,"clear");
                }
            }
        }
    }
  • 相关阅读:
    VS2010和VS2015的Dll项目
    Umbraco遇到的问题解决
    EF Code first 和 DDD (领域驱动设计研究)系列一
    Gulp的学习和使用
    .Net开发中的@ 和 using 使用技巧
    异常基础
    正则表达式
    常用类
    泛型设计中<T> 和<E>的区别
    各个服务器启动命令
  • 原文地址:https://www.cnblogs.com/zhangxuechao/p/11709545.html
Copyright © 2011-2022 走看看