赞
踩
本次编程实验以IAP15F2K61S2为单片机主控芯片,其编程使用与STC15F2K60S2完全相同,头文件为STC15F2K60S2.H
。若用于51系列单片机,以reg52.h
为头文件,则需将后文中timer0.c中void Timer0_Init(void)
函数中的AUXR &= 0x7F;
一行删除(后文有提示)。程序中涉及的定时器初始化程序和LED亮灭程序和数码管显示程序,读者可根据自身所用单片机原理图和手册自行修改。
在对主程序执行效率要求低、项目工程复杂度低的情况下,通常我们对数码管位选、段选后用delay延时函数进行延时,利用人眼视觉暂留效应实现8位数码管的静态、动态显示。但数码管延时时间,以2ms为例,相比机器周期微秒级别还是太长。为了提高主程序执行效率,故使用定时器扫描数码管的方式。
定时器定时1ms,每隔2ms刷新1位数码管的显示,从而代替了delay延时函数。
#include <STC15F2K60S2.H> typedef unsigned char u8; #define outputp0(y,x) P0=x,P2&=0x1f,P2|=y,P2&=0x1f; //P2高三位用于74HC138译码器选择锁存器,P0由于发送数据 int shownum=123; //数码管显示数值 unsigned char Seg_sy[]={10,10,10,10,10,10,10,10}; //数码管段选索引数组,上电默认数码管全灭 unsigned char code Seg_Table[]={ 0xc0, //共阳数码管 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0xff //8段全灭 }; void Timer0_Init(void) //1毫秒@11.0592MHz { AUXR &= 0x7F; //定时器时钟12T模式,若以reg52.h为头文件时删除这行代码 TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //设置定时器模式 TL0 = 0x66; //设置定时初始值 TH0 = 0xFC; //设置定时初始值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 ET0 = 1; //使能定时器0中断 EA=1; //使能总中断 } /* * @brief 数码管显示函数 * @param pos:位选;dat:显示数字;dot:小数点选择位,1有0无 * @reval * @note: */ void showbit(unsigned char pos,dat,dot) //数码管显示函数 { outputp0(0xc0,0x01<<pos); //位选 outputp0(0xe0,Seg_Table[10]); //段选,这两行用于消影 outputp0(0xc0,0x01<<pos); //位选 outputp0(0xe0,Seg_Table[dat]+0x80*dot); //段选 } /* * @brief 8位数码管显示函数 * @param * @reval * @note: */ void showloop() { static unsigned char sy=0; //sy用于选择位选和位选对应的段选索引 showbit(sy,Seg_sy[sy],0); //刷新1位数码管 sy++; //每执行一次,sy加一,从而下次执行时刷新下一位数码管 sy%=8; //8位数码管,因此sy不超过8 } void main() { Timer0_Init(); Seg_sy[0]=shownum/100; //赋初值 Seg_sy[1]=shownum/10%10; Seg_sy[2]=shownum%10; while(1) { } } void Timer0_Isr(void) interrupt 1 { static u8 tsmg=0; //用于数码管扫描时间计数 TL0 = 0x66; //设置定时初始值 TH0 = 0xFC; //设置定时初始值 tsmg++; if(tsmg>=2) //每2ms扫描一次数码管 { tsmg=0; //清零 showloop(); //刷新数码管 } }
编译下载程序后,数码管正常显示123。
有时候我们希望数码管显示像滚动屏一样,数据能够从左向右或从右向左进入然后从另一端消失。以显示"HELLO",从右向左,每1s滚动一次为例,首先写出对应的段码表,将上文代码中的unsigned char code Seg_Table[]
修改为如下值:
unsigned char code Seg_Table[]={ //数码管段选数组
0x89, //H
0x86, //E
0xc7, //L
0xc7, //L
0xc0, //O
0xff //0xff,用于熄灭1位数码管
};
为了实现滚动显示,数码管段选索引数组应该每1秒向左移动一次。当”HELLO“全部移出数码管后,此时数码管应该全灭,下一秒再将”H“移入数码管,从而在数码管段选数组中需要8个连续0xff用于全灭8位数码管,即在数码管段选索引数组中有8个连续5。将上文代码中的unsigned char Seg_sy[]
修改为如下值:
unsigned char Seg_sy[]={5,5,5,5,5,5,5,5,0,1,2,3,4};
完整代码如下:
#include <STC15F2K60S2.H> typedef unsigned char u8; #define outputp0(y,x) P0=x,P2&=0x1f,P2|=y,P2&=0x1f; //P2高三位用于74HC138译码器选择锁存器,P0由于发送数据 unsigned char Seg_sy[]={5,5,5,5,5,5,5,5,0,1,2,3,4}; //数码管段选索引数组 unsigned char code Seg_Table[]={ //数码管段选数组 0x89, //H 0x86, //E 0xc7, //L 0xc7, //L 0xc0, //O 0xff //0xff,用于熄灭1位数码管 }; void Timer0_Init(void) //1毫秒@11.0592MHz { AUXR &= 0x7F; //定时器时钟12T模式,若以reg52.h为头文件时删除这行代码 TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //设置定时器模式 TL0 = 0x66; //设置定时初始值 TH0 = 0xFC; //设置定时初始值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 ET0 = 1; //使能定时器0中断 EA=1; //使能总中断 } /* * @brief 数码管显示函数 * @param pos:位选;dat:显示数字;dot:小数点选择位,1有0无 * @reval * @note: */ void showbit(unsigned char pos,dat,dot) //数码管显示函数 { outputp0(0xc0,0x01<<pos); //位选 outputp0(0xe0,Seg_Table[10]); //段选,这两行用于消影 outputp0(0xc0,0x01<<pos); //位选 outputp0(0xe0,Seg_Table[dat]+0x80*dot); //段选 } /* * @brief 8位数码管显示函数 * @param * @reval * @note: */ void showloop() { static unsigned char sy=0; //sy用于选择位选和位选对应的段选索引 showbit(sy,Seg_sy[sy],0); //刷新1位数码管 sy++; //每执行一次,sy加一,从而下次执行时刷新下一位数码管 sy%=8; //8位数码管,因此sy不超过8 } void dongtaishaomiao() { u8 i=0,temp=0; temp=Seg_sy[0]; //temp用于保存数码管段选索引数组第0位 for(i=0;i<sizeof(Seg_sy)-1;i++) Seg_sy[i]=Seg_sy[i+1]; //数码管段选索引数组循环向左移动,每次移动一位 Seg_sy[sizeof(Seg_sy)-1]=temp; //数码管段选索引数组第0位向左移动一位后变成第12位 } void main() { outputp0(0x80,0xff); outputp0(0xa0,0x00); Timer0_Init(); while(1) { } } void Timer0_Isr(void) interrupt 1 { static u8 tsmg=0; //用于数码管扫描时间计数 static int dtaismg=0; TL0 = 0x66; //设置定时初始值 TH0 = 0xFC; //设置定时初始值 tsmg++; if(tsmg>=2) //每2ms扫描一次数码管 { tsmg=0; //清零 showloop(); //刷新数码管 } dtaismg++; if(dtaismg>=1000) //每1秒 { dtaismg=0; dongtaishaomiao(); //将数码管段选索引数组循环向左移动,每次移动一位 } }
编译下载程序,数码管滚动显示"HELLO"。
通过上述程序,可以实现定时器扫描数码管(含滚动显示)以提高主程序执行效率。通过类比,也可以实现定时器扫描独立按键和矩阵按键,详情见定时器扫描按键(短按/长按)和定时器扫描矩阵键盘简易代码(短按/长按)
此外,由于定时器每1ms进入一次中断,对于具有IIC和One-Wire通信等具有严格时序要求的项目来说,容易使通信被干扰,因此不建议使用定时器扫描的方式。当然,通过一些方法也可以实现二者兼容并存,在DS1302可调时钟(按键短按/长按)中提供了其中一种方法。
有任何问题和补充,欢迎评论区交流。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。