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

 

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/289290.html

(0)
上一篇 2022年9月14日
下一篇 2022年9月14日

相关推荐

发表回复

登录后才能评论