Перейти к содержанию
    

Программирование на C++

По идее, IAR должны были бы вместе с EC++ и стантдартными библиотеками предоставлять и библиотеки классов, описывающие микроконтроллеры, хотя бы тот же MSP430. Но я у них ничего подобного не нашёл, нет даже упоминаний. Интересно, кто-нибудь вообще в этом деле использует С++ как С++. Если да, давайте одсудим детали. Я (скромный такой :rolleyes: ) за месяц с небольшим знакомства с предметной областью кое-что своё накарябал. Готов предъявить и получить заимечания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У IAR вообще всё идёт довольно медленно, но не будем отзываться плохо об отсутствующих.

И тем не менее, даже у них был когда-то туториал (под AVR), где они реализовали таймер в виде базового класса. Странно, что начиная с версии 3.10, они подменили его совершенно никчемным примером с числами Фибоначчи.

Кстати, KingGeorg, давайте обсудим что у Вас есть.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня есть классы:

clocking -- инкапсулирует систему тактирования

 

DAC12 -- инкапсулирует цифро-аналоговый преобразователь

 

flash -- инкапсулирует работу с флеш-памятью

 

abstract_port -- инкапсулирует работу с портами ввода-вывода

|

+-- read_only_port -- реализация порта только для ввода

|......|

|......+-- read_interrupt_port -- то же с обработкой прерываний

|

+---write_only_port -- реализация порта только для вывода

 

SVS -- инкапсулирует работу с супервайзером питания

 

timerA -- инкапсулирует таймер А

 

timerB -- инкапсулирует таймер В

 

WDT -- инкапсулирует сторожевой таймер

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Неплохо, а где можно на реализацию взглянуть?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну, напимер, сторожевой таймер:

 

 
#ifndef __WDT_HPP__
#define __WDT_HPP__

#include "430.hpp" 
// здесь typedef bit unsigned char
// typedef byte unsigned char, и описания регистров связанных с прерываниями 
// от разных устройств (комментарий для сообщения в форум)


struct WDTCTL{
    bit WDTIS    : 2; /* Выбор интервала сторожевого таймера. Эти биты определяют интервал времени
             * сторожевого таймера, по истечении которого устанавливаетс
           * флаг WDTIFG и/или генерируется сигнал PUC.
           * 00 Частота источника тактирования сторожевого таймера / 32768
            * 01 Частота источника тактирования сторожевого таймера / 8192
           * 10 Частота источника тактирования сторожевого таймера / 512
           * 11 Частота источника тактирования сторожевого таймера / 64   */
    bit WDTSSEL  : 1; /* Выбор источника тактирования сторожевого таймера
           * 0 SMCLK    1 ACLK */
    bit WDTCNTCL : 1; /* Очистка счетчика сторожевого таймера.
          * Установкой WDTCNTCL=1 производится очистка счетчика до значения 0000h.
          * Бит WDTCNTCL автоматически сбрасывается.
          * 0 Действие не производитс
          * 1 WDTCNT = 0000h */
    bit WDTTMSEL : 1; /*a Выбор режима сторожевого таймера
          * 0 Сторожевой режим
          * 1 Режим интервального таймера */
    bit WDTNMI   : 1; /* Выбор NMI сторожевого таймера.
          * Этот бит позволяет установить режим функционирования вывода nonRST/NMI.
          * 0 Функция сброса
          * 1 Функция NMI */
    bit WDTNMIES : 1; /* Выбор фронта NMI сторожевого таймера. Этот бит позволяет выбрать
          * фронт прерывания для NMI прерывания при WDTNMI=1.
          * Изменение этого бита может вызвать NMI. Чтобы избежать
          * случайного запуска NMI следует изменять этот бит при WDTNMI=0.
          * 0 NMI прерывание происходит по переднему фронту
          * 1 NMI прерывание происходит по спаду */
    bit WDTHOLD  : 1; /* Останов сторожевого таймера. Этот бит останавливает сторожевой таймер.
          * Установка WDTHOLD=1, когда WDT не используется, позволяет снизить
          * энергопотребление.
          * 0 Сторожевой таймер не остановлен
          * 1 Сторожевой таймер остановлен  */
    byte WDTPW;       /* Пароль сторожевого таймера. Всегда читается как 069h.
          * Должен записываться как 05Ah, в противном случае будет сгенерирован PUC. */

    static const WDTCTL *address;         // адрес настоящего регистра управления WDT

    WDTCTL()                              // конструктор читает данные из настоящего регистра
    { *(int*)this = *(int*)address;    }

    void set(void)                        // установить данные в настоящий регистр
    {
  WDTPW = 0x5A;
  *(int*)address = *(int*)this;
    }
};

