求解一道关于定时器的c编程题目

[复制链接]
 楼主| s675 发表于 2009-10-21 17:34 | 显示全部楼层 |阅读模式
同时用两个定时器控制蜂鸣器发声,定时器0控制频率,定时器1控制同个频率持续的时间,间隔300ms依次输出1,10,50,100,200,400,800,1K(Hz)的方波。晶振为12MHz,P2.3口接蜂鸣器,低电平有蜂鸣器响。
xwj 发表于 2009-10-21 17:43 | 显示全部楼层
太简单,自己去想。
for_fun 发表于 2009-10-21 19:20 | 显示全部楼层
1,10,50,100,200,400,800,1K(Hz)对应的时间分别为
1000ms,100ms,20000us,10000us,5000us,2500us,1250us,1000us他们的最大公约数是50us,
若用定时器0控制频率
弄个for(i=需要计数的个数;i>0;i--){delay_us(50);}的循环即可!
kfawj 发表于 2009-10-22 10:50 | 显示全部楼层
自己动手吧!!!
问题是过于简单了一点!!!
你可以先找找跑马灯的程序!!!没有什么难度的!!!
awmc_m 发表于 2009-10-22 12:57 | 显示全部楼层
间隔300ms输出1hz?~~~~~
 楼主| s675 发表于 2009-10-23 10:03 | 显示全部楼层
谢谢ls各位解答,根据 for_fun 的提示,我编写了以下程序:
#include <reg52.h>
#define uint unsigned int
sbit beep = P2^3;
uint num1,num2,tnum;
uint code table[] = {4,5,10,20,40,80,400,4000}; //{4000,400,80,40,20,10,5,4};

void main()
{
        TMOD = 0x11;
        TH0 = (65536-250)/256;
        TL0 = (65536-250)%256;
        TH1 = (65536-50000)/256;
        TL1 = (65536-50000)%256;
        EA = 1;
        ET0 = 1;
        ET1 = 1;
        TR0 = 1;
        TR1 = 1;
        while(1);
}

void T0_time() interrupt 1
{
        TH0 = (65536-250)/256;
        TL0 = (65536-250)%256;
        num1++;
        if(num1 == table[tnum])
        {
                num1 = 0;
                beep = ~beep;
        }
}

void T1_time() interrupt 3
{
        TH1 = (65536-50000)/256;
        TL1 = (65536-50000)%256;
        num2++;
        if(num2 == 6)
        {
                num2 = 0;
                tnum++;
                if(tnum == 8)
                        tnum = 0;
        }
}

但还是存在 awmc_m 所提的问题: 间隔300ms输出1hz?~~~~~
最后程序到4000处停止,不能循环。因为num1不能检测到4000这个点吧。不知道应该怎么解决这个问题呢?请各位指点小弟一下!
 楼主| s675 发表于 2009-10-23 10:04 | 显示全部楼层
谢谢ls各位解答,根据 for_fun 的提示,我编写了以下程序:
#include <reg52.h>
#define uint unsigned int
sbit beep = P2^3;
uint num1,num2,tnum;
uint code table[] = {4,5,10,20,40,80,400,4000}; //{4000,400,80,40,20,10,5,4};

void main()
{
        TMOD = 0x11;
        TH0 = (65536-250)/256;
        TL0 = (65536-250)%256;
        TH1 = (65536-50000)/256;
        TL1 = (65536-50000)%256;
        EA = 1;
        ET0 = 1;
        ET1 = 1;
        TR0 = 1;
        TR1 = 1;
        while(1);
}

void T0_time() interrupt 1
{
        TH0 = (65536-250)/256;
        TL0 = (65536-250)%256;
        num1++;
        if(num1 == table[tnum])
        {
                num1 = 0;
                beep = ~beep;
        }
}

void T1_time() interrupt 3
{
        TH1 = (65536-50000)/256;
        TL1 = (65536-50000)%256;
        num2++;
        if(num2 == 6)
        {
                num2 = 0;
                tnum++;
                if(tnum == 8)
                        tnum = 0;
        }
}

