• STM32F103驱动GT911


    0x00 引脚连接:

    // SCL-------PB10
    // SDA-------PB11
    // INT--------PB1
    // RST--------PB2

    IIC的SCL与SDA需要接上拉电阻!

    0x01 模拟IIC:

    在模拟IIC的头文件中:

    定义所需的IO操作宏:

    //IO操作函数    
    #define IIC_SCL    PBout(10) //SCL
    #define IIC_SDA    PBout(11) //SDA    
    #define READ_SDA   PBin(11)  //输入SDA

    宏定义模拟IIC的引脚:

    #define    GT911_PIN_SCL    GPIO_Pin_10
    #define    GT911_PIN_SDA    GPIO_Pin_11

    在模拟IIC的C源文件中实现相关函数:

    void SDA_IN(void)
    {
         GPIO_InitTypeDef GPIO_InitStructure;
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
        
         GPIO_InitStructure.GPIO_Pin = GT911_PIN_SDA;
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(GPIOB, &GPIO_InitStructure);       
    }

    void SDA_OUT(void)
    {
         GPIO_InitTypeDef GPIO_InitStructure;
         RCC_APB2PeriphClockCmd(    RCC_APB2Periph_GPIOB, ENABLE);
        
         GPIO_InitStructure.GPIO_Pin = GT911_PIN_SDA;
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;
         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(GPIOB, &GPIO_InitStructure);
    }

    //初始化IIC
    void IIC_Init(void)
    {                        
         GPIO_InitTypeDef GPIO_InitStructure;
         RCC_APB2PeriphClockCmd(    RCC_APB2Periph_GPIOB, ENABLE );   
           
         GPIO_InitStructure.GPIO_Pin = GT911_PIN_SCL|GT911_PIN_SDA;
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; 
         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(GPIOB, &GPIO_InitStructure);
         GPIO_SetBits(GPIOB,GT911_PIN_SCL|GT911_PIN_SDA);
    }
    //产生IIC起始信号
    void IIC_Start(void)
    {
         SDA_OUT();   
         IIC_SDA=1;           
         IIC_SCL=1;
         delay_us(4);
          IIC_SDA=0;//START:when CLK is high,DATA change form high to low
         delay_us(4);
         IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
    }     
    //产生IIC停止信号
    void IIC_Stop(void)
    {
         SDA_OUT();
         IIC_SCL=0;
         IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
          delay_us(4);
         IIC_SCL=1;
         IIC_SDA=1;//发送I2C总线结束信号
         delay_us(4);                                  
    }
    //等待应答信号到来
    //返回值:1,接收应答失败
    //        0,接收应答成功
    u8 IIC_Wait_Ack(void)
    {
         u8 ucErrTime=0;
         SDA_IN();      //SDA设置为输入 
         IIC_SDA=1;delay_us(1);      
         IIC_SCL=1;delay_us(1);    
         while(READ_SDA)
         {
             ucErrTime++;
             if(ucErrTime>250)
             {
                 IIC_Stop();
                 return 1;
             }
         }
         IIC_SCL=0;//时钟输出0       
         return 0; 
    }
    //产生ACK应答
    void IIC_Ack(void)
    {
         IIC_SCL=0;
         SDA_OUT();
         IIC_SDA=0;
         delay_us(2);
         IIC_SCL=1;
         delay_us(2);
         IIC_SCL=0;
    }
    //不产生ACK应答           
    void IIC_NAck(void)
    {
         IIC_SCL=0;
         SDA_OUT();
         IIC_SDA=1;
         delay_us(2);
         IIC_SCL=1;
         delay_us(2);
         IIC_SCL=0;
    }                                         
    //IIC发送一个字节
    //返回从机有无应答
    //1,有应答
    //0,无应答             
    void IIC_Send_Byte(u8 txd)
    {                       
         u8 t;  
         SDA_OUT();        
         IIC_SCL=0;//拉低时钟开始数据传输
         for(t=0;t<8;t++)
         {             
             //IIC_SDA=(txd&0x80)>>7;
             if((txd&0x80)>>7)
                 IIC_SDA=1;
             else
                 IIC_SDA=0;
             txd<<=1;      
             delay_us(2);   //对TEA5767这三个延时都是必须的
             IIC_SCL=1;
             delay_us(2);
             IIC_SCL=0;   
             delay_us(2);
         }    
    }        
    //读1个字节,ack=1时,发送ACK,ack=0,发送nACK  
    u8 IIC_Read_Byte(unsigned char ack)
    {
         unsigned char i,receive=0;
         SDA_IN();//SDA设置为输入
         for(i=0;i<8;i++ )
         {
             IIC_SCL=0;
             delay_us(2);
             IIC_SCL=1;
             receive<<=1;
             if(READ_SDA)receive++;  
             delay_us(1);
         }                    
         if (!ack)
             IIC_NAck();//发送nACK
         else
             IIC_Ack(); //发送ACK  
         return receive;
    }

    0x02 初始化GT911:

    查阅《GT911编程指南》:

    GT911上电时序

    IIC通信地址选择 0x28/0x29,在头文件中加入相关声明和定义:

    //I2C读写命令   
    #define GT_CMD_WR         0X28         //写命令
    #define GT_CMD_RD         0X29        //读命令
      
    //GT911 部分寄存器定义
    #define GT_CTRL_REG     0X8040       //GT911控制寄存器
    #define GT_CFGS_REG     0X8047       //GT911配置起始地址寄存器
    #define GT_CHECK_REG     0X80FF       //GT911校验和寄存器
    #define GT_PID_REG         0X8140       //GT911产品ID寄存器

    #define GT_GSTID_REG     0X814E       //GT911当前检测到的触摸情况

    #define    GT911_PIN_INT    GPIO_Pin_1
    #define    GT911_PIN_RST    GPIO_Pin_2

    typedef struct _POINT{
         u16 x;
         u16 y;
    }POINT, *PPOINT;

    typedef struct _GT911_POINT_DATA{
         u8 cnt;
         POINT points[5];
    }GT911_POINT_DATA, *PGT911_POINT_DATA;

    extern GT911_POINT_DATA     gt911_data;

    在C源文件中添加GT911初始化所需要的准备函数:

    void GT911_INT_Init(void)
    {
         GPIO_InitTypeDef GPIO_InitStructure;
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
         GPIO_InitStructure.GPIO_Pin = GT911_PIN_INT;
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(GPIOB, &GPIO_InitStructure);
         GPIO_ResetBits(GPIOB, GT911_PIN_INT);
    }

    void GT911_INT(u8 cmd)
    {
         if(cmd)    GPIO_SetBits(GPIOB, GT911_PIN_INT);
         else    GPIO_ResetBits(GPIOB, GT911_PIN_INT);
    }

    void GT911_INT_Change(void)
    {
         GPIO_InitTypeDef GPIO_InitStructure;
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
         GPIO_InitStructure.GPIO_Pin = GT911_PIN_INT;
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(GPIOB, &GPIO_InitStructure);
         GPIO_ResetBits(GPIOB, GT911_PIN_INT);   
    }

    void GT911_RST_Init(void)
    {
         GPIO_InitTypeDef GPIO_InitStructure;
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
         GPIO_InitStructure.GPIO_Pin = GT911_PIN_RST;
         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(GPIOB, &GPIO_InitStructure);
         GPIO_ResetBits(GPIOB, GT911_PIN_RST);
    }

    void GT911_RST(u8 cmd)
    {
         if(cmd)    GPIO_SetBits(GPIOB, GT911_PIN_RST);
         else    GPIO_ResetBits(GPIOB, GT911_PIN_RST);
    }

    按照时序GT911上电初始化大致流程如下(IIC通信地址选择 0x28/0x29):

    GT911_RST_Init();
    GT911_INT_Init();
    IIC_Init();

    GT911_RST(0);
    GT911_INT(1);
    delay_us(200);
    GT911_RST(1);
    delay_ms(6);
    GT911_INT(0);
    delay_ms(55);
    GT911_INT_Change();
    delay_ms(50);

    在C源文件中添加读写GT911寄存器以及修改配置的相关函数:

    //reg:起始寄存器地址
    //buf:数据缓缓存区
    //len:写数据长度
    //返回值:0,成功;1,失败.
    u8 GT911_WR_Reg(u16 reg,u8 *buf,u8 len)
    {
         u8 i;
         u8 ret=0;
         IIC_Start();   
          IIC_Send_Byte(GT_CMD_WR);       //发送写命令     
         IIC_Wait_Ack();
         IIC_Send_Byte(reg>>8);       //发送高8位地址
         IIC_Wait_Ack();                                                          
         IIC_Send_Byte(reg&0XFF);       //发送低8位地址
         IIC_Wait_Ack(); 
         for(i=0;i<len;i++)
         {      
             IIC_Send_Byte(buf[i]);      //发数据
             ret=IIC_Wait_Ack();
             if(ret)break; 
         }
         IIC_Stop();                    //产生一个停止条件       
         return ret;
    }

    //reg:起始寄存器地址
    //buf:数据缓缓存区
    //len:读数据长度             
    void GT911_RD_Reg(u16 reg,u8 *buf,u8 len)
    {
         u8 i;
          IIC_Start();   
          IIC_Send_Byte(GT_CMD_WR);   //发送写命令     
         IIC_Wait_Ack();
          IIC_Send_Byte(reg>>8);       //发送高8位地址
         IIC_Wait_Ack();                                                          
          IIC_Send_Byte(reg&0XFF);       //发送低8位地址
         IIC_Wait_Ack(); 
          IIC_Start();             
         IIC_Send_Byte(GT_CMD_RD);   //发送读命令          
         IIC_Wait_Ack();      
         for(i=0;i<len;i++)
         {      
             buf[i]=IIC_Read_Byte(i==(len-1)?0:1); //发数据     
         }
         IIC_Stop();//产生一个停止条件   
    }

    //发送配置参数
    //mode:0,参数不保存到flash
    //     1,参数保存到flash
    u8 GT911_Send_Cfg(u8 mode)
    {
         u8 buf[2];
         u8 i=0;
         buf[0]=0;
         buf[1]=mode;    //是否写入到GT911 FLASH?  即是否掉电保存
         for(i=0;i<sizeof(GT911_Cfg);i++)buf[0]+=GT911_Cfg[i];//计算校验和
         buf[0]=(~buf[0])+1;
         GT911_WR_Reg(GT_CFGS_REG,(u8*)GT911_Cfg,sizeof(GT911_Cfg));//发送寄存器配置
         GT911_WR_Reg(GT_CHECK_REG,buf,2);//写入校验和,和配置更新标记
         return 0;
    }

    其中GT911_Cfg为寄存器配置数据,一般由厂商直接提供

    完整的GT911初始化代码如下:

    void GT911_Init(void)
    {   
         GT911_RST_Init();
         GT911_INT_Init();
         IIC_Init();
        
         GT911_RST(0);
         GT911_INT(1);
         delay_us(200);
         GT911_RST(1);
         delay_ms(6);
         GT911_INT(0);
         delay_ms(55);
         GT911_INT_Change();
         delay_ms(50);
        
         u8 tmp[4]={0};
         //读取PID
         GT911_RD_Reg(GT_PID_REG, tmp, 4);
        
         //修改配置
         tmp[0] = 0x02;
         GT911_WR_Reg(GT_CTRL_REG, tmp, 1);
         GT911_RD_Reg(GT_CFGS_REG, tmp, 1);
         if(tmp[0] < 0x60){
             printf("Default Ver:0x%X\r\n",tmp[0]);
             GT911_Send_Cfg(1);
         }
         delay_ms(10);
         tmp[0] = 0x00;
         GT911_WR_Reg(GT_CTRL_REG, tmp, 1);
        
         EXTIX_Init();
    }

    0x03 中断接收GT911坐标数据:

    GT911所连引脚外部中断初始化(PB1):

    void EXTIX_Init(void)
    {
          EXTI_InitTypeDef EXTI_InitStructure;
          NVIC_InitTypeDef NVIC_InitStructure;

          RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

          GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);

          EXTI_InitStructure.EXTI_Line=EXTI_Line1;   
           EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;   
           EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
           EXTI_InitStructure.EXTI_LineCmd = ENABLE;
           EXTI_Init(&EXTI_InitStructure);    

        NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;           
           NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
           NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;           
           NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                   
           NVIC_Init(&NVIC_InitStructure);
    }

    中断服务函数:

    查阅《GT911编程指南》:

    GT911坐标数据读取

    void EXTI1_IRQHandler(void)
    {
         u8 tmp;
         GT911_RD_Reg(0x8140, data, 0x40);
         tmp = data[0x0E];
         if((tmp&0x80) && ((tmp&0x0f)>0)){
             GetPointData(tmp&0x0f, data);
             ShowPointData();
         }
         tmp = 0;
         GT911_WR_Reg(0x814E, &tmp, 1);
        
         delay_ms(10);
         EXTI_ClearITPendingBit(EXTI_Line1);
    }

    data为全局数据(0x8140-0x8180一共0x40个数据),直接一次性读出所有的数据

    其中获取和打印坐标的相关函数:

    在GT911的头文件中:extern GT911_POINT_DATA     gt911_data;

    void GetPointData(u8 cnt, u8 data[])
    {
         gt911_data.cnt = 0;
         switch(cnt){
             case 5:
                 gt911_data.points[4].x = data[0x31]<<8 | data[0x30];
                 gt911_data.points[4].y = data[0x33]<<8 | data[0x32];       
             case 4:
                 gt911_data.points[3].x = data[0x29]<<8 | data[0x28];
                 gt911_data.points[3].y = data[0x2B]<<8 | data[0x2A];       
             case 3:
                 gt911_data.points[2].x = data[0x21]<<8 | data[0x20];
                 gt911_data.points[2].y = data[0x23]<<8 | data[0x22];
             case 2:
                 gt911_data.points[1].x = data[0x19]<<8 | data[0x18];
                 gt911_data.points[1].y = data[0x1B]<<8 | data[0x1A];
             case 1:
                 gt911_data.points[0].x = data[0x11]<<8 | data[0x10];
                 gt911_data.points[0].y = data[0x13]<<8 | data[0x12];           
                 break;
             default:
                 break;
         }

        gt911_data.cnt = cnt;
    }

    void ShowPointData(void)
    {
         u8 cnt = gt911_data.cnt;
         for(u8 i=0; i<cnt; i++){
             printf("Point%d(%d,%d)\t", i+1, gt911_data.points[i].x, gt911_data.points[i].y);
         }
         printf("\r\n");
         memset(&gt911_data, 0, sizeof(gt911_data));
    }

    0x04 验证结果:

    烧录程序至MCU,接线、上电,打开串口调试助手查看打印信息(最多同时五点触摸):

    串口打印坐标

  • 相关阅读:
    MySQL执行计划extra中的using index 和 using where using index 的区别
    Python + Apache Kylin 让数据分析更加简单!
    性能测试解读:Kyligence vs Spark SQL
    greenplum 表在各个节点数据的分布情况
    postgresql drop表后空间不释放
    PostgreSQL 查看表、索引等创建时间
    postgresql Kill掉正在执行的SQL语句
    linux ps命令查看最消耗CPU、内存的进程
    Linux shell
    TPC-H 下载参考
  • 原文地址:https://www.cnblogs.com/DarkBright/p/10730346.html
Copyright © 2020-2023  润新知