请选择 进入手机版 | 继续访问电脑版

迪文科技论坛

 找回密码
 立即注册
搜索
查看: 1132|回复: 0

【开源】利用自重力实现横竖屏切换(一)

[复制链接]

4

主题

4

回帖

419

积分

中级会员

Rank: 3Rank: 3

积分
419
发表于 2020-11-2 15:30:45 | 显示全部楼层 |阅读模式
本帖最后由 湘江旧迹秋心 于 2020-12-5 21:15 编辑

T5L屏能够利用指令通过改变系统变量地址0x81上的.1-.0位,实现显示方向的更改。在有些应用场合下,我们可能更希望利用重力感应实现屏幕显示方向的自动更改。
在这里,限于内容,第一节我主要介绍使用MPU6050芯片实现横竖屏切换的功能的主要原理,下一节将贴上个人写的功能代码。
MPU6050是一种六轴运动传感器,能够输出姿态角(俯仰角,横滚角,偏转角),被大量用于飞行器等需要姿态输出的控制场合中,所以使用MPU6050可以有效帮助没有使用经验的人减少开发时间。关于其详细介绍,我在这里不做过多的概述,网络上非常多,鉴于MPU6050的某些特性,我将介绍两种方案。
方案一:使用MPU6050芯片
图0是mpu6050的原理图,其使用IIC(SCL和 SDA)作为通信接口,鉴于T5L没有IIC口,所以需要用软件模拟的方法,这一点可以参考IIC通信的时序图进行编辑。
//I2C起始信号
void I2C_Start()
{
    SDA = 1;                 
    SCL = 1;                  

    Delay5us();                 //延时
    SDA = 0;                    //产生下降沿
    Delay5us();
    SCL=0;                //延时
}

//I2C停止信号
void I2C_Stop()
{
    SDA = 0;                    //拉低数据线
    SCL = 1;                    //拉高时钟线
    Delay5us();                 //延时
    SDA = 1;                    //产生上升沿
    Delay5us();                 //延时
}

//I2C发送应答信号,入口参数:ack (0:ACK 1:NAK)
void I2C_SendACK(bit ack)
{
    SDA = ack;                  //写应答信号
    SCL = 1;                    //拉高时钟线
    Delay5us();                 //延时
    SCL = 0;                    //拉低时钟线
    Delay5us();                 //延时
}

//I2C接收应答信号
bit I2C_RecvACK()
{
    SCL = 1;                    //拉高时钟线
    Delay5us();                 //延时
    CY = SDA;                   //读应答信号
    SCL = 0;                    //拉低时钟线
    Delay5us();                 //延时
    return CY;
}

//向I2C总线发送一个字节数据
void I2C_SendByte(uchar dat)
{
    uchar i;
    for (i=0; i<8; i++)         //8位计数器
    {
        dat <<= 1;              //移出数据的最高位
        SDA = CY;               //送数据口
        SCL = 1;                //拉高时钟线
        Delay5us();             //延时
        SCL = 0;                //拉低时钟线
        Delay5us();             //延时
    }
    I2C_RecvACK();
}

//从I2C总线接收一个字节数据
uchar I2C_RecvByte()
{
    uchar i;
    uchar dat = 0;
    SDA = 1;                    //使能内部上拉,准备读取数据,
    for (i=0; i<8; i++)         //8位计数器
    {
        dat <<= 1;
        SCL = 1;                //拉高时钟线
        Delay5us();             //延时
        dat |= SDA;             //读数据               
        SCL = 0;                //拉低时钟线
        Delay5us();             //延时
    }
    return dat;
}