但还是存在 awmc_m 所提的问题: 间隔300ms输出1hz?~~~~~
最后程序到4000处停止,不能循环。因为num1不能检测到4000这个点吧。不知道应该怎么解决这个问题呢?请各位指点小弟一下!
hyg1984 发表于 2009-10-23 12:23 | 显示全部楼层
本帖最后由 hyg1984 于 2009-10-23 12:32 编辑

晕啊,这个延时是不是计算错了?3楼讲的很不错,不知道你明白没有。
这个程序浪费太多的空间了,8位单片机最好不要用16位的变量,最好像3楼说得那样循环,当然,软件延时改成定时器延时最好。
1、if(num2 == 6)这里是不是应该改成60,因为5ms*60才等于300ms吧?
2、定时器0频率计算的好像不对头。
这样改看行不行,至于4000处停止的问题,应该是跑飞了吧,这个你再检查检查。

unsigned char count1,count2;
unsigned char num,tnum;

void T0_time() interrupt 1
{
        TH0 = (65536-50)/256;            //12M晶振,一次中断约等于50us吧
        TL0 = (65536-50)%256;
/*1000ms=50us*20000;100ms=50us*2000;20000us=50us*400;10000us=50us*200;5000us=50us*100;2500us=50us*50;1250us=50us*25;1000us=50us*20*/
        if(tnum == 0x00)  
        {
                if(++count1 == 20)
                {
                          count1 = 0;
                          beep = ~beep;
                }
        }
        else if(tnum == 0x01)  
        {
                if(++count1 == 25)
                {
                          count1 = 0;
                          beep = ~beep;
                }
        }
        else if(tnum == 0x02)  
        {
                if(++count1 == 50)
                {
                          count1 = 0;
                          beep = ~beep;
                }
        }

        ..............自己对照着时间来改

        else if(tnum == 0x05)  
        {
                if(++count1 == 200)
                {
                         count1 = 0;
                         if(++count == 2)
                         {
                                  count2 = 0;
                                  beep = ~beep;
                         }
                }
        }

         ...........自己对照着时间来改
}

void T1_time() interrupt 3
{
        TH1 = (65536-50000)/256;    //12M的晶振约等于5ms
        TL1 = (65536-50000)%256;
        num++;
        if(num == 60)         //约300ms
        {
                num = 0;
                tnum++;
                if(tnum == 8)
               {
                        tnum = 0;
                        count1 = 0;
                        count2 = 0;//清零,不然不准了
               }
        }
}
for_fun 发表于 2009-10-23 12:45 | 显示全部楼层
LS正解哦!:)

LZ别着急,再好好想想!
 楼主| s675 发表于 2009-10-24 10:45 | 显示全部楼层
hyg1984 谢谢你细心的回复,但有些疑问还要向你请教!

这个程序浪费太多的空间了,   //浪费空间是指数据存储器(RAM)空间吗?
8位单片机最好不要用16位的变量,最好像3楼说得那样循环,
当然,软件延时改成定时器延时最好。  //我俩都是用定时器来延时的呀,不知道你说的软件延时在哪里?
1、if(num2 == 6)这里是不是应该改成60,因为5ms*60才等于300ms吧?  //12M晶振,50000个机器周期应该是50ms吧?
2、定时器0频率计算的好像不对头。
这样改看行不行,至于4000处停止的问题,应该是跑飞了吧,这个你再检查检查。  //应该是跑飞了

unsigned char count1,count2;
unsigned char num,tnum;

void T0_time() interrupt 1
{
        TH0 = (65536-50)/256;            //12M晶振,一次中断约等于50us吧 //我用的是250us一次中断,50us和250us中断有没有区别?
        TL0 = (65536-50)%256;
/*1000ms=50us*20000;100ms=50us*2000;20000us=50us*400;10000us=50us*200;5000us=50us*100;2500us=50us*50;1250us=50us*25;1000us=50us*20*/
/*1000ms=250us*4000;100ms=250us*400;20000us=250us*80;10000us=250us*40;5000us=250us*20;2500us=250us*10;1250us=250us*5;1000us=250us*4*/
        if(tnum == 0x00)  
        {
                if(++count1 == 20)
                {
                          count1 = 0;
                          beep = ~beep;
                }
        }
        else if(tnum == 0x01)  
        {
                if(++count1 == 25)
                {
                          count1 = 0;
                          beep = ~beep;
                }
        }
        else if(tnum == 0x02)  
        {
                if(++count1 == 50)
                {
                          count1 = 0;
                          beep = ~beep;
                }
        }

        ..............自己对照着时间来改

        else if(tnum == 0x05)      // 知道怎么分解4000了   
           {
                if(++count1 == 200)
                {
                         count1 = 0;
                         if(++count == 2)
                         {
                                  count2 = 0;
                                  beep = ~beep;
                         }
                }
        }

         ...........自己对照着时间来改
}

void T1_time() interrupt 3
{
        TH1 = (65536-50000)/256;    //12M的晶振约等于5ms  //50ms??
        TL1 = (65536-50000)%256;
        num++;
        if(num == 60)         //约300ms    //num == 6??
        {
                num = 0;
                tnum++;
                if(tnum == 8)
               {
                        tnum = 0;
                        count1 = 0;
                        count2 = 0;//清零,不然不准了      //如果继续用16位变量方法,是不是只要这里将num1清0就能解决4000跑飞的问题了?
          }
        }
}
 楼主| s675 发表于 2009-10-24 10:50 | 显示全部楼层
这里1Hz频率(1000ms)的方波是不是不能改变蜂鸣器的电平,只能保持?
hyg1984 发表于 2009-10-24 12:14 | 显示全部楼层
//浪费空间是指数据存储器(RAM)空间吗?
答:是的,是指内部存储器RAM

//我俩都是用定时器来延时的呀,不知道你说的软件延时在哪里?
答:3楼的意思是用软件延时,我们都用定时器延时
1、if(num2 == 6)这里是不是应该改成60,因为5ms*60才等于300ms吧?  //12M晶振,50000个机器周期应该是50ms吧?
答:恩,这里是我错了,应该是50ms

//12M晶振,一次中断约等于50us吧 //我用的是250us一次中断,50us和250us中断有没有区别?
答:我是按3楼的最大公约数来算的,你能算的通就行

//清零,不然不准了      //如果继续用16位变量方法,是不是只要这里将num1清0就能解决4000跑飞的问题了?
答:试一试再说
1HZ的方波不就是500ms低电平,500ms高电平吗?
 楼主| s675 发表于 2009-10-25 11:36 | 显示全部楼层
//清零,不然不准了      //如果继续用16位变量方法,是不是只要这里将num1清0就能解决4000跑飞的问题了?
答:试一试再说

谢谢,我试过了,可以
1HZ的方波不就是500ms低电平,500ms高电平吗?

原来是这样啊:$   
那么每次的定时时间都应该减半了
for_fun 发表于 2009-10-25 13:33 | 显示全部楼层
:)恭喜LZ了!
llf2385668061 发表于 2016-3-5 16:09 | 显示全部楼层
#include<reg51.h>
#define uint unsigned int
#define uchar unsigned char
sbit beep=P2^3;
uchar num1,num2,tt,aa,i;
uchar table[]={20000,2000,400,200,100,50,25,20};
uchar temp[]={0,3,15,30,60,120,240,300};
void main()
{  tt=0;
   num1=0; num2=0;
   aa=0;
TMOD=0x01;  //定时器0,1采用工作方式1中断
        TH0=(65536-25000)/256;
        TL0=(65536-25000)%256;
        TR0=1;
        TH1=(65536-50000)/256;
        TL1=(65536-50000)%256;
        TR1=1;
        EA=1;
        ET0=1;
        ET1=1;
        TF1=1;
        while(1)
        {       
                if(aa==6)
                {        if(num1==8)
                      num1=0;
                         if(num2==8)
                           num2=0;
                aa=0;
                for(i=0;i<temp[num1];i++)
                    {
                          beep=0;
                          if(tt==table[num2])
                          beep=1;
                          if(tt==2*table[num2])
                          beep=0;
                       
                        }
                        num1++;
                        num2++;
       
                }       
        }
}
void timer0() interrupt 1
{          TH0=(65536-25000)/256;
        TL0=(65536-25000)%256;
        tt++;
}
void timer1() interrupt 3
{        TH1=(65536-50000)/256;
        TL1=(65536-50000)%256;
        aa++;
}
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

12

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部