提问一个关于单片机C语言,程序延时的问题。

qq_21557607 2014-12-26 08:02:08
void delayus(int b)  //微秒延时
{
int i;
for(;b>0;b--)
for(i=2;i>0;i--);
}
if(a==0)//输出方波
{
P1=0x00;
delayus(50);
P1=0xff;
delayus(50);
}

用这个延时输出的方波周期在示波器上看为什么是3ms多?
我想做到的是输出频率为5KHz的方波,也就是周期200微秒是吧,为什么做不到呢?
...全文
486 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_21557607 2014-12-29
  • 打赏
  • 举报
回复
引用 15 楼 pathletboy 的回复:
你这种代码当然出不来你想要的结果,你想想你
        if(a==0)//输出方波
        { 
               led=0;
               delayus();
               led=1;
               delayus();          
        }
最后一个delayus()过后,单片机执行了多少代码,才又执行到led=0,你程序结构得好好规划。
谢谢提醒啊,从前做的题目都是没有遇到过这类问题,就根本没有在意过这个问题,这可以说是一个隐患啊。其实感觉有问题,但是根本没往那方面想。
pathletboy 2014-12-28
  • 打赏
  • 举报
回复
你这种代码当然出不来你想要的结果,你想想你
        if(a==0)//输出方波
        { 
               led=0;
               delayus();
               led=1;
               delayus();          
        }
最后一个delayus()过后,单片机执行了多少代码,才又执行到led=0,你程序结构得好好规划。
qq_21557607 2014-12-28
  • 打赏
  • 举报
回复
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
//#pragma OT(4,speed)
sbit led=P2^4;
sbit key1=P3^7;
sbit key2=P3^6;
void display(char);//定义显示函数,参数为显示内容
void delayus(int);
void delayms(uint);
void init();
unsigned char tt=0;//初如化函数
sbit RS = P2^0;//定义端口
sbit RW = P2^1;
sbit EN = P2^2;
#define RS_CLR RS=0
#define RS_SET RS=1
#define RW_CLR RW=0
#define RW_SET RW=1
#define EN_CLR EN=0
#define EN_SET EN=1
/*延时函数*/
void delay_us(unsigned int n) //延时 如果需要高精度延时 请嵌入汇编
{
/*if (n == 0)
{
return ;
} */
while (--n);
}
/*延时函数*/
void delay_ms(unsigned char i)
{
unsigned char a, b;
for (a = 1; a < i; a++)
{
for (b = 1; b; b++)
{ ; }
}
}/*显示屏命令写入函数*/
void LCD_write_com(unsigned char com)
{
RS_CLR;
RW_CLR;
EN_SET;
P0 = com;
delay_us(5);
EN_CLR;
}
/*显示屏命令写入函数*/
void LCD_write_Data(unsigned char Data)
{
RS_SET;
RW_CLR;
EN_SET;
P0 = Data;
delay_us(5);
EN_CLR;
}
/*显示屏清空显示*/
void LCD_clear(void)
{
LCD_write_com(0x01);
delay_ms(5);}
/*显示屏字符串写入函数*/
void LCD_write_str(unsigned char x,unsigned char y,unsigned char *s)
{
if (y == 0)
{
LCD_write_com(0x80 + x);
}
else
{
LCD_write_com(0xC0 + x);
}
while (*s)
{
LCD_write_Data( *s);
s ++;
}
}
/*显示屏单字符写入函数*/
void LCD_write_char(unsigned char x,unsigned char y,unsigned char Data)
{
if (y == 0)
{
LCD_write_com(0x80 + x);
}
else
{
LCD_write_com(0xC0 + x);
}
LCD_write_Data( Data);
}
/*显示屏初始化函数*/
void LCD_init(void)
{
LCD_write_com(0x38); /*显示模式设置*/
delay_ms(5);
LCD_write_com(0x38);
delay_ms(5);
LCD_write_com(0x38);
delay_ms(5);
LCD_write_com(0x38);
LCD_write_com(0x08); /*显示关闭*/
LCD_write_com(0x01); /*显示清屏*/
LCD_write_com(0x06); /*显示光标移动设置*/
delay_ms(5);
LCD_write_com(0x0C); /*显示开及光标设置*/
}


