红牛stmf103原版例程红牛板_Touch(2.8和3.2寸)(2016.05.04)改硬spi

原版的标准库触摸板用的是软件gpio模拟spi    但是读出来的值都是0无法使用。参考以前的官方bsp教程使用硬件spi读取触摸芯片的值。把用spi操作的部分改成硬spi

Touch.h

#ifndef __TOUCH_H
#define __TOUCH_H    

#include "stm32f10x.h"
#include "WB_LCD.h"
#include "stdlib.h"
#include "math.h"
#include "24c02.h"
#include "delay.h"

#define Key_Down   0x01  //触摸状态
#define Key_Up     0x00

#define READ_TIMES 15   //读取次数
#define LOST_VAL    5      //丢弃值
#define ERR_RANGE  10   //误差范围 

typedef struct 
{
    u16 X0;               //原始坐标
    u16 Y0;
    u16 X;                //最终/暂存坐标
    u16 Y;                                   
    u8  Key_Sta;          //笔的状态              
    
    float xfac;           //触摸屏校准参数
    float yfac;
    short xoff;
    short yoff;
}Pen_Holder;
extern Pen_Holder Pen_Point;


//触摸屏芯片连接引脚配置  
#define PEN           GPIOG->IDR&0x0080                                            //PG7   INT
#define DOUT         GPIOB->IDR&0x4000                                            //PB14  MISO

#define TDIN(x)   ((x) ? (GPIOB->BSRR = 0x00008000):(GPIOB->BSRR = 0x80000000)) //PB15  MOSI
#define TCLK(x)   ((x) ? (GPIOB->BSRR = 0x00002000):(GPIOB->BSRR = 0x20000000)) //PB13  SCLK
#define TCS(x)    ((x) ? (GPIOB->BSRR = 0x00001000):(GPIOB->BSRR = 0x10000000)) //PB12  CS 


//ADS7843/7846/UH7843/7846/XPT2046/TSC2046 指令集 
#define CMD_RDY 0x90  //0B10010000即用差分方式读X坐标
#define CMD_RDX    0xD0  //0B11010000即用差分方式读Y坐标  
  
void Touch_Init(void);
void Touch_Adjust(void);
void Convert_Pos(void);
void Pen_Int_Set(uint8_t en);
void Touch_Configuration(void);
uint8_t SPI_WriteByte(uint8_t data);
uint16_t ADS_Read_AD(uint8_t TOUCH_MSR_XY);
uint16_t ADS_Read_XY(uint8_t xy);
uint8_t Read_TP_Once(void);
uint8_t Read_ADS2(uint16_t *x,uint16_t *y);
uint8_t Read_ADS(uint16_t *x,uint16_t *y);
void Save_Adjdata(void);                                    //保存校准参数

void Drow_Touch_Point(uint8_t x,uint16_t y,uint16_t Color);
void Draw_Big_Point(uint8_t x,uint16_t y,uint16_t Color);   //打点
void Load_Drow_Dialog(void);
void Draw_Color_Box(void);
#endif

 

touch/c   修改了spi读写函数,spi初始化函数

/**
 * @file    Touch.c
 * @author  WB R&D Team - openmcu666
 * @version V1.0
 * @date    2016.05.05
 * @brief   Touch Driver
 */
#include "Touch.h"

Pen_Holder Pen_Point; //定义笔实体

/**
 * @brief  SPI写1byte数据
 * @param  写入的数据
 * @retval 接收到的字节
 */

 uint8_t SPI_WriteByte(uint8_t data)
{
     //Wait until the transmit buffer is empty
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
    // Send the byte
    SPI_I2S_SendData(SPI2, data);

    //Wait until a data is received
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
    // Get the received data
    data = SPI_I2S_ReceiveData(SPI2);

    // Return the shifted data
    return data;
}
/**
 * @brief  从7846/7843/XPT2046/UH7843/UH7846读取adc值
 * @param  命令
 * @retval 读取的数据
 */
uint16_t ADS_Read_AD(uint8_t TOUCH_MSR_XY)
{


    uint16_t usAdc;

    TCS(0); /* 使能TS2046的片选 */

    SPI_WriteByte(TOUCH_MSR_XY);
     usAdc =  (SPI_WriteByte(0x00) & 0x7F) << 5;
    usAdc |= (SPI_WriteByte(0x00) >> 3) & 0x1F;

    TCS(1); /* 禁能片选 */

    //printf("%d ", TOUCH_MSR_XY); //测试用
    //printf("%d ", usAdc);        //测试用

    return (usAdc);
}

