先说两句
最近上班摸鱼太无聊了,因为和某人约定好了要送一个礼物,又因为最近做嵌入式的原因,有点手痒,想自己做个东西玩玩,所以打算开始做个点阵屏。然后前阵子学了一下kicad,打算拿这个练手,算是我第一次画电路板。感觉和大佬比起来,我这就像过家家一样🙃。
MAX7219芯片
因为没学过硬件,画电路板没一点头绪,所以就花了5块钱从淘宝上买了一个8×8的点阵屏,打算抄参考一下,买来以后是这样的:
感觉比我想像的要简单一点,就一个芯片、一个点阵屏、一个电容和一个电阻。去找商家要了一下资料(下载链接),后来才知道这个芯片叫MAX7219。扫了一眼MAX7219的芯片手册,没怎么看懂🙃,结合资料里的样例代码才勉强看懂了一点点。
硬件方面
MAX7219一共有24个引脚,各个引脚的功能如下表:
管脚 | 名称 | 功能描述 |
---|---|---|
1 | DIN | 串行数据输入端口。在时钟上升沿时数据被载入内部的16位寄存器。 |
2,3,5-8,10,11 | DIG0–DIG7 | 八个数据驱动线路置显示器共阴极为低电平。关闭时此管脚输出高电平。 |
4,9 | GND | 地线(4 脚和 9 脚必须同时接地) |
12 | LOAD | 载入数据。连续数据的后16位在LOAD端的上升沿时被锁定。 |
13 | CLK | 时钟序列输入端。最大速率为10MHz.在时钟的上升沿,数据移入内部移位寄存器。下降沿时,数据从DOUT端输出。 |
14-17,20-23 | SEGA-SEGG,DP | 7段和小数点驱动,为显示器提供电流。当一个段驱动关闭时,此端呈低电平 |
18 | SET | 通过一个电阻连接到 $V_{DD}$ 来提高段电流。 |
19 | $V_{+}$ | 正极电压输入,+5V(好像3.3V)也可以 |
24 | DOUT | 串行数据输出端口,从DIN输入的数据在16.5个时钟周期后在此端有效。当使用多个MAX7219时用此端方便扩展。 |
然后8×8的点阵屏模块MAX7219部分的原理图是这样的:
按照原理图,MAX7219的DIG0–DIG7接点阵屏的共阴极,SEGA-SEGG和DP接点阵屏的共阳极,DIN、CLK、LOAD接到MCU的IO口上,用来与MCU通信,DOUT接到下一个MAX7219的DIN上,用来实现多个级联。
然后其他引脚按照电路图接对应的元件和电源就好了。
软件方面
控制MAX7219的方式是写寄存器,MAX7219一共有14个8位的可寻址的数据寄存器和控制寄存器,MCU通过给这些寄存器写数据来控制MAX7219的工作。
写移位寄存器
刚刚说到,MAX7219有3个引脚(DIN、CLK、LOAD)是接到MCU的IO口上的,写寄存器就是通过这3个引脚来完成的。在MAX7219里有一个16位的移位寄存器,当CLK引脚出现一个上升沿的电压信号后,MAX7219就会将DIN端的信号移入移位寄存器里,作为移位寄存器的最后一位。
举个栗子,下图中在CLK的第1个上升沿,MCU给了DIN一个高电平,所以MAX7219的移位寄存器移入了一个1,然后在CLK的第2个上升沿,MCU给了DIN一个低电平,所以MAX7219的移位寄存器移入了一个0。最终的效果就是移位寄存器里原来的数据向前移动了两位,后两位数据变成了移入的1和0。
按照上面说的方法,连续写16位数据,就可以把移位寄存器写成我们想要的数据了。
写内部寄存器
数据写入移位寄存器之后,就可以利用移位寄存器的数据来更改MAX7219的14个数据寄存器和控制寄存器(以下简称为内部寄存器)了。
移位寄存器的数据可以分成两个部分,一部分是用来表示内部寄存器的地址,占4位,位于第8到第11位,一部分是用来表示寄存器的数据,位于第0到第7位,如下图所示:
当MCU给LOAD引脚一个上升沿信号时,MAX7219就根据移位寄存器中的4个地址位,选择对应的内部寄存器,然后把移位寄存器里的8个数据位写入该寄存器中。
结合之前的写移位寄存器的方法,就可以实现将数据据写入对应的内部寄存器中了。这里给出一个用来写内部寄存器的参考代码:
1 | /** |
内部寄存器
刚刚已经介绍了如何写内部寄存器,接下来就是如何用这14个内部寄存器控制MAX7219工作。这些寄存器分两类,一类是控制寄存器,共5个,分别用来设置编码模式、显示亮度、扫描限制、掉电模式以及显示检测,另一类是数据寄存器,用来设置显示的数据。
地址 | 寄存器 |
---|---|
0x00 | 不工作寄存器 |
0x01-0x08 | 8个数据寄存器 |
0x09 | 译码模式寄存器 |
0x0A | 亮度控制寄存器 |
0x0B | 扫描控制寄存器 |
0x0C | 掉电模式寄存器 |
0x0F | 显示检测寄存器 |
数据寄存器很好理解,共8个,对应8个段选,每个8位,每一位对应SEGA~SEGG和SEGDP八个引脚的输出电平。MAX7219工作时,DIG0~7八个引脚会按顺序输出低电平,同时根据数据寄存器中的值,给SEG八个引脚输出对应的电平。比如,当前DIG引脚输出低电平时,其他DIG引脚都输出高电平,MAX7219就按照第2个数据寄存器(地址是0x03)中的值,给SEG引脚输出对应的电平,下一次就轮到给DIG3引脚输出低电平,按照第3个数据寄存器中的值,给SEG引脚输出对应的电平,如此循环八个引脚。
控制寄存器我没怎么细看,打算直接按照参考的驱动代码设置,如下:
1 | /** |
按照上面的代码初始化好后,将要显示的内容写入数据寄存器就好了。比如要显示一个字母’A’的代码如下:
1 | /** |
点阵屏
点阵屏比较容易理解,就是一些led灯组成的点阵。分为共阴极和共阳极两种,共阴极点阵屏的同一行led阴极是连在一起的,同一列的阳极连在一起,而共阳极点阵屏同一行led的阳极是连在一起的,同一列的阴极连在一起。原理图如下(左边是共阳,右边是共阴):
从点阵屏的正面看,四个边中有个一个边有突起,将那个边向下,这时点阵的行和列就和上图对应了。上图中圆圈里的编号是引脚编号,点阵屏一共有16个引脚,分成两行,按刚刚的方法放好,上面一排的引脚编号从左往右是16、15、…、9,下面一排的引脚编号从左往右是1、2、…、8。
硬件设计
原理图设计
看懂了MAX7219和点阵屏的工作原理后,就可以用kicad开始设计电路了。kicad是一个开源的PCB设计软件,用起来感觉不错,而且有中文文档教程,还跨平台,对于我这个新手来说相当友好,想了解的小伙伴可以去kicad的官网看看。
kicad的元件库里有MAX7219,可以直接拿来用,但是没有点阵屏,所以要自己加一个点阵屏元件,下图是我自己加的1088AS元件和封装:
接下来就是设计原理图了,MAX7219部分可以参考资料里的原理图来设计,要做成16×16的点阵的话,需要4个8×8点阵拼接起来,原理图就是下面这样的。
MCU本来打算用STM32F103C8T6的,在淘宝上看了一下,发现最近因为芯片缺货的问题,C8T6涨到了30块钱一片😓….,不过C6T6价格还可以接受,6块一片,而且C6T6的引脚和C8T6的完全一样,用来替代C8T6刚刚好。去网上找了一个STM32F103C8T6最小系统板的资料,参考原理图改了一下,如下:
完整的pdf原理图可以在这里查看。
电路设计
设计好原理图后开始设计电路。
首先选择封装,所有的电阻和电容都选择0603贴片,两个LED灯用了0805,USB插座想用type-c的,本来想用6PIN的,在kicad里没找到6PIN的封装,干脆就用16PIN的了,都差不多。其他的按照元件的尺寸随便选了一些。
接下来就是让人头大的布线了,唔….,第一次布线,感觉比想像中要难一些,改了很久才搞定,特别是MCU附近的线比较难走线。布好线后是这样的:
kicad里有个3D查看器,可以模拟成品的样子,大概是这个样子的:
左边是正面,右边是背面,因为点阵屏的封装里没有3D模型,所以这个渲染出来就没有点阵屏。
制作
布好线后,在淘宝上找了个PCB打样的,发现22块钱能打10块板子,感觉还算比较便宜。打样好是这个样子的:
然后把需要的元件都买到后,开始焊板子,感觉比想像中要难焊一点,特别是焊MCU的时候,锡容易把两个引脚粘在一起,用了助焊剂后好了很多。焊好后是这样的:
焊的有点丑,有些电容和电阻歪了。接下来把点阵屏插上去应该就能用了。
写代码
环境搭建
用STM32CubeMX生成了一个工程(不清楚的小伙伴可以参考这篇博客),按照电路的连接,配置对应引脚为GPIO上拉输出模式。
接下来生成工程代码,make以后尝试烧录,烧录失败了….。openocd报了下面这个错:
1 | > program build/lattice_screen.hex |
一开始还以为是芯片某个引脚没焊好,然后检查一下电路,发现没问题。百度了一下,网上说是因为芯片flash上了锁,要解锁才能烧录,参考了一下大佬的这篇博客,用openocd执行下面的解锁命令后,就可以烧录了。
1 | > reset halt |
汉字编码生成
要显示一个汉字,需要有对应的汉字编码,自己设计比较麻烦,在网上找了一个大佬写的生成16×16汉字点阵的代码。大致的原理是用汉字的GB2312编码,在HZK16字库中,索引到对应的编码,然后打印出来。
显示逻辑
前面说了8×8点阵屏的显示逻辑,现在是16×16的,也就是4个8×8拼在一起,所以只要让每个8×8显示对应的内容就好了,显示一个汉字的代码如下:
1 | /** |
接下来实现一个字符串的循环移动显示,其实也很简单,只要在一定的延时后,把汉字编码按照一定的逻辑,循环移动一位,然后再把开头显示出来就好了。循环移位的代码如下:
1 | /** |
主函数代码:
1 | HAL_Delay(2); // 防止MAX7219未正常启动 |
成果演示
虽然点阵屏算是比较简单的一个东西,但是因为是第一次自己画板子,设计电路,感觉还是挺好玩的。
这个点阵屏的硬件设计和代码都已经放到github上了,https://github.com/ganyuo/lattice_screen。