找回密码
 立即注册

QQ登录

只需一步,快速开始

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

制作单片机+红外+光敏模块操控步进电机,现在光敏自动控制出了点问题,求大佬

[复制链接]
跳转到指定楼层
楼主
ID:889445 发表于 2021-4-21 13:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
步进电机用的是ULN2003模块,光敏模块是LM393通过比较光敏电阻和变阻器的阻值,输出0,1信号。现在的问题是如果一开始光敏信号输入为1,电动机正转,光敏信号变为0时,电动机不反转。反之如果一开始为0,电机反转,改变光敏信号无反应。我觉着应该是光敏程序出了问题,光敏程序在下面117行求大佬指点。
单片机源程序如下:
  1. #include<reg52.h>    //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
  2. #define uchar unsigned char
  3. sbit IR=P3^2;  //红外接口标志
  4. sbit light=P2^3;//定义光敏模块信号输入口为P3-5
  5. sbit upswitch=P2^0;//定义上行程开关为s4
  6. sbit downswitch=P2^1;//定义下行程开关为s2

  7. unsigned char  irtime;//红外用全局变量

  8. bit irpro_ok,irok; //处理OK,接收OK
  9. unsigned char IRcord[4]; //定义ircord是4个数组构成的数字
  10. unsigned char irdata[33];//定义irdata是33个b组成的数据,
  11. unsigned char nt[8]={0x01,0x03,0x02,0x06,0x04,0x0c,0x08,0x09}; //顺时针旋转
  12. unsigned char st[8]={0x09,0x08,0x0c,0x04,0x06,0x02,0x03,0x01};//逆时针旋转表


  13. void delay(unsigned int n) //系统延时用于四步电机控制
  14. {
  15. unsigned int i=0,j=0;
  16. for(i=0;i<n;i++)
  17. {
  18.   for(j=0;j<120;j++);
  19. }
  20. }
  21. /*定时器0中断处理*/

  22. void tim0_isr (void) interrupt 1 using 1
  23. {
  24.   irtime++;  //用于计数2个下降沿之间的时间
  25. }

  26. /*外部中断0中断处理*/
  27. void EX0_ISR(void) interrupt 0 //外部中断0服务函数
  28. {
  29.   static unsigned char  i;             //接收红外信号处理
  30.   static bit startflag;                //是否开始处理标志位

  31. if(startflag)
  32.    {
  33.     if(irtime<63&&irtime>=33)//引导码 TC9012的头码,9ms+4.5ms 头码的持续时间的范围,33(8.448ms)<63(16.128ms),
  34.                         i=0;
  35.                     irdata[ i]=irtime;//存储每个电平的持续时间,用于以后判断是0还是1
  36.                     irtime=0;
  37.                     i++;
  38.                             if(i==33)          //33是33位的意思,包括32位的数据和一位的头码。
  39.                               {
  40.                                    irok=1;
  41.                                  i=0;
  42.                                   }
  43.           }
  44.            else
  45.                 {
  46.                 irtime=0;
  47.                 startflag=1;
  48.                 }

  49. }

  50. /*定时器0初始化*/
  51. void TIM0init(void)//定时器0初始化
  52. {

  53.   TMOD=0x02;//定时器0工作方式2,TH0是重装值,TL0是初值
  54.   TH0=0x00; //装初值
  55.   TL0=0x00;
  56.   ET0=1;    //开中断
  57.   TR0=1;
  58. }
  59. /*外部中断0初始化*/
  60. void EX0init(void)
  61. {
  62. IT0 = 1;   //指定外部中断0下降沿触发,INT0 (P3.2)
  63. EX0 = 1;   //打开外部中断
  64. EA = 1;    //开总中断
  65. }
  66. /*步进电机控制程序*/
  67. void stepperdown()//四相步进电机逆时针转
  68. {
  69. //  delay(10);加上就变成点动了
  70.   while(1)
  71. {
  72. int i=0;
  73. for(i=0;i<8;i++)
  74.    {
  75.   P1=nt[ i];
  76.   delay(2);//delay2这个时间差不多合适<2无法运行
  77.    }
  78. if(IR==0) //事实证明可行
  79. {
  80.   break;
  81. }
  82. }
  83. }


  84. void stepperup()//四相步进电机顺时针旋转
  85. {
  86.   while(1)
  87. {
  88. int i=0;
  89. for(i=0;i<8;i++)
  90.    {
  91.   P1=st[ i];
  92.   delay(2);//delay2这个时间差不多合适<2无法运行
  93.    }
  94. if(IR==0) //事实证明可行
  95. {
  96.   break;
  97. }
  98. }
  99. }
  100. void stepperstop()
  101. {
  102. P1=0x00;
  103. }

  104. /*光敏自动控制模式*/
  105. void lightmod()        //现在的问题:只走一个程序其他if语句完全没用
  106. {
  107. while(1)
  108. { if(light==1)
  109.     {
  110.           stepperup();
  111.         }
  112.    if(light==0)
  113.    {
  114.            stepperdown();
  115.    }

  116.    if(IR==0) //事实证明可行
  117.    {
  118.      break;
  119.    }
  120. }
  121. }

  122. /*原键值处理*/
  123. void Ir_work(void)//红外键值散转程序
  124. {
  125.                 P1=0x00;//初始化p1
  126.            switch(IRcord[2])//判断第三个数码前两个是用户码,最后一个是反码,第三个才是真正的数据码。
  127.                  {
  128.                          case 0x45:stepperdown();break;//- 按下遥控器上面0-9的按键,led亮起相应的数值
  129.                          case 0x47:stepperup();break;//+
  130.                          case 0x46:stepperstop();break;
  131.                          case 0x09:lightmod();break;
  132.              default:break;
  133.                          }


  134.                   irpro_ok=0;//处理完成标志

  135.   }



  136. /*红外码值处理*/
  137. void Irpro(void)//红外码值处理函数        分析出那些是1那些是0
  138. {
  139.   unsigned char i, j, k;
  140.   unsigned char cord,value;

  141.   k=1;        //前导码没数据,从第二个开始,就是用户码开始。
  142.   for(i=0;i<4;i++)      //处理4个字节
  143.      {
  144.       for(j=1;j<=8;j++) //处理1个字节8位。for语句:先执行j=1;在执行j<=8,为真则继续执行,否则结束执行;执行完循环体后执行j++,重复执行执行循环和j++直到j<=8为假
  145.          {
  146.           cord=irdata[k]; //
  147.           if(cord>7)  //低电平下降沿到下一个下降沿的宽度是0.56+0.565=1.125ms,高电平则是0.56+1.69=2.25ms,同样我们也给出一个范围用于区分它们,可以这样识别 (1.125ms + 2.25ms )/ 2=1.68ms,
  148.                        //大于1.68为高,小于1.68为低。
  149.                                   //假设使用12M晶振 定时器的单位数值时1us,使用8位定时器自动重装,将得到每个定时周期0.256ms的时长, 1.68/0.256=6.59,约等于7.也就是 定时器0计数次数。
  150.             value|=0x80;//最高位就给1,
  151.                         if(j<8)
  152.                     {
  153.                          value>>=1;
  154.                         }
  155.            k++;
  156.          }
  157.      IRcord[ i]=value;
  158.      value=0;
  159.      }
  160.          irpro_ok=1;//处理完毕标志位置1
  161. }

  162. /*主函数*/
  163. void main(void)
  164. {
  165. EX0init(); //初始化外部中断
  166. TIM0init();//初始化定时器
  167. while(1)//主循环
  168.    {
  169.     if(irok)                        //如果接收好了进行红外处理
  170.           {
  171.            Irpro();
  172.             irok=0;
  173.           }

  174.     if(irpro_ok)                   //如果处理好后进行工作处理,如按对应的按键后显示对应的数字等
  175.           {
  176.            Ir_work();

  177.             }

  178.    }
  179. }



  180.   }
复制代码

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

使用道具 举报

沙发
ID:889445 发表于 2021-4-21 18:10 | 只看该作者
过段时间把源码会分享出来,问题已解决
回复

使用道具 举报

板凳
ID:889445 发表于 2021-7-6 18:11 | 只看该作者
  1. #include<reg52.h>    //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
  2. #define uchar unsigned char
  3. sbit IR=P3^2;  //红外接口标志
  4. sbit light=P2^3;//定义光敏模块信号输入口为P3-5
  5. sbit upswitch=P3^4;//定义上行程开关为s4
  6. sbit downswitch=P3^5;//定义下行程开关为s2
  7. sbit IN1=P1^0;
  8. sbit IN2=P1^1;
  9. sbit IN3=P1^2;
  10. sbit IN4=P1^3;
  11. sbit ENA=P1^4;
  12. sbit ENB=P1^5;//定义l298n引脚

  13. unsigned char  irtime;//红外用全局变量

  14. bit irpro_ok,irok; //处理OK,接收OK
  15. unsigned char IRcord[4]; //定义ircord是4个数组构成的数字
  16. unsigned char irdata[33];//定义irdata是33个b组成的数据,

  17. void delay(unsigned int n) //系统延时用于四步电机控制
  18. {
  19. unsigned int i=0,j=0;
  20. for(i=0;i<n;i++)
  21. {
  22.   for(j=0;j<120;j++);
  23. }
  24. }
  25. /*定时器0中断处理*/

  26. void tim0_isr (void) interrupt 1 using 1
  27. {
  28.   irtime++;  //用于计数2个下降沿之间的时间
  29. }

  30. /*外部中断0中断处理*/
  31. void EX0_ISR(void) interrupt 0 //外部中断0服务函数
  32. {
  33.   static unsigned char  i;             //接收红外信号处理
  34.   static bit startflag;                //是否开始处理标志位

  35. if(startflag)                        
  36.    {
  37.     if(irtime<63&&irtime>=33)//引导码 TC9012的头码,9ms+4.5ms 头码的持续时间的范围,33(8.448ms)<63(16.128ms),
  38.                         i=0;
  39.                     irdata[i]=irtime;//存储每个电平的持续时间,用于以后判断是0还是1
  40.                     irtime=0;
  41.                     i++;
  42.                             if(i==33)          //33是33位的意思,包括32位的数据和一位的头码。
  43.                               {
  44.                                    irok=1;
  45.                                  i=0;
  46.                                   }
  47.           }
  48.            else
  49.                 {
  50.                 irtime=0;
  51.                 startflag=1;
  52.                 }

  53. }

  54. /*定时器0初始化*/
  55. void TIM0init(void)//定时器0初始化
  56. {

  57.   TMOD=0x02;//定时器0工作方式2,TH0是重装值,TL0是初值
  58.   TH0=0x00; //装初值
  59.   TL0=0x00;
  60.   ET0=1;    //开中断
  61.   TR0=1;   
  62. }
  63. /*外部中断0初始化*/
  64. void EX0init(void)
  65. {
  66. IT0 = 1;   //指定外部中断0下降沿触发,INT0 (P3.2)
  67. EX0 = 1;   //打开外部中断
  68. EA = 1;    //开总中断
  69. }
  70. /*直流电机控制部分*/
  71. void nishizhen()//电机逆时针转动
  72. {
  73. while(1)
  74. {
  75.   ENA=1;
  76.   if(downswitch==1)
  77.   {
  78.    IN1=1;
  79.    IN2=0;
  80.    IN3=1;
  81.    IN4=0;
  82.   }
  83.    if(downswitch!=1)
  84.   {
  85.    IN1=0;
  86.    IN2=0;
  87.    IN3=0;
  88.    IN4=0;
  89.   }
  90.   if(IR==0)
  91.   {
  92.    break;
  93.   }
  94. }
  95. }

  96. void shunshizhen()//电机顺时针转动
  97. {
  98. while(1)
  99. {
  100.   ENA=1;
  101.   if(downswitch==1)
  102.   {
  103.    IN1=0;
  104.    IN2=1;
  105.    IN3=0;
  106.    IN4=1;
  107.   }
  108.    if(downswitch!=1)
  109.   {
  110.    IN1=0;
  111.    IN2=0;
  112.    IN3=0;
  113.    IN4=0;
  114.   }
  115.   if(IR==0)
  116.   {
  117.    break;
  118.   }
  119. }
  120. }

  121. void motorstop()
  122. {
  123.    IN1=0;
  124.    IN2=0;
  125.    IN3=0;
  126.    IN4=0;
  127. }

  128. /*光敏自动控制模式*/
  129. void lightmod()        //现在的问题:只走up程序else语句完全没用
  130. {
  131. // if(light==1&&downswitch==1)//如果光敏模块输出1亮且下限位开关不触发(限位器平常为高电位,触发后为低电位)
  132. //  {
  133.   while(1)                   //循环执行
  134.     {
  135.         if(light==1&&downswitch==1)        //再次确定
  136.            {
  137.            IN1=0;
  138.        IN2=1;
  139.        IN3=0;
  140.        IN4=1;
  141.           if(IR==0) //有其他红外按键命令来就中断
  142.       break;
  143.           }
  144.           if(light==0&&upswitch==1)//如果光照变暗反转
  145.            {
  146.          IN1=1;
  147.      IN2=0;
  148.      IN3=1;
  149.       IN4=0;
  150.           if(IR==0) //有其他红外按键命令来就中断
  151.       break;
  152.        }
  153.          }   
  154. }
  155. /*原键值处理*/
  156. void Ir_work(void)//红外键值散转程序
  157. {
  158.                 P1=0x00;//初始化p1
  159.            switch(IRcord[2])//判断第三个数码前两个是用户码,最后一个是反码,第三个才是真正的数据码。
  160.                  {
  161.                          case 0x45:nishizhen();break;//- 按下遥控器上面0-9的按键,led亮起相应的数值
  162.                          case 0x47:shunshizhen();break;//+
  163.                          case 0x46:motorstop();break;
  164.                          case 0x09:lightmod();break;
  165.              default:break;
  166.                          }
  167.                        

  168.                   irpro_ok=0;//处理完成标志

  169.   }



  170. /*红外码值处理*/
  171. void Irpro(void)//红外码值处理函数        分析出那些是1那些是0
  172. {
  173.   unsigned char i, j, k;
  174.   unsigned char cord,value;

  175.   k=1;        //前导码没数据,从第二个开始,就是用户码开始。
  176.   for(i=0;i<4;i++)      //处理4个字节
  177.      {
  178.       for(j=1;j<=8;j++) //处理1个字节8位。for语句:先执行j=1;在执行j<=8,为真则继续执行,否则结束执行;执行完循环体后执行j++,重复执行执行循环和j++直到j<=8为假
  179.          {
  180.           cord=irdata[k]; //
  181.           if(cord>7)  //低电平下降沿到下一个下降沿的宽度是0.56+0.565=1.125ms,高电平则是0.56+1.69=2.25ms,同样我们也给出一个范围用于区分它们,可以这样识别 (1.125ms + 2.25ms )/ 2=1.68ms,
  182.                        //大于1.68为高,小于1.68为低。
  183.                                   //假设使用12M晶振 定时器的单位数值时1us,使用8位定时器自动重装,将得到每个定时周期0.256ms的时长, 1.68/0.256=6.59,约等于7.也就是 定时器0计数次数。
  184.             value|=0x80;//最高位就给1,
  185.                         if(j<8)
  186.                     {
  187.                          value>>=1;
  188.                         }
  189.            k++;
  190.          }
  191.      IRcord[i]=value;
  192.      value=0;     
  193.      }
  194.          irpro_ok=1;//处理完毕标志位置1
  195. }

  196. /*主函数*/
  197. void main(void)
  198. {
  199. EX0init(); //初始化外部中断
  200. TIM0init();//初始化定时器
  201. P1=0x00;
  202. while(1)//主循环
  203.    {
  204.     if(irok)                        //如果接收好了进行红外处理
  205.           {   
  206.            Irpro();
  207.            irok=0;
  208.           }

  209.     if(irpro_ok)                   //如果处理好后进行工作处理,如按对应的按键后显示对应的数字等
  210.           {
  211.            Ir_work();
  212.           
  213.             }

  214.    }
  215. }
复制代码


程序框图.docx

33.33 KB, 下载次数: 6

评分

参与人数 1黑币 +50 收起 理由
admin + 50 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

地板
ID:97350 发表于 2021-7-7 15:58 | 只看该作者
原理图放上来岂不是更完美
回复

使用道具 举报

5#
ID:161164 发表于 2021-7-7 16:07 | 只看该作者
在函数里用while(1)是什么脑洞?
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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