仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
电路图
单片机源程序如下:
- //main.c
- -----------------------------------
- /*******************************************************************************
- *
- *
- --------------------------------------------------------------------------------
- * 实 验 名 : 动态数码管显示,定时器
- * 实验说明 :
- * 连接方式 :
- * 注 意 :
- *******************************************************************************/
- #include"STC15F2K.h"
- #include"epprom.h"
- //--定义使用的IO口--//
- #define u8 unsigned char
- #define u16 unsigned int
- sbit you1=P2^0;
- sbit you2=P2^1;
- sbit you3=P2^2;
- sbit you4=P2^3;
- sbit you23=P2^4;
- sbit kai=P2^5;
- sbit fen=P2^6;
- sbit shi=P2^7;
- sbit jidianqi=P3^7;
- //--定义全局变量--//
- u8 code DIG_PLACE[8] = {
- 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//位选控制 查表的方法控制
- u8 code DIG_CODE[18] = {
- 0x3f,0x06,0x5b,0x4f,0x66,
- 0x6d,0x7d,0x07,0x7f,0x6f,
- 0x77,0x7c,0x39,0x5e,0x79,
- 0x71,0x40,0x80};
- //0、1、2、3、4、5、6、7、8、9、A、b、C、d、E、F、- 的显示码
- u8 X1,X2,X3,X4,X5;
- u8 DisplayData[8];
- u16 DJS=0,fen60,shi6;
- bit kk=0; //开关,1,倒计时进行,继电器闭合;0,输入时间,继电器断开
- u16 ff=10*60/*600秒*/,ss=60*60/*3600秒*/;
- u16 count_djs=0;
- u16 countt=0;
- u8 KKKEY;
- //--声明全局函数--//
- void DigDisplay(); //动态显示函数
- void ConfigTimer0(u8 ms);
- void key_sm();
- void anjian();
- /*******************************************************************************
- * 函 数 名 : XX,提供各个数码管的数值
- *******************************************************************************/
- void XX()
- {
- countt=DJS-count_djs;
- if(kk==0) {
- X1=shi6/10;
- X2=shi6%10;
- X3=fen60/10;
- X4=fen60%10;
- X5=17;
- }
- if(kk==1)
- {
- if(countt<=3600)
- {
- X1=countt/600%10;
- X2=countt/60%10;
- X3=countt/10%6 ;
- X4=countt%10/*kk */ ;
- X5=17;
- }
- if(countt>3600)
- {
- X1=countt/36000%10;
- X2=countt/3600%10 ;
- X3=countt%3600/600%6;
- X4=countt%3600/60%10;
- }
- if(X1==0)
- { X1=16;
- if(X2==0)
- {X2=16;
- if(X3==0)X3=16;
- }}
- }
- }
- /*******************************************************************************
- * 函 数 名 : 扫描按键,赋值。
- *******************************************************************************/
- void key_sm()
- {
- anjian();
- if(KKKEY==1) {KKKEY=0;fen60=fen60+10;if(fen60>=60)fen60=0;}
- if(KKKEY==2) {KKKEY=0;shi6=shi6+1;if(shi6>6)shi6=0;}
- if(KKKEY==3) {KKKEY=0;kk=~kk;;}
- ////写入epprom
- if(KKKEY>0){
- shanchu(0x0000);
- xieru(0x0001,fen60) ;
- xieru(0x0002,shi6) ; }
- DJS=(shi6*ss+fen60*60); //单位是秒。
- }
- /*******************************************************************************
- * 函 数 名 : main
- * 函数功能 : 主函数
- * 输 入 : 无
- * 输 出 : 无
- *******************************************************************************/
- void main(void)
- {
- ConfigTimer0(5);
- while(1)
- {
- key_sm();
-
- XX();
- jidianqi=!kk;
- DigDisplay();
- if(countt<=0){kk=0;you23=0; }
- }
- }
- /*******************************************************************************
- * 函 数 名 : DigDisplay
- * 函数功能 : 使用数码管显示
- * 输 入 : 无
- * 输 出 : 无
- *******************************************************************************/
- void DigDisplay()
- {
- unsigned int j;
- //******************************
- you1=0;
- P1= DIG_CODE[X1]; //发送位选
- j = 200; //扫描间隔时间设定
- while(j--);
- P1 = 0x00;//消隐
- you1=1;
- //******************************
- you2=0;
- P1= DIG_CODE[X2]; //发送位选
- j = 200; //扫描间隔时间设定
- while(j--);
- P1 = 0x00;//消隐
- you2=2;
- //******************************
- you3=0;
- P1= DIG_CODE[X3]; //发送位选
- j = 200; //扫描间隔时间设定
- while(j--);
- P1 = 0x00;//消隐
- you3=3;
- //******************************
- you4=0;
- P1 = DIG_CODE[X4]; //发送位选
- j = 200; //扫描间隔时间设定
- while(j--);
- P1 = 0x00;//消隐
- you4=1;
-
- }
- /* 配置并启动T0,ms-T0定时时间 */
- void ConfigTimer0(u8 ms)
- {
- unsigned long tmp; //临时变量
-
- tmp = 12000000 / 12; //定时器计数频率
- tmp = (tmp * ms) / 1000; //计算所需的计数值
- tmp = 65536 - tmp; //计算定时器重载值
- TMOD &= 0xF0; //清零T0的控制位
- TH0 = (u8)(tmp>>8); //定时器重载值拆分为高低字节
- TL0 = (u8)tmp;
- ET0 = 1; //使能T0中断
- TR0 = 1; //启动T0
- EA=1;
- }
- //中断定义为5毫秒
- void InterruptTimer0() interrupt 1
- {
- static u8 Di;
- Di++;
- if(kk==0){count_djs=0;you23=0; }
- if(Di==100) {you23=1;} //秒显示赋值 0.5秒
- if(Di==200 &&kk==1 ) {{you23=0;count_djs=count_djs+1;; }}
- WDT_CONTR=0x37; //看门狗刷新 8.4S
-
- }
- /**/
- //按钮扫描 需在定时中断中调用
- void anjian()
- {
- static u16 JiShu =0;
- static u16 JiShu1=0;
- static u16 JiShu2=0;
- static u8 keybuf = 0xff;
- static u8 keybuf1 = 0xff;
- static u8 keybuf2 = 0xff;
- u8 nm=500;
- keybuf = (keybuf <<1) |fen;
- if(keybuf == 0x00)
- { JiShu++; if(JiShu>=nm) {JiShu=0;KKKEY=1;} }
- keybuf1 = (keybuf1 <<1) |shi;
- if(keybuf1 == 0x00)
- { JiShu1++; if(JiShu1>=nm) {JiShu1=0;KKKEY=2;} }
- keybuf2 = (keybuf2 <<1) |kai;
- if(keybuf2 == 0x00)
- { JiShu2++; if(JiShu2>=nm) {JiShu2=0;KKKEY=3;} }}
- // epprom.c
- #include "epprom.h"
- void Delay(uchar n)
- {
- uint x;
- while (n--)
- {
- x = 0;
- while (++x);
- }
- }
- void guanbi() //iap闲置
- {
- IAP_CONTR = 0; //Close IAP function \关闭IAP功能
- IAP_CMD = 0; //Clear command to standby \清除待命命令
- IAP_TRIG = 0; //Clear trigger register \清除触发寄存器
- IAP_ADDRH = 0x80; //Data ptr point to non-EEPROM area \数据ptr指向非EEPROM区域
- IAP_ADDRL = 0; //Clear IAP address to prevent misuse \清除IAP地址以防止误用
- }
- uchar duqu(uint addr)
- {
- uchar dat; //Data buffer \数据缓冲区
- IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time \打开IAP功能,设置等待时间
- IAP_CMD = CMD_READ; //Set ISP/IAP/EEPROM READ command \设置ISP/IAP/EEPROM读取命令
- IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low \将ISP/IAP/EEPROM地址设置为低位
- IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high \将ISP/IAP/EEPROM地址设置为高
- IAP_TRIG = 0x5a; //Send trigger command1 (0x5a) \发送触发器命令1(0x5a)
- IAP_TRIG = 0xa5; //Send trigger command2 (0xa5) \发送触发器命令2(0xa5)
- _nop_(); //MCU will hold here until ISP/IAP/EEPROM \MCU将在此保持,直到ISP/IAP/EEPROM
- //operation complete \操作完成
- dat = IAP_DATA; //Read ISP/IAP/EEPROM data \读取ISP/IAP/EEPROM数据
- guanbi(); //Close ISP/IAP/EEPROM function \关闭ISP/IAP/EEPROM功能
- return dat; //Return Flash data \返回闪存数据
- }
- void xieru(uint addr, uchar dat)
- {
- IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time \打开IAP功能,设置等待时间
- IAP_CMD = CMD_PROGRAM; //Set ISP/IAP/EEPROM PROGRAM command \设置ISP/IAP/EEPROM程序命令
- IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low \将ISP/IAP/EEPROM地址设置为低位
- IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high \将ISP/IAP/EEPROM地址设置为高
- IAP_DATA = dat; //Write ISP/IAP/EEPROM data \写入ISP/IAP/EEPROM数据
- IAP_TRIG = 0x5a; //Send trigger command1 (0x5a) \发送触发器命令1(0x5a)
- IAP_TRIG = 0xa5; //Send trigger command2 (0xa5) \发送触发器命令2(0xa5)
- _nop_(); //MCU will hold here until ISP/IAP/EEPROM \MCU将在此保持,直到ISP/IAP/EEPROM
- //operation complete \操作完成
- guanbi();
- Delay(1);
- }
- void shanchu(uint addr)
- {
- IAP_CONTR = ENABLE_IAP; //Open IAP function, and set wait time \打开IAP功能,设置等待时间
- IAP_CMD = CMD_ERASE; //Set ISP/IAP/EEPROM ERASE command \设置ISP/IAP/EEPROM擦除命令
- IAP_ADDRL = addr; //Set ISP/IAP/EEPROM address low \将ISP/IAP/EEPROM地址设置为低位
- IAP_ADDRH = addr >> 8; //Set ISP/IAP/EEPROM address high \将ISP/IAP/EEPROM地址设置为高
- IAP_TRIG = 0x5a; //Send trigger command1 (0x5a) \发送触发器命令1(0x5a)
- IAP_TRIG = 0xa5; //Send trigger command2 (0xa5) \发送触发器命令2(0xa5)
- _nop_(); //MCU will hold here until ISP/IAP/EEPROM operation complete \MCU将在此保持,直到ISP/IAP/EEPROM操作完成
- //
- guanbi();
- }
- //epprom.h
- #ifndef __EPPROM1_H__
- #define __EPPROM1_H__
- //---包含头文件---//
- #include "STC15F2K.h"
- #include "intrins.h"
- //typedef unsigned char BYTE;
- //typedef unsigned int WORD;
- //---重定义关键词---//
- #ifndef uchar
- #define uchar unsigned char
- #endif
- #ifndef uint
- #define uint unsigned int
- #endif
- #endif
- #define CMD_IDLE 0 //Stand-By
- #define CMD_READ 1 //Byte-Read
- #define CMD_PROGRAM 2 //Byte-Program
- #define CMD_ERASE 3 //Sector-Erase
- #define ENABLE_IAP 0x82 //if SYSCLK<20MHz
- #define IAP_ADDRESS 0x0000
- void Delay(uchar n);
- void guanbi();
- uchar duqu(uint addr);
- void xieru(uint addr, uchar dat);
- void shanchu(uint addr);
复制代码
Keil代码与Proteus仿真下载:
定时器带显示20211206.7z
(1.57 MB, 下载次数: 40)
|