单色数码管arduino类库-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8338|回复: 6

单色数码管arduino类库

[复制链接]
发表于 2013-12-5 22:22 | 显示全部楼层 |阅读模式
本帖最后由 ardypro 于 2013-12-6 09:56 编辑

我是个懒人,懒的每次在arduino使用数码管显示的时候,都要拼凑段的真值表,刚开始也蛮有野心的,也想支持彩色,但是手头上没有彩色的数码管,因此最后完成的只是单色数码管的类库。能驱动单色、7段式数码管/时钟管,位数可以不限,同时也可以支持共阴类型或者共阳类型,默认支持的是共阴型数码管。


支持显示0-9数字、负号以及简单的字符,显示的时候可以是左对齐、居中或者右对齐格式,显示数字的时候,还可以选择是否用0补全。


可以在声明数码管类库对象时传递片选脚和码段脚,也可以事后传递,但必须在调用其它方法之前完成。保存IO脚的数组,在C++语言中,数组是指针类型,所以传递数组的时候,可以直接传递数组名字,也可以传递数组第一个元素的首地址,两种方式效果是一样的。


头文件:
[mw_shl_code=cpp,true]/*
* 七段数码管Arduino类库,在Arduino0023下面编译/测试
*
* SevenSegmentDisplay.cpp
*
*  Created on: 2012-4-12
*      Author: Jack Zhong (jzopen@yeah.net)
*           Version: 0.2
*
*数码管位数索引从0开始,为最右边那位,依次向左增加
*
*使用之前,需要设置数码管的类型,默认为共阴,接着设置位选脚和码段脚
*
*
*        HISTORY
*
*
*        2012-04-18        增加文本对齐功能,为左对齐/居中/右对齐
*/

/*
* Seven segment display library 0.2
*
* by Jack Zhong
*
*
* LICENSE:
*
* This library is an OPEN SOURCE application, and free of charge for personal
* and commercial usage, but you need get a permission in writing from
* the author for commercial usage.
*
* Please let me know if you find any bugs, if you made any modification, please
* give me a copy of your new library.
*
*
* USAGE INSTRUCTION:
*
* This library supports cathode common and anode common type 7 segment displays,
* the default type is cathode one, if you have anode common displays, you need declare
* variables and set the parameter to COMMONANODE explicitly., for example:
*
*                 SevenSegmentDisplay led(COMMONANODE);
*
* and you could pass the pins to the variable when declared as following:
*
*                 SevenSegmentDisplay(unsigned int* DigitPins, unsigned int Digits,
*                unsigned int* SegmentPins, unsigned int Segments, LEDTYPE LEDType =
*                COMMONCATHODE);
*
* Please bear in mind that the display digits are indexed from 0, it is the rightmost
* one
*
* ┌─┐  ┌─┐  ┌─┐  ┌─┐
* ├─┤  ├─┤  ├─┤  ├─┤
* └─┘. └─┘. └─┘. └─┘.
*  3    2    1    0
*
* then you declare an array, for example, unsigned int digitsPins[4] ={ 2, 3, 4, 5 }
* to host the digit pins. pin 2 is the first digit, pin 3 is the second digit and so on.
*
* As for passing the segment pins, it needs an array to host the pins for a,b,c,
* d,e,f,g,dp segments in series,
*
*                 unsigned int segPins[8] ={ 6, 7, 8, 9, 10, 11, 12, 13 };
*
* Also, the pins could be configured later with the following methods:
*
*                 //led.setSegmentPins(&segPins[0]);
*                 led.setSegmentPins(segPins);
*                 led.setDigitPins(digitsPins);
*
* display() are a couple of overloaded methods to display string, integer, single char,
* or float number. It's simple to use:
*
*                 display(3721);
*                 display("Err", taRIGHT);
*
*/

#ifndef SEVENSEGMENTDISPLAY_H_
#define SEVENSEGMENTDISPLAY_H_

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

enum LEDTYPE
{
        COMMONCATHODE = 0 /*共阴*/, COMMONANODE = 1 /*共阳*/
};

enum TextAlignment
{
        taLEFT, taCENTER, taRIGHT
};

class SevenSegmentDisplay
{
private:
    void initial(LEDTYPE ledtype);
        void displaySingleChar(char chr, unsigned int position, bool displayDot =
                        false); // 显示某一位,为数码管的显示功能的实现方式
public:
        SevenSegmentDisplay(LEDTYPE LEDType = COMMONCATHODE);
        SevenSegmentDisplay(unsigned int* DigitPins, unsigned int Digits,
                        unsigned int* SegmentPins, unsigned int Segments, LEDTYPE LEDType =
                                        COMMONCATHODE);

