OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 6893|回复: 10

stm32模拟eeprom读出的数据不正确

[复制链接]

80

主题

188

帖子

0

精华

高级会员

Rank: 4

积分
678
金钱
678
注册时间
2013-8-16
在线时间
37 小时
发表于 2014-11-25 08:54:23 | 显示全部楼层 |阅读模式
5金钱
我使用了正点原子MINI开发板flash模拟EEPROM的例程,对模拟EEPROM部分没有做任何修改,但是我使用写入函数void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)写入一个u16 write_data[9]={100,200,300,533,,444,621,567,678,959}这个数组后,在使用读出函数void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)读取这一组数据,用于接收的数组定义为数组 receive_data[9]={0};结果收到的数据不是我写入的数据,我不清楚这是什么原因,还请知道的大哥,能够指点指点,比较急,谢谢。

最佳答案

查看完整内容[请看2#楼]

回复【4楼】星空: --------------------------------- 代码我帮你测试了下没有任何问题,出问题是你自己不会测试。 你串口直接输出数据,而串口助手显示的是ASCII,你得设置HEX显示,然后拼凑起来,才能正常。 这种测试方法都搞不清的问题,我只能说你还要多多学习。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-11-25 08:54:24 | 显示全部楼层
回复【4楼】星空:
---------------------------------
代码我帮你测试了下没有任何问题,出问题是你自己不会测试。
你串口直接输出数据,而串口助手显示的是ASCII,你得设置HEX显示,然后拼凑起来,才能正常。

这种测试方法都搞不清的问题,我只能说你还要多多学习。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

3

主题

2170

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
5781
金钱
5781
注册时间
2013-11-22
在线时间
1212 小时
发表于 2014-11-25 10:53:12 | 显示全部楼层
写入数据的flash地址安全么    接收到的数据是不是固定的?
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-11-25 16:41:27 | 显示全部楼层
代码呢???
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

80

主题

188

帖子

0

精华

高级会员

Rank: 4

积分
678
金钱
678
注册时间
2013-8-16
在线时间
37 小时
 楼主| 发表于 2014-11-26 08:54:54 | 显示全部楼层
回复【3楼】正点原子:
---------------------------------
下面是我的代码:
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"   
#include "stmflash.h"   
//FLASH模拟EEPROM实验  
//要写入到STM32 FLASH的字符串数组
const u16 write_data[9]={100,200,300,533,444,621,567,678,959};
#define FLASH_SAVE_ADDR  0X08020000  //FLASH 保存地址

int main(void)
{
u8 i;
u16 datatemp[9];  
  Stm32_Clock_Init(9); //系统时钟设置---外部晶振8M
uart_init(72,9600);   //串口初始化为9600--用于发送从eeprom中读取到的数据
delay_init(72);       //延时初始化 
  
while(1)
{
      STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)write_data,9);
              delay(2);//延时2ms
      STMFLASH_Read(FLASH_SAVE_ADDR,(u16*)datatemp,9);
              delay(2);//延时2ms
             for(i=0;i<9;i++)
             {
                  
                   USART1->DR=(datatemp>>8);
                   while((USART1->SR&0X40)==0);//等待发送结束
                   USART1->DR=(datatemp&0x00FF);
                   while((USART1->SR&0X40)==0);//等待发送结束
             }
}
}

//--------------------------

//解锁STM32的FLASH
void STMFLASH_Unlock(void)
{
  FLASH->KEYR=FLASH_KEY1;//写入解锁序列.
  FLASH->KEYR=FLASH_KEY2;
}
//flash上锁
void STMFLASH_Lock(void)
{
  FLASH->CR|=1<<7;//上锁
}
//得到FLASH状态
u8 STMFLASH_GetStatus(void)
{
u32 res;
res=FLASH->SR; 
if(res&(1<<0))return 1;          //忙
else if(res&(1<<2))return 2; //编程错误
else if(res&(1<<4))return 3; //写保护错误
return 0; //操作完成
}
//等待操作完成
//time:要延时的长短
//返回值:状态.
u8 STMFLASH_WaitDone(u16 time)
{
u8 res;
do
{
res=STMFLASH_GetStatus();
if(res!=1)break;//非忙,无需等待了,直接退出.
delay_us(1);
time--;
 }while(time);
 if(time==0)res=0xff;
 return res;
}
//擦除页
//paddr:页地址
//返回值:执行情况
u8 STMFLASH_ErasePage(u32 paddr)
{
u8 res=0;
res=STMFLASH_WaitDone(0X5FFF);//等待上次操作结束,>20ms    
if(res==0)

FLASH->CR|=1<<1;//页擦除
FLASH->AR=paddr;//设置页地址 
FLASH->CR|=1<<6;//开始擦除   
res=STMFLASH_WaitDone(0X5FFF);//等待操作结束,>20ms  
if(res!=1)//非忙
{
FLASH->CR&=~(1<<1);//清除页擦除标志.
}
}
return res;
}
//在FLASH指定地址写入半字
//faddr:指定地址(此地址必须为2的倍数!!)
//dat:要写入的数据
//返回值:写入的情况
u8 STMFLASH_WriteHalfWord(u32 faddr, u16 dat)
{
u8 res;         
res=STMFLASH_WaitDone(0XFF);  
if(res==0)//OK
{
FLASH->CR|=1<<0;//编程使能
*(vu16*)faddr=dat;//写入数据
res=STMFLASH_WaitDone(0XFF);//等待操作完成
if(res!=1)//操作成功
{
FLASH->CR&=~(1<<0);//清除PG位.
}

return res;

//读取指定地址的半字(16位数据) 
//faddr:读地址 
//返回值:对应数据.
u16 STMFLASH_ReadHalfWord(u32 faddr)
{
return *(vu16*)faddr; 
}
#if STM32_FLASH_WREN //如果使能了写   
//不检查的写入
//WriteAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数   
void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)   
{     
u16 i;
for(i=0;i<NumToWrite;i++)
{
STMFLASH_WriteHalfWord(WriteAddr,pBuffer);
    WriteAddr+=2;//地址增加2.
}  

//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为2的倍数!!)
//pBuffer:数据指针
//NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
#if STM32_FLASH_SIZE><256
#define STM_SECTOR_SIZE 1024 //字节
#else 
#define STM_SECTOR_SIZE 2048
#endif  
u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节
void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{
u32 secpos;    //扇区地址
u16 secoff;    //扇区内偏移地址(16位字计算)
u16 secremain; //扇区内剩余地址(16位字计算)    
  u16 i;    
u32 offaddr;   //去掉0X08000000后的地址
if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址
STMFLASH_Unlock(); //解锁
offaddr=WriteAddr-STM32_FLASH_BASE; //实际偏移地址.
secpos=offaddr/STM_SECTOR_SIZE; //扇区地址  0~127 for STM32F103RBT6
secoff=(offaddr%STM_SECTOR_SIZE)/2; //在扇区内的偏移(2个字节为基本单位.)
secremain=STM_SECTOR_SIZE/2-secoff; //扇区剩余空间大小   
if(NumToWrite<=secremain)secremain=NumToWrite;//不大于该扇区范围
while(1) 
{
STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容
for(i=0;i<secremain;i++)//校验数据
{
if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除     
}
if(i><secremain)//需要擦除
{
STMFLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区
for(i=0;i<secremain;i++)//复制
{
STMFLASH_BUF[i+secoff]=pBuffer;   
}
STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区  
}else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间.     
if(NumToWrite==secremain)break;//写入结束了
else//写入未结束
{
secpos++; //扇区地址增1
secoff=0; //偏移位置为0   
    pBuffer+=secremain;   //指针偏移
WriteAddr+=secremain*2; //写地址偏移(16位数据地址,需要*2)    
    NumToWrite-=secremain; //字节(16位)数递减
if(NumToWrite>(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
else secremain=NumToWrite;//下一个扇区可以写完了
}  
};
STMFLASH_Lock();//上锁
}
#endif
//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)数
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)   
{
u16 i;
for(i=0;i<NumToRead;i++)
{
pBuffer=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节.
ReadAddr+=2;//偏移2个字节.
}
}

程序使用keil4编译后的编译信息是:
test.c(20): warning:  #177-D: variable "key" was declared but never referenced
test.c:         u8 key;
test.c:            ^
test.c(21): warning:  #177-D: variable "i" was declared but never referenced
test.c:         u16 i=0;
test.c:             ^
test.c: test.c: 2 warnings, 0 errors
linking...
Program Size: Code=9130 RO-data=630 RW-data=332 ZI-data=3884  
FromELF: creating hex file...
"..\OBJ\test.axf" - 0 Error(s), 2 Warning(s).>
回复

使用道具 举报

80

主题

188

帖子

0

精华

高级会员

Rank: 4

积分
678
金钱
678
注册时间
2013-8-16
在线时间
37 小时
 楼主| 发表于 2014-11-26 08:56:31 | 显示全部楼层
在过程中flash模拟EEPROM部分是单独放在一个.C文件中的
回复

使用道具 举报

80

主题

188

帖子

0

精华

高级会员

Rank: 4

积分
678
金钱
678
注册时间
2013-8-16
在线时间
37 小时
 楼主| 发表于 2014-11-27 08:23:17 | 显示全部楼层
我使用的是串口调试工具,设置的是hex显示的啊。不是什么串口调试助手,我也使用了逻辑分析仪测试,测试得到的数据也是和串口调试工具测试到的效果相同的。是不是显示ASCII,我还是分得清楚的。
回复

使用道具 举报

80

主题

188

帖子

0

精华

高级会员

Rank: 4

积分
678
金钱
678
注册时间
2013-8-16
在线时间
37 小时
 楼主| 发表于 2014-11-27 08:46:24 | 显示全部楼层
在这里还是得谢谢原子哥,你能这么快回复我的问题,你很负责的。我现在在将现象写的详细些,测得的数据结果是:数据的低八位正常,高八位不正常,例如:按照代码上显示,先我使用STMFLASH_Write(0x08020000,dataBuffer,9)将一个 u16 dataBuffer[9]={700,500,876,1023,511,732,543,959,1000}数组存储在了从0x08020000开始的地址中,接下来我调用函数STMFLASH_Read(0X08020000,pBuffer,9),从地址0x08020000开始读取数据,连续读取9个数据,读取到的数据存放在数组u16 pBuffer[9]中。那读取到的数据理论上应该是与dataBuffer[9]这个数组中的数据相同才对,可测出来的数据不相同。例如读取到的第一个数据,理论上应该是700,高8位应该是(0x02),低8位应该是(0xBC).可得到的数据是0x00(高8位),0xBC(低8位)。后面的获得的数据也是相同的错误,不知道问题出在什么地方了。
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-11-27 09:42:31 | 显示全部楼层
回复【8楼】星空:
---------------------------------
我按你3楼的代码,将for里面的代码,换成printf,结果输出很正常。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-11-27 09:42:49 | 显示全部楼层
对了,我用战舰板的寄存器版本例程测试的。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

30

主题

184

帖子

0

精华

高级会员

Rank: 4

积分
608
金钱
608
注册时间
2020-4-17
在线时间
111 小时
发表于 2020-6-15 22:16:32 | 显示全部楼层
#if STM32_FLASH_SIZE><256  改为#if STM32_FLASH_SIZE<256
回复

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-11 11:32

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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