找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 8788|回复: 46
打印 上一主题 下一主题
收起左侧

STC15单片机没有按照设置的定时时间进入中断

  [复制链接]
跳转到指定楼层
楼主
现在手上使用的一款IAP15W4K58S4单片机,需要使用到的中断有定时器T0中断和串口中断,使用内部时钟22.1184Mhz,配置如下:

/*配置并启动T0,定时时间是5ms*/
void Timer0Init()
{   
    AUXR |= 0x80;                          //定时器时钟1T模式
    TMOD &= 0xF0;                          //清零T0的控制位
    TH0 = 0xFF;
    TL0 = 0xC9;
    ET0 = 1;                               //使能T0中断
    TF0 = 0;
    TR0 = 1;                               //启动T0
}

/*配置串口*/
void UART_init()
{
    SCON = 0x50;    //01010000 SM0.SM1 = 01(最普遍的8位通信),REN = 1(允许接收)
    AUXR |= 0x01;                //串口1选择定时器2为波特率发生器
        AUXR |= 0x04;                //定时器2时钟为Fosc,即1T
    T2L = 0xC0;                //设定定时初值
        T2H = 0xFD;                //设定定时初值
        AUXR |= 0x10;                //启动定时器2

    //下面的代码设置中断
    ES = 1;         //开串口1中断

}


在主函数中的调用如下:
void main()
{
    port_mode();
    Timer0Init();                        //配置T0定时器定时时间5ms,打开T0定时器开始计时
    UART_init();
    EA = 1;                                 //开总中断
    InitLcd1602();

//    LcdShowStr(0,0,Fun1);
    LcdShowStr(3,0,"F");
    LcdShowStr(8,0,"A-");
    LcdShowStr(0,1,"B-");
    LcdShowStr(8,1,"C-");
    Delay_ms(10);
    ClearZeroKeyAction();   

    while(1)
    {   
        KeyDriver();                        //按键驱动里包含了按键执行相关的动作
        weigh();                  
        ValueToString(str,val_ShiWu);       //转为字符串格式的电压值
//        LcdShowStr(0,1,str);                //显示到液晶上
        UartSend();
    }
}


现在在软件仿真中发现,这个定时器中断并没有按照设定好的时间即5ms进入中断,而是只有大约一半的时间就进入了,而且不管怎么更改这个定时时间,它都是维持这个5ms一半的时间进入,就是说跟更改这个定时时间没关系,但是它也进入中断,执行了中断函数,现在查找这个寄存器配置感觉也没有错误,不知道问题出在什么地方?恳请坛友帮忙指正!
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:523886 发表于 2020-10-20 16:06 | 只看该作者
    TH0 = 0xFF;     TL0 = 0xC9;改这里,一个是高位一个是地位,两位拼成一个16位数据,改这个数据就可以了
回复

使用道具 举报

板凳
ID:523886 发表于 2020-10-20 16:08 | 只看该作者
  TH0 = 0xFF;
    TL0 = 0xC9;这两个八位数据一个高位一个低位拼成一个16位数据,改这个就行
回复

使用道具 举报

地板
ID:213173 发表于 2020-10-20 16:20 | 只看该作者
22.1184MHz时钟1T模式不可能设置为5ms定时时长。要改为12T模式。
void Timer0Init(void)                //5毫秒@22.1184MHz
{
        AUXR &= 0x7F;                //定时器时钟12T模式
        TMOD &= 0xF0;                //设置定时器自动重装模式
        TL0 = 0x00;                //设置定时初值
        TH0 = 0xDC;                //设置定时初值
        TF0 = 0;                //清除TF0标志
        TR0 = 1;                //定时器0开始计时
}

回复

使用道具 举报

5#
ID:47286 发表于 2020-10-20 16:31 | 只看该作者
不解 没看到中断服务程序 那产生了中断也没程序接收 有什么用呢 你发的程序里只有T0的初始化 初始化的作用只是开寄存器和给初值 等于你开了中断但没有使用中断啊
回复

使用道具 举报

6#
ID:446775 发表于 2020-10-20 16:35 | 只看该作者
dzbj 发表于 2020-10-20 16:31
不解 没看到中断服务程序 那产生了中断也没程序接收 有什么用呢 你发的程序里只有T0的初始化 初始化的作用 ...

使用中断了下面就是中断服务函数
/*T0中断服务函数,执行配置时间定时*/
void Timer0()interrupt 1
{   
        KeyScan();
}

