一般我们在arduino开发板上显示数字,通常采用多位数码管进行显示,而多位数码管实际是采用“动态扫描显示”的方法进行显示,即依次显示第1位数码管、第2位数码管、第3位数码管、第4位数码管……此方法是利用人眼的视觉残留,当扫描显示的频率大于25帧/秒,我们看到的就是每个数码管同时都在显示。目前大多数arduino的样本程序都是在主循环中不断地进行循环显示,但这样的做法有一个很大问题。如果主循环中的一次循环需要运行较长时间(超过40ms),那显示频率就会低于25帧/秒,从而看到的显示是抖动的,甚至内容是跳跃的。
为保证显示频率大于25帧/秒,我们可以采用arduino的时钟中断来进行“动态扫描显示”。首先要设置合适的时钟中断间隔,每次中断显示一位数码管,以及25帧/秒的最低显示要求,中断时间间隔必须小于10ms(1000ms/4/25),为提高显示质量,本程序采用了中断间隔为5ms。
本次实验采用arduino UNO,所用的4位数码管型号为共阴3641AS,下面是该管的引脚图:
(我图片上传了半个小时也未完成,请各位自行上网查找该管引脚图吧)
为接线方便,依次将3641AS的1到12引脚接到arduino的D2到D13,实际接线图如下:
(我图片上传了半个小时也未完成,各位只要将3641AS的1到12引脚接到arduino UNO的D2到D13这12个IO口即可)
完整程序(该程序经过测试)如下:
#include<MsTimer2.h> //调用定时器T2的库文件
/*
采用时钟中断方式,4位数码管动态显示0—9999程序
优点:可在主循环中任意使用delay 延时函数
端口直接驱动4位共阴数码管,一般情况无需外接限流电阻,
因为端口的输出电流有限,一般不超过20mA,长期使用建议加限流电阻。
*/
int ledCount=8;//8段数码管
int segCount=4;//4位数码管
//long previousMillis = 0;
//定义段码,这里是共阴段码,可以使用数码管段码软件改变数组值或者任意显示形状
const unsigned char dofly_DuanMa[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
//位码
//unsigned char const dofly_WeiMa[]={0,1,2,3};
int ledPins[] = {
12,8,5, 3, 2, 11, 6, 4, }; // 11,7,4,2,1,10,5,3 数码管实际引脚数,和芯片一样,逆时针数
int segPins[] = {
13,10,9,7}; //12,9,8,6 数码管实际引脚数,和芯片一样,逆时针数
unsigned char displayTemp[4];//显示缓冲区,存放段码
void setup() {
// 循环设置,把对应的端口都设置成输出
for (int thisLed = 0; thisLed < ledCount; thisLed++) {
pinMode(ledPins[thisLed], OUTPUT); }
for (int thisSeg = 0; thisSeg < segCount; thisSeg++) {
pinMode(segPins[thisSeg], OUTPUT);
}
MsTimer2::set(5, Timedisp); //定义Timedisp为时钟中断调用的子程序,每5ms触发时钟中断进入一次Timedisp函数
MsTimer2::start(); //时钟中断开始
}
// 数据处理,把需要处理的byte数据写到对应的引脚端口。
void deal(unsigned char value){
for(int i=0;i<8;i++)
digitalWrite(ledPins[i],bitRead(value,i));//使用了bitWrite函数,非常简单
// !bitRead(value,i),这里前面加!(非运算符号),取决于使用的是共阴还是共阳数码管。
}
// 时钟中断调用的显示程序
//每中断一次,显示displayTemp[0]—displayTemp[3]中的一个段码值一次
void Timedisp() {
static int i;
deal(0);// 清除“鬼影”
for(int a=0;a<segCount;a++) //循环写位码,任何时刻只有1位数码管选通,之前全部关闭,然后再选通需要的那位数码管
digitalWrite(segPins[a],1);//关闭全部数码管
digitalWrite(segPins[i],0);//选通对应的数码管
deal(displayTemp[i]);//读取对应的段码值写到对应的数码管
i++;
if(i==segCount) //4位结束后重新循环
i=0;
}
//显示程序,在4位数码中显示num,num小于10000
void disp(unsigned long num) {
num=num%10000;//取模运算,防止num超过9999
displayTemp[0]=dofly_DuanMa[num/1000]; //将num的个位数段码值送到显示缓存displayTemp[0]中
displayTemp[1]=dofly_DuanMa[(num%1000)/100]; //将num的十位数段码值送到显示缓存displayTemp[1]中
displayTemp[2]=dofly_DuanMa[((num%1000)%100)/10]; //将num的百位数段码值送到显示缓存displayTemp[2]中
displayTemp[3]=dofly_DuanMa[((num%1000)%100)%10]; //将num的千位数段码值送到显示缓存displayTemp[3]中
}
// 主循环
void loop() {
static unsigned int num;//定义一个数据
disp(num);
num++;
delay(100); //延时100ms
}