        void setDigitPins(unsigned int *, unsigned int counts = 4); //设置位选脚
        void setSegmentPins(unsigned int *, unsigned int counts = 8); //设置码段脚

        void display(char c, unsigned int position = 0); //显示
        void display(String msg, TextAlignment textAlign = taLEFT);
        void display(int value, bool insertLeadingZero = false);
        void display(double value, bool insertLeadingZero = false);

        void turnOff(void); //关闭整个数码管

        void turnOffSingle(unsigned int position);

        void diagnoze(void); //测试数码管好坏
};

#endif /* SEVENSEGMENTDISPLAY_H_ */
[/mw_shl_code]





实现代码:
[mw_shl_code=cpp,true]#include "SevenSegmentDisplay.h"

#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

//#define DEBUG 1

extern HardwareSerial Serial;

/*
*   共阴类型数码管的真值表,dp均未点亮
*   如果需要点亮dp,则在真值上+1
*
*           码段顺序为a/b/c/d/e/f/g/dp
*
*   如果是驱动共阳类型,则用FF-共阴真值
*/
unsigned int truthTable[14] =
{
//0-9,E,r,-
    0xFC, //0
    0x60, //1
    0xDA, //2
    0xF2, //3
    0x66, //4
    0xB6, //5
    0xBE, //6
    0xE0, //7
    0xFE, //8
    0xF6, //9
    0x9E, //E
    0x0A, //r
    0x02, //-
    0x00 //blank
};

const int charE = 10;       //在真值表中的位置
const int charR = 11;
const int charMinus = 12;
const int charBlank = 13;

unsigned int* pinDigits;    //存放位选脚的数组
unsigned int* pinSegments;  //存放码段的数组
unsigned int digitCount = 4; //位数,默认4位
unsigned int segCount = 8;  //码段数,默认8位,含小数点

LEDTYPE ledType;

//下面四个变量存放不同类型数码管的ACTIVE/INACTIVE,便于阅读
bool inactiveDigit;
bool activeDigit;
bool inactiveSegment;
bool activeSegment;

struct LEDString
{
    char originChar;
    bool attachedDot;
};

String dtoa(double value)
{
    int i = 0;
    int v = (int) value;
    while (value != v)
    {
        value *= 10.0;
        v = (int) value;
        i++;
    }
    char str[20];
    itoa(value, str, 10);
    String ret = "";
    String tmp = "";
    ret = str;

    tmp += ret.substring(0, ret.length() - i);
    tmp += ".";
    tmp += ret.substring(ret.length() - i);

    return tmp;
}

SevenSegmentDisplay::SevenSegmentDisplay(LEDTYPE LEDType)
{
    initial(LEDType);

}

SevenSegmentDisplay::SevenSegmentDisplay(unsigned int* DigitPins,
        unsigned int Digits, unsigned int* SegmentPins, unsigned int Segments,
        LEDTYPE LEDType)
{
    initial(LEDType);

    setDigitPins(DigitPins, Digits);
    setSegmentPins(SegmentPins, Segments);
}

void SevenSegmentDisplay::initial(LEDTYPE ledtype)
{
    ledType = ledtype;

    //片选信号的inactive/active,其值跟LEDTYPE类型相同
    inactiveDigit = !ledType;
    activeDigit = ledType;

    //码段信号的inactive/active
    inactiveSegment = ledType;
    activeSegment = !ledType;

}
void SevenSegmentDisplay::setDigitPins(unsigned int * pins, unsigned int counts)
{
    pinDigits = &pins[0];
    for (unsigned int i = 0; i < counts; i++)
    {
        //pinDigits = pins;
        pinMode(pins, OUTPUT);
        digitalWrite(pins, inactiveDigit); //digitalWrite(pins, ~ledType);
    }

    digitCount = counts;
}

void SevenSegmentDisplay::setSegmentPins(unsigned int * pins,
        unsigned int counts)
{
    pinSegments = &pins[0];
    for (unsigned int i = 0; i < counts; i++)
    {
        //pinSegments = pins;
        pinMode(pins, OUTPUT);
        digitalWrite(pins, inactiveSegment); //digitalWrite(pins, ledType);
    }

    segCount = counts;
}

void SevenSegmentDisplay::turnOffSingle(unsigned int position)
{
    //先将位选信号值置inactive,共阴类型置HIGH,共阳类型置LOW
    digitalWrite(pinDigits[position], inactiveDigit); //digitalWrite(this->pinDigits[position], ~ledType);
}

