换了个思路,重新整理下eeprom按字节写入
关于我这个手电的换挡实现方法,之前我想复杂了,其实逻辑可以简单一点 首先定义一个sbit cap=P32;P32 连接一个22uf电容,然后接地.,上电后 P32在 0.5秒后,充满电应该是属于低电平,(P32=0)在这0.5秒内,应该属于高电平(P32=1).那我直接判断 if(P32==1) 那就写eeprom(按字节写入), 如果P32==0 那就读取上一次写的eeprom 这不就实现我的需求了吗?按照这个逻辑,我自己写了一个代码 .但是老是有问题.#include "stc8g.h"
#include "intrins.h"
#include <stdio.h>
#define MAIN_Fosc 11059200UL
#define BRT (65536 - MAIN_Fosc / 115200 / 4)
typedef unsigned char u8;
typedef unsigned int u16;
u8 dat; //定义eeprom 储存数据,但实际好像没用上
u16 EEPROMId = 0x0020; //定义eeprom的地址
sbit cap = P3^2; //p32引脚连电容,接地 做电平判定
void sys_init(); //声明系统初始化配置
void PWM_init(void); //声明pwm
void main()
{
unsigned char x; //定义变量x 用于读取eeprom
unsigned char y=5; //定义变量y用于保存pwm值
sys_init(); //调用系统配置
P3M0 = 0x00; P3M1 = 0x00; //P32 输出对电容充电
P5M0 = 0x00; P5M1 = 0x00; //pwm 设置在p55口
x = IapRead(EEPROMId); //读取的当前eeprom 赋值给x
while(1)
{
if(cap) //如果p32引脚 充电中 p32==1
{
IapProgram(EEPROMId,y); //写地址为0x0020 为 y(以后设置为switch或者数组)
EEPROMId=EEPROMId+1; //下次写eeprom +10x0021 ,在下次0x0022 以此类推
y=y+1; //pwm亮度 数组+1 (1,15,55,255)
}
CCAP2H=x; //把x写入的值 赋值给pwm
if(EEPROMId >= 0X1FE) //如果当前字节到达EEPROM末尾,擦除扇区数据
{
IapErase(0x0020); //擦除扇区
EEPROMId = 0x0020; //从头开始按字节写入
}
}
}
void sys_init(void)
{
P_SW2=0x80;
PWM_init();
EA=1; //打开总中断
}
//// 初始化PWM功能 P55 pwm
void PWM_init(void)
{
P_SW1=0x20;
CCON = 0x00;
CMOD = 0x08;
CL = 0x00;
CH = 0x00;
CCAPM2 = 0x42;
PCA_PWM2 = 0x00;
CCAP2L = 0x00;
CCAP2H = 0x00;
CR=1;
}
void delayms(u16 ms)
{
unsigned int i;
do{
i = MAIN_Fosc /10000;
while(--i);
}while(--ms);
}
void IapIdle()
{
IAP_CONTR = 0; // 关闭 IAP 功能
IAP_CMD = 0; // 清除命令寄存器
IAP_TRIG = 0; // 清除触发寄存器
IAP_ADDRH = 0x00; // 清零高地址寄存器
IAP_ADDRL = 0x00; // 清零低地址寄存器
}
char IapRead(unsigned int addr)
{
char dat;
IAP_CONTR = 0x80; // 使能 IAP
IAP_TPS = 12; // 设置等待参数 12MHz
IAP_CMD = 1; // 设置 IAP 读命令
IAP_ADDRL = addr; // 设置 IAP 低地址
IAP_ADDRH = addr >> 8; // 设置 IAP 高地址
EA=0;
_nop_();
_nop_();
IAP_TRIG = 0x5a; // 写触发命令 (0x5a)
IAP_TRIG = 0xa5; // 写触发命令 (0xa5)
EA=1;
_nop_();
_nop_();
_nop_();
_nop_();
dat = IAP_DATA; // 读 IAP 数据
IapIdle(); // 关闭 IAP 功能
return dat;
}
void IapProgram(unsigned int addr, char dat)
{
IAP_CONTR = 0x80; // 使能 IAP
IAP_TPS = 12; // 设置等待参数 12MHz
IAP_CMD = 2; // 设置 IAP 写命令
IAP_ADDRL = addr; // 设置 IAP 低地址
IAP_ADDRH = addr >> 8; // 设置 IAP 高地址
IAP_DATA = dat; // 写 IAP 数据
EA=0;
_nop_();
_nop_();
IAP_TRIG = 0x5a; // 写触发命令 (0x5a)
IAP_TRIG = 0xa5; // 写触发命令 (0xa5)
EA=1;
_nop_();
_nop_();
_nop_();
_nop_();
IapIdle(); // 关闭 IAP 功能
}
void IapErase(unsigned int addr)
{
IAP_CONTR = 0x80; // 使能 IAP
IAP_TPS = 12; // 设置等待参数 12MHz
IAP_CMD = 3; // 设置 IAP 擦除命令
IAP_ADDRL = addr; // 设置 IAP 低地址
IAP_ADDRH = addr >> 8; // 设置 IAP 高地址
EA=0;
_nop_();
_nop_();
IAP_TRIG = 0x5a; // 写触发命令 (0x5a)
IAP_TRIG = 0xa5; // 写触发命令 (0xa5)
EA=1;
_nop_();
_nop_();
_nop_();
_nop_();
IapIdle(); // 关闭 IAP 功能
}
1. P32刚上电是低电平,0.5秒后才是高电平
2. EEPROMId 是变量,无论加到多少,上电后都会初始化
3. 你这代码是疲劳化EEProm, 1秒已经擦写166次(6ms),上电10分钟这芯片的0x0020扇区就会可能会GG了 如果p32开机是低电平会不会进入USB下载模式 正常上电后,去读EEPROM,遍历定位写到哪里去了,然后记录当前地址,下次记录挨着往进写,这样满一页就写下一页,有两个页够倒腾了。 Lkck8210 发表于 2024-10-22 16:30
1. P32刚上电是低电平,0.5秒后才是高电平
2. EEPROMId 是变量,无论加到多少,上电后都会初始化
3. 你这代 ...
是的,现在就是这样,每次上电都是重新读 eeprom了
我在printf查看的
晓飛飛 发表于 2024-10-22 18:14
正常上电后,去读EEPROM,遍历定位写到哪里去了,然后记录当前地址,下次记录挨着往进写,这样满一页就写下 ...
现在是一个页,每次上电eepromid都重置,不能跟上上一条eeprom的数据 Lkck8210 发表于 2024-10-22 16:30
1. P32刚上电是低电平,0.5秒后才是高电平
2. EEPROMId 是变量,无论加到多少,上电后都会初始化
3. 你这代 ...
应该也不会,,因为我没有擦除的,,只是写入而已,现在就是每次都重置eeprom
vb2002 发表于 2024-10-22 18:28
现在是一个页,每次上电eepromid都重置,不能跟上上一条eeprom的数据
EEPROM读是很快的,每次上电后先从头读EEPROM,看最后一条记录写到了哪里,然后接着那个地址往下写,直到写满一页再擦除或者写下一页。 vb2002 发表于 2024-10-22 18:31
应该也不会,,因为我没有擦除的,,只是写入而已,现在就是每次都重置eeprom
...
44行IapErase(0x0020);就是擦除啊 Lkck8210 发表于 2024-10-23 09:12
44行IapErase(0x0020);就是擦除啊
前面有个条件, 写到 字节0x1fe才擦除.
我用了delayms (1000)
关键是每次printf看到他1秒自增.. 断电后,马上有还原了..{:5_312:}
不会弄.还是不会弄
页:
[1]
2