简介
MAX7219是微处理器和共阴极七段八位LED显示、图条/柱图显示或64点阵显示接口的小型串行输入/输出芯片。片内包括BCD译码器、多路扫描控制器、字和位驱动器和8X8静态RAM。外部只需要一个电阻设置所有LED显示器字段电流。MAX7219和微处理器只需三根导线连接,每位显示数字有一个地址由微处理器写入。允许使用者选择每位是BCD译码或不译码。使用者还可选择停机模式、数字亮度控制、从1~8选择扫描位数和对所有LED显示器的测试模式。
工作原理
接口方式
MAX7219和STM32单片机连接有三条引线(DIN、CLK、LOAD),采用16 位数据串行移位接收方式。即单片机将16位二进制数逐位发送到DIN端,在CLK上升沿到来前准备就绪,CLK的每个上升沿将一位数据移入MAX7219 内移位寄存器,当16位数据移入完,在LOAD引脚信号上升沿将16 位数据装入MAX7219内的相应位置,在MAX7219内部硬件动态扫描显示控制电路作用下实现动态显示。
组成结构
上图中各部分作用是:
16位地址/数据移位寄存器接收串行数据,实现串/并变换。
16位数据含义如下:
D7~D0:写入内部RAM和功能寄存器的数据;
D8~D11:内部RAM和功能寄存器地址;
D12~D15:无定义。
地址译码器是一个4~16线译码器,用于选择数据存放单元,在LOAD信号作用下将接收数据送入指定单元:八字节双端口静态存储器存放接收数据和提供动态显示数据;B译码和不译码电路对RAM数据进行BCD译码或直接送显示;段码电流参考电路、亮度脉冲产生调制器实现对显示器的亮度控制,段码电流参考电路由硬件调节显示器亮度;动态扫描控制器实现由硬件控制动态扫描显示。LED段/位驱动器提供显示器的一段和一位点亮的电流。
各内部功能寄存器含义如下:
(1)停机寄存器(地址0CH): 当D0=0时,MAX721处于停机状态;当D0=1时,处于正常工作状态。
(2)显示测试寄存器(地址0FH): 当D0=0时,MAX7219 按设定模式正常工作;当D0=1 时,处于测试状态。在该状态下,不管MAX7219处于什么模式,全部LED将按最大亮度显示。
(3)亮度寄存器(地址0AH):亮度可以用硬件和软件两种方法调节。亮度寄存器中的D0~D3 位可以控制LED显示器的亮度。
(4)扫描界限寄存器(地址0BH):该寄存器中D0-D3位数据设定值为0-7H,设定值表示显示器动态扫描个数位1~8。
(5)译码方式寄存器(地址09H): 该寄存器的8位二进制数的各位分别控制8个LED显示器的译码方式。当高电平时,选择BCD-B译码模式,当低电平时选择不译码模式(即送来数据为字型码)。
(6)内部RAM地址01-08H分别对应于DIG0~ DIG7。
时序图
寄存器
数据寄存器和控制寄存器
14 个可寻址的数据寄存器和控制寄存器。数据寄存器由一个在片上的8×8 的双向 SRAM 来实现。它们可以直接寻址所以只要在 V+大于 2V 的情况下每个数据都可以独立的修改或保存。控制寄存器包括编码模式、显示亮度、扫描限制、关闭模式以及显示检测五个寄存器,如下图所示:
译码模式寄存器
用来设置对每个数据进行 B 型 BCD 译码或者不译码。寄存器中的每一位对应一个数据。逻辑高电平用来选择译码低电平取消译码。下面举例说明了译码控制寄存器的格式:
当选择译码模式时,译码器只对数据的低四位进行译码(D3-D0),D4-D6 为无效位。D7 位用来设置小数点,不受译码器的控制且为高电平。
下面为B 型译码的格式:
当选择不译码时,数据的八位与MAX7219的各段线上的信号一致。下表列出了每个数字对应的段位码。
强度(亮度)控制
MAX7219 通过加在 V+和 ISET 之间的一个外部电阻来控制显示亮度。段驱动电流一般是流入 ISET 端电流的 100 倍。这个电阻可以是固定的,也可以是可变电阻,通过前面板来控制以选择合适的亮度。其最小值为 9.53KΩ,它对应设定段电流的40mA。显示亮度也可以通过亮度寄存器来控制。数字控制显示亮度是通过亮度寄存器的低四位来控制的脉宽调制器来控制。调制器将段电流平均分为 16 个阶次,最大值为由 RSET 设置的最大电流的31/32,最小值为电流峰值的 1/32。下表列出了亮度寄存器的格式。最小数据熄灭时间设置为时钟周期的 1/32。
扫描控制寄存器
扫描控制寄存器用来设定扫描显示器的个数,从 1 个到 8 个,它们将以 800Hz 的扫描速率进行多路扫描显示。如果数据少的话,扫描速率为 8*fosc/N,N 是指需要扫描数字的个数。扫描数据的个数影响显示亮度,所以不能将扫描寄存器设置为空扫描。下表列出了扫描寄存器的格式:
如果扫描寄存器被设置扫描 3 个数据或者更少,个别的数据驱动将损耗过多的能量。所以,RSET 必须根据显示数据的个数来确定,从而限制个别数据驱动对能源的浪费。下表列出了不同个数字被扫描时所对应的最大需求段电流:
显示检测寄存器
显示检测寄存器有正常和显示检测两种工作状态。显示检测状态在不改变所有其他控制和数据寄存器(包括关闭寄存器)的情况下将所有 LED 都点亮。在此状态下,8 个数据都会被扫描,工作周期为 31/32。下表列出了显示检测寄存器的格式:
取模
打开取模软件,选择选项→点阵格式-阴码→格式-C51→取模方式-逐行式→取模走向-顺向→输出数制-十六进制,行前、后缀的“{“、”}“要删掉,配置好后点确定即可,配置如下图:
接着点击模式,选择字符模式,选好后就可以进行编辑需要显示的文字,随后点击生成字模即可完成中文取模,如下图:
数字和图片取模跟中文取模有点区别,选项配置如下:
模式选择图片模式,接着选择新建图像,尺寸8X8:
左键点击矩阵图中点画出需要显示的数字和图形,点击生成字模既可生成数字和图片的十六进制形式:
接线
STM32 | MAX7219 |
---|---|
5V | VCC |
GND | GND |
PB9 | CLK |
PB10 | CS |
PB11 | DIN |
代码
Dot_Matrix.c
#include "Dot_Matrix.h"
#include "bsp_SysTick.h"
#include "Typehead.h"
uint8_t Number=4;
void MAX7219_GPIO_Config(void)
{
/*定义一个MAX7219_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/*开启LED相关的GPIO外设时钟*/
RCC_APB2PeriphClockCmd(DIN_GPIO_CLK|CS_GPIO_CLK|CLK_GPIO_CLK , ENABLE);
/*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Pin = DIN_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DIN_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = CS_GPIO_PIN;
GPIO_Init(CS_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = CLK_GPIO_PIN;
GPIO_Init(CLK_GPIO_PORT, &GPIO_InitStructure);
}
//--------------------------------------------
//功能:向MAX7219(U3)写入字节
//DATA :写入的8位数据
//出口参数:无
//说明:
/*-------------------------------------------
//功能:向MAX7219写入字节
//dat:写入数据
//出口参数:无
-------------------------------------------*/
void Write_Max7219_byte(uint8_t DATA)
{
uint8_t i;
for(i=8;i>=1;i--)
{
CLK_0;
if(DATA&0x80)
{
DIN_1;
}
else
{
DIN_0;
}
DATA=DATA<<1;
CLK_1;
}
}
/*-------------------------------------------
//功能:向MAX7219写入数据
//address1:显示地址
//dat:显示数据
//出口参数:无
-------------------------------------------*/
/*-------------------------------------------
//功能:MAX7219初始化写入函数
//address1:第一个地址 其他以此类推
//dat1:对应写第一个数据 其他以此类推
//出口参数:无
-------------------------------------------*/
void Write_Max7219_Init(uint8_t address1,uint8_t dat1)
{
uint8_t i;
CS_0;
for(i=0;i<Number;i++)
{
Write_Max7219_byte(address1); //写入地址,即数码管编号
Write_Max7219_byte(dat1); //写入数据,即数码管显示数字
}
CS_1;
}
/*-------------------------------------------
//功能:向MAX7219写入数据
//address1:第一个地址 其他以此类推
//dat1:对应写第一个数据 其他以此类推
//出口参数:无
-------------------------------------------*/
void Write_Max7219_Dat(uint8_t address1,uint8_t dat1)
{
Write_Max7219_byte(address1); //写入地址,即数码管编号
Write_Max7219_byte(dat1); //写入数据,即数码管显示数字
}
void Init_MAX7219(void)
{
// uint8_t k;
Write_Max7219_Init(0x09,0x00 ); //译码方式:BCD码
Write_Max7219_Init(0x0a,0x01 ); //亮度
Write_Max7219_Init(0x0b,0x07 ); //扫描界限;8个数码管显示
Write_Max7219_Init(0x0c,0x01 ); //掉电模式:0,普通模式:1
Write_Max7219_Init(0x0f,0x00 ); //显示测试:1;测试结束,正常显示:0
}
/*-------------------------------------------
//功能:一定延时切换显示数字
//Num:数字首地址
//Long:需要切换显示数字个数
//Time:切换显示数字时间间隔 单位MS
//出口参数:无
-------------------------------------------*/
void Show_Num(uint8_t *Num,uint8_t Long,uint16_t Time)
{
uint8_t i,j,k;
for(j=0;j<Long;j++)
{
for(i=1;i<9;i++)
{
CS_0;
for(k=0;k<Number;k++)
{
Write_Max7219_Dat(i,*(Num+(i-1)+8*j));
}
CS_1;
}
SysTick_Delay_Ms(Time);
}
}
//功能:一定延时切换显示图片
//Num:数字首地址
//Long:需要切换显示图片个数
//Time:切换显示数字时间间隔 单位MS
//出口参数:无
void Show_Pic(uint8_t *Num,uint8_t Long,uint16_t Time)
{
uint8_t i,j,k;
for(j=0;j<Long;j++)
{
for(i=1;i<9;i++)
{
CS_0;
for(k=0;k<Number;k++)
{
Write_Max7219_Dat(i,*(Num+(i-1)+8*j));
}
CS_1;
}
SysTick_Delay_Ms(Time);
}
}
/*-------------------------------------------
//功能:一定延时切换显示中文
//Num:中文数组首地址
//Long:需要切换显示中文个数
//Time:切换显示中文时间间隔 单位MS
//出口参数:无
-------------------------------------------*/
void Show_CH(uint8_t *Num,uint8_t Long,uint16_t Time)
{
uint8_t i,j,k;
if(!(Number%2))
{
for(j=0;j<Long;j++)
{
for(i=0;i<8;i++)
{
CS_0;
for(k=0;k<Number;k++)
{
if(k<(Number/2))
{
Write_Max7219_Dat(i+1,*(Num+2*i+k%2+k/2*32+j*32));
}
else
{
Write_Max7219_Dat(i+1,*(Num+16+2*i+k%2+(k-(Number/2))/2*32+j*32));
}
}
CS_1;
}
SysTick_Delay_Ms(Time);
}
}
else
{
return;
}
}
Main.c
#include "Dot_Matrix.h"
#include "bsp_SysTick.h"
#include "Typehead.h"
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
SysTick_Init();
MAX7219_GPIO_Config();
Init_MAX7219();
while (1)
{
Show_CH(disp1,10,1000);
Show_Num(disp2,10,1000);
Show_Pic(disp3,2,1000);
}
}
Typehead.c
中文取模:
uint8_t disp1[]=
{
0x08,0x90,0x08,0x88,0x08,0x88,0x10,0x80,
0x17,0xFE,0x30,0xA0,0x30,0xA0,0x50,0xA0,
0x90,0xA0,0x10,0xA0,0x11,0x20,0x11,0x22,
0x11,0x22,0x12,0x22,0x12,0x1E,0x14,0x00,/*"优",0*/
0x08,0x40,0x08,0x20,0x0B,0xFE,0x10,0x00,
0x10,0x00,0x31,0xFC,0x30,0x00,0x50,0x00,
0x91,0xFC,0x10,0x00,0x10,0x00,0x11,0xFC,
0x11,0x04,0x11,0x04,0x11,0xFC,0x11,0x04,/*"信",1*/
0x01,0x00,0x01,0x00,0x01,0x00,0x3F,0xF8,
0x21,0x08,0x21,0x08,0x21,0x08,0x3F,0xF8,
0x21,0x08,0x21,0x08,0x21,0x08,0x3F,0xF8,
0x21,0x0A,0x01,0x02,0x01,0x02,0x00,0xFE,/*"电",2*/
0x00,0x00,0x7F,0xF8,0x00,0x10,0x00,0x20,
0x00,0x40,0x01,0x80,0x01,0x00,0xFF,0xFE,
0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,
0x01,0x00,0x01,0x00,0x05,0x00,0x02,0x00,/*"子",3*/
0x08,0x10,0x1D,0x10,0xF0,0x90,0x10,0x90,
0x10,0x10,0xFD,0x10,0x10,0x90,0x38,0x90,
0x34,0x10,0x50,0x1E,0x53,0xF0,0x90,0x10,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,/*"科",4*/
0x10,0x20,0x10,0x20,0x10,0x20,0x13,0xFE,
0xFC,0x20,0x10,0x20,0x10,0x20,0x15,0xFC,
0x18,0x84,0x30,0x88,0xD0,0x48,0x10,0x50,
0x10,0x20,0x10,0x50,0x51,0x88,0x26,0x06,/*"技",5*/
0x02,0x00,0x02,0x00,0xFF,0xFE,0x04,0x00,
0x04,0x00,0x0F,0xF0,0x08,0x10,0x18,0x10,
0x2F,0xF0,0x48,0x10,0x88,0x10,0x0F,0xF0,
0x08,0x10,0x08,0x10,0x08,0x50,0x08,0x20,/*"有",6*/
0x00,0x00,0x7B,0xF8,0x4A,0x08,0x52,0x08,
0x53,0xF8,0x62,0x08,0x52,0x08,0x4B,0xF8,
0x4A,0x44,0x4A,0x48,0x6A,0x30,0x52,0x20,
0x42,0x10,0x42,0x88,0x43,0x06,0x42,0x00,/*"限",7*/
0x00,0x80,0x04,0x80,0x04,0x80,0x08,0x40,
0x08,0x40,0x10,0x20,0x20,0x10,0x42,0x08,
0x82,0x06,0x04,0x00,0x04,0x40,0x08,0x20,
0x10,0x20,0x3F,0xF0,0x10,0x10,0x00,0x00,/*"公",8*/
0x00,0x00,0x3F,0xF8,0x00,0x08,0x00,0x08,
0x7F,0xE8,0x00,0x08,0x00,0x08,0x1F,0x88,
0x10,0x88,0x10,0x88,0x10,0x88,0x10,0x88,
0x1F,0x88,0x10,0x88,0x00,0x28,0x00,0x10,/*"司",9*/
};
数字取模:
uint8_t disp2[]=
{
0x00,0x7E,0x42,0x42,0x42,0x42,0x42,0x7E,/*"0",0*/
0x00,0x02,0x02,0x02,0x02,0x02,0x02,0x02,/*"1",1*/
0x00,0x7E,0x02,0x02,0x7E,0x40,0x40,0x7E,/*"2",2*/
0x00,0x7E,0x02,0x02,0x7E,0x02,0x02,0x7E,/*"3",3*/
0x00,0x42,0x42,0x42,0x7E,0x02,0x02,0x02,/*"4",4*/
0x00,0x7E,0x40,0x40,0x7E,0x02,0x02,0x7E,/*"5",5*/
0x00,0x7E,0x40,0x40,0x7E,0x42,0x42,0x7E,/*"6",6*/
0x00,0x7E,0x02,0x02,0x02,0x02,0x02,0x02,/*"7",7*/
0x00,0x7E,0x42,0x42,0x7E,0x42,0x42,0x7E,/*"8",8*/
0x00,0x7E,0x42,0x42,0x7E,0x02,0x02,0x7E,/*"9",0*/
};
图像取模:
uint8_t disp3[]=
{
0x00,0x00,0x6C,0xFE,0xFE,0x7C,0x38,0x10,/*"爱心",0*/
0x3C,0x42,0xA5,0x81,0xA5,0x99,0x42,0x3C,/*"笑脸",1*/
};
现象
文字
数字和图形
总结
以上是关于MAX7219点阵模块原理解析和取模的操作步骤以及程序展示,在使用过程中如果出现显示不全或者显示分上下两截显示的,那很大可能是因为取模出了问题,有可能是选项里的取模方式有问题,或者是取模模式的问题,等等,需要根据情况检查下并进行修正。
感兴趣的可以关注收藏一下。需要资料代码的可以评论留言。