void delayus(void) //微秒延时
{
/* #pragma asm
MOV R6,#13H
DL0:
MOV R5,#01H
DJNZ R5,$
DJNZ R6,DL0
RET
#pragma endasm */
unsigned char a,b;
for(b=39;b>0;b--)
for(a=1;a>0;a--);
}
void delayms(uint ms)//毫秒延时
{
int i,j;
for(i=ms;i>0;i--)
for(j=110;j>0;j--);
}
void main()
{
unsigned char bb=0; //作为显示变量
char a=1,c=0,d=0,shi,ge,f=0,f_shi,f_ge,h,e;//设置标志识别位,c为选档键标志位(按1下为10s,按2下为20s,按3下为30s),d为确认键标志位,
init();//定时中断
LCD_init();
LCD_clear();
LCD_write_str(0,0,"DELAY:");
LCD_write_str(0,1,"SELECT:");
while(1){
if(key1==0)
{
delayms(10);//防抖
if(key1==0)
{
c++;
if(c==1){f=5;}
if(c==2){f=10;}
if(c==3){f=15;}
if(c==4)
{
c=0;
f=0;
}
f_shi=f/10+0x30;
f_ge=f%10+0x30;
LCD_write_char(8,1,f_shi);
LCD_write_char(9,1,f_ge);
while(!key1);//防抖
}
}
if((key2==0)&&(c!=0))//判断确认键和选档键是否同时满足条件
{
d=1;//标志位d变化
e=0;
h=e/10+0x30;
LCD_write_char(8,1,h);
LCD_write_char(9,1,h);
while(!key2);//防抖
}
if(d!=0)
{
TR0=1; //启定定时器0
if(c==1)//选档键按1下为定时10s
{
bb=f;
a=0;
d=0;
c=0;
}
if(c==2)//选档键按2下为定时20S
{
bb=f;
a=0;
d=0;
c=0;
}
if(c==3)//选档键按3下为定时30S
{
bb=f;
a=0;
d=0;
c=0;
}
if(c==4)//选档键按超过3下则清零
{
c=0;
return;
}
}
if(a==0)//输出方波
{
led=0;
delayus();
led=1;
delayus();
}
else
{
led=1;//灯灭
}
if(tt==20)
{ //20*50MS定时时间为1秒
tt=0;
bb--; //计数变量减1
if(bb==0)
{
c=0;
f=0;
a=1;
TR0=0; //启定定时器0
return;
}
}
shi=bb/10+0x30;
ge=bb%10+0x30;
LCD_write_char(8,0,shi);
LCD_write_char(9,0,ge);
} //while结束
}

void init()
{
tt=0;
TMOD=0X01; //设置定时器1为模式一,即16位计算模式
TH0=(65536-50000)/256; //给计数寄存器赋值,50毫秒时间
TL0=(65536-50000)%256;
EA=1; //开启总中断
ET0=1; //开启定时器0中断
// TR0=1; //启定定时器0
}
void timer() interrupt 1
{
TH0=(65536-50000)/256; //重新赋值
TL0=(65536-50000)%256;
tt++; //50毫秒加1,加20次为一秒
}

这个是我全部的程序,请问为什么设定的200微秒延时和出来实际波形是不一样的?实际波形是这样的

不是5KHz的方波。
pathletboy 2014-12-28
  • 打赏
  • 举报
回复
引用 12 楼 qq_21557607 的回复:

#include<reg52.h>
#pragma OT(4,speed)
void delayus(int);
sbit led=P2^4;
void delayus(void) //微秒延时
{
#pragma asm
MOV R6,#13H
DL0:
MOV R5,#01H
DJNZ R5,$
DJNZ R6,DL0
RET
#pragma endasm
}
void main()
{
led=0;
delayus();
led=1;
delayus();
}

嵌入汇编后,接在示波器上,显示波形的周期还是不对。加的延时是100US,那一个周期应该是200us。而示波器上一个周期显示出来是600US,请问为什么?


你这程序跑飞了,请加个死循环。
另外可以生成C代码,见图。
qq_21557607 2014-12-28
  • 打赏
  • 举报
回复