/**
  * @brief  连续读取READ_TIMES次数据,对这些数据升序排列,
            然后去掉最低和最高LOST_VAL个数,取平均值
  * @param  读坐标命令
  * @retval 坐标值
  */
uint16_t ADS_Read_XY(uint8_t xy)
{
    uint16_t i, j;
    uint16_t buf[READ_TIMES];
    uint16_t sum = 0;
    uint16_t temp;
    for (i = 0; i < READ_TIMES; i++)
    {
        buf[i] = ADS_Read_AD(xy);
    }
    for (i = 0; i < READ_TIMES - 1; i++) //排序
    {
        for (j = i + 1; j < READ_TIMES; j++)
        {
            if (buf[i] > buf[j]) //升序排列
            {
                temp = buf[i];
                buf[i] = buf[j];
                buf[j] = temp;
            }
        }
    }
    sum = 0;
    for (i = LOST_VAL; i < READ_TIMES - LOST_VAL; i++)
        sum += buf[i];
    temp = sum / (READ_TIMES - 2 * LOST_VAL);
    return temp;
}

/**
 * @brief  带滤波的坐标读取  最小值不能少于200.
 * @param  xy首地址
 * @retval return 1读数成功
 */
uint8_t Read_ADS(uint16_t *x, uint16_t *y)
{
    uint16_t xtemp, ytemp;
    xtemp = ADS_Read_XY(CMD_RDX);
    ytemp = ADS_Read_XY(CMD_RDY);
    if (xtemp < 200 || ytemp < 200)
        return 0; //读数失败
    *x = xtemp;
    *y = ytemp;
    return 1; //读数成功
}

/**
  * @brief  2次读取ADS7846,连续读取2次有效的AD值,且这两次的偏差不能超过
            ERR_RANGE,满足条件,则认为读数正确,否则读数错误.
  * @param  xy首地址
  * @retval return 1读数成功
  */
uint8_t Read_ADS2(uint16_t *x, uint16_t *y)
{
    uint16_t x1, y1;
    uint16_t x2, y2;
    uint8_t flag;
    flag = Read_ADS(&x1, &y1);
    if (flag == 0)
        return (0);
    flag = Read_ADS(&x2, &y2);
    if (flag == 0)
        return (0);
    if (((x2 <= x1 && x1 < x2 + ERR_RANGE) || (x1 <= x2 && x2 < x1 + ERR_RANGE)) //前后两次采样在+-50内
        && ((y2 <= y1 && y1 < y2 + ERR_RANGE) || (y1 <= y2 && y2 < y1 + ERR_RANGE)))
    {
        *x = (x1 + x2) / 2;
        *y = (y1 + y2) / 2;
        return 1;
    }
    else
        return 0;
}

/**
 * @brief  读取一次坐标值,直到PEN松开才返回!
 * @param  None
 * @retval return 1读数成功
 */
uint8_t Read_TP_Once(void)
{
    uint8_t t = 0;
    Pen_Int_Set(0); //关闭中断
    Pen_Point.Key_Sta = Key_Up;
    Read_ADS2(&Pen_Point.X, &Pen_Point.Y);
    while (!(PEN & 0x80) && t <= 250)
    {
        t++;
        Delay(10);
    }
    Pen_Int_Set(1); //开启中断
    if (t >= 250)
        return 0; //按下2.5s 认为无效
    else
        return 1;
}

/**
 * @brief  画一个触摸点,用来校准用的
 * @param  x,y:TFT坐标
 * @retval None
 */
void Drow_Touch_Point(uint8_t x, uint16_t y, uint16_t Color)
{
    LCD_DrawLine(x - 12, y, x + 13, y, Color); //横线
    LCD_DrawLine(x, y - 12, x, y + 13, Color); //竖线
    LCD_DrawPoint(x + 1, y + 1, Color);
    LCD_DrawPoint(x - 1, y + 1, Color);
    LCD_DrawPoint(x + 1, y - 1, Color);
    LCD_DrawPoint(x - 1, y - 1, Color);
    LCD_DrawCircle(x, y, 6, Color); //画中心圈
}

/**
 * @brief  画一个2*2的点
 * @param  x,y:TFT坐标 Color 打点颜色
 * @retval None
 */
void Draw_Big_Point(uint8_t x, uint16_t y, uint16_t Color)
{
    LCD_DrawPoint(x, y, Color); //中心点
    LCD_DrawPoint(x + 1, y, Color);
    LCD_DrawPoint(x, y + 1, Color);
    LCD_DrawPoint(x + 1, y + 1, Color);
}

/**
 * @brief  根据触摸屏的校准参数来决定转换后的结果,保存在X0,Y0中
 * @param  None
 * @retval None
 */
