基于树莓派的辉光管时钟制作

warning: 这篇文章距离上次修改已过757天,其中的内容可能已经有所变动。

效果展示

原材料

树莓派zero×1、东德产RFT Z750M辉光管×4、ds1302时钟模块×1、K155ID1×1、5v升170v升压模块×1

辉光管工作原理

和普通的灯泡类似,辉光管内有10个铁片,分别是1-10十个数字,接通哪个就亮哪个,不过这种灯需要高压并限流,需要在电路上注意一下。

170v电压的获得与限流

5v升170v的模块可以从淘宝上轻易获得,这里用5v升压的原因是可以直接从树莓派上取得需要的电压,并且不建议自己DIY升压电路,可能会烧毁树莓派。至于限流,直接加电阻就可以了,我这里用的是20kΩ的电阻。之后阳极连170v加电阻,随便接一根阴极,辉光管就能亮起来了。

辉光管的驱动

因为每一只辉光管都有10+1=11只引脚,树莓派的GPIO肯定是不够用来控制四只辉光管,并且辉光管所需要的高压对树莓派来说也是一个问题,所以需要K155ID1译码器来控制每一只辉光管。下面是该译码器的引脚定义和真值表,需要输出哪个数字就可以在相应的引脚加上需要的高低电平,这样就解决了辉光管的驱动问题。

时间的获取与保存

众所周知,树莓派可以连接wifi进行时间的同步,但是断电后时间不能继续流逝,这就需要ds1302模块进行时间的存储,这里我们可以直接使用WiringPi自带的驱动程序对模块进行操作。文件位置在 WiringPi 安装包的 examples/ds1302.c,代码如下

/*
 * ds1302.c:
 *    Real Time clock
 *
 * Copyright (c) 2013 Gordon Henderson.
 ***********************************************************************
 * This file is part of wiringPi:
 *    https://projects.drogon.net/raspberry-pi/wiringpi/
 *
 *    wiringPi is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Lesser General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    wiringPi is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public License
 *    along with wiringPi.  If not, see <http://www.gnu.org/licenses/>.
 ***********************************************************************
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>

#include <wiringPi.h>
#include <ds1302.h>

// Register defines

#define    RTC_SECS     0
#define    RTC_MINS     1
#define    RTC_HOURS     2
#define    RTC_DATE     3
#define    RTC_MONTH     4
#define    RTC_DAY         5
#define    RTC_YEAR     6
#define    RTC_WP         7
#define    RTC_TC         8
#define    RTC_BM        31


static unsigned int masks [] = { 0x7F, 0x7F, 0x3F, 0x3F, 0x1F, 0x07, 0xFF } ;


/*
 * bcdToD: dToBCD:
 *    BCD decode/encode
 *********************************************************************************
 */

static int bcdToD (unsigned int byte, unsigned int mask)
{
  unsigned int b1, b2 ;
  byte &= mask ;
  b1 = byte & 0x0F ;
  b2 = ((byte >> 4) & 0x0F) * 10 ;
  return b1 + b2 ;
}

static unsigned int dToBcd (unsigned int byte)
{
  return ((byte / 10) << 4) + (byte % 10) ;
}


/*
 * ramTest:
 *    Simple test of the 31 bytes of RAM inside the DS1302 chip
 *********************************************************************************
 */

static int ramTestValues [] =
  { 0x00, 0xFF, 0xAA, 0x55, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0xF0, 0x0F, -1 } ;

static int ramTest (void)
{
  int addr ;
  int got ;
  int i = 0 ;
  int errors = 0 ;
  int testVal ;

  printf ("DS1302 RAM TEST\n") ;

  testVal = ramTestValues [i] ;

  while (testVal != -1)
  {
    for (addr = 0 ; addr < 31 ; ++addr)
      ds1302ramWrite (addr, testVal) ;

    for (addr = 0 ; addr < 31 ; ++addr)
      if ((got = ds1302ramRead (addr)) != testVal)
      {
    printf ("DS1302 RAM Failure: Address: %2d, Expected: 0x%02X, Got: 0x%02X\n",
        addr, testVal, got) ;
    ++errors ;
      }
    testVal = ramTestValues [++i] ;
  }

  for (addr = 0 ; addr < 31 ; ++addr)
    ds1302ramWrite (addr, addr) ;

  for (addr = 0 ; addr < 31 ; ++addr)
    if ((got = ds1302ramRead (addr)) != addr)
    {
      printf ("DS1302 RAM Failure: Address: %2d, Expected: 0x%02X, Got: 0x%02X\n",
          addr, addr, got) ;
      ++errors ;
    }

  if (errors == 0)
    printf ("-- DS1302 RAM TEST: OK\n") ;
  else
    printf ("-- DS1302 RAM TEST FAILURE. %d errors.\n", errors) ;

  return 0 ;
}

