栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

2.树莓派与Java驱动多个Max7219的LED矩阵

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

2.树莓派与Java驱动多个Max7219的LED矩阵

很久之前写了一篇树莓派用Java驱动一个8x8 LED矩阵,传送门: Java控制树莓派8x8矩阵LED_xss13的博客-CSDN博客

今天我要吐槽一下,CSDN各种低质量的文章,没有任何用处而且还帮倒忙,驱动多个LED矩阵这个问题在开始的时候卡了我好几天,后来被迫无奈放弃了,好在今天想起来了,又拾起来再研究了一次,终于搞清楚了。

首先感谢这篇文章对我的帮助,不胜感激:
怎样将MAX7219驱动的LED矩阵8x8与ATtiny85微控制器连接-电子发烧友网 ,让我明白了一些API具体的意义,接下来再进行操作,即便不清楚,也可以慢慢的猜,慢慢的试验出来。

步入正题,首先如何接线就不多说了,之前的文章都有,上代码:

//len是数据长度,一个8x8矩阵可以用一个long表示,一个long有8个字节。
//比如len = 16,表示驱动两个led矩阵。
//推荐改 (len & 7) != 0 效率更高
if (len % 8 != 0) {                     
    return;                             
}                                       
int size = len/8;                       
if (!isInit) {
    isInit = true;                          
    wiringPiSetup();                    
    pinMode(DIN,OUTPUT);                
    pinMode(CS,OUTPUT);                 
    pinMode(CLK,OUTPUT);                
                           
    //首先要明确,CS LOW表示解锁max7219内存,此时可以将数据送入到寄存器,所以将每个led矩阵的数据全部都送入后再将CS HIGH,表示锁住内存,即完成一次数据写入。             
    //再者,只要addr相同,重复往寄存器写数据,就是从第一个LED开始一个一个的有顺序的写入(同一个addr写完后一定要锁定内存来通知本次数据写完,可以写下一个addr的数据)。
    digitalWrite(CS, LOW);              
    for (int i = 0; i < size; i++) {    
        writeData(0x09,0x00);           
    }                                   
    digitalWrite(CS, HIGH);             
    digitalWrite(CS, LOW);              
    for (int i = 0; i < size; i++) {    
        writeData(0x0a,0x03);           
    }                                   
    digitalWrite(CS, HIGH);             
    digitalWrite(CS, LOW);              
    for (int i = 0; i < size; i++) {    
        writeData(0x0b,0x07);           
    }                                   
    digitalWrite(CS, HIGH);             
    digitalWrite(CS, LOW);              
    for (int i = 0; i < size; i++) {    
        writeData(0x0c,0x01);           
    }                                   
    digitalWrite(CS, HIGH);             
    digitalWrite(CS, LOW);              
    for (int i = 0; i < size; i++) {    
        writeData(0xff,0x00);           
    }                                   
    digitalWrite(CS, HIGH);    
}

long []all = new long[size];                         
for (int i = 0; i < all.length; i++) {   
    //此处我用的netty的buf,通过socket将数据输送过来(len就是从buf里读出来的数据长度),这里可以替换成自己的数据,可以参见 DefaultFont8x8.getPoints()方法将数据从long转为byte或从byte转为long,本质上就是用8x8的LED矩阵拼图拼成一个大的LED屏幕           
    all[i]=in.readLong();                            
}                                                    
int index = 0;                                       
byte[][] data = new byte[size][8];                   
for (int i = 0; i < size; i++) {       
    //该类在我的单个8x8矩阵的文章里有,可以从那里copy出来。              
    data[i] = DefaultFont8x8.getPoints(all[index]);  
    index ++;                                        
} 
//注意这里,j = 1表示写入每个8x8矩阵的第一行,2表示第二行,以此类推;
//即把所有的LED矩阵的第一行都写完了再封锁内存,然后再写第二行,直到把8行数据都写完为止。
//这样写入的数据不会存在CSDN另一篇播客用户区评论的有剪影的问题。                                                   
for (int j = 1; j <= 8; j++) {                       
    digitalWrite(CS, LOW);                           
    for (int i = 0; i < size; i++) {                 
        writeData(j, data[i][j-1]);                  
    }                                                
    digitalWrite(CS, HIGH);                          
}                                                             

