找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2879|回复: 1
收起左侧

51单片机和步进电机的自动升降旗帜系统设计资料 含程序与电路等

[复制链接]
ID:380893 发表于 2018-7-30 15:32 | 显示全部楼层 |阅读模式
本系统采用单片机+LCD1602液晶+语音模块+ULN2003驱动芯片+5线4相步进电机+按键模块+遥控器模块设计而成。
按键说明:
从左边第一个起,升旗键、降旗键、停止键。
  
1. 单片机型号:STC89C52/51、AT89C52/51、AT89S52/51 可任选。

2.按下上升按键后,旗帜匀速上升,同时流畅地演奏歌。

3.上升到最高端时自动停止上升,歌停奏。

4.按下下降按键后,旗帜匀速下降,降旗的时间不放歌曲,下降到最低端时自动停止。

5.为避免误动作,旗帜在最高端时,按上升键不起作用;旗帜在最低端时,按下降键不起作用。

6.液晶第二行数字即时显示旗帜所在的高度。

7.可以通过遥控器控制旗帜升降和停止。

8.有旗帜升降和停止指示灯。


Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)
0.png 0.png

元件清单        
元件标号    元件名称    数量
C1    10uf电解电容    1
C2, C3    30pf瓷片电容    2
C4    100uf电解电容    1
C6    470uf电解电容    1
D1, D2    IN4007二极管    2
IR1    1838红外一体接收头+红外遥控    1
J1    电源接口    1
"K1, K2, K3, K4, K5, K6,
K7
"    轻触按键    7
L1, L2, L3, L4    3mm红色led灯    4
P1    LCD1602液晶显示屏+16P插座    1
P2    4针排针    1
P4    排针+步进电机+旗杆    1
PR1    103排阻    1
R1    3K电阻    1
R2, R9    10K电阻    2
R3, R4    1K电阻    2
SP1    喇叭    1
SW1    自锁开关    1
U1    STC89C52单片机+DIP40插座    1
U2    WT588D -16语音模块+2*8P 圆头插座    1
U3    ULN2003芯片+DIP16插座    1
Y1    12M晶振    1

