zzz 发表于 2013-6-29 16:59:53

【Z】Arduino也能驱动LED显示屏,LED业界标准Arduino驱动方案解析

本帖最后由 zzz 于 2013-6-29 17:08 编辑

现在市面上有很多很多的LED显示屏,但大多都基于同一种,或者同一类型的驱动方式,简称08驱动方式,它内部有LED点阵,74HC595,以及138行扫芯片组成,但毫无例外的,是主控板都采用了STC方案,或者串口方案,而Arduino驱动却鲜有人用,今天,小Z就带了LED业界标准Arduino驱动方案的介绍与解析

市场上主流的显示屏有F3.75和F3.0两种,F后面代表的点阵屏单体LED的直径,而今天,小Z用的是F2.0的超密集进口点阵,显示效果个人很喜欢,下面是市场上常见的2种屏幕(F3.75 F3.0)和今天所使用的F2.0屏幕(分辨率均为16*64)的对比图,可以很轻松的看出大小的差别。


随后的重点便是行驱的模式,今天我推荐两种驱动模式,分别是16*16驱动模式,和16*64直接驱动模式,这两种模式各有特点,16*16即是汉字是一个一个取模,一个一个显示,而16*64是取模软件直接取出一幅完整的图像。如果是显示汉字的同学,推荐采用第一种,而显示图形的同学,推荐采用第二种。

下面,先把主体的演示代码发一下。
#define RowA 2   
#define RowB 3
#define RowC 4
#define RowD 5
//业界所采用的ABCD 08驱动模式
int hc138en=6; //EN口

//使用了硬件SPI,以下脚不能更改
#define R1 11          //数据出    MOSI
#define CLK 13         //时钟    SCK
#define STB 10         //595 刷新显示SS
#define DATAIN12   //数据入,读FLASH时有用MISO

byte row=0;
byte zzz[] =

{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF1,0xFF,0xE3,0xFF,0xC0,0x00,0x00,
0xFF,0xF1,0xFF,0xE3,0xFF,0xC0,0x00,0x00,0x00,0x70,0x00,0xE0,0x01,0xC0,0x00,0x00,
0x00,0xE0,0x01,0xC0,0x03,0x80,0x00,0x00,0x01,0xC0,0x03,0x80,0x07,0x00,0x00,0x00,
0x03,0x80,0x07,0x00,0x0E,0x00,0x00,0x00,0x07,0x00,0x0E,0x00,0x1C,0x00,0x00,0x00,
0x0E,0x00,0x1C,0x00,0x38,0x00,0x00,0x00,0x1C,0x00,0x38,0x00,0x70,0x00,0x00,0x00,
0x38,0x00,0x70,0x00,0xE0,0x00,0x00,0x00,0x70,0x00,0xE0,0x01,0xC0,0x00,0x00,0x00,
0xE0,0x01,0xC0,0x03,0x80,0x00,0x00,0x00,0xFF,0xF1,0xFF,0xE3,0xFF,0xC0,0x00,0x00,
0xFF,0xF1,0xFF,0xE3,0xFF,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};



void spi_transfer(volatile char data)
{
SPDR = data;                  // Start the transmission
while (!(SPSR & (1<<SPIF)))   // Wait the end of the transmission
{
};
//return SPDR;                  // return the received byte
}


void hc138sacn(byte r){//输出行线状态ABCD (A低,D高)
    digitalWrite(RowA,(r & 0x01));
    digitalWrite(RowB,(r & 0x02));
    digitalWrite(RowC,(r & 0x04));
    digitalWrite(RowD,(r & 0x08));
}

void hc595senddata(byte data){// 高位在前反相(1亮0灭)
for (byte i=0; i<8;i++) {
   digitalWrite(CLK,0);
   if (data & 0x80) {
         digitalWrite(R1, 0);   
   } else {
         digitalWrite(R1, 1);
   }
   data=data<<1;
   digitalWrite(CLK,1);
}

}


void setup () {

    pinMode(RowA, OUTPUT);
    pinMode(RowB, OUTPUT);
    pinMode(RowC, OUTPUT);
    pinMode(RowD, OUTPUT); //138片选
    pinMode(hc138en, OUTPUT); //138 使能

    pinMode(R1, OUTPUT);//595 数据
    pinMode(CLK, OUTPUT); //595 时钟
    pinMode(STB, OUTPUT); //595 使能
    pinMode(DATAIN, INPUT); //595 使能


   //digitalWrite(hc138d, HIGH);
    Serial.begin(19200);

    //SPI硬件设置
    // SPCR = 01010000
    //interrupt disabled,spi enabled,msb 1st,master,clk low when idle,
    //sample on leading edge of clk,system clock/4 rate (fastest)
    SPCR = (1<<SPE)|(1<<MSTR);
    delay(10);
}