完成了这一步,就可以做MPU605的程序了。
MPU6050的程序可以分为以下几步:
1)  初始化IIC接口
2)  复位 MPU6050
这一步让 MPU6050 内部所有寄存器恢复默认值,通过对电源管理寄存器 1(0X6B)的bit7 写 1 实现。复位后,电源管理寄存器 1 恢复默认值(0X40),然后必须设置该寄存器为0X00,以唤醒 MPU6050,进入正常工作状态。
3)  设置角速度传感器(陀螺仪)和加速度传感器的满量程范围
这一步,我们设置两个传感器的满量程范围(FSR),分别通过陀螺仪配置寄存器(0X1B)和加速度传感器配置寄存器(0X1C)设置。我们一般设置陀螺仪的满量程范围为±2000dps,加速度传感器的满量程范围为±2g。
4)  设置其他参数
这里,我们还需要配置的参数有:关闭中断、关闭 AUX IIC 接口、禁止 FIFO、设置陀螺仪采样率和设置数字低通滤波器(DLPF)等。我们不用中断方式读取数据,所以关闭中断,然后也没用到 AUX IIC 接口外接其他传感器,所以也关闭这个接口。分别通过中断使能寄存器(0X38)和用户控制寄存器(0X6A)控制。MPU6050 可以使用 FIFO 存储传感器数据,不过我们没有用到,所以关闭所有 FIFO 通道,这个通过 FIFO 使能寄存器(0X23)控制,默认都是 0(即禁止FIFO),所以用默认值就可以了。陀螺仪采样率通过采样率分频寄存器(0X19)控制,这个采样率我们一般设置为 50 即可。数字低通滤波器(DLPF)则通过配置寄存器(0X1A)设置,一般设置 DLPF 为带宽的 1/2 即可。
5)  配置系统时钟源并使能角速度传感器和加速度传感器
系统时钟源同样是通过电源管理寄存器 1(0X1B)来设置,该寄存器的最低三位用于设置系统时钟源选择,默认值是 0(内部 8M RC 震荡),不过我们一般设置为 1,选择 x 轴陀螺 PLL 作为时钟源,以获得更高精度的时钟。同时,使能角速度传感器和加速度传感器,这两个操作通过电源管理寄存器 2(0X6C)来设置,设置对应位为 0即可开启。
至此,MPU6050 的初始化就完成了,可以正常工作了(其他未设置的寄存器全部采用默认值即可),接下来,我们就可以读取相关寄存器,得到加速度传感器、角速度传感器和温度传感器的数据了。
以下是部分代码程序,可以在T5L上运行
//向I2C设备写入一个字节数据
void Single_WriteI2C(uchar REG_Address,uchar REG_data)
{
    I2C_Start();                  //起始信号
    I2C_SendByte(SlaveAddress);   //发送设备地址+写信号
    I2C_SendByte(REG_Address);    //内部寄存器地址,
    I2C_SendByte(REG_data);       //内部寄存器数据,
    I2C_Stop();                   //发送停止信号
}

//从I2C设备读取一个字节数据
uchar Single_ReadI2C(uchar REG_Address)
{
        uchar REG_data;
        I2C_Start();                   //起始信号
        I2C_SendByte(SlaveAddress);    //发送设备地址+写信号
        I2C_SendByte(REG_Address);     //发送存储单元地址,从0开始        
        I2C_Start();                   //起始信号
        I2C_SendByte(SlaveAddress+1);  //发送设备地址+读信号
        REG_data=I2C_RecvByte();       //读出寄存器数据
        I2C_SendACK(1);                 //接收应答信号
        I2C_Stop();                    //停止信号
        return REG_data;
}

