你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

指针访问结构体出现硬件错误

[复制链接]
风铃草2 提问时间:2016-12-2 13:44 /
我在MDK518环境下, 使用STM32F072芯片,在做结构体时,定义了两个变量saveblock,Storage。用指针访问saveblock成功,访问Storage时就跳转到硬件错误,  两个变量是同一个结构,进行的同样的操作,为什么先定义的那个就没事,后定义的那个旧不能正常访问。

typedef union
{
        u8 Mem[6];
        struct
        {
                u8 ID            : 8;
                u8 Year                : 8;
                u8 Month        : 4;
                u8 Day                : 6;
                u8 Hour                : 6;
                u8 Minute        : 8;
                u8 Second        : 8;                       
        }Date;
}Date_Union;

typedef struct {
               
        u8 Machine_State[2];
        Date_Union Date_Result;               
       
}STORAGE;

STORAGE saveblock,Storage;


int main()
{       
        u16 *Tmp;       
        u16 TestValue;
                       
        saveblock.Date_Result.Date.ID=0x15;
        Storage.Date_Result.Date.ID=0x16;
       
        Tmp = (u16*)&saveblock;
        Tmp+=2;
        TestValue = *Tmp;
       
        Tmp = (u16*)&Storage;
        Tmp+=1;
        TestValue = *Tmp;        //调试的时候  在这里跳转到硬件错误  不能正常读取
       
        while(1);
}

收藏 1 评论12 发布时间:2016-12-2 13:44

举报

12个回答
风铃草2 最优答案 回答时间:2016-12-2 14:51:28
解决了,是字节对齐问题,要凑够32位,分享一下别人的介绍http://blog.csdn.net/u013445530/article/details/44005057

评分

参与人数 1ST金币 +2 收起 理由
zero99 + 2 结贴奖励

查看全部评分

moyanming2013 回答时间:2016-12-2 15:03:14
本帖最后由 moyanming2013 于 2016-12-2 15:07 编辑
风铃草2 发表于 2016-12-2 14:19
我不赞同你的说法,它更内部匹配没有关系,  我只是把这个变量的地址取出来,不管你匹不匹配,指针++后, ...

1.指针++后的具体“跨度”取决于该指针的数据类型,这就要求你的强制类型转换要“得体”。
即使人眼看的不明显也得让编译器明白才行,你的tmp是u16的,但是强制转换的结构体并没有体现出来和它对应的值。
2.指针++后无论“跨度”怎么样确实会指向一个内存,但这个内存不一定是安全或可以用的。STM32永远不会把4GB的存储器地址全部用完且都可访问即使你只是读。
3.内核寄存器寻址和存储器寻址不是一个概念,对于STM32,对内核寄存器寻址只能使用R0~R15等方式(意思就是说你如果不用汇编则无法直接访问到),对存储器寻址可以直接引用其地址值(无论是外设寄存器或者是RAM存储器等)。
你说的“指针跳到STM32的寄存器当中”我对你的理解是对存储器的寻址,当你试图访问系统不允许的位置时自然会引起HardFault。由于你存在不“得体”的强制类型转换,使得内存位置访问变得不可靠,具体你可以调试到此处时打开汇编,看下具体的位置是否被允许访问。但指针错误引用不是导致HardFault的唯一原因,比如大小越位也会导致此类错误。
4.你说的其它MCU可行,那完全是巧合导致的。这中巧合可能由于编译器、芯片类型、存储器映射、代码大小等等各类因素制约,但它基于错误的指针运算,永远都不是安全的即使你看起来“行得通”。

评分

参与人数 1ST金币 +2 收起 理由
zero99 + 2

查看全部评分

风铃草2 回答时间:2016-12-2 13:46:27
typedef union
{
        u8 Mem[6];
        struct
        {
                u8 ID            : 8;
                u8 Year                : 8;
                u8 Month        : 4;
                u8 Day                : 6;
                u8 Hour                : 6;
                u8 Minute        : 8;
                u8 Second        : 8;                       
        }Date;
}Date_Union;

typedef struct {
               
        u8 Machine_State[2];
        Date_Union Date_Result;               
       
}STORAGE;

STORAGE saveblock,Storage;

u8 Errno;
void Test(void)
{
        u16 *Tmp;       
        u16 TestValue;
                       
        saveblock.Date_Result.Date.ID=0x15;
        Storage.Date_Result.Date.ID=0x16;
       
        Tmp = (u16*)&saveblock;
        Tmp+=1;
        TestValue = *Tmp;
        if(TestValue!=0x0015)
        {
                Errno=1;
        }
       
        Tmp = (u16*)&Storage;
        Tmp+=1;
        TestValue = *Tmp;       
        if(TestValue!=0x0016)
        {
                Errno=1;
        }       
}

你们试试这段代码看看能不能跑通
moyanming2013 回答时间:2016-12-2 13:51:57
STORAGE saveblock,Storage;
他们都是STORAGE类型的,即使可以通过强制类型转换你也得转换的“得体”才行。
对于:
Tmp = (u16*)&saveblock;
这种,显然有问题!即使你现在没有出现问题。
语法上看,你把Tmp+=1,相当于u16的指针往下跳u16,跟STORAGE内部完全匹配不上。
风铃草2 回答时间:2016-12-2 14:19:46
moyanming2013 发表于 2016-12-2 13:51
STORAGE saveblock,Storage;
他们都是STORAGE类型的,即使可以通过强制类型转换你也得转换的“得体”才行。 ...

我不赞同你的说法,它更内部匹配没有关系,  我只是把这个变量的地址取出来,不管你匹不匹配,指针++后,都应该能够正常指向下一个内存, 我仅仅是读取了下一个内存单元的值,就跳入硬件错误,就算指针跳到STM32的寄存器当中,不管怎么样也该可以读取
风铃草2 回答时间:2016-12-2 14:21:40
经过测试 STM32F103没有问题  ,STM32F072将指针变为8位的也行的通,  就是16位的失败
        u8 *Tmp;       
        u16 TestValue;
                       
        saveblock.Date_Result.Date.ID=0x15;
        Storage.Date_Result.Date.ID=0x16;
       
        Tmp = (u8*)&saveblock;
        Tmp+=2;
        TestValue = *Tmp;
        if(TestValue!=0x15)
        {
                Errno=1;
        }
       
        Tmp = (u8*)&Storage;
        Tmp+=2;
        TestValue = *Tmp;       
        if(TestValue!=0x16)
        {
                Errno=1;
        }       

creep 回答时间:2016-12-2 14:46:40
本帖最后由 creep 于 2016-12-2 14:50 编辑

测试了F76x运行下代码没有问题。楼主看下fault的时候Tmp的地址是不是有问题。
ts2000 回答时间:2016-12-2 15:32:07
觉得这样访问地址确实有问题、
peter001 回答时间:2016-12-2 18:53:00
学习了,要注意对齐
12下一页

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版