【赛博沙漏科普】MAX7219 芯片与模块学习
前言
Hello,大家好,今天我们来讨论一下老掉牙但应用广泛的MAX7219(咱已然立誓,不是老掉牙的芯片坚决不讨论,哈哈,不要打我),它是一款可以驱动多位LED的芯片。
MAX7219的硬件连接比较简单,除用于驱动LED的16个引脚外,ISET引脚可以设置LED的驱动电流值(因为MAX7219是恒流驱动形式)。也就是说,你只需要额外添加一个外围电阻即可使MAX7219正常工作,《显示器件》给出的电路类似如下图所示。需要特别注意的是,MAX7219只能驱动共阴(common-cathode)类型的数码管。

引脚


数据传输与寄存器
那怎么样才能让MAX7219驱动数码管显示想要的数据呢?几乎所有LED驱动芯片是相似的,我们肯定需要往芯片的某个存储区域写入一些数据。首先我们来明确单片机是如何控制MAX7219的,它是由时钟(CLK)、数据(DIN)、载入(LOAD)这3个引脚完成的串行通信来实现,每次传输16位数据(高位先行),
时序图:

相应的格式如下图所示。

可以看到,给MAX7219发送的16位数据中,低8位是具体的数据(DATA),而高8位为相应的地址(ADDRESS,仅低4位有效),所以其有效的寄存器最多只有16个(8位寄存器),所以我们接下来需要明确这16个寄存器各自的功能是什么。
MAX7219内部存在14个寄存器(2个地址无效),总体来说可以分为数据寄存器与控制寄存器,前者决定LED数码管可以显示的内容(简单地说,你往里面写什么,LED数码管就会显示什么),后者则决定LED如何显示内容,具体如下图所示。

数据寄存器
Digit0~~Digit7(地址为0x1~0x8,写成0xX1~0xX8是因为仅低4位有效)这8个寄存器分别对应多位数码管的每一位数字,在上面的仿真电路图中,Digit0对应最左侧位,Digit1对应左侧第二位,其它依此类推,下面为显示数字0~7的仿真效果。
控制寄存器
1.译码模式(Decode Mode)寄存器
现在的问题是:怎么样才能显示出这样的效果呢?往数据寄存器中写入BCD码还是字型码(代表每个段亮灭的数据)呢?这取决于译码模式(Decode Mode)寄存器,它的每一位(共8位)可以控制相应数据寄存器的译码模式,具体如下表所示。

例如,当设置译码模式寄存器的D0位为1时,表示Digit0数据寄存器中的数据会经过译码后驱动LED数码管(而不是直接输出),这样如果你需要最左侧显示“0”,则只需要往Digit0数据寄存器中写入0的BCD码即可(也就是0),具体的译码表如下所示。

如果你选择不译码,数据寄存器中的数据会直接输出以驱动LED数码管的每个段,那么同样显示数字“0”就得往相应的数据寄存器中写入0b1111110(0x7E)。也就是说,译码模式对于LED数码管非常方便,但是只能显示约定好的某些特定字符,对于需要驱动LED点阵模块的场合,通常还是会选择不译码。
当然,上面这个译码表成立的前提条件是,你必须按照预定义的连接方式将MAX7219与LED数码管连接,MAX7219约定的段与数据位的对应关系如下图所示,前面的仿真电路图也遵从此约定,这样可以避免将简单的问题复杂化。

