2302|1

36

帖子

1

TA的资源

一粒金砂(中级)

楼主
 

HC32F4A0-硬件SPI应用-触摸屏 [复制链接]

 

       前期已经实现了LCD液晶屏的显示,这次实现电阻触摸屏的使用。电阻触摸屏的原理再次不在赘述,可以去看原子教程的原理讲解,其中校准函数等都参考了原子的代码。校准完成之后需要将校准系数等保存到AT24C02中的前13个字节,上篇我们已经是现实了硬件I2C来将数据写入AT24C02并读取,我们可以直接拿来使用。

        首先,先介绍一下HC32F4A0的硬件SPI。HC32F4A0共有6个硬件SPI,支持高速全双工通讯,数据格式有多种选择,并且可以设置3线或4线SPI,波特率可以根据实际调整。本篇使用到的是SPI6,4线全双工模式,数据格式为MSB先行,波特率根据实际情况调整为PLCK1/64,PCLK为120MHz。下面是波特率设置图。

        本篇使用到的SPI6对应的管脚是SCK->PE4、MOSI->PE5、MISO->PE5、CS->TCA9539的P06、Pen_IRQ->TCA9539的P04。根据数据手册43页的表2-1引脚功能表可知,通讯复用功能组为FG2,再根据51页的表2-2 Fun32-63表(如下图)可知,SPI6_SCK、SPI6_MOSI、SPI6_MISO的复用号分别为Func46、Func47、Func48

 

        用到的电阻触摸屏是用XPT2046这个芯片,这是一个12位4通道的ADC芯片。下面是XPT2046电路图、通讯时序图。

        通过发送相应的命令字,即可从xpt2046中读回数据,从时序图中可知,读回来的是一个12位的数据。在程序中的实现方式是读回两个8位数据,再将数据合并。以下是实现代码:

/**************************************************************
  * [url=home.php?mod=space&uid=32621]@name[/url] TP_Read_AD
  * [url=home.php?mod=space&uid=159083]@brief[/url] * @param   CMD: [输入/出]
  * @retval
  * [url=home.php?mod=space&uid=1315547]@author[/url] Zachary
  * [url=home.php?mod=space&uid=34591]@data[/url] 2022-11-09
 **************************************************************/
uint16_t TP_Read_AD( uint8_t CMD )
{
    uint16_t Num = 0;

    T_CS_LOW(); 		//选中触摸屏IC
    xpt2046_spi_send_byte( CMD ); //发送命令字
	Num = 0x0;
	Num = xpt2046_spi_send_byte( 0x00 ) << 8;
	Num |= xpt2046_spi_send_byte( 0x00 );
	Num >>= 4;
    T_CS_HIGH();		//释放片选
	Num &= 0x0FFF;
    return( Num );
}

        上述代码中使用到的xpt2046_spi_send_byte()函数是驱动触摸屏的关键函数,用的是查询法读SPI,先等待发送寄存器为空,发送字节数据,查询接收寄存器,再返回数据,其代码如下:

uint16_t xpt2046_spi_send_byte( uint8_t byte )
{
    /* 等待发送寄存器为空 */
    while( RESET == SPI_GetStatus( T_SPIx, SPI_FLAG_TX_BUF_EMPTY ) );

    /* 发送一个字节数据 */
    SPI_WriteData( T_SPIx, byte );

    /* 等待接收寄存器不为空 */
    while( RESET == SPI_GetStatus( T_SPIx, SPI_FLAG_RX_BUF_FULL ) );

    /* 返回收到的数据 */
    return SPI_ReadData( T_SPIx );
}

        了解了相关电路与关键代码,开始配置SPI,以下是SPI的配置,包括管脚配置和SPI配置,其中管脚配置需要注意,除了配置复用功能外,其他如管脚的上下拉、输入输出等都不要配置,否则SPI会读不到数据,卡在while( RESET == SPI_GetStatus( T_SPIx, SPI_FLAG_RX_BUF_FULL ) ),保持默认就好。其余参数配置都做了相关注释。

/**************************************************************
  * @Name    bsp_XPT2046_Init
  * @brief
  * @param   None
  * @retval
  * @author  Zachary
  * @Data    2022-11-09
 **************************************************************/
void bsp_XPT2046_Init( void )
{
    bsp_XPT2046_GPIO_Init();
    bsp_XPT2046_SPI_Init();
	delay_ms( 100 );
    TP_Read_XY( &tp_dev.x[0], &tp_dev.y[0] ); //第一次读取初始化
    if( TP_Get_Adjdata() )
    {
        return; //已经校准
    }
    else			   //未校准?
    {
//#ifdef SSD1963
//        SSD_LCD_Clear( WHITE ); //清屏
//#else
//		LCD_Clear( WHITE ); //清屏
//#endif
        TP_Adjust();  	//屏幕校准
    }
    TP_Get_Adjdata();
}

/**************************************************************
  * @Name    bsp_XPT2046_GPIO_Init
  * @brief
  * @param   None
  * @retval
  * @author  Zachary
  * @Data    2022-11-09
 **************************************************************/
static void bsp_XPT2046_GPIO_Init( void )
{
//    stc_gpio_init_t GPIO_InitStruct = { 0 };
    
    LL_PERIPH_WE( LL_PERIPH_GPIO );
    
    /* Config T_SCK_PIN */
//    GPIO_StructInit( &GPIO_InitStruct );
//    GPIO_InitStruct.u16PinDrv = PIN_HIGH_DRV;
//    GPIO_InitStruct.u16PinDir = PIN_DIR_OUT;				/* --方向 输入或输出--- */
//    GPIO_InitStruct.u16PullUp = PIN_PU_ON;
//    GPIO_InitStruct.u16PinOutputType = PIN_OUT_TYPE_NMOS;	/* --正常CMOS电平输出或NMOS开漏输出--- */
//    GPIO_Init( T_SCK_PORT, T_SCK_PIN, &GPIO_InitStruct );

    /* Config T_MISO_PIN */
//    GPIO_StructInit( &GPIO_InitStruct );
//    GPIO_InitStruct.u16PinDir = PIN_DIR_IN;				/* --方向 输入或输出--- */
//    GPIO_InitStruct.u16PullUp = PIN_PU_ON;
//    GPIO_Init( T_MISO_PORT, T_MISO_PIN, &GPIO_InitStruct );

    /* Config T_MOSI_PIN */
//    GPIO_StructInit( &GPIO_InitStruct );
//    GPIO_InitStruct.u16PinDrv = PIN_HIGH_DRV;
//    GPIO_InitStruct.u16PinDir = PIN_DIR_OUT;				/* --方向 输入或输出--- */
//    GPIO_InitStruct.u16PullUp = PIN_PU_ON;
//    GPIO_InitStruct.u16PinOutputType = PIN_OUT_TYPE_NMOS;	/* --正常CMOS电平输出或NMOS开漏输出--- */
//    GPIO_Init( T_MOSI_PORT, T_MOSI_PIN, &GPIO_InitStruct );

    /* Config T_CS_PIN */
    TCA9539_ConfigPin( T_CS_PORT, T_CS_PIN, TCA9539_DIR_OUT );

    /* Config T_PEN_IRQ_PIN */
    TCA9539_ConfigPin( T_PEN_IRQ_PORT, T_PEN_IRQ_PIN, TCA9539_DIR_IN );
    
    /* ---复用设置--- */
    GPIO_SetFunc( T_SCK_PORT, T_SCK_PIN, GPIO_FUNC_46 );
    GPIO_SetFunc( T_MOSI_PORT, T_MOSI_PIN, GPIO_FUNC_47 );
    GPIO_SetFunc( T_MISO_PORT, T_MISO_PIN, GPIO_FUNC_48 );
    
    LL_PERIPH_WP( LL_PERIPH_GPIO );
}

/**************************************************************
  * @Name    bsp_XPT2046_SPI_Init
  * @brief
  * @param   None
  * @retval
  * @author  Zachary
  * @Data    2022-11-09
 **************************************************************/
static void bsp_XPT2046_SPI_Init( void )
{
    stc_spi_init_t spi_init_struct;
    stc_spi_delay_t stcSpiDelayCfg;

    LL_PERIPH_WE( LL_PERIPH_FCG | LL_PERIPH_GPIO );

    T_CS_HIGH();    /* ---拉高片选--- */

    SPI_StructInit( &spi_init_struct );
    SPI_DelayStructInit( &stcSpiDelayCfg );
    
    FCG_Fcg1PeriphClockCmd( FCG1_PERIPH_SPI6, ENABLE );             /* ---失能SPI6时钟--- */
    
    SPI_DeInit( T_SPIx );                                           /* ---反初始化SPI6--- */
    spi_init_struct.u32BaudRatePrescaler = SPI_BR_CLK_DIV64;        /* ---波特率 PCLK1 / 64--- */
    spi_init_struct.u32DataBits = SPI_DATA_SIZE_8BIT;               /* ---8位数据长度--- */
    spi_init_struct.u32FirstBit = SPI_FIRST_MSB;                    /* ---高位先行--- */
    spi_init_struct.u32FrameLevel = SPI_1_FRAME;                    /* ---帧数--- */
    spi_init_struct.u32MasterSlave = SPI_MASTER;                    /* ---主机模式--- */
    spi_init_struct.u32ModeFaultDetect = SPI_MD_FAULT_DETECT_DISABLE;
    spi_init_struct.u32Parity = SPI_PARITY_INVD;                    /* ---禁用校验--- */
    spi_init_struct.u32SpiMode = SPI_MD_0;                          /* ---模式0-- */
    spi_init_struct.u32SuspendMode = SPI_COM_SUSP_FUNC_OFF;
    spi_init_struct.u32TransMode = SPI_FULL_DUPLEX;                 /* ---全双工--- */
    spi_init_struct.u32WireMode = SPI_4_WIRE;                       /* ---四线制--- */
    SPI_Init( T_SPIx, &spi_init_struct );
    
    stcSpiDelayCfg.u32IntervalDelay = SPI_INTERVAL_TIME_8SCK;       /* ---数据延时--- */
    stcSpiDelayCfg.u32ReleaseDelay  = SPI_RELEASE_TIME_8SCK;
    stcSpiDelayCfg.u32SetupDelay    = SPI_SETUP_TIME_1SCK;
    SPI_DelayTimeConfig( T_SPIx, &stcSpiDelayCfg );
    
    SPI_Cmd( T_SPIx, ENABLE );   /* ---失能SPI6--- */
    
    LL_PERIPH_WP( LL_PERIPH_FCG | LL_PERIPH_GPIO );
}

以下是读电阻触摸屏AD值、校准等相关代码,参考了原子的。


/**************************************************************
  * @Name    TP_Read_AD
  * @brief
  * @param   CMD: [输入/出]
  * @retval
  * @author  Zachary
  * @Data    2022-11-09
 **************************************************************/
uint16_t TP_Read_AD( uint8_t CMD )
{
    uint16_t Num = 0;

    T_CS_LOW(); 		//选中触摸屏IC
    xpt2046_spi_send_byte( CMD ); //发送命令字
	Num = 0x0;
	Num = xpt2046_spi_send_byte( 0x00 ) << 8;
	Num |= xpt2046_spi_send_byte( 0x00 );
	Num >>= 4;
    T_CS_HIGH();		//释放片选
	Num &= 0x0FFF;
    return( Num );
}

/**************************************************************
  * @Name    TP_Read_XOY
  * @brief   读取一个坐标值(x或者y)
  * @param   xy: [输入/出]
  * @retval
  * @author  Zachary
  * @Data    2022-11-09
 **************************************************************/
#define READ_TIMES 5 	//读取次数
#define LOST_VAL 2	  	//丢弃值
uint16_t TP_Read_XOY( 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] = TP_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;
}

/**************************************************************
  * @Name    TP_Read_XY
  * @brief   读取x,y坐标
  * @param   x: [输入/出]
**			 y: [输入/出]
  * @retval
  * @author  Zachary
  * @Data    2022-11-09
 **************************************************************/
uint8_t TP_Read_XY( uint16_t *x, uint16_t *y )
{
    uint16_t xtemp, ytemp;
    xtemp = TP_Read_XOY( CMD_RDX );
    ytemp = TP_Read_XOY( CMD_RDY );
    if( xtemp < 100 || ytemp < 100 )
        return 0;//读数失败
    *x = xtemp;
    *y = ytemp;
    return 1;//读数成功
}

/**************************************************************
  * @Name    TP_Read_XY2
  * @brief
  * @param   x: [输入/出]
**			 y: [输入/出]
  * @retval
  * @author  Zachary
  * @Data    2022-11-09
 **************************************************************/
