【发布时间】:2016-11-16 13:49:24
【问题描述】:
我想为 Atmel ATMega32U4 实现类似于 Arduino 的引脚号的东西。我查看了 Arduino 的 digitalWrite 命令和相关的源文件以了解它们是如何做到的,但我认为这有点令人费解,所以我想实现一个更基本的版本。
这个想法是让整数 1 到 n 代表 AVR 芯片上的每个 I/O 引脚。我从一个指向 DDR/PORT 寄存器地址的指针数组开始,其中的索引代表引脚:
volatile uint8_t *pin_port_dir_regs[] = {
0, // NOT USED
0, // NOT USED
0, // NOT USED
0, // NOT USED
0, // NOT USED
0, // NOT USED
0, // NOT USED
&DDRE, // PIN_7
&DDRB, // PIN_8
0, // NOT USED
0, // NOT USED
0, // NOT USED
0, // NOT USED
0, // NOT USED
0, // NOT USED
&DDRB, // PIN_15
&DDRB // PIN_16
};
volatile uint8_t *pin_port_out_regs[] = {
0, // NOT USED
0, // NOT USED
0, // NOT USED
0, // NOT USED
0, // NOT USED
0, // NOT USED
0, // NOT USED
&PORTE, // PIN_7
&PORTB, // PIN_8
0, // NOT USED
0, // NOT USED
0, // NOT USED
0, // NOT USED
0, // NOT USED
0, // NOT USED
&PORTB, // PIN_15
&PORTB // PIN_16
};
我还需要知道每个 DDRx/PORTx 寄存器中的位数,所以我创建了另一个数组:
const uint8_t pin_bits[] = {
_BV(0), // NOT USED
_BV(0), // NOT USED
_BV(0), // NOT USED
_BV(0), // NOT USED
_BV(0), // NOT USED
_BV(0), // NOT USED
_BV(0), // NOT USED
_BV(6), // PIN_7
_BV(4), // PIN_8
_BV(0), // NOT USED
_BV(0), // NOT USED
_BV(0), // NOT USED
_BV(0), // NOT USED
_BV(0), // NOT USED
_BV(0), // PIN_14
_BV(1), // PIN_15
_BV(3) // PIN_16
};
为了设置引脚模式和写入引脚,我创建了以下函数:
void pin_mode(uint8_t pin, uint8_t direction) {
// defeference the pointer to the direction register
uint8_t port_dir_register = *(pin_port_dir_regs[pin]);
// get pin mask
uint8_t mask = pin_bits[pin];
// set its mode
if (direction == INPUT) {
port_dir_register &= ~mask;
} else {
port_dir_register |= mask;
}
}
void pin_write(uint8_t pin, uint8_t level) {
// defeference the pointer to the output register
uint8_t port_out_register = *(pin_port_out_regs[pin]);
// get pin mask
uint8_t mask = pin_bits[pin];
// set output
if (level == LOW) {
port_out_register &= ~mask;
} else {
port_out_register |= mask;
}
}
应该发生的是你会打电话给例如pin_mode(7, OUTPUT) 将引脚 7 设置为输出,然后 pin_write(7, HIGH) 将输出设置为 1(其中 OUTPUT 和 HIGH 是预定义的宏)。代码成功编译并上传到 AVR,但是当我测试输出时它没有响应。我想我必须写入 some 内存位置,但不是与预期寄存器对应的位置。有人发现我尝试这样做的方式有问题吗?
【问题讨论】:
-
为什么不使用 gcc 提供的标准文件 for avr?另外:如果您使用 pin_write 方法为引脚编写一些初始化,那么您只会在 prog 的启动阶段浪费大量代码。所有这些都可以在编译时通过模板代码完成,而不是单独使用每个引脚。同一作业设置 ddr 和端口寄存器一次而不是 8 次。
-
@Klaus,你指的是什么标准文件?我不知道现有的代码可以做我想做的事。此外,我不关心现阶段的启动优化 - 但感谢您的建议。
-
这对我来说似乎是在浪费宝贵的 RAM 和 ROM 空间。你的问题不是这里的主题。我们是 noi 讨论网站,它太自以为是了。编辑:对不起,我想到了最后一句话。请提供更多细节什么是错的。见How to Ask。
标签: c avr cpu-registers atmega atmel