void Convert_Pos(void)
{
    if (Read_ADS2(&Pen_Point.X, &Pen_Point.Y))
    {
        Pen_Point.X0 = Pen_Point.xfac * Pen_Point.X + Pen_Point.xoff;
        Pen_Point.Y0 = Pen_Point.yfac * Pen_Point.Y + Pen_Point.yoff;
    }
}

/**
 * @brief  获取校准值
 * @param  None
 * @retval return 1 读数成功
 */
u8 Get_Adjdata(void)
{
    s32 temp_data;
    u16 temp[8], i;
    temp_data = AT24CXX_Read(0x20, temp, 8);
    if (temp[0] == 0xff)
    {
        for (i = 0; i < 8; i++)
        {
            temp[i] = 0;
        }
        AT24CXX_Read(0x00, temp, 8);
        temp_data = (s32)((temp[3] << 24) | (temp[2] << 16) | (temp[1] << 8) | temp[0]);
        Pen_Point.xfac = (float)temp_data / 100000000;

        AT24CXX_Read(0x08, temp, 8);
        temp_data = (s32)((temp[3] << 24) | (temp[2] << 16) | (temp[1] << 8) | temp[0]);
        Pen_Point.yfac = (float)temp_data / 100000000;

        AT24CXX_Read(0x10, temp, 8);
        temp_data = (s32)((temp[1] << 8) | temp[0]);
        Pen_Point.xoff = temp_data;

        AT24CXX_Read(0x18, temp, 8);
        temp_data = (s32)((temp[1] << 8) | temp[0]);
        Pen_Point.yoff = temp_data;
        return 1;
    }

    return 0;
}

/**
 * @brief  得到四个校准参数
 * @param  None
 * @retval None
 */
void Touch_Adjust(void)
{
    uint16_t pos_temp[4][2]; //坐标缓存值
    uint8_t cnt = 0;
    uint16_t d1, d2;
    uint32_t tem1, tem2;
    float fac;
    cnt = 0;
    LCD_Clear(WHITE);              //清屏
    Drow_Touch_Point(20, 20, RED); //画点1
    Pen_Point.Key_Sta = Key_Up;    //消除触发信号
    Pen_Point.xfac = 0;            // xfac用来标记是否校准过,所以校准之前必须清掉!以免错误
    while (1)
    {
        if (Pen_Point.Key_Sta == Key_Down) //按键按下了
        {
            if (Read_TP_Once()) //得到单次按键值
            {
                pos_temp[cnt][0] = Pen_Point.X;
                pos_temp[cnt][1] = Pen_Point.Y;
                cnt++;
            }
            switch (cnt)
            {
            case 1:
                LCD_Clear(WHITE);               //清屏
                Drow_Touch_Point(220, 20, RED); //画点2
                break;
            case 2:
                LCD_Clear(WHITE);               //清屏
                Drow_Touch_Point(20, 300, RED); //画点3
                break;
            case 3:
                LCD_Clear(WHITE);                //清屏
                Drow_Touch_Point(220, 300, RED); //画点4
                break;
            case 4:                                          //全部四个点已经得到
                                                             //对边相等
                tem1 = abs(pos_temp[0][0] - pos_temp[1][0]); // x1-x2
                tem2 = abs(pos_temp[0][1] - pos_temp[1][1]); // y1-y2
                tem1 *= tem1;
                tem2 *= tem2;
                d1 = sqrt(tem1 + tem2); //得到1,2的距离

                tem1 = abs(pos_temp[2][0] - pos_temp[3][0]); // x3-x4
                tem2 = abs(pos_temp[2][1] - pos_temp[3][1]); // y3-y4
                tem1 *= tem1;
                tem2 *= tem2;
                d2 = sqrt(tem1 + tem2); //得到3,4的距离
                fac = (float)d1 / d2;
                if (fac < 0.95 || fac > 1.05 || d1 == 0 || d2 == 0) //不合格
                {
                    cnt = 0;
                    LCD_Clear(WHITE); //清屏
                    Drow_Touch_Point(20, 20, RED);
                    continue;
                }
                tem1 = abs(pos_temp[0][0] - pos_temp[2][0]); // x1-x3
                tem2 = abs(pos_temp[0][1] - pos_temp[2][1]); // y1-y3
                tem1 *= tem1;
                tem2 *= tem2;
                d1 = sqrt(tem1 + tem2); //得到1,3的距离

                tem1 = abs(pos_temp[1][0] - pos_temp[3][0]); // x2-x4
                tem2 = abs(pos_temp[1][1] - pos_temp[3][1]); // y2-y4
                tem1 *= tem1;
                tem2 *= tem2;
                d2 = sqrt(tem1 + tem2); //得到2,4的距离
                fac = (float)d1 / d2;
                if (fac < 0.95 || fac > 1.05) //不合格
                {
                    cnt = 0;
                    LCD_Clear(WHITE); //清屏
                    Drow_Touch_Point(20, 20, RED);
                    continue;
                } //正确了

                //对角线相等
                tem1 = abs(pos_temp[1][0] - pos_temp[2][0]); // x1-x3
                tem2 = abs(pos_temp[1][1] - pos_temp[2][1]); // y1-y3
                tem1 *= tem1;
                tem2 *= tem2;
                d1 = sqrt(tem1 + tem2); //得到1,4的距离

                tem1 = abs(pos_temp[0][0] - pos_temp[3][0]); // x2-x4
                tem2 = abs(pos_temp[0][1] - pos_temp[3][1]); // y2-y4
                tem1 *= tem1;
                tem2 *= tem2;
                d2 = sqrt(tem1 + tem2); //得到2,3的距离
                fac = (float)d1 / d2;
                if (fac < 0.95 || fac > 1.05) //不合格
                {
                    cnt = 0;
                    LCD_Clear(WHITE); //清屏
                    Drow_Touch_Point(20, 20, RED);
                    continue;
                }                                                                                //正确了
                                                                                                 //计算结果
                Pen_Point.xfac = (float)200 / (pos_temp[1][0] - pos_temp[0][0]);                 //得到xfac
                Pen_Point.xoff = (240 - Pen_Point.xfac * (pos_temp[1][0] + pos_temp[0][0])) / 2; //得到xoff

                Pen_Point.yfac = (float)280 / (pos_temp[2][1] - pos_temp[0][1]);                 //得到yfac
                Pen_Point.yoff = (320 - Pen_Point.yfac * (pos_temp[2][1] + pos_temp[0][1])) / 2; //得到yoff

                LCD_Clear(WHITE);                                                                //清屏
                LCD_DisplayStr(35, 110, (unsigned char *)"Touch Screen Adjust OK!", RED, WHITE); //显示校正完成
                Delay(1000);
                LCD_Clear(WHITE); //清屏
                return;           //校正完成
            }
        }
    }
}

