duocool 发表于 2018-5-18 16:26:58

Arduino-ESP8266之MAX7219 8位数码管级联的实现

    先上最终效果,感觉还是可以的,不过要是想完美,得像卖得挺火的那种木壳钟一样,平常像块木头,显示的时候才透出来,不过没找到合适的外壳。
    最近想用arduino-esp8266网上抓点东西下来玩,先试了试OLED模块,网上0.9寸的多,怕小买了1.3寸的,倒是搞定了显示,不过感觉还是小,不够用。

   还有种办法是用电子纸模块,淘宝上也有现成的,不过2,3百的价钱感觉性价比不高。后来决定用下面这种Max7219 8段数码管模块


这种模块从5块多到10多块,样子都差不多,都宣称三线驱动,支持级联,有例程。有焊的也有没焊接口的,我省事买了7块多的焊了的,后的发觉要级联还是得焊,还不如买没焊接口的,自己接线还能紧凑点。

   然后就是填级联这个坑了。最省力的应该是用LedControl这个库了,论坛里也有用这个库max7219 级联LED点阵的例子。不过不管怎么试,都是报错,好象这个库是不支持esp8266的。问卖家要到例程,arduino的例程只有单个模块的,这个样子,没用什么库,感觉就是别的单片机的c代码直接移值过来的。
/*******************************************************************************       
* Software Author:        HQ       
* Creation Date:      2015-2-10
* Software History:        2015-3-10
* Version:            2.0
* Sales address:       http://qifeidz.taobao.com/
********************************************************************************/
//模块引脚定义
int CLK = 2;
int CS = 1;
int DIN = 0; //这里定义了那三个脚

void setup() {
// put your setup code here, to run once:
pinMode(CLK,OUTPUT);
pinMode(CS,OUTPUT);
pinMode(DIN,OUTPUT); //让三个脚都是输出状态
}

void loop() {
// put your main code here, to run repeatedly:
   Delay_xms(50);
   Init_MAX7219();
   Delay_xms(2000);
   Write_Max7219(0x0f, 0x00);       //显示测试:1;测试结束,正常显示:0
   Write_Max7219(1,8);
   Write_Max7219(2,7);
   Write_Max7219(3,6);
   Write_Max7219(4,5);
   Write_Max7219(5,4);
   Write_Max7219(6,3);
   Write_Max7219(7,2);
   Write_Max7219(8,1);
   while(1);
}
void Delay_xms(unsigned int x)
{
unsigned int i,j;
for(i=0;i<x;i++)
for(j=0;j<112;j++);
}
//--------------------------------------------
//功能:向MAX7219(U3)写入字节
//入口参数:DATA
//出口参数:无
//说明:
void Write_Max7219_byte(unsigned char DATA)         
{
    unsigned char i;   
    digitalWrite(CS,LOW);               
    for(i=8;i>=1;i--)
    {                  
      digitalWrite(CLK,LOW);   
      if(DATA&0X80)
         digitalWrite(DIN,HIGH);
      else
         digitalWrite(DIN,LOW);
      DATA<<=1;
      digitalWrite(CLK,HIGH);
   }                                 
}
//-------------------------------------------
//功能:向MAX7219写入数据
//入口参数:address、dat
//出口参数:无
//说明:
void Write_Max7219(unsigned char address,unsigned char dat)
{
   digitalWrite(CS,LOW);
   Write_Max7219_byte(address);         //写入地址,即数码管编号
   Write_Max7219_byte(dat);               //写入数据,即数码管显示数字
   digitalWrite(CS,HIGH);                        
}

void Init_MAX7219(void)
{
   Write_Max7219(0x09, 0xff);       //译码方式:BCD码
   Write_Max7219(0x0a, 0x03);       //亮度
   Write_Max7219(0x0b, 0x07);       //扫描界限;4个数码管显示
   Write_Max7219(0x0c, 0x01);       //掉电模式:0,普通模式:1
   Write_Max7219(0x0f, 0x01);       //显示测试:1;测试结束,正常显示:0
}