/*串口1中断服务函数*/
void UART1()interrupt 4
{
    if(RI)
    {
        RI = 0;
        cmdIndex = SBUF;
        cmdArrived = 1;     
    }
    if(TI)
    {
        TI = 0;
        if(cndtxd > 0)
        {
            SBUF = *ptrtxd;
            cndtxd--;
            ptrtxd++;
        }
    }
}
回复

使用道具 举报

7#
ID:446775 发表于 2020-10-20 16:36 | 只看该作者
g2363451687 发表于 2020-10-20 16:08
TH0 = 0xFF;
    TL0 = 0xC9;这两个八位数据一个高位一个低位拼成一个16位数据,改这个就行

这个怎么改?这个本身就是计算出来的初值
回复

使用道具 举报

8#
ID:446775 发表于 2020-10-20 16:36 | 只看该作者
wulin 发表于 2020-10-20 16:20
22.1184MHz时钟1T模式不可能设置为5ms定时时长。要改为12T模式。
void Timer0Init(void)                //5毫秒@22.1184 ...

改过了,还是不管用的
回复

使用道具 举报

9#
ID:446775 发表于 2020-10-20 16:43 | 只看该作者
这是用逻辑分析仪抓取的TF0的位数据,间隔还是2ms多,就好像这个T0设置的时间没有用,我设置的是5ms,但是它也进入中断了。
回复

使用道具 举报

10#
ID:446775 发表于 2020-10-20 16:45 | 只看该作者
g2363451687 发表于 2020-10-20 16:06
TH0 = 0xFF;     TL0 = 0xC9;改这里,一个是高位一个是地位,两位拼成一个16位数据,改这个数据就可以 ...

这个本身就是计算出来的初值
回复

使用道具 举报

11#
ID:47286 发表于 2020-10-20 19:40 | 只看该作者
karolyte 发表于 2020-10-20 16:35
使用中断了,下面就是中断服务函数
/*T0中断服务函数,执行配置时间定时*/
void Timer0()interrupt 1

你没设置定时器T0的重装模式
回复

使用道具 举报

12#
ID:446775 发表于 2020-10-20 23:11 | 只看该作者
dzbj 发表于 2020-10-20 19:40
你没设置定时器T0的重装模式

这个重装模式已经在配置函数里设置过了,不需要在中断服务函数里再重新设置了
回复

使用道具 举报

13#
ID:446775 发表于 2020-10-21 08:21 | 只看该作者
wulin 发表于 2020-10-20 16:20
22.1184MHz时钟1T模式不可能设置为5ms定时时长。要改为12T模式。
void Timer0Init(void)                //5毫秒@22.1184 ...

已经改为12T模式了,但是结果跟之前一样
回复

使用道具 举报

14#
ID:446775 发表于 2020-10-21 08:23 | 只看该作者
会不会是内存不足的原因导致的呢?
回复

使用道具 举报

15#
ID:414556 发表于 2020-10-21 19:32 | 只看该作者
你的程序定时是5uS啊,仿真软件有时因为单片机设置的问题并不准确.
回复

使用道具 举报

16#
ID:446775 发表于 2020-10-21 21:53 | 只看该作者
amandv 发表于 2020-10-21 19:32
你的程序定时是5uS啊,仿真软件有时因为单片机设置的问题并不准确.

是的,我写错了,已经改过来的,但是问题还是那样,没有改变
回复

使用道具 举报

17#
ID:213173 发表于 2020-10-22 06:48 | 只看该作者
karolyte 发表于 2020-10-20 16:36
改过了,还是不管用的

定时器是单片机的一项基础功能,并且使用上也没有什么难度。楼主发的程序不完整,难以准确判断问题所在。楼主发的定时器设置参数是5us不是5ms。中断函数根本就不可能正常运行。
回复

使用道具 举报

18#
ID:446775 发表于 2020-10-22 08:05 | 只看该作者
wulin 发表于 2020-10-22 06:48
定时器是单片机的一项基础功能,并且使用上也没有什么难度。楼主发的程序不完整,难以准确判断问题所在。 ...

是的,我写的5us,发错了,不过现在改过来了,但是问题还是老样子,就是说不管你把时间改成什么样,它总是维持5ms一半的时间(也就是说2.1ms、2.2ms)这个样子进入中断,改这个定时时间不管用。
回复

使用道具 举报

19#
ID:213173 发表于 2020-10-22 08:40 | 只看该作者
karolyte 发表于 2020-10-22 08:05
是的,我写的5us,发错了,不过现在改过来了,但是问题还是老样子,就是说不管你把时间改成什么样,它总是 ...