void SevenSegmentDisplay::displaySingleChar(char chr, unsigned int position,
        bool displayDot)
{

    //先将位选信号置为active
    digitalWrite(pinDigits[position], activeDigit);

    //然后显示字符
    int truthValue = 0;
    int index = -1; //如果是不被支持的字符,则不显示
    switch (chr)
    {
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
        index = chr - '0';
        break;
    case 'E':
        index = charE;
        break;
    case 'r':
        index = charR;
        break;
    case '-':
        index = charMinus;
        break;
    case ' ':
        index = charBlank;
        break;
    }

    if (index != -1)
    {
        //取得字符对应的真值,真值表中的值是共阴类型
        truthValue = truthTable[index];

        if (displayDot)
            truthValue++;
        //因此共阳类型数码管的真值需要取反
        if (ledType == COMMONANODE)
            truthValue = 0xFF - truthValue;

        for (unsigned int i = 0; i < segCount; i++)
        {
            digitalWrite(pinSegments, bool(truthValue & 0x80));
            truthValue <<= 1;

        }

#ifdef DEBUG
        delay(500);
#else
        delay(3);
#endif

    }
    //先关闭position位置的数码管的显示
    turnOff();
    //显示之前,先关闭码段
    for (unsigned int i = 0; i < segCount; i++)
    {
        digitalWrite(pinSegments, inactiveSegment);
    }
}

void SevenSegmentDisplay::display(char c, unsigned int position)
{
    displaySingleChar(c, position);
}

void SevenSegmentDisplay::display(String msg, TextAlignment textAlign)
{
    unsigned int len = msg.length();
    unsigned int p = digitCount - 1;
    unsigned char c = ' ';
    unsigned int i = 0;

    LEDString ledStr[len];

    unsigned int j = 0;
    while (i < len)
    {
        c = msg;
        if (c == '.'||c==':')
        {
            if (j == 0)
            {
                ledStr[j].originChar = ' ';
                ledStr[j].attachedDot = true;
                j++;
            }
            else
            {
                ledStr[j - 1].attachedDot = true;
            }
        }
        else
        {
            ledStr[j].originChar = c;
            ledStr[j].attachedDot = false;
            j++;
        }
        i++;
    }

    //计算字符串显示的开始位置
    switch (textAlign)
    {
    case taRIGHT:
        p = j - 1; //digitCount-(digitCount-len)-1=len-1
        break;
    case taLEFT:
        break; //p=digitCount-1
    case taCENTER:
        p = digitCount - ((digitCount - j) / 2) - 1;
        break;
    }

    i = 0;

    while (i < j)
    {

#ifdef DEBUG
        Serial.println(i);
        Serial.println(ledStr.originChar);
        Serial.println(p);
        Serial.println(i);
        Serial.println(ledStr.attachedDot);
#endif

        displaySingleChar(ledStr.originChar, p - i, ledStr.attachedDot);
        i++;

    }
}

void SevenSegmentDisplay::display(int value, bool insertLeadingZero)
{
    String str;
    char c[digitCount + 1]; //数组会在后面加\0,所以数组长度+1,防止溢出 (from 小菜)
    itoa(value, c, 10);
    str = c;

    if ((insertLeadingZero) && (value > 0))
    {
        unsigned int len;
        len = str.length();
        for (unsigned int i = 0; i < (digitCount - len); i++)
            str = "0" + str;
    }

    display(str, taRIGHT);

}

void SevenSegmentDisplay::display(double value, bool insertLeadingZero)
{
    //display(ftoa(value), insertLeadingZero);
    String str;
    str = dtoa(value);

    Serial.println("display float");
    Serial.println(str);

    if ((insertLeadingZero) && (value > 0))
    {
        unsigned int len;
        len = str.length();
        for (unsigned int i = 0; i < (digitCount - len); i++)
            str = "0" + str;
    }
    display(str, taRIGHT);
}

void SevenSegmentDisplay::turnOff(void)
{
    for (unsigned int i = 0; i < digitCount; i++) //TODO 修改关闭算法
        turnOffSingle(i);
}

void SevenSegmentDisplay::diagnoze(void)
{
    //★★★★★这个地方有点风险,当位数较多时,暂时过流的风险比较大★★★★★

    //先显示8.
    for (unsigned int i = 0; i < segCount; i++)
        digitalWrite(pinSegments, activeSegment);
    //然后依次位选
    unsigned int t = 0;
    t = millis();
    while ((millis() - t) < 200)
    {
        for (unsigned int i = 0; i < digitCount; i++)
        {
            digitalWrite(pinDigits, activeDigit);
        }
    }
    turnOff();
}
[/mw_shl_code]







