找回密码
 立即注册

QQ登录

只需一步,快速开始

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

请教各位大师,为何以下简单的单片机程序执行M2电机异常?

[复制链接]
跳转到指定楼层
楼主
单片机用的是STC12C2052AD,时延子函数是STC-ISP(V6.88)自动计算出来的,用12M的外部晶振。用STC12C2052AD+L298N去控制12V直流电机执行动作,使用的测试电源是正常的。

程序执行后期望达到的目的:
1、当SS1启动开关被触发一下后,在SW4未被按下之前,M2电机保持运行。
2、SW4被按下后,M2电机停止运行4秒钟。
3、M2电机恢复运行,直至SW3被按压下后停止运行,回到初始状态。

程序运行后,测试了一百次,有六十多次都是可以正常运行的,其他几十次不正常。很多次都是在SW4还未被按压,M2电机运行一会儿后暂停,然后再运行到SW4被压下后不再执行程序下半部分。当出现M2电机异常暂停这种情况后,用万用表测试单片机运行时I/O脚的电压,发现P1^5引脚的电压还是保持在+5V,而P1^2输出已经是0V,请问这个是啥原因呢?


单片机程序如下
#include<STC12C2052AD.H> //头文件
#define uchar unsigned char
#define uint unsigned intsbit M2F=P1^2;
sbit M2F=P1^2;
sbit M2B=P1^3;
sbit SS1=P1^7;            //定义启动开关
sbit SW3=P1^4;                  //定义剪切原位感应开关
sbit SW4=P1^5;                  //定义剪切限位感应开关

void Delay200ms()                //@12.000MHz
{
        unsigned char i, j, k;

        i = 10;
        j = 31;
        k = 147;
        do
        {
                do
                {
                        while (--k);
                } while (--j);
        } while (--i);
}

void Delay1000ms()                //@12.000MHz
{
        unsigned char i, j, k;

        i = 46;
        j = 153;
        k = 245;
        do
        {
                do
                {
                        while (--k);
                } while (--j);
        } while (--i);
}

void Delay4000ms()                //@12.000MHz
{
        unsigned char i, j, k;

        i = 183;
        j = 100;
        k = 225;
        do
        {
                do
                {
                        while (--k);
                } while (--j);
        } while (--i);
}

void main()        //主函数
{
        SS1=1;                                                                         //启动开关初值置1
        SW4=1;                                                                         //剪切限位感应开关置1
        M2F=0;                                                                         //剪切电机正极置0
        M2B=0;                                                                         //剪切电机负极置0
        if(SS1==0)               //判断启动开关被按下
        {                                         
        while(SW4)                //剪切限位感应开关被按下之前执行以下代码
        {                  
        M2F=1;                   //启动M2电机
        }
        M2F=0;          //暂停M2电机
        Delay4000ms();
        while(SW3)                //剪切限位感应开关被按下后执行以下两行代码
        {   
        M2F=1;                                                                   //剪切原位感应开关未按下之前执行行代码
        Delay200ms();
        }
        M2F=0;                                                                         //停止M2电机
  Delay1000ms();
        }
}
         

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:213173 发表于 2021-3-24 15:51 | 只看该作者
程序没有限制在主循环while(1)内运行,会跑飞。
  1. #include<STC12C2052AD.H> //头文件
  2. #define uchar unsigned char
  3. #define uint unsigned intsbit M2F=P1^2;
  4. sbit M2F=P1^2;
  5. sbit M2B=P1^3;
  6. sbit SS1=P1^7;            //定义启动开关
  7. sbit SW3=P1^4;                  //定义剪切原位感应开关
  8. sbit SW4=P1^5;                  //定义剪切限位感应开关

  9. void Delay200ms()                //@12.000MHz
  10. {
  11.         unsigned char i, j, k;

  12.         i = 10;
  13.         j = 31;
  14.         k = 147;
  15.         do
  16.         {
  17.                 do
  18.                 {
  19.                         while (--k);
  20.                 } while (--j);
  21.         } while (--i);
  22. }

  23. void Delay1000ms()                //@12.000MHz
  24. {
  25.         unsigned char i, j, k;

  26.         i = 46;
  27.         j = 153;
  28.         k = 245;
  29.         do
  30.         {
  31.                 do
  32.                 {
  33.                         while (--k);
  34.                 } while (--j);
  35.         } while (--i);
  36. }

  37. void Delay4000ms()                //@12.000MHz
  38. {
  39.         unsigned char i, j, k;

  40.         i = 183;
  41.         j = 100;
  42.         k = 225;
  43.         do
  44.         {
  45.                 do
  46.                 {
  47.                         while (--k);
  48.                 } while (--j);
  49.         } while (--i);
  50. }

  51. void main()        //主函数
  52. {
  53.         SS1=1;                 //启动开关初值置1
  54.         SW4=1;                 //剪切限位感应开关置1
  55.         M2F=0;                 //剪切电机正极置0
  56.         M2B=0;                 //剪切电机负极置0
  57.         while(1)
  58.         {
  59.                 if(SS1==0)             //判断启动开关被按下
  60.                 {                                         
  61.                         while(SW4)          //剪切限位感应开关被按下之前执行以下代码
  62.                         {                  
  63.                                 M2F=1;           //启动M2电机
  64.                         }
  65.                         M2F=0;                          //暂停M2电机
  66.                         Delay4000ms();
  67.                         while(SW3)           //剪切限位感应开关被按下后执行以下两行代码
  68.                         {   
  69.                                 M2F=1;            //剪切原位感应开关未按下之前执行行代码
  70.                                 Delay200ms();
  71.                         }
  72.                         M2F=0;               //停止M2电机
  73.                         Delay1000ms();
  74.                 }
  75.         }
  76. }