void loop () {
if (Serial.available() > 0) {
// read the incoming byte:
row = Serial.read();

// say what you got:
Serial.print("I received: ");
Serial.println(row, DEC);
}

for(row=0;row<16;row++){

      for (int i=0;i<8;i++){   
         spi_transfer(~(zzz));
      }
         

      digitalWrite(hc138en, 1);//关闭显示
      hc138sacn(row);            //换行
      digitalWrite(STB, 0);      //595刷新      
      digitalWrite(STB, 1);
      delayMicroseconds(500) ;   //节电用,
      digitalWrite(hc138en, 0);//开启显示

      delayMicroseconds(500) ;//刷新频率调,差不多60HZ,1/16间隔
   
}

}

从上面代码可以轻松的看出驱动原理并不复杂,其实就是把取模软件生成的字模,储存到一个数组里,然后调用arduino的硬件SPI通讯接口,把每8个LED看成是一个十六进制编码,然后一行一行的发送出去,发完一行后,再发出换行指令,就是这么简单。
置于16*16单个汉字取模显示,只要把主loop里的代码改为即可,其实就是简单的数学原理,把数组里的十六进制数按照一组一组提取显示而已~
for(row=0;row<16;row++){

      for (int i=0;i<4;i++){//8片595
         //硬件SPI发送8字节耗时:22US         
         spi_transfer(~(zzz));//硬件SPI      
         spi_transfer(~(zzz));//硬件SPI      
      }

取模软件请选择横向顺序扫描~下载在附件哦~


下面就是小Z做的演示品~主控为Arduino Tiny~欢迎大家根据此来完成各种有趣的Ardunio点阵屏作品~希望此文能给大家拓宽一定的思维~







fddxsyf123 发表于 2015-10-23 17:58:56

对楼上所有的楼主和访客表示感谢,提供了很多有用的资料。
我在此基础上实现了64*32LED阵列的显示,但是问题是用软件SPI刷新速度跟不上,屏幕呈闪烁状态。顾想通过软硬SPI一起执行,提高速率。但是失败了。用了硬件SPI就没法用软件SPI,用了软件SPI就没法用硬件SPI。(我对SPI通信不是很懂)望各位能不能提供好的方法提高刷新速度。

PS:刷 64 * 16 还算可以,可是64 * 32 就 不行了。

附上代码:
int R1=11;
int R2=9;
int STR=10;
int CLK=13;
int EN=6;


int dig0=2;
int dig2=3;
int dig4=4;
int dig8=5;
//int i,m;

unsigned char jj,j;

int down = 0;
int row_ = 0;
void setup()
{
pinMode(R1,OUTPUT);
   pinMode(R2,OUTPUT);
pinMode(STR,OUTPUT);
pinMode(CLK,OUTPUT);
pinMode(EN,OUTPUT);
pinMode(dig0,OUTPUT);
pinMode(dig2,OUTPUT);
pinMode(dig4,OUTPUT);
pinMode(dig8,OUTPUT);

//Serial.begin(19200);

//SPCR = (1<<SPE)|(1<<MSTR);
//delay(10);

}

unsigned char zi[]={
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFD,0xFE,0x1E,0x01,0xBF,0x7F,0x7F,0x7F,0xFD,0xFD,0xEF,0xFD,0xBE,0xFF,0x7F,0x7F,
0xF9,0xFB,0xF7,0xFB,0xBD,0xFF,0x7F,0x7F,0xFA,0xFB,0xFF,0xF7,0xBB,0xFF,0x6F,0x7B,
0x87,0x0D,0xFF,0xEF,0xB7,0xFF,0x70,0x07,0xEF,0xBE,0x1F,0xDF,0xAB,0xFF,0x7C,0x1F,
0xF7,0x7F,0xEF,0xDF,0x9D,0xFF,0x7E,0x3F,0xF7,0x7F,0xF7,0xBF,0xBD,0xFF,0x7C,0x1F,
0xF0,0x7B,0xF7,0x7F,0xBE,0xEF,0x7D,0xDF,0xF7,0x7D,0xEE,0xFF,0xBF,0x6F,0x7B,0xEF,
0xEF,0xBE,0x1E,0x01,0xBF,0xB0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xED,0xB7,0xFE,0xFF,0xFD,0xFF,0x90,0x07,0xE5,0x37,0xFF,0x7F,0xFE,0xFF,0xDF,0xF7,
0xF5,0xE0,0x40,0x01,0x80,0x03,0xFF,0xF7,0xC8,0x2F,0xDF,0xFD,0xBF,0xFB,0x60,0x37,
0xF1,0xCE,0xF8,0x07,0xF3,0x3F,0x6F,0xB7,0xCC,0x4E,0xFF,0xCF,0xE7,0xCF,0x6F,0xB7,
0xFB,0xF5,0xFF,0xBF,0x9F,0xE3,0x60,0x37,0xC0,0x75,0xFF,0x7F,0x3F,0xF9,0x6F,0xB7,
0xEE,0xF9,0x80,0x00,0xC0,0x07,0x6F,0xB7,0xEE,0xFB,0xFF,0x7F,0xFE,0xFF,0x60,0x37,
0xF1,0xF5,0xFF,0x7F,0xFE,0xFF,0x6F,0xF7,0xF0,0x4C,0xFF,0x7F,0xFE,0xFF,0x7F,0xF7,
0xCE,0x9F,0x78,0x7F,0x80,0x03,0x7F,0x87,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};

void row1(int i)
{
      digitalWrite(dig0,(i&0x01));
      digitalWrite(dig2,(i&0x02));
      digitalWrite(dig4,(i&0x04));
      digitalWrite(dig8,(i&0x08));
}


void spi_transfer(volatile char data)
{
SPDR = data;                  // Start the transmission
while (!(SPSR & (1<<SPIF)))   // Wait the end of the transmission
{
};
//return SPDR;                  // return the received byte
}

void sendbyte(byte bbyte1){// 高位在前 反相(1亮0灭)
for (byte i=0; i<8;i++) {
digitalWrite(CLK,0);
if ( bbyte1 & 0x80) {
digitalWrite(R1, 1);
} else {
digitalWrite(R1, 0);
}
bbyte1= bbyte1<<1;
digitalWrite(CLK,1);
}

}

void sendbyte2(byte bbyte1){// 高位在前 反相(1亮0灭)
for (byte i=0; i<8;i++) {
digitalWrite(CLK,0);
if ( bbyte1 & 0x80) {
digitalWrite(R2, 1);
} else {
digitalWrite(R2, 0);
}
bbyte1= bbyte1<<1;
digitalWrite(CLK,1);
}

}




void loop()
{
      unsigned char row,m,k;
       for(row=0;row<16;row++){
         
            for (int i=0;i<8;i++){
               sendbyte(zi);
         }

//          for(row=0;row<16;row++){
//         
//                for (int i=0;i<8;i++){   
//                   //spi_transfer((zi));
//                }
               
            down++;
                digitalWrite(EN,1);
                row1(row);
                digitalWrite(STR,0);
                digitalWrite(STR,1);
                delayMicroseconds(0);
                digitalWrite(EN,0);
                delayMicroseconds(0);
      }
      
         for(row=0;row<16;row++){
         
            for (int i=0;i<8;i++){
                sendbyte2(zi);
         }
            down++;
                digitalWrite(EN,1);
                row1(row);
                digitalWrite(STR,0);
                digitalWrite(STR,1);
                delayMicroseconds(0);
                digitalWrite(EN,0);
                delayMicroseconds(0);
      }
      down = 0;
}

ranqingfa 发表于 2013-6-29 17:11:52

不错不错,我的就是stc的{:soso_e113:}
http://v.youku.com/v_show/id_XNDYyMzg1MjIw.html
现丑了

ranqingfa 发表于 2013-6-29 17:13:33

LZ几个屏哪里买的,喜欢那个小点的,我这个太大个头

ranqingfa 发表于 2013-6-29 17:21:36

其实我开始时候就是arduino控制的,2560 ,竟然忘了,后来改了stc,stc有点吃力,但是安装方便
http://v.youku.com/v_show/id_XMzk3NzMwNzg0.html


tingjie 发表于 2013-6-29 18:04:40

最大可以驱动多少点阵?

万马奔腾 发表于 2013-6-29 19:47:39

tingjie 发表于 2013-6-29 18:04 static/image/common/back.gif
最大可以驱动多少点阵?

同问 分辨率64*128的可以驱动不?

zzz 发表于 2013-6-29 21:17:48

tingjie 发表于 2013-6-29 18:04 static/image/common/back.gif
最大可以驱动多少点阵?

理论上arduino的刷新速度足够,稍微的改下代码中的行扫和列扫就行了~

pww999 发表于 2013-6-30 10:17:11

可以滚屏么?

zzz 发表于 2013-6-30 11:50:25

pww999 发表于 2013-6-30 10:17 static/image/common/back.gif
可以滚屏么?

基础程序放在这里了。。其他的随便自己加把~~~~

pan8412929 发表于 2013-6-30 14:20:31

希望arduino越做越好

ranqingfa 发表于 2013-6-30 21:06:41

是不是不该放在这啊,如果惹LZ不高兴希望版主给删掉,继续问LZ,你的显示屏都是TB买的吗

firewise 发表于 2013-7-2 07:52:44

不错。挺好的,希望arduino越做越好

ro0t 发表于 2013-7-2 11:24:46

楼主给个硬件链接呗、、、

wangku001wei 发表于 2013-7-2 18:16:21

楼主有原理图么?

zzz 发表于 2013-7-3 07:15:41

wangku001wei 发表于 2013-7-2 18:16 static/image/common/back.gif
楼主有原理图么?

呃,等会我找找,应该有
页: [1] 2 3 4 5
查看完整版本: 【Z】Arduino也能驱动LED显示屏,LED业界标准Arduino驱动方案解析