需要注意的是,当你使用译码模式时,数据寄存器仅使用到了低7位,而最高位对应小数点控制位(1为亮,0为灭)在译码模式中没有用到,需要手动写入。
2. 扫描限制(Scan-Limit)寄存器
MAX7219还可以控制扫描的数码管位数,这是由扫描限制(Scan-Limit)寄存器完成的。与译码模式控制寄存器有限不同的是,你需要往其中输入限制位数的BCD码(而并非每一位数据寄存器对应控制扫描与否,这也就意味着,扫描位数只能是连续的,你不能异想天开地只企图扫描第1、3、5位)。例如,当你往其中写入0时,表示仅扫描第0位对应的数码管(其它数码管不会亮,即便你已经往其中写入了数据),当你往其中写入4时,则表示第0、1、2、3、4位都会扫描,而5、6、7位不扫描(不会亮)、
3. 显示测试(Display Test)寄存器
显示测试寄存器主要用于测试,当其最低位为1时,表示进入测试模式,此时所有数码管都会亮起来(即显示8.8.8.8.8.8.8.8.),这样你就可以判断芯片驱动是否正常,数码管是否存在无法点亮的段等情况。在正常工作(Normal Operation)时,应该将其最低位置0。
4. 关闭寄存器
关闭寄存器可以控制是否输出。在关闭模式下,MAX7219内部时钟源处于挂起状态,所有段驱动引脚(Seg A,B,C,…)都下拉到地,所有位选通引脚(DIG0~7)都上拉到电源,此时所有数码管都不会显示。
案例
下图为限制低4位扫描时依次发送的数据。

