arduino用时钟中断方式的4位数码管动态显示

    一般我们在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

}

猜你喜欢

转载自blog.csdn.net/m0_61543203/article/details/126129038