试了下,可以用。级联怎么解决呢,网上反复找,本坛里有篇写的http://www.geek-workshop.com/forum.php?mod=viewthread&tid=7951&highlight=max7219控制led点阵的,试着小改用了用,显示还是乱的,不行。又搜到这个贴http://lib.csdn.net/article/embeddeddevelopment/63594 MAX7219多级联串行控制多个点阵/数码管的详解用的是c语言,都不是写给arduino用的,不过我一看注释那么熟,有些部分简直和卖家给的例程一模一样,可以肯定他们都有一个共同的祖先。仔细研究后,发现级联的关键是写后面的模块就得把它前面的模块写空。像这样/*第二片MAX7219的写入数据*/
void Write_Max7219_2(uchar add2,uchar dat2)
{
        Max7219_pinCS=0;
        Write_Max7219_byte(add2);
        Write_Max7219_byte(dat2);
        Max7219_pinCLK=1;
        Write_Max7219_byte(0x00);//片1写入空
        Write_Max7219_byte(0x00);
        Max7219_pinCS=1;
}
/*第三片MAX7219的写入数据*/
void Write_Max7219_3(uchar add3,uchar dat3)
{
        Max7219_pinCS=0;
        Write_Max7219_byte(add3);
        Write_Max7219_byte(dat3);
        Max7219_pinCLK=1;
        Write_Max7219_byte(0x00); //片1写入空
        Write_Max7219_byte(0x00);
        Write_Max7219_byte(0x00); //片2写入空
        Write_Max7219_byte(0x00);
        Max7219_pinCS=1;
}



我的代码如下: 定义了一个总的片数,然后用循环把初始化数码管模块和写每片的数据都统一起来了,这样不管是写一片,还是8片,代码都是一样的长度(好象max7219最多就支持8片),还自定义了一个DP参数,解决了卖家例程没写的小数点有无的问题。卖家例程是在loop中初始化模块的,这样显示感觉有闪烁,我移到setup中初始化,闪烁就没了
//模块引脚定义
int CLK = D6;
int CS = D7;
int DIN = D8; //这里定义了那三个脚
int PIECENUM = 4;//数码管片数

void setup() {
// put your setup code here, to run once:
pinMode(CLK, OUTPUT);
pinMode(CS, OUTPUT);
pinMode(DIN, OUTPUT); //让三个脚都是输出状态
Delay_xms(50);
Init_MAX7219(PIECENUM);
Delay_xms(2000);
}

void loop() {
// put your main code here, to run repeatedly:

Write_Max7219(1, 0x0f, 0x00, 0);   //显示测试:1;测试结束,正常显示:0

for (int i = 1; i <= 5; i++) {
    Write_Mynum(1, i, i + 1, 1);
}
//Write_Mynum(1, 7, '_', 0);
// Write_Mynum(1, 8, '_', 0);
for (int i = 1; i <= 8; i++) {
    Write_Mynum(2, i, 2, 0);
}

for (int i = 1; i <= 8; i++) {
    Write_Mynum(3, i, 3, 0);
}

for (int i = 1; i <= 8; i++) {
    Write_Mynum(4, i, 8 - i, 1);
}

while (1);
}


void Delay_xms(unsigned int x)
{
unsigned int i, j;
for (i = 0; i < x; i++)
    for (j = 0; j < 112; j++);
}

//切换地址,方便写
void Write_Mynum(int pnum,unsigned char address, unsigned char dat , int dp) {
Write_Max7219(pnum, 9 - address, dat, dp);
}

//--------------------------------------------
//功能:向MAX7219写入字节
//入口参数:DATA,dp显示小数点与否
void Write_Max7219_byte(unsigned char DATA, int dp)
{
unsigned char i;
digitalWrite(CS, LOW);
for (i = 8; i >= 1; i--)
{
    digitalWrite(CLK, LOW);
    if (i == 8 && dp == 1)
      digitalWrite(DIN, HIGH);
    else {
      if (DATA & 0X80)
      digitalWrite(DIN, HIGH);
      else
      digitalWrite(DIN, LOW);
    }
    DATA <<= 1;
    digitalWrite(CLK, HIGH);
}
}

//-------------------------------------------
//功能:向MAX7219写入数据
//入口参数:pnum数码管片序号,address,dat,dp显示小数点与否
void Write_Max7219(int pnum, unsigned char address, unsigned char dat, int dp)
{
digitalWrite(CS, LOW);
Write_Max7219_byte(address, 0);          //写入地址,即数码管编号
Write_Max7219_byte(dat, dp);            //写入数据,即数码管显示数字
if (pnum > 1) {
    digitalWrite(CLK, HIGH);
    for (int i = 1; i < pnum; i++) {
      Write_Max7219_byte(0X00, 0);
      Write_Max7219_byte(0X00, 0);
    }
}
digitalWrite(CS, HIGH);
}


//Max7219初始化
void Init_MAX7219(int pienum)
{
for (int i = 1 ; i <= pienum ; i++) {
    Write_Max7219(i, 0x09, 0xff, 0);   //译码方式:BCD码
    Write_Max7219(i, 0x0a, 0x03, 0);   //参数3:亮度
    Write_Max7219(i, 0x0b, 0x07, 0);   //扫描界限;参数3:8个数码管显示
    Write_Max7219(i, 0x0c, 0x01, 0);   //掉电模式:参数3:0,普通模式:1
    Write_Max7219(i, 0x0f, 0x01, 0);   //显示测试:参数3:1;测试结束,正常显示:0
}
}


anqiw 发表于 2018-5-27 22:49:35

很好,每一怕贴代码的帖子都是好帖子。谢谢,大神,受用。:loveliness:

off-ice 发表于 2018-5-28 20:46:03

不错。
支持楼主。
学习一下。:)

anqiw 发表于 2018-6-3 09:58:28

大神,小白问下,这个代码,可以写中横线吗?我想写温度,需要写负号,提示零下,怎么写,多谢了

duocool 发表于 2018-6-4 08:21:40

anqiw 发表于 2018-6-3 09:58
大神,小白问下,这个代码,可以写中横线吗?我想写温度,需要写负号,提示零下,怎么写,多谢了

中横就用":" 英文的冒号,

anqiw 发表于 2018-6-4 10:39:28

多谢了,我试了下,10也可以输出中横。11-15 还可以输出 E L H P 空白,请问还有更多的输出吗,比如F怎么弄。总共能输出多少种,怎么对应的,谢谢了。

duocool 发表于 2018-6-4 11:17:13

anqiw 发表于 2018-6-4 10:39
多谢了,我试了下,10也可以输出中横。11-15 还可以输出 E L H P 空白,请问还有更多的输出吗,比如F怎么弄 ...

空白我用的是"_",数字,小数点,还有空白,中横一般也就用这么多了,

发烧的小学生 发表于 2018-7-12 14:50:39

写得很好,但有点疑问楼主有空解答一下吗?
我也在调595数码管,不知道小数点怎么点亮,请楼主指点一下、
具体在哪段代码呢,小数点的地址是什么呢

duocool 发表于 2018-7-13 10:05:30

发烧的小学生 发表于 2018-7-12 14:50
写得很好,但有点疑问楼主有空解答一下吗?
我也在调595数码管,不知道小数点怎么点亮,请楼主指点一下、
...

void Write_Max7219_byte(unsigned char DATA, int dp)最后一个dp参数就是显示小数点的开关,程序注释里已经说清楚了的

发烧的小学生 发表于 2018-7-13 15:18:21

duocool 发表于 2018-7-13 10:05
void Write_Max7219_byte(unsigned char DATA, int dp)最后一个dp参数就是显示小数点的开关,程序注释 ...

可以详细说一下点亮小数点的思路吗,代码看得很吃力,万分感谢

duocool 发表于 2018-7-16 15:28:02

发烧的小学生 发表于 2018-7-13 15:18
可以详细说一下点亮小数点的思路吗,代码看得很吃力,万分感谢

其实就这句 if (i == 8 && dp == 1)
      digitalWrite(DIN, HIGH);   第8位且带小数点,就写高电平,第8位就是小数点
页: [1]
查看完整版本: Arduino-ESP8266之MAX7219 8位数码管级联的实现