Работа с портами в функциях. Порт как аргемент для функции

Обсуждаем контроллеры компании Atmel.
ZiperRUS
Родился
Сообщения: 18
Зарегистрирован: Сб июн 08, 2013 19:12:54

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение ZiperRUS »

Здравствуйте друзья. Вот и прошли выходные дни, кто то может расстроиться и сказать как то быстро они прошли ничего не успел, кто то наоборот подумать прошли и славу богу что прошли. Это как про тему оптимист пессимист и стакан. У каждого своё на уме всем не угодишь!!!
Так вот к чему это я , проснувшись сегодня поняв. осмыслив то что что прошло уже не вернёшь, а всё новое только впереди я решил сюда написать как с вашей помощью я решил задачи собственно темы этого форума.
Работа с портами в функциях. Порт как аргумент для функции

функция из исходника многоуважаемого uk8amk для установки пина порта

void PortSetPin(volatile char *AddressPort, char NumberPin, char Value)
{
if( Value )
{
*AddressPort |= (1<<NumberPin);
}else
{
*AddressPort &= ~(1<<NumberPin);
};
}

где :
AddressPort адрес порта например ((char*)0x38);//PORTB SRAM adress +0x20
NumberPin номер пина порта 0-7
Value значение в какое состояние переключить пин порта 0 или 1
пример вызова:
volatile char *port;
port = ((char*)0x32); //PORTD SRAM adress + 0x20
PortSetPin(port, 0, 1);

функция для определения текущего состояния пина, это уже я сам постарался :oops:
возвращает 1 если пин установлен (1) или 0 если пин не установлен (0)

int TestPinTrue(volatile char *AddressPin, char NumberPin)
{
if(*AddressPin &(1<<NumberPin)) return 1; // проверяем есть ли 1 на PINB.7
else return 0;
}

где:
AddressPin адрес PINB ((char*)0x36); //PINB SRAM adress + 0x20
NumberPin номер пина у которого проверяем состояние 0-7
пример вызова:
volatile char *port;
volatile char *pin;
port = ((char*)0x32); //PORTD SRAM adress + 0x20
pin = ((char*)0x36); //PINB SRAM adress + 0x20

if(TestPinTrue(pin,7)==1) PortSetPin(port, 0, 1);
else PortSetPin(port, 0, 0);
В этом примере проверяется состояние PINB.7 если на PINB.7==1 тогда и на выходе PORD.0=1
иначе PINB.7==0 тогда и на выходе PORD.0=0

Спасибо всем благородно, великодушно кто принимал участие в решении этой интереснейшей задачи.
Итог, решение написал подробно так как встречал не раз на форумах такую ситуацию когда идёт обсуждение какого то вопроса хоть на 10стр. отдельные слова фразы предложения я на последней стр написано : ааааааа спасибо я всё понял, тему можно закрывать :o :shock:
Мне кажется что надо писать в таких ситуациях, так сказать подводить итог какая была задача и как что ты понял как её реализовал!!! потому что это может быть интересно не только тебе но и другим ! не надо быть эгоистом!!! :)
Аватара пользователя
uni
Встал на лапы
Сообщения: 137
Зарегистрирован: Пт дек 07, 2007 11:17:40
Откуда: г. Екатеринбург
Контактная информация:

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение uni »

Можно использовать для подобных целей следующий набор макросов:

Код: Выделить всё

#define sbi(port, b) (port) |= (1 << (b))
#define cbi(port, b) (port) &= ~(1 << (b))
#define TOGGLE(x,y) ((x) ^= (1<<(y)))
#define CHECKBIT(x,y) ((x) & (1<<(y)))
#define PortSetPin(port,b,value) if (value) sbi((port),(b)); else cbi((port),(b))


К сожалению, я не понял как записать последнюю функцию через ? и :. Первые два макроса взяты из WinAVR.

Код: Выделить всё

if(TestPinTrue(pin,7)==1) PortSetPin(port, 0, 1); 
else PortSetPin(port, 0, 0);


будет выглядеть вот так:

Код: Выделить всё