你的故障描述不可思议,肯定程序有错。你把完整程序发上来帮你看看。
回复

使用道具 举报

20#
ID:832987 发表于 2020-10-22 08:59 | 只看该作者
把你的程序发上来,设置没有问题了。
回复

使用道具 举报

21#
ID:446775 发表于 2020-10-22 17:02 | 只看该作者
wulin 发表于 2020-10-22 06:48
定时器是单片机的一项基础功能,并且使用上也没有什么难度。楼主发的程序不完整,难以准确判断问题所在。 ...

这个就似源码,可以看一下
回复

使用道具 举报

22#
ID:213173 发表于 2020-10-23 08:02 | 只看该作者
karolyte 发表于 2020-10-22 17:02
这个就似源码,可以看一下

楼主的程序不能通过编译,有3段子程序没有被调用,1项地址空间溢出错误以及其它40多项错误。
要分步查找错误。先屏蔽一部分模块,调试正常后逐一添加模块,这样比较容易找到问题点。
特别提示:使用IAP15Wxx单片机和STC15Wxx单片机是有区别的,STC15W的EEPROM地址是固定的,IAP15W的EEPROM地址是放在用户程序区剩余区域。如安排不当会造成写EEPROM数据时破坏用户程序而发生不可预测的错误。
回复

使用道具 举报

23#
ID:446775 发表于 2020-10-23 08:45 | 只看该作者
wulin 发表于 2020-10-23 08:02
楼主的程序不能通过编译,有3段子程序没有被调用,1项地址空间溢出错误以及其它40多项错误。
要分步查找 ...

不能通过编译?为啥在我这里可以通过编译啊,现在只能分步查找错误了,谢谢你!
回复

使用道具 举报

24#
ID:337139 发表于 2020-10-23 18:02 | 只看该作者
我需要看一下你的KeyScan();和KeyDriver();这两个函数!
回复

使用道具 举报

25#
ID:451718 发表于 2020-10-23 18:41 | 只看该作者
STC有个非常好用的工具,STC-ISP。  我以前也是自己改定时器初值,很多次都是把参数弄错了 。 后来直接用这个软件生产的代码,几乎没有在定时器初值,和设置上出过错。  

stc.jpg (305.4 KB, 下载次数: 97)

stc.jpg
回复

使用道具 举报

26#
ID:446775 发表于 2020-10-23 22:27 | 只看该作者
长风007 发表于 2020-10-23 18:02
我需要看一下你的KeyScan();和KeyDriver();这两个函数!

/*按键驱动,根据扫描按键的状态,确定哪个按键执行动作*/
  1. void KeyDriver()
  2. {
  3.     unsigned char i,j;
  4.     static unsigned char xdata backup[5][4] = {       //按键值备份,保存前一次的值
  5.         {1,1,1,1},{1,1,1,1},
  6.         {1,1,1,1},{1,1,1,1},
  7.         {1,1,1,1}
  8.     };
  9.    
  10.     for(i = 0;i < 5;i++)                        //循环检测4*4矩阵键盘
  11.     {
  12.         for(j = 0;j < 4;j++)
  13.         {
  14.             if(backup[i][j] != KeySta[i][j])
  15.             {
  16.                 if(backup[i][j] != 0)          //只有当按键是按下时才返回键码值
  17.                 {
  18.                     KeyAction(KeyCodeMap[i][j]);
  19.                 }                                                   
  20.                 backup[i][j] = KeySta[i][j];
  21.             }
  22.         }
  23.     }
  24. }

  25. /*按键扫描,增加一行键盘*/
  26. void KeyScan()
  27. {
  28.     unsigned char i;
  29.     static unsigned char keyout = 0;                //矩阵按键扫描输出索引
  30.     static unsigned char xdata keybuf[5][4] = {           //键盘状态缓存
  31.         {0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},
  32.         {0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},
  33.         {0xFF,0xFF,0xFF,0xFF}
  34.     };
  35.    
  36. /*扫描输入,将每行4个键盘的当前状态移入缓存*/   
  37.     keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;
  38.     keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;
  39.     keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;
  40.     keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;
  41. /*根据每个键盘缓存区中的低四位,判断键盘当前的状态并更新按键的状态*/
  42.     for(i = 0;i < 4;i++)
  43.     {
  44.         if((keybuf[keyout][i] & 0x0F) == 0x00)
  45.         {
  46.             KeySta[keyout][i] = 0;
  47.         }
  48.         else if((keybuf[keyout][i] & 0x0F) == 0x0F)
  49.         {
  50.             KeySta[keyout][i] = 1;
  51.         }
  52.     }

  53. /*改变输出*/   
  54.     keyout++;
  55.     if(keyout > 4)
  56.         keyout = 0;
  57.                
  58.     switch(keyout)
  59.     {
  60.         case 0:KEY_OUT_5 = 1;KEY_OUT_4 = 0;break;
  61.         case 1:KEY_OUT_4 = 1;KEY_OUT_3 = 0;break;
  62.         case 2:KEY_OUT_3 = 1;KEY_OUT_2 = 0;break;
  63.         case 3:KEY_OUT_2 = 1;KEY_OUT_1 = 0;break;
  64.         case 4:KEY_OUT_1 = 1;KEY_OUT_5 = 0;break;
  65.         default:break;
  66.     }
  67. }
