找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1209|回复: 11
收起左侧

51单片机计数器程序问题请教

[复制链接]
ID:1005338 发表于 2022-4-24 21:55 | 显示全部楼层 |阅读模式
我用计数器0对直流减速电机编码器计数,编码器每651个脉冲代表电机转动一圈,主函数通过计数器0的溢出标志位TR0变为1的次数,对电机的圈数进行累加、显示,但不知为什么,显示一直都是零,是计数器0一直就没有触发中断?还是程序设计有问题?求高手指点指点,谢谢!
单片机源程序如下:
#include "reg52.h"

typedef unsigned int u16;        //对系统默认数据类型进行重定义
typedef unsigned char u8;

//定义LED1管脚
sbit LED1=P2^0;

#define SMG_A_DP_PORT        P0        //使用宏定义数码管段码口

//定义数码管位选信号控制脚
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;



/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能                 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出             : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
        while(ten_us--);      
}

//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
                                0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};


/*******************************************************************************
* 函 数 名       : smg_display
* 函数功能                 : 动态数码管显示
* 输    入       : 无
* 输    出             : 无
*******************************************************************************/
void smg_display(u8 dat[])
{
        u8 i=0;

        for(i=0;i<8;i++)
        {
                   switch(i)//位选
                {
                        case 0: LSC=1;LSB=1;LSA=1;SMG_A_DP_PORT=gsmg_code[dat[0]];break;
                        case 1: LSC=1;LSB=1;LSA=0;SMG_A_DP_PORT=gsmg_code[dat[1]];break;
                        case 2: LSC=1;LSB=0;LSA=1;SMG_A_DP_PORT=gsmg_code[dat[2]];break;
                        case 3: LSC=1;LSB=0;LSA=0;SMG_A_DP_PORT=gsmg_code[dat[3]];break;
                        case 4: LSC=0;LSB=1;LSA=1;SMG_A_DP_PORT=gsmg_code[dat[4]];break;
                        case 5: LSC=0;LSB=1;LSA=0;SMG_A_DP_PORT=gsmg_code[dat[5]];break;
                        case 6: LSC=0;LSB=0;LSA=1;SMG_A_DP_PORT=gsmg_code[dat[6]];break;
                        case 7: LSC=0;LSB=0;LSA=0;SMG_A_DP_PORT=gsmg_code[dat[7]];break;
                }
                delay_10us(20);//延时一段时间,等待显示稳定
                SMG_A_DP_PORT=0x00;//消音
        }
}


