|
Передача в качестве параметра порта ввода-вывода, как? |
|
|
|
Oct 7 2007, 17:23
|
Местный
  
Группа: Свой
Сообщений: 262
Регистрация: 18-02-05
Из: SPb
Пользователь №: 2 743

|
Есть набор функций работы с однопроводными устройствами,вроде Код #define ONEPIN PINC // PIN register #define ONEDDR DDRC // Data Direction Register #define ONEPORT PORTC// PORT
unsigned char OneWireReset(unsigned char mask) { ONEPORT &= ~(mask); // Normal input no pull up if (ONEPIN == 0) return 0; // detect 0V on buss error ONEDDR |= mask; // out at 0 delay_us(500); ONEDDR &= ~(mask); // Set to input delay_us(70); if ((ONEPIN & mask) == 0) { delay_us(500); return mask; } mask&=~ONEPIN; delay_us(500); return mask; } Работают замечательно, НО в железе есть восемь датчиков DS18b20, подключенных к одному порту (PORTC) и еще один датчик, подключенный к другому порту. Пробовал переделать функции так, чтобы рабочий порт можно было передавать, как параметр в функцию, но либо я чего-то не допер, либо это невозможно. На текущий момент предыдущим разработчиком просто сделан второй набор функций, где они работают с другим портом. На мой взгляд это не совсем правильно.
|
|
|
|
|
Oct 7 2007, 18:18
|
Местный
  
Группа: Свой
Сообщений: 262
Регистрация: 18-02-05
Из: SPb
Пользователь №: 2 743

|
Цитата(rezident @ Oct 7 2007, 21:55)  Почему это по-вашему неправильно? У вас нехватка памяти или какая-то другая причина извращаться с оптимизацией кода? Неправильно - потому, что сделано несколько подобных устройств и хочется не то, чтобы оптимизировать, а скорее унифицировать код - то есть, сделать одинаковые функции для разных проектов. Потому что потом приходится путаться, какая функция из какого именно порта читает.
|
|
|
|
|
Oct 7 2007, 18:40
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(AlexMad @ Oct 8 2007, 00:18)  Неправильно - потому, что сделано несколько подобных устройств и хочется не то, чтобы оптимизировать, а скорее унифицировать код - то есть, сделать одинаковые функции для разных проектов. Потому что потом приходится путаться, какая функция из какого именно порта читает. Дык если функция работает одинаково с портами, то чтобы не переписывать обе функции можно писать одну, но при включении ее в текст исходника манипулировать адресами портов с помощью макросов. В противном случае в функцию придется передавать все три адреса. Либо передавать номер "набора" из адресов портов, но при этом добавить кучу ветвлений для проверки и вызова той или иной операции внутри вашей функции. Или вы считаете что куча ветвлений, лучше линейного кода?
|
|
|
|
|
Oct 7 2007, 18:54
|
Местный
  
Группа: Свой
Сообщений: 262
Регистрация: 18-02-05
Из: SPb
Пользователь №: 2 743

|
Цитата(rezident @ Oct 7 2007, 22:40)  Дык если функция работает одинаково с портами, то чтобы не переписывать обе функции можно писать одну, но при включении ее в текст исходника манипулировать адресами портов с помощью макросов. В противном случае в функцию придется передавать все три адреса. Либо передавать номер "набора" из адресов портов, но при этом добавить кучу ветвлений для проверки и вызова той или иной операции внутри вашей функции. Или вы считаете что куча ветвлений, лучше линейного кода? Так я в вопросе и писал про то, что хочу передать как параметры все три адреса (порт, пин, ддр). Проблема в том и заключается, что сами порты не передать, а если передавать условные значения, то придется делать кучу ветвлений. Просто хотелось сделать красиво - одна функция на все порты, только в параметре указывать, какие именно.
|
|
|
|
|
Oct 7 2007, 19:58
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
В avr-gcc нормально передаются указатели на порты, думаю, что и у IAR должны передаваться, причём не удивлюсь, если там найдётся какое-то "волшебное слово" по типу __flash, которое ещё и делает это более удобным. Для большинства портов идёт единый порядок PIN-DDR-PORT (не выполняется это, например, для порта F у меги64, который в наследство от меги103 достался как порт толькона чтение и его DDRF, PORTF улетели в memory-mapped IO, включаемое при стёртом фьюзе M103). Учитывая это, можно (но осторожно) обойтись одним указателем. Код #include <avr/io.h> #define F_CPU 8000000UL #include <util/delay.h>
typedef struct { uint8_t pin; uint8_t ddr; uint8_t port; } port_t;
uint8_t OneWireReset(volatile port_t *pport, uint8_t mask) { pport->port &= ~mask; if( (pport->pin & mask) == 0) return 0; // detect 0V on buss error pport->ddr |= mask; // out at 0 _delay_ms(0.5); pport->ddr &= ~mask; // Set to input _delay_us(70); if( (pport->pin & mask) == 0) { _delay_ms(0.5); return mask; } mask &= ~pport->pin; _delay_ms(0.5); return mask; }
uint8_t test(void) { return OneWireReset( (volatile port_t*)&PINB, 0x02); }
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Oct 8 2007, 04:48
|
Местный
  
Группа: Свой
Сообщений: 262
Регистрация: 18-02-05
Из: SPb
Пользователь №: 2 743

|
Цитата(ReAl @ Oct 7 2007, 23:58)  Учитывая это, можно (но осторожно) обойтись одним указателем. Код #include <avr/io.h> #define F_CPU 8000000UL #include <util/delay.h>
typedef struct { uint8_t pin; uint8_t ddr; uint8_t port; } port_t;
} Вот тут уже ближе. Я с ходу именно так и сделал, но, толи кодевижен это не хочет понимать, толи это все-таки не получится. У меня при инициализации Код pin=PINB , а также по остальным двум портам матерно ругается, что PINB должно быть константой, указатель на PINB тоже не принимает, говорит порты нельзя передать  После этого я свой вопрос и задал. А вот насчет обращения, как к памяти это интересно, попробую.
|
|
|
|
|
Oct 8 2007, 08:36
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(AlexMad @ Oct 8 2007, 06:48)  Я с ходу именно так и сделал, но, толи кодевижен это не хочет понимать, ... А вот насчет обращения, как к памяти это интересно, попробую. Ну или выбрось каку, или пробуй вручную адрес писать - как адрес памяти, из скобок в register summary. В моём примере как раз и сделано через "обращения к памяти" Код #define MEGA8_PINB_ADR 0x36 uint8_t test(void) { return OneWireReset( (volatile port_t*)MEGA8_PINB_ADDR, 0x02); } У avr-gcc в h-файлах адреса портов как адреса памяти сразу и прописаны, а уж он потом смотрит - если попадает в достижимое по in/out или sbi/cbi - то оптимизирует до коротких команд. И если в приведенном мной примере объявить OneWireReset как inline - то он её по месту вставит именно с командами sbi/cbi/sbis/sbic даже если передать (volatile port_t*)0x36
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Oct 8 2007, 09:12
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(AlexMad @ Oct 8 2007, 12:48)  А вот насчет обращения, как к памяти это интересно, попробую. В ИАРе прокатывает вот такой код Код
char* pPORTA = &PORTA; *pPORTA = 0x55; То бишь, при присвоении указателю адреса порта происходит прибавление к адресу IO 0х20
--------------------
|
|
|
|
|
Oct 8 2007, 13:38
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(rezident @ Oct 8 2007, 15:20)  должен ли быть только указатель на структуру port_t типом volatile или все-таки все члены структуры должны быть volatile? volatile там не указатель, а тот объект, на который он указывает. Ведь не port_t * volatile pport;написано. Т.е. вся структура (все её поля) - volatile. Так же, как все они const, если вся структура const. Вместо этого приписывать кавлификатор персонально к полям имеет смысл только тогда, когда часть полей volatile, часть - нет. Собственно, квалификатор нужно было вообще в typedef включить и везде использовать просто port_t *Код typedef volatile struct { uint8_t pin; uint8_t ddr; uint8_t port; } port_t;
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Oct 8 2007, 16:19
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(ReAl @ Oct 8 2007, 17:38)  Собственно, квалификатор нужно было вообще в typedef включить и везде использовать просто port_t *Код typedef volatile struct { uint8_t pin; uint8_t ddr; uint8_t port; } port_t; Объясните мне пожалуйста, зачем эту структуру содержащую адреса регистров портов нужно объявлять volatile ? Недопонимаю...
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|