树莓派 - MAX7219

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/waterseason/article/details/84916976
1.基础:认识MAX7219

拿到MAX7219驱动的LED矩阵,第一件事是先连接并尝试显示图案。使用MAX7219除了需要提供GND以及VCC外,只需要再提供三根引脚即可点亮矩阵。其中,DIN引脚输入数据,CS(LOAD)引脚控制数据输入,CLK引脚用于区分每个bit。
[img]http://dl2.iteye.com/upload/attachment/0129/0210/2a506a2a-f93c-3c83-9001-c81b5a4922b0.png[/img]
MAX的整个写入流程为,首先CS引脚置0,表示允许写入。而后从高位顺序写入16个bit。每个bit的写入方式为首先DIN置为要写入的bit值,而后CLK产生一个下降沿(图中为上升沿,不知道为何有差别)即被读入。最后CS引脚置1表示写入结束。

时序图如下:
[img]http://dl2.iteye.com/upload/attachment/0129/0212/cd0358a7-8cc9-346b-b98c-4efb3c20920f.png[/img]
在运行之前,需要进行一次初始化,其行为是向某几个特定的地址写入特定的值。至少需要写入两个地址,第一个是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

效果如图:
[img]http://dl2.iteye.com/upload/attachment/0129/0216/51403fb9-4fd0-342f-a2e6-4b1ffc5bacdf.png[/img]
3. 树莓派对GPIO的访问——使用库

这里我使用了wiring库,非常容易上手。关键函数:digitalWrite()写GPIO;pinMode()设置GPIO方向;

需要注意的是它的管脚编号和树莓派不同。
[img]http://dl2.iteye.com/upload/attachment/0129/0218/84c25217-85d3-3eb8-ac32-b23a98164898.png[/img]
上代码:

#include <wiringPi.h>
#include <stdio.h>

#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()
展开阅读全文
博主设置当前文章不允许评论。

没有更多推荐了,返回首页