/**
 * @brief  保存校准参数
 * @param  None
 * @retval None
 */
void Save_Adjdata(void)
{
    s32 temp_data;
    u16 temp[8];
    temp_data = Pen_Point.xfac * 100000000;   //保存x校正因素
    temp[0] = (u8)(temp_data & 0xff);         //保存x校正因素
    temp[1] = (u8)((temp_data >> 8) & 0xff);  //保存x校正因素
    temp[2] = (u8)((temp_data >> 16) & 0xff); //保存x校正因素
    temp[3] = (u8)((temp_data >> 24) & 0xff); //保存x校正因素
    AT24CXX_Write(0x00, temp, 8);

    temp_data = Pen_Point.yfac * 100000000;   //保存y校正因素
    temp[0] = (u8)(temp_data & 0xff);         //保存x校正因素
    temp[1] = (u8)((temp_data >> 8) & 0xff);  //保存x校正因素
    temp[2] = (u8)((temp_data >> 16) & 0xff); //保存x校正因素
    temp[3] = (u8)((temp_data >> 24) & 0xff); //保存x校正因素
    AT24CXX_Write(0x08, temp, 8);

    temp_data = Pen_Point.xoff;
    temp[0] = (u8)(temp_data & 0xff);
    temp[1] = (u8)((temp_data >> 8) & 0xff);
    AT24CXX_Write(0x10, temp, 8);

    temp_data = Pen_Point.yoff;
    temp[0] = (u8)(temp_data & 0xff);
    temp[1] = (u8)((temp_data >> 8) & 0xff);
    AT24CXX_Write(0x18, temp, 8);

    temp[0] = 0xff;
    AT24CXX_Write(0x20, temp, 8);
}

/**
 * @brief  SPI引脚配置(x模拟SPIx)    使能硬件SPI2, 片选由软件控制
 * @param  None
 * @retval None
 */
