2016-11-16 14 views
0

Я хотел бы реализовать что-то похожее на номера контактов Arduino для Atmel ATMega32U4. Я посмотрел на команду Arduino digitalWrite и связанные с ней исходные файлы, чтобы посмотреть, как они это делают, но я думаю, что это немного запутанно, поэтому я хотел реализовать более базовую версию.Реализация номеров выводов в микроконтроллере AVR, аналогичном Arduino

Идея состоит в том, чтобы иметь целые числа от 1 до n, которые представляют каждый вывод I/O на микросхеме AVR. Я начал с массивом указателей на адреса регистров 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 
}; 

мне также нужно знать битовые числа в каждой из/PortX регистров DDRx, так Я создал еще один массив:

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 успешно, но когда я тестирую вывод, он не отвечает. Наверное, я должен написать памяти, но не тот, который соответствует указанным регистрам. Кто-нибудь видит проблему с тем, как я пытаюсь это сделать?

+0

Почему вы не используете стандартные файлы, поставляемые с gcc для avr? Кроме того: если вы пишете некоторую инициализацию для контактов с чем-то вроде вашего метода pin_write, вы тратите много кода только на начальную фазу своей проги. Все это можно сделать с помощью кода шаблона во время компиляции вместо того, чтобы действовать с каждым выводом. Установите регистр ddr и port один раз не 8 раз для одной и той же работы. – Klaus

+0

@Klaus, в каких стандартных файлах вы ссылаетесь? Я не знал о существующем коде, чтобы делать то, что хочу. Кроме того, на этом этапе меня не интересует оптимизация запуска, но спасибо за совет. – Sean

+0

Это выглядит довольно пустой тратой драгоценного RAM и ROM пространства для меня. Ваш вопрос здесь не по теме. Мы - дискуссионный сайт noi, и это слишком похоже. Изменить: извините, что у меня был последний смысл. Пожалуйста, предоставьте более подробную информацию о том, что не так. См. [Ask]. – Olaf

ответ

1

Причина, почему ваш код не работает этот шаг:

uint8_t port_out_register = *(pin_port_out_regs[pin]); 

Вы хотите написать в аппаратный регистр, расположенный по конкретному адресу. Для этого вам необходимо:

*(pin_port_out_regs[pin]) = some_value; 

В противном случае вы просто модифицируете стек стека без усиления.

Попробуйте изменить на это вместо:

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

Спасибо, что сделал! – Sean

2

В ответ на комментарий я дал:

, что стандартные файлы вы смотрите?

От avr-gcc с установленным avrlibc - это стандартный набор файлов для каждого доступного контроллера.

Если ваш код что-то вроде:

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

Сделать простой PORTA= 1 << PA4 для вызова функции много отходов. И определение ваших собственных имен имен и имен контактов бесполезно. Все контакты уже определены, как вы можете видеть.

Ваша идея иметь только логический номер порта, который находится «где-то» на волшебном определенном порту, выглядит для меня не очень естественным. Если вы разрабатываете схему и программное обеспечение, вам приходится иметь дело с контактами, как описано в таблице данных. Нет «логического номера штыря».Эта идея помогает только для увеличения размера кода :-)

Кроме того, вы должны помнить, какие контакты имеют также несколько функций, таких как uarts и все другие аппаратные средства. Таким образом, переход на другое устройство всегда потребует обзора использования булавки/порта. Здесь логический номер порта также является усложняющим слоем между аппаратным обеспечением и естественным способом программного обеспечения.