复制代码

回复

使用道具 举报

板凳
ID:889206 发表于 2021-3-24 15:59 | 只看该作者
wulin 发表于 2021-3-24 15:51
程序没有限制在主循环while(1)内运行,会跑飞。

谢谢您的指导,我改一下试试。
回复

使用道具 举报

地板
ID:889206 发表于 2021-3-24 16:33 | 只看该作者
wulin 发表于 2021-3-24 15:51
程序没有限制在主循环while(1)内运行,会跑飞。

测试了,收效不大。还是多次出现没到SW4,M2已停止的问题。
回复

使用道具 举报

5#
ID:889206 发表于 2021-3-24 16:38 | 只看该作者
wulin 发表于 2021-3-24 15:51
程序没有限制在主循环while(1)内运行,会跑飞。

是否需要在下载程序时,硬件选项上增加看门狗参数的设置?当前状态没有对勾选这两个选项。
回复

使用道具 举报

6#
ID:213173 发表于 2021-3-24 17:30 | 只看该作者
kpljn 发表于 2021-3-24 16:38
是否需要在下载程序时,硬件选项上增加看门狗参数的设置?当前状态没有对勾选这两个选项。

这样的程序不能用看门狗,更乱套。
回复

使用道具 举报

7#
ID:213173 发表于 2021-3-24 21:49 | 只看该作者
kpljn 发表于 2021-3-24 16:33
测试了,收效不大。还是多次出现没到SW4,M2已停止的问题。

这里还有问题#define uint unsigned intsbit M2F=P1^2;
应该#define uint unsigned int
回复

使用道具 举报

8#
ID:889206 发表于 2021-3-24 21:59 | 只看该作者
wulin 发表于 2021-3-24 21:49
这里还有问题#define uint unsigned intsbit M2F=P1^2;
应该#define uint unsigned int

笔误而已,实际程序是按照您这个标准写的。
回复

使用道具 举报

9#
ID:889206 发表于 2021-3-24 22:04 | 只看该作者
现在出现好多次要按着启动开关不放好几秒钟,程序才会执行的问题。
回复

使用道具 举报

10#
ID:889206 发表于 2021-3-24 22:15 | 只看该作者

主函数调整为以下的流程,电机的动作更迟钝,很多次都需要长按启动开关不放手才开始动作。。。。