#define ERR_RANGE 50 //误差范围 
uint8_t TP_Read_XY2( uint16_t *x, uint16_t *y )
{
    uint16_t x1, y1;
    uint16_t x2, y2;
    uint8_t flag;
    flag = TP_Read_XY( &x1, &y1 );
    if( flag == 0 )
        return( 0 );
    flag = TP_Read_XY( &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;
}

//与LCD部分有关的函数
//画一个触摸点
//用来校准用的
//x,y:坐标
//color:颜色
void TP_Drow_Touch_Point( uint16_t x, uint16_t y, uint16_t color )
{
#ifdef SSD1963
    LCD_DrawLine( x - 12, y, x + 13, y, color ); //横线
    LCD_DrawLine( x, y - 12, x, y + 13, color ); //竖线
    SSD_LCD_Fast_DrawPoint( x + 1, y + 1, color );
    SSD_LCD_Fast_DrawPoint( x - 1, y + 1, color );
    SSD_LCD_Fast_DrawPoint( x + 1, y - 1, color );
    SSD_LCD_Fast_DrawPoint( x - 1, y - 1, color );
    LCD_Draw_Circle( x, y, 6, color ); //画中心圈
#else
	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_Draw_Circle( x, y, 6, color ); //画中心圈
#endif
}
//画一个大点(2*2的点)
//x,y:坐标
//color:颜色
void TP_Draw_Big_Point( uint16_t x, uint16_t y, uint16_t color )
{
#ifdef SSD1963
    SSD_LCD_Fast_DrawPoint( x, y, color ); //中心点
    SSD_LCD_Fast_DrawPoint( x + 1, y, color );
    SSD_LCD_Fast_DrawPoint( x, y + 1, color );
    SSD_LCD_Fast_DrawPoint( x + 1, y + 1, color );
#else
	LCD_DrawPoint( x, y, color ); //中心点
    LCD_DrawPoint( x + 1, y, color );
    LCD_DrawPoint( x, y + 1, color );
    LCD_DrawPoint( x + 1, y + 1, color );
#endif
}

/**************************************************************
  * @Name    TP_Scan
  * @brief
  * @param   tp: [输入/出]
  * @retval
  * @author  Zachary
  * @Data    2022-11-09
 **************************************************************/
uint8_t TP_Scan( uint8_t tp )
{
    uint8_t KeyStat = 0x01;
    TCA9539_ReadPin( T_PEN_IRQ_PORT, T_PEN_IRQ_PIN, &KeyStat );
    if( KeyStat == RESET ) //有按键按下
    {
        if( tp )
        {
            TP_Read_XY2( &tp_dev.x[0], &tp_dev.y[0] ); //读取物理坐标
        }
        else if( TP_Read_XY2( &tp_dev.x[0], &tp_dev.y[0] ) ) //读取屏幕坐标
        {
            tp_dev.x[0] = tp_dev.xfac * tp_dev.x[0] + tp_dev.xoff; //将结果转换为屏幕坐标
            tp_dev.y[0] = tp_dev.yfac * tp_dev.y[0] + tp_dev.yoff;
        }
        if( ( tp_dev.sta & TP_PRES_DOWN ) == 0 ) //之前没有被按下
        {
            tp_dev.sta = TP_PRES_DOWN | TP_CATH_PRES; //按键按下
            tp_dev.x[4] = tp_dev.x[0]; //记录第一次按下时的坐标
            tp_dev.y[4] = tp_dev.y[0];
        }
    }
    else
    {
        if( tp_dev.sta & TP_PRES_DOWN ) //之前是被按下的
        {
            tp_dev.sta &= ~( 1 << 7 ); //标记按键松开
        }
        else//之前就没有被按下
        {
            tp_dev.x[4] = 0;
            tp_dev.y[4] = 0;
            tp_dev.x[0] = 0xffff;
            tp_dev.y[0] = 0xffff;
        }
    }
    return tp_dev.sta & TP_PRES_DOWN; //返回当前的触屏状态
}

#define SAVE_ADDR_BASE 0
//保存校准参数
void TP_Save_Adjdata( void )
{
    uint8_t Reg;
    uint8_t tempbuf[8];
    int32_t temp;
    //保存校正结果!
    temp = tp_dev.xfac * 100000000; //保存x校正因素
    tempbuf[0] = ( temp & 0xFF000000 ) >> 24;
    tempbuf[1] = ( temp & 0x00FF0000 ) >> 16;
    tempbuf[2] = ( temp & 0x0000FF00 ) >> 8;
    tempbuf[3] = ( temp & 0x000000FF );
    Reg = SAVE_ADDR_BASE;
    AT24Cxx_I2C_Write( AT24Cxx_Addr, &Reg, 1U, &tempbuf[0], 4U );
    delay_ms( 20 );
    temp = tp_dev.yfac * 100000000; //保存y校正因素
    tempbuf[0] = ( temp & 0xFF000000 ) >> 24;
    tempbuf[1] = ( temp & 0x00FF0000 ) >> 16;
    tempbuf[2] = ( temp & 0x0000FF00 ) >> 8;
    tempbuf[3] = ( temp & 0x000000FF );
    Reg = SAVE_ADDR_BASE + 4;
    AT24Cxx_I2C_Write( AT24Cxx_Addr, &Reg, 1U, &tempbuf[0], 4U );
    delay_ms( 20 );
    //保存x偏移量
    tempbuf[0] = ( tp_dev.xoff & 0xFF00 ) >> 8;
    tempbuf[1] = tp_dev.xoff & 0x00FF;
    Reg = SAVE_ADDR_BASE + 8;
    AT24Cxx_I2C_Write( AT24Cxx_Addr, &Reg, 1U, &tempbuf[0], 2U );
    delay_ms( 20 );
    //保存y偏移量
    tempbuf[0] = ( tp_dev.yoff & 0xFF00 ) >> 8;
    tempbuf[1] = tp_dev.yoff & 0x00FF;
    Reg = SAVE_ADDR_BASE + 10;
    AT24Cxx_I2C_Write( AT24Cxx_Addr, &Reg, 1U, &tempbuf[0], 2U );
    delay_ms( 20 );
    //保存触屏类型
    tempbuf[0] = tp_dev.touchtype;
    Reg = SAVE_ADDR_BASE + 12;
    AT24Cxx_I2C_Write( AT24Cxx_Addr, &Reg, 1U, &tempbuf[0], 1U );
    delay_ms( 20 );

    tempbuf[0] = 0X0A; //标记校准过了
    Reg = SAVE_ADDR_BASE + 13;
    AT24Cxx_I2C_Write( AT24Cxx_Addr, &Reg, 1U, &tempbuf[0], 1U );
}
//得到保存在EEPROM里面的校准值
//返回值:1,成功获取数据
//        0,获取失败,要重新校准
uint8_t TP_Get_Adjdata( void )
{
    uint8_t Reg, tempbuf[4];
    int32_t tempfac;
    Reg = SAVE_ADDR_BASE + 13;
//    tempbuf[0] = 0x00;
//    AT24Cxx_I2C_Write( AT24Cxx_Addr, &Reg, 1U, &tempbuf[0], 1U );
    AT24Cxx_I2C_Read( AT24Cxx_Addr, &Reg, 1U, &tempbuf[0], 1U );//读取标记字,看是否校准过!
    if( tempbuf[0] == 0x0A ) //触摸屏已经校准过了
    {
        Reg = SAVE_ADDR_BASE;
        //tempfac = FM24CL16_ReadLenByte( SAVE_ADDR_BASE, 4 );
        AT24Cxx_I2C_Read( AT24Cxx_Addr, &Reg, 1U, &tempbuf[0], 4U );
        tempfac = tempbuf[0] << 24 | tempbuf[1] << 16 | tempbuf[2] << 8 | tempbuf[3];
        tp_dev.xfac = ( float )tempfac / 100000000; //得到x校准参数
        
        Reg = SAVE_ADDR_BASE + 4;
        //tempfac = FM24CL16_ReadLenByte( SAVE_ADDR_BASE + 4, 4 );
        AT24Cxx_I2C_Read( AT24Cxx_Addr, &Reg, 1U, &tempbuf[0], 4U );
        tempfac = tempbuf[0] << 24 | tempbuf[1] << 16 | tempbuf[2] << 8 | tempbuf[3];
        tp_dev.yfac = ( float )tempfac / 100000000; //得到y校准参数
        
        //得到x偏移量
        //tp_dev.xoff = FM24CL16_ReadLenByte( SAVE_ADDR_BASE + 8, 2 );
        Reg = SAVE_ADDR_BASE + 8;
        AT24Cxx_I2C_Read( AT24Cxx_Addr, &Reg, 1U, &tempbuf[0], 2U );
        tempfac = tempbuf[0] << 8 | tempbuf[1];
        tp_dev.xoff = tempfac;
        
        //得到y偏移量
        //tp_dev.yoff = FM24CL16_ReadLenByte( SAVE_ADDR_BASE + 10, 2 );
        Reg = SAVE_ADDR_BASE + 10;
        AT24Cxx_I2C_Read( AT24Cxx_Addr, &Reg, 1U, &tempbuf[0], 2U );
        tempfac = tempbuf[0] << 8 | tempbuf[1];
        tp_dev.yoff = tempfac;
        
        Reg = SAVE_ADDR_BASE + 12;
        AT24Cxx_I2C_Read( AT24Cxx_Addr, &Reg, 1U, &tempbuf[0], 1U );
        tempfac = tempbuf[0];
        tp_dev.touchtype = tempfac; //读取触屏类型标记
        
        if( tp_dev.touchtype ) //X,Y方向与屏幕相反
        {
            CMD_RDX = 0X90;
            CMD_RDY = 0XD0;
        } else				   //X,Y方向与屏幕相同
        {
            CMD_RDX = 0XD0;
            CMD_RDY = 0X90;
        }
        return 1;
    }
    return 0;
}
//提示校准结果(各个参数)
void TP_Adj_Info_Show( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t fac )
{
    LCD_ShowString( 40, 160, lcddev.width, lcddev.height, 16, ( uint8_t * )"x1:", RED, GBLUE );
    LCD_ShowString( 40 + 80, 160, lcddev.width, lcddev.height, 16, ( uint8_t * )"y1:", RED, GBLUE );
    LCD_ShowString( 40, 180, lcddev.width, lcddev.height, 16, ( uint8_t * )"x2:", RED, GBLUE );
    LCD_ShowString( 40 + 80, 180, lcddev.width, lcddev.height, 16, ( uint8_t * )"y2:", RED, GBLUE );
    LCD_ShowString( 40, 200, lcddev.width, lcddev.height, 16, ( uint8_t * )"x3:", RED, GBLUE );
    LCD_ShowString( 40 + 80, 200, lcddev.width, lcddev.height, 16, ( uint8_t * )"y3:", RED, GBLUE );
    LCD_ShowString( 40, 220, lcddev.width, lcddev.height, 16, ( uint8_t * )"x4:", RED, GBLUE );
    LCD_ShowString( 40 + 80, 220, lcddev.width, lcddev.height, 16, ( uint8_t * )"y4:", RED, GBLUE );
    LCD_ShowString( 40, 240, lcddev.width, lcddev.height, 16, ( uint8_t * )"fac is:", RED, GBLUE );
    LCD_ShowNum( 40 + 24, 160, x0, 4, 16, RED, GBLUE );		//显示数值
    LCD_ShowNum( 40 + 24 + 80, 160, y0, 4, 16, RED, GBLUE );	//显示数值
    LCD_ShowNum( 40 + 24, 180, x1, 4, 16, RED, GBLUE );		//显示数值
    LCD_ShowNum( 40 + 24 + 80, 180, y1, 4, 16, RED, GBLUE );	//显示数值
    LCD_ShowNum( 40 + 24, 200, x2, 4, 16, RED, GBLUE );		//显示数值
    LCD_ShowNum( 40 + 24 + 80, 200, y2, 4, 16, RED, GBLUE );	//显示数值
    LCD_ShowNum( 40 + 24, 220, x3, 4, 16, RED, GBLUE );		//显示数值
    LCD_ShowNum( 40 + 24 + 80, 220, y3, 4, 16, RED, GBLUE );	//显示数值
    LCD_ShowNum( 40 + 56, 240, fac, 3, 16, RED, GBLUE ); 	//显示数值,该数值必须在95~105范围之内.

}

//触摸屏校准代码
//得到四个校准参数
uint8_t* const TP_REMIND_MSG_TBL = ( uint8_t * )"Please use the stylus click the cross on the screen.The cross will always move until the screen adjustment is completed.";
void TP_Adjust( void )
{
    uint16_t pos_temp[4][2];//坐标缓存值
    uint8_t  cnt = 0;
    uint16_t d1, d2;
    uint32_t tem1, tem2;
    double fac;
    uint16_t outtime = 0;
    cnt = 0;
#ifdef SSD1963
    SSD_LCD_Clear( WHITE ); //清屏
#else
	LCD_Clear( WHITE );
#endif

#ifdef SSD1963	
    SSD_LCD_ShowString( 40, 40, 160, 100, 16, ( uint8_t* )TP_REMIND_MSG_TBL, RED, GBLUE ); //显示提示信息
#else
	LCD_ShowString( 40, 40, 160, 100, 16, ( uint8_t* )TP_REMIND_MSG_TBL, RED, GBLUE ); //显示提示信息
#endif
    TP_Drow_Touch_Point( 20, 20, RED ); //画点1
    tp_dev.sta = 0; //消除触发信号
    tp_dev.xfac = 0; //xfac用来标记是否校准过,所以校准之前必须清掉!以免错误
    while( 1 ) //如果连续10秒钟没有按下,则自动退出
    {
        tp_dev.scan( 1 ); //扫描物理坐标
        if( ( tp_dev.sta & 0xc0 ) == TP_CATH_PRES ) //按键按下了一次(此时按键松开了.)
        {
            outtime = 0;
            tp_dev.sta &= ~( 1 << 6 ); //标记按键已经被处理过了.

            pos_temp[cnt][0] = tp_dev.x[0];
            pos_temp[cnt][1] = tp_dev.y[0];
            cnt++;
            switch( cnt )
            {
            case 1:
                TP_Drow_Touch_Point( 20, 20, WHITE );				//清除点1
                TP_Drow_Touch_Point( lcddev.width - 20, 20, RED );	//画点2
                break;
            case 2:
                TP_Drow_Touch_Point( lcddev.width - 20, 20, WHITE );	//清除点2
                TP_Drow_Touch_Point( 20, lcddev.height - 20, RED );	//画点3
                break;
            case 3:
                TP_Drow_Touch_Point( 20, lcddev.height - 20, WHITE );			//清除点3
                TP_Drow_Touch_Point( lcddev.width - 20, lcddev.height - 20, 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;
                    TP_Drow_Touch_Point( lcddev.width - 20, lcddev.height - 20, WHITE );	//清除点4
                    TP_Drow_Touch_Point( 20, 20, RED );								//画点1
                    TP_Adj_Info_Show( pos_temp[0][0], pos_temp[0][1], pos_temp[1][0], pos_temp[1][1], pos_temp[2][0], pos_temp[2][1], pos_temp[3][0], pos_temp[3][1], fac * 100 ); //显示数据
                    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;
                    TP_Drow_Touch_Point( lcddev.width - 20, lcddev.height - 20, WHITE );	//清除点4
                    TP_Drow_Touch_Point( 20, 20, RED );								//画点1
                    TP_Adj_Info_Show( pos_temp[0][0], pos_temp[0][1], pos_temp[1][0], pos_temp[1][1], pos_temp[2][0], pos_temp[2][1], pos_temp[3][0], pos_temp[3][1], fac * 100 ); //显示数据
                    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;
                    TP_Drow_Touch_Point( lcddev.width - 20, lcddev.height - 20, WHITE );	//清除点4
                    TP_Drow_Touch_Point( 20, 20, RED );								//画点1
                    TP_Adj_Info_Show( pos_temp[0][0], pos_temp[0][1], pos_temp[1][0], pos_temp[1][1], pos_temp[2][0], pos_temp[2][1], pos_temp[3][0], pos_temp[3][1], fac * 100 ); //显示数据
                    continue;
                }//正确了
                //计算结果
                tp_dev.xfac = ( float )( lcddev.width - 40 ) / ( pos_temp[1][0] - pos_temp[0][0] ); //得到xfac
                tp_dev.xoff = ( lcddev.width - tp_dev.xfac * ( pos_temp[1][0] + pos_temp[0][0] ) ) / 2; //得到xoff

                tp_dev.yfac = ( float )( lcddev.height - 40 ) / ( pos_temp[2][1] - pos_temp[0][1] ); //得到yfac
                tp_dev.yoff = ( lcddev.height - tp_dev.yfac * ( pos_temp[2][1] + pos_temp[0][1] ) ) / 2; //得到yoff
                if( fabs( tp_dev.xfac ) > 2 || fabs( tp_dev.yfac ) > 2 ) //触屏和预设的相反了.
                {
                    cnt = 0;
                    TP_Drow_Touch_Point( lcddev.width - 20, lcddev.height - 20, WHITE );	//清除点4
                    TP_Drow_Touch_Point( 20, 20, RED );								//画点1
                    LCD_ShowString( 40, 26, lcddev.width, lcddev.height, 16, ( uint8_t * )"TP Need readjust!", RED, GBLUE );
                    tp_dev.touchtype = !tp_dev.touchtype; //修改触屏类型.
                    if( tp_dev.touchtype ) //X,Y方向与屏幕相反
                    {
                        CMD_RDX = 0X90;
                        CMD_RDY = 0XD0;
                    } else				   //X,Y方向与屏幕相同
                    {
                        CMD_RDX = 0XD0;
                        CMD_RDY = 0X90;
                    }
                    continue;
                }
                LCD_Clear( WHITE ); //清屏
                LCD_ShowString( 35, 110, lcddev.width, lcddev.height, 16, ( uint8_t * )"Touch Screen Adjust OK!", GREEN, GBLUE ); //校正完成
                delay_ms( 1000 );
                TP_Save_Adjdata();
                LCD_Clear( WHITE ); //清屏
                return;//校正完成
            }
        }
        delay_ms( 10 );
        outtime++;
        if( outtime > 1000 )
        {
            TP_Get_Adjdata();
            break;
        }
    }
}

        以下是main.c中的代码:

/**
  ************************************* Copyright ******************************
  *
  *                 (C) Copyright 2022,Zachary ,HPU, China.
  *                            All Rights Reserved
  *
  * FileName   : main.c
  * Version    : v1.0
  * Author     : Zachary
  * Date       : 2023-02-13
  * Description: This is a template project of HC32F4A0
											---Zachary,in Zhejiang Hanpu.
  ******************************************************************************
 */

/* Includes --------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "bsp_Gpio.h"
#include "bsp_TCA9539.h"
#include "bsp_NT35510.h"
#include "bsp_XPT2046.h"
#include "bsp_AT24Cxx.h"
/* --- Typedef -----------------------------------------------------------*/
/* --- Define ------------------------------------------------------------*/
/* --- Macro -------------------------------------------------------------*/
/* --- Variables ---------------------------------------------------------*/
stc_clock_freq_t sysclk;
uint8_t Reg = 0x20;
uint8_t ReadBuf[8];
uint8_t WriteBuf[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
char DispBuf1[50], DispBuf2[50];
/* --- Functions ---------------------------------------------------------*/
static void SysInit( void );
static void bsp_SetSysClk( void );
static void LCD_Test( void );
/*------------------------------------------------------------------------*/
void Load_Drow_Dialog( void )
{
    LCD_Clear( WHITE );//清屏
    LCD_ShowString( lcddev.width - 24, 0, lcddev.width, lcddev.height, 16, ( uint8_t * )"RST", BLACK, WHITE ); //显示清屏区域
}
//电阻触摸屏测试函数
void rtp_test( void )
{
    Load_Drow_Dialog();
    while( 1 )
    {
        tp_dev.scan( 0 );
        if( tp_dev.sta & TP_PRES_DOWN )			//触摸屏被按下
        {
            if( tp_dev.x[0] < lcddev.width && tp_dev.y[0] < lcddev.height )
            {
                if( tp_dev.x[0] > ( lcddev.width - 24 ) && tp_dev.y[0] < 16 )
                    Load_Drow_Dialog();//清除
                else 
                    TP_Draw_Big_Point( tp_dev.x[0], tp_dev.y[0], RED );		//画图
            }
        }
        else
            delay_ms( 1 );	//没有按键按下的时候
    }
}
/**************************************************************
  * @Name    main
  * @brief
  * @param   None
  * @retval
  * @author  Zachary
  * @Data    2023-03-22
 **************************************************************/
int32_t main( void )
{
    SysInit();
    sprintf( DispBuf1, "WirteBuf:%d,%d,%d,%d,%d,%d,%d,%d", WriteBuf[0], WriteBuf[1], \
    WriteBuf[2], WriteBuf[3], WriteBuf[4], WriteBuf[5], WriteBuf[6], WriteBuf[7] );
    LCD_ShowString( 10, 500, lcddev.width, lcddev.height, 24, ( uint8_t *)DispBuf1, WHITE, BLACK );

    AT24Cxx_I2C_Write( AT24Cxx_Addr, &Reg, 0x01, WriteBuf, 0x08 );
    delay_ms( 10 );
    AT24Cxx_I2C_Read( AT24Cxx_Addr, &Reg, 0x01, ReadBuf, 0x08 );

    sprintf( DispBuf2, "ReadBuf:%d,%d,%d,%d,%d,%d,%d,%d", ReadBuf[0], ReadBuf[1], \
    ReadBuf[2], ReadBuf[3], ReadBuf[4], ReadBuf[5], ReadBuf[6], ReadBuf[7] );
    LCD_ShowString( 10, 550, lcddev.width, lcddev.height, 24, ( uint8_t *)DispBuf2, WHITE, BLACK );
    delay_ms( 1000 );
    rtp_test();
    while( 1 )
    {
        LED10_TOGGLE();
        LED11_TOGGLE();
        TCA9539_WritePin( TCA9539_IO_PORT1, TCA9539_IO_PIN7, TCA9539_PIN_SET );
        delay_ms( 500 );
        TCA9539_WritePin( TCA9539_IO_PORT1, TCA9539_IO_PIN7, TCA9539_PIN_RESET );
        delay_ms( 500 );
    }
}

/**************************************************************
  * @Name    SysInit
  * @brief
  * @param   None
  * @retval
  * @author  Zachary
  * @Data    2023-02-13
 **************************************************************/
static void SysInit( void )
{
    bsp_SetSysClk();
    CLK_GetClockFreq( &sysclk );	/* ---检查时钟是否正确--- */
    delay_init( 240 );				/* ---系统滴答定时器初始化--- */
    bsp_Gpio_Init();				/* ---初始化Gpio--- */
    bsp_TCA9539_Init();
    TCA9539_ConfigPin( TCA9539_IO_PORT1, TCA9539_IO_PIN7, TCA9539_DIR_OUT );
    bsp_NT35510_Init();
    LCD_Test();
    bsp_XPT2046_Init();

}

/**************************************************************
  * @Name    LCD_Test
  * @brief
  * @param   None
  * @retval
  * @author  Zachary
  * @Data    2023-03-04
 **************************************************************/
static void LCD_Test( void )
{
    LCD_Clear( RED );
    delay_ms( 500 );
    LCD_Clear( GREEN );
    delay_ms( 500 );
    LCD_Clear( BLACK );
    delay_ms( 500 );
    LCD_Clear( BLUE );
    delay_ms( 500 );
    LCD_Clear( YELLOW );
    delay_ms( 500 );
    LCD_Clear( MAGENTA );
    delay_ms( 500 );
    LCD_Draw_Circle( 200, 200, 100, BLACK );
    LCD_ShowString( 300, 300, lcddev.width, lcddev.height, 24, ( uint8_t * )"hello world", BLACK, MAGENTA );
}

/**************************************************************
  * @Name    SetSysClk
  * @brief	 参考自官方工程
  * @param   None
  * @retval
  * @author  Zachary
  * @Data    2023-02-13
 **************************************************************/
static void bsp_SetSysClk( void )
{
    stc_clock_xtal_init_t stcXtalInit;
    stc_clock_pll_init_t stcPLLHInit;

    LL_PERIPH_WE( LL_PERIPH_FCG | LL_PERIPH_PWC_CLK_RMU | \
                  LL_PERIPH_EFM | LL_PERIPH_SRAM );		/* ---解保护相关外设--- */

    /* PCLK0, HCLK  Max 240MHz */
    /* PCLK1, PCLK4 Max 120MHz */
    /* PCLK2, PCLK3 Max 60MHz  */
    /* EX BUS Max 120MHz */
    CLK_SetClockDiv( CLK_BUS_CLK_ALL, \
                     ( CLK_PCLK0_DIV1 | CLK_PCLK1_DIV2 | CLK_PCLK2_DIV4 | \
                       CLK_PCLK3_DIV4 | CLK_PCLK4_DIV2 | CLK_EXCLK_DIV2 | \
                       CLK_HCLK_DIV1 ) );				/* ---外设总线分频--- */

    CLK_XtalStructInit( &stcXtalInit );
    /* Config Xtal and enable Xtal */
    stcXtalInit.u8Mode   = CLK_XTAL_MD_OSC;			/* ---选择外部晶振--- */
    stcXtalInit.u8Drv    = CLK_XTAL_DRV_ULOW;		/* ---晶振驱动能力 有源晶振驱动能力强--- */
    stcXtalInit.u8State  = CLK_XTAL_ON;
    stcXtalInit.u8StableTime = CLK_XTAL_STB_2MS;	/* ---晶振稳定等待周期--- */
    CLK_XtalInit( &stcXtalInit );

    CLK_PLLStructInit( &stcPLLHInit );				/* ---锁相环寄存器初始化--- */
    /* VCO = (8/1)*120 = 960MHz*/
    stcPLLHInit.u8PLLState = CLK_PLL_ON;
    stcPLLHInit.PLLCFGR = 0UL;
    stcPLLHInit.PLLCFGR_f.PLLM = 1UL - 1UL;
    stcPLLHInit.PLLCFGR_f.PLLN = 120UL - 1UL;
    stcPLLHInit.PLLCFGR_f.PLLP = 4UL - 1UL;
    stcPLLHInit.PLLCFGR_f.PLLQ = 4UL - 1UL;
    stcPLLHInit.PLLCFGR_f.PLLR = 4UL - 1UL;
    stcPLLHInit.PLLCFGR_f.PLLSRC = CLK_PLL_SRC_XTAL;
    CLK_PLLInit( &stcPLLHInit );

    /* Highspeed SRAM set to 0 Read/Write wait cycle */
    SRAM_SetWaitCycle( SRAM_SRAMH, SRAM_WAIT_CYCLE0, SRAM_WAIT_CYCLE0 );

    /* SRAM1_2_3_4_backup set to 1 Read/Write wait cycle */
    SRAM_SetWaitCycle( ( SRAM_SRAM123 | SRAM_SRAM4 | SRAM_SRAMB ), SRAM_WAIT_CYCLE1, SRAM_WAIT_CYCLE1 );

    /* 0-wait @ 40MHz */
    EFM_SetWaitCycle( EFM_WAIT_CYCLE5 );

    /* 4 cycles for 200 ~ 250MHz */
    GPIO_SetReadWaitCycle( GPIO_RD_WAIT4 );

    CLK_SetSysClockSrc( CLK_SYSCLK_SRC_PLL );

    LL_PERIPH_WP( LL_PERIPH_FCG | LL_PERIPH_PWC_CLK_RMU | \
                  LL_PERIPH_EFM | LL_PERIPH_SRAM );		/* ---保护相关外设--- */
}

以下是视频验证:

b285d44851a6a40271447aef5ef9f492

以下是代码附件:

HC32F4A0_TOUCH.7z (1.11 MB, 下载次数: 18)

最新回复

看起来电阻触摸屏的使用也不难,谢谢楼主分享   详情 回复 发表于 2023-3-24 07:31
点赞 关注
 
 

回复
举报

6807

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

看起来电阻触摸屏的使用也不难,谢谢楼主分享

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表