if CHECKBIT( PINA, 7 ) sbi(PORTB, 0); else cbi(PORTB, 0);
Россия навсегда!
ZiperRUS
Родился
Сообщения: 18
Зарегистрирован: Сб июн 08, 2013 19:12:54

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение ZiperRUS »

будет выглядеть вот так:

Код: Выделить всё

if CHECKBIT( PINA, 7 ) sbi(PORTB, 0); else cbi(PORTB, 0);


Нее мне это не подходит. Задумка то и была в том чтоб отказаться от PINA и PORTB
и использовать переменные как указатель на них чтоб потом использовать по аналогии с #define.
при такой конструкции
volatile char *port;
port = ((char*)0x32); //PORTD SRAM adress + 0x20
PortSetPin(port, 0, 1);

мы можем программно поменять значение переменной port и вся программа будет использовать уже другой порт.
Аватара пользователя
uni
Встал на лапы
Сообщения: 137
Зарегистрирован: Пт дек 07, 2007 11:17:40
Откуда: г. Екатеринбург
Контактная информация:

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение uni »

В таком случае программно нужно переключать не только регистр порта, а также DDR и PIN регистры, если вы хотите сделать этот приём универсальным. Сомнительное решение. Я понимаю, если портов было бы 20 штук, но для двух портов зачем это делать? Может проще явно работу с ними прописывать?

Да, кстати, я не проверял, но такая вещь тоже компилируется:

Код: Выделить всё

    char port = PORTB;
    char pin = PINA;
    char b = 7;
   
    if CHECKBIT( pin, b ) sbi(port, 1); else cbi(port, 1);


В листинге ассемблера получается целая портянка для реализации этого кода, она по длине в 10 раз больше предыдущего варианта.
Россия навсегда!
ZiperRUS
Родился
Сообщения: 18
Зарегистрирован: Сб июн 08, 2013 19:12:54

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение ZiperRUS »

спасибо за вашу лепту в суть вопроса uni :)

В листинге ассемблера получается целая портянка для реализации этого кода, она по длине в 10 раз больше предыдущего варианта.

ещёб конечно портянка не появилась бы между функцией написанной на С и макросом на АСМ

попробовал я ваш макрос любезнейший uni
добавил се в исходник:
#define CHECKBIT(x,y) ((x) & (1<<(y))) // чтение пина
#define sbi(port, b) (port) |= (1 << (b)) // установка пина
#define cbi(port, b) (port) &= ~(1 << (b))// сброс пина

и код для проверки:
volatile char *pinBT = ((char*)0x36);//PINB SRAM adress + 0x20;
if CHECKBIT( pinBT, 7 )
{
// перепробовав разные варианты не компилится (( для проверки это
}


пробовал и так:
volatile char *pinBT = ((char*)0x36);//PINB SRAM adress + 0x20;
if(CHECKBIT( pinBT, 7 ))
// перепробовав разные варианты некомпилится (( пля проверки и это тоже
}

не компилиться ошибка компилятора CodeVision 2.05.0
: declaration syntax error
на строке:
if CHECKBIT( pinBT, 7 )
{
// и так тоже самая ошибка if(CHECKBIT( pinBT, 7 ))
}

эту строку компилятор вообще отказался принять категорически!!!
char pin = PINB;

поэтому я её поменял на:
volatile char *pinBT = ((char*)0x36);//PINB SRAM adress + 0x20;
эту скушал молча :)
Аватара пользователя
uni
Встал на лапы
Сообщения: 137
Зарегистрирован: Пт дек 07, 2007 11:17:40
Откуда: г. Екатеринбург
Контактная информация:

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение uni »

У меня нет макросов на ассемблере (это вообще выглядит по-другому). Мои определения называются препроцессорными определениями, они входят в стандарт языка C. Надо делать вот так:

Код: Выделить всё

sbi( DDRA, 1 );
cbi( PORTA, 1 );

