其他分享
首页 > 其他分享> > 红牛stmf103原版例程红牛板_Touch(2.8和3.2寸)(2016.05.04)改硬spi

红牛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);
}

 

标签:stmf103,temp,Point,例程,SPI,Pen,InitStructure,GPIO,红牛
来源: https://www.cnblogs.com/kyo413/p/16691565.html