void Touch_Configuration() //把模拟spi改成硬件spi
{

      



    GPIO_InitTypeDef GPIO_InitStructure;
    SPI_InitTypeDef SPI_InitStructure;
     NVIC_InitTypeDef NVIC_InitStructure;

 

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOG | RCC_APB2Periph_AFIO, ENABLE); //重要!!

    //下面是SPI相关GPIO初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //通用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // Configure PB12 pin: TP_CS pin    PB12片选
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //通用推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);


    // Configure PC5??? pin: TP_INT pin
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;     // TOUCH_INT   PG7触摸中断
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
    GPIO_Init(GPIOG, &GPIO_InitStructure);



    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组2

    NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;        //配置中断线7
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //次占优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* SPI1总线 配置 */
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //全双工
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                       //主模式
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                   // 8位
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                          //时钟极性 空闲状态时,SCK保持低电平
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                        //时钟相位 数据采样从第一个时钟边沿开始
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                           //软件产生NSS
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; //波特率控制 SYSCLK/64
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                  //数据高位在前
    SPI_InitStructure.SPI_CRCPolynomial = 7;                            // CRC多项式寄存器初始值为7
    SPI_Init(SPI2, &SPI_InitStructure);

    /* SPI2 使能 */
    SPI_Cmd(SPI2, ENABLE);
}

/**
 * @brief  触摸初始化
 * @param  None
 * @retval None
 */
void Touch_Init()
{
    EXTI_InitTypeDef EXTI_InitStructure;

    Touch_Configuration();
    Read_ADS(&Pen_Point.X, &Pen_Point.Y); //第一次读取初始化

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //使能IO复用功能,使用中断功能重要!!!
    /* Connect PEN EXTI Line to Key Button GPIO Pin */
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOG, GPIO_PinSource7);

    /* Configure PEN EXTI Line to generate an interrupt on falling edge */
    EXTI_InitStructure.EXTI_Line = EXTI_Line7;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    /* Generate software interrupt: simulate a falling edge applied on PEN EXTI line */
    EXTI_GenerateSWInterrupt(EXTI_Line7);

    LCD_Clear(WHITE); //清屏
    if (Get_Adjdata())
    {
        return;
    }    //已经校准
    else //未校准
    {
        Touch_Adjust(); //屏幕校准
        Save_Adjdata(); //保存校准值
    }

    Get_Adjdata(); //获取校准值
}

/**
 * @brief  中断开关
 * @param  1开中断 0关中断
 * @retval None
 */
void Pen_Int_Set(uint8_t en)
{
    if (en)
        EXTI->IMR |= 1 << 7; //开启line7上的中断
    else
        EXTI->IMR &= ~(1 << 7); //关闭line7上的中断
}

/**
 * @brief  清除画图区域
 * @param  None
 * @retval None
 */
void Load_Drow_Dialog(void)
{
    LCD_Fill(50, 0, 240, 320, WHITE);
    LCD_DrawCircle(230, 10, 10, RED);
}

/**
 * @brief  显示画笔颜色选择框
 * @param  None
 * @retval None
 */
void Draw_Color_Box(void)
{
    LCD_Fill(20, 30, 50, 60, RED);
    LCD_Fill(20, 70, 50, 100, GREEN);
    LCD_Fill(20, 110, 50, 140, BLUE);
    LCD_Fill(20, 150, 50, 180, YELLOW);
    LCD_Fill(20, 190, 50, 220, MAGENTA);
    LCD_DrawCircle(230, 10, 10, RED);
}

 附上使用hal库函数的文件

TOUCH_H
#ifndef __TOUCH_H
#define __TOUCH_H

#include "stm32f1xx_hal.h"
#include "main.h"
#include "spi.h"

extern SPI_HandleTypeDef hspi2;
void MX_SPI2_Init(void);

typedef struct
{
    uint16_t usAdcNowX;
    uint16_t usAdcNowY;

    uint16_t coordX;
    uint16_t coordY;

    uint16_t min_x, max_x;
    uint16_t min_y, max_y;

    uint8_t Enable; /* �������ʹ�ܱ�־ */

} TOUCH_T;

extern TOUCH_T touch_device;

/* �����¼� */
enum
{
    TOUCH_NONE    = 0, /* �޴��� */
    TOUCH_DOWN    = 1, /* ���� */
    TOUCH_MOVE    = 2, /* �ƶ� */
    TOUCH_RELEASE = 3  /* �ͷ� */
};

/* ���ⲿ���õĺ������� */
void TOUCH_InitHard(void);

void TOUCH_SCAN(void);

#endif

touch.c

#include <stdio.h>

#include "touch.h"

/*
    PB12   --> TP_CS
    PB13   --> TP_SCK
    PB14   --> TP_MISO
    PB15   --> TP_MOSI
    PG7    --> TP_PEN_INT
*/

/* TSC2046 片选 */
#define CS_0()           HAL_GPIO_WritePin(TP_CS_GPIO_Port, TP_CS_Pin, GPIO_PIN_RESET)
#define CS_1()           HAL_GPIO_WritePin(TP_CS_GPIO_Port, TP_CS_Pin, GPIO_PIN_SET)
#define TOUCH_PressValid HAL_GPIO_ReadPin(GPIOG, TP_INT_Pin)

