⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 【006】多位数码管动态显示 [51] -- 一步一脚印 -- 编程爱好者blog.htm

📁 本人写的STC单片机EEPROM功能程序
💻 HTM
📖 第 1 页 / 共 5 页
字号:
            color=#0000ff>★</FONT>另外只要把程序中的延时加长,如delayms(250),下载到板上就可以看到实际上数码管是由低位到高位逐位显示的。<BR>
            <HR>
            &nbsp;&nbsp;&nbsp; 
            若单单就实现这个功能而言,可以直接调入段码数组dis_code[11]中下标从0到7的值,而不必再设置缓冲数组dis_buf[],实现如下:<BR><BR>#include 
            &lt;reg51.h&gt;<BR>#include 
            &lt;intrins.h&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            //_crol_()用 
            <P></P>
            <P>void delayms(unsigned char ms); //延时子程序</P>
            <P>unsigned char data dis_digit;&nbsp;&nbsp; //位选通值, 
            传送到P2口用于选通当前数码管的数值,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            //如等于0x01时,选通P2.0口数码管</P>
            <P>unsigned char code 
            dis_code[11]={0x08,0xab,0x12,0x22,0xa1,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            // 
            0,1,2,3,4<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            0x24,0x04,0xaa,0x00,0x20, 0xff}; // 5,6,7,8,9,off </P>
            <P>unsigned char data dis_index;&nbsp; //显示索引, 
            用于标识当前显示的数码管和缓冲区的偏移量</P>
            <P>void main()<BR>{<BR>&nbsp;&nbsp;&nbsp; P0 = 
            0xff;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 
            关闭所有数码管<BR>&nbsp;&nbsp;&nbsp; P2 = 0x00;</P>
            <P>&nbsp;&nbsp;&nbsp; dis_index = 0;&nbsp;&nbsp;&nbsp; // 
            当前偏移量为0<BR>&nbsp;&nbsp;&nbsp; dis_digit = 0x01; // 选通P2.0</P>
            <P>&nbsp;&nbsp;&nbsp; while(1)<BR>&nbsp;&nbsp;&nbsp; 
            {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; P0 = 
            dis_code[dis_index]; // 
            段码送P0口<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; P2 = 
            dis_digit;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            // 位码送P2口<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            delayms(1);</P>
            <P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dis_digit = 
            _crol_(dis_digit, 1); // 位选通左移, 下次选通下一位</P>
            <P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            dis_index++;<BR>&nbsp;<FONT 
            color=#0033ff>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dis_index &amp;= 
            0x07;<BR></FONT>&nbsp;&nbsp;&nbsp; }<BR>}<BR>void delayms(unsigned 
            char ms)&nbsp; // 
            延时子程序(晶振12M)<BR>{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            <BR>&nbsp;&nbsp;&nbsp; unsigned char i;<BR>&nbsp;&nbsp;&nbsp; 
            while(ms--)<BR>&nbsp;&nbsp;&nbsp; 
            {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i = 0; i &lt; 
            120; i++);<BR>&nbsp;&nbsp;&nbsp; }<BR>}</P>
            <P><FONT 
            color=#0000ff>★</FONT>本来是想通过以下方式实现一次循环的:<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            for (dis_index = 0; dis_index &lt; 8; 
            dis_index++)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            P0 = dis_code[dis_index]; // 
            段码送P0口<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            P2 = dis_index+1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 
            位码送P2口<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            delayms(1);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            }<BR><BR>可得到的总是错误的结果:第0位到第2位这三位显示的是三个8,第3位显示的是7,高四位没有显示。加长延时逐位观察也没有发现错误的规律,对Keil的调试也不熟悉,先把问题留到这,待找出原因后再补上。</P>
            <P><FONT color=#0000ff>[2006.5.2] 
            找出原因啦,补上:</FONT><BR><BR>今天又看了一下,找到上面的错误出在哪了。当时是想用dis_index的值做为位码的,即第一位显示0时,段码为dis_code[0], 
            即dis_index值为0, 
            此时位码值为1。第二位显示1时,段码为dis_code[1],即dis_index值为1,此时位码值为2。所以就简单用了个加1运算,将P0口的偏移值与P2口的位码联系起来。但仔细想一下位码的原理,上述方法显然是错的,只要再验证一步就明白了,即当第3位显示2时,段码为dis_code[2], 
            dis_index值为2,加1后为3,按上述方法时就将这个3作为了位码,而正确的位码应该是4 
            (00000100B)。所以出错。实际上这个对应关系是有的,但不是简简单单的加1,位码应该是2的dis_index次幂。即:<BR>0--1<BR>1--2<BR>2--4<BR>3--8<BR>4--16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            ……<BR>幂次运算函数flaot pow(float x, float y)包含在math.h中, 返回值为x<SUP>y 
            </SUP>(float型):&nbsp;<BR><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            for (dis_index = 0; dis_index &lt; 8; 
            dis_index++)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            P0 = dis_code[dis_index]; // 
            段码送P0口<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            P2 = (char) <FONT color=#000711>pow(2, 
            dis_index);</FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            // 
            位码送P2口<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            delayms(255);<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            }<BR><BR>再次下载到板上发现仍有问题, 
            即延时很小的时候显示混乱,但加大延时时间(如程序中的值)可以观查到数码管是按位正确显示的。另外用这种方法产生的代码量也很大(从写入速度看,很明显)。这里仅提出了一个思路,只在此实验中适用,意义不大,到此为止。</P>
            <P><FONT color=#0000ff>[补充结束]</FONT></P>
            <P>
            <HR>

            <P></P>
            <P><A href="http://blog.programfan.com/article.asp?id=11866" 
            target=_blank><FONT 
            color=#0099ff>AS</FONT></A>中绐出的例程是利用定时中断做的延时,参考修改到我的板上,程序如下:<BR><BR>#include 
            &lt;reg51.h&gt;<BR>#include 
            &lt;intrins.h&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            // 包含了左移函数_crol_()</P>
            <P>unsigned char data dis_digit;&nbsp;&nbsp; // 位选通值, 
            传送到P2口用于选通当前数码管的数值,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            // 如等于0x01时,选通P2.0口数码管</P>
            <P>unsigned char code 
            dis_code[11]={0x08,0xab,0x12,0x22,0xa1,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            // 
            0,1,2,3,4<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            0x24,0x04,0xaa,0x00,0x20, 0xff}; // 5,6,7,8,9,off </P>
            <P>unsigned char data dis_buf[8];&nbsp; // dis_buf 显于缓冲区基地址</P>
            <P>unsigned char data dis_index;&nbsp;&nbsp; // 显示索引, 
            用于标识当前显示的数码管和缓冲区的偏移量</P>
            <P>void main()<BR>{<BR>&nbsp;&nbsp;&nbsp; P0 = 
            0xff;&nbsp;&nbsp;&nbsp; //关闭所有数码管<BR>&nbsp;&nbsp;&nbsp; P2 = 
            0x00;</P>
            <P>&nbsp;&nbsp;&nbsp; TMOD = 0x01;&nbsp; // 00000001B 
            定时计数器0工作在方式1,16位定时器/计数器<BR>&nbsp;&nbsp;&nbsp; TH0 = 
            0xFC;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; TL0 = 
            0x17;&nbsp;&nbsp; // 预置初值 FC17H=64535D, 
            2<SUP>16</SUP>-64535=1001us=1ms</P>
            <P>&nbsp;&nbsp;&nbsp; IE = 0x82;&nbsp;&nbsp;&nbsp; // 10000010B 
            T0溢出中断允许</P>
            <P>&nbsp;&nbsp;&nbsp; dis_buf[0] = 
            dis_code[0x0];<BR>&nbsp;&nbsp;&nbsp; dis_buf[1] = 
            dis_code[0x1];<BR>&nbsp;&nbsp;&nbsp; dis_buf[2] = 
            dis_code[0x2];<BR>&nbsp;&nbsp;&nbsp; dis_buf[3] = 
            dis_code[0x3];<BR>&nbsp;&nbsp;&nbsp; dis_buf[4] = 
            dis_code[0x4];<BR>&nbsp;&nbsp;&nbsp; dis_buf[5] = 
            dis_code[0x5];<BR>&nbsp;&nbsp;&nbsp; dis_buf[6] = 
            dis_code[0x6];<BR>&nbsp;&nbsp;&nbsp; dis_buf[7] = 
            dis_code[0x7];<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 
            dis_digit = 0x01;&nbsp;&nbsp; // 选通第0位数码管<BR>&nbsp;&nbsp;&nbsp; 
            dis_index = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 
            偏移初值为0<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; TR0 = 
            1;&nbsp;&nbsp;&nbsp; // 启动T0<BR>&nbsp;&nbsp;&nbsp; 
            while(1);&nbsp;&nbsp; // 循环等待中断</P>
            <P>}</P>
            <P>void timer0() interrupt 1&nbsp; // 定时器0中断服务程序, 用于数码管的动态扫描</P>
            <P>{<BR>&nbsp;&nbsp;&nbsp; TH0 = 
            0xFC;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            // 发生中断定时/计数器重装初值<BR><FONT color=#0000ff>&nbsp;&nbsp;&nbsp; TL0 = 
            0x17;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            // 
            感觉此处(及上)应该是0x18,而不是17,分析如下</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp; 
            P2 = 
            0x00;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            // 先关闭所有数码管<BR>&nbsp;&nbsp;&nbsp; P0 = 
            dis_buf[dis_index];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            // 段码送P0口<BR>&nbsp;&nbsp;&nbsp; P2 = 
            dis_digit;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            // 位码送P2口</P>
            <P>&nbsp;&nbsp;&nbsp; dis_digit = _crol_(dis_digit,1);&nbsp; // 
            位选通值左移, 下次中断时选通下一位数码管<BR>&nbsp;&nbsp;&nbsp; 
            dis_index++;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
            <BR>&nbsp;&nbsp;&nbsp; dis_index &amp;= 
            0x07;&nbsp;&nbsp;&nbsp;&nbsp; // 
            8个数码管全部扫描完一遍之后,再回到第一个开始下一次扫描<BR>}<BR><BR><FONT 
            color=#0000ff>★</FONT>定时器/计数器的输入脉冲周期与机器周期一样, 
            为时钟振荡频率的1/12。晶振用12M时,输入脉冲周期间隔为1us。机器周期为 
            1us。设T0的初值为X,计算初值的方法:本例中定时器用方式1,是16位的定时器,即最大值为2<SUP>16</SUP>=65536,超过此值将发生溢出,引起中断,进入中断处理程序。这里要让其延时1ms,即1000us, 
            则有式2<SUP>16</SUP>-X=1000,可得X=64536,换算为16进制为FC18,即初值TH0=0xFC,TL0=0x18。即定时器由64536开始计数,经1000次计数后值为65536,将发生定时中断,再进入中断处理子程序后,重新装和初值,如此循环下去。<BR>&nbsp;&nbsp;&nbsp; 
            而在上例中其装入的初值并非FC18(64536),而是FC17(64535)。我想大概认为其计数范围在0~65565的原因吧,我也想过这个问题,是用<FONT 
            color=#ff3300>2<SUP>16</SUP>-计数初值=中断间隔</FONT>&nbsp;呢,还是用<FONT 
            color=#0000ff>(2<SUP>16</SUP>-1)-计数初值=中断间隔</FONT>呢? 随手查了几本书, 
            说法不一,不过用前者的较多, 我自己也认为前者比较合理, 因为在计算机中16位的二进制不能表示65536, 
            在各位均为1时表示的值为65535, 即65535H=1111111111111111B, 
            也可以说65536是溢出得到的。而何时响应中断就成了关键,拿上例来说,如设初值为64535(FC17),则计数到65535时,已经计数为1000个,即1ms,但此时并未发生溢出,因此也没有触发中断。而是在下一个计数后才发生。确切值应为1001us。若初值为64536(FC18),则恰好为所需值,所以上例中的初值应该用FC18而不是FC17。这仅仅是我自己的一点看法,至于是不是这样,还有待进一步考证。<BR>
            <HR>
            最终下载到实验板上结果:<FONT color=#000000><BR>
            <P align=center><IMG 
            src="【006】多位数码管动态显示&nbsp;[51] -- 一步一脚印 -- 编程爱好者BLOG.files/fb51a_8_01_on.gif"></P><FONT 
            color=#0000ff>★</FONT>该电路段码是按与板上接法对应的,即按前面的段码表次序连接。另外这个八位的仿真数码管最左端是第一位,最右端是第八位,与板上的顺序相反,所以接为了统一,该图以板为准连接。上图不加上拉电阻也可仿真出结果,只是P0口高电平显示为灰,即高阻。</FONT></DIV>
            <P align=center><BR><STRONG><A name=trackback></A>引用地址:<A 
            href="http://blog.programfan.com/trackback.asp?id=12535">http://blog.programfan.com/trackback.asp?id=12535</A></STRONG></P>&nbsp;</DIV>
            <DIV>
            <TABLE 
            style="BORDER-RIGHT: #ff9900 1px solid; PADDING-RIGHT: 1px; BORDER-TOP: #ff9900 1px solid; PADDING-LEFT: 1px; PADDING-BOTTOM: 1px; BORDER-LEFT: #ff9900 1px solid; PADDING-TOP: 1px; BORDER-BOTTOM: #ff9900 1px solid" 
            cellSpacing=0 cellPadding=0 width="95%" align=center border=0>
              <TBODY>
              <TR>
                <TD align=middle bgColor=#ff9900><STRONG><A 
                  name=comment>文章评论</A></STRONG></TD></TR>
              <TR>
                <TD><BR>
                  <TABLE cellSpacing=0 cellPadding=0 width="95%" align=center 
                  border=0>
                    <TBODY>
                    <TR>
                      <TD width="91%" bgColor=#dff0ff height=20>
                        <LI>评论人:<A 
                        href="mailto:wiyhrftgw@wogh.com">mackenzie</A>&nbsp;&nbsp;&nbsp;时间:2007-9-22 
                        23:34:00</LI></TD>
                      <TD width="9%" bgColor=#dff0ff></TD></TR>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -