Микроконтроллеры, АЦП, память и т.д Темы касающиеся микроконтроллеров разных производителей, памяти, АЦП/ЦАП, периферийных модулей... |
20.03.2010, 00:55
|
|
Почётный гражданин KAZUS.RU
Регистрация: 13.12.2004
Сообщений: 3,172
Сказал спасибо: 11
Сказали Спасибо 692 раз(а) в 504 сообщении(ях)
|
Re: О программировании AVR на C++.
Сообщение от neiver
|
Никто никого не инлайнит.
|
Сообщение №10 прочтите - https://kazus.ru/forums/showpost.php...9&postcount=10 И то что Вы отцитировали и то что в ответ написали. Изначально речь шла о оптимизации на уровне исходника. Я static в объектник добавить уже не могу.
Вообще вопрос линковки отдельный. Там уже никакой оптимизации не будет, только можно неиспользуемое выкинуть. GCC линкер умеет выкидывать только секциями целиком.
|
|
|
|
20.03.2010, 00:59
|
|
Временная регистрация
Регистрация: 30.07.2007
Сообщений: 51
Сказал спасибо: 1
Сказали Спасибо 12 раз(а) в 7 сообщении(ях)
|
Re: О программировании AVR на C++.
Сообщение от kison
|
Там, где Вы ищете PINF - регистр зарезервирован для будущего использования.
|
Частный случай.
Читайте следующие посты. Там будет другой подход. Этот подход я привел как пример подхода к вопросу в лоб, и сам его забраковал, по причине неэффективности работы с такими пинами как глобальными переменными. Почитайте мои посты сначала.
|
|
|
|
20.03.2010, 01:08
|
|
Временная регистрация
Регистрация: 30.07.2007
Сообщений: 51
Сказал спасибо: 1
Сказали Спасибо 12 раз(а) в 7 сообщении(ях)
|
Re: О программировании AVR на C++.
Сообщение от kison
|
Там, где Вы ищете PINF - регистр зарезервирован для будущего использования.
|
Кстати спасибо за наводку, учту.
|
|
|
|
20.03.2010, 01:09
|
|
Почётный гражданин KAZUS.RU
Регистрация: 13.12.2004
Сообщений: 3,172
Сказал спасибо: 11
Сказали Спасибо 692 раз(а) в 504 сообщении(ях)
|
Re: О программировании AVR на C++.
Сообщение от neiver
|
Частный случай.
|
![Улыбка](images/smilies/icon_smile.gif) Так все из этого и состоит. Из таких вот частностей.
Но раз механизм признан неприемлемым, то спорить не буду.
Странно что Вы в конструктор не добавили еще параметров - PINx,DDRx...
Сообщение от neiver
|
Почитайте мои посты сначала.
|
Я то их читаю. Похоже что я один вникаю в то, что Вы пишете. ![Улыбка](images/smilies/icon_smile.gif)
Ждемс продолжения
|
|
|
|
20.03.2010, 01:11
|
|
Почётный гражданин KAZUS.RU
Регистрация: 13.12.2004
Сообщений: 3,172
Сказал спасибо: 11
Сказали Спасибо 692 раз(а) в 504 сообщении(ях)
|
Re: О программировании AVR на C++.
Сообщение от neiver
|
Кстати спасибо за наводку, учту.
|
Сходите на электроникс, там долго перебирались варианты. И с классами и со структурами и еще что то было. Решения универсального до сих пор нет ![Улыбка](images/smilies/icon_smile.gif)
Или нет - не ходите. Так интересней
|
|
|
|
20.03.2010, 01:48
|
|
Временная регистрация
Регистрация: 25.11.2009
Сообщений: 61
Сказал спасибо: 1
Сказали Спасибо 17 раз(а) в 17 сообщении(ях)
|
Re: О программировании AVR на C++.
Попробуй вот так:
Код:
|
template ‹volatile unsigned char &port, uint8_t pin› class Pin
{
public:
void Set() const
{
port |= (1 ‹‹ pin);
}
void Set(uint8_t val) const
{
if(val)
Set();
else Clear();
}
void Clear()const
{
port &= (uint8_t)~(1 ‹‹ pin);
}
void Togle()const
{
port ^= (1 ‹‹ pin);
}
void SetDirWrite ()const
{
*(&port - 1) |= (1 ‹‹ pin);
}
void SetDirRead()const
{
*(&port - 1) &= (uint8_t)~(1 ‹‹ pin);
}
uint8_t IsSet()const
{
return (*(&port - 2)) & (uint8_t)(1 ‹‹ pin);
}
};
Pin‹PORTA, 1› pin1; |
Объект памяти не занимает, а компилятор может проделать максимальную оптимизацию, т.к. все констаты подставляются во время компиляции.
Не тестировал, т.к. не программлю под AVR, но пробовал такой подход на армах, результат положительный.
|
|
|
|
20.03.2010, 11:21
|
|
Временная регистрация
Регистрация: 30.07.2007
Сообщений: 51
Сказал спасибо: 1
Сказали Спасибо 12 раз(а) в 7 сообщении(ях)
|
Re: О программировании AVR на C++.
Сообщение от roxfan
|
Попробуй вот так:
|
Об этом дальше. Я этот путь уже прошел. Буду потихоньку выкладывать.
|
|
|
|
20.03.2010, 13:36
|
|
Временная регистрация
Регистрация: 30.07.2007
Сообщений: 51
Сказал спасибо: 1
Сказали Спасибо 12 раз(а) в 7 сообщении(ях)
|
Re: О программировании AVR на C++.
Можно попробовать передать порт и номер пина в виде шаблонных параметров.
Однако сделать это непосредственно, как уже советуют некоторые товарищи, к сожалению не получится:
Код:
|
template ‹volatile unsigned char &port, uint8_t pin›
class Pin
{…};
Pin‹PORTA, 1› pin1; |
В Си++ нетиповые параметры шаблонов могут быть только интегральных типов: целые, bool и перечисления - всё. Ни указатель, ни ссылку, ни вещественное число, нельзя использовать, по крайней мере, в текущей реализации.
Придётся вводить ещё один уровень абстракции. Надо как-то заменить
volatile unsigned char &port;
на тип, чтобы его можно было передать в шаблон в качестве типового параметра.
То есть нужен тип, который бы представлял порт – по одному типу на каждый порт. Для этого придётся воспользоваться препроцессором:
Код:
|
#define MAKE_PORT(portName, ddrName, pinName, className) \
struct className{\
static volatile uint8_t &data()\
{\
return portName;\
}\
static volatile uint8_t &dir()\
{\
return ddrName;\
}\
static volatile uint8_t &pin()\
{\
return pinName;\
}\
static void Write(uint8_t value)\
{\
data() = value;\
}\
static uint8_t Read()\
{\
return data();\
}\
}; |
А теперь объявим портов на все случаи жизни, благо портов не много (если кому-то мало – можно и ещё добавить):
Код:
|
#ifdef PORTA
MAKE_PORT(PORTA, DDRA, PINA, Porta)
#endif
#ifdef PORTB
MAKE_PORT(PORTB, DDRB, PINB, Portb)
#endif
#ifdef PORTC
MAKE_PORT(PORTC, DDRC, PINC, Portc)
#endif
#ifdef PORTD
MAKE_PORT(PORTD, DDRD, PIND, Portd)
#endif
#ifdef PORTE
MAKE_PORT(PORTE, DDRE, PINE, Porte)
#endif
#ifdef PORTF
MAKE_PORT(PORTF, DDRF, PINF, Portf)
#endif
#ifdef PORTG
MAKE_PORT(PORTG, DDRG, PING, Portg)
#endif |
Теперь у нас есть классы Porta, Portb,…,Portg если объявлены соответствующие им регистры.
И класс для пина можно теперь переписать так:
Код:
|
template‹class PORT, uint8_t PIN›
class TPin
{
public:
static void Set()
{
PORT::data() |= (1 ‹‹ PIN);
}
static void Set(uint8_t val)
{
if(val)
Set();
else Clear();
}
static void Clear()
{
PORT::data() &= (uint8_t)~(1 ‹‹ PIN);
}
static void Togle()
{
PORT::data() ^= (1 ‹‹ PIN);
}
static void SetDirRead()
{
PORT::dir() &= (uint8_t)~(1 ‹‹ PIN);
}
static void SetDirWrite()
{
PORT::dir() |= (1 ‹‹ PIN);
}
static uint8_t IsSet()
{
return PORT::pin() & (uint8_t)(1 ‹‹ PIN);
}
static void WaiteForSet()
{
while(IsSet()==0){}
}
static void WaiteForClear()
{
while(IsSet()){}
}
}; |
Теперь посмотрим какой код будет генерироваться при использовании этого подхода:
Код:
|
TPin‹Porta, PA2› pin1;
int main()
{
pin1.SetDirWrite();
pin1.Set();
pin1.Clear();
pin1.Togle();
pin1.SetDirRead();
if(pin1.IsSet())
pin1.Clear();
} |
И в результате получаем то, что нужно. Даже при использовании глобальной переменной код оптимизируется как надо.
Код:
|
main:
sbi 58-32,2
sbi 59-32,2
cbi 59-32,2
in r24,59-32
ldi r25,lo8(4)
eor r24,r25
out 59-32,r24
cbi 58-32,2
sbic 57-32,2
cbi 59-32,2
ldi r24,lo8(0)
ldi r25,hi8(0)
ret |
Класс TPin полностью статический и переменную, в принципе, можно вообще не объявлять:
Код:
|
TPin‹Porta, PA2›::Set(); |
Однако удобнее её всё-таки объявить – места она всё равно не занимает.
|
|
|
|
20.03.2010, 23:34
|
|
Временная регистрация
Регистрация: 30.07.2007
Сообщений: 51
Сказал спасибо: 1
Сказали Спасибо 12 раз(а) в 7 сообщении(ях)
|
Re: О программировании AVR на C++.
А теперь простой пример использования таких пинов.
Это класс для управления униполярным шаговым двигателем, которые подключен через интегральный драйвер, например популярный L293.
Код:
|
template‹class IN1, class IN2, class E1, class IN3, class IN4, class E2›
class SimpleStepper //L293 driver, for example
{
public:
static void StepBack()
{
_phase = (_phase - 1) & 0x3;
SetOutput();
}
static void StepFwd()
{
_phase = (_phase + 1) & 0x3;
SetOutput();
}
static void Enable()
{
E1::SetDirWrite();
E2::SetDirWrite();
IN1::SetDirWrite();
IN2::SetDirWrite();
IN3::SetDirWrite();
IN4::SetDirWrite();
E1::Set();
E2::Set();
}
static void Disable()
{
E1::Clear();
E2::Clear();
}
protected:
static void SetOutput()
{
switch(_phase)
{
case 0:
IN1::Set(); IN2::Clear(); IN3::Clear(); IN4::Clear();
break;
case 1:
IN1::Clear(); IN2::Clear(); IN3::Set(); IN4::Clear();
break;
case 2:
IN1::Clear(); IN2::Set(); IN3::Clear(); IN4::Clear();
break;
case 3:
IN1::Clear(); IN2::Clear(); IN3::Clear(); IN4::Set();
break;
}
}
static uint8_t _phase;
};
template‹class IN1, class IN2, class E1, class IN3, class IN4, class E2›
uint8_t SimpleStepper‹IN1, IN2, E1, IN3, IN4, E2›::_phase=0; |
А вот так его можно использовать:
Код:
|
SimpleStepper
‹
TPin‹Portc, 4›, //in1
TPin‹Portc, 5›, //in2
TPin‹Portd, 7›, //e1
TPin‹Portc, 6›, //in3
TPin‹Portc, 7›, //in4
TPin‹Portd, 6› //e2
› stepper;
int main()
{
while(1)
{
stepper.StepFwd();
_delay_ms(5);
}
} |
Преимущества такого подхода перед традиционным «сишным», когда порты и пины задаются define-ами:
- можно использовать любые доступные пины на любых имеющихся портах. В традиционном подходе пришлось бы написать 12 define-ов. Поэтому было естествнным стремление использовать ноги с одного порта, что не всегда возможно.
- вся конфигурация осуществляется в единственном месте – вместе использования класса. Не надо править библиотечные файлы под каждый проект, или объявлять кучу глобальных define-ов.
- можно подключить столько шаговиков сколько портов хватит. Объявляем ещё объекты SimpleStepper со своими наборами параметров и всё. В сишном подходе для этого придётся дублировать код, или вручную или с помощью препроцессора.
- код получается более чистым и легко читаемым, по сравнению с использованием битовых операций.
|
|
|
Эти 5 пользователя(ей) сказали Спасибо neiver за это сообщение:
|
|
|
21.03.2010, 00:32
|
|
Почётный гражданин KAZUS.RU
Регистрация: 13.12.2004
Сообщений: 3,172
Сказал спасибо: 11
Сказали Спасибо 692 раз(а) в 504 сообщении(ях)
|
Re: О программировании AVR на C++.
Сообщение от neiver
|
Преимущества такого подхода перед традиционным «сишным», когда порты и пины задаются define-ами:
- можно использовать любые доступные пины на любых имеющихся портах. В традиционном подходе пришлось бы написать 12 define-ов. Поэтому было естествнным стремление использовать ноги с одного порта, что не всегда возможно.
|
О преимуществах написали. Давйте теперь и о недостатках. Ваш метод не проиграет традиционному сишному ( рассматриваем Ваш пример с ШД) только в случае, если все четыре вывода взяты с разных портов. А выиграть не сможет вообще никогда. Иначе - увы и ах, но за нежелание писать дефайны придется платить производительностью и размером программы. Если выводы все же на одном порту - Ваш метод дольше раза в три и больше тоже примерно в три раза. Не верите? Соберите для порта F, да вообще любого, куда не достает sbi.
В Вашем же примере все будет еще запущеннее - у Вас там четыре ветки внутри case. Я от такого листинга, который Вы получите, плакать начинаю или на людей кидаться. ![Улыбка](images/smilies/icon_smile.gif)
Есть еще случаи с так называемым запрещенным состоянием выводов. Ну к примеру два вывода могут иметь состояние 10 или 01. А 00 и 11 - запрещены. Ваши действия? В традиционном подходе это не вызывает затруднений.
В общем реальный плюс один - лентяям, не желающим один раз за проект написать несколько дефайнов, способ понравится. Правда потом лентяям может придется потратить несколько дней, пытаясь всунуть раздувшуюся прошивку в выбранный кристалл... Есть история о одном байте. Не читали? ![Улыбка](images/smilies/icon_smile.gif) Гугл сразу находит.
Я могу еще пару недостатков привести, но уже лень набирать.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 21:15.
|
|