/*******************************************************************************
* 函 数 名       : time0_init
* 函数功能                 : 定时器0中断配置函数,通过设置TH和TL即可确定定时时间
* 输    入       : 无
* 输    出             : 无
*******************************************************************************/
void counter0_init(void)
{
        TMOD|=0X05;//选择为计数器0模式,工作方式1
        TH0=0XFD;        //给计数器赋初值
        TL0=0X71;      
        ET0=1;//打开计数器0中断允许
        EA=1;//打开总中断
        TR0=1;//打开计数器
        IT0=0;//下降沿触发               
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能                 : 主函数
* 输    入       : 无
* 输    出             : 无
*******************************************************************************/
void main()
{      
        u16 roll;
        u8 rollb8[8];

        counter0_init();//计数器0中断配置

        while(1)
        {                       
                if(TF0==1)
                {
                        roll++;
                        TF0=0;
                }
                rollb8[3]=roll/10000;                        //读取万位数
                rollb8[4]=roll%10000/1000;                //读取千位数
                rollb8[5]=roll%1000/100;                  //读取百位数
                rollb8[6]=roll%100/10;                           //读取十位数
                rollb8[7]=roll%10;                                     //读取个位数
                smg_display(rollb8);                        //调用数码管显示
                                               
        }               
}

void conter0() interrupt 1 //定时器0中断函数
{
        TH0=0XFD;        //给计数器赋初值
        TL0=0X71;
}
回复

使用道具 举报

ID:1005338 发表于 2022-4-24 22:28 | 显示全部楼层
调试后发现,确定是计数器0溢出后,TF0不会自动置1,这到底是什么原因?
回复

使用道具 举报

ID:624769 发表于 2022-4-24 22:58 来自手机 | 显示全部楼层
你开了中断,tf0会自动清0,你要做个标志位,在中断里置1,然后主程序判断这个标志位。
回复

使用道具 举报

ID:1005338 发表于 2022-4-24 23:41 | 显示全部楼层
188610329 发表于 2022-4-24 22:58
你开了中断,tf0会自动清0,你要做个标志位,在中断里置1,然后主程序判断这个标志位。

不好意思,我是初学,没太理解你的意思,请您再帮忙指点一下:
先开的中断,然后开始while死循环,等待计数器溢出,溢出后TF0不就应该自动置1吗?TF0不就是溢出的标志位吗?
回复

使用道具 举报

ID:624769 发表于 2022-4-25 00:07 来自手机 | 显示全部楼层
niejiangong 发表于 2022-4-24 23:41
不好意思,我是初学,没太理解你的意思,请您再帮忙指点一下:
先开的中断,然后开始while死循环,等待 ...

tf0==1之后,就会立刻执行中断程序,中断程序会自动清0标志tf0,即,你只要开了定时器0的中断,你就永远读不到tf0==1。tf会等于1一瞬间,但是你永远看不到,当你去判断的时候,tf0一定已经变0了,明白了么?
回复

使用道具 举报

ID:1005338 发表于 2022-4-25 12:03 | 显示全部楼层
188610329 发表于 2022-4-25 00:07
tf0==1之后,就会立刻执行中断程序,中断程序会自动清0标志tf0,即,你只要开了定时器0的中断,你就永远 ...

非常感谢您的耐心指点!我还有疑惑:
一、既然开了定时器0的中断,无法读到TF0==1,那这个TF0标志位不是失去存在的意义了吗?
二、有没有什么办法来利用这个TF0标志位呢?
三、如果TF0不能用,通常用哪个寄存器来做标志位比较好?是不是需要定义一个全局变量?
回复

使用道具 举报

ID:213173 发表于 2022-4-25 14:35 | 显示全部楼层
niejiangong 发表于 2022-4-25 12:03
非常感谢您的耐心指点!我还有疑惑:
一、既然开了定时器0的中断,无法读到TF0==1,那这个TF0标志位不是 ...

使用定时器分查询方式和中断方式。如果用查询方式,TF0是要软件清0。使用中断方式TF0由硬件自动清0。两者不可以同时使用。在楼主此应用中不宜使用查询方式。因为电机转速可能超过主循环周期,就有可能丢失数据。给你把程序改了,你试试。
  1. #include "reg52.h"

  2. typedef unsigned int u16;        //对系统默认数据类型进行重定义
  3. typedef unsigned char u8;

  4. //定义LED1管脚
  5. sbit LED1=P2^0;

  6. #define SMG_A_DP_PORT P0        //使用宏定义数码管段码口

  7. //定义数码管位选信号控制脚
  8. sbit LSA=P2^2;
  9. sbit LSB=P2^3;
  10. sbit LSC=P2^4;

  11. //共阴极数码管显示0~F的段码数据
  12. u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
  13.                   0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
  14. u16 count=0;
  15. u8  rollb8[8];
  16. /*******************************************************************************
  17. * 函 数 名       : delay_10us
  18. * 函数功能       : 延时函数,ten_us=1时,大约延时10us
  19. * 输    入       : ten_us
  20. * 输    出       : 无
  21. *******************************************************************************/
  22. /*
  23. void delay_10us(u16 ten_us)
  24. {
  25.         while(ten_us--);      
  26. }*/
  27. /*******************************************************************************
  28. * 函 数 名       : smg_display
  29. * 函数功能       : 动态数码管显示
  30. * 输    入       : 无
  31. * 输    出       : 无
  32. *******************************************************************************/
  33. void smg_display()
  34. {
  35.         static u8 i=0;
  36.         u8 j=0;
  37.         u16 k;//缓冲变量
  38.         k=count;       
  39.         for(j=0;j<5;j++)
  40.         {
  41.                 rollb8[j]=k%10;//由低位到高位分解保存
  42.                 k/=10;
  43.         }
  44.         SMG_A_DP_PORT=0x00;//段消隐
  45.         P2&=0xe3;//位清除
  46.         P2|=i<<2;//送位码
  47.         SMG_A_DP_PORT=gsmg_code[rollb8[i]];//送段码
  48.         i=++i%5;//循环计数
  49. }
  50. /*******************************************************************************
  51. * 函 数 名       : time0_init
  52. * 函数功能       : 定时器0中断配置函数,通过设置TH和TL即可确定定时时间
  53. * 输    入       : 无
  54. * 输    出       : 无
  55. *******************************************************************************/
  56. void counter0_init(void)
  57. {
  58.         TMOD|=0X05;//选择为计数器0模式,工作方式1
  59.         TH0=0XFD;  //给计数器赋初值65536-651
  60.         TL0=0X75;      
  61.         TF0=0;
  62.         TR0=1;        //打开计数器
  63.         ET0=1;        //打开计数器0中断允许
  64.         EA=1;        //打开总中断
  65. //        IT0=0;        //下降沿触发               
  66. }
  67. /*******************************************************************************
  68. * 函 数 名       : main
  69. * 函数功能       : 主函数
  70. * 输    入       : 无
  71. * 输    出       : 无
  72. *******************************************************************************/
  73. void main()
  74. {      
  75.         counter0_init();//计数器0中断配置
  76.         while(1)
  77.         {                       
  78.                 smg_display();
  79.         }
  80. }

  81. void conter0() interrupt 1 //定时器0中断函数
  82. {
  83.         TH0=0xfd;        //给计数器赋初值
  84.         TL0=0x75;
  85.         count++;
  86.         if(count>50000)//限制最大数
  87.                 count=0;
  88. }
复制代码




回复

使用道具 举报

ID:624769 发表于 2022-4-25 14:52 来自手机 | 显示全部楼层
niejiangong 发表于 2022-4-25 12:03
非常感谢您的耐心指点!我还有疑惑:
一、既然开了定时器0的中断,无法读到TF0==1,那这个TF0标志位不是 ...

1)  tf0标志,是定时器中断触发的重要标志,怎么会没有意义?
2) 你不开中断(et0=0),就能读到tf0==1了。
3) 在板凳的回复已经说了,声明一个全局标志位,在中断里置1,主程序里面判断这个标志来取代判断tf0。
回复

