我正在使用avr微控制器和C ++ 14。在尝试为io引脚实现C ++包装时,我偶然发现了一个错误。
这个想法是,让包装器将sfr
作为模板参数,以便于编译器的简单优化(不要在那里使用额外的函数并使用模板参数,我可以向编译器指出,我的论点应始终是编译时可评估的)。我想,可以有constexpr uint8_t& x = ...
个变量引用一些编译时已知的地址。但以下不起作用(定义取自avr include):
#include <avr/io.h>
constexpr uint32_t addr[] = { _SFR_IO_ADDR(PORTB) };
constexpr uint32_t GetAddr()
{
return addr[0];
}
constexpr decltype(auto) Get()
{
_SFR_IO8(GetAddr());
}
int main() {
auto addr = GetAddr();
auto b = Get();
_SFR_IO8(addr) &= ~(1 << 2);
b |= (1 << 3);
}
它在error: expression '*(volatile uint8_t*)(GetAddr() + 32u)' has side-effects
函数中为Get()
提供了decltype(auto)
。用uint8_t&
取代constexpr uint8_t
(当然)没有帮助。
为什么我无法获得指向_SFR_IO_ADDR(PORTB) = (volatile uint8_t*)(_SFR_IO8(5u) - 32u) = (volatile uint8_t*)(5u + 32u - 32u)
内存位置的NSDataDetector
引用?
答案 0 :(得分:0)
我正在做这样的事情:
#include <avr/io.h>
#include <util/delay.h>
constexpr uint8_t INPUT =0;
constexpr uint8_t OUTPUT =1; // output + set pin LOW
constexpr uint8_t OUTPUT_LOW =1; // output + set pin LOW
constexpr uint8_t INPUT_PULLUP =2;
constexpr uint8_t OUTPUT_HIGH =3; // output + set pin HIGH
struct pin_setting {
uint8_t p; // PORTx is enough, because DDRx is allway -1, PINX -2
uint8_t bit_mask;
};
//#define MEM8_OFFSET 0x100 // for megaxxx0
constexpr pin_setting pins[] {
{(uint16_t)&PORTD, _BV(PD0)},
{(uint16_t)&PORTD, _BV(PD1)},
{(uint16_t)&PORTD, _BV(PD2)},
{(uint16_t)&PORTD, _BV(PD3)},
{(uint16_t)&PORTD, _BV(PD4)},
{(uint16_t)&PORTD, _BV(PD5)},
{(uint16_t)&PORTD, _BV(PD6)},
{(uint16_t)&PORTD, _BV(PD7)},
{(uint16_t)&PORTB, _BV(PB0)},
{(uint16_t)&PORTB, _BV(PB1)},
{(uint16_t)&PORTB, _BV(PB2)},
{(uint16_t)&PORTB, _BV(PB3)},
{(uint16_t)&PORTB, _BV(PB4)},
{(uint16_t)&PORTB, _BV(PB5)},
{(uint16_t)&PORTC, _BV(PC0)},
{(uint16_t)&PORTC, _BV(PC1)},
{(uint16_t)&PORTC, _BV(PC2)},
{(uint16_t)&PORTC, _BV(PC3)},
{(uint16_t)&PORTC, _BV(PC4)},
{(uint16_t)&PORTC, _BV(PC5)}
};
inline void mDigitalSet(uint8_t pin) {
_SFR_IO8(pins[pin].p) |= pins[pin].bit_mask;
}
inline void mDigitalClr(uint8_t pin) {
_SFR_IO8(pins[pin].p) &= ~pins[pin].bit_mask;
}
inline void mDigitalToggle(uint8_t pin) {
_SFR_IO8(pins[pin].p-2) = pins[pin].bit_mask;
}
inline void mDigitalWrite(uint8_t pin, bool level=true) {
level ? mDigitalSet(pin) : mDigitalClr(pin);
}
inline bool mDigitalRead(uint8_t pin) {
return _SFR_IO8(pins[pin].p-2) & pins[pin].bit_mask;
}
inline void mPinMode(uint8_t pin, uint8_t dir) {
if (dir & 1) {
_SFR_IO8(pins[pin].p-1) |= pins[pin].bit_mask;
} else {
_SFR_IO8(pins[pin].p-1) &= ~pins[pin].bit_mask;
}
mDigitalWrite(pin, dir&2);
}
它并不完美,可以做得更好。 (这只是概念的证明,从未使用过)
Arduino以同样的方式将SFR
指针存储到PROGMEM
- uint16_t
。
答案 1 :(得分:0)
我希望可以将类似的模板化编译时间减少到一条指令。我必须使用一些模板元编程才能使这项工作完成。
一个简单的例子:
#include <avr/io.h>
struct A {
constexpr static volatile uint8_t *const PORT() { return &PORTA; }
constexpr static volatile uint8_t *const DDR() { return &DDRA; }
};
template <class port, u1 pin> class IOpin {
constexpr static volatile uint8_t *DDR = port::DDR();
constexpr static volatile uint8_t *PORT = port::PORT();
constexpr static uint8_t mask = 1 << pin;
public:
inline IOpin() {}
inline static void output() { *DDR |= mask; }
inline static void input() { *DDR &= ~mask; }
inline static void set() { *PORT |= mask; }
}
// Use as type or instance
using myPinType = IOpin<A, 1>;
IOpin<A, 1> myPinInstance;
// Use myPin
myPinType::set(true);
myPinInstance.output();
完整实施:https://github.com/cinderblock/AVR/blob/master/AVR%2B%2B/IOpin.h