买了一个四位数码管,它长这样,有4个针脚,内部驱动芯片为TM1637,还有一种内部驱动芯片为74HC595,有5个针脚,千万要注意,不然就要996了,不过如果你买成了74HC585,可以参考阿迪王的这篇文章:
说回TM1637,这个模块是一个12脚的带时钟点的4位共阳数码管,只需要2跟线号线即可使单片机控制4位8段数码管,并且亮度8级可调。
接线
接线如上图,VCC接5V,GND接GND,CLK接GPIO19,DIO接GPIO26。显示是通过时钟CLK和DIO共同控制。
新建TLEDTM1637Driver类,用来封装显示模块,代码如下:
public class LEDTM1637Driver : IDisposable
{
private byte[] Characters = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71 };//0~9,A,b,C,d,E,F
private int dataPin { get; set; } // Serial Digital Input
private int clockPin { get; set; } // Serial Clock
private GpioController gpio;
public LEDTM1637Driver(int dio, int clock)
{
dataPin = dio;
clockPin = clock;
gpio = new GpioController(PinNumberingScheme.Logical);
gpio.OpenPin(dataPin, PinMode.Output);
gpio.OpenPin(clockPin, PinMode.Output);
gpio.Write(dataPin, PinValue.Low);
gpio.Write(clockPin, PinValue.Low);
}
public void Dispose()
{
gpio?.Dispose();
gpio = null;
}
private void WriteByte(byte input)
{
for (int i = 0; i < 8; i++)//每次写入一个byte,一共8bit
{
gpio.Write(clockPin, PinValue.Low);//确保无误输入前再拉低一次时钟 ,代表开始写入数据
if ((input & 0x01) == 1)
{
gpio.Write(dataPin, PinValue.High);
}
else
{
gpio.Write(dataPin, PinValue.Low);
}
input >>= 1;//每写入完毕一次,移动一位
gpio.Write(clockPin, PinValue.High);//每次输入完一位,就拉高一次时钟
}
//应答信号ACK,这里本来是用来判断DIO脚是否被自动拉低,代表上面写入的数据TM1637已经接受到了,
//但是我们这里闲麻烦,直接将CLK信号低高低的拉,让芯片直接执行下一步操作
gpio.Write(clockPin, PinValue.Low);//先拉低
gpio.Write(clockPin, PinValue.High);//需要判断D是否为低电平此期间C一直拉高
gpio.Write(clockPin, PinValue.Low);//应答完毕以后拉低C
}
private void Write(byte input)
{
StartDiaplay();
WriteByte(input);
StopDiaplay();
}
public void Show(char[] msg)
{
Write(0x40);//指定功能参数为自动增加
StartDiaplay();
WriteByte(0xC0);//设置首地址,指向第一个字符
for (int i = 0; i < 4; i++)
{
if (i != 1)
{
WriteByte(Characters[msg[i] - 48]);//从Characters数组根据索引获得字符显示的编码
}
else
{
WriteByte((byte)(Characters[msg[1] - 48] + 0x80));//第二个字符带有冒号,因此将第一位空置拉高
}
}
StopDiaplay();//开始写入亮度
Write(0x8f);
}
public void ShowV2(char[] msg)
{
//设置基本参数
Write(0x44);//指定功能参数为固定地址显示
//设置显示地址以及显示内容
StartDiaplay();
WriteByte(0xC0);//第一个字符
WriteByte(Characters[msg[0] - 48]);
StopDiaplay();
StartDiaplay();
WriteByte(0xC1);//第二个字符
WriteByte((byte)(Characters[msg[1] - 48] + 0x80));//第二个字符带有冒号,因此将第一位空置拉高
StopDiaplay();
StartDiaplay();
WriteByte(0xC2);//第三个字符
WriteByte(Characters[msg[2] - 48]);
StopDiaplay();
StartDiaplay();
WriteByte(0xC3);//第四个字符
WriteByte(Characters[msg[3] - 48]);
StopDiaplay();
//开始写入亮度
Write(0x8f);
}
private void StartDiaplay()
{
gpio.Write(clockPin, PinValue.High);//CLK拉为高电平
gpio.Write(dataPin, PinValue.High);//DIO拉为高电平
gpio.Write(dataPin, PinValue.Low); //和上面那句指令一起就是DIO由高变低
gpio.Write(clockPin, PinValue.Low);//然后CLK上的时钟信号拉低,DIO接口的数据允许改变,代表开始写入数据
}
private void StopDiaplay()
{
//结束条件是CLK为高时,DIO由低电平变为高电平
gpio.Write(clockPin, PinValue.Low);//先拉低CLK,代表允许DIO改变数据
gpio.Write(dataPin, PinValue.Low);//拉低DIO
gpio.Write(clockPin, PinValue.High);//CLK拉高,满足结束条件前半部分
gpio.Write(dataPin, PinValue.High);//DIO由低变高,代表数据输入结束
}
}
该模块的现实,可以参考TM1637的文档,不想看文档可以参考 在树莓派Zero上使用C#+Mono驱动TM1637四位数码管 这篇文章,我在这篇文章代码的基础上进行了一点修改。
要显示内容,调用代码如下:
static void Main(string[] args)
{
Console.WriteLine("Hello World TM1637 4 Digit LED!");
string s = args.Length > 0 ? args[0] : "";
if (!string.IsNullOrEmpty(s))
{
Console.WriteLine("args:" + s);
}
using (LEDTM1637Driver ledtm1673Driver = new LEDTM1637Driver(26, 19))
{
while (true)
{
char[] date = s == "" ? DateTime.Now.ToString("hhmm").ToCharArray() : s.ToCharArray();//获得当前日期,并表示为小时分钟
ledtm1673Driver.Show(date);
}
}
}
可以接受4为数字输入显示,如果没有输入,就是个时钟,显示时分。显示效果如下:
▲996😂
▲ 1024 😁
参考
- https://www.cnblogs.com/ACDIV/p/11625977.html
- https://edi.wang/post/2016/4/29/windows-10-iot-74hc595-led-digital-tube