基于STM32F103口袋开发平台的模拟时钟及水平仪
本项目以“嵌入式系统可以玩着学 - 寒假在家一起练(5)”为契机,完成一个可以进行时间设置、整点报时、姿态翻转的模拟时钟,以及一个建议的水平仪。
标签
嵌入式系统
STM32
MPU
显示
接口
寒假在家一起练
C编程
youngsea
更新2021-03-03
1154

一、平台简介

      STM32F103 作为一款 Arm 架构Cortex-M3的一款入门级芯片,在嵌入式学习期间广受在校大学生、工程师等人员的青睐。本次活动使用的口袋开发平台上采用的是 STM32F103RBT6,具有128KB Flash,20KB Ram,足以满足大部分的简单需求。作为一块完整的开发板,该口袋平台上具有独立按键、蜂鸣器、姿态传感器、LCD等多种基础的片外外设。

二、项目简介

      本项目意在使用平台完成一个可以设置时间、整点报时的模拟时钟(量程为12小时),整点的时候可以通过板上的蜂鸣器以声音报时;转动板子,LCD屏上的时钟自动跟着旋转。作为模拟时钟表盘的设计以及转动板子时的图像旋转都要对LCD的基本功能进行考量,板子的旋转需要用到板上的姿态传感器MPU6050来感测。该项目本身(模拟时钟)并无太大难度。项目的主要难点在于对MPU6050测得的数据进行欧拉角的转化以及LCD的旋转绘制。

三、完成过程

  1.  工程基本框架搭建
    由于本人HAL库为初学,所以本项目代码框架并没有使用STM32CubeMX生成工程,而是使用标准固件库以及Keil MDK编译器搭建工程框架,使用基本流程创建项目,项目目录以及工程目录如下图:
                                               工程结构文件结构
                                                                                图一、工程结构(左)与目录结构(右)
  2. LCD代码移植:
    平台提供的LCD的驱动IC是ST7789,对其相关寄存器进行研究之后发现其中有几个寄存器是控制色块刷新以及数据传输方向的这个寄存器在屏幕旋转时是右用武之地的,但笔者并没有使用该方法进行屏幕旋转,因为使用此方法旋转之后,各个点的坐标需要重新找,在此排除该种旋转方式。既然没有其他有用的寄存器了那就开始进行驱动程序移植,该LCD采用的是驱动IC的SPI接口,由于相连的引脚没有可使用的硬件SPI可供使用,所以进行软件SPI的编写,软件SPI网络上有很多,随便找来一个稍加修改就能用,考虑到严谨性,便对内容进行简单的优化,由于习惯,将传输数据时的for循环改为while循环(主观感觉while的判断方式比for循环要简单一点点),在传输时要对传输的数据进行判断是发送1还是发送0,普遍方法是:
    if(dat&0x80)
    {
        LCD_SDA_Set();
    } else {
        LCD_SDA_Clr();
    }

    还有一种比较简单的写法是使用寄存器位的映射寄存器进行数据写入:

    #define LCD_SDA PBout(5)
    
    LCD_SDA = dat>>7;

    但是由于实际分析时后者并没有前者快,就索性使用前者了。分析原因应该是这个映射寄存器的读写速度或者说映射还需要个过程吧。。。具体原因没细究。

    软件SPI写好了之后就可以和驱动IC进行对接了,驱动IC的初始化序列时已经给好的了,直接填上就行,不过研究一下人家的初始化序列也是不错的,我简单看了一下,驱动序列里面有一个颜色取反的命令不知道为什么要颜色反显一次,某度上查不到原因索性就放弃了。至于界面的设计都是基本操作了,除了画圆就是画线,通过这次活动笔者也解除了两个小巧的GUI库,一个是μGUI这个库可以说是机器的精简,毕竟还是在开发之中的,没有button接口,不过无伤大雅可以说是很好用的,界面非常的复古,有点像winXP的风格,还有一个是LVGL,这个GUI功能相对于μGUI功能可是大了去了,而且这个GUI的运行方式感觉更像是一种内嵌的操作系统需要给GUI提供时间接口以及软中断的调用,使用起来相对来说比较复杂,功能太多就意味着没用的功能也多,索性就不用这些GUI了,有几个函数能在屏幕上圈圈点点的就够了。
                                                                      μGUI窗口对象
                                                                                        图二、μGUI窗口对象
    移植的驱动取自骑飞电子的驱动代码,下载自 LCD wiki,至于界面怎么画的就不细说了,简单说一下局部刷新吧,局部刷新我见过的有几种刷新方法一种是在一些视频里听到的叫做“开窗”的操作,我是没用过,还有一种是SPI设置LCD刷新范围然后进行刷新,这两个方法可能就是一个,没研究过前者的代码也不知道是不是这样。局部刷在简单的颜色域里其实也用不到。就比如说表针的绘制,每一次跳动都要画一次新表针,那旧的表针需要消去,就比如所我做的这个简单界面,总不能每隔一秒都要画一个方块再重新话一次界面吧,费时费力。函数划线只要两点确定了中间画的线的样子也随之固定了,倒不如把原来的表针用背景色绘画一次覆盖掉原来的表针,既达到了局部刷新的快速又能让界面不是一直在闪。屏幕旋转的话其实也还行,难点在于如果不适用驱动IC对界面进行翻转,如何将绘制的字符也随之翻转,其实直接改绘制字符的库就好了,根据旋转之后x和y的变化规律设置字符的绘制方向,就能完成字符的转向了。表盘上有六十个点每一个点的位置都需要进行计算,笔者的做法是设置几个数组序列将这些点一次性的全算出来写入数组,好处是省掉每次都需要运算,缺点就是占了空间,二者必有一失,不过自我感觉还是有点麻烦了。
  3. 姿态传感器
    姿态传感器MPU6050采用的是I2C接口,这下好了正好连上了硬件I2C,既然有了就开始整,毕竟以前就听说硬件I2C是个坑不好使,我也亲自体验一回,结果还真是难搞,在读数据的时候停止的非应答标志写在哪里都不对劲,即使采纳官方的解决办法效果也不是很如意,又花了半个钟头把硬件I2C改成了软件I2C,代码都是网上的轮子复制下来改改就好了。姿态角有三个方向,其中航向角本项目并不需要,那么又有两种解决办法了,一种是直接读取加速度值经过各种算法进行零点偏移矫正然后再通过如下公式进行计算
    //roll横滚角 pitch俯仰角 由加速计求得
    roll=atan(ax/sqrt(ay^2+az^2));
    pitch=atan(ay/sqrt(ax^2+az^2));

    还有一种是使用官方的DMP eMPL库,这样就省事多了,事情全是姿态传感器干的,需要做的就读取数据就完事了。没有算法基础的我更倾向于后者。

  4. 算出来之后就剩下和界面交互了,闲暇之余顺便吧水平仪也简单搞了一下,就是简单的将中心坐标加上欧拉角的偏移值画个圆就完事了。

以上就是本项目的全部完成过程。。。

附件下载
资料.zip
各种文档以及工具
STM32_Pocket_V2.0.zip
项目工程,更新内容:解决了时针显示不正常的问题
团队介绍
东北林业大学
团队成员
杨海洋
东北林业大学 信息与计算机工程学院 电子信息工程专业 2018级学生
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号