复制代码
回复

使用道具 举报

27#
ID:833710 发表于 2020-10-23 22:34 | 只看该作者
你定时器工作模式设置错误,应该设置成模式1    TMOD=0x01;
回复

使用道具 举报

28#
ID:833710 发表于 2020-10-23 22:41 | 只看该作者
你定时器工作模式设置错误,设置在模式0,是13位计数器,应该设置成模式1;TMOD&=0xf0;TMOD|=0x01;
回复

使用道具 举报

29#
ID:833710 发表于 2020-10-23 22:44 | 只看该作者
你T0工作模式设置错误,应设置成模式1

void Timer0Init()
{   
    AUXR |= 0x80;                          //定时器时钟1T模式
    TMOD &= 0xF0;                          //清零T0的控制位
    TMOD|=0x01;            //工作模式1
    TH0 = 0xFF;
    TL0 = 0xC9;
    ET0 = 1;                               //使能T0中断
    TF0 = 0;
    TR0 = 1;                               //启动T0
}
回复

使用道具 举报

30#
ID:446775 发表于 2020-10-24 17:28 | 只看该作者
robinsonlin 发表于 2020-10-23 18:41
STC有个非常好用的工具,STC-ISP。  我以前也是自己改定时器初值,很多次都是把参数弄错了 。 后来直接用这 ...

是的,我也是用这个工具设置的参数,发现不是这里的问题,因为我把模型设置为STC89C52就没有问题
回复

使用道具 举报

31#
ID:446775 发表于 2020-10-24 17:29 | 只看该作者
jokez7 发表于 2020-10-23 22:34
你定时器工作模式设置错误,应该设置成模式1    TMOD=0x01;

我用的是STC15系列的单片机,模式1不是自动重载的,也试过这种模式,没有用的,我发现把模型设置为STC89C52就没问题,是不是模型的问题呀?
回复

使用道具 举报

32#
ID:446775 发表于 2020-10-24 17:30 | 只看该作者
jokez7 发表于 2020-10-23 22:41
你定时器工作模式设置错误,设置在模式0,是13位计数器,应该设置成模式1;TMOD&=0xf0;TMOD|=0x01;

我使用的是STC15系列的单片机,模式配置跟51系列的不太一样哦
回复

使用道具 举报

33#
ID:446775 发表于 2020-10-24 17:31 | 只看该作者
jokez7 发表于 2020-10-23 22:44
你T0工作模式设置错误,应设置成模式1

void Timer0Init()

谢谢您,这个是STC89C51系列的模式配置方式,我使用的是STC15系列的单片机
回复

使用道具 举报

34#
ID:401564 发表于 2020-10-24 19:09 | 只看该作者
哥们你整这玩意好几天了都没有搞定吗?这根本不是什么特困难的事呀
你始终没有把完整的代码和仿真图上传上来,都N个网友分析来分析去,谁也不知道是你什么代码
这个是很基础的东西,手头上要是有个学习板和一个LED,可以自己单独写一个定时器中断程序,LED每1秒取反一次,不需要什么工具就可以看出来你定时器设定的时间对不对
这只是一个仿真问题,很多人可能觉得:仿真都不行,那实物更不行了,实际上却是:用了STC的单片机,在时间一类的仿真结果一定是和实际结果不一样的,那还不如直接烧录验证
回复

使用道具 举报

35#
ID:446775 发表于 2020-10-25 23:11 | 只看该作者
Y_G_G 发表于 2020-10-24 19:09
哥们你整这玩意好几天了都没有搞定吗?这根本不是什么特困难的事呀
你始终没有把完整的代码和仿真图上传上 ...

STC的单片机,在时间一类的仿真结果确实是和实际结果不一样的,但不至于相差太多,这个我也尝试过了,现在的问题是我仿真STC89C52的定时器中断,就没有问题,但是仿真STC15的定时器中断就有问题
回复