class WDT
{
public:
    static void reset(void)    //    сброс и рестарт сторожевого таймера
    {
 WDTCTL wdtctl;
 wdtctl.WDTCNTCL = 1;
 wdtctl.set();
    }

    static void turnOff(void)    //    выключение  сторожевого таймера
    {
 WDTCTL wdtctl;
 wdtctl.WDTHOLD = 1;
 wdtctl.set();
    }

    static void turnOn(void)    //    включение  сторожевого таймера
    {
 WDTCTL wdtctl;
 wdtctl.WDTHOLD = 0;
 wdtctl.set();
    }

    enum dividers{ d32768, d8192, d512, d64}; // значения делителя частоты ст. тайм.

    static void set_divider( const dividers divider) // установека значения делителя частоты
    {
 WDTCTL wdtctl;
 wdtctl.WDTIS = divider;
 wdtctl.set();
    }

    enum source{ SMCLK, ACLK}; // источники тактовой частоты ст. тайм.

    static void set_source( source sour) // установека источника частоты
    {
 WDTCTL wdtctl;
 wdtctl.WDTSSEL = sour;
 wdtctl.set();
    }

    enum modes{ watchdog, interval};    // режимы сторожевой-интервальный
    static void set_mode(modes mode)
    {
 WDTCTL wdtctl;
 wdtctl.WDTTMSEL = mode;
 wdtctl.set();
    }

    enum NMIs{ rst, NMI};
    static void setNMI( NMIs nmi)
    {
 WDTCTL wdtctl;
 wdtctl.WDTNMI = nmi;
 wdtctl.set();
    }

    enum fronts{ front, back};
    static void setNMI( fronts fr)
    {
 WDTCTL wdtctl;
 wdtctl.WDTNMIES = fr;
 wdtctl.set();
    }

    static int getWDTIFG(void)
    {
 return WDTIFG;
    }


};

#endif

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А вот код инкапсулирующий ЦАП

#ifndef __DAC12_HPP__
#define __DAC12_HPP__
#include "430.hpp"

struct DAC12_CTL
{
    bit DAC12GRP   : 1; /* Группировка ЦАП12. Группируется DAC12_x с DAC12_х, имеющий следующий
                     * более высокий порядковый номер. 0 Нет группировки 1 ЦАП`ы сгруппированы */
    bit DAC12ENC   : 1; /* Включение преобразования ЦАП12. Этот бит включает модуль ЦАП12,
                     * когда DAC12LSELx>0. Когда DAC12LSELx=0, бит DAC12ENC игнорируется.
                     * 0 ЦАП12 выключен 1 ЦАП12 включен */
    bit DAC12IFG   : 1; /* Флаг прерывания ЦАП12 0 Прерывание не ожидается 1 Прерывание ожидается */
    bit DAC12IE    : 1; /* Разрешение прерывания от ЦАП12 0 Запрещено 1 Разрешено */
    bit DAC12DF    : 1; /* Формат данных ЦАП12 0 Натуральный двоичный 1 Формат с дополнением до двух */
    bit DAC12AMP   : 3; /* Настройка усилителя ЦАП12. Эти биты выбирают время установки в зависимости
                     * от потребляемого тока для входного и выходного усилителей ЦАП12
                     * DAC12AMPx  Входной буфер              Выходной буфер
                     *    000     Выключен ЦАП12 выключен,   выход в высокоимпедансном состоянии
                     *    001     Выключен ЦАП12 выключен,   на выходе 0В
                     *    010     Низкая скорость/ток        Низкая скорость/ток
                     *    011     Низкая скорость/ток        Средняя скорость/ток
                     *    100     Низкая скорость/ток        Высокая скорость/ток
                     *    101     Средняя скорость/ток       Средняя скорость/ток
                     *    110     Средняя скорость/ток       Высокая скорость/ток
                     *    111     Высокая скорость/ток       Высокая скорость/ток */
    bit DAC12IR    : 1; /* Входной диапазон ЦАП12.
                     * Этот бит устанавливает диапазон входного опорного напряжения и выходного напряжения.
                     * 0 Полный диапазон выходного напряжения ЦАП12 равен 3-х кратному опорному напряжению
                     * 1 Полный диапазон выходного напряжения ЦАП12 равен 1-но кратному опорному напряжению */
    bit DAC12CALON : 1; /* Включение калибровки ЦАП12. Этот бит инициирует последовательность калибровки
                     * смещения ЦАП12 и сбрасывается автоматически после завершения калибровки.
                     * 0 Калибровка не выполняетс
                     * 1 Инициирование калибровки / выполняется калибровка */
    bit DAC12LSEL : 2;  /* Выбор загрузки ЦАП12. Выбирается сигнал запуска загрузки защелки ЦАП12. Для обновлени
                     * ЦАП должен быть установлен DAC12ENC, за исключением случая, когда DAC12LSELx=0.
                     * 00 Загрузка в защелку ЦАП12 выполняется при записи в DAC12_xDAT
                     *     (DAC12ENC игнорируется)
                     * 01 Загрузка в защелку ЦАП12 выполняется при записи в DAC12_xDAT, или,
                     * когда используется группировка, при записи во все регистры DAC12_xDAT группы
                     * 10 Фронт сигнала c Таймера_А3.Выход1 (TA1)
                     * 11 Фронт сигнала c Таймера_B7.Выход2 (TB2) */
    bit DAC12RES   : 1; /* Выбор разрешения ЦАП12 0 12-разрядное разрешение 1 8-разрядное разрешение */
    bit DAC12SREF  : 2; /* Выбор опорного напряжения ЦАП12 00 VREF+ 01 VREF+ 10 VeREF+ 11 VeREF+ */
    bit reserved   : 1; /* Не используется */
};
__no_init volatile DAC12_CTL dac12_ctl[2] @ 0x01C0;

struct DAC12_DAT
{
    unsigned int data       :12; /* данные ЦАП */
    unsigned int reserved   : 4; /* Не используется */
};
__no_init volatile DAC12_DAT dac12_dat[2] @ 0x01C8;

class DAC12
{
    byte n;
public:
    DAC12(byte no) : n(no-1)
    {}

    enum grouping{ nogrp, grp};
    void group(grouping g){ dac12_ctl[n].DAC12GRP = grp; }    // группировка ЦАПов

    void on( void) { dac12_ctl[n].DAC12ENC = 1; }           // включение и

    void off(void) { dac12_ctl[n].DAC12ENC = 0; }           // выключение ЦАП

    bit is_interrupt(void){ return dac12_ctl[n].DAC12IFG; } // Флаг прерывания ЦАП12

    void enable_interrupt(){ dac12_ctl[n].DAC12IE = 1; }    // Разрешение прерывания от ЦАП12

    void disable_interrupt(){dac12_ctl[n].DAC12IE = 0; }    // Запрет прерывания от ЦАП12

    enum formats{ natural, up_to_two};
    void data_format( formats fmt){ dac12_ctl[n].DAC12DF = fmt; } // Формат данных ЦАП12

    /* не стал делать enum */
    void amp_cust( byte a){ dac12_ctl[n].DAC12AMP = a; }    // Настройка усилителя ЦАП12.

    enum ranges{ x3, x1};
    void range( ranges r){ dac12_ctl[n].DAC12IR = r; }      // Входной диапазон ЦАП12.

 void calibration(void){ dac12_ctl[n].DAC12CALON = 1; }  // Включение калибровки ЦАП12.

 enum run_signals{ DAC12_DAT, DAC12_DAT_or_group, A3_1, B7_2};
 void sel_loading(run_signals s) { dac12_ctl[n].DAC12LSEL = s; } // Выбор загрузки ЦАП12.

    enum permissions{ x12, x8};
 void permission( permissions p){ dac12_ctl[n].DAC12RES = p; }   // Выбор разрешения ЦАП12

 enum reference_voltages{ VREF, VREF_, VeREF, VeREF_ };
 void ref_volt( reference_voltages v){ dac12_ctl[n].DAC12SREF = v; } // Выбор опорного напряжения ЦАП12

 int operator =( int value)
 { return dac12_dat[n].data = value & 0x0FFF; }

};

#endif

Обеспокоен Вашим молчанием, господа :unsure:. Хотелось бы узнать мнение компетентных специалистов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Уважаемый KingGeorg

 

Я все таки так и не пойму, зачем все это делать через С++?????

Можете вы мне объяснить преимущества???? А то до сих пор пока не вижу никаких преимуществ. И никто толком объяснить не можем в чем фишка.

Все это можно, точно также лаконично, только без объявления класса описать на обысчном С и оформить в виде библиотеки....

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Фишка вот в чём. Всё это нет никакого резона писать не только на С++, но и на С. Можно на ассемблере. Если нужно только сбрасывать в цикле сторожевой таймер, или только передать одно значение на ЦАП.

А если программа достаточно сложная, должна принимать решения в зависимости не от 3 -10, а от 500 условий? Причём условий имеющих разную природу?

С++ нужен не для того, чтобы делать что-то через него. А для того, чтобы описать на нём предметную область, выделить в ней объекты-субъекты, определить что каждый из них может делать, и забыть об их внутреннем устройстве. Каждый из объектов теперь можно считать "чёрным ящиком", о котором мы знаем как он себя ведёт и собираем систему из них. Это и есть ООП.

Конечно, любую предметную область можно описать и на процедурно-ориентированном языке. При этом хочешь -- не хочешь существует суперобъект "ПРОГРАМА", который всё и делает. Но предметные области не состоят из единственного объекта. Не состоят они и из "действий", непонятно кем производимых, над "данными". Предметные области состоят из сущностей которые взаимодейтствуют, влияют друг на друга, изменяют состояния друг друга, и, тем самым изменяют состояние всей системы. Так что объектно-ориентированное описание получается более адекватным.

По поводу лаконичности:

Лаконичным должен быть исполняемый код. Как этого добиться -- проблемы компилятора. Справляется. А исходный код должен быть понятен хотябы автору, даже через неделю. Ну устроены мы так, что подавай нам избыточность.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если программа достаточно сложная, должна принимать решения в зависимости не от 3 -10, а от 500 условий? Причём условий имеющих разную природу?

 

Да - если это так, то на мой взгляд, выгоднее описывать

обьекты конечными автоматами. И программа будет структурно

выглядеть как совокупность автоматов (в том числе подчиненных).

А С++ тут ни при чем. По крайней мере - прямым образом.

Он дает выигрыш если нужно динамически создавать-уничтожать

большое кол-во однотипных обьектов. И вообше при создании

гигантских программных продуктов. (как MS Word)

 

O-кстати! Например, писать программаторы конечно лучше

всего на ++ - большое количество похожих но не точно

одинаковых обьектов.

B)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Уже давно пишу на С++ для МК.

Плевать на снижение на 0.5% производительности и увеличение на 1.5% объёма кода.

Проекты разные: от 0.5К до 1.5М.

Пишу на С++ не из религиозных соображений, а просто потому, что УДОБНО мыслить категориями объектов, а не алгоритмов.

Пытался даже пропагандировать среди коллег, но недолго, т. к. быстро осознал тщетность этих попыток. Со временем они и сами перешли на С++, когда увидели преимущества (но не раньше) даже те, кто был ярым сторонником ассемблера и АлгоритмБилдера (последний похоронили как страшный сон).

Мой совет начинающим - не слушайте ничьих советов, пробуйте ВСЁ (пока ещё не выработалась интуиция) и только на основании собственного опыта делайте выводы.

По крайней мере ответственность за принятые решения будет только Ваша.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

KingGeorg

Попробывал маленький проектик, аля мигание...Вобщем то работает-). Тока кода получилось многовато.

Ок. Понятно. Т.е я так понимаю, что резонно применять С++ только в здоровых приложениях, в которых есть нормальный запас по памяти.

Для мелких проектов С++ избыточен.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня есть классы:

clocking -- инкапсулирует систему тактирования

 

DAC12 -- инкапсулирует цифро-аналоговый преобразователь

 

flash -- инкапсулирует работу с флеш-памятью

 

abstract_port -- инкапсулирует работу с портами ввода-вывода

|

+-- read_only_port -- реализация порта только для ввода

|......|

|......+-- read_interrupt_port -- то же с обработкой прерываний

|

+---write_only_port -- реализация порта только для вывода

 

SVS -- инкапсулирует работу с супервайзером питания

 

timerA -- инкапсулирует таймер А

 

timerB -- инкапсулирует таймер В

 

WDT -- инкапсулирует сторожевой таймер

 

KingGeorg, могу я получить flash, timerA, timerB и WDT. Если да, то заранее благодарю ([email protected]).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

C++ удобно применять где мегабайты текста.

А для встраиваемых приложений, где к примеру килобайт до пятисот памяти или процессор мегагерц до ста, смысла никакого. Для таких вещей оптимально C/Asm.

 

Инженеру должно быть удобно мыслить в любых здравых категориях, лишь бы задача была решена, и решена оптимально по возможности.

 

На мой субъективный взгляд использовать С++ темболее для микроконтроллеров неразумно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

На мой субъективный взгляд использовать С++ темболее для микроконтроллеров неразумно.

 

Почему бы и нет? Если Мы от использования Си++ только выигрываем?

Из плюсов - 3 кита ООП. :)

из минусов:

вижу только "разбухание" исходников, и то что надо немножко "повернуть" голову :)

Но наша цель не компактность исходников а скомпилированного кода. :)

 

P.S.

Код при компиляциии не увеличивается, если не использовать динамическое объявлении переменных.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Опять же, на мой субъективный взгляд, для встраиваемых приложений больше подходит именно структурное программирование. А проблема с C++ не в разбухании исходников, а в разбухании скомпилированного кода даже без динамически выделяемой памяти, и, как следствие уменьшение производительности.

 

Но, придвидя, что разговор может скатится к теме типа "что лучьше, паскаль или си", умолкаю.

 

Сам я ярый приверженец Asm, С, С++. :twak: :D

 

А наша цель - рабочее устройство, отвечающее заданными требованиям.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...