找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2577|回复: 17
收起左侧

stc8g1k08a单片机掉电存储问题

  [复制链接]
ID:716660 发表于 2021-9-9 11:14 | 显示全部楼层 |阅读模式
感觉程序没有问题但是掉电之后不能重新读取上次保存到eeprom 不知道是没有保存到内部还是读取不行

//STC8G1K08A工作电压范围1.9~5.5V
//测试工作频率为11.0592MHz
//S_ADC基准值由调试后确定
//此程序为基础构架,需经调试完善
//#include "reg51.h"
#include "STC8.H"
#include "intrins.h"
#define ADCTIM  (*(unsigned char volatile xdata *)0xfea8)
#define WT_12M   0x83
typedef unsigned char uchar;
typedef unsigned int uint;
//端口定义
sbit LED=P3^2;
sbit OUT=P3^3;
sbit ADC=P5^4;
sbit KEY=P5^5;
//全局变量
uchar S_ADC,M_ADC;                                                                //ADC采样值
/*----------------------------
        初始化定时器
----------------------------*/
void Timer0Init()                                                                //2毫秒@11.0592MHz
{
        AUXR |= 0x80;                                                                //定时器时钟1T模式
        TMOD &= 0xF0;                                                                //设置定时器自动重装模式
        TL0 = 0x9A;                                                                        //设置定时初值
        TH0 = 0xA9;                                                                        //设置定时初值
        TF0 = 0;                                                                        //清除TF0标志
        TR0 = 1;                                                                        //定时器0开始计时
}
/*----------------------------
        读取ADC结果
----------------------------*/
uchar GetADCResult()
{        //ADC 控制器  电源  启动  完成  --   15通道模拟选择位
        //ADC_CONTR    B7    B6    B5   B4   B3   B2   B1   B0
        ADC_CONTR|= 0x44;                                       //启动AD转换,P5.4 ADC输入
        _nop_();_nop_();                                                //延时2个时钟
        while (!(ADC_CONTR & 0x20));                //查询ADC完成标志
        ADC_CONTR &= ~0x20;                                                //清完成标志
        return ADC_RES;                                 //返回8位ADC结果
}

void IapIdle()
{
    IAP_CONTR = 0;                     //关闭IAP功能
    IAP_CMD = 0;                       //清除命令寄存器
    IAP_TRIG = 0;                      //清除触发寄存器
    IAP_ADDRH = 0x80;                  //将地址设置到非IAP区域
    IAP_ADDRL = 0;
}

char IapRead(int addr)
{
    char dat;

    IAP_CONTR = WT_12M;                //使能IAP
    IAP_CMD = 1;                       //设置IAP读命令
    IAP_ADDRL = addr;                  //设置IAP低地址
    IAP_ADDRH = addr >> 8;             //设置IAP高地址
    IAP_TRIG = 0x5a;                   //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                   //写触发命令(0xa5)
    _nop_();
    dat = IAP_DATA;                    //读IAP数据
    IapIdle();                         //关闭IAP功能

    return dat;
}

void IapProgram(int addr, char dat)
{
    IAP_CONTR = WT_12M;                //使能IAP
    IAP_CMD = 2;                       //设置IAP写命令
    IAP_ADDRL = addr;                  //设置IAP低地址
    IAP_ADDRH = addr >> 8;             //设置IAP高地址
    IAP_DATA = dat;                    //写IAP数据
    IAP_TRIG = 0x5a;                   //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                   //写触发命令(0xa5)
    _nop_();
    IapIdle();                         //关闭IAP功能
}

void IapErase(int addr)
{
    IAP_CONTR = WT_12M;                //使能IAP
    IAP_CMD = 3;                       //设置IAP擦除命令
    IAP_ADDRL = addr;                  //设置IAP低地址
    IAP_ADDRH = addr >> 8;             //设置IAP高地址
    IAP_TRIG = 0x5a;                   //写触发命令(0x5a)
    IAP_TRIG = 0xa5;                   //写触发命令(0xa5)
    _nop_();                           //
    IapIdle();                         //关闭IAP功能
}

