roboforum.ru

Технический форум по робототехнике.

Передача аргментом ножки порта

Передача аргментом ножки порта

Hagrael » 16 авг 2011, 16:01

Здравствуйте, программисты! Я изучил C++, но ни разу не видел операции, которую сразу же увидел при программировании микроконтроллеров:
Код: Выделить всёРазвернуть
PORTC.1 = 0;

Что она делает, и можно ли каким-то образом передать эту ножку порта аргументом функции?

Re: Передача аргментом ножки порта

Grem » 16 авг 2011, 16:11

Устанавливает лог 0 на первый бит С порта.
avr123.nm.ru и читать до дыр :)

Re: Передача аргментом ножки порта

=DeaD= » 16 авг 2011, 16:14

Вообще говоря это не Си++ :) это некоторая нашлепка на него от CvAVR.

Правильный Си++ :) делает так (на примере установки бита, т.е. PORTC.1=1):

PORTx |= 1 << BIT_NUMBER;

PORTx - нужный нам порт (соотв. ему ячейка памяти, если я правильно помню как там что устроено), например PORTC, BIT_NUMBER - номер бита, например 1.

Т.е., например, PORTC |= 0x02;

Re: Передача аргментом ножки порта

dccharacter » 16 авг 2011, 16:38

Передать одним аргументом, наверное, нельзя, а вот двумя - можно. Адрес регистра + маска.

Адрес можно передать как в явном виде (см. даташит), так и скорее всего взять его от имени порта (хотя не уверен - там в хидерах такое понакручено).

т.е.

unsigned char * addr_ptr;
addr_ptr = &PORTC; //хотя наверное в CvAVR PORTC - это само по себе что-то структуры
some_function (addr_ptr, mask);

Добавлено спустя 51 секунду:
=DeaD= писал(а):Т.е., например, PORTC |= 0x02;

Так он передаст не ножку в функцию, а беззнаковый чар

Re: Передача аргментом ножки порта

Hagrael » 16 авг 2011, 18:39

Grem, я начинаю читать книгу "Самоучитель разработчика устройств на микроконтроллерах AVR". Но все-таки интересно, dccharacter, как внутри применять этот код? Если таким образом:
Код: Выделить всёРазвернуть
addr_ptr.mask

то у меня выходит ошибка. Ваш код:
=DeaD=, ваш код:
Код: Выделить всёРазвернуть
PORTC |= 0x02;

как я понимаю, поставит на второй с конца бит 1. А если я пишу
Код: Выделить всёРазвернуть
PORTC.2 = 0;

то как тогда эта инструкция расшифруется?

Большое спасибо за быстрые отзывы!

Re: Передача аргментом ножки порта

Виталий » 16 авг 2011, 19:18

Вообще говоря это не Си++ это некоторая нашлепка на него от CvAVR.

Могли бы назвать PORTC.b1 и тогда уместились бы в C Bitfields. =)

Re: Передача аргментом ножки порта

boez » 16 авг 2011, 19:56

Эта вся беда оттого, что в С работы с железом нету как таковой, а людям хочется :)

Запись PORTC.1 ошибочна с точки зрения С, любой _стандартный_ С компилятор должен выдавать ошибку. Но в некоторых компиляторах, заточенных именно под АВРки, как минимум в CVAVR, такое прокатывает. При этом это уже магия компилятора, соответственно поддержка "указателей на ножку" - тоже вопрос нестандартного расширения языка, насколько я знаю - такого нету.

Что касается все же передачи ножки в функцию - отдельно ссылку на порт можно передать как обычный указатель, поскольку в АВР порты - это ячейки памяти. Т.е. обращение к такому порту будет выглядеть например так:

Код: Выделить всёРазвернуть
void SetPinTo1(volatile unsigned char *port, unsigned char bit)
{
    *port |= (1<<bit);
}
void SetPinTo0(volatile unsigned char *port, unsigned char bit)
{
    *port &= ~(1<<bit);
}
void SetPin(volatile unsigned char *port, unsigned char bit, unsigned char val)
{
    *port = (*port&~(1<<bit))|((val&1)<<bit);
}


вызываться это дело должно как SetPinTo1(&PORTA,0) и работать чисто теоретически должно на любом компиляторе, разве что тип указателя может придется подкрутить.

как-то так, на WinAVR (компилятор gcc) компилится, будет ли работать - не проверял, не на чем.

Re: Передача аргментом ножки порта

MiBBiM » 16 авг 2011, 20:51

http://easyelectronics.ru/avr-uchebnyj- ... h-rom.html - информация по адресным пространствам.
Код: Выделить всёРазвернуть
PORTC.2 = 0;  =>  PORTC &= ~(1<<2);

Re: Передача аргментом ножки порта

dccharacter » 16 авг 2011, 22:58

boez писал(а):
Код: Выделить всёРазвернуть
void SetPinTo1(volatile unsigned char *port, unsigned char bit)
{
    *port |= (1<<bit);
}




Не, ну а я чо сказал? :-)))

Re: Передача аргментом ножки порта

MiBBiM » 16 авг 2011, 23:12

есть ведь еще индусский подход:
Код: Выделить всёРазвернуть
enum ports_pins { PORTC1, PORTC2, PORTC3, PORTC4, PORTD1, PORTD2, PORTD3, PORTD4 };

void my_func (ports_pins out)
{
  switch(out) {
    case PORTC1: PORTC.1 = 1; break;
    case PORTC2: PORTC.2 = 1; break;
    case PORTC3: PORTC.3 = 1; break;
    case PORTC4: PORTC.4 = 1; break;
    case PORTD1: PORTD.1 = 1; break;
    case PORTD2: PORTD.2 = 1; break;
  }
}

Re: Передача аргментом ножки порта

Vooon » 17 авг 2011, 00:56

2 boez: там кажется нужна была дополнительная магия. Ну и через mmap оно тормознее.
Если достаточно #define'а то лучше обойтись им.

Re: Передача аргментом ножки порта

Hagrael » 17 авг 2011, 08:25

Всем спасибо! Вопрос решен!

Re: Передача аргментом ножки порта

boez » 17 авг 2011, 10:48

Vooon писал(а):2 boez: там кажется нужна была дополнительная магия. Ну и через mmap оно тормознее.
Если достаточно #define'а то лучше обойтись им.

Это понятно, что если достаточно дефайнов - то хорошо. А магия там, насколько я знаю, спрятана в компилятор - в хидерах, если не баловаться с _SFR_ASM_COMPAT и ассемблером, все регистры определяются как
Код: Выделить всёРазвернуть
#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
#define _MMIO_WORD(mem_addr) (*(volatile uint16_t *)(mem_addr))
#define _MMIO_DWORD(mem_addr) (*(volatile uint32_t *)(mem_addr))

А вот уже компилятор, если видит, что указатель константный и в пределах 0x20..0x5f, заменяет работу с памятью на in/out.

Это все про avr-gcc. Другими не балуюсь.

Re: Передача аргментом ножки порта

linvinus » 17 авг 2011, 18:20

Немного не по теме,но возможно автору пригодится.
когда нужно установить несколько бит на порту то операции с масками будут занимать больше чем один такт.
В avr есть аппаратный xor на порту, это запись не в PORTB а в PINB
подробнее http://hackaday.com/2011/07/09/hardware ... ntrollers/


Rambler\'s Top100 Mail.ru counter