调用到的方法:

private void writeData(int addr, int data) {  
    //通知要往那个地址上写             
    writeByte(addr);     
    //往这个地址上写什么样的数据,连续写两次表示写完一次数据                                  
    writeByte(data);    
    //表示将数据flush出去                                   
    digitalWrite(CLK,HIGH);                                
}                                                          
                                                           
private void writeByte(int data) {                         
    for (int i = 0; i < 8; i++) {                          
        digitalWrite(CLK, LOW);                            
        digitalWrite(DIN, (data & 0x80) == 0 ? LOW : HIGH);
        digitalWrite(CLK, HIGH);                           
        data <<= 1;                                        
    }                                                      
}                                                          

需要导入的包:

import static com.pi4j.wiringpi.Gpio.HIGH;              
import static com.pi4j.wiringpi.Gpio.LOW;               
import static com.pi4j.wiringpi.Gpio.OUTPUT;            
import static com.pi4j.wiringpi.Gpio.digitalWrite;      
import static com.pi4j.wiringpi.Gpio.pinMode;           
import static com.pi4j.wiringpi.Gpio.wiringPiSetup;     

内容补充:

如果是为了节约布线,从如下的布线方式改为省线方式则需要旋转:

原始

第一个灯条: OUT<--8x8矩阵<--8x8矩阵<--8x8矩阵<--8x8矩阵<--第二个灯条结束

第二个灯条: 第一个灯条开始<--8x8矩阵<--8x8矩阵<--8x8矩阵<--8x8矩阵<--第三个灯条结束

第三个灯条: 第二个灯条开始<--8x8矩阵<--8x8矩阵<--8x8矩阵<--8x8矩阵<--IN

(上述是一个4x3即32x24像素的矩阵)

改为:

第一个灯条: OUT<--8x8矩阵<--8x8矩阵<--8x8矩阵<--8x8矩阵<--第二个灯条结束

第二个灯条: 第三个灯条结束-->8x8矩阵-->8x8矩阵-->8x8矩阵-->8x8矩阵-->第一个灯条开始

第三个灯条: 第二个灯条开始<--8x8矩阵<--8x8矩阵<--8x8矩阵<--8x8矩阵<--IN

则需要对第二个灯条的每一个8x8矩阵自身的每个点做180度旋转,同时矩阵之间要做左右互换。

以下代码是对矩阵自身的每个点做i180度的旋转操作:

                                                                                                     
public static long rotate180(long points) {                                                             
    long newPoints = 0, tmp, low, high, pl, ph;                                                         
    for (int i = 0; i < 8; i++) {                                                                       
        if (i < 4) {                                                                                    
            newPoints = newPoints | (tmp = (points >> ((8 - i * 2 - 1) << 3) & (0xFFL << (i << 3))));   
        } else {                                                                                        
            newPoints = newPoints | (tmp = (points << ((i - 1 - 3) * 2 + 1 << 3) & (0xFFL << (i << 3))))
        }                                                                                               
        if ((tmp = (tmp >> (i << 3) & 0xFF)) == 0L || tmp == 0xFFL) {                                   
            continue;                                                                                   
        }                                                                                               
        for (int j = 0; j < 4; j++) {                                                                   
            //低位                                                                                        
            low = newPoints & (pl = 1L << j + (i << 3));                                                
            //高位                                                                                        
            high = newPoints & (ph = (1L << (7 - j + (i << 3))));                                       
            newPoints = low == 0L ? (newPoints & ~ph) : (newPoints | ph);                               
            newPoints = high == 0L ? (newPoints & ~pl) : (newPoints | pl);                              
        }                                                                                               
    }                                                                                                   
    return newPoints;                                                                                   
}                                                                                                       

好了,到此为止,一个多段LED驱动就告一段落了,接下来就可以尽情的玩耍了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/781326.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号