这是我正在研究的C项目的反汇编AVR代码片段.我注意到这个好奇的代码正在生成,我无法理解它是如何工作的.我假设这是一种荒谬的优化......
解释是什么?
92: ticks++; // unsigned char ticks;
+0000009F: 91900104 LDS R25,0x0104 Load direct from data space
+000000A1: 5F9F SUBI R25,0xFF Subtract immediate
+000000A2: 93900104 STS 0x0104,R25 Store direct to data space
95: if (ticks == 0) {
+000000A4: 2399 TST R25 Test for Zero or Minus
+000000A5: F009 BREQ PC+0x02 Branch if equal
+000000A6: C067 RJMP PC+0x0068 Relative jump
Run Code Online (Sandbox Code Playgroud)
具体来说,为什么第二条指令从R25中减去0xFF而不仅仅是INC R25?
我一直在考虑"继续"进行MCU编程,但问题是我从未使用过任何微控制器或类似产品.据我所知,AVR和PIC是业余爱好者中最常见的微控制器,显然大多数人建议AVR为像我这样的新手,因为它的"C友好架构"(无论这意味着什么),它的C编译器及其大型业余爱好者社区.AVR或PIC或其他任何东西,对我来说并不重要,我希望能够在Linux上用一个好的编译器编写C代码,并最终能够在我的MCU上添加一个LCD屏幕(只是为了输出基本的ASCII字符,也许在这里和那里画几个像素,单色,没什么大的).我不需要任何复杂或极快或甚至大量的记忆,因为我喜欢有限(但不是太有限)的事情,你需要一些创造力来实现目标.我在互联网上环顾四周,但我发现的大多数页面已经有几十年的历史了,并且/或者没有提出我可以购买的任何好的'包'(这将支持上面提到的内容).这就是为什么我问你,希望你能帮助我一点.:)
谢谢,霍法.
我正在为AVR平台开发,我有一个问题.我不希望浮点库与我的代码链接,但我喜欢模拟值范围为0.0 ... 1.0而不是0 ... 255和0 ... 1023的概念,具体取决于偶数我是使用端口作为输入还是输出.
所以我决定将输入/输出函数的参数乘以1023.0和255.0.现在,我的问题是:如果我实现这样的部门:
#define analog_out(port, bit) _analog_out(port, ((uint8_t)((bit) * 255.0)))
Run Code Online (Sandbox Code Playgroud)
将GCC(打开-O3标志)优化编译时浮点乘法(在编译时已知并转换为整数类型)进行整数运算?(我知道当使用带有非常量参数的这些宏时,优化是不可能的;我只是想知道它是否会在另一种情况下完成.)
AVR/Arduino上是否实现了AMQP消息发送方?
是否可以使用AVR端口作为可以传递的变量?
例如
LED myLed(PORTA,7); //myLED hooked to PORTA, Pin 7
Run Code Online (Sandbox Code Playgroud)
我想让LED能够采用任何PORT/Pin组合,所以我宁愿不用硬编码.
请注意,PORT定义为:
#define PINA _SFR_IO8(0x00)
#define DDRA _SFR_IO8(0x01)
#define PORTA _SFR_IO8(0x02)
Run Code Online (Sandbox Code Playgroud)
PORTA符号解析为(*(volatile uint8_t*)((0x02)+ 0x20))
我相信这将允许我做类似下面的事情,但我不确定我是否需要volatile关键字,也不确定它是否真的按预期工作
class LED{
public:
LED(volatile uint8_t* port, uint8_t pin);
{
Port=port;
Pin=pin;
}
void write(bool val)
{
if(val) (*Port) |= 1 << Pin;
else (*Port) &= ~(1 << Pin);
}
private:
uint8_t Pin
volatile uint8_t* Port;
}
Run Code Online (Sandbox Code Playgroud)
最后,有没有办法将端口/引脚设置为LED构造器的输出?这将涉及为给定端口#找到相对DDR#寄存器.我可以假设和DDR#将永远是&PORT#-1?
我得到了枚举
enum ProgramID
{
A = 0,
B = 1,
C = 2,
MIN_PROGRAM_ID = A,
MAX_PROGRAM_ID = C,
} CurrentProgram;
Run Code Online (Sandbox Code Playgroud)
现在,我试图CurrentProgram像这样增加:CurrentProgram++,但编译器抱怨:no 'operator++(int)' declared for postfix '++' [-fpermissive].我认为有这样一个运算符增加"枚举",但如果没有,我如何获得其中一个值的后继?
前言
我正在使用avr-g ++来编程AVR微控制器,因此我总是需要获得非常高效的代码.
如果GCC的参数是编译时常量,GCC通常可以优化函数,例如,我有函数pin_write(uint8_t pin, bool val)确定AVR的寄存器pin(使用我从整数pin到一对端口/引脚的特殊映射)并写入这些寄存器的对应值.由于其通用性,这个功能不是太小.但是,如果我把这个函数编译时间常数pin和val,GCC可以在编译时所有的计算和消除这一呼吁的一对夫妇的AVR指令,例如
sbi PORTB,1
sbi DDRB,1
Run Code Online (Sandbox Code Playgroud)
缓行
我们写一个这样的代码:
class A {
int x;
public:
A(int x_): x(x_) {}
void foo() { pin_write(x, 1); }
};
A a(8);
int main() {
a.foo();
}
Run Code Online (Sandbox Code Playgroud)
我们只有一个A类对象,并用常量(8)初始化.因此,可以在编译时进行所有计算:
foo() -> pin_write(x,1) -> pin_write(8,1) -> a couple of asm instructions
Run Code Online (Sandbox Code Playgroud)
但海湾合作委员会没有这样做.
令人惊讶的是,如果我删除全局A a(8)并且只是写
A(8).foo()
Run Code Online (Sandbox Code Playgroud)
我得到了我想要的东西:
00000022 <main>:
22: c0 9a sbi 0x18, 0 ; 24
24: b8 9a sbi …Run Code Online (Sandbox Code Playgroud) 我想交叉编译Clang以在ARM设备上运行,并为ARM mcu(Cortex M3)或ATmega AVR mcus进行编译。Clang能够做到吗?
更新:我已经找到了LLVM 3.5的llvm-avr后端:https : //github.com/sushihangover/llvm-avr
除了我以外,还有其他人感兴趣吗?
在编译和链接--gc-sections时,使用avr-gcc并尝试使用-ffunction-sections和-fdata-sections来减小二进制文件的大小..lds文件不包含任何内容:
部分{}
将许多.o部分链接到.a时会发生此错误,稍后将使用它来完成构建.
我已经阅读了其他一些讨论这些选项的帖子,但没有任何内容可以澄清ENTRY()问题.在尝试减少代码大小之前,它们在部分阶段似乎不需要它(预先存在的链接器脚本显然不使用它).
文档说明: - gc-sectionts
"在执行部分链接时可以设置此选项(使用选项'-r'启用).在这种情况下,必须通过'--entry'或`--undefined'选项或通过链接描述文件中的ENTRY命令."
这就是我失去的地方.非常感谢有关如何在链接描述文件中使用--undefined,--entry或ENTRY cmd来解决此问题的更多解释.
下面的代码在使用avr-g ++编译器编译时忽略了打包属性,但由于未打包的非POD字段'float&foo :: BAR',导致我遇到此错误
是什么原因?
class foo {
public:
foo(float &bar);
private:
float &BAR;
};
foo::foo(float &bar):BAR(bar)
{
}
int main()
{
float something;
foo fooobject(something);
}
Run Code Online (Sandbox Code Playgroud)