void keys_can()                                                                //按键扫描
{
        static uint count=0;                                        //长按计数变量
        static bit sign=0;                                                //状态标志
        if(!KEY)                                                                   //按键按下
        {  
                if(++count>=500)                                        //长按计数1s
                {
                        sign=1;                                                        //状态标志置1
                        S_ADC=GetADCResult();                        //读取ADC
                        IapErase(0x0000);                                //擦除第0扇区
                        IapProgram(0x0000,S_ADC);                //写入数据
                        LED=0;                                                        //保存成功指示
                }
        }  
        else                                                                        //按键抬起
        {  
                if(sign)                                                        //判断状态标志
                {
                        LED=1;                                                        //指示灯复位
                        sign=0;                                                        //状态标志清0
                }
                count=0;                                                        //长按计数变量清0
        }   
}

void main()
{
//配置端口模式寄存器
        P3M0 = 0x00;                                                        //设置P3准双向口
        P3M1 = 0x00;                                                        //设置P3准双向口
        P5M0 = 0x00;                                                        //设置P5.4为ADC口
        P5M1 = 0x10;                                                        //设置P5.4为ADC口
        OUT  = 0;                                                                //输出口低电平
//配置ADC寄存器 --  -- 格式控制位 --   速度控制位
//   ADCCFG     B7  B6     B5     B4   B3 B2 B1 B0
        P_SW2 |= 0x80;                                                        //打开外设寄存器
        ADCTIM = 0x3f;                                                        //设置 ADC 内部时序
        P_SW2 &= 0x7f;                                                        //关闭外设寄存器
        ADCCFG = 0x0f;                                                        //设置 ADC 时钟为系统时钟/2/16
        ADC_CONTR = 0x80;                                                //使能 ADC 模块
//EEPROM初始操作
        S_ADC=IapRead(0x0000);                                        //读取EEPROM保存的数据
        //if(S_ADC<50||S_ADC>150)                                        //判断超出合适范围,初次使用EEPROM全为0xff
                //S_ADC=100;                                                        //预设基准值

        Timer0Init();                                                        //初始化定时器

        while (1)
        {
                if(TF0)                                                                //中断请求周期2ms
                {
                        TF0=0;                                                        //中断请求标志清0
                        keys_can();                                                //按键扫描
                        M_ADC=GetADCResult();                        //读取ADC
                        if(M_ADC < S_ADC)                                //比较
                        {
                                OUT = 1;                                        //输出高电平
                                LED = 1;                                        //输出指示亮
                        }
                        else         
                        {
                                OUT = 0;                                        //输出低电平
                                LED = 0;                                        //输出指示熄
                        }
                }
        }
}

51黑论坛_急停测试程序.zip

19.82 KB, 下载次数: 14

回复

使用道具 举报

ID:94031 发表于 2021-9-9 14:38 | 显示全部楼层
可以先把 IapProgram(int addr, char dat)(写),char IapRead(int addr)(读) 单独测试一下,看正常吗。
回复

使用道具 举报

ID:123289 发表于 2021-9-9 16:05 | 显示全部楼层
先证明一下,是否写进去了。
当然,当掉电发重在写数据期间,会发生写失败的,不过这是个概率问题。
回复

使用道具 举报

ID:792404 发表于 2021-9-9 18:10 | 显示全部楼层
IapErase(0);                    //擦除第0扇区
IapProgram(1,S_ADC);     //写入数据
S_ADC=IapRead(1);        //读取EEPROM保存的数据
这样改一下就可以了,我之前有个程序也是按照官网提供的代码写的不行,这样改一下就没问题了,你试一下
回复

使用道具 举报