/* TSC2046读取转换命令 */
#define TOUCH_MSR_X 0xd0 //读X轴坐标指令
#define TOUCH_MSR_Y 0x90 //读Y轴坐标指令

#define X_WIDTH     240
#define Y_WIDTH     320

/* 触屏模块用到的全局变量 */
TOUCH_T touch_device;

static void TSC2046_InitHard(void);
uint16_t TSC2046_ReadAdc(uint8_t _ucCh);
void TOUCH_LoadParam(void);
void TOUCH_SaveParam(void);
int32_t TOUCH_Abs(int32_t x);

/*
*********************************************************************************************************
*    函 数 名: TOUCH_InitHard
*    功能说明: 配置STM32和触摸相关的口线,使能硬件SPI2, 片选由软件控制
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void TOUCH_InitHard(void)
{
    TSC2046_InitHard();

    TOUCH_LoadParam(); /* 读取校准参数 */

    touch_device.Enable = 1;
}

/*
*********************************************************************************************************
*    函 数 名: TOUCH_DataFilter
*    功能说明: 读取一个坐标值(x或者y)
*             连续读取XPT2046_READ_TIMES次数据,对这些数据升序排列,
*             然后去掉最低和最高XPT2046_LOST_VAL个数,取平均值
*    形    参:无
*    返 回 值: 读到的数据
*********************************************************************************************************
*/
/* 读取次数 */
#define XPT2046_READ_TIMES 5
/* 丢弃值  */
#define XPT2046_LOST_VAL 1
uint16_t TOUCH_DataFilter(uint8_t _ucCh)
{
    uint16_t i, j;
    uint16_t buf[XPT2046_READ_TIMES];
    uint16_t usSum;
    uint16_t usTemp;

    /* 读取READ_TIMES次数据*/
    for (i = 0; i < XPT2046_READ_TIMES; i++)
    {
        buf[i] = TSC2046_ReadAdc(_ucCh);
    }

    /* 升序排列 */
    for (i = 0; i < XPT2046_READ_TIMES - 1; i++)
    {
        for (j = i + 1; j < XPT2046_READ_TIMES; j++)
        {
            if (buf[i] > buf[j])
            {
                usTemp = buf[i];
                buf[i] = buf[j];
                buf[j] = usTemp;
            }
        }
    }

    usSum = 0;

    /*求和 */
    for (i = XPT2046_LOST_VAL; i < XPT2046_READ_TIMES - XPT2046_LOST_VAL; i++)
    {
        usSum += buf[i];
    }
    /*求平均 */
    usTemp = usSum / (XPT2046_READ_TIMES - 2 * XPT2046_LOST_VAL);

    return usTemp;
}

/*
*********************************************************************************************************
*    函 数 名: TOUCH_ReadAdcXY
*    功能说明: 连续2次读取触摸屏IC,且这两次的偏差不能超过
*             ADC_ERR_RANGE,满足条件,则认为读数正确,否则读数错误.
*             该函数能大大提高准确度
*    形    参:x,y:读取到的坐标值
*    返 回 值: 0,失败;1,成功
*********************************************************************************************************
*/
/* 误差范围 */
uint8_t ADC_ERR_RANGE = 5;
uint8_t TOUCH_ReadAdcXY(int16_t *_usX, int16_t *_usY)
{
    uint16_t iX1, iY1;
    uint16_t iX2, iY2;
    int16_t iX, iY;

    iX1 = TOUCH_DataFilter(TOUCH_MSR_X);
    iY1 = TOUCH_DataFilter(TOUCH_MSR_Y);
    iX2 = TOUCH_DataFilter(TOUCH_MSR_X);
    iY2 = TOUCH_DataFilter(TOUCH_MSR_Y);

    iX = TOUCH_Abs(iX1 - iX2);
    iY = TOUCH_Abs(iY1 - iY2);

    /* 前后两次采样在+-ERR_RANGE内 */
    if ((iX <= ADC_ERR_RANGE) && (iY <= ADC_ERR_RANGE))
    {
        *_usY = (iX1 + iX2) / 2;
        *_usX = (iY1 + iY2) / 2;
        //        *_usX = (iX1 + iX2) / 2;
        //      *_usY = (iY1 + iY2) / 2;
        return 1;
    }
    else
    {
        return 0;
    }
}