首先发送“F00”表示往显示测试寄存器(地址为0xF)中写入0,将最低位清零也就进入了正常工作模式。
然后往译码模式寄存器(地址为0x9)中写入“9FF”,表示进行全8位译码(BCD译码),因为我们驱动的是LED数码管。接下来的“B03”表示限制扫描位数为0、1、2、3,所以最右侧4位是不会显示的。
“A0F”通过往亮度(Intensity)寄存器中写入数据以达到控制LED显示亮度的目的,本质上是通过控制PWM来实现的,受限于篇幅不再讨论,因为即便你不往其中写入数据,MAX7219也存在一个默认的亮度,有兴趣的读者可参考《显示器件》一书。
紧接着往关闭寄存器(地址为0xC)中发送“C01”,将最低位置1即可进入正常工作模式。
此后,数据寄存器中的数据将会被显示出来。当然,到目前为止,我们还没有往数据寄存器中写入任何内容,本例中依次往地址0x1~0x8中写入0~7的BCD码即可。
STM32 实例代码
/*******************************************************************************
* 函数名:Write_Max7219_Date
* 描述 :向Max7219写入数据
* 输入 :addr地址,dat数据
* 输出 :void
* 调用 :内部调用
* 备注 :
*******************************************************************************/
void Write_Max7219_Date(uint8_t addr,uint8_t dat)
{
uint8_t i;
SPI2_CLK_LOW();
SPI2_CS_LOW();//拉低CS,选中器件
//发送地址
for(i=0;i<8;i++)
{
if(addr & 0x80)
{
SPI2_SI_HIGH();
}
else
{
SPI2_SI_LOW();
}
addr <<= 1;
SPI2_CLK_HIGH();
SPI2_CLK_LOW();
}
//发送数据
for(i=0;i<8;i++)
{
if(dat & 0x80)
{
SPI2_SI_HIGH();
}
else
{
SPI2_SI_LOW();
}
dat <<= 1;
SPI2_CLK_HIGH();
SPI2_CLK_LOW();
}
SPI2_CS_HIGH();//发送结束,上升沿锁存数据
SPI2_CLK_LOW();
SPI2_SI_LOW();
}
宏定义
/* Defines ------------------------------------------------------------------*/
#define DIG0_Registe 0x01//选位0寄存器
#define DIG1_Registe 0x02//选位1寄存器
#define DIG2_Registe 0x03//选位2寄存器
#define DIG3_Registe 0x04//选位3寄存器
#define DIG4_Registe 0x05//选位4寄存器
#define DIG5_Registe 0x06//选位5寄存器
#define DIG6_Registe 0x07//选位6寄存器
#define DIG7_Registe 0x08//选位7寄存器
#define DECODE_MODE 0x09//译码模式寄存器
//0x00:7-0不采用译码
//0x01:0采用BCD译码,7-1不采用
//0x0F:3-0采用BCD译码,7-4不采用
//0xFF:7-0采用BCD译码
//当选择BCD译码模式时,译码器只对数据的低四位进行译码(D3-D0),D4-D6为无效位。D7位用来设置小数点,不受译码器的控制且为高电平。
//当选择不译码时,数据的八位与MAX7219的各段线上的信号一致。
#define INTENSITY 0x0A//亮度寄存器
//亮度等级设置 0x00-0x0F 设置电流为最大电流的 1/32 - 31/32(间隔2/32)
//也可以通过硬件来改变,修改V+和ISET之间的电阻阻值大小,最小阻值为9.53kΩ,它设定段电流为40mA。
#define SCAN_LIMIT 0x0B//扫描寄存器
//0x00:只显示数字0
//0x01:显示数字0&1
//0x02:显示数字0,1,2
//0x03:显示数字0,1,2,3
//0x04:显示数字0,1,2,3,4
//0x05:显示数字0,1,2,3,4,5
//0x06:显示数字0,1,2,3,4,5,6
//0x07:显示数字0,1,2,3,4,5,6,7
#define SHUTDOWN 0x0C//掉电寄存器
//0x00:掉电模式
//0x01:正常模式
#define DISPLAY_TEST 0x0F//显示测试寄存器
//0x00:正常模式
//0x01:显示测试模式
#define SHUTDOWN 0x0C//掉电寄存器
//0x00:掉电模式
//0x01:正常模式
Write_Max7219_Date(SHUTDOWN,0x01);//掉电模式:0;普通模式:1
#define DECODE_MODE 0x09//译码模式寄存器
//0x00:7-0不采用译码
//0x01:0采用BCD译码,7-1不采用
//0x0F:3-0采用BCD译码,7-4不采用
//0xFF:7-0采用BCD译码
//当选择BCD译码模式时,译码器只对数据的低四位进行译码(D3-D0),D4-D6为无效位。D7位用来设置小数点,不受译码器的控制且为高电平。
//当选择不译码时,数据的八位与MAX7219的各段线上的信号一致。
Write_Max7219_Date(DECODE_MODE,0x00);//译码方式:非BCD译码
#define INTENSITY 0x0A//亮度寄存器
//亮度等级设置 0x00-0x0F 设置电流为最大电流的 1/32 - 31/32(间隔2/32)
//也可以通过硬件来改变,修改V+和ISET之间的电阻阻值大小,最小阻值为9.53kΩ,它设定段电流为40mA。
Write_Max7219_Date(INTENSITY,0x0C);//亮度
#define SCAN_LIMIT 0x0B//扫描寄存器
//0x00:只显示数字0
//0x01:显示数字0&1
//0x02:显示数字0,1,2
//0x03:显示数字0,1,2,3
//0x04:显示数字0,1,2,3,4
//0x05:显示数字0,1,2,3,4,5
//0x06:显示数字0,1,2,3,4,5,6
//0x07:显示数字0,1,2,3,4,5,6,7
Write_Max7219_Date(SCAN_LIMIT,0x07);//扫描界限:8个数码管显示
#define DISPLAY_TEST 0x0F//显示测试寄存器
//0x00:正常模式
//0x01:显示测试模式
Write_Max7219_Date(DISPLAY_TEST,0x00);//显示测试:1;测试结束,正常显示:0
初始化函数案例;
/*******************************************************************************
* 函数名:User_Max7219_Init
* 描述 :MAX7219配置初始化
* 输入 :void
* 输出 :void
* 调用 :初始化
* 备注 :
*******************************************************************************/
void User_Max7219_Init(void)
{
User_SPI2_Init();//SPI引脚配置初始化
Write_Max7219_Date(SHUTDOWN,0x01);//掉电模式:0;普通模式:1
Write_Max7219_Date(DISPLAY_TEST,0x00);//显示测试:1;测试结束,正常显示:0
Write_Max7219_Date(DECODE_MODE,0x00);//译码方式:非BCD译码
Write_Max7219_Date(SCAN_LIMIT,0x07);//扫描界限:8个数码管显示
Write_Max7219_Date(INTENSITY,0x0C);//亮度
}
8-8 LED 显示屏参考编码
uchar code disp1[38][8]={
{0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C},//0
{0x10,0x18,0x14,0x10,0x10,0x10,0x10,0x10},//1
{0x7E,0x2,0x2,0x7E,0x40,0x40,0x40,0x7E},//2
{0x3E,0x2,0x2,0x3E,0x2,0x2,0x3E,0x0},//3
{0x8,0x18,0x28,0x48,0xFE,0x8,0x8,0x8},//4
{0x3C,0x20,0x20,0x3C,0x4,0x4,0x3C,0x0},//5
{0x3C,0x20,0x20,0x3C,0x24,0x24,0x3C,0x0},//6
{0x3E,0x22,0x4,0x8,0x8,0x8,0x8,0x8},//7
{0x0,0x3E,0x22,0x22,0x3E,0x22,0x22,0x3E},//8
{0x3E,0x22,0x22,0x3E,0x2,0x2,0x2,0x3E},//9
{0x8,0x14,0x22,0x3E,0x22,0x22,0x22,0x22},//A
{0x3C,0x22,0x22,0x3E,0x22,0x22,0x3C,0x0},//B
{0x3C,0x40,0x40,0x40,0x40,0x40,0x3C,0x0},//C
{0x7C,0x42,0x42,0x42,0x42,0x42,0x7C,0x0},//D
{0x7C,0x40,0x40,0x7C,0x40,0x40,0x40,0x7C},//E
{0x7C,0x40,0x40,0x7C,0x40,0x40,0x40,0x40},//F
{0x3C,0x40,0x40,0x40,0x40,0x44,0x44,0x3C},//G
{0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x44},//H
{0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x7C},//I
{0x3C,0x8,0x8,0x8,0x8,0x8,0x48,0x30},//J
{0x0,0x24,0x28,0x30,0x20,0x30,0x28,0x24},//K
{0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7C},//L
{0x81,0xC3,0xA5,0x99,0x81,0x81,0x81,0x81},//M
{0x0,0x42,0x62,0x52,0x4A,0x46,0x42,0x0},//N
{0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C},//O
{0x3C,0x22,0x22,0x22,0x3C,0x20,0x20,0x20},//P
{0x1C,0x22,0x22,0x22,0x22,0x26,0x22,0x1D},//Q
{0x3C,0x22,0x22,0x22,0x3C,0x24,0x22,0x21},//R
{0x0,0x1E,0x20,0x20,0x3E,0x2,0x2,0x3C},//S
{0x0,0x3E,0x8,0x8,0x8,0x8,0x8,0x8},//T
{0x42,0x42,0x42,0x42,0x42,0x42,0x22,0x1C},//U
{0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18},//V
{0x0,0x49,0x49,0x49,0x49,0x2A,0x1C,0x0},//W
{0x0,0x41,0x22,0x14,0x8,0x14,0x22,0x41},//X
{0x41,0x22,0x14,0x8,0x8,0x8,0x8,0x8},//Y
{0x0,0x7F,0x2,0x4,0x8,0x10,0x20,0x7F},//Z
{0x8,0x7F,0x49,0x49,0x7F,0x8,0x8,0x8},//中
{0xFE,0xBA,0x92,0xBA,0x92,0x9A,0xBA,0xFE},//国
};
参考文章:
1. 《一文教你全面透彻使用MAX7219驱动8位LED数码管》
https://baijiahao.baidu.com/s?id=1743172249286220791&wfr=spider&for=pc
2. 《MAX7219(模拟SPI)驱动灯环的简单应用》
https://blog.csdn.net/qq_44836335/article/details/139430345

浙公网安备 33010602011771号