简体   繁体   English

在类似于Arduino的AVR微控制器中实现引脚号

[英]Implementing pin numbers in AVR microcontroller similar to Arduino

I'd like to implement something similar to Arduino's pin numbers for an Atmel ATMega32U4. 我想为Atmel ATMega32U4实现类似于Arduino的引脚号的功能。 I've looked at Arduino's digitalWrite command and associated source files to see how they do it, but I think this is slightly convoluted so I wanted to implement a more basic version. 我查看了Arduino的digitalWrite命令和相关的源文件以了解它们的工作方式,但是我认为这有点令人费解,所以我想实现一个更基本的版本。

The idea is to have integers 1 to n that represent each of the I/O pins on the AVR chip. 想法是使整数1到n代表AVR芯片上的每个I / O引脚。 I started with an array of pointers to the addresses of the DDR/PORT registers, where the index would represent the pin: 我从指向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
};

I also need to know the bit numbers in each of the DDRx/PORTx registers, so I created another array: 我还需要知道每个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
};

To set the pin mode and write to the pins, I created the following functions: 要设置引脚模式并写入引脚,我创建了以下功能:

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;
    }
}

What's supposed to happen is that you would call eg pin_mode(7, OUTPUT) to set pin 7 as an output, and then pin_write(7, HIGH) to set the output to 1 (where OUTPUT and HIGH are predefined macros). 应该发生的情况是,您将调用例如pin_mode(7, OUTPUT)将引脚7设置为输出,然后pin_write(7, HIGH)将输出设置为1(其中OUTPUT和HIGH是预定义的宏)。 The code compiles and uploads to the AVR successfully, but when I test the output it doesn't respond. 代码可以编译并成功上传到AVR,但是当我测试输出时,它没有响应。 I guess I must be writing to some memory location, but not the one corresponding to the intended registers. 我想我一定要写某个存储位置,但是不能写对应于预期寄存器的位置。 Does anyone see a problem with the way I am trying to do this? 有人看到我尝试执行此操作的方式的问题吗?

As answer to the comment I gave: 作为对我的评论的答复:

what standard files do you refer to? 您指的是什么标准文件?

From avr-gcc with installed avrlibc is a standard set of files for each controller available. 对于已安装avrlibc的avr-gcc,它是每个可用控制器的标准文件集。

If your code is something like: 如果您的代码是这样的:

#include <avr/io.h>  // automatic include correct io from device like
                     // <avr/iom32u4.h> in your case. That file defines
                     // all registers and pin descriptions and also irq
                     // vectors!

// So you can write:
int main()
{
     DDRA= 1 << PA4;  // enable output Pin 4 on Port A
     PORTA= 1 << PA4; // set output Pin4 on Port A high

     // and normally on startup all needed output pins will be 
     // set with only one instruction like:
     // To set Pin 2..4 as output
     DDRA= ( 1 << PA4) | ( 1 << PA3 ) | ( 1 << PA2 );
}

Make a simple PORTA= 1 << PA4 to a function call is a lot of waste. 对函数调用进行简单的PORTA= 1 << PA4浪费很多。 And defining your own register names and pin names is useless. 并且定义自己的寄存器名称和引脚名称是没有用的。 All the pins are already defined as you can see. 如您所见,所有引脚均已定义。

Your idea to have only a logical port number which is located "somewhere" on a magic defined port looks not very natural to me. 您的想法是,只有一个逻辑端口号位于“魔术定义的”端口上的“某处”,这对我来说不是很自然。 If you design a circuit and the software, you have to deal with the pins as described in the datasheet. 如果设计电路和软件,则必须按照数据表中的说明处理引脚。 There is no "logical pin number". 没有“逻辑引脚号”。 This idea helps for nothing but for bigger code size :-) 这个想法对增加代码大小无济于事:-)

In addition you have to remember which pins have also multiple functions like for uarts and all the other hardware stuff. 另外,您必须记住哪些引脚还具有多种功能,例如用于uart和所有其他硬件的功能。 So moving to another device will always need a review on pin / port usage. 因此,移至另一台设备将始终需要检查引脚/端口的使用情况。 Here a logical port number is also a complicating layer between the hardware and the natural way of software. 在此,逻辑端口号也是硬件和软件自然方式之间的复杂层。

The reason to why your code does not work is this step: 您的代码无法正常工作的原因是此步骤:

uint8_t port_out_register = *(pin_port_out_regs[pin]);

You want to write to a hardware register located at a specific address. 您要写入位于特定地址的硬件寄存器。 To do this you need to: 为此,您需要:

*(pin_port_out_regs[pin]) = some_value;

Otherwise you will just modify stack memory to no gain. 否则,您将只是修改堆栈内存而没有收益。

Try to change to this instead: 尝试改为以下内容:

void pin_write(uint8_t pin, uint8_t level)
{
    uint8_t *port_out_register = pin_port_out_regs[pin];
    uint8_t mask = pin_bits[pin];

    if (level == LOW) {
        *port_out_register &= ~mask;
    } else {
        *port_out_register |= mask;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM