Обсуждаем контроллеры компании Atmel.
Ответить

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

Вс окт 20, 2013 16:58:22

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

функция из исходника многоуважаемого 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:
Мне кажется что надо писать в таких ситуациях, так сказать подводить итог какая была задача и как что ты понял как её реализовал!!! потому что это может быть интересно не только тебе но и другим ! не надо быть эгоистом!!! :)

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

Вс окт 20, 2013 17:53:41

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

Код:
#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);

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

Вс окт 20, 2013 18:50:39

будет выглядеть вот так:
Код:
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 и вся программа будет использовать уже другой порт.

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

Вс окт 20, 2013 20:35:30

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

Да, кстати, я не проверял, но такая вещь тоже компилируется:
Код:
    char port = PORTB;
    char pin = PINA;
    char b = 7;
   
    if CHECKBIT( pin, b ) sbi(port, 1); else cbi(port, 1);


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

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

Пн окт 21, 2013 01:55:51

спасибо за вашу лепту в суть вопроса 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;
эту скушал молча :)

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

Пн окт 21, 2013 08:14:12

У меня нет макросов на ассемблере (это вообще выглядит по-другому). Мои определения называются препроцессорными определениями, они входят в стандарт языка 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 сразу вставляется в текст программы, поэтому здесь его использовать в таком виде не имеет смысла, т.к. он развёртывается в большой кусок кода на ассемблере. При частом обращении флеш мк быстро закончится.

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

Вт окт 22, 2013 01:49:19

не компилится это: :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 не хватает мне чуть чуть

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

Вт окт 22, 2013 08:03:19

У меня 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, как видно, они имеют ожидаемые значения.

Изображение

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

Вт окт 22, 2013 12:18:56

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


я не профи конечно, но сделал бы так.

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

Вт окт 22, 2013 18:38:04

Про макросы много где есть. И у нас тоже, если кто не видел. :)
Но макросы это не функция и код генерируемый компилятором будет отличаться от способа с указателями.

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

Чт окт 24, 2013 11:42:20

Уважаемые программисты!
Досталась недоделанная прошивка (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 - выходы.

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

Вс окт 27, 2013 01:58:11

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

// сюда пиши :)
и будет так как хочешь !
void main (void)
{
}
Последний раз редактировалось Аlex Пн окт 28, 2013 20:13:41, всего редактировалось 1 раз.
Причина: -

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

Пн окт 28, 2013 19:37:46

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

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

Код:
void main (void)
{
// инициализация

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

// прочая инициализация
// основной цикл
}

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

Вт окт 29, 2013 13:04:37

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

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

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

С уважением, Евгений.
Вложения
Фрагмент.gif
(4.01 KiB) Скачиваний: 247

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

Чт авг 10, 2023 13:11:45

Народ, а как сделать на 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 больше или равен единице, то запускаем второй таймер
   }
}
Ответить