void Coord_trans(void)
{
    if (touch_device.max_x > touch_device.min_x)
    {
        touch_device.coordX = (touch_device.usAdcNowX - touch_device.min_x) * Y_WIDTH / (touch_device.max_x - touch_device.min_x);
    }
    else if (touch_device.max_x < touch_device.min_x)
    {
        touch_device.coordX = (touch_device.min_x - touch_device.usAdcNowX) * Y_WIDTH / (touch_device.min_x - touch_device.max_x);
    }

    if (touch_device.max_y > touch_device.min_y)
    {
        touch_device.coordY = (touch_device.usAdcNowY - touch_device.min_y) * X_WIDTH / (touch_device.max_y - touch_device.min_y);
    }
    else if (touch_device.max_y < touch_device.min_y)
    {
        touch_device.coordY = (touch_device.min_y - touch_device.usAdcNowY) * X_WIDTH / (touch_device.min_y - touch_device.max_y);
    }
}

/*
*********************************************************************************************************
*    函 数 名: TOUCH_SCAN
*    功能说明: 触摸板事件检测程序。该函数被周期性调用,每1ms调用1次. 见 bsp.c
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void TOUCH_SCAN(void)
{
    uint8_t s_invalid_count = 0;

    if (TOUCH_PressValid == 0)
    {
        while (!TOUCH_ReadAdcXY(&touch_device.usAdcNowX, &touch_device.usAdcNowY) && s_invalid_count < 20)
            ;
        {
            s_invalid_count++;
        }
        if (s_invalid_count >= 20)
        {
            touch_device.usAdcNowX = -1;
            touch_device.usAdcNowY = -1;
        }
    }
    else
    {
        touch_device.usAdcNowX = -1;
        touch_device.usAdcNowY = -1;
    }
}
static void NVIC_Configuration(void) //中断设置
{
    // NVIC_InitTypeDef NVIC_InitStructure;

    // /* Enable the EXTI0 Interrupt */
    // NVIC_InitStructure.NVIC_IRQChannel                   = EXTI9_5_IRQn;
    // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    // NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    // NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    // NVIC_Init(&NVIC_InitStructure);
}

void EXTI_Enable(uint32_t enable) //开启关闭中断功能
{
    // EXTI_InitTypeDef EXTI_InitStructure;

    // /* Configure  EXTI  */
    // EXTI_InitStructure.EXTI_Line    = EXTI_Line7;
    // EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;
    // EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // Falling下降沿 Rising上升

    if (enable)
    {
        /* enable */
        HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
    }
    else
    {
        /* disable */
        HAL_NVIC_DisableIRQ(EXTI9_5_IRQn);
    }

    // EXTI_Init(&EXTI_InitStructure);
    // EXTI_ClearITPendingBit(EXTI_Line7);
}

static void EXTI_Configuration(void) //已在cubeMX自动生成
{
    // {
    //     GPIO_InitTypeDef GPIO_InitStructure;
    //     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);

    //     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_7;
    //     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;
    //     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    //     GPIO_Init(GPIOG, &GPIO_InitStructure);
    // }

    // GPIO_EXTILineConfig(GPIO_PortSourceGPIOG, GPIO_PinSource7);

    // /* Configure  EXTI  */
    // EXTI_Enable(1);
}

/*
*********************************************************************************************************
*    函 数 名: TSC2046_InitHard
*    功能说明: 配置STM32和触摸相关的口线,使能硬件SPI2, 片选由软件控制
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
static void TSC2046_InitHard(void) // spi跟按键设置需要用hal替代
{
    //     GPIO_InitTypeDef  GPIO_InitStructure;
    //     SPI_InitTypeDef   SPI_InitStructure;

    // //    NVIC_Configuration();
    // //    EXTI_Configuration();

    //     RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);

    //     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOG | RCC_APB2Periph_AFIO, ENABLE );  //重要!!

    //     //下面是SPI相关GPIO初始化
    //     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 |  GPIO_Pin_15;
    //     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //通用推挽输出
    //     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    //     GPIO_Init(GPIOB,&GPIO_InitStructure);

    //     //Configure PB12 pin: TP_CS pin
    //     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    //     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     //通用推挽输出
    //     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    //     GPIO_Init(GPIOB,&GPIO_InitStructure);  //已经在gpio。c中设置

    //     //Configure PG7 pin: TP_INT pin
    //     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    //     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;     //上拉输入???
    //     GPIO_Init(GPIOG,&GPIO_InitStructure);//已经在gpio。c中设置

    //     /* SPI1总线 配置 */
    //     SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;   //全双工
    //     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                           //主模式
    //     SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                       //8位
    //     SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                           //时钟极性 空闲状态时,SCK保持低电平
    //     SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                           //时钟相位 数据采样从第一个时钟边沿开始
    //     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                               //软件产生NSS
    //     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;  //波特率控制 SYSCLK/64
    //     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                   //数据高位在前
    //     SPI_InitStructure.SPI_CRCPolynomial = 7;                               //CRC多项式寄存器初始值为7
    //     SPI_Init(SPI2, &SPI_InitStructure);

    //     /* SPI2 使能 */
    //     SPI_Cmd(SPI2,ENABLE);
}

