51单片机交通灯答辩问题问题

Powered by0}{else}no-cache{/if}" />
51单片机应用中5个常见问题总结
本文就51单片机应用中一些常见问题作个总结,这都是我实际碰到过的,因为文章篇幅所限,这些问题远远不足以表达单片机的常见问题。希望对初学者有所帮助,文中不完善的地方务请指点。谢谢!
1:C51编译器如何区分位地址和字节地址
是靠预定义实现的,比如:sfr P0 = 0x80; sbit P0_0 = 0x80;前者声明了P0端口地址位于0x80,后者说明了P0端口的bit0,即P0.0位于位地址空间0x80处。这2个0x80具有完全不同的含义,靠关键字sfr和sbit来区别。这样当程序被编译时,编译器会依此编译成相应的汇编语言。例如:
C51语句: P0 = 1;
P0声明为sfr,因此编译成:mov 80h,01h,将把0x01数据送入0x80单元,由于0x80单元物理上对应P0端口,因此,P0.0脚将输出高电平(其实是呈现高阻态,P0口独有的),其他.1-.7脚输出低电平。
C51语句: P0_0 = 1;
P0_0声明为sbit,因此编译成:setb 80h,这将把位地址空间的0x80地址的bit的值置1。这个位正是P0口的bit0,执行后,P0.0将输出高阻态。而P0.1-.7不会变化。
2:C51为什么要嵌套汇编
51单片机一个显著优点就是指令执行时间固定,因此可以适应时序要求严格的场合。例如符合ISO7816协议的cpu卡的读写,对时序要求比较严格。其实就是用io脚做出来的同步半双工串口。支持cpu卡的程序一般比较庞大,需要用c51来组织,但是由于c编译的不确定性,必须把底层程序封装成汇编语言模块嵌入到工程中。这就带来几个问题:如何声明函数、参数如何传递等。限于篇幅,不能说得很细。下面举例:
汇编程序单独保存一个文件,加入到工程中,函数如下:
用c语言在.h文件中声明: extern unsigned char proc_a(unsigned char val);
调用时形如: retvalue = proc_a(0x11);
a:汇编程序如果带参数,则需要在汇编程序前多加一个下划线。而声明它的地方不用加(伟福编译器这么要求的)。
b:函数的形参中第一参数用R7传递,函数返回值用R7返回,这是C51的通用规范。其他参数都有相应规定。函数可以返回一个位,用psw的c位返回。c:上面的语句,执行顺序是把0x11给R7,然后跳转子程序,子程序将它加1后送回。
d:函数跳转到汇编程序时,本区的R0-R7,A,B,PSW,DPTR等寄存器可以供子程序使用,不必考虑调用后是否要恢复这些常规资源。上例中,A的值被函数使用了,编程者不必恢复调用前的值。
3:51单片机的P0口特殊之处
许多新手都碰到这个问题,其实很简单,这涉及到芯片的io脚是怎么做出来的。这对硬件工程师来说十分重要。TTL的io脚模型:
P1,P2,P3口都可以理解成左图,注意vcc下面有个电阻,因此可以理解成:引脚输出1的能力弱。地那边没有电阻,可以理解成引脚吸入电流能力强。而P0口,可以理解成右图。这就是集电极开路输出,也叫OC输出。可以看出,当CTR=1时,三极管导通,引脚被接地;当ctr=0时,三极管截止,引脚浮空,也叫三态。这个端口这么做的目的是考虑P0口肩负读写数据和地址复用,这个关系要仔细看懂cpu时序图。因此,P0口要加合适的上拉电阻,绝不要加下拉电阻。上拉电阻的选择要看外部负载情况。
4:P1-3口如何输入输出
从上节的左图可以看出。做输出时,ctr=1则输出强信号0,ctr=0则输出弱信号1。当io脚做输入时,应使ctr=0,这样三极管截止。外部信号如果是1,则上拉电阻加强了这个1,单片机就会读到1。当外部信号为0时,注意,必须将上拉电阻的上拉作用全部抵消,才能在引脚上得到0。
因此,对于程序来说,把io脚置1就处于接收状态,当然也是输出1状态。程序置io口为1,读取的信号是不是1就依靠外部电路了,如果外部电路没有&吃掉&上拉电阻的电流,则读取得到1,反之,虽然程序置io脚为1,但是读取得到的就是0。
因此,如果用io脚的高电平驱动外部电路时,要小心外部电路把这个1&吃掉&从而输出不了1。而作为输入时,为0电平的外设必须足够有能力将io脚拉低。所以,用io脚直接点亮led的时候,最好用反逻辑,就是输出0,让led亮。这样能保证驱动能力。就是io脚接led的负端,led的正端过电阻接vcc。
因此,io脚输出1时,外部电路将它强行接地是没有关系的,而io脚输出0的时候,外部电路强行接电源就会把io脚损坏。所以,程序加电之后,一般把所有io口都写成1:MOV P0,0FFH。
P3口引脚复用,必须引脚都处于输出1状态。例如,把RXD脚输出0,则它什么数据都读不进来了,笔者早期曾调试一整天才发现串口收不到数据是没有把RXD置1的原因,把时间都浪费在外围了,当时很是汗颜。
5:有关晶振
单片机的晶振在内部可以简化成一个反向器。当晶振输入脚XI刚过坎压、被认为是1的一瞬间,输出脚XO就输出0,这个0会带动晶振使XI电压下降,当降低到坎压被认为是0的一瞬间,输出脚XO就输出1。这样周而复始。
因此,用示波器观察正常工作的晶振输入脚XI时,得到的是一个不高不低的近似水平线。而XO则是幅值很大的正弦波。测量晶振输入脚XI时,示波器表笔要打在X10档上,否则,表笔就能把晶振弄停。
因此布线时,晶振输入脚XI要尽量靠近晶振,而XO脚可稍远。同时XO具有一定的驱动能力,某些芯片可以用它驱动其它时序电路(不推荐这么做,因为系统可靠性下降)。
写到这里,才发觉51单片机的问题太多了,这篇文字简直就是沧海一粟。
文章来源专栏
加载更多评论
后参与评论51单片机和61单片机的c语言程序是一样的通用的吗?
单片机程序分为两个部分,底层驱动,上层逻辑;
既然是C语言写的,上层逻辑部分99%是可以移植的。
底层驱动部分是随着单片机的不同而不同的,所以这部分基本上是要修改的,比如说同样是设置串口波特率,可能随着单片机的不同,寄存器就不同,再或者,即使同一内核的单片机,也有可能虽然寄存器名字相同,但是实际地址不同,也需要改变。
其他答案(共1个回答)
程序分为两个部分,底层驱动,上层逻辑;
既然是C语言写的,上层逻辑部分99%是可以移植的。
底层驱动部分是随着单片机的不同而不同的,所以这部分基本上是要修改的,比如说同样是设置串口波特率,可能随着单片机的不同,寄存器就不同,再或者,即使同一内核的单片机,也有可能虽然寄存器名字相同,但是实际地址不同,也需要改变。
基本型有五个(所有51系列的一定有这5个),不同厂家会有一些增强版的会超过五个中断,是在基本型上进行增加,不会取消基本型的5个。
8051单片机提供5个中断请求...
在51单片机的输出口中,P3口的输出电流最大,也只有800μA左右,也就是说51单片机的输出电流是微安级的而不是毫安级的,要输出毫安级电流应该加驱动器。
这是一种聪明的解决办法,对于一些不提供基准输入引脚,只能以电源电压为基准的CPU。该方法消除了电源电压带来的误差。
具体是在多路AD的某一路连接一个高精度电压基...
51单片机采用的是哈佛结构,即数据和程序分开,这样可以提高程序的执行速度,如果是MOV 21H
#35H这样的指令,#35H是作为一个立即数,是要和指令放在一...
让孩子们能更好的在欢快中学习,过一个充满童趣的节日。活动包括诗歌表演,续编故事,环保“有用的纸盒” 制作比赛,才艺比赛,智力抢答,游园等等。充满童趣的节日,为了...
答: 一倍速度的150KB/S,那么其他的数字大家就会都明白了.其速度是指读取,和刻录--有刻录功能的情况下.
答: 综上,当一个交换机上的所有端口中有至少一个端口属于不同网段的时候,当路由器的一个物理端口要连接2个或者以上的网段的时候,就是VLAN发挥作用的时候,这就是VLA...
答: 笔记本才有的
在网上邻居
win7在 网络里面
或是电脑的右下角
大家还关注
Copyright &
Corporation, All Rights Reserved
确定举报此问题
举报原因(必选):
广告或垃圾信息
激进时政或意识形态话题
不雅词句或人身攻击
侵犯他人隐私
其它违法和不良信息
报告,这不是个问题
报告原因(必选):
这不是个问题
这个问题分类似乎错了
这个不是我熟悉的地区
相关问答:123456789101112131415查看: 9333|回复: 1
关于51单片机AD转换的问题
使用单片机自带的AD转换功能将模拟量转换为数字量,并以float输发送给串口调试助手,但是发现通过调试助手得到的电压值与实际测得的电压值不同,小弟C语言能力一般,请大神们帮助看看程序应该怎门改。附上程序和部分原理图。。。。。
#include &reg51.h&
#include &intrins.h&
#define FOSC L
#define BAUD 9600
#define V_SCALE (4.89f/1024)
typedef unsigned char BYTE;
typedef unsigned int WORD;
union float2int{
BYTE num[4];
/*声明与ADC有关的SFR*/
sfr AUXR = 0x8e;
sfr ADC_CONTR = 0xC5;//ADC控制寄存器
sfr ADC_DATA = 0xC6;//DC高8为结果寄存器
sfr ADC_LOW2 = 0xBE;//ADC结果寄存器低2位有效
sfr P1M0 = 0x91;//P1口模式控制寄存器0
sfr P1M1 = 0x92;//P1口模式控制寄存器1
/*定义ADC_CONTR中ADC操作常量*/
#define ADC_POWER 0x80 //ADC电源控制位
#define ADC_FLAG 0x10 //ADC完成标志
#define ADC_START 0x08 //ADC开始控制位
#define ADC_SPEEDLL 0x00 //1080
#define ADC_SPEEDL 0x20 //810
#define ADC_SPEEDH 0x40 //540
#define ADC_SPEEDHH 0x60 //270 clocks
void InitUart();
void SendData(BYTE dat);
void Delay(WORD n);
void InitADC();
void SendHello(BYTE dat);
void ADC_DataProcess(void);
//ADC channel NO.
BYTE ch = 2;
void main()
InitUart();
InitADC();
AUXR |= 0x10;//set EADCI
IE = 0xa0;//开中断
//SendHello('H');
* ADC interrupt service routine
void adc_isr() interrupt 5 using 1
ADC_CONTR &= !ADC_FLAG;//清ADC中断标志位
// SendData(ADC_DATA);
// SendData(ADC_LOW2);
// SendData('\n');
ADC_DataProcess();
// if((++ch) & 7)
// ch = 0;
// SendData('\n');
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START |
void ADC_DataProcess(void)
unsigned int t2;
temp = ADC_DATA;
t2 = ADC_LOW2;
temp = temp&&2;
temp = temp + t2;
t = temp * 478;//V_SCALE;
// SendData(data_send.num[3]);
// SendData(data_send.num[2]);
// SendData(data_send.num[1]);
// SendData(data_send.num[0]);
//f = f*1000.0;
SendData((t/100000) + '0');
SendData('.');
SendData((t/10000)%10 + '0');
SendData((t/1000)%10 + '0');
SendData(t%10 + '0');
SendData('\n');
* Initial ADC sfr
void InitADC()
P1 = P1M0 = P1M1 |= 0//把P1设为开漏
ADC_DATA = 0;
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ADC_START |
* Initial UART
void InitUart()
//PCON &= 0x7F; //波特率不倍速
SCON = 0x52; //8位数据,可变波特率
//TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xFA; //设定定时初值
TH1 = 0xFA; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
* 发送一个字节数据
void SendData(BYTE dat)
while(!TI); //等待
void SendHello(BYTE dat)
while(!TI); //等待
* 软件延时
void Delay(WORD n)
while(n--)
while(x--);
看看晶振与程序是否一致
Powered by后使用快捷导航没有帐号?
请完成以下验证码
& & & & 【51单片机】
1 / 143 页
前天&23:56
- [售价 1 枚芯币]
1 / 143 页
EEWORLD 官方微信
Powered by}

我要回帖

更多关于 单片机面试问题 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信