while (1) {

    unsigned char * port = ( unsigned char * ) ( 0x1B + 0x20 );
    unsigned char * pin = ( unsigned char * ) ( 0x19 + 0x20 );
    char b = 1;
   
    if CHECKBIT( * pin, b ) cbi( * port, b ); else sbi( * port, b );       
   
    delay_ms(1);

}

Изображение

Использовать PORTA и PINA напрямую по всей видимости нельзя и у меня вообще-то пример был записан неправильно скорее всего. Доступ к регистрам через разыменование указателя в CodeVision возможен, хотя я бы не стал использовать такой способ, т.к. численные значения плохо поддаются отлову ошибок. Для того и придумывали идентификаторы, чтобы уйти от прямого указания цифр в коде. И да, в отличие о функции, макрос на C сразу вставляется в текст программы, поэтому здесь его использовать в таком виде не имеет смысла, т.к. он развёртывается в большой кусок кода на ассемблере. При частом обращении флеш мк быстро закончится.
Россия навсегда!
ZiperRUS
Родился
Сообщения: 18
Зарегистрирован: Сб июн 08, 2013 19:12:54

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение ZiperRUS »

не компилится это: :o

unsigned char *pin = ( unsigned char * ) ( 0x19 + 0x20 );
char b = 1;
if CHECKBIT( *pin, b )
{
}

пишет ошибка на строке if CHECKBIT( * pin, b ) Error:......: declaration syntax error
и так тоже не компилет:
unsigned char *pin = ( unsigned char * ) ( 0x19 + 0x20 );
char b = 1;
if (CHECKBIT( *pin, b ))
{
}

unsigned char *pin = ( unsigned char * ) ( 0x19 + 0x20 );
char b = 1;
if CHECKBIT( pin, b )
{
}

unsigned char *pin = ( unsigned char * ) ( 0x19 + 0x20 );
char b = 1;
if (CHECKBIT( pin, b ))
{
}


всегда ругается :
ошибка на строке if CHECKBIT( * pin, b ) в разных её вариантах!

Error:......: declaration syntax error