void main()        //主函数
{
        SS1=0;                                                                        //启动开关初值置0------这里修改了
        SW4=0;                                                                         //剪切限位感应开关置0------这里修改了
        M2F=0;                                                                         //剪切电机正极置0
        M2B=0;                                                                         //剪切电机负极置0
        while(1)
        {
        if(SS1==!0)                //判断启动开关被按下------这里修改了
{     //------这里修改了
        while(!SW4)                //剪切限位感应开关被按下之前执行以下代码------这里修改了
        {                  
        M2F=1;                   //启动M2电机
        }
                M2F=0;        //暂停M2电机
}     //------这里修改了
        Delay4000ms();
        while(SW3)                //剪切限位感应开关被按下后执行以下两行代码
        {   
        M2F=1;                                                                   //剪切原位感应开关未按下之前执行行代码
        Delay200ms();
        }
        M2F=0;                                                                         //停止M2电机
  Delay1000ms();
       
}
}        
回复

使用道具 举报

11#
ID:213173 发表于 2021-3-24 22:18 | 只看该作者
kpljn 发表于 2021-3-24 22:15
主函数调整为以下的流程,电机的动作更迟钝,很多次都需要长按启动开关不放手才开始动作。。。。

void ...

改这样试试
  1. #include<STC12C2052AD.H> //头文件

  2. #define uchar unsigned char
  3. #define uint unsigned int

  4. sbit M2F=P1^2;
  5. sbit M2B=P1^3;
  6. sbit SS1=P1^7;            //定义启动开关
  7. sbit SW4=P1^5;            //定义剪切限位感应开关
  8. sbit SW3=P1^4;            //定义剪切原位感应开关

  9. uint time;
  10. uchar count,num;
  11. bit lock;

  12. void Timer0Init()        //10毫秒@12.000MHz
  13. {
  14.         TMOD= 0x01;                //设置定时器模式
  15.         TL0 = 0xF0;                //设置定时初值
  16.         TH0 = 0xD8;                //设置定时初值
  17.         TF0 = 0;                        //清除TF0标志
  18.         TR0 = 1;                        //定时器0开始计时
  19. }

  20. void main()        //主函数
  21. {
  22.         SS1=1;                 //启动开关初值置1
  23.         SW4=1;                 //剪切限位感应开关置1
  24.         M2F=0;                 //剪切电机正极置0
  25.         M2B=0;                 //剪切电机负极置0
  26.         Timer0Init();       
  27.         while(1)
  28.         {
  29.                 if(TF0==1)
  30.                 {
  31.                         TF0=0;
  32.                         TL0 = 0xF0;                //设置定时初值
  33.                         TH0 = 0xD8;                //设置定时初值

  34.                         if(!SS1||!SW4||!SW3)
  35.                         {
  36.                                 if(++count>=2 && lock==0)//20ms防抖
  37.                                 {
  38.                                         lock=1;
  39.                                         if(!SS1) num=1;

  40.                                         if(!SW4)
  41.                                         {
  42.                                                 num=2;
  43.                                                 time=0;
  44.                                         }

  45.                                         if(!SW3) num=3;
  46.                                 }
  47.                         }
  48.                         else
  49.                         {
  50.                                 count=0;
  51.                                 lock=0;
  52.                         }

  53.                         if(num==1)
  54.                         {
  55.                                 M2F=1;           //启动M2电机
  56.                                 num=0;
  57.                         }
  58.                         if(num==2)
  59.                         {
  60.                                 time++;
  61.                                 if(time<400)
  62.                                 {       
  63.                                         M2F=0;           //暂停M2电机
  64.                                 }
  65.                                 else
  66.                                 {
  67.                                         M2F=1;                        //暂停4秒后继续运转
  68.                                         num=0;
  69.                                 }
  70.                         }
  71.                         if(num==3)
  72.                         {
  73.                                 M2F=0;         //停止M2电机
  74.                                 num=0;
  75.                         }
  76.                 }
  77.         }
  78. }
复制代码



回复

使用道具 举报

12#
ID:889206 发表于 2021-3-24 22:33 | 只看该作者

谢谢您的指导,我试一下。
回复

使用道具 举报

13#
ID:383215 发表于 2021-3-24 22:42 | 只看该作者
按键去抖动都没有,可能是程序不稳定的原因之一,M2是什么电机?是否会干扰单片机?我最近也想试试STC单片机,主要就是测试抗干扰能力,我用AVR单片机控制385水泵,也就是385电机,有6个按键开关,从来没有发生过程序不稳定的情况,如果STC单片机可以做到,我就用STC单片机,做不到继续使用AVR单片机。
回复

