打印

C51串口中断标志位TI和RI被主程序中的一个延迟子程序置1

[复制链接]
1912|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zxsa_001|  楼主 | 2012-10-22 20:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
上述说的这种情况我已经试过好多不同人编的串口中断程序了,其中不乏高手,
其实最后这个问题通过修改程序也解决了,但是老是存在这么个疑问,到底是
怎么造成的;所以在此不睹不快,提出来让高手指点一二,下面我用郭天祥51
书中的串口中断来说明这个问题,**书中的例程在实验现象上是没问题的
,也能实现程序设计初衷,但是使用keil 51进行仿真一步一步走时就会发现上
面我说的问题了;

#include <reg52.h>
#include <intrins.h>
#include <stdio.h>
#define uchar unsigned char
#define uint unsigned int
sbit dula=P2^6;  //申明U1锁存器的锁存端
sbit wela=P2^7;  //申明U2锁存器的锁存端
sbit adwr=P3^6;  //定义AD的WR端口
sbit adrd=P3^7;  //定义AD的RD端口
uchar flag,a;
unsigned char flag_uart,flag_time,flag_on,a,i,t0_num,ad_val;
float ad_vo;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
void delayms(uint xms)    /*问题经过一步一步的单步运行最后确认问题就出在延迟子程序上*/
{
uint i,j;
for(i=xms;i>0;i--)        
  for(j=110;j>0;j--);
}
void init()
{
TMOD=0x21;
// SCON=0x50;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TH1=0xfd;
TL1=0xfd;
TR1=1;
ET0=1;
SM0=0;
SM1=1;
REN=1;
EA=1;
ES=1;
}
void display(uchar value)  //显示子函数
{
uchar bai,shi,ge;
bai=value/100;  //分出百,十,和个位
shi=value%100/10;
ge=value%10;
dula=1;
P0=table[bai];    //送段选数据
dula=0;
P0=0xff;  //送位选数据前关闭所有显示,防止打开位选锁存时
wela=1;   //原来段选数据通过位选锁存器造成混乱
P0=0x7e;  //送位选数据
wela=0;
delayms(5);     //延时
dula=1;
P0=table[shi];
dula=0;
P0=0xff;
wela=1;
P0=0x7d;
wela=0;
delayms(5);
dula=1;
P0=table[ge];
dula=0;
P0=0xff;
wela=1;
P0=0x7b;
wela=0;
delayms(5);
}
uchar get_ad()  
{
  uchar adval;
adwr=1;
_nop_();
adwr=0;   //启动AD转换
_nop_();
adwr=1;
P1=0xff;                    //读取P1口之前先给其写全1
adrd=1;                  
_nop_();
adrd=0;                     //AD读使能
_nop_();
adval=P1;   //AD数据读取
adrd=1;
return adval;
}
void main()
{
init();
wela=1;
P0=0x7f;           //置CSAD为0,选通ADCS 以后不必再管ADCS
wela=0;
while(1)
{
  if(flag_uart==1)
  {
   flag_uart=0;
   ES=0;
   TI=1;
   switch(flag_on)
   {
    case 0: puts("Turn on ad!\n");
      TR0=1;
      break;
    case 1: printf("Turn off ad!\n");
      TR0=0;
      break;
    case 2: puts("Error!\n");
      break;
   }
   while(!TI);//必须要加
   TI=0;
   ES=1;
  }
  if(flag_time==1)
  {
   flag_time=0;
   ad_val=get_ad();
   ad_vo=(float)ad_val*5.0/256.0;
   ES=0;
   TI=1;
   printf("The voltage is %fV\n",ad_vo);
   while(!TI);
   TI=0;
  ES=1;/*单步运行到这里的时候TI和RI都还是0,没什么问题可是只要运行到下面
的display(ad_val);后程序TI和RI就全部被置1了,然后举直接跳到中断子程序那里去了,循环上几次有的时候自己还能跳出来,我再进入到display子程序中找原因最后就锁定在了延迟子程序的调用上了,当然这个问题可以在程序中用ES=0屏蔽掉,同时我用_nop_()做延迟就没这个请款,但是总是很纳闷到底是什么原因造成而来标志位被置1了,想彻底弄明白;小弟初接触51还请各位高手指点小可一二;
  }
  display(ad_val);
}
}
void timer0() interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
t0_num++;
if(t0_num==20)
{
  t0_num=0;
  flag_time=1;
}
}
void ser() interrupt 4
{
RI=0;
a=SBUF;
flag_uart=1;
if(a==1)
  flag_on=0;
  else if(a==2)
   flag_on=1;
  else
   flag_on=2;
}
沙发
阿南| | 2012-10-23 09:15 | 只看该作者
这个在调试时要用混合模式查看,对着汇编代码,且要实时监控TI和RI两个标志位才能找出具体原因。

使用特权

评论回复
板凳
kk8346| | 2012-10-24 21:43 | 只看该作者
我觉得问题可能在于“printf("The voltage is %fV\n",ad_vo); ”这一句。具体解释如下:printf实际是调用系统库函数中的“putchar()”函数(C:\Keil\C51\LIB下的“PUTCHAR.C”中)。该函数中,串口发送时,是先判断TI,再发送(送数据给SBUF)。
所以当printf执行完后,实际只是把要发送的数据送给了SBUF,硬件上正在发。
所以这时候如果紧跟着就执行后续指令,那么,执行到后续的某个位置时,刚才那个字节发送完成,硬件上就会把TI置1。
所以在现象上,就会观察到是在delay中出了问题。
附:PUTCHAR中的发送的部分:
“  while (!TI);
  TI = 0;
  return (SBUF = c);

使用特权

评论回复
地板
kk8346| | 2012-10-24 21:47 | 只看该作者
很抱歉,我刚才有看到在"printf("The voltage is %fV\n",ad_vo);" 的后面有一句"while(!TI);",那么刚才的分析就不成立了。很抱歉。

使用特权

评论回复
5
kk8346| | 2012-10-24 21:52 | 只看该作者
建议LZ不用printf,而改用直接串口发送,试试看。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

7

帖子

0

粉丝