wulin 发表于 2017-7-1 09:58 照着搭了个电路试了下。手动切换是可以的。但是貌似EEPROM没能写成功。断电后重新上电不是断电前的状态。 |
wulin 发表于 2017-7-1 09:58 感谢您的无私奉献,回头我试试。 |
jimi123 发表于 2017-6-30 15:13 给你写了程序和电路图: ![]() #include "STC15W104.H" //单片机头文件 //#include "STC15F104.H" //单片机头文件 #include <intrins.h> //库头文件 #define uint unsigned int //宏定义数据类型uint #define uchar unsigned char //宏定义数据类型uchar /**宏定义ISP的操作命令****/ #define CMD_IDLE 0 //空闲模式 #define CMD_READ 1 //IAP字节读命令 #define CMD_PROGRAM 2 //IAP字节编程命令 #define CMD_ERASE 3 //IAP扇区擦除命令 #define ENABLE_IAP 0x82 //CPU的等待时间 #define IAP_ADDRESS 0x0400 //测试地址 /********端口定义*********/ sbit OUT1=P3^0; //输出端口定义 sbit OUT2=P3^1; sbit OUT3=P3^2; sbit OUT4=P3^3; sbit CN =P3^4; //备用端口定义 sbit key =P3^5; //按键端口定义 /*******变量声明**********/ uchar ch; //中间变量 uint tim; //键值变量 bit flag=0; //操作标志 /******子程序声明*********/ void keyscan(); //按键识别子程序声明 void key_service(); //按键服务程序声明 void Preservation(); //写入状态数据 /****EEPROM操作程序声明****/ void IapIdle(); //关闭IAP/EEPROM uchar IapReadByte(uint addr); //读取EEPROM数据 void IapProgramByte(uint addr, uchar dat);//写入EEPROM数据 void IapEraseSector(uint addr); //擦除EEPROM数据 /*******主函数*************/ void main() { P3M1 = 0x00; //设置P3.0~P3.3推挽模式:0000 0000 P3M0 = 0x0f; //设置P3.0~P3.3推挽模式:0000 1111 tim=IapReadByte(IAP_ADDRESS); //程序开始时读取EEPROM中数据 if((tim<1)||(tim>4)) //判断读取的键值数据是否有效 { tim=0; //键值数据无效即清0 } while(1) { keyscan(); //按键识别程序 key_service(); //按键服务程序 Preservation(); //保存键值程序 P1=ch; //输出状态 } } /*********按键识别子程序**********/ void keyscan() { static bit key_sign=0; //按键自锁标志 static uchar count=0; //消抖计数变量 if(key==0) //检测按键如果为0 { count++; //消抖计数 if(count>=100) //100次检测按键如果为0 { count=100; //防止溢出 if(key_sign==0) //按键自锁标志为0 { key_sign=1; //按键自锁标志置1 flag=1; //操作标志置1 tim++; //状态变量自+1 if(tim>4) //如果tim>4 tim=0; //tim>4清0 } } } else { key_sign=0; //按键自锁标志清0 count=0; //消抖计数清0 } } /*********按键服务程序**********/ void key_service() { switch(tim) { case 0: ch=0xf0; //备用端输出高电平 break; case 1: ch=0xe1; //第1通道输出高电平 break; case 2: ch=0xe2; //第2通道输出高电平 break; case 3: ch=0xe4; //第3通道输出高电平 break; case 4: ch=0xe8; //第4通道输出高电平 break; } } /*********保存键值数据程序**********/ void Preservation() { if(flag==1) //如果操作标志为1 { flag=0; //操作标志清0 IapEraseSector(IAP_ADDRESS);//擦除EEPROM数据 IapProgramByte(IAP_ADDRESS,tim);//写入EEPROM数据 } } /**********关闭IAP功能************/ void IapIdle() { IAP_CONTR = 0; //关闭IAP功能 IAP_CMD = 0; //清除命令寄存器 IAP_TRIG = 0; //清除触发寄存器 IAP_ADDRH = 0x80; //将地址设置到非IAP区域 IAP_ADDRL = 0; } /***从ISP/IAP/EEPROM区域读取一字节***/ uchar IapReadByte(uint addr) { uchar dat; //数据缓冲区 IAP_CONTR = ENABLE_IAP; //使能IAP IAP_CMD = CMD_READ; //设置IAP命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); //等待ISP/IAP/EEPROM操作完成 dat = IAP_DATA; //读ISP/IAP/EEPROM数据 IapIdle(); //关闭IAP功能 return dat; //返回数据 } /***写一字节数据到ISP/IAP/EEPROM区域***/ void IapProgramByte(uint addr, uchar dat) { IAP_CONTR = ENABLE_IAP; //使能IAP IAP_CMD = CMD_PROGRAM; //设置IAP命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_DATA = dat; //写ISP/IAP/EEPROM数据 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); //等待ISP/IAP/EEPROM操作完成 IapIdle(); //关闭IAP功能 } /***ISP/IAP/EEPROM扇区擦除****/ void IapEraseSector(uint addr) { IAP_CONTR = ENABLE_IAP; //使能IAP IAP_CMD = CMD_ERASE; //设置IAP命令 IAP_ADDRL = addr; //设置IAP低地址 IAP_ADDRH = addr >> 8; //设置IAP高地址 IAP_TRIG = 0x5a; //写触发命令(0x5a) IAP_TRIG = 0xa5; //写触发命令(0xa5) _nop_(); //等待ISP/IAP/EEPROM操作完成 IapIdle(); //关闭IAP功能 } ![]() |
wulin 发表于 2017-6-25 08:59 我想用STC15F104,能否给具体的电路和程序 ![]() |
1.采用内含EEPROM的单片机,把操作数据保存,下次开机读取保存的操作数据控制相应电路,如STC15F104等 2.AT89C2051+外接EEPROM,把操作数据保存,下次开机读取保存的操作数据控制相应电路,如AT24CXX系列 3.使用充电电池,只单独给4017保持供电,4017静态电流不到1mA,4个晶体管换为MOS管,以降低4017电耗 |
1.采用内含EEPROM的单片机,把操作数据保存,下次开机读取保存的操作数据控制相应电路,如STC15F104等 2.AT89C2051+外接EEPROM,把操作数据保存,下次开机读取保存的操作数据控制相应电路,如AT24CXX系列 3.使用充电电池,只单独给4017保持供电,4017静态电流不到1mA,4个晶体管换为MOS管,以降低4017电耗 |
cjjcjj1 发表于 2017-6-16 12:29 没关系的,互相学习嘛 |