使用道具 举报

14#
ID:889206 发表于 2021-3-24 23:11 | 只看该作者
kmsj 发表于 2021-3-24 22:42
按键去抖动都没有,可能是程序不稳定的原因之一,M2是什么电机?是否会干扰单片机?我最近也想试试STC单片 ...

应该和去抖没啥关系吧,因为按流程来说,只要启动开关SS1状态被触发之后,程序就应该执行SS1=1这个条件内的While(SW4)内嵌语句了,在SW4未变为0时,M2电机应该一直是保持运行才对。现在测试的M2是普通12V直流电机,安装位置与单片机有一定的距离,电路板也测试过了,电机运行时或状态变化时,单片机VCC电压一直是4.998V至5V左右。
回复

使用道具 举报

15#
ID:889206 发表于 2021-3-24 23:45 | 只看该作者

老师您好,测试了,电机无法启动。
回复

使用道具 举报

16#
ID:213173 发表于 2021-3-25 06:37 | 只看该作者
kpljn 发表于 2021-3-24 23:45
老师您好,测试了,电机无法启动。

把硬件图发上来看看。从你表述情况很像环境干扰导致异常,可以把电机换成LED或灯泡试试。
回复

使用道具 举报

17#
ID:889206 发表于 2021-3-25 08:02 | 只看该作者
wulin 发表于 2021-3-25 06:37
把硬件图发上来看看。从你表述情况很像环境干扰导致异常,可以把电机换成LED或灯泡试试。

是呀,我也怀疑是电路的问题,现在订了两片最小系统,到货后重新再测试。
回复

使用道具 举报

18#
ID:383215 发表于 2021-3-25 10:41 | 只看该作者
kpljn 发表于 2021-3-24 23:11
应该和去抖没啥关系吧,因为按流程来说,只要启动开关SS1状态被触发之后,程序就应该执行SS1=1这个条件内 ...

只要是按键,就必须去抖动,这是最最基本的常识,连按键去抖动都懒得编,编程还有什么意义?按键去抖动能有多难编?M2是普通12V直流电机,我用的385水泵电机也是12V直流电机,我的电路分别控制一个385水泵电机、可控硅触发、可控硅击穿检测、继电器切断可控硅、HX711重量传感器,两个18B20、6个RH6030感应式按键、12个数码管,比你的电路复杂好几倍,运行了三年多,从来没有发现程序不稳定的现象,6个RH6030感应式按键照样用了编程去抖动,一巴掌按上去都不会产生干扰,你这个电路最大问题就是电机是否会干扰STC单片机,确实本论坛有人反映电机会干扰STC单片机,那只有换单片机了,我知道AVR单片机的抗干扰能力很强,最强的是PIC单片机我没有用过,STC单片机的抗干扰能力我还没有测试,一看你的程序结构就不对,我的程序也比你这个复杂好几倍,一共编了2000多行,5K多的程序,编下来也很轻松啊,你要细化到步,用步骤式编程,是化繁为简的最佳方法,你这个程序,我几分钟之内就可以搞定,我把我的程序复制修改一下就完事了。本论坛不能直接给程序,我也只能提醒到这里,你自己慢慢搞定。
回复

使用道具 举报

19#
ID:143767 发表于 2021-3-25 13:45 | 只看该作者
跟马达干扰系统有很大关系,试试如下图防干扰:


回复

使用道具 举报

20#
ID:889206 发表于 2021-3-25 14:01 | 只看该作者
kmsj 发表于 2021-3-25 10:41
只要是按键,就必须去抖动,这是最最基本的常识,连按键去抖动都懒得编,编程还有什么意义?按键去抖动能 ...

谢谢您的指点,不去抖动的主要原因是刚学单片机和C语言,很多知识点还没弄明白,就如时延和时钟这两个知识点,我也是在这个程序的测试中明白了大概的区别。另外,我也很想您再指导一下,我写的这个程序的结构错误位置在哪里?因为新手的知识有限,就算是写错了,也不知道错误在哪里。再次感谢您的指导。
回复

使用道具 举报

21#
ID:889206 发表于 2021-3-25 21:43 | 只看该作者
dj3365191 发表于 2021-3-25 13:45
跟马达干扰系统有很大关系,试试如下图防干扰:

谢谢您的指导,我增加这三个电容试试。
回复

使用道具 举报

22#
ID:889206 发表于 2021-3-25 21:55 | 只看该作者
dj3365191 发表于 2021-3-25 13:45
跟马达干扰系统有很大关系,试试如下图防干扰:

回想了一下电机的特性,电机动作有问题。很有可能是电机造成。因为作为感性元件,当输入端电流突变时,会产生反电动势,干扰单片机电源。
回复

使用道具 举报

23#
ID:889206 发表于 2021-3-26 00:42 | 只看该作者

老师您好,我是刚学单片机和C语言的,知识有限。今天分析了您写的程序的思路,以下是我的理解,不知道是否理解正确。理解有误和不明白的地方请再多多指导:
1、单片机启动内部时钟,8位置0,开始死循环,时钟溢出一次后,溢出标志位置0,内8位置0,重新执行。
2、单片机在主线程继续同步执行由40行开始的代码,扫描在SS1或SW4或SW3任一条件为0的基础上,设置三个状态条件,分别满足时各个条件下需执行的各组动作,要是不满足三个条件,count和lock置0。
这一段里面,还没办法理解的有多处:第42行代码是如何实现20ms时延(++count在何处执行了?是否在IF语句里面可以合并后简写?)、第44行的代码的目的是啥?、第50行的代码是否对内时钟8位全置0?)、58和59行的count和lock置0有啥用?
3、主程序执行满足扫描外部开关状态条件下面的三组动作。
这一段里面,还没办法理解也有多处:第65行77行83行的作用是啥?
回复

使用道具 举报

24#
ID:213173 发表于 2021-3-26 07:57 | 只看该作者
kpljn 发表于 2021-3-26 00:42
老师您好,我是刚学单片机和C语言的,知识有限。今天分析了您写的程序的思路,以下是我的理解,不知道是 ...

由于你的目的是通过3个开关控制电机的开停且有随时间变化的要求。你的原程序从逻辑上没有问题,但实现的方法不妥。阻滞型延时方式是迫使MCU原地踏步等待,有其它事件发生MCU不会做出响应,这只适合作短暂计时。大于ms级计时就要使用定时器,不但准确而且不会耽误其它程序执行。在此使用了定时器查询方式if(TF0==1),MCU在主循环while(1)内可以做很多很多事情。这里只占用几us到几十us,只有当TF0==1时(每隔10ms)才执行其{ }内任务。这里任务分两块,1.判断3个开关状态,满足条件继续执行,否则退出。当++count>=2两次满足条件证明确实有按键操作不是干扰和抖动再结合lock状态判断有效,继续执行。因为lock=1;就把此次扫描按键状态锁定,不会因不松手又按其它键导致错误。松手后count和lock清0。2.按照键值num执行相应任务。任务完成num清0。time是计时变量,可以正计时也可以倒计时,在这里使用前者。不论如何在使用前要赋初值。
回复

使用道具 举报

25#
ID:889206 发表于 2021-3-26 09:13 | 只看该作者
wulin 发表于 2021-3-26 07:57
由于你的目的是通过3个开关控制电机的开停且有随时间变化的要求。你的原程序从逻辑上没有问题,但实现的 ...

非常感谢您的解答,拜读了您的方案让我理解好几个模糊的概念。我本来的目的是控制两个直流电机依次执行动作的,在一开始写的函数也是用条件语句结合定时器去控制,但很多概念类的知识还没弄清楚,所以初始版本的程序的执行结果就是动作不受控制(特别是在时延4秒这个节点上不好把握)。针对上述情况,我把难度降低了一点,先从控制一个电机入手。然后就如您所说的那样,选用空计算的方式迫使MCU达到延时效果,计算完毕后,再执行下一步的有效动作。从流程上来看,我也知道我写的肯定是最笨的程序,因为根本就没有充分利用了MCU的能力,根本就没有拓展性。但这种写法难度很低,很适合我这种脑子里没啥干货的人,不需要涉及更多的知识点,几个动作依次执行,简单而粗暴。嘻嘻-------------------
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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