:(



Использовать PORTA и PINA напрямую по всей видимости нельзя

Да в том и дело что можно и щас так оно и реализованно у меня что используются они явно
Может проще явно работу с ними прописывать?

так щас оно и есть! это можно но не желательно.

суть дела в чём:

сам себя цитирую :oops:
Задача функции такая. Есть у меня две функции одинаковые они полностью отличаются только они как раз что используют разные PIN и PORT.
первая использует PIND.5 PIND.0 PINB.3 и PORTD.0
вторая использует PIND.0 PIND.5 PINB.4 и PORTD.5

одинаковые PINы используются в разных местах кода.
Так вот для начала я хочу эти две функции объединить в одну, оптимизировать а нужные PINы и PORTы передавать ей в качестве параметров при вызове. или вот думаю можно так реализовать смену PINов в самой функции по команде через параметр
void TestPort(int command)
{
port; // здесь мы объявили переменные для порта и пина, но какой ставить тип переменных ?
pin;

if(command==1)
{
port = PORTB; // здесь мы присваиваем переменным номер порта и пина в зависимости от команды
pin = PINB.5;
}

if(pin)port=0; // работаем с переменными пора и пина
else port=1;

}

вот так тоже делать пришла идея но как?

Вообще это устройство у меня стоит в авто уже года три назад я его сам собрал. его назначение это управление стёклами (стеклоподъёмник) и закрывает он их автоматически при постановке на сигнализацию. У меня там две функции есть одна управляет закрытием водительского окна , другая закрытием пассажирского окна, они одинаковые различаются только работой с разными пинами и портом. Поюзав это собственно ручно собранное замечательное устройство не один год и убедившись в его замечательной надёжности и нужности я решил сделать ему upgrade добавить дополнительно новые функции полезные и подключить его к блютузу.
В частности планируется задействовать в алгоритме ещё и открывание окон (щас только закрыванием онных оно отвечает). Не писать же ещё две такие же функции на открывание
поэтому я и решил написать одну функцию и в параметрах при вызове указывать ей какое окно открывать или закрывать. Вот в чём задумка!!!
Я понимаю некоторые могут подумать и сказать типа пиши четыре функции одинаковых и иди пей пиво светлое, тёмное кому как нравиться на вкус и цвет товарищей нет. Яб мог конечно так сделать еслиб был пивным алкоголиком но я не из них! Мне кажется это логически неправильно так делать. Да и ресурсы у контроллера не безграничные!!! щас стоит ATTINY2313 новую реализацию планирую реализовать на ATMEGA8 а то чёт ног у 2313 не хватает мне чуть чуть
Аватара пользователя
uni
Встал на лапы
Сообщения: 137
Зарегистрирован: Пт дек 07, 2007 11:17:40
Откуда: г. Екатеринбург
Контактная информация:

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение uni »

У меня CodeVision 2.05.0, как видно про снимку экрана, в Proteus всё работает. CHECKBIT() не обязательно брать в скобки, т.к. определение само содержит эти скобки. Когда я говорил о прямом использовании идентификаторов регистров ввода/вывода, то имел в виду такую конструкцию:

Код: Выделить всё

#include <mega16.h>
#include <delay.h>

#define sbi(port, b) (port) |= (1 << (b))
#define cbi(port, b) (port) &= ~(1 << (b))
#define TOGGLE(x,y) ((x) ^= (1<<(y)))
#define CHECKBIT(x,y) ((x) & (1<<(y)))

sbi( DDRA, 1 );
cbi( PORTA, 1 );

while (1) {

    unsigned char * port = ( unsigned char * ) ( & PORTA );
    unsigned char * pin = ( unsigned char * ) ( & PINA );
    char b = 1;   
   
    CHECKBIT( * pin, b ) ? (cbi( * port, b )) : (sbi( * port, b ));       
   
    delay_ms(1);

}

У меня сначала почему-то не получилось такой вариант скомпилировать, но теперь это работает, т.е. лучше вместо цифр 0x20 + 0x19 использовать адрес & PINA. По сути это одно и то же, но второй вариант более понятен. На картинке ниже я прошагал до момента инициализации переменных pin и port, как видно, они имеют ожидаемые значения.

Изображение
Россия навсегда!
fzr400gr
Первый раз сказал Мяу!
Сообщения: 36
Зарегистрирован: Вс сен 25, 2011 09:40:47

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение fzr400gr »

ZiperRUS писал(а):первая использует PIND.5 PIND.0 PINB.3 и PORTD.0
вторая использует PIND.0 PIND.5 PINB.4 и PORTD.5

одинаковые PINы используются в разных местах кода.
Так вот для начала я хочу эти две функции объединить в одну, оптимизировать а нужные PINы и PORTы передавать ей в качестве параметров при вызове. или вот думаю можно так реалировать смену PINов в самой функции по команде через параметр, вот как то так:

void TestPort(int command)
{
port; // здесь мы объявили переменные для порта и пина, но какой ставить тип переменных ?
pin;

if(command==1)
{
port = PORTB; // здесь мы присваиваем переменным номер порта и пина в зависимости от команды
pin = PINB.5;
}

if(pin)port=0; // работаем с переменными пора и пина
else port=1;

}

вот так тоже делать пришла идея но как?



#define input1 PIND.5
#define input2 PIND.0
#define input3 PINB.3
#define input4 PINB.4

#define output1 PORTD.0
#define output2 PORTD.5

void test_port (unsigned char input,unsigned char output){
if(input){
output = 0;
}

else output = 1;
}


я не профи конечно, но сделал бы так.
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение Kavka »

Про макросы много где есть. И у нас тоже, если кто не видел. :)
Но макросы это не функция и код генерируемый компилятором будет отличаться от способа с указателями.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
variaevg
Встал на лапы
Сообщения: 103
Зарегистрирован: Пт фев 03, 2012 19:39:32

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение variaevg »

Уважаемые программисты!
Досталась недоделанная прошивка (AnMega16, CodeVisionAVR).
Как правильно прописать, чтобы при включении питания устанавливались эти условия:

if(in_rp==1) {out_bloc=1;
out_klap=0;
out_cc=0;
out_buz=0;}