//初始化MPU6050
void MPU6050_Init(void)
{
  int i=0,j=0;
  for(i=0;i<1000;i++)
  {
    for(j=0;j<1000;j++)
    {
      ;
    }
  }
    Single_WriteI2C(MPU6050_RA_PWR_MGMT_1, 0x00);        //解除休眠状态
    Single_WriteI2C(MPU6050_RA_SMPLRT_DIV , 0x07);        //陀螺仪采样率,1KHz
    Single_WriteI2C(MPU6050_RA_CONFIG , 0x06);            //低通滤波器的设置,截止频率是1K,带宽是5K
    Single_WriteI2C(MPU6050_RA_ACCEL_CONFIG , 0x00);      //配置加速度传感器工作在2G模式,不自检
    Single_WriteI2C(MPU6050_RA_GYRO_CONFIG, 0x18);     //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
}
//获得数据
int GetData(uchar REG_Address)                        
{
        uchar H,L;
        H=Single_ReadI2C(REG_Address);
        L=Single_ReadI2C(REG_Address+1);
        return (H<<8)+L;            

}
void MPU6050_ReadData(u8 reg_add,unsigned char*Read,u8 num)
{
    unsigned char i;
   
    I2C_Start();
    Single_WriteI2C(MPU6050_SLAVE_ADDRESS);
    Single_WriteI2C(reg_add);
   
    I2C_Start();
    Single_WriteI2C(MPU6050_SLAVE_ADDRESS+1);
   
    for(i=0;i<(num-1);i++){
        *Read=IIC_mpu6050_ReadByte(1);
        Read++;
    }
    *Read=Single_ReadI2C(0);
    I2C_Stop();
}
void MPU6050ReadAcc(short *accData)
{
    u8 buf[6];
    Single_ReadI2C(MPU6050_ACC_OUT, buf, 6);
    accData[0] = (buf[0] << 8) | buf[1];
    accData[1] = (buf[2] << 8) | buf[3];
    accData[2] = (buf[4] << 8) | buf[5];
}
void MPU6050ReadGyro(short *gyroData)
{
    u8 buf[6];
    Single_ReadI2C(MPU6050_GYRO_OUT,buf,6);
    gyroData[0] = (buf[0] << 8) | buf[1];
    gyroData[1] = (buf[2] << 8) | buf[3];
    gyroData[2] = (buf[4] << 8) | buf[5];
}
void MPU6050ReadTemp(short *tempData)
{
    u8 buf[2];
    Single_ReadI2C(MPU6050_RA_TEMP_OUT_H,buf,2);     //读取温度值
    *tempData = (buf[0] << 8) | buf[1];
}
void MPU6050_ReturnTemp(float *Temperature)
{
    short temp3;
    u8 buf[2];
   
    Single_ReadI2C(MPU6050_RA_TEMP_OUT_H,buf,2);     //读取温度值,
    temp3= (buf[0] << 8) | buf[1];   
    *Temperature=((double) temp3/340.0)+36.53;      
//转换温度值为摄氏度
}
下图是我用串口助手将数据进行打印的一个效果。
//以下是部分MPU6050的内部地址
#define        SMPLRT_DIV             0x19        //陀螺仪采样率,典型值:0x07(125Hz)
#define        CONFIG                     0x1A        //低通滤波频率,典型值:0x06(5Hz)
#define        GYRO_CONFIG          0x1B        //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define        ACCEL_CONFIG        0x1C        //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
#define        ACCEL_XOUT_H       0x3B
#define        ACCEL_XOUT_L       0x3C
#define        ACCEL_YOUT_H       0x3D
#define        ACCEL_YOUT_L       0x3E
#define        ACCEL_ZOUT_H      0x3F
#define        ACCEL_ZOUT_L      0x40
#define        TEMP_OUT_H         0x41
#define        TEMP_OUT_L         0x42
#define        GYRO_XOUT_H      0x43
#define        GYRO_XOUT_L       0x44        
#define        GYRO_YOUT_H      0x45
#define        GYRO_YOUT_L       0x46
#define        GYRO_ZOUT_H      0x47
#define        GYRO_ZOUT_L      0x48
#define        PWR_MGMT_1      0x6B        //电源管理,典型值:0x00(正常启用)
#define        WHO_AM_I           0x75        //IIC地址寄存器(默认数值0x68,只读)
#define        SlaveAddress         0xD0        //IIC写入时的地址字节数据,+1为读取
//函数声明
实际上,此时输出的只是加速度,还需要用姿态融合算法进行处理,这些比较话多,直接看教程吧https://zhuanlan.zhihu.com/p/20082486
到这一步也就完成MPU6050的工作,下一步就是在T5L屏上的处理了,所以先说一下第二种方案吧。
方案一:使用对MPU6050进行过封装的芯片

在这里,我以陀螺仪加速度计 JY61(MPU6050)为例进行讲解。JY61和MPU6050为从属关系。六轴模块jy61自带稳压电路,包含陀螺仪加速度计MPU6050和STM8单片机,STM8通过IIC读取 MPU6050 中DMP的测量数据然后通过串口输出,免去了用户自己去开发 MPU6050 复杂的 IIC 协议;同时保留了 MPU6050 的 IIC 接口,以满足用户访问底层测量数据(加速度、角速度)的需求,所以我比较倾向于使用这个方案,具体原理参考文章https://blog.csdn.net/weixin_45263626/article/details/105230225,讲的也是比较简单易懂。
对于T5L屏的串口处理程序,论坛里有很多,就不多说了。
到了这儿,姿态数据的获取已经完成了,接下来就是屏幕的配合了,这儿我们需要提前准备两张背景图,横屏和竖屏的,并且用DGUS做好工程,注意,两张背景图上必须是一模一样的控件,即他们的地址,功能要相同,然后我们利用页面切换+方向更改命令或者在T5L上进行编程处理。







本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

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

本版积分规则

QQ|Archiver|手机版|小黑屋|迪文科技论坛 ( 京ICP备05033781号-1 )

GMT+8, 2024-3-28 19:44 , Processed in 0.100177 second(s), 22 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表