實驗構思:
一, 兩位共陰數碼管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();
- }
復制代碼
|