使用道具 举报

ID:1005338 发表于 2022-4-25 17:21 | 显示全部楼层
wulin 发表于 2022-4-25 14:35
使用定时器分查询方式和中断方式。如果用查询方式,TF0是要软件清0。使用中断方式TF0由硬件自动清0。两者 ...

我试了一下,完全正确!水平太高了。
回复

使用道具 举报

ID:149451 发表于 2022-4-26 17:18 | 显示全部楼层
wulin 发表于 2022-4-25 14:35
使用定时器分查询方式和中断方式。如果用查询方式,TF0是要软件清0。使用中断方式TF0由硬件自动清0。两者 ...

菜鸟晕了,求指点。
楼主说是“对直流减速电机编码器计数”,那么旋转编码端子没定义,是因为用了“TMOD|=0X05;//选择为计数器0模式,工作方式1”,编码器端子自然要接入P3.2,不用在程序里表明了?
回复

使用道具 举报

ID:161164 发表于 2022-4-27 11:52 | 显示全部楼层
w1179benp 发表于 2022-4-26 17:18
菜鸟晕了,求指点。
楼主说是“对直流减速电机编码器计数”,那么旋转编码端子没定义,是因为用了“TMOD ...

P3.4才对 2022-04-27_115125.png

回复

使用道具 举报

ID:1005338 发表于 2022-5-22 12:56 | 显示全部楼层
w1179benp 发表于 2022-4-26 17:18
菜鸟晕了,求指点。
楼主说是“对直流减速电机编码器计数”,那么旋转编码端子没定义,是因为用了“TMOD ...

编码器的端子直接接入P3.4,不用表明
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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