拿到MAX7219驱动的LED矩阵,第一件事是先连接并尝试显示图案。使用MAX7219除了需要提供GND以及VCC外,只需要再提供三根引脚即可点亮矩阵。其中,DIN引脚输入数据,CS(LOAD)引脚控制数据输入,CLK引脚用于区分每个bit。
MAX的整个写入流程为,首先CS引脚置0,表示允许写入。而后从高位顺序写入16个bit。每个bit的写入方式为首先DIN置为要写入的bit值,而后CLK产生一个下降沿(图中为上升沿,不知道为何有差别)即被读入。最后CS引脚置1表示写入结束。
时序图如下:
在运行之前,需要进行一次初始化,其行为是向某几个特定的地址写入特定的值。至少需要写入两个地址,第一个是0x0b,写入0x07表示扫描显示所有行。第二个是0x0c,写入1表示进入工作模式。
而后点阵上每一行都有其地址,如第一行是0x01到第八行是0x08,每次向固定行的地址写入一个8位二进制数即可在指定行上显示图案。
2. 树莓派对GPIO的访问——虚拟文件系统访问
Linux可以通过访问sys/class/gpio下的一些文件,通过对这些文件的读写来实现对于GPIO的访问。
树莓派下面的可用的GPIO如右图所示,需要注意树莓派一代和二代的区别。
这里根据大大的博客攻略,我首先尝试用shell。代码直接参考了大大的。先试着玩一下。
!/bin/bash # DIN, CS, CLK的GPIO口位置 DIN=4 CS=3 CLK=2 # 一些文件路径 GPIO_BASE=/sys/class/gpio GPIO_EXPORT=${GPIO_BASE}/export GPIO_UNEXPORT=${GPIO_BASE}/unexport BIN=(00000001 00000010 00000011 00000100 00000101 00000110 00000111 00001000) # 生成指定GPIO引脚的文件夹位置 function GPIO(){ echo ${GPIO_BASE}/gpio$1 } # 将某个引脚export到用户态 function GPIO_export(){ if [ -d `GPIO $1` ]; then echo GPIO pin $1 found in folder. else echo $1 > ${GPIO_EXPORT} fi } # unexport某个引脚 function GPIO_unexport(){ if [ -d `GPIO $1` ]; then echo $1 > ${GPIO_UNEXPORT} else echo GPIO pin $1 not found. fi } # 改变某个引脚的方向 function GPIO_direction(){ echo $2 > `GPIO $1`/direction } # 改变某个引脚的值 function GPIO_set(){ echo $2 > `GPIO $1`/value } # 改变DIN的值 function GPIO_DIN(){ GPIO_set $DIN $1 } # 改变CS的值 function GPIO_CS(){ GPIO_set $CS $1 } # 改变CLK的值 function GPIO_CLK(){ GPIO_set $CLK $1 } # 向MAX7219发送一个byte的值 function Matrix_send_char(){ local i=1 for ((i=1;i<=8;i++)); do chr=`expr substr $1 $i 1` GPIO_DIN $chr GPIO_CLK 1 GPIO_CLK 0 done } # 向MAX7219发送一次完整的信号 function Matrix_send_word(){ GPIO_CS 1 GPIO_CS 0 GPIO_CLK 0 Matrix_send_char $1 Matrix_send_char $2 GPIO_CS 1 } # 初始化GPIO引脚 function GPIO_init(){ GPIO_export $DIN GPIO_export $CS GPIO_export $CLK sleep 2 GPIO_direction $DIN out GPIO_direction $CS out GPIO_direction $CLK out } # 清除GPIO引脚 function GPIO_clear(){ GPIO_unexport $DIN GPIO_unexport $CS GPIO_unexport $CLK } # 在点阵上显示数据 function Matrix_render(){ local i=1 for ((i=0;i<8;i++)); do echo $i $1 Matrix_send_word ${BIN[$i]} $1 shift done } # 使用文件中的数据进行显示 function Matrix_render_file(){ local tmp=(`cat $1`) Matrix_render "${tmp[@]}" } # 使用某个图案清屏 function Matrix_clear(){ local STR=( 00000000 01100110 11111111 11111111 11111111 01111110 00111100 00011000 ) Matrix_render "${STR[@]}" } # 初始化点阵 function Matrix_init(){ # 编码模式 Matrix_send_word 00001001 00000000 # 亮度 Matrix_send_word 00001010 00000011 # 扫描数码管个数 Matrix_send_word 00001011 00000111 # 工作模式 Matrix_send_word 00001100 00000001 # 初始化完毕后清屏显示默认图案 Matrix_clear }
在终端中:
source matrix.sh GPIO_init Matrix_init
效果如图:
3. 树莓派对GPIO的访问——使用库
这里我使用了wiring库,非常容易上手。关键函数:digitalWrite()写GPIO;pinMode()设置GPIO方向;
需要注意的是它的管脚编号和树莓派不同。
上代码:
#include#include #define uchar unsigned char #define uint unsigned int #define DecodeMode 0x09 //译码模式寄存器 #define Intensity 0x0a //亮度寄存器 #define ScanLimit 0x0b //扫描位数寄存器 #define ShutDown 0x0c //低功耗模式寄存器 #define DisplayTest 0x0f //显示测试寄存器 #define ShutdownMode 0x00 //低功耗方式 #define NormalOperation 0x01 //正常操作方式 #define ScanDigit 0x07 //扫描位数设置,显示8位数码管 #define DecodeDigit 0x00 //译码设置,8位均为非译码 #define IntensityGrade 0x0a //亮度级别设置 #define TestMode 0x01 //显示测试模式 #define TextEnd 0x00 //显示测试结束,恢复正常工作模式 #define DIN 8 #define CS 9 #define CLK 7 uchar buffer[8]={0x00,0x66,0xff,0xff,0xff,0xff,0x7e,0x3c,0x18}; void delay(uint t){ uint i; while(t--) for (i = 0; i < 125; i++); } void sendChar(char ch){ char i, tmp; for(i = 0; i < 8; i++){ tmp = ch & 0x80; if(tmp) digitalWrite(DIN, HIGH); else digitalWrite(DIN, LOW); ch = ch << 1; digitalWrite(CLK, HIGH:); digitalWrite(CLK, LOW); } } void writeWord(char addr, char num){ digitalWrite(CS, HIGH); digitalWrite(CS, LOW); digitalWrite(CLK, LOW); sendChar(addr); sendChar(num); digitalWrite(CS, HIGH); } void write(){ char i; for(i = 0; i < 8; i++){ printf("%d %d\n",i, buffer[i]); writeWord(i + 1, buffer[i]); } } void init(){ writeWord(0x09, 0x00); writeWord(0x0a, 0x03); writeWord(0x0b, 0x07); writeWord(0x0c, 0x01); } int main(){ wiringPiSetup(); pinMode(DIN, OUTPUT); pinMode(CS, OUTPUT); pinMode(CLK, OUTPUT); init(); wirte(); return 0; }
Makefile:
matrix:matrix.o gcc matrix.c -o matrix -lwiringPi clean: rm -f matrix matrix.o
结果和前面一样。LED矩阵上显示了爱心。
把上面代码改为python
#!/usr/bin/env python # encoding: utf-8 import RPi.GPIO as GPIO import time DIN = 12 CS = 16 CLK = 18 GPIO.setmode(GPIO.BOARD) GPIO.setup(DIN,GPIO.OUT) GPIO.setup(CS,GPIO.OUT) GPIO.setup(CLK,GPIO.OUT) buffer = ['00000000','01100110','11111111','11111111','11111111','01111110','00111100','00011000'] #buffer = [0x00,0x66,0xff,0xff,0xff,0x7e,0x3c,0x18] def send(byteData): for bit in range(0,8): if(byteData & 0x80): GPIO.output(DIN,True) else: GPIO.output(DIN,False) byteData = byteData<<1 GPIO.output(CLK,True) GPIO.output(CLK,False) def writeWord(addr,num): GPIO.output(CS,True) GPIO.output(CS,False) GPIO.output(CLK,False) send(addr) send(num) GPIO.output(CS,True) def wt(): for i in range(0,8): print("%d %d" %(i,int(buffer[i],2))) writeWord(i+1,int(buffer[i],2)) def initData(): writeWord(0x09,0x00) writeWord(0x0a,0x03) writeWord(0x0b,0x07) writeWord(0x0c,0x01) writeWord(0xff,0x00) try: initData() wt() except KeyboardInterrupt: pass time.sleep(2) GPIO.cleanup()