|
本帖最后由 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]
手机拍的效果图:
|
|