实验构思:
一, 两位共阴数码管4个,要求显示范围0.0~9.9 分别对应4个电机运行时间; 开机无显示,
当电机运行时,对应的数码管从0开始计时,设定的时间到电机停止运行,数码管保持停止时间上.当下个电机运行时熄灭.
二 按键加减范围1~99 ,按设置键3秒进入电机1时间设置 ,(K_SET) 进入设置后,上次设置的数字闪烁, 用 K_UP和K_DN进行数字加减; 步进1,相当于时间0.1秒, 步数100个(0~99);进入设置后,再按设置键,每按一次,进行电机1,2,3,4,1.....循环,同时对应的数码管闪烁,分别显示AA,BB,CC,DD来区分,按下设置键,或者设置完成后3秒无任何按键操作;保存当前数据并退出设置状态. ,在设置的时候不得影响程序的正常运行,设置保存后,程序立即运行新设置的数据.
P0 P0 P0 P0
P1^1 P1^0 P1^3 P1^2 P1^5 P1^4 P1^7 P1^6
数码显示1 数码显示2 数码显示3 数码显示4
开始----------->电机1-------------->电机2---------->电机3-------------电机4-------------->挡杆
PIN_POW PIN_DJA PIN_DJB PIN_DJC PIN_DJD PIN_STOP
P2^2 P2^3 P2^4 P2^5 P2^6 P2^7
控制1 控制2 控制3
PA1 P3^0 PA2 P3^1 PA3^2
K_POW按一次开机,再按一次停机. K_POW=P3^4, K_SET=P3^5, K_UP=P3^6, K_DN=P3^7,
控制触发是低电平有效 输出为低电平 单片机STC89C52 程序C,不要汇编等.
工作过程:
开始(PIN_POW=0,其他=1),等待控制1触发,
控制1触发 (PIN_POW=1,PIN_STOP=0, PIN_DJA =0)
电机1运转时间到,PIN_DJA =1,等待控制2触发.
控制2触发.PIN_DJB =0,
电机2运转时间到 PIN_DJB =1,PIN_DJC =0,电机3接着运行
电机3运转时间到 PIN_DJC =1,PIN_DJD =0,电机4接着运行
电机4运转时间到 PIN_DJD =1,等待控制3触发.
控制3触发.PIN_STOP=1,PIN_POW=0,.
整个过程无限循环,只有有开关机键控制;
按关机键后,等运行到PIN_POW=0时关机,不得在工作过程中途停机.
要求主程序和子程序分类;建立单独的.h文件.此设计中需要设置的数据保存,断电重新开机运行的是上次修改的参数.不得每次开机重新设定.
脚位功能在程序中直接定义,除数码管P0口外,其他单个脚位不得使用代码代替;
以上是题目,贴出全部单片机代码
- main.c
- #include<STC15F2K60S2.H>
- #include"delay.h"
- #include"dj.h"
- #include"key.h"
- #include "eeprom.h"
- uint time_DJA=3000;
- uint time_DJB=3000;
- uint time_DJC=3000;
- uint time_DJD=3000;
- extern bit flag_DJA1;
- extern bit flag_DJB1;
- extern bit flag_DJC1;
- extern bit flag_DJD1;
- extern bit flag_kaiguan;
- sbit PA1=P2^0;
- sbit PA2=P3^6;
- sbit PA3=P3^7;
- void main()
- {
- Init_Timer0();
- PA1=1; //测试的时候用的
- PA2=1; //测试的时候用的
- PA3=1; //测试的时候用的
- /*初始值从EEPROM 中读取*/
- time_DJA=iap_READ(iap_ADDRESS)*1000+iap_READ(iap_ADDRESS+1)*100+iap_READ(iap_ADDRESS+2)*10+iap_READ(iap_ADDRESS+3);
- time_DJB=iap_READ(iap_ADDRESS+4)*1000+iap_READ(iap_ADDRESS+5)*100+iap_READ(iap_ADDRESS+6)*10+iap_READ(iap_ADDRESS+7);
- time_DJC=iap_READ(iap_ADDRESS+8)*1000+iap_READ(iap_ADDRESS+9)*100+iap_READ(iap_ADDRESS+10)*10+iap_READ(iap_ADDRESS+11);
- time_DJD=iap_READ(iap_ADDRESS+12)*1000+iap_READ(iap_ADDRESS+13)*100+iap_READ(iap_ADDRESS+14)*10+iap_READ(iap_ADDRESS+15);
- while(1)
- {
- Key(); // 检测开关是否按下,开关打开,开始执行下面的代码
- if(flag_kaiguan==1)
- {
- PIN_STOP=1; //停止指示灯
- PIN_POW=0; //开始指示灯
- delay_ms(50);//延时程序时间定义50ms,
- if(PA1==1) //PA1触发来到执行下面的代码,相当于开门
- {
- PIN_POW=1;
- PIN_STOP=0;
- DJA(); //电机1开始执行
- while(flag_DJA1==0)Key(); //等待电机1执行完毕
- // delay_ms(1000); //测试的时候用的,假设1秒后触发信号2来到了
- while(PA2==0); //等待触发信号2来
- if(PA2==1)
- {
- DJB(); //电机B开始执行
- while(flag_DJB1==0)Key(); //等待电机B执行结束
- DJC(); //同理
- while(flag_DJC1==0)Key();
- DJD();
- while(flag_DJD1==0)Key();
- // delay_ms(1000); //测试的时候用的假设1秒后触发信号3来到
- while(PA3==0);
- if(PA3==1)
- {
- PIN_STOP=1;
- PIN_POW=0;
- // PA1=0;
- }
- }
- }
- }
- else TR0=0;P0=0X00; //开关关闭的时候把定时器关闭,数码管再清空
- }
- ///*下面的代码可以用来第一次向EEPROM中写入数据,以后都不会用到所以注释掉*/
- // iap_ERASE(iap_ADDRESS);
- // iap_PROGRAM(iap_ADDRESS,3000/1000);
- // iap_PROGRAM(iap_ADDRESS+1,3000/100%10);
- // iap_PROGRAM(iap_ADDRESS+2,3000/10%10);
- // iap_PROGRAM(iap_ADDRESS+3,3000%10);
- //
- // iap_PROGRAM(iap_ADDRESS+4,3000/1000);
- // iap_PROGRAM(iap_ADDRESS+5,3000/100%10);
- // iap_PROGRAM(iap_ADDRESS+6,3000/10%10);
- // iap_PROGRAM(iap_ADDRESS+7,3000%10);
- //
- // iap_PROGRAM(iap_ADDRESS+8,3000/1000);
- // iap_PROGRAM(iap_ADDRESS+9,3000/100%10);
- // iap_PROGRAM(iap_ADDRESS+10,3000/10%10);
- // iap_PROGRAM(iap_ADDRESS+11,3000%10);
- //
- // iap_PROGRAM(iap_ADDRESS+12,3000/1000);
- // iap_PROGRAM(iap_ADDRESS+13,3000/100%10);
- // iap_PROGRAM(iap_ADDRESS+14,3000/10%10);
- // iap_PROGRAM(iap_ADDRESS+15,3000%10);
- // while(1);
- }
- key.c
- #include"key.h"
- extern uint time_DJA;
- extern uint time_DJB;
- extern uint time_DJC;
- extern uint time_DJD;
- bit flag_key1=0; //设置键被按下三秒
- bit flag_anjian=0; // 用于标记有按键按下,三秒无按键按下则退出设置界面
- bit flag_kaiguan=0; //开关键1是开机,0是关机
- uint key_num=1;
- void Key()
- {
- if(K_SET ==0 && flag_key1==0) //检查P3.7端口是否为低电平,即检测S17是否被按下
- {
- delay_ms(2000); //再次检测S17是否被按下
- if(K_SET ==0)
- {
- while(K_SET == 0); //等待按键释放
- flag_key1=1;
- }
- }
- if(flag_key1==1)
- {
- if(K_SET == 0) //检查P3.7端口是否为低电平,即检测S17是否被按下
- { //延时一定时间,去抖
- delay_ms(10); //再次检测S17是否被按下
- if(K_SET == 0)
- {
- while(K_SET == 0); //等待按键释放
- key_num++;
- flag_anjian=1;
- if(key_num==5)
- {
- key_num=1;
- }
- }
- }
- }
-
- if(flag_key1==1)
- {
- if(K_UP == 0) //检查P3.7端口是否为低电平,即检测S17是否被按下
- { //延时一定时间,去抖
- delay_ms(10); //再次检测S17是否被按下
- if(K_UP == 0)
- {
- while(K_UP == 0); //等待按键释放
- flag_anjian=1;
- switch(key_num)
- {
- case 1:
- time_DJA+=100;
- break;
- case 2:
- time_DJB+=100;
- break;
- case 3:
- time_DJC+=100;
- break;
- case 4:
- time_DJD+=100;
- break;
- }
- }
- }
-
- if(K_DN == 0) //检查P3.7端口是否为低电平,即检测S17是否被按下
- { //延时一定时间,去抖
- delay_ms(10); //再次检测S17是否被按下
- if(K_DN == 0)
- {
- while(K_DN == 0); //等待按键释放
- flag_anjian=1;
- switch(key_num)
- {
- case 1:
- time_DJA-=100;
- break;
- case 2:
- time_DJB-=100;
- break;
- case 3:
- time_DJC-=100;
- break;
- case 4:
- time_DJD-=100;
- break;
- }
- }
- }
- }
-
-
- /*开关按键代码*/
- if(K_POW ==0 ) //检查P3.7端口是否为低电平,即检测S17是否被按下
- {
- delay_ms(10); //再次检测S17是否被按下
- if(K_POW ==0)
- {
- while(K_POW == 0); //等待按键释放
- flag_kaiguan=~flag_kaiguan;
- }
- }
-
- }
- delay.c
- #include"delay.h"
- /*==========================================================
- 函数名称:void delayms(void)
- 形 参:无
- 返回值 :无
- 功能描述:1ms延时
- 时 间:2015-11-19
- 使 用:delayms();
- ==========================================================*/
- void delayms(void) //@11.0592MHz
- {
- unsigned char i,j;
- _nop_();
- _nop_();
- _nop_();
- i = 11;
- j = 190;
- do
- {
- while (--j);
- }
- while (--i);
- }
- void delay_ms(unsigned int time)
- {
- unsigned int i;
- for(i=0;i<time;i++)
- delayms();
- }
- dj.c
- #include"dj.h"
- #include"key.h"
- #include "eeprom.h"
- extern uint key_num;
- extern bit flag_key1;
- extern uint key_num;
- extern bit flag_anjian;
- extern uint time_DJA;
- extern uint time_DJB;
- extern uint time_DJC;
- extern uint time_DJD;
- bit flag_DJA=0; //定时器运行电机A的代码
- bit flag_DJA1=0; //电机进入一次DJA()后主模块就不第二次进去了
- bit flag_DJB=0; //定时器运行电机B的代码
- bit flag_DJB1=0; //电机进入一次DJB()后主模块就不第二次进去了
- bit flag_DJC=0; //定时器运行电机C的代码
- bit flag_DJC1=0; //电机进入一次DJC()后主模块就不第二次进去了
- bit flag_DJD=0; //定时器运行电机D的代码
- bit flag_DJD1=0; //电机进入一次DJD()后主模块就不第二次进去了
- uint num=0;
- uint num1=0;
- uint num2=0; //用于在设置模式定时三秒,没有操作则退出设置模式
- uchar SMG_N[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; // 共阴极数码管
- uchar shu_1,shu_2,shu_3,shu_4,shu_5,shu_6,shu_7,shu_8;
- void DJA()
- {
- TR0=1;// 定时器0打开
- num=0;
- PIN_DJA=0;
- flag_DJD=0;
- flag_DJD1=0;
- flag_DJA=1;
-
- }
- void DJB()
- {
- TR0=0;// 定时器0关闭 //还原定时器0
- TH0=(65536-45872)/256; //11.0592 晶振定时50ms还原定时器0
- TL0=(65536-45872)%256; //还原定时器0
- num=0; //还原定时器0
- flag_DJA=0; //还原A的标志位
- flag_DJA1=0; //还原A的标志位
- PIN_DJB=0;
- flag_DJB=1;
- TR0=1;
-
- }
- void DJC()
- {
- TR0=0;// 定时器0关闭
- TH0=(65536-45872)/256; //11.0592 晶振定时50ms
- TL0=(65536-45872)%256;
- num=0;
- flag_DJB=0; //还原B的标志位
- flag_DJB1=0; //还原B的标志位
- PIN_DJC=0;
- flag_DJC=1;
- TR0=1;
-
- }
- void DJD()
- {
- TR0=0;// 定时器0关闭
- TH0=(65536-45872)/256; //11.0592 晶振定时50ms
- TL0=(65536-45872)%256;
- num=0;
- flag_DJC=0; //还原C的标志位
- flag_DJC1=0; //还原C的标志位
- PIN_DJD=0;
- flag_DJD=1;
- TR0=1;
- }
- void time0() interrupt 1
- {
- TH0=(65536-9216)/256; //11.0592 晶振定时50ms
- TL0=(65536-9216)%256;
- num++;num1++; //num1控制数码管显示num控制电机什么时候停止
- /*电机A的代码******************************************************************/
- if(flag_DJA==1)
- {
- if(num>=(time_DJA/10)) //time_DJA是电机A转动的时间,单位为ms
- {
- PIN_DJA=1;
- flag_DJA1=1;
- num=0;
- }
- if(PIN_DJA==0) //如果电机在运行则说明数码管数子还在跳动
- {
- shu_1=(num/10)/10;
- shu_2=(num/10)%10;
- }
- else
- {
- shu_1=(time_DJA/100)/10;
- shu_2=(time_DJA/100)%10;
- }
- if(num1==1 && flag_key1==0)
- {
- P0=0X00;
- P1=0xfe;
- P0=SMG_N[shu_1]+128;
- }
- if(num1==2 && flag_key1==0 )
- {
- num1=0;
- P0=0X00;
- P1=0xfd;
- P0=SMG_N[shu_2];
- }
- }
- /******************************************************************************/
- /*********************************************************************************/
- /*d电机B的代码 *******************************************************************/
- if(flag_DJB==1)
- {
- if(num>=(time_DJB/10)) //time_DJA是电机A转动的时间,单位为ms
- {
- PIN_DJB=1;
- flag_DJB1=1;
- num=0;
- }
- if(PIN_DJB==0) //如果电机在运行则说明数码管数子还在跳动
- {
- shu_3=(num/10)/10;
- shu_4=(num/10)%10;
- }
- else
- {
- shu_1=(time_DJB/100)/10;
- shu_2=(time_DJB/100)%10;
- }
- if(num1==1 && flag_key1==0 )
- {
- P0=0X00;
- P1=0xfb;
- P0=SMG_N[shu_3]+128;
- }
- if(num1==2 && flag_key1==0 )
- {
- num1=0;
- P0=0X00;
- P1=0xf7;
- P0=SMG_N[shu_4];
- }
- }
- /****************************************************************************/
- /*d电机C的代码 *******************************************************************/
- if(flag_DJC==1)
- {
- if(num>=(time_DJC/10)) //time_DJA是电机A转动的时间,单位为ms
- {
- PIN_DJC=1;
- flag_DJC1=1;
- num=0;
- }
- if(PIN_DJC==0) //如果电机在运行则说明数码管数子还在跳动
- {
- shu_5=(num/10)/10;
- shu_6=(num/10)%10;
- }
- else
- {
- shu_5=(time_DJC/100)/10;
- shu_6=(time_DJC/100)%10;
- }
- if(num1==1 && flag_key1==0 )
- {
- P0=0X00;
- P1=0xef;
- P0=SMG_N[shu_5]+128;
- }
- if(num1==2 && flag_key1==0 )
- {
- num1=0;
- P0=0X00;
- P1=0xdf;
- P0=SMG_N[shu_6];
- }
- }
- /****************************************************************************/
- /*d电机D的代码 *******************************************************************/
- if(flag_DJD==1)
- {
- if(num>=(time_DJD/10)) //time_DJA是电机A转动的时间,单位为ms
- {
- PIN_DJD=1;
- flag_DJD1=1;
- num=0;
- }
- if(PIN_DJD==0) //如果电机在运行则说明数码管数子还在跳动
- {
- shu_7=(num/10)/10;
- shu_8=(num/10)%10;
- }
- else
- {
- shu_7=(time_DJD/100)/10;
- shu_8=(time_DJD/100)%10;
- }
- if(num1==1 && flag_key1==0 )
- {
- P0=0X00;
- P1=0xBf;
- P0=SMG_N[shu_7]+128;
- }
- if(num1==2 && flag_key1==0 )
- {
- num1=0;
- P0=0X00;
- P1=0x7f;
- P0=SMG_N[shu_8];
- }
- }
- /****************************************************************************/
- /*按下设置键后数码管显示的代码*/
- if(flag_key1==1)
- {
- switch(key_num)
- {
- case 1:
- if(num1==1)
- {
- P0=0X00;
- P1=0xfe;
- P0=SMG_N[(time_DJA/100)/10]+128;
- }
- if(num1==2)
- {
- num1=0;
- P0=0X00;
- P1=0xfd;
- P0=SMG_N[(time_DJA/100)%10];
- }break;
- case 2:
- if(num1==1)
- {
- P0=0X00;
- P1=0xfb;
- P0=SMG_N[(time_DJB/100)/10]+128;
- }
- if(num1==2)
- {
- num1=0;
- P0=0X00;
- P1=0xf7;
- P0=SMG_N[(time_DJB/100)%10];
- }break;
- case 3:
- if(num1==1)
- {
- P0=0X00;
- P1=0xef;
- P0=SMG_N[(time_DJC/100)/10]+128;
- }
- if(num1==2)
- {
- num1=0;
- P0=0X00;
- P1=0xdf;
- P0=SMG_N[(time_DJC/100)%10];
- }break;
- case 4:
- if(num1==1)
- {
- P0=0X00;
- P1=0xbf;
- P0=SMG_N[(time_DJD/100)/10]+128;
- }
- if(num1==2)
- {
- num1=0;
- P0=0X00;
- P1=0x7f;
- P0=SMG_N[(time_DJD/100)%10];
- }break;
- }
- }
- /* 进入设置后三秒没有操作自动退出并且把数据保存到EEPROM*/
- if(flag_key1==1)
- {
- num2++;
- if(num2==300)
- {
- flag_key1=0;
- iap_ERASE(iap_ADDRESS);
- iap_PROGRAM(iap_ADDRESS,time_DJA/1000);
- iap_PROGRAM(iap_ADDRESS+1,time_DJA/100%10);
- iap_PROGRAM(iap_ADDRESS+2,time_DJA/10%10);
- iap_PROGRAM(iap_ADDRESS+3,time_DJA%10);
-
- iap_PROGRAM(iap_ADDRESS+4,time_DJB/1000);
- iap_PROGRAM(iap_ADDRESS+5,time_DJB/100%10);
- iap_PROGRAM(iap_ADDRESS+6,time_DJB/10%10);
- iap_PROGRAM(iap_ADDRESS+7,time_DJB%10);
-
- iap_PROGRAM(iap_ADDRESS+8,time_DJC/1000);
- iap_PROGRAM(iap_ADDRESS+9,time_DJC/100%10);
- iap_PROGRAM(iap_ADDRESS+10,time_DJC/10%10);
- iap_PROGRAM(iap_ADDRESS+11,time_DJC%10);
- iap_PROGRAM(iap_ADDRESS+12,time_DJD/1000);
- iap_PROGRAM(iap_ADDRESS+13,time_DJD/100%10);
- iap_PROGRAM(iap_ADDRESS+14,time_DJD/10%10);
- iap_PROGRAM(iap_ADDRESS+15,time_DJD%10);
- }
- if(flag_anjian==1)
- {
- flag_anjian=0;
- num2=0;
- }
-
- }
- }
- void Init_Timer0(void)
- {
- AUXR=0X00; //定时器0 定时器 1工作在12分频 即1T
- TMOD=0x11; //定时器0 和定时器1 不可自动重装载模式
- TH0=(65536-9216)/256; //11.0592 晶振定时50ms
- TL0=(65536-9216)%256;
- TL1 = (65536-46080)/256; // 11.0592 晶振定时20ms
- TH1 = (65536-46080)%256;
- TR0=0; //定时器0关闭
- TR1 = 0; //定时器1关闭
- ET0=1; //允许定时器0中断
- ET1=1; //允许定时器1中断
- EA=1; //开启总中断
- }
- eeprom.c
- #include "eeprom.h"
- //使硬件或软件操作停止
- void iap_IDLE()
- {
- IAP_CONTR=0; //禁止IAP读写擦除
- IAP_CMD=0; //等待
- IAP_TRIG=0; //命令未触发
- IAP_ADDRH=0x80; //高位数据地址
- IAP_ADDRL=0; //低位
- }
- //从数据里面读取数据
- uchar iap_READ(uint addr)
- { uchar datas;
- IAP_CONTR=IAP_EN; //控制允许位
- IAP_CMD=CMD_READ; //写入读命令
- IAP_ADDRL=addr; //自定义地址
- IAP_ADDRH=addr>>8;
- IAP_TRIG=0x5a; //命令有效
- IAP_TRIG=0xa5;
- _nop_();
- datas=IAP_DATA;
- iap_IDLE();
- return datas; //返回读出的数据
- }
- //写一个比特ISP写到某个地方
- void iap_PROGRAM(uint addr,uchar datas)
- {
- IAP_CONTR=IAP_EN;
- IAP_CMD=CMD_PROGRAM;
- IAP_ADDRL=addr;
- IAP_ADDRH=addr>>8;
- IAP_DATA=datas;
- IAP_TRIG=0x5a;
- IAP_TRIG=0xa5;
- _nop_();
- iap_IDLE();
- }
- //擦掉某个区域
- void iap_ERASE(uint addr)
- {
- IAP_CONTR=IAP_EN;
- IAP_CMD=CMD_ERASE;
- IAP_ADDRL=addr;
- IAP_ADDRH=addr>>8;
- IAP_TRIG=0x5a;
- IAP_TRIG=0xa5;
- _nop_();
- iap_IDLE();
- }
复制代码
|