找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2512|回复: 17
打印 上一主题 下一主题
收起左侧

stc8g1k08a单片机掉电存储问题

  [复制链接]
跳转到指定楼层
楼主
感觉程序没有问题但是掉电之后不能重新读取上次保存到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

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏5 分享淘帖 顶1 踩
回复

使用道具 举报

沙发
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保存的数据
这样改一下就可以了,我之前有个程序也是按照官网提供的代码写的不行,这样改一下就没问题了,你试一下
回复

使用道具 举报

5#
ID:716660 发表于 2021-9-9 18:28 | 只看该作者
YUANYUXING 发表于 2021-9-9 18:10
IapErase(0);                    //擦除第0扇区
IapProgram(1,S_ADC);     //写入数据
S_ADC=IapRead( ...

还是不行呀
回复

使用道具 举报

6#
ID:94031 发表于 2021-9-9 19:48 | 只看该作者
不知你是如何得到 “掉电之后不能重新读取” 结论的。
回复

使用道具 举报

7#
ID:716660 发表于 2021-9-9 20:07 | 只看该作者
xuyaqi 发表于 2021-9-9 19:48
不知你是如何得到 “掉电之后不能重新读取” 结论的。

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

使用道具 举报

8#
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
回复

使用道具 举报

9#
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;                                                        //保存成功指示
来确定, 是不是真的保存成功了, 比较好。
回复

使用道具 举报

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

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

使用道具 举报

11#
ID:716660 发表于 2021-9-10 09:27 | 只看该作者
确实保存了,但是重新上电 数据就变成11111111没有之前的数了咋回事
回复

使用道具 举报

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

试了 ,只能读不能写
回复

使用道具 举报

13#
ID:170318 发表于 2021-9-10 16:18 | 只看该作者
读写程序有问题,STC8与STC15的EEPROM有点不一样,详细看手册
回复

使用道具 举报

14#
ID:401564 发表于 2021-9-10 18:25 | 只看该作者
呦呦奥利给 发表于 2021-9-10 15:26
试了 ,只能读不能写

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

使用道具 举报

15#
ID:716660 发表于 2021-9-10 19:01 | 只看该作者
Y_G_G 发表于 2021-9-10 18:25
晚上有空我帮你写一个看一下

好的谢谢哥
回复

使用道具 举报

16#
ID:401564 发表于 2021-9-11 06:59 | 只看该作者
Stc8g1k17_GPS时钟.rar (143.73 KB, 下载次数: 48)
我这个是在自己以前的一个工程中测试的,运行的结果是可以写入和读取的,掉电之后两次读取的结果是正确的
在EEPROM.c中,你可以
我手头上没有08a的,所以,我用的是STC8G1k17的,其实也是一样的,STC8g系列是一样的
要注意几个点:
1,这个型号的EEPROM只能把"1"写成"0"!!!!!!!!!!这个很重要,也很扯,所以,每次写入你要保存的数据之前,一定要先进行"擦除"操作,而每次擦除却是以扇区进行的,这一点一定要理解!!!!!数据手册中有说明,要认真看
比如,你要保存5个地址的数据,但你盲区还有这5个数据以外的其它数据,那么,你就要先把这整个扇区数据先读取出来,保存好,然后改动你要保存的5个地址的数据,进行整个扇区的擦除(全部写入1),然后,再把之前改动过的一起写入
2,下载器有一个"本次下载程序时擦除用户EEPROM区"选项,不要打钩!
回复

使用道具 举报

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

,好了
回复

使用道具 举报

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

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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