本系统采用单片机+LCD1602液晶+语音模块+ULN2003驱动芯片+5线4相步进电机+按键模块+遥控器模块设计而成。
按键说明:
从左边第一个起,升旗键、降旗键、停止键。
1. 单片机型号:STC89C52/51、AT89C52/51、AT89S52/51 可任选。
2.按下上升按键后,旗帜匀速上升,同时流畅地演奏歌。
3.上升到最高端时自动停止上升,歌停奏。
4.按下下降按键后,旗帜匀速下降,降旗的时间不放歌曲,下降到最低端时自动停止。
5.为避免误动作,旗帜在最高端时,按上升键不起作用;旗帜在最低端时,按下降键不起作用。
6.液晶第二行数字即时显示旗帜所在的高度。
7.可以通过遥控器控制旗帜升降和停止。
8.有旗帜升降和停止指示灯。
Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)
元件清单
元件标号 元件名称 数量
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
单片机源程序如下:
- #include <reg52.h> //调用单片机头文件
- #define uchar unsigned char //无符路字符型 宏定义 变量范围0~255
- #define uint unsigned int //无符路整型 宏定义 变量范围0~65535
- #include "eeprom52.h" //单片机存储控制程序调用
- #include "LCD1602.h" //LCD1602控制显示程序调用
- sbit VSDA = P3^5; //语音控制IO口定义
- sbit VCS = P3^6;
- sbit VSCL = P3^7;
- sbit key_1=P1^0; //控制按键IO口
- sbit key_2=P1^1;
- sbit key_3=P1^2;
- sbit key_4=P1^3;
- sbit key_5=P1^4;
- sbit key_6=P1^5;
- sbit led_1=P1^6; //系统指示灯IO口
- sbit led_2=P1^7;
- sbit led_3=P3^0;
- sbit led_4=P3^1;
- uchar code zz[]={0x01,0x03,0x02,0x06,0x04,0x0c,0x08,0x09}; //步进电机正转动数据数组
- uchar code fz[]={0x09,0x08,0x0c,0x04,0x06,0x02,0x03,0x01};//步进电机反转动数据数组
- uint UP_dat=0,Below_dat=0,Current_dat=0;
- //上移动的角度数据变量,下移动的角度数据变量,当前位置数据变量
- uchar Current_Height=0,circulation,speed_dat,dat_A;
- //当前旗帜的高度数据变量,步进电机循环控制变量,转动速度控制变量,显示当前高度变量
- uchar sys_state,state;
- //系统状态变量 ,工作流程控制变量
- uchar irbyte[4];
- //分析红外数据存数的32位数据;
- uchar irtime,irflag,bitnum,irdateok;
- //脉冲周期计时便利阿尼哥,分析数据标志位,数据存入数组下标变量 ,数据接受完成标志位
- uchar irdate[33];
- //红外信号的数据存储数组
- /***********************小延时函数**************************/
- void delay_us (unsigned int us)
- {
- while(us--)
- {
- _nop_();
- }
- }
- /********************************************************************
- * 名称 : delay_1ms()
- * 功能 : 延时1ms函数
- * 输入 : q
- * 输出 : 无
- ***********************************************************************/
- void delay_1ms(uint q)
- {
- uint i,j;
- for(i=0;i<q;i++)
- for(j=0;j<115;j++);
- }
-
-
- /************ 延时函数 *****************/
- void delay_uint(uint z)
- {
- while(z--);
- }
- /***************清楚红外信号暂存数组中的数据******************/
- void qing(void)
- {
- uint i;
- for(i=0;i<33;i++)
- {
- irdate[i]=0;
- }
- }
- /****************分析红外信号32位数据***************/
- void deal_with(void)
- {
- uchar i,j,k,temp;
- k=1;
- for(j=0;j<4;j++)
- {
- for(i=0;i<8;i++) //每8位数据切换一个数组单元
- {
- temp=temp>>1;
- if(irdate[k]>7) //根据脉冲周期的时长判断红外数据
- {
- temp=temp|0x80;
- }
- k++;
- }
- irbyte[j]=temp;
- }
- }
- /***********************三线发码子程序************************/
- void Send_threelines(unsigned char addr) //控制语音模块播放那段地址的语音
- {
- unsigned char i;
- VCS=0;
- delay_1ms(5); /* 片选拉低5ms */
- for(i=0;i<8;i++)
- {
- VSCL=0;
- if(addr&0x01)
- {
- VSDA=1;
- }
- else
- VSDA=0;
- addr>>=1;
- delay_us(150); /* 150us */
- VSCL=1;
- delay_us(150); /* 150us */
- }
- VCS=1;
- delay_1ms(30);
- }
- /***************液晶初始化显示函数**************/
- void show_init(void)
- {
- LCD1602_write(0,0xC0);
- LCD1602_writebyte("Height:14.0cm");//显示旗杆总长度
- LCD1602_write(0,0x80);
- LCD1602_writebyte("C_Height:"); //显示当前高度
- LCD1602_write(1,0x30+Current_Height/100%10); //十位
- LCD1602_write(1,0x30+Current_Height/10%10); //个位
- LCD1602_writebyte(".");
- LCD1602_write(1,0x30+Current_Height%10); //0.1位
- LCD1602_writebyte("cm"); //单位
- }
- void show(void) //系统循环显示函数
- {
- LCD1602_write(0,0x89); //显示当前旗帜高度
- LCD1602_write(1,0x30+Current_Height/100%10);
- LCD1602_write(1,0x30+Current_Height/10%10);
- LCD1602_writebyte(".");
- LCD1602_write(1,0x30+Current_Height%10);
- }
- //sys_state=0 为 旗低的状态
- //sys_state=1 为 旗顶的状态
- //sys_state=2 为 半旗的状态
- //sys_state=3 为 正在运行的一个状态
- //sys_state=4 为 停止的一个状态
- void key_code(void) //系统按键检测控制程序
- {
- if(irdateok==1) //如果红外信号接收完成标志位触发 则
- {
- irdateok=0;
- deal_with(); //分析红外数据
- }
- if((!key_1||irbyte[2]==0x44)&&sys_state==0) //如果升全旗按键按下(按键以及红外遥控) 并旗帜处于最低部
- { //延时去抖
- delay_uint(1000);
- if(!key_1||irbyte[2]==0x44) //再次判断按键按下
- {
- while(!key_1||irbyte[2]==0x44) //等待按键释放
- {
- qing();
- deal_with();
- }
- state=1; //跳转升全旗流程节点
- sys_state=3; //置为系统当前状态
- led_1=0; //对应指示灯
- }
- }
- if((!key_2||irbyte[2]==0x40)&&sys_state==1) //如果将旗旗按键按下(按键以及红外遥控)并旗帜处于最顶部
- {
- delay_uint(1000); //延时去抖
- if(!key_2||irbyte[2]==0x40) //再次判断按键按下
- {
- while(!key_2||irbyte[2]==0x40) //等待按键释放
- {
- qing();
- deal_with();
- }
- led_2=0; //对应指示灯
- state=3; //跳转将全旗流程节点
- sys_state=3; //置为系统当前状态
- }
- }
- if((!key_3||irbyte[2]==0x07)&&sys_state==0) //如果升半旗按键按下(按键以及红外遥控)并旗帜处于最低部
- {
- delay_uint(1000);//延时去抖
- if(!key_3||irbyte[2]==0x07) //再次判断按键按下
- {
- while(!key_3||irbyte[2]==0x07) //等待按键释放
- {
- qing();
- deal_with();
- }
- led_3=0; //对应指示灯
- state=5; //跳转升半旗流程节点
- sys_state=3; //置为系统当前状态
- }
- }
- if((!key_4||irbyte[2]==0x15)&&sys_state==2) //如果半旗降下按键按下(按键以及红外遥控)并旗帜处于最半旗状态
- {
- delay_uint(1000); //延时去抖
- if(!key_4||irbyte[2]==0x15) //再次判断按键按下
- {
- while(!key_4||irbyte[2]==0x15) //等待按键释放
- {
- qing();
- deal_with();
- }
- state=8; //跳转半旗将下流程节点
- led_4=0; //对应指示灯
- sys_state=3; //置为系统当前状态
- }
- }
- if(!key_5||irbyte[2]==0x43) //复位按键复发
- {
- delay_uint(1000); //延时去抖
- if(!key_5||irbyte[2]==0x43) //再次判断按键按下
- {
- while(!key_5||irbyte[2]==0x43) //等待按键释放
- {
- qing();
- deal_with();
- }
- state=11; //跳转旗帜返回最低端节点
- sys_state=3; //置为系统当前状态
- led_1=led_2=led_3=led_4=1; //对应指示灯
- }
- }
- if(!key_6||irbyte[2]==0x09) //复位按键复发
- {
- delay_uint(1000); //延时去抖
- if(!key_6||irbyte[2]==0x09) //再次判断按键按下
- {
- while(!key_6||irbyte[2]==0x09)
- {
- qing();
- deal_with();
- }
- Send_threelines(1);//停止语音播报
- state=0;
- sys_state=4; //停止当前旗帜动作
- Below_dat=0;
- UP_dat=0;
- led_1=led_2=led_3=led_4=1; //取消指示灯
- }
- }
- }
- //sys_state=0 为 旗低的状态
- //sys_state=1 为 旗顶的状态
- //sys_state=2 为 半旗的状态
- //sys_state=3 为 正在运行的一个状态
- //uint UP_dat=0,Below_dat=0;
- void Control_code(void)
- {
- switch(state)
- {
- case 0: //停止转动
- P2 &= 0xf0;
- P2 |= 0x00;
- break;
- case 1: //升全旗 并播音
- Send_threelines(0);
- UP_dat=8800;
- state=2;
- break;
- case 2: //判断是否升到最顶端
- if(UP_dat==0)
- {
- state=0;
- sys_state=1;
- led_1=1;
- Current_dat=8800;
- }
- break;
- case 3: //将全旗
- Below_dat=8800;
- state=4;
- break;
- case 4: //判断是否将到最低端
- if(Below_dat==0)
- {
- state=0;
- sys_state=0;
- led_2=1;
- Current_dat=0;
- }
- break;
- case 5: //升全旗 并播音
- Send_threelines(0);
- UP_dat=8800;
- state=6;
- break;
- case 6: //判断是否升到最顶端 并降半旗
- if(UP_dat==0)
- {
- Below_dat=2933;
- state=7;
- }
- break;
- case 7: //判断是否将到半旗状态
- if(Below_dat==0)
- {
- state=0;
- sys_state=2;
- led_3=1;
- Current_dat=8800-2933;
- }
- break;
- case 8: //升半旗
- UP_dat=2933;
- state=9;
- break;
- case 9: //判断是否上升完成 并降全旗
- if(UP_dat==0)
- {
- Below_dat=8800;
- state=10;
- }
- break;
- case 10: //判断是否将到最低端
- if(Below_dat==0)
- {
- state=0;
- sys_state=0;
- led_4=1;
- Current_dat=0;
- }
- break;
- case 11: //停止语音播报 并将旗帜降到最低端
- Send_threelines(1);
- UP_dat=0;
- Below_dat=Current_dat;
- state=12;
- break;
- case 12: //判断是否将到最低端
- if(Below_dat==0)
- {
- state=0;
- sys_state=0;
- }
- break;
- }
- Current_Height=Current_dat/62.8; //当前旗帜高度计算
- if(Current_Height>140) Current_Height=140;
- if(dat_A!=Current_Height) //如果显示的旗帜高度不等于实际高度 从新赋值并保存
- {
- dat_A=Current_Height;
- SectorErase(0x2000); //保存当前报读
- byte_write(0x2000,Current_Height);
- }
- }
- void Time_init(void) //定时器初始化配置
- {
- TMOD = 0x20;
- TH1 = 0x00;
- TL1 = 0x00;
- ET1 = 1;
- TR1 = 1;
- }
- void main(void) //系统主程序
- {
- Time_init(); // 调用定时器初始化配置程序
- EA=1; //打开总中断
- EX0=1; //打开外部中断0
- IT0=1; //配置触发方式
- delay_uint(20000); // 系统等待延时
- Current_Height=byte_read(0x2000); //读取EEPROM中存储的数据
- if(Current_Height>140) Current_Height=0; //如果当前高度数据不正确则重新赋值
- if(Current_Height==0) sys_state=0; //判读当前系统工作模式
- else if(Current_Height==140)sys_state=1;
- else if(Current_Height>90&&Current_dat<100) sys_state=2;
- else sys_state=4;
- Current_dat=Current_Height*62.8; //高度计算
- if(Current_dat>8800) Current_dat=8800;
- LCD1602_cls(); //液晶屏初始化程序调用
- show_init(); //显示内容初始化调用程序
- while(1)
- {
- show(); //显示函数
- key_code(); //按键处理函数
- Control_code(); //系统控制函数
- }
- }
- void Time_2() interrupt 3
- {
- irtime++;
- speed_dat++;
- if(speed_dat>17) //8600-8800 旗杆走一杆110mm
- {
- speed_dat=0;
- if(UP_dat!=0)
- {
- P2 &= 0xf0;
- P2 |= zz[circulation]; //步进电机控制
- circulation=(circulation+1)%8;
- UP_dat--;
- if(Current_dat<8800) Current_dat++;
- }
- if(Below_dat!=0)
- {
- P2 &= 0xf0;
- P2 |= fz[circulation]; //步进电机控制
- circulation=(circulation+1)%8;
- Below_dat--;
- if(Current_dat!=0) Current_dat--;
- }
- }
- }
- void int0() interrupt 0 //外部中断0 中断程序 用于接收红外数据信号
- {
- if(irflag==1)
- {
- if(irtime>32) //判断起始信号
- {
- bitnum=0;
- }
- irdate[bitnum]=irtime;
- irtime=0;
- bitnum++;
- if(bitnum==33) //连续接收32为数据 则为一组数据接收完成
- {
- bitnum=0;
- irdateok=1; //触发接收完成标志位
- }
- }
- else
- {
- irflag=1;
- irtime=0;
- }
- }
复制代码
所有资料51hei提供下载:
51单片机自动升国旗完整资料.rar
(3.46 MB, 下载次数: 111)
|