在之前的章节,我们曾经用树莓派的IO口输出不同调宽的PWM信号来控制LED灯的亮度。
本文使用芯片TLC5940来输出多路PWM信号以同时控制多达16个LED的亮度。
在本文的基础上你可以发挥想象,制作出各种有趣的彩灯效果。

最终效果TODO

视频演示

硬件

  • TLC5940芯片 X 1
  • LED X 3
  • 2-3k电阻一只

原理说明

简单的说,TLC5940是一个拥有16路输出的LED驱动芯片,每一路输出支持4096级!亮度调节。
老规矩,看一下它的引脚图:
TLC5940的引脚图
跟本文无关的内容或设置在此不做说明,请自己查询datasheet:

引脚功能
OUT0-1516路PWM信号输出(负极)
VPRG指定工作模式,接GND是我们需要的PWM模式
SIN串行移位输入
SCLK串行移位寄存器时钟(上升沿有效)
XLAT从移位寄存器写入GS寄存器(下文介绍)时钟(上升沿有效)
BLANK当设为高电平时,关闭所有输出,GS计数器(下文介绍)也将重置
IREF跟GND之间连接一个电阻,阻值决定了输出电流的最大值
GSCLKGS时钟输入(下文介绍)
SOUT串行输出,级联多块芯片时使用
  1. 先将BLANK设置为H,关闭所有输出。
  2. 输入各组亮度信息。跟我们之前学过的芯片一样,这款芯片同样是通过移位寄存器来输入数据的。
    移位寄存器用于传送12bit X 16组PWM数值GSn(n=0-15),共192bit。每组数据的值范围是0-4095。
    传送顺序是倒序的:GS15,GS14。。。GS0。先传输的是OUT15的12位数据,其次是OUT14的12位数据。。。最后是OUT0的12位数据。
    GSn决定了OUTn的PWM调宽。(GSn / 4095 = 0% - 100%)
  3. 192位数据全部传送完毕后制造XLAT的上升沿,将移位寄存器里的数据写入GS寄存器。
  4. BLANK设置为L,打开所有输出
  5. 准备工作完毕,为了让TLC5940芯片正常工作,还需要向GSCLK输送时钟信号。
    啥是时钟信号?简单的说就是高低电平不停交替的信号,也称作方波信号。
    TLC5940会根据这个时钟信号进行从0-4095的计数(高低电平每交替一次数一次),一边计数一边检查各GSn的设定值,一旦到达GSn的值,则切换OUTn的电平一直计数到4095为止,再从0开始重新计数。从0计数到4095就是一个高低电平的切换周期。所以我们给5940提供的时钟频率越快,最后输出的PWM频率就越快。最后输出的PWM的频率 = 时钟信号的频率 / 4095。
    比如时钟频率是8M,则最后从各OUT口输出的PWM频率是8MHz / 4095 = 1.953KHz。
    根据TLC5940的官方文档,GSCLK可支持最高30MHz的时钟频率,也就是最高可以输出7.3KHz的PWM信号。如果是控制LED的亮度,那么让人眼感觉不到闪烁的最低频率应该是50Hz以上,所以我们应该至少给GSCLK提供不低于50 X 4095 = 200KHz的方波。树莓派Python的GPIO库翻转IO口的速度不高,实测速度只能达到60KHz,导致最后输出的PWM频率只有14Hz,会有明显的闪烁感。但我们主要是为了说明原理,明白原理了可以用别的方法来实现功能,比如使用c语言的wiringPi库的话效率会高不少,甚至可以使用外部的单片机或其他电路来产生高频率的时钟信号提供给TLC5940,这个作者也在探索中。以后有空再更新。

硬件连接

模块1引脚模块2引脚
TLC5940VPRG树莓派GPIO17
TLC5940SIN树莓派GPIO13
TLC5940SCLK树莓派GPIO19
TLC5940XLAT树莓派GPIO27
TLC5940BLANK树莓派GPIO23
TLC5940IREF树莓派GND(中间串联一个2-3k的电阻)
TLC5940SOUT树莓派GPIO4
TLC5940OUT0LED0负极
TLC5940OUT1LED1负极
TLC5940OUT2LED2负极
TLC5940VCC树莓派5V
TLC5940GND树莓派GND
LED0,1,2正极树莓派5V

代码(Python)

#!/usr/bin/env python
 
import RPi.GPIO as GPIO
import time

VPRG=17
SIN=13
SCLK=19
XLAT=27
BLANK=23
DCPRG=18
GSCLK=4