/*
 * setLinuxClock:
 *    Set the Linux clock from the hardware
 *********************************************************************************
 */

static int setLinuxClock (void)
{
  char dateTime [20] ;
  char command [64] ;
  int  clock [8] ;


  printf ("Setting the Linux Clock from the DS1302... ") ; fflush (stdout) ;

  ds1302clockRead (clock) ;

// [MMDDhhmm[[CC]YY][.ss]]

  sprintf (dateTime, "%02d%02d%02d%02d%02d%02d.%02d",
    bcdToD (clock [RTC_MONTH], masks [RTC_MONTH]),
    bcdToD (clock [RTC_DATE],  masks [RTC_DATE]),
    bcdToD (clock [RTC_HOURS], masks [RTC_HOURS]),
    bcdToD (clock [RTC_MINS],  masks [RTC_MINS]),
    20,
    bcdToD (clock [RTC_YEAR],  masks [RTC_YEAR]),
    bcdToD (clock [RTC_SECS],  masks [RTC_SECS])) ;

  sprintf (command, "/bin/date %s", dateTime) ;
  system (command) ;

  return 0 ;
}


/*
 * setDSclock:
 *    Set the DS1302 block from Linux time
 *********************************************************************************
 */

static int setDSclock (void)
{
  struct tm* t = NULL ;
  time_t now ;
  int clock [8] ;

  printf ("Setting the clock in the DS1302 from Linux time... ") ;

  now = time (NULL) ;
  //gmtime_r (&now, &t) ;
 t = localtime(&now);

  clock [ 0] = dToBcd (t->tm_sec) ;    // seconds
  clock [ 1] = dToBcd (t->tm_min) ;    // mins
  clock [ 2] = dToBcd (t->tm_hour) ;    // hours
  clock [ 3] = dToBcd (t->tm_mday) ;    // date
  clock [ 4] = dToBcd (t->tm_mon + 1) ;    // months 0-11 --> 1-12
  clock [ 5] = dToBcd (t->tm_wday + 1) ;    // weekdays (sun 0)
  clock [ 6] = dToBcd (t->tm_year - 100) ;       // years
  clock [ 7] = 0 ;            // W-Protect off

  ds1302clockWrite (clock) ;

  printf ("OK\n") ;

  return 0 ;
}




int main (int argc, char *argv [])
{
  int i ;
  int clock [8] ;

  wiringPiSetup () ;
  ds1302setup   (14, 30, 10) ;
  //此处填写ds1302模块对应的管脚

  if (argc == 2)
  {
    /**/ if (strcmp (argv [1], "-slc") == 0)
      return setLinuxClock () ;
    else if (strcmp (argv [1], "-sdsc") == 0)
      return setDSclock () ;
    else if (strcmp (argv [1], "-rtest") == 0)
      return ramTest () ;
    else
    {
      printf ("Usage: ds1302 [-slc | -sdsc | -rtest]\n") ;
      return EXIT_FAILURE ;
    }
  }

  for (i = 0 ;; ++i)
  {
    printf ("%5d:  ", i) ;

    ds1302clockRead (clock) ;
    printf (" %2d:%02d:%02d",
    bcdToD (clock [2], masks [2]), bcdToD (clock [1], masks [1]), bcdToD (clock [0], masks [0])) ;

    printf (" %2d/%02d/%04d",
    bcdToD (clock [3], masks [3]), bcdToD (clock [4], masks [4]), bcdToD (clock [6], masks [6]) + 2000) ;
      
    printf ("\n") ;

    delay (200) ;
  }
 
  return 0 ;
}

以下是辉光管驱动程序

# coding=utf-8
import time
import datetime
import RPi.GPIO

# 定义单个辉光管各段led对应的GPIO口
L = [[12, 20, 21, 16], [26, 13, 6, 19], [22, 17, 4, 27], [18, 24, 25, 23]]

RPi.GPIO.setmode(RPi.GPIO.BCM)
for i in range(0, 4):
    for j in range(0, 4):
        RPi.GPIO.setup(L[i][j], RPi.GPIO.OUT)


# 指定no(1-4)号辉光管显示数字num(0-9)
def showDigit(no, num):
    if (no):
        if (num == 0):
            RPi.GPIO.output(L[no - 1][0], False)
            RPi.GPIO.output(L[no - 1][1], False)
            RPi.GPIO.output(L[no - 1][2], False)
            RPi.GPIO.output(L[no - 1][3], False)

        elif (num == 1):
            RPi.GPIO.output(L[no - 1][0], True)
            RPi.GPIO.output(L[no - 1][1], False)
            RPi.GPIO.output(L[no - 1][2], False)
            RPi.GPIO.output(L[no - 1][3], False)

        elif (num == 2):
            RPi.GPIO.output(L[no - 1][0], False)
            RPi.GPIO.output(L[no - 1][1], True)
            RPi.GPIO.output(L[no - 1][2], False)
            RPi.GPIO.output(L[no - 1][3], False)

        elif (num == 3):
            RPi.GPIO.output(L[no - 1][0], True)
            RPi.GPIO.output(L[no - 1][1], True)
            RPi.GPIO.output(L[no - 1][2], False)
            RPi.GPIO.output(L[no - 1][3], False)

        elif (num == 4):
            RPi.GPIO.output(L[no - 1][0], False)
            RPi.GPIO.output(L[no - 1][1], False)
            RPi.GPIO.output(L[no - 1][2], True)
            RPi.GPIO.output(L[no - 1][3], False)

        elif (num == 5):
            RPi.GPIO.output(L[no - 1][0], True)
            RPi.GPIO.output(L[no - 1][1], False)
            RPi.GPIO.output(L[no - 1][2], True)
            RPi.GPIO.output(L[no - 1][3], False)

        elif (num == 6):
            RPi.GPIO.output(L[no - 1][0], False)
            RPi.GPIO.output(L[no - 1][1], True)
            RPi.GPIO.output(L[no - 1][2], True)
            RPi.GPIO.output(L[no - 1][3], False)

        elif (num == 7):
            RPi.GPIO.output(L[no - 1][0], True)
            RPi.GPIO.output(L[no - 1][1], True)
            RPi.GPIO.output(L[no - 1][2], True)
            RPi.GPIO.output(L[no - 1][3], False)

        elif (num == 8):
            RPi.GPIO.output(L[no - 1][0], False)
            RPi.GPIO.output(L[no - 1][1], False)
            RPi.GPIO.output(L[no - 1][2], False)
            RPi.GPIO.output(L[no - 1][3], True)

        elif (num == 9):
            RPi.GPIO.output(L[no - 1][0], True)
            RPi.GPIO.output(L[no - 1][1], False)
            RPi.GPIO.output(L[no - 1][2], False)
            RPi.GPIO.output(L[no - 1][3], True)


# 防止阴极中毒,每隔一段时间循环点亮所有数字
def protect():
    t = 2
    for i in range(0, 10):
        showDigit(1, i)
        showDigit(2, i)
        showDigit(3, i)
        showDigit(4, i)
        time.sleep(t)


t = 0.01
start_time = datetime.datetime.now()
while True:
    now_time = datetime.datetime.now()
    time.sleep(t)
    showDigit(1, int(time.strftime("%H", time.localtime(time.time()))) / 10)
    showDigit(2, int(time.strftime("%H", time.localtime(time.time()))) % 10)
    showDigit(3, int(time.strftime("%M", time.localtime(time.time()))) / 10)
    showDigit(4, int(time.strftime("%M", time.localtime(time.time()))) % 10)
    if (now_time - start_time).seconds >= 600:
        start_time = datetime.datetime.now()
        protect()

版权属于:NoColor

转载时须注明出处及本声明

添加新评论