矿石收音机论坛

 找回密码
 加入会员

QQ登录

只需一步,快速开始

搜索
楼主: wey05

帮助新手学习单片机数码管电子钟:原理,c程序详解

  [复制链接]
发表于 2011-4-28 06:07:40 | 显示全部楼层
P2=0X01 ;// 最右端:秒个位亮
P2=0X02;//秒十位亮,个位灭
P2=0X04,;//分个位亮,秒十位灭,如果要点8个管,就要写8个语句,太累了!
也可以这样
unsigned char a=0x01;//
P2=a;                              //P2点亮秒个位
a=a<<1;
P2=a;                             //P2点亮秒十位,以后我们会通过循环操作就不要写8个句子了。


i will give you a simpler solution

#define OUT_PORT P2 //output on p2

OUT_PORT <= 1; //left shift OUT_PORT by 1


the advantage here is that if you were to change the output from P2 to P3, all you need is to redefine OUT_PORT to be P3 and the code will work.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-4-28 11:21:06 | 显示全部楼层
原帖由 millwood 于 2011-4-28 06:07 发表


i will give you a simpler solution



the advantage here is that if you were to change the output from P2 to P3, all you need is to redefine OUT_PORT to be P3 and the code will work.

这个我知道,现在只是针对初学者举个例子,并不是正式代码,因为现在还没有说到宏定义#define请勿打断,谢谢!

[ 本帖最后由 wey05 于 2011-4-28 11:29 编辑 ]
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-4-28 23:00:22 | 显示全部楼层

再说一点

或许会说,干嘛这么麻烦非要用变量a给P2赋值,直接就
P2=0X01;
P2=P2<<1;
不行吗?虽然说这样做KEIL编译器也能通过,但实际上却达不到运行效果,LED不会点亮,对于P2(其他口也一样)可以进行位运算符操作:但是移位除外。这点要注意。
还有,你不是说变量要先声明后使用吗?那51单片机P2这样的口,以及它的一些特殊功能寄存器例如定时器的TMOD、TCON等在哪里声明呢?实际上也需要声明的,大家在看51C程序的第一行:
#include  "REG51.h"
这一行的意思就是以下程序包含了REG51.h这个文件(头文件)在这个文件里面对51单片机的包括P0P1P2P3在内的所有特殊功能寄存器都进行了形如
sfr P0 = 0X80;
的定义,所以只要在程序顶端加这一个包含语句,在以下整个程序里就直接使用他们而不需要再加以声明-定义。要注意包含什么文件和具体所用的单片机有关。如果是AT89C51、AT89S51等,用上述REG51.h就可以,也可以用另一个AT89X51.h这个更是连同P口的位都加以定义了,在程序里可以直接使用如同P1_0  、P2_1这样的位线表示。
但是如果使用的是52单片机,仅仅用REG51..h 在用到定时器T/C2时就不行了,因为51中没有这个定时器当然也没有定义它。REG52.h则对他进行了定义。对于本制作使用的STC单片机和AT的还是有些差别,它有T2MOD,AT没有,如果简单点就用REG52.h也行,只是在程序里加一个对它的定义:sfr T2MOD =  0XC9;要完整的话就要包含STC提供的头文件STC89C51RC_RD_PLUS.h了。
回复 支持 反对

使用道具 举报

发表于 2011-4-28 23:44:44 | 显示全部楼层
或许会说,干嘛这么麻烦非要用变量a给P2赋值,直接就
P2=0X01;
P2=P2<<1;
不行吗?虽然说这样做KEIL编译器也能通过,但实际上却达不到运行效果,LED不会点亮,对于P2(其他口也一样)可以进行位运算符操作:但是移位除外。这点要注意。


maybe because you didn't do it right?

here is the execution of the following code:

#include <regx51.h>

int main(void) {
        P2 = 1;
        while (1) {
                P2 = P2 << 1;
        }
}


notice the changes in the pins on P2?

[ 本帖最后由 millwood 于 2011-4-29 01:06 编辑 ]
42. led on p2.PNG
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-4-29 11:31:25 | 显示全部楼层
你仿真是可以没错,我现在用的是keil硬件做出来的,最好你自己也去做一下,看看究竟行不行,P口不能进行移位操作不是我发明的,书上也是这么说的。仿真和实际还是有差距。你去用硬件做一个电路做一个再说吧

[ 本帖最后由 wey05 于 2011-4-29 11:32 编辑 ]
回复 支持 反对

使用道具 举报

     
发表于 2011-4-29 12:49:48 | 显示全部楼层

回复 57# wey05 的帖子

如果 89s52出不来,只能说明它没能力,哈哈
我这就有硬件,可以回来try下,而且还有本书 ,开头讲流水灯里面有这个,我也回来看下
回复 支持 反对

使用道具 举报

     
发表于 2011-4-29 13:05:02 | 显示全部楼层
简单啊!看看C语句编译成汇编是什么样子的就知道了

这段代码:
#include <regx51.h>

int main(void) {
        P2 = 1;
        while (1) {
                P2 = P2 << 1;
        }
}

对应的汇编是:
ROLS.PNG
回复 支持 反对

使用道具 举报

     
发表于 2011-4-29 21:40:56 | 显示全部楼层

