只有在使用-Os,-O1和-O2时,C/C++编译器才能使用常量参数(编译时已知)优化单层函数.他们没有优化所有层.只有-O3可以做到这一点.gcc是WinAVR 4.3.3,它不支持属性"optimize".
void inner(double value)
{
//operations using value
//...
}
void outer(double value)
{
//few operations using value
//...
inner(value);
}
int main()
{
inner(1); //optimize
outer(1); //only optimize by using -O3
}
Run Code Online (Sandbox Code Playgroud)
除以下之外,有哪些可能的解决方案?
更新:
//inner function
static inline void _delay_us(double __us) __attribute__((always_inline));
//outer function
void f(double);
inline f1(double);
static inline f2(double);
static f3(double);
Run Code Online (Sandbox Code Playgroud)
f1已经过优化,但发出警告'_delay_us'是静态的,但在内联函数'f1'中使用,由于静态函数问题,它不是静态的.其他人没有优化.
解:
static inline void outer(double) __attribute__((always_inline));
Run Code Online (Sandbox Code Playgroud)
内联是关键.我的外部函数对于内联来说太大了.属性always_inline强制函数内联.这允许编译器以比编写优化更少的编译成本来优化函数.-O3足够聪明,可以进行优化但不是-Os.-Os可能需要一些编译器选项.(关键字static是必需的,因为内部函数也是静态内联的.)
是否有一种简单的方法可以使用用于Arduino IDE的库以及我为AVR-G ++/AVR-GCC编写的C和汇编代码?
我正在尝试使用Adafruit Wave Shield库,但只是包含头文件和cpp文件并没有太大的帮助.我可以以某种方式编译它并将其链接到我的C代码?或者也许只是找到一种方法来使用我的C代码进行编译.
目前,当我尝试做一些简单的事情时:
#include "WaveHC/WaveHC.h"
SdReader card;
card.init();
Run Code Online (Sandbox Code Playgroud)
我受到了欢迎:
70: undefined reference to `SdReader::init(unsigned char)'
Run Code Online (Sandbox Code Playgroud) 目前我们正在学习如何编程AVR微控制器(仅限Ansi C89标准).部分包含的驱动程序是一个标题,用于处理调度,即以不同的速率运行任务.我的问题是与文档中的引用有关:
"每个任务必须通过使用静态局部 变量来维护自己的状态."
那是什么意思呢?他们似乎传递void*给维持状态的功能但是不使用它?
看一下我收集的文件中的代码,这就是他们的意思:
{.func = led_flash_task, .period = TASK_RATE / LED_TASK_RATE, .data = 0}
/* Last term the pointer term */
Run Code Online (Sandbox Code Playgroud)
有一个函数在数组中使用上述参数运行,但它只作为调度程序.然后功能led_flash_task是
static void led_flash_task (__unused__ void *data)
{
static uint8_t state = 0;
led_set (LED1, state); /*Not reall important what this task is */
state = !state; /*Turn the LED on or off */
}
Run Code Online (Sandbox Code Playgroud)
并从标题
#define __unused__ __attribute__ ((unused))
Run Code Online (Sandbox Code Playgroud)
而传递void *data是为了维持任务的状态?这是什么意思?
谢谢您的帮助
我在我的Arduino Uno上运行了简单的串行程序,它只是回显你输入的内容.在Arduino Sketch IDE(v22)中运行时,这非常有效.
int incomingByte = 0; // for incoming serial data
void setup() {
Serial.begin(115200); // opens serial port, sets data rate
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// say what you got:
Serial.print("I received: ");
Serial.println(incomingByte, DEC);
}
}
Run Code Online (Sandbox Code Playgroud)
(代码来自http://arduino.cc/en/Serial/Available)
但是,我不想使用Arduino IDE而宁愿使用avr-g ++编译我的C++代码,所以我写了这个,它应该与上面完全相同:
extern "C" {
#include <avr/io.h>
}
#include <HardwareSerial.h>
extern …Run Code Online (Sandbox Code Playgroud) 例如,在Atmel处理器的codevision编译器中,可以指定全局变量的存储地址
int a @0x100; // will place the variable at the address 0x100 in RAM
Run Code Online (Sandbox Code Playgroud)
当然,根据标准C,变量可以在声明时初始化
int a=42;
Run Code Online (Sandbox Code Playgroud)
但是,我没有发现任何可能同时做到这两点.int a @0x100 = 42或者int a = 42 @0x100;不工作,它们会导致编译器错误.
你可能会问为什么这么做很重要,因为人们可以这样做
int a @0x100;
int main()
{
a = 42;
//...
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我在EEPROM中有变量,我需要初始化它们,因为这是自动生成带有值的eeprom文件的唯一方法.我以后不能分配这些值,因为在这种情况下,它实际上会在程序的每个开始时将值写入eeprom.
我有一个非常简单的中断服务程序(ISR)为atmega328编写,并使用AVR工作室使用avrgcc(使用-Os)编译.
ISR (TIMER0_OVF_vect) {
txofcnt++; //count overflows and store in uint16_t
}
Run Code Online (Sandbox Code Playgroud)
如果你注意到生成的程序集(如下),它使用r24,r25来获取增加易失性uint16_t txofcnt的作业,但它也是push-write-pop r1,r28,r29而没有读取它们.它还有一个额外的r0推/弹,而不会在它们之间使用它.
我不知道为什么r1被推,清除然后最终poped.但是为什么gcc觉得需要将EIMSK和GPIOR0加载到寄存器中然后不使用它们.如果你能告诉我GPIOR0的用途是什么,那么数据表说它存在但没有描述.
00000258 <__vector_16>:
ISR (TIMER0_OVF_vect) {
258: 1f 92 push r1
25a: 0f 92 push r0
25c: 00 90 5f 00 lds r0, 0x005F
260: 0f 92 push r0
262: 11 24 eor r1, r1
264: 8f 93 push r24
266: 9f 93 push r25
268: cf 93 push r28
26a: df 93 push r29
26c: cd b7 in r28, 0x3d ; 61 reads register …Run Code Online (Sandbox Code Playgroud) 我正在使用Atmega328在SD卡上实现FAT16.
我经常需要更改扇区中的一个或两个字节(512B区域).
我知道Flash是如何工作的,它需要立刻覆盖整个扇区,但我想知道是否有一些特殊的命令可以使卡本身处理它?
关键是,atmega只有2k RAM,而且只为读取 - 修改 - 写入SD卡缓冲区分配512是非常不利的.没有其他办法吗?
(PS.AFAIK atmega本身不能有外部ram)
为微控制器编程可重用模块(在我的情况下为AVR)需要一般IO引脚的灵活性.每个引脚由字母(AG)和数字(0-7)定义.然而,它由三个寄存器中相同位置的一位控制.因此配置文件需要包含四个条目(指向寄存器的3个指针+ 1个位置),这不是那么优雅.
简单的解决方法是简单地接受这个,但由于这是一个常见的问题,它至少应该得到一点关注.
让预编译器像这样重复工作会很好:
//CONFIGURATION
#define IO_NAME B5
//MACRO
#define PORT_(ID)
#define PIN_(ID)
#define DDR_(ID)
#define BIT_(ID)
Run Code Online (Sandbox Code Playgroud)
结果应如下所示
PORT_(IO_NAME) => PORTB
PIN_(IO_NAME) => PINB
DDR_(IO_NAME) => DDRB
BIT_(IO_NAME) => 5
Run Code Online (Sandbox Code Playgroud)
结果表达式在AVR Studio中定义.
我无法弄清楚如何忽略字母而不是数字,所以我尝试了连接:
#define PORT_(REG, BIT) PORT_2(REG, BIT)
#define PIN_(REG, BIT) PIN_2(REG, BIT)
#define DDR_(REG, BIT) DDR_2(REG, BIT)
#define PORT_2(REG, BIT) (PORT ## REG)
#define PIN_2(REG, BIT) (PIN ## REG)
#define DDR_2(REG, BIT) (DDR ## REG)
#define BIT(REG, BIT) (BIT)
Run Code Online (Sandbox Code Playgroud)
额外的层需要使用任何#defined值作为REG或BIT.
以下代码按预期工作:
#define IO_NAME_REG B
#define IO_NAME_BIT …Run Code Online (Sandbox Code Playgroud) 在调试会话期间,我发现snprintf在使用avr-gcc编译代码时无法按预期工作.示例代码应该简单地将浮点值3999.9f转换为其字符表示形式.
这是一个最小的测试用例:
int TestSnprintf(void)
{
const float inputValue = 3999.9f;
/* Print with a fixed width of 6 characters (5 numbers and 1 dot).
The buffer must have a length of 7, because snprintf appends a '\0' at the end. */
char buf[7U] = {0, 0, 0, 0, 0, 0, 0};
const uint8_t bufferSize = 7U;
if(6 != snprintf(buf, bufferSize, "%06.1f", inputValue))
{
return -1;
}
if( buf[0] != '3'
|| buf[1] != '9'
|| buf[2] …Run Code Online (Sandbox Code Playgroud) 尝试寻址时uint64,AVR gcc?¹?中的各个字节。给了我一个奇怪的序言/结尾,而使用编写的同一函数uint32_t给了我一个ret(示例函数为NOP)。
为什么gcc这样做?我该如何删除?
您可以在此处在Compiler Explorer中查看代码。
???来自Arduino 1.8.9发行版的gcc 5.4.0,parameters = -O3 -std=c++11。
源代码:
#include <stdint.h>
uint32_t f_u32(uint32_t x) {
union y {
uint8_t p[4];
uint32_t w;
};
return y{ .p = {
y{ .w = x }.p[0],
y{ .w = x }.p[1],
y{ .w = x }.p[2],
y{ .w = x }.p[3]
} }.w;
}
uint64_t f_u64(uint64_t x) {
union y {
uint8_t p[8];
uint64_t w;
};
return y{ .p = {
y{ …Run Code Online (Sandbox Code Playgroud)