# 传输GSData(0-4095)
def setGSData(data):
    # print ""
    # print "S-----------setByte---------------:", hex(data)
    for bit in range(0,12):
        # 传入的数字从高位到低位依次判断是否为1,若为1则设置高电平,否则设置低电平
        # 判断的方法是先向左移位,把要判断的位移动到最高位然后跟0x800(1000 0000 0000)相与,
        # 如果结果仍然是0x80(1000 0000 0000)就表示最高位是1,否则最高位就是0
        if ((data<<bit) & 0x800 == 0x800):
            setBitData(True)
            # print "1",
        else:
            setBitData(False)
            # print "0",
    # print ""
    # print "E-----------setByte---------------"

def setBitData(data):
    GPIO.output(SCLK, False)
    GPIO.output(SIN, data)
    GPIO.output(SCLK, True)

# 输出GSCLK时钟信号
def runGSCLK():
    i=0
    while(1):
        i+=1
        if i>=4096:
            # 注意,每次计数到4095时需要手动重置一次芯片的计数器
            GPIO.output(BLANK, True)
            #time.sleep(0.001);
            GPIO.output(BLANK, False)
            i=0
        else:
            GPIO.output(GSCLK, True)
            GPIO.output(GSCLK, False)

try:
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(VPRG, GPIO.OUT)
    GPIO.setup(SIN, GPIO.OUT)
    GPIO.setup(SCLK, GPIO.OUT)
    GPIO.setup(XLAT, GPIO.OUT)
    GPIO.setup(BLANK, GPIO.OUT)
    GPIO.setup(DCPRG, GPIO.OUT)
    GPIO.setup(GSCLK, GPIO.OUT)

    # VPRG设置为L,使其工作在GS mode
    GPIO.output(VPRG, False)

    # BLANK设置为H,关闭所有输出
    GPIO.output(BLANK, True)

    GPIO.output(DCPRG, True)

    # 传送12bit X 16组PWM数值GSn(n=0-15),共192bit
    # 每组数据的值范围是0-4095
    # 因为是通过移位寄存器传输,所以传送顺序是倒序的:GS15,GS14。。。GS0
    # GSn决定了OUTn的PWM调宽。(GSn / 4095 = 0% - 100%)
    setGSData(0) # GS15 本文不使用15-3号输出,设为0
    setGSData(0) # GS14
    setGSData(0) # GS13
    setGSData(0) # GS12
    setGSData(0) # GS11
    setGSData(0) # GS10
    setGSData(0) # GS9
    setGSData(0) # GS8
    setGSData(0) # GS7
    setGSData(0) # GS6
    setGSData(0) # GS5
    setGSData(0) # GS4
    setGSData(0) # GS3

    # print "GS2"
    setGSData(4095) # GS2

    # print "GS1"
    setGSData(2500) # GS1

    # print "GS0"
    setGSData(1000) # GS0

    # 送完GS数据后,创造XLAT的上升沿,将移位寄存器的数据一次性送入GS寄存器
    GPIO.output(XLAT, False)
    GPIO.output(XLAT, True)

    # BLANK设置为L,打开所有输出
    # GPIO.output(BLANK, False)

    # 准备工作完毕,下面向GSCLK输送时钟信号(高低电平交互的方波信号)
    # TLC5940会根据这个时钟信号进行从0-4095的计数,一边计数一边检查各GSn的设定值,一旦到达GSn的值,则切换OUTn的电平
    # 一直计数到4095为止,再从0开始重新计数。从0计数到4095就是一个高低电平的切换周期。
    # 所以我们给5940提供的时钟频率越快,最后输出的PWM频率就越快
    # 最后输出的PWM的频率 = 时钟信号的频率 / 4095
    # 比如时钟频率是8M,则最后从各OUT口输出的PWM频率是8MHz / 4095 = 1.953KHz
    # 根据TLC5940的官方文档,GSCLK可支持最高30MHz的时钟频率,也就是最高可以输出7.3KHz的PWM信号。
    # 如果是控制LED的亮度,那么让人眼感觉不到闪烁的最低频率应该是50Hz以上,
    # 所以我们应该至少给GSCLK提供不低于50 X 4095 = 200KHz的方波。
    # 树莓派Python的GPIO库翻转IO口的速度不高,实测速度只能达到60KHz,
    # 导致最后输出的PWM频率只有14Hz,会有明显的闪烁感
    runGSCLK()

except KeyboardInterrupt:
    pass

# 清理GPIO口
GPIO.cleanup()
Last modification:September 8, 2023
If you think my article is useful to you, please feel free to appreciate