给你写了程序和电路图:
#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功能
}
4路记忆控制器.zip
(57.33 KB, 下载次数: 60)
|