/*
*********************************************************************************************************
*    函 数 名: SPI_WriteByte
*    功能说明: 向SPI总线发送一个字节,同时返回接收到的字节
*    形    参:写入的数据
*    返 回 值: 接收到的字节
*********************************************************************************************************
*/
static uint8_t SPI_WriteByte(uint8_t data)
{
    // Wait until the transmit buffer is empty
    // while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET)
    // while (__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE) == RESET)

    ;
    // Send the byte
    // SPI_I2S_SendData(hspi2, data);

    // Wait until a data is received
    // while (SPI_I2S_GetFlagStatus(hspi2, SPI_I2S_FLAG_RXNE) == RESET)
    // while (__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE) == RESET)
    ;
    // Get the received data
    // data = SPI_I2S_ReceiveData(hspi2);

    // Return the shifted data
    // return data;

    uint8_t Rxdata;
    HAL_SPI_TransmitReceive(&hspi2, &data, &Rxdata, 1, 1000);
    return Rxdata; //返回收到的数据
}

/*
*********************************************************************************************************
*    函 数 名: Touch_Delay
*    功能说明: 延时
*    形    参:时间
*    返 回 值: 无
*********************************************************************************************************
*/
void Touch_Delay(uint32_t DelayCnt)
{
    uint32_t i;

    for (i = 0; i < DelayCnt; i++)
        ;
}

/*
*********************************************************************************************************
*    函 数 名: TSC2046_ReadAdc
*    功能说明: 选择一个模拟通道,启动ADC,并返回ADC采样结果
*    形    参:_ucCh = TOUCH_MSR_X表示X通道; TOUCH_MSR_Y表示Y通道
*    返 回 值: 12位ADC值
*********************************************************************************************************
*/
uint16_t TSC2046_ReadAdc(uint8_t TOUCH_MSR_XY)
{
    uint16_t usAdc;

    CS_0(); /* 使能TS2046的片选 */

    SPI_WriteByte(TOUCH_MSR_XY);
    usAdc = (SPI_WriteByte(0x00) & 0x7F) << 5;
    usAdc |= (SPI_WriteByte(0x00) >> 3) & 0x1F;

    CS_1(); /* 禁能片选 */

    return (usAdc);
}

/*
*********************************************************************************************************
*    函 数 名: TOUCH_Abs
*    功能说明: 计算绝对值
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
int32_t TOUCH_Abs(int32_t x)
{
    if (x >= 0)
    {
        return x;
    }
    else
    {
        return -x;
    }
}

/*
*********************************************************************************************************
*    函 数 名: TOUCH_SaveParam
*    功能说明: 保存校准参数    s_usAdcX1 s_usAdcX2 s_usAdcY1 s_usAdcX2
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void TOUCH_SaveParam(void)
{
#if 0
    /* 保存下面的4个变量即可 */
    uint16_t usBuf[5];

    usBuf[0] = touch_device.min_x;
    usBuf[1] = touch_device.min_y;

    usBuf[2] = touch_device.max_x;
    usBuf[3] = touch_device.max_y;
#endif
}

/*
*********************************************************************************************************
*    函 数 名: TOUCH_LoadParam
*    功能说明: 读取校准参数
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void TOUCH_LoadParam(void)
{
#if 1
    /* 保存下面的5个变量即可 */
    //    uint16_t usBuf[5];

    /* ReadParamToBuf() */

    touch_device.min_x = 212; // usBuf[0];
    touch_device.min_y = 91;  // usBuf[1];

    touch_device.max_x = 3933; // usBuf[2];
    touch_device.max_y = 3779; // usBuf[3];
#endif
}

// void EXTI9_5_IRQHandler(void) //中断事件  被回调函数重写
// {
//     /* disable interrupt */
//     EXTI_Enable(0);

//     TOUCH_SCAN();

//     EXTI_ClearITPendingBit(EXTI_Line7);
//     EXTI_Enable(1);
// }
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) //中断事件
{
    if (GPIO_Pin == TP_INT_Pin)
    {
        EXTI_Enable(0);
        TOUCH_SCAN();

        __HAL_GPIO_EXTI_CLEAR_IT(TP_INT_Pin);
        EXTI_Enable(1);
    }
}

 

posted @ 2022-09-14 00:54  kyo413  阅读(90)  评论(0编辑  收藏  举报