#include<reg52.h>
#pragma OT(4,speed)
void delayus(int);
sbit led=P2^4;
void delayus(void)  //微秒延时
{
	#pragma asm
	MOV R6,#13H
    DL0:
    MOV R5,#01H
    DJNZ R5,$
    DJNZ R6,DL0
    RET
	#pragma endasm
}
void main()
{
	           led=0;
	           delayus();
	           led=1;
	           delayus();
}
嵌入汇编后,接在示波器上,显示波形的周期还是不对。加的延时是100US,那一个周期应该是200us。而示波器上一个周期显示出来是600US,请问为什么?
qq_21557607 2014-12-28
  • 打赏
  • 举报
回复
引用 9 楼 pathletboy 的回复:
有个叫
引用
单片机小精灵
的软件,可以很方便的生成延时函数,你可以试试。 另AT89C52是12T的51片子,12个机器周期才能执行完一条单周期指令。
已经下了破解版了,现在去试试代码有没有用。
qq_21557607 2014-12-28
  • 打赏
  • 举报
回复
引用 9 楼 pathletboy 的回复:
有个叫
引用
单片机小精灵
的软件,可以很方便的生成延时函数,你可以试试。 另AT89C52是12T的51片子,12个机器周期才能执行完一条单周期指令。
你好,我听你说的,下好了这个软件,但是只能查看汇编,转换成C的话要我注册买会员。如果有会员的话,能麻烦你帮我转换一下吗?谢谢 汇编的代码是这个: ;参数寄存器:R2 存放延时时间的倍数 DELAY10US: ;误差 0us START: MOV R5,#01H DJNZ R5,$ NOP DJNZ R2,START RET
pathletboy 2014-12-27
  • 打赏
  • 举报
回复
有个叫
引用
单片机小精灵
的软件,可以很方便的生成延时函数,你可以试试。 另AT89C52是12T的51片子,12个机器周期才能执行完一条单周期指令。
qq_21557607 2014-12-27
  • 打赏
  • 举报
回复
引用 7 楼 pathletboy 的回复:
按照你的代码,使用12T的51片子,周期是3ms没错的。 用模拟仿真,如图,右下角,单步运行delayus前右键reset一下计时器,然后f10单步,就能看到delayus所消耗的时间了。
你好,就是AT89C52,做毕设用的那种。我不太会弄仿真,汇编也不太熟,所以请问下,有什么办法能把延时做到我想要的200US呢?谢谢。
sunsc2010 2014-12-27
  • 打赏
  • 举报
回复
延迟和单片机的指令周期有关,或者是单片机的主频有关,你可以换算一下,如果时间长,可以缩短延迟啊。
pathletboy 2014-12-27
  • 打赏
  • 举报
回复
按照你的代码,使用12T的51片子,周期是3ms没错的。

用模拟仿真,如图,右下角,单步运行delayus前右键reset一下计时器,然后f10单步,就能看到delayus所消耗的时间了。
pathletboy 2014-12-27
  • 打赏
  • 举报
回复
什么单片机?是1T的还是12T的,这个很重要,那些较早的51,大都12T,也就是12个机器周期执行一条单周期指令,新的一些大都1T。这些都要说清楚。
qq_21557607 2014-12-27
  • 打赏
  • 举报
回复
引用 1 楼 wangfan027 的回复:
这个要看晶振和生成的汇编代码的 先根据晶振算出一条指令的执行时间 然后看生成的汇编代码里一个循环有多少条指令
请问版主,Keil里怎么查看,C转汇编啊? 晶振是12MHZ,一个机器周期是1US,所以一条指令是1US,DJNZ之类的有些指令是2US,然后我根据转换后汇编指令条数算出延时的时间是吗? 那像我要输出的5KHZ的方波,也就是一个周期200微秒左右,也不用精确200微秒,上面那个DELAY也是看了论坛的一些介绍后拷贝来计算后用的,为什么效果没有达到呢?链接是这个麻烦解答一下,谢谢。http://blog.csdn.net/shawsun/article/details/24560255
worldy 2014-12-27
  • 打赏
  • 举报
回复
建议lz还是使用定时器中断做
ggrfdsfsd 2014-12-27
  • 打赏
  • 举报
回复
你这个延时函数延时时间是多少,比如b=1时,延时多久,测出来之后再来做你想要的周期就很方便了
dceacho 2014-12-26
  • 打赏
  • 举报
回复
这个要看晶振和生成的汇编代码的 先根据晶振算出一条指令的执行时间 然后看生成的汇编代码里一个循环有多少条指令

27,374

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 单片机/工控
社区管理员
  • 单片机/工控社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