- 打卡等级:初来乍到
- 打卡总天数:3
- 最近打卡:2025-09-23 00:23:35
已绑定手机
新手上路
- 积分
- 19
|
求助帖~!
AI8H2K12U的EEPROM在ISP中配置为0.5K,使用EEPROM地址0x0001时程序功能正常,0x0000时EEPROM无法保存,测试过修改EEPROM配置从0.5~2K,结果一样;
注释掉的测试代码,在主程序开始前直接在地址0x0000写入5后能够正常读取,地址0x0000的写入和其它地址有什么不一样么?测试除0x0000意外随机的地址也都正常使用
附代码:
#include <AI8H.H>
#include "Delay.h"
#include "STC8H_PWM.h"
#include "INT0and1.h"
#include "STC8_EEPROM.h"
#define PWM6_E 0x0001 //PWM6档位的EEPROM存储地址(0x0000无法使用原因不明)
u8 Key1; //档位变量
u8 PWM6_MOD; //PWM6初始占空比
bit PWM6_KG = 0; //PWM6开关状态
bit PWM6_UP = 0; //PWM6更新标识位
bit EEPROM_UP = 0; //EEPROM更新标识位
void main()
{
INT0and1_Init(); //外部中断初始化,一定要加在main主程序前
STC8H_PWM_Init(); //初始化硬件PWM
P3M0 &= ~0x0c; P3M1 &= ~0x0c; //P32/33设为准双向口
// 测试
// IapEraseSector(IAP_ADDRESS1); //擦除第1扇区(写入地址所在扇区)
// IapProgramByte(0x0000,5); //在地址写入5
// switch(IapReadByte(0x0000)) //读取EEPROM数据
switch(IapReadByte(0x0001)) //读取EEPROM数据
{
case 2:Key1 = 2;PWM6_MOD = 40;break;
case 3:Key1 = 3;PWM6_MOD = 50;break;
case 4:Key1 = 4;PWM6_MOD = 60;break;
case 5:Key1 = 5;PWM6_MOD = 70;break;
case 6:Key1 = 6;PWM6_MOD = 80;break;
case 7:Key1 = 7;PWM6_MOD = 90;break;
case 8:Key1 = 8;PWM6_MOD = 100;break;
default:Key1 = 1;PWM6_MOD = 30;break;
}
while (1)
{
if(PWM6_UP)
{
PWM6_UP = 0;//清除更新标识位
if(PWM6_KG)//判断开关状态
{
PWM_Set(6,PWM6_MOD);
}else
{
PWM_Set(6,0);
}
}
if(EEPROM_UP)
{
EEPROM_UP = 0; //清除更新标识位
IapEraseSector(IAP_ADDRESS1); //擦除第1扇区(写入地址所在扇区)
IapProgramByte(0x0001,Key1); //在地址0x00F1写入Key1的值
}
}
}
void INT_0(void) interrupt 0 //外部中断P32接口
{
Delay(50);//延时消抖
if(P32 == 0)
{
while(P32==0); //松手检测
PWM6_KG = ~PWM6_KG; //翻转开关状态
PWM6_UP = 1; //开启PWM6更新
}
}
void INT_1(void) interrupt 2 //外部中断P33接口
{
Delay(50);//延时消抖
if(P33==0)
{
while(P33 == 0);//松手检测
Key1++;
EEPROM_UP = 1;//开启EEPROM更新
switch(Key1)//判断档位
{
case 2:PWM6_MOD = 40;break;
case 3:PWM6_MOD = 50;break;
case 4:PWM6_MOD = 60;break;
case 5:PWM6_MOD = 70;break;
case 6:PWM6_MOD = 80;break;
case 7:PWM6_MOD = 90;break;
case 8:PWM6_MOD = 100;break;
default:Key1 = 1;PWM6_MOD = 30;break;
}
if(PWM6_KG) //如果PWM6开启,则开启PWM6更新
{
PWM6_UP = 1;
}
}
}
EEPROM封装函数.c:
#include <AI8H.H>
#include "STC8_EEPROM.h"
/*----------------------------
关闭ISP/IAP/EEPROM功能
使单片机处于安全状态
----------------------------*/
void IapIdle(void)
{
IAP_CONTR = 0; //关闭ISP/IAP/EEPROM功能
IAP_CMD = 0; //待机模式无ISP操作
IAP_TRIG = 0; //ISP/IAP操作时的命令触发寄存器
IAP_ADDRH = 0x80; //操作时的地址寄存器高八位
IAP_ADDRL = 0; //操作时的地址寄存器低八位
}
/*----------------------------
从ISP/IAP/EEPROM区域读取一个字节
输入:addr (ISP/IAP/EEPROM地址)
输出:Flash数据
----------------------------*/
u8 IapReadByte(u16 addr)
{
u8 dat;
IAP_CONTR = 0x80; //打开IAP功能
IAP_TPS = ENABLE_IAP; //设置等待时间,根据系统时钟频率
IAP_CMD = CMD_READ; //设为读字节操作
IAP_ADDRL = addr; //地址低8位
IAP_ADDRH = addr >> 8; //地址高8位
IAP_TRIG = 0x5a; //发送触发命令1-必须
IAP_TRIG = 0xa5; //发送触发命令2-必须
_nop_(); //MCU将保持在这里,直到ISP/IAP/EEPROM操作完成
dat = IAP_DATA; //读取数据
IapIdle(); //关闭ISP/IAP/EEPROM功能
return dat; //返回读取的数据
}
/*----------------------------
写一个字节到ISP/IAP/EEPROM区域
addr:ISP/IAP/EEPROM地址
dat :数据
----------------------------*/
void IapProgramByte(u16 addr, u8 dat)
{
IAP_CONTR = 0x80; //打开IAP功能
IAP_TPS = ENABLE_IAP; //设置等待时间,根据系统时钟频率
IAP_CMD = CMD_PROGRAM; //设为写字节操作
IAP_ADDRL = addr; //地址低8位
IAP_ADDRH = addr >> 8; //地址高8位
IAP_DATA = dat; //写ISP/IAP/EEPROM数据
IAP_TRIG = 0x5a; //发送触发命令1-必须
IAP_TRIG = 0xa5; //发送触发命令2-必须
_nop_(); //MCU将保持在这里,直到ISP/IAP/EEPROM操作完成
IapIdle(); //关闭ISP/IAP/EEPROM功能
}
/*----------------------------
擦除一个扇区
addr:ISP/IAP/EEPROM地址(起始地址)
----------------------------*/
void IapEraseSector(u16 addr)
{
IAP_CONTR = 0x80; //打开IAP功能
IAP_TPS = ENABLE_IAP; //设置等待时间,根据系统时钟频率
IAP_CMD = CMD_ERASE; //设为扇区擦除操作
IAP_ADDRL = addr; //地址低8位
IAP_ADDRH = addr >> 8; //地址高8位
IAP_TRIG = 0x5a; //发送触发命令1-必须
IAP_TRIG = 0xa5; //发送触发命令2-必须
_nop_(); //MCU将保持在这里,直到ISP/IAP/EEPROM操作完成
IapIdle(); //关闭ISP/IAP/EEPROM功能
}
EEPROM封装函数.h:
#ifndef __STC8_EEPROM_H__
#define __STC8_EEPROM_H__
#include <AI8H.H>
#include "intrins.h"
/*定义操作命令*/
#define CMD_READ 1 //读字节
#define CMD_PROGRAM 2 //写字节
#define CMD_ERASE 3 //扇区擦除
/*根据系统时钟选择等待时间*/
#define ENABLE_IAP 11 //11.0592MHZ 等待时间=系统工作频率/1000000(小数部分四舍五入取整)
//擦除EEPROM的起始地址,以扇区起始地址来擦除,EEPROM大小请在ISP下载工具中进行配置
#define IAP_ADDRESS1 0x0000 //第1扇区 结束地址:0x01FF 注意0x0000无法使用原因不明
#define IAP_ADDRESS2 0x0200 //第2扇区 结束地址:0x03FF
#define IAP_ADDRESS3 0x0400 //第3扇区 结束地址:0x05FF
#define IAP_ADDRESS4 0x0600 //第4扇区 结束地址:0x07FF
//外部可调用的函数声明
u8 IapReadByte(u16 addr); //读取一个字节
void IapProgramByte(u16 addr, u8 dat); //写一个字节
void IapEraseSector(u16 addr); //擦除扇区
#endif
|
-
|