使用相同的内存地址,但是代码在程序内存中添加8个字节?

发布于 2025-01-28 08:26:46 字数 2152 浏览 3 评论 0原文

我正在使用Atmel Studio进行Atmega8微控制器。在这里,我有两个访问它的IO端口的选项。

  1. 我可以使用DDRB,PortB和PINB宏


    MCU STD端口宏

      #define _mmio_byte(mem_addr)( *(volatile uint8_t *)(mem_addr))
    #define _sfr_io8(io_addr)_mmio_byte((io_addr) + __sfr_offset)
    
    / *端口B */
    #Define PINB _SFR_IO8(0x16)
    #Define DDRB _SFR_IO8(0x17)
    #define portb _sfr_io8(0x18)
     

这是我的简单测试代码

   #include <avr/io.h>

   #define F_CPU 1000000UL

   #include <util/delay.h>

   int main(void)
   {
    DDRB = 0x01;
    while (1)
    {
        PORTB = 0x01;
        _delay_ms(1000);
        PORTB = 0x00;
        _delay_ms(1000);
    }
   }

成功编译后

程序内存使用:108字节1.3%完整
数据存储器使用:0字节0.0%完整

  1. ,或者我可以使用自己的版本

    gpio.h \

#ifndef gpio_h_
#define gpio_h_

#include <avr/io.h>

typedef union {
    struct  
    {
        uint8_t pin0:1;
        uint8_t pin1:1;
        uint8_t pin2:1;
        uint8_t pin3:1;
        uint8_t pin4:1;
        uint8_t pin5:1;
        uint8_t pin6:1;
        uint8_t pin7:1;
    };
    struct {
        uint8_t lsb4:4;
        uint8_t msb4:4;
        };
        uint8_t pins;
}port_reg_t;

typedef struct  
{
    port_reg_t r;
    port_reg_t d;
    port_reg_t p;
}port_t;

#define bio    (*(volatile port_t *) (0x16 + __SFR_OFFSET))

#endif /* gpio_h_* /

这是示例代码

/*

  • led.cpp < /p>

  • 创建:12-05-2022 14:59:53

  • 作者:HP */

      #include&lt; avr/io.h&gt;
     #define f_cpu 1000000ul
     #include&lt; util/delay.h&gt;
    
     #include“ gpio.h”
    
     int主(void)
     {
    
         // ddrb = 0x01;
         //
         //
         //(1)
         // {
         // portb = 0x01;
         // _ delay_ms(1000);
         // portb = 0x00;
         // _ delay_ms(1000);
         //}
    
     bio.d.pin0 = 1;
    
     而(1) 
     {
         bio.p.pin0 = 1;
         _delay_ms(1000);
         Bio.P.Pin0 = 0;
        _delay_ms(1000);
    
     }
    }
     

成功编译后

程序内存使用率:116字节1.4%完整
数据存储器使用:0字节0.0%完整

我的问题,是, 为什么在程序内存中需要8个字节?

I am using Atmel Studio for the atmega8 microcontroller. Here I have two options for accessing it's io ports.

  1. I can use DDRB, PORTB, and PINB Macro

    MCU std ports macros

    #define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
    #define _SFR_IO8(io_addr) _MMIO_BYTE((io_addr) + __SFR_OFFSET)
    
    /* Port B */
    #define PINB     _SFR_IO8(0x16)
    #define DDRB     _SFR_IO8(0x17)
    #define PORTB    _SFR_IO8(0x18)
    

this is my simple test code

   #include <avr/io.h>

   #define F_CPU 1000000UL

   #include <util/delay.h>

   int main(void)
   {
    DDRB = 0x01;
    while (1)
    {
        PORTB = 0x01;
        _delay_ms(1000);
        PORTB = 0x00;
        _delay_ms(1000);
    }
   }

after successful compilation

Program Memory Usage : 108 bytes 1.3 % Full
Data Memory Usage : 0 bytes 0.0 % Full

  1. Or I can use my own version

    gpio.h\

#ifndef GPIO_H_
#define GPIO_H_

#include <avr/io.h>

typedef union {
    struct  
    {
        uint8_t pin0:1;
        uint8_t pin1:1;
        uint8_t pin2:1;
        uint8_t pin3:1;
        uint8_t pin4:1;
        uint8_t pin5:1;
        uint8_t pin6:1;
        uint8_t pin7:1;
    };
    struct {
        uint8_t lsb4:4;
        uint8_t msb4:4;
        };
        uint8_t pins;
}port_reg_t;

typedef struct  
{
    port_reg_t r;
    port_reg_t d;
    port_reg_t p;
}port_t;

#define bio    (*(volatile port_t *) (0x16 + __SFR_OFFSET))

#endif /* GPIO_H_ */

this is sample code

/*

  • led.cpp

  • Created: 12-05-2022 14:59:53

  • Author : HP
    */

     #include <avr/io.h>
     #define F_CPU 1000000UL
     #include <util/delay.h>
    
     #include "gpio.h"
    
     int main(void)
     {
    
         //DDRB = 0x01;
         //
         //
         //while (1)
         //{
         //PORTB = 0x01;
         //_delay_ms(1000);
         //PORTB = 0x00;
         //_delay_ms(1000);
         //}
    
     bio.d.pin0 = 1;
    
     while (1) 
     {
         bio.p.pin0 = 1;
         _delay_ms(1000);
         bio.p.pin0 = 0;
        _delay_ms(1000);
    
     }
    }
    

after successful compilation

Program Memory Usage : 116 bytes 1.4 % Full
Data Memory Usage : 0 bytes 0.0 % Full

my question is,
why it's taking 8 bytes extra in program memory?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

空气里的味道 2025-02-04 08:26:46

从您显示的代码中,我可以演示您的结构多6个字节(在程序空间中)。我不知道为什么您的编译器还需要8个字节而不是6个字节,但是您可以调查生成的汇编程序(也许您必须要求生成它)。

C中的I/O寄存器分配,例如:

PORTB = 0x01;

由AVR MCU以这种方式执行:

LDI   R1, 1      ; 16 bit instruction, 2 bytes
STS   PORTB, R1  ; again 2 bytes

总计4个字节。有时可以使用STS,而是可以使用(请参见稍后),但无论如何都是指令。

在您的第一个程序中,您有3个分配。

在第二个程序中,编译器知道它应该在单个位而不是整个字节上运行。要在I/O寄存器中设置一个位,因为C程序指出:

bio.p.pin0 = 1;

编译器必须生成:

LDS   R1, bio.p
ORI   R1, 1       ; <-- added instruction, 2 bytes
STS   bio.p, R1

该添加的指令是设置一点的指令。需要更多指令。

现在,在两个程序中,都有这样的3个分配,在第二版中,每个程序都需要一个MCU指令,总共有6个字节。

AVR MCU有指示操纵单位 - 在寄存器或I/O空间中。 可以制定同样的效果

SBI   PORTB, 0   ; <-- set bit 0 of PORTB

因此,单个指令与以前的3个LDS/ORI/STS相同, 。值得注意的是,如果使用了这些说明,第二个程序将比前者短,而不是更长。

问题在于这些说明(SBI/CBI)只能应用于其空间中的前32个地址。现在,根据MCU的精确模型,并不是所有的I/O寄存器都位于第一个32个地址中,因此不能始终使用此指令,它取决于目标。

您的编译器可能选择不使用SBI/CBI,因为在这种情况下,它无法理解它们是安全的。也许如果您打开完整的优化,它们将被使用,或者您必须指示编译器在这种特殊情况下使用它们。

关于STS和OUT:STS可以做所有事情,但是它们使用不同的地址。我不明白为什么存在(及其同伴)存在,但肯定是有原因的。

From the code you show, I can demonstrate your structs take 6 bytes more (in program space). I don't know why your compiler needs 8 bytes more instead of 6, but you can investigate the generated assembler (maybe you has to ask to generate it).

An assignation in C to an I/O register, like:

PORTB = 0x01;

is carried out by an AVR MCU in this way:

LDI   R1, 1      ; 16 bit instruction, 2 bytes
STS   PORTB, R1  ; again 2 bytes

For a total of 4 bytes. Instead of STS, sometimes it is possible to use OUT (see later), but it is an instruction anyway.

In your first program, you have 3 assignation like this.

In the second program, the compiler know it should operate on single bits, not whole bytes. To set a single bit in a I/O register, because the C program states:

bio.p.pin0 = 1;

the compiler has to generate:

LDS   R1, bio.p
ORI   R1, 1       ; <-- added instruction, 2 bytes
STS   bio.p, R1

That added instruction is the one that sets a bit leaving the other untouched. One instruction more is needed.

Now, in both programs there are 3 assignations like this and, in the second version, each one takes one more MCU instruction, for a total of 6 bytes.

The AVR MCU has instruction to manipulate single bits - in a register or in the I/O space. So the same effect to set a bit would have been made with a single:

SBI   PORTB, 0   ; <-- set bit 0 of PORTB

This single instruction does the same as the 3 previous LDS/ORI/STS! And it is to be noted that, if those instructions were used, the second program would be shorter than the former, not longer.

The problem is that those instructions (SBI/CBI) can be applied only to the first 32 addresses in their space. Now, depending also on the precise model of MCU, not all I/O registers reside in the first 32 addresses, so this instruction can not always be used, it depends on the target.

Probably your compiler chose to not use SBI/CBI because it is not able to understand they are safe in this case. Maybe if you turn on full optimization they will be used, or maybe you have to instruct the compiler to use them in this particular case.

About STS and OUT: STS can do everything OUT does, but they use different addresses. I don't understand why OUT (and its companion IN) exists, but surely there is a reason.

楠木可依 2025-02-04 08:26:46

您假设两个程序都做相同,但是它们不是。因此,这就是造成不同内存使用情况的原因。

第一个程序将一个完整的字节写入端口B:

    PORTB = 0x01;

第二个程序集(重置)仅一位,仅留下其他七个位:

    bio.p.pin0 = 1;

这就是“引擎盖下”的情况:

    bio.p.pins = bio.r.pins | 0x01;

这是与您的Header的可比版本:

    bio.p.pins = 0x01;

You assume that both program do the same, but they do not. So this is the reason for the different memory usages.

The first program writes a complete byte to port B:

    PORTB = 0x01;

The second program sets (resets) just one bit, leaving the other seven bits alone:

    bio.p.pin0 = 1;

This is what happens "under the hood":

    bio.p.pins = bio.r.pins | 0x01;

This is the comparable version with your header:

    bio.p.pins = 0x01;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文