else {out_bloc=in_out2;
out_klap=in_out1;
out_cc=1;
out_buz=0;}

Соответственно in -входы, out - выходы.
ZiperRUS
Родился
Сообщения: 18
Зарегистрирован: Сб июн 08, 2013 19:12:54

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение ZiperRUS »

так а в чём проблема то ?
при инициализации контроллера, перед функцией main

// сюда пиши :)
и будет так как хочешь !
void main (void)
{
}
Последний раз редактировалось Аlex Пн окт 28, 2013 20:13:41, всего редактировалось 1 раз.
Причина: -
Аватара пользователя
Kavka
Мудрый кот
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение Kavka »

ZiperRUS, во-первых, цитировать предыдущее сообщение полностью - не по правилам этого форума. Смотрите, а то получите оплеуху от модераторов. :)
Во-вторых, если просто вставить код приведённый variaevg в то место куда вы указали - компилятор скажет вам куда идти что он думает о таком стиле написания кода. :)) :)) :)) Или мы говорим на разных языках. :))

variaevg, код надо вставлять в самое начало функции main, или в то место где закончилась инициализация всего что надо для приведённого вами фрагмента кода. Как-то так. Точнее знать только вам.

Код: Выделить всё

void main (void)
{
// инициализация

// вставлять сюда

// прочая инициализация
// основной цикл
}
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
variaevg
Встал на лапы
Сообщения: 103
Зарегистрирован: Пт фев 03, 2012 19:39:32

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение variaevg »

Большое спасибо всем неравнодушным!
Наберусь нахальства об еще одной просьбе:

В программе такая запись (фрагмент).

При переходе входа in_cc с 1 в 0, на выходе out_buz формируется положительный импульс длительностью 5 сек.
Формируется однократно.
Подскажите пожалуйста, как сделать чтобы импульс был при каждом переходе с 1 в 0?
В процессе работы эта ситуация возникает неоднократно.

С уважением, Евгений.
Вложения
Фрагмент.gif
(4.01 КБ) 268 скачиваний
Аватара пользователя
Мокренькая кисонька
Открыл глаза
Сообщения: 59
Зарегистрирован: Вт сен 27, 2011 07:28:44
Откуда: Москва
Контактная информация:

Re: Работа с портами в функциях. Порт как аргемент для функц

Сообщение Мокренькая кисонька »

Народ, а как сделать на gcc?

Код: Выделить всё

void buzz_n_blink(uint16_t duration, uint8_t quantity, uint16_t pause, uint8_t pin) 
{
	// аргументы: длительность, количество, пауза (2-я длительность), нога
	for (uint8_t i=0; i < quantity; i++) // количество оборотов цикла опеределено в quantity
	{	
		PORTA |=(1<<pin); // поднимаем ногу
		loopdelay(duration); // вызываем задержку
		PORTA &=~(1<<pin); // опускаем ногу
		if (pause >= 1) loopdelay(pause); // если аргумент pause больше или равен единице, то запускаем второй таймер
	}
}
В pin подставляется PORTAn. Но работает как-то не так все это...
Еще мне хотелось бы добавить работу с PORTB, я вижу это так, но ничего не работает:

Код: Выделить всё

void buzz_n_blink(uint16_t duration, uint8_t quantity, uint16_t pause, uint8_t pin) 
{
	// аргументы: длительность, количество, пауза (2-я длительность), нога
	for (uint8_t i=0; i < quantity; i++) // количество оборотов цикла опеределено в quantity
	{	
                if (pin == PORTB) PORTB |=(1<<pin);
                else PORTA |=(1<<pin); // поднимаем ногу
		loopdelay(duration); // вызываем задержку
                if (pin == PORTB) PORTB &=~(1<<pin);
                else PORTA &=~(1<<pin); // опускаем ногу
		if (pause >= 1) loopdelay(pause); // если аргумент pause больше или равен единице, то запускаем второй таймер
	}
}
ИзвЕните от слова - веник, ИзвИните от слова - вина.
Ответить

Вернуться в «AVR»