使用道具 举报

36#
ID:446775 发表于 2020-10-27 09:05 | 只看该作者
Y_G_G 发表于 2020-10-24 19:09
哥们你整这玩意好几天了都没有搞定吗?这根本不是什么特困难的事呀
你始终没有把完整的代码和仿真图上传上 ...

昨天又试了下,发现在KEIL中模型选择89C2就可以正常使用,但是只能使用定时器的16位计数的12T模式,当然这跟使用的模型有关,但是选择STC15系列的模型,定时器就不能正常计数,是不是我这个KEIL软件有问题啊,还有就是STC官方给出的范例,头文件调用的是“reg51.h”,这个头文件里有缺省的15系列的寄存器,所以在程序里要进行sfr和初始化,那么15系列的现在也有专用的头文件了,里面就包含了这些寄存器的sfr,调用这个头文件库应该跟之前的调用"reg51.h"再sfr和初始化效果是一样的吧?
回复

使用道具 举报

37#
ID:401564 发表于 2020-10-27 09:43 | 只看该作者
karolyte 发表于 2020-10-25 23:11
STC的单片机,在时间一类的仿真结果确实是和实际结果不一样的,但不至于相差太多,这个我也尝试过了,现 ...

这个时间不一样就是不一样的,没有什么多不多的问题,编程是一个严谨的东西,不是说差不多或者什么的就可以了
在实际应用中,最终要求的结果一定是以实际测试的结果为准的,不管你仿真出来怎样的数据,最终还是要实际测试的,那仿真的意义何在呢?
如果你一定要仿真,那也没有问题,但是,你始终没有代码出来,都是靠网友去猜的,这就是为什么一个一直搞不定有原因
KEIL不管是用STC什么型号,它都是以8051为内核运行的,这15系列和89系列还T0定时器上的应用是一样的,进入T0定时器中断的时序是这样的:1:关闭TR0,2:赋值两个定时器的值,3开启TR0并返回
回复

使用道具 举报

38#
ID:828632 发表于 2020-10-27 10:26 | 只看该作者
karolyte 发表于 2020-10-27 09:05
昨天又试了下,发现在KEIL中模型选择89C2就可以正常使用,但是只能使用定时器的16位计数的12T模式,当然 ...

使用15W你要用   15W.H  头文件   用51.h  是不行的
回复

使用道具 举报

39#
ID:451718 发表于 2020-10-27 11:52 | 只看该作者
仿真的坑很多的,测试定时器,我一般都是在定时器里面这样做的
void t1int() interrupt 3       
{
        P10 = 1;

        SysTick++;
  if(SysTick%1000 == 0)SysTickSec++;       

        if(DIR==0)
        {
                  if(MotoTick<=60)
                        {                               
                                switch(MotoTick)
                                {
                                        case 0:
                                                PWM_Init(7200);
                                        break;
                                        case 10:
                                                PWM_Init(5400);
                                                break;
                                        case 25:
                                                PWM_Init(4200);
                                                break;
                                        case 35:
                                                PWM_Init(5400);
                                                break;
                                        case 50:
                                                PWM_Init(7200);
                                                break;
                                }
                                MotoTick++;
                        }
                        else
                        {
                                MotoTick = 0;
                                DIR = 1;
                        }
        }
        else if(DIR==1)
        {
                  if(MotoTick<=55)
                        {
                                switch(MotoTick)
                                {
                                        case 0:
                                                PWM_Init(7200);
                                        break;
                                        case 10:
                                                PWM_Init(5400);
                                        break;
                                        case 25:
                                                PWM_Init(4200);
                                        break;
                                        case 30:
                                                PWM_Init(5400);
                                        break;
                                        case 45:
                                                PWM_Init(7200);
                                        break;
                                }
                                MotoTick++;
                        }
                        else
                        {
                                MotoTick = 0;
                                DIR = 0;
                        }
        }
  P10 = 0;
}

用示波器看看P10的波形,定时器周期和定时器效率都一目了然了。毕竟是做实物,不要在软件层面去纠结。退一万步说,你用的是有版权的软件么?
回复

使用道具 举报

40#
ID:446775 发表于 2020-10-27 14:40 | 只看该作者
Y_G_G 发表于 2020-10-27 09:43
这个时间不一样就是不一样的,没有什么多不多的问题,编程是一个严谨的东西,不是说差不多或者什么的就可以 ...

不是说不发代码,您需要看的代码是那一部分的,我这边截取一下给您发过来
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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