ID:716660 发表于 2021-9-9 18:28 | 显示全部楼层
YUANYUXING 发表于 2021-9-9 18:10
IapErase(0);                    //擦除第0扇区
IapProgram(1,S_ADC);     //写入数据
S_ADC=IapRead( ...

还是不行呀
回复

使用道具 举报

ID:94031 发表于 2021-9-9 19:48 | 显示全部楼层
不知你是如何得到 “掉电之后不能重新读取” 结论的。
回复

使用道具 举报

ID:716660 发表于 2021-9-9 20:07 | 显示全部楼层
xuyaqi 发表于 2021-9-9 19:48
不知你是如何得到 “掉电之后不能重新读取” 结论的。

重新上电,之前保存到eeprom的adc值没了
回复

使用道具 举报

ID:814525 发表于 2021-9-9 22:46 | 显示全部楼层
是不是IAP_CONTR = WT_12M;       //使能IAP  这句有问题。以下是验证没问题的
sfr IAP_TPS = 0xF5;
#define  IAP_EN     (1<<7)
#define  IAP_ENABLE()        IAP_CONTR = IAP_EN; IAP_TPS = MAIN_Fosc / 1000000
回复

使用道具 举报

ID:624769 发表于 2021-9-9 23:00 | 显示全部楼层
你把:
                        S_ADC=GetADCResult();                        //读取ADC
                         IapErase(0x0000);                                //擦除第0扇区
                        IapProgram(0x0000,S_ADC);                //写入数据
                        LED=0;                                                        //保存成功指示
这里的 LED = 0;  改成:
if((IAP_CONTR & 0x10) == 0x00)    LED=0;                                                        //保存成功指示
来确定, 是不是真的保存成功了, 比较好。
回复

使用道具 举报

ID:401564 发表于 2021-9-10 08:30 | 显示全部楼层
这不是很简单的东西吗?
1,开发板上连接一个能显示数据的,数码管,OLED都行
2,写一段开机就读取指定EEPROM地址的程序,再写一段按下按键就写入指定地址EEPROM的,不要ADC,也不要什么串口,直接就是向一个地址写入数据:123,代码越少越好
3,写完之后,拔下电,然后上电,只要显示的是123,就说明读写程序是对的

像你这个,又是ADC,又是比较的,总之就是结果不如意,但并不能确定问题出现在哪一步
回复

使用道具 举报

ID:716660 发表于 2021-9-10 09:27 | 显示全部楼层
确实保存了,但是重新上电 数据就变成11111111没有之前的数了咋回事
回复

使用道具 举报

ID:716660 发表于 2021-9-10 15:26 | 显示全部楼层
Y_G_G 发表于 2021-9-10 08:30
这不是很简单的东西吗?
1,开发板上连接一个能显示数据的,数码管,OLED都行
2,写一段开机就读取指定EEPROM ...

试了 ,只能读不能写
回复

使用道具 举报

ID:170318 发表于 2021-9-10 16:18 | 显示全部楼层
读写程序有问题,STC8与STC15的EEPROM有点不一样,详细看手册
回复

使用道具 举报

ID:401564 发表于 2021-9-10 18:25 | 显示全部楼层
呦呦奥利给 发表于 2021-9-10 15:26
试了 ,只能读不能写

晚上有空我帮你写一个看一下
回复

使用道具 举报

ID:716660 发表于 2021-9-10 19:01 | 显示全部楼层
Y_G_G 发表于 2021-9-10 18:25
晚上有空我帮你写一个看一下

好的谢谢哥
回复

使用道具 举报

ID:401564 发表于 2021-9-11 06:59 | 显示全部楼层
Stc8g1k17_GPS时钟.rar (143.73 KB, 下载次数: 48)
回复

使用道具 举报

ID:716660 发表于 2021-9-11 22:41 | 显示全部楼层
Y_G_G 发表于 2021-9-11 06:59
我这个是在自己以前的一个工程中测试的,运行的结果是可以写入和读取的,掉电之后两次读取的结果是正确的
...

,好了
回复

使用道具 举报

ID:65956 发表于 2022-11-9 08:47 | 显示全部楼层
看你这程序要写入内部EEPROM数据要满足按键按下一秒才会写入,这样掉电1秒才写入是来不及写入的,如果要确保掉电时写入数据,就要用到掉电中断,可以在中断里直接写入,但字节要越少越好,不然要用一个AD功能读电源输入,当电源低于一定值后就把数据写入,否则按你这程序是不行的。仅供参考
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表