代码里注释比较丰富,关键是LED的驱动方式很简单,应该很容易理解。举个例子更直观:
[mw_shl_code=cpp,true]#include <SevenSegmentDisplay.h>
/*
Sample codes for 7 segments display

by Jack Zhong(jzopen@yeah.net)



Please refer to the library header file
for usage instructions in Chinese.

If you ran into trouble to read those
Chinese words, please open the .h files
with Notepad or any other word processing
application you like. Please bear in mind,
DO NOT try to modify the codes unless there
is a must to do so.

*/

//  Declare a variable led of cathode common type,
//  if it were a anode one, please imply the type
//  when declared in this way:
//  SevenSegmentDisplay led(COMMONANODE);
SevenSegmentDisplay led;
//  Define an array to host digit pins
//  In this example, the display has
//  4 digits, in another word, it could
//  display 4 digits at a time
unsigned int digitsPins[4] =
{
  2, 3, 4, 5 };
//  Define an array to host segment pins
//  pins start from segmemt a to segment dp.
unsigned int segPins[8] =
{
  6, 7, 8, 9, 10, 11, 12, 13 };

char c='1';
int i=0;

void setup()
{
  //  enable Serial object if you need trace the project
  Serial.begin(9600);  

  //  You can pass the pins in either of two ways
  //led.setSegmentPins(&segPins[0]);
  led.setSegmentPins(&segPins[0]);
  led.setDigitPins(&digitsPins[0]);

  // call diagnoze() to check if the display work properly
  led.diagnoze();
}

void loop()
{
  i++;
  c= i/1000;
  if (c>6)
    i=0;

  //because my serial in mega board was out of work,
  //so I disable the following code.

  //#define GOODSERIAL
#ifdef GOODSERIAL
  if (Serial.available()>0)
    c= Serial.read();
#else
  c=c+'0';
#endif

  Serial.println(c);

  switch (c)
  {
  case '0':
  case 'l':
  case 'L':

    //  Display string, it supports left alignment,
    //  center alignment and right alignment
    //  the default value for displaying string is left alignment.
    led.display("Err");
    break;
  case '1':
  case 'c':
  case 'C':
    led.display("Err", taCENTER);
    break;
  case '2':
  case 'r':
  case 'R':
    led.display("Err", taRIGHT);
    break;
  case '3':
  case 'i':
  case 'I':
    //  Display integer number
    led.display(i/5);
    break;
  case '4':
    //  you can decide whether add the leading zero or not
    led.display(i/5,true);
    break;
  case '5':
  case 'f':
  case 'F':
    //  display float number
    led.display( i/10.0);
    break;
  default:
    //led.diagnoze();
    break;
  }

}

[/mw_shl_code]






手机拍的效果图:
led2.jpg






led1.jpg




发表于 2013-12-7 05:30 | 显示全部楼层
秒点是怎么回事?后加上的吗?
 楼主| 发表于 2013-12-7 21:45 | 显示全部楼层
新月 发表于 2013-12-7 05:30
秒点是怎么回事?后加上的吗?

图片不是sample的那个结果,是另外一个sample的,懒得再搭电路做示范了
发表于 2013-12-8 14:05 | 显示全部楼层
请问你的数码管加了三极管驱动吗?我以前测试的时侯想根据传入的串口数字来动态显示。没加任何其他电路的时侯发现数码管显示很暗,仔细观察,好像不停的闪,因为串口数字经常变化,导致数码管每段都有机会显示,所以整体很灰暗,只有出现概率高的数字能显示亮一些,不知道是不是因为驱动电流不够的缘故,我的是共阳数码管,如果加三极管应该加什么型号的?
 楼主| 发表于 2013-12-8 18:19 | 显示全部楼层
软件我是小白, 硬件就是老白了

没加三极管,加了三极管之后是不是能提高亮度也不敢确定。扫描方式驱动的LED,亮度跟扫描的频率有关。对于变化频率很高的显示效果要暗一些,甚至可能这个类库不适合,解决办法可能需要借鉴色LED屏的方案。
发表于 2013-12-10 00:57 | 显示全部楼层
我喜欢这段代码
 楼主| 发表于 2013-12-11 08:17 | 显示全部楼层

thanks
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2025-1-1 21:10 , Processed in 0.081782 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表