回复 60# Paktu 的帖子

这个办法好,程序运行过程是
1+1=2->2
2+2 =4 ->2
4+4=8-> P2
8+8->2
........
128+128->2(溢出!0x100)
所以如果把P2每个IO口都接上LED灯+限流电阻 再接5V电源,一上电,会有一次很迅速的灯逐个灭-》亮(从P2低位到高位),最后是所有的LED灯全亮, 结束!



----------------------------------------------------------------------------
如果汇编是这个结果 是否说明硬件也亦是如此?
回复 支持 反对

使用道具 举报

发表于 2011-4-29 22:36:27 | 显示全部楼层
原帖由 wey05 于 2011-4-29 11:31 发表
我现在用的是keil硬件做出来的,


did you use "P2 <<=1;' and it didn't work on your hardware or you used "var <<= 1; P2=var;" and it did work?

P口不能进行移位操作不是我发明的,书上也是这么说的。


many false things are said in many books too. that doesn't make them true.
回复 支持 反对

使用道具 举报

发表于 2011-4-29 22:48:51 | 显示全部楼层
我这就有硬件,可以回来try下,而且还有本书 ,开头讲流水灯里面有这个,我也回来看下


you will find cases where such an approach ("P2 = P2 << 1;") may fail. what 8051 vendors licensed from Intel is the core and they have to design their own peripherals (like IO ports). on some 8051 chips, you do not have output latches on the IO ports. so when you turn to read that pin / port, you are actually reading the voltage on that port / pin and the load on that pin / port will force a "0' read on that port / pin. that's where this approach will fail.

most chips today have otuput latches.

a more interesting approach on a shadow variable is to use a sequence:

#define SEQ1(val) (((val) << 1) | ((val) & 0x80)?1:0)
#define SEQ2(val) (((val) << 1) | ((val) & 0x80)?0:1)

...
  while (1) {
    s=SEQ1(s); //get a new pattern (seq1)
    OUT_PORT = s; //output the new pattern
  }
...


try to use SEQ1() and SEQ2() and see how the leds behave.
回复 支持 反对

使用道具 举报

     
发表于 2011-4-29 23:08:12 | 显示全部楼层

回复 63# millwood 的帖子

millwood兄 目前我在用 Atmel  89s52这个片子,它是由I/O寄存器的,avr mega8 mega16也是有的,
呵呵本楼的发言我基本看懂了,硬件我还是会try的
回复 支持 反对

使用道具 举报

     
发表于 2011-4-29 23:09:38 | 显示全部楼层
--------------------占楼贴-----------------------------------------
去睡了 最近累坏了,最近单片机编程遇到不少问题,回来发贴单说
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-4-30 15:27:52 | 显示全部楼层
原帖由 millwood 于 2011-4-29 22:36 发表


did you use "P2  

哈哈英文老兄又来了,看好了,我,说,
unsigned char ve=0x80;
P2=ve;
ve>>=1;
P2=ve;
当然没问题!只是
P2=0X80;
P2>>=1;
keil编译没问题,可以通过,实际运行不行,我的硬件有问题吗见本帖开始的图,书说的不对?编书的不至于糊涂至此吧。还是请你深入分析一下问题在什么地方

[ 本帖最后由 wey05 于 2011-4-30 16:03 编辑 ]
回复 支持 反对

使用道具 举报

 楼主| 发表于 2011-4-30 15:54:36 | 显示全部楼层
原帖由 xiaomu 于 2011-4-29 21:40 发表
这个办法好,程序运行过程是
1+1=2->P2
2+2 =4 ->P2
4+4=8-> P2
8+8->P2
........
128+128->P2(溢出!0x100)
所以如果把P2每个IO口都接上LED灯+限流电阻 再接5V电源,一上电,会有一次很迅速的灯逐个灭-》亮( ...

实际上KEIL也可有不同的汇编,用的是RRC A
......
P2.jpg

[ 本帖最后由 wey05 于 2011-4-30 16:04 编辑 ]
回复 支持 反对

使用道具 举报

     
发表于 2011-4-30 22:07:55 | 显示全部楼层
在89s52 ISR里不清TF2,我try过了,在 ISR 里 把一个I/O口管脚拉高拉低,来观察输出方波的频率,
如果不清 也有方波输出,但频率比 设定的频率高2倍多一些,比如你设定频率是2KHz,输出频率大约为4.3KHz
如果在ISR里 清TF2,输出频率很准确在2.00x范围(用数字示波器看的),
中断0和中断1里面 采用模式1,也是在 ISR 里 把一个I/O口管脚拉高拉低来观察,输出频率和设定值偏离较大,
比如你设定10KHz,输出大约为7.8KHz,不如定时器2 采用16位自动加载模式的方法准确!

原帖由 wey05 于 2011-4-24 21:52 发表

TF2必须由中断响应程序清除,这个非常非常重要,如果你不清除,那么它继续计数,预置值已经不起作用。你不管设置什么预置值,他都以一个没有明显变化的定时工作。我做过这个试验。输出方波最大50千赫?没有试过
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入会员

本版积分规则

小黑屋|手机版|矿石收音机 ( 蒙ICP备05000029号-1 )

蒙公网安备 15040402000005号

GMT+8, 2025-4-27 21:48

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表