单片机源程序如下:
  1. #include <reg52.h>                 //调用单片机头文件
  2. #define uchar unsigned char  //无符路字符型 宏定义        变量范围0~255
  3. #define uint  unsigned int         //无符路整型 宏定义        变量范围0~65535
  4. #include "eeprom52.h"          //单片机存储控制程序调用
  5. #include "LCD1602.h"         //LCD1602控制显示程序调用

  6. sbit  VSDA = P3^5;         //语音控制IO口定义
  7. sbit  VCS  = P3^6;  
  8. sbit  VSCL = P3^7;
  9. sbit  key_1=P1^0;         //控制按键IO口
  10. sbit  key_2=P1^1;
  11. sbit  key_3=P1^2;
  12. sbit  key_4=P1^3;
  13. sbit  key_5=P1^4;
  14. sbit  key_6=P1^5;

  15. sbit led_1=P1^6;        //系统指示灯IO口
  16. sbit led_2=P1^7;
  17. sbit led_3=P3^0;
  18. sbit led_4=P3^1;



  19. uchar code zz[]={0x01,0x03,0x02,0x06,0x04,0x0c,0x08,0x09}; //步进电机正转动数据数组
  20. uchar code fz[]={0x09,0x08,0x0c,0x04,0x06,0x02,0x03,0x01};//步进电机反转动数据数组

  21. uint UP_dat=0,Below_dat=0,Current_dat=0;
  22. //上移动的角度数据变量,下移动的角度数据变量,当前位置数据变量
  23. uchar Current_Height=0,circulation,speed_dat,dat_A;
  24. //当前旗帜的高度数据变量,步进电机循环控制变量,转动速度控制变量,显示当前高度变量
  25. uchar sys_state,state;
  26. //系统状态变量 ,工作流程控制变量

  27. uchar irbyte[4];
  28. //分析红外数据存数的32位数据;
  29. uchar irtime,irflag,bitnum,irdateok;
  30. //脉冲周期计时便利阿尼哥,分析数据标志位,数据存入数组下标变量 ,数据接受完成标志位
  31. uchar irdate[33];
  32. //红外信号的数据存储数组

  33. /***********************小延时函数**************************/
  34. void  delay_us (unsigned int us)
  35. {

  36.         while(us--)
  37.         {
  38.                 _nop_();
  39.         }
  40. }

  41. /********************************************************************
  42. * 名称 : delay_1ms()
  43. * 功能 : 延时1ms函数
  44. * 输入 : q
  45. * 输出 : 无
  46. ***********************************************************************/
  47. void delay_1ms(uint q)
  48. {
  49.         uint i,j;
  50.         for(i=0;i<q;i++)
  51.                 for(j=0;j<115;j++);
  52. }
  53.                                    
  54.                                           
  55. /************ 延时函数  *****************/
  56. void delay_uint(uint z)
  57. {
  58.    while(z--);
  59. }

  60. /***************清楚红外信号暂存数组中的数据******************/
  61. void qing(void)         
  62. {
  63.    uint i;
  64.         for(i=0;i<33;i++)
  65.         {
  66.          irdate[i]=0;
  67.         }

  68. }
  69. /****************分析红外信号32位数据***************/
  70. void deal_with(void)                  
  71. {
  72.         uchar i,j,k,temp;
  73.         k=1;
  74.         for(j=0;j<4;j++)
  75.         {
  76.                 for(i=0;i<8;i++)  //每8位数据切换一个数组单元
  77.                 {        
  78.                         temp=temp>>1;
  79.                         if(irdate[k]>7)          //根据脉冲周期的时长判断红外数据
  80.                         {
  81.                                 temp=temp|0x80;        
  82.                         }
  83.                         k++;
  84.                 }
  85.                 irbyte[j]=temp;
  86.         }
  87. }


  88. /***********************三线发码子程序************************/
  89. void Send_threelines(unsigned char addr)   //控制语音模块播放那段地址的语音
  90. {
  91.    unsigned char i;
  92.         VCS=0;
  93.         delay_1ms(5);  /* 片选拉低5ms */
  94.     for(i=0;i<8;i++)
  95.         {
  96.                 VSCL=0;
  97.                 if(addr&0x01)
  98.                 {
  99.                         VSDA=1;
  100.                 }
  101.                 else
  102.                         VSDA=0;
  103.                 addr>>=1;
  104.                 delay_us(150); /* 150us */
  105.                 VSCL=1;
  106.                 delay_us(150); /* 150us */
  107.         }
  108.         VCS=1;
  109.         delay_1ms(30);
  110. }


  111. /***************液晶初始化显示函数**************/
  112. void show_init(void)
  113. {
  114.         LCD1602_write(0,0xC0);
  115.         LCD1602_writebyte("Height:14.0cm");//显示旗杆总长度

  116.         LCD1602_write(0,0x80);
  117.         LCD1602_writebyte("C_Height:");        //显示当前高度
  118.         LCD1602_write(1,0x30+Current_Height/100%10);   //十位
  119.         LCD1602_write(1,0x30+Current_Height/10%10);        //个位
  120.         LCD1602_writebyte(".");
  121.         LCD1602_write(1,0x30+Current_Height%10);  //0.1位
  122.         LCD1602_writebyte("cm");        //单位
  123. }

  124. void show(void)          //系统循环显示函数
  125. {
  126.         LCD1602_write(0,0x89);                   //显示当前旗帜高度
  127.         LCD1602_write(1,0x30+Current_Height/100%10);
  128.         LCD1602_write(1,0x30+Current_Height/10%10);
  129.         LCD1602_writebyte(".");
  130.         LCD1602_write(1,0x30+Current_Height%10);
  131. }

  132. //sys_state=0  为 旗低的状态
  133. //sys_state=1 为 旗顶的状态
  134. //sys_state=2 为 半旗的状态
  135. //sys_state=3 为 正在运行的一个状态
  136. //sys_state=4 为 停止的一个状态

  137. void key_code(void)        //系统按键检测控制程序
  138. {
  139.         if(irdateok==1)        //如果红外信号接收完成标志位触发  则
  140.         {
  141.                 irdateok=0;
  142.                 deal_with();  //分析红外数据
  143.         }
  144.         if((!key_1||irbyte[2]==0x44)&&sys_state==0)          //如果升全旗按键按下(按键以及红外遥控)  并旗帜处于最低部
  145.         {                                                        //延时去抖
  146.                 delay_uint(1000);
  147.                 if(!key_1||irbyte[2]==0x44)        //再次判断按键按下        
  148.                 {
  149.                         while(!key_1||irbyte[2]==0x44) //等待按键释放
  150.                         {
  151.                                 qing();
  152.                                 deal_with();
  153.                         }
  154.                         state=1;        //跳转升全旗流程节点
  155.                         sys_state=3;  //置为系统当前状态
  156.                         led_1=0;         //对应指示灯
  157.                 }        
  158.         }

  159.         if((!key_2||irbyte[2]==0x40)&&sys_state==1)          //如果将旗旗按键按下(按键以及红外遥控)并旗帜处于最顶部
  160.         {
  161.                 delay_uint(1000); //延时去抖
  162.                 if(!key_2||irbyte[2]==0x40)        //再次判断按键按下
  163.                 {
  164.                         while(!key_2||irbyte[2]==0x40) //等待按键释放
  165.                         {
  166.                                 qing();
  167.                                 deal_with();
  168.                         }
  169.                         led_2=0;        //对应指示灯        
  170.                         state=3;         //跳转将全旗流程节点
  171.                         sys_state=3;  //置为系统当前状态
  172.                 }        
  173.         }

  174.         if((!key_3||irbyte[2]==0x07)&&sys_state==0)         //如果升半旗按键按下(按键以及红外遥控)并旗帜处于最低部
  175.         {
  176.                 delay_uint(1000);//延时去抖
  177.                 if(!key_3||irbyte[2]==0x07)         //再次判断按键按下
  178.                 {
  179.                         while(!key_3||irbyte[2]==0x07)        //等待按键释放
  180.                         {
  181.                                 qing();
  182.                                 deal_with();
  183.                         }         
  184.                         led_3=0;         //对应指示灯
  185.                         state=5;        //跳转升半旗流程节点
  186.                         sys_state=3;   //置为系统当前状态
  187.                 }        
  188.         }

  189.         if((!key_4||irbyte[2]==0x15)&&sys_state==2)        //如果半旗降下按键按下(按键以及红外遥控)并旗帜处于最半旗状态
  190.         {
  191.                 delay_uint(1000); //延时去抖
  192.                 if(!key_4||irbyte[2]==0x15)         //再次判断按键按下
  193.                 {
  194.                         while(!key_4||irbyte[2]==0x15)        //等待按键释放
  195.                         {
  196.                                 qing();
  197.                                 deal_with();
  198.                         }
  199.                         state=8;         //跳转半旗将下流程节点
  200.                         led_4=0;   //对应指示灯
  201.                         sys_state=3;   //置为系统当前状态
  202.                 }        
  203.         }

  204.         if(!key_5||irbyte[2]==0x43)           //复位按键复发
  205.         {
  206.                 delay_uint(1000);        //延时去抖
  207.                 if(!key_5||irbyte[2]==0x43)        //再次判断按键按下
  208.                 {
  209.                         while(!key_5||irbyte[2]==0x43)        //等待按键释放
  210.                         {
  211.                                 qing();
  212.                                 deal_with();
  213.                         }
  214.                         state=11;          //跳转旗帜返回最低端节点
  215.                         sys_state=3; //置为系统当前状态
  216.                         led_1=led_2=led_3=led_4=1;         //对应指示灯
  217.                 }        
  218.         }

  219.         if(!key_6||irbyte[2]==0x09)         //复位按键复发
  220.         {
  221.                 delay_uint(1000);                //延时去抖
  222.                 if(!key_6||irbyte[2]==0x09)        //再次判断按键按下
  223.                 {
  224.                         while(!key_6||irbyte[2]==0x09)
  225.                         {
  226.                                 qing();
  227.                                 deal_with();
  228.                         }
  229.                         Send_threelines(1);//停止语音播报
  230.                         state=0;
  231.                         sys_state=4;                //停止当前旗帜动作
  232.                         Below_dat=0;
  233.                         UP_dat=0;
  234.                         led_1=led_2=led_3=led_4=1; //取消指示灯
  235.                 }        
  236.         }
  237. }
  238. //sys_state=0  为 旗低的状态
  239. //sys_state=1 为 旗顶的状态
  240. //sys_state=2 为 半旗的状态
  241. //sys_state=3 为 正在运行的一个状态
  242. //uint UP_dat=0,Below_dat=0;
  243. void Control_code(void)
  244. {
  245.         switch(state)
  246.         {
  247.                 case 0:          //停止转动
  248.                         P2 &= 0xf0;         
  249.                         P2 |= 0x00;
  250.                 break;
  251.                 case 1:          //升全旗 并播音
  252.                         Send_threelines(0);        
  253.                         UP_dat=8800;
  254.                         state=2;
  255.                 break;
  256.                 case 2:         //判断是否升到最顶端
  257.                         if(UP_dat==0)
  258.                         {
  259.                                 state=0;
  260.                                 sys_state=1;
  261.                                 led_1=1;
  262.                                 Current_dat=8800;
  263.                         }
  264.                 break;
  265.                 case 3:           //将全旗
  266.                         Below_dat=8800;
  267.                         state=4;
  268.                 break;
  269.                 case 4:          //判断是否将到最低端
  270.                         if(Below_dat==0)
  271.                         {
  272.                                 state=0;
  273.                                 sys_state=0;
  274.                                 led_2=1;        
  275.                                 Current_dat=0;
  276.                         }
  277.                 break;
  278.                 case 5:         //升全旗 并播音
  279.                         Send_threelines(0);        
  280.                         UP_dat=8800;
  281.                         state=6;
  282.                 break;
  283.                 case 6:         //判断是否升到最顶端  并降半旗
  284.                         if(UP_dat==0)
  285.                         {
  286.                                 Below_dat=2933;
  287.                                 state=7;
  288.                         }
  289.                 break;
  290.                 case 7:         //判断是否将到半旗状态
  291.                         if(Below_dat==0)
  292.                         {
  293.                                 state=0;
  294.                                 sys_state=2;
  295.                                 led_3=1;
  296.                                 Current_dat=8800-2933;                        
  297.                         }
  298.                 break;
  299.                 case 8:                //升半旗
  300.                         UP_dat=2933;
  301.                         state=9;
  302.                 break;                                                   
  303.                 case 9:           //判断是否上升完成    并降全旗
  304.                         if(UP_dat==0)
  305.                         {
  306.                                 Below_dat=8800;
  307.                                 state=10;
  308.                         }
  309.                 break;
  310.                 case 10:        //判断是否将到最低端
  311.                         if(Below_dat==0)
  312.                         {
  313.                                 state=0;
  314.                                 sys_state=0;
  315.                                 led_4=1;
  316.                                 Current_dat=0;                        
  317.                         }
  318.                 break;
  319.                 case 11:           //停止语音播报  并将旗帜降到最低端
  320.                         Send_threelines(1);
  321.                         UP_dat=0;
  322.                         Below_dat=Current_dat;
  323.                         state=12;
  324.                 break;
  325.                 case 12:        //判断是否将到最低端
  326.                         if(Below_dat==0)
  327.                         {
  328.                                 state=0;
  329.                                 sys_state=0;                        
  330.                         }
  331.                 break;
  332.         }
  333.         Current_Height=Current_dat/62.8;        //当前旗帜高度计算
  334.         if(Current_Height>140) Current_Height=140;
  335.         if(dat_A!=Current_Height) //如果显示的旗帜高度不等于实际高度  从新赋值并保存
  336.         {
  337.                 dat_A=Current_Height;
  338.                 SectorErase(0x2000);   //保存当前报读
  339.                 byte_write(0x2000,Current_Height);
  340.         }

  341. }

  342. void Time_init(void)  //定时器初始化配置
  343. {
  344.         TMOD = 0x20;               
  345.         TH1 = 0x00;               
  346.         TL1 = 0x00;               
  347.         ET1 = 1;        
  348.         TR1 = 1;                                
  349. }


  350. void main(void)         //系统主程序
  351. {
  352.         Time_init(); //        调用定时器初始化配置程序
  353.         EA=1;                 //打开总中断
  354.         EX0=1;                 //打开外部中断0
  355.         IT0=1;                  //配置触发方式
  356.         delay_uint(20000);        // 系统等待延时
  357.         Current_Height=byte_read(0x2000);         //读取EEPROM中存储的数据
  358.         if(Current_Height>140) Current_Height=0;   //如果当前高度数据不正确则重新赋值
  359.         if(Current_Height==0) sys_state=0;        //判读当前系统工作模式
  360.         else if(Current_Height==140)sys_state=1;
  361.         else if(Current_Height>90&&Current_dat<100) sys_state=2;
  362.         else sys_state=4;
  363.         Current_dat=Current_Height*62.8;          //高度计算
  364.         if(Current_dat>8800) Current_dat=8800;
  365.         LCD1602_cls();         //液晶屏初始化程序调用
  366.         show_init();        //显示内容初始化调用程序
  367.         while(1)
  368.         {
  369.                 show();           //显示函数
  370.                 key_code();        //按键处理函数
  371.                 Control_code();         //系统控制函数
  372.         }
  373. }

  374. void Time_2() interrupt 3
  375. {
  376.         irtime++;
  377.         speed_dat++;
  378.         if(speed_dat>17)   //8600-8800  旗杆走一杆110mm         
  379.         {
  380.                 speed_dat=0;
  381.                 if(UP_dat!=0)
  382.                 {
  383.                         P2 &= 0xf0;
  384.                         P2 |= zz[circulation];         //步进电机控制
  385.                         circulation=(circulation+1)%8;
  386.                         UP_dat--;
  387.                         if(Current_dat<8800) Current_dat++;
  388.                 }
  389.                 if(Below_dat!=0)
  390.                 {
  391.                          P2 &= 0xf0;
  392.                         P2 |= fz[circulation]; //步进电机控制
  393.                         circulation=(circulation+1)%8;
  394.                         Below_dat--;
  395.                         if(Current_dat!=0) Current_dat--;
  396.                 }        

  397.         }
  398. }

  399. void int0() interrupt 0  //外部中断0 中断程序    用于接收红外数据信号         
  400. {
  401.         if(irflag==1)
  402.         {
  403.                 if(irtime>32)  //判断起始信号
  404.                 {
  405.                         bitnum=0;
  406.                 }
  407.                 irdate[bitnum]=irtime;
  408.                 irtime=0;
  409.                 bitnum++;
  410.                 if(bitnum==33)           //连续接收32为数据  则为一组数据接收完成
  411.                 {
  412.                         bitnum=0;
  413.                         irdateok=1;           //触发接收完成标志位
  414.                 }
  415.         }
  416.         else
  417.         {
  418.                 irflag=1;
  419.                 irtime=0;
  420.         }
  421. }
复制代码
0.png

所有资料51hei提供下载:
51单片机自动升国旗完整资料.rar (3.46 MB, 下载次数: 111)
回复

使用道具 举报

ID:923199 发表于 2021-5-18 13:07 | 显示全部楼层
哪位大神能根据这个电路画一个protues仿真图吗?
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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