|
Программирование на C++, А почему не С++? |
|
|
|
Oct 23 2004, 12:51
|
Группа: Свой
Сообщений: 9
Регистрация: 20-10-04
Пользователь №: 933

|
По идее, IAR должны были бы вместе с EC++ и стантдартными библиотеками предоставлять и библиотеки классов, описывающие микроконтроллеры, хотя бы тот же MSP430. Но я у них ничего подобного не нашёл, нет даже упоминаний. Интересно, кто-нибудь вообще в этом деле использует С++ как С++. Если да, давайте одсудим детали. Я (скромный такой  ) за месяц с небольшим знакомства с предметной областью кое-что своё накарябал. Готов предъявить и получить заимечания.
|
|
|
|
|
Oct 24 2004, 09:31
|
Группа: Свой
Сообщений: 9
Регистрация: 20-10-04
Пользователь №: 933

|
У меня есть классы: clocking -- инкапсулирует систему тактирования
DAC12 -- инкапсулирует цифро-аналоговый преобразователь
flash -- инкапсулирует работу с флеш-памятью
abstract_port -- инкапсулирует работу с портами ввода-вывода | +-- read_only_port -- реализация порта только для ввода |......| |......+-- read_interrupt_port -- то же с обработкой прерываний | +---write_only_port -- реализация порта только для вывода
SVS -- инкапсулирует работу с супервайзером питания
timerA -- инкапсулирует таймер А
timerB -- инкапсулирует таймер В
WDT -- инкапсулирует сторожевой таймер
|
|
|
|
|
Oct 27 2004, 14:54
|
Группа: Свой
Сообщений: 9
Регистрация: 20-10-04
Пользователь №: 933

|
Ну, напимер, сторожевой таймер: Код #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
|
|
|
|
|
Nov 1 2004, 16:11
|
Группа: Свой
Сообщений: 9
Регистрация: 20-10-04
Пользователь №: 933

|
А вот код инкапсулирующий ЦАП Код #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 Обеспокоен Вашим молчанием, господа  . Хотелось бы узнать мнение компетентных специалистов.
|
|
|
|
|
Nov 4 2004, 11:38
|
Группа: Свой
Сообщений: 9
Регистрация: 20-10-04
Пользователь №: 933

|
Фишка вот в чём. Всё это нет никакого резона писать не только на С++, но и на С. Можно на ассемблере. Если нужно только сбрасывать в цикле сторожевой таймер, или только передать одно значение на ЦАП. А если программа достаточно сложная, должна принимать решения в зависимости не от 3 -10, а от 500 условий? Причём условий имеющих разную природу? С++ нужен не для того, чтобы делать что-то через него. А для того, чтобы описать на нём предметную область, выделить в ней объекты-субъекты, определить что каждый из них может делать, и забыть об их внутреннем устройстве. Каждый из объектов теперь можно считать "чёрным ящиком", о котором мы знаем как он себя ведёт и собираем систему из них. Это и есть ООП. Конечно, любую предметную область можно описать и на процедурно-ориентированном языке. При этом хочешь -- не хочешь существует суперобъект "ПРОГРАМА", который всё и делает. Но предметные области не состоят из единственного объекта. Не состоят они и из "действий", непонятно кем производимых, над "данными". Предметные области состоят из сущностей которые взаимодейтствуют, влияют друг на друга, изменяют состояния друг друга, и, тем самым изменяют состояние всей системы. Так что объектно-ориентированное описание получается более адекватным. По поводу лаконичности: Лаконичным должен быть исполняемый код. Как этого добиться -- проблемы компилятора. Справляется. А исходный код должен быть понятен хотябы автору, даже через неделю. Ну устроены мы так, что подавай нам избыточность.
|
|
|
|
|
Nov 5 2004, 13:32
|

Частый гость
 
Группа: Свой
Сообщений: 146
Регистрация: 4-11-04
Из: Московская область
Пользователь №: 1 040

|
Цитата(KingGeorg @ Nov 4 2004, 03:38 PM) А если программа достаточно сложная, должна принимать решения в зависимости не от 3 -10, а от 500 условий? Причём условий имеющих разную природу? Да - если это так, то на мой взгляд, выгоднее описывать обьекты конечными автоматами. И программа будет структурно выглядеть как совокупность автоматов (в том числе подчиненных). А С++ тут ни при чем. По крайней мере - прямым образом. Он дает выигрыш если нужно динамически создавать-уничтожать большое кол-во однотипных обьектов. И вообше при создании гигантских программных продуктов. (как MS Word) O-кстати! Например, писать программаторы конечно лучше всего на ++ - большое количество похожих но не точно одинаковых обьектов.
--------------------
- ЗАМЕНЯТЬ ДЕТАЛИ НА ХОДУ ВОСПРЕЩАЕТСЯ !!! -
|
|
|
|
|
Nov 5 2004, 15:03
|

Шаман
     
Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221

|
Уже давно пишу на С++ для МК. Плевать на снижение на 0.5% производительности и увеличение на 1.5% объёма кода. Проекты разные: от 0.5К до 1.5М. Пишу на С++ не из религиозных соображений, а просто потому, что УДОБНО мыслить категориями объектов, а не алгоритмов. Пытался даже пропагандировать среди коллег, но недолго, т. к. быстро осознал тщетность этих попыток. Со временем они и сами перешли на С++, когда увидели преимущества (но не раньше) даже те, кто был ярым сторонником ассемблера и АлгоритмБилдера (последний похоронили как страшный сон). Мой совет начинающим - не слушайте ничьих советов, пробуйте ВСЁ (пока ещё не выработалась интуиция) и только на основании собственного опыта делайте выводы. По крайней мере ответственность за принятые решения будет только Ваша.
|
|
|
|
|
Nov 15 2004, 09:50
|
Группа: Новичок
Сообщений: 5
Регистрация: 4-11-04
Пользователь №: 1 037

|
Цитата У меня есть классы: clocking -- инкапсулирует систему тактирования
DAC12 -- инкапсулирует цифро-аналоговый преобразователь
flash -- инкапсулирует работу с флеш-памятью
abstract_port -- инкапсулирует работу с портами ввода-вывода | +-- read_only_port -- реализация порта только для ввода |......| |......+-- read_interrupt_port -- то же с обработкой прерываний | +---write_only_port -- реализация порта только для вывода
SVS -- инкапсулирует работу с супервайзером питания
timerA -- инкапсулирует таймер А
timerB -- инкапсулирует таймер В
WDT -- инкапсулирует сторожевой таймер KingGeorg, могу я получить flash, timerA, timerB и WDT. Если да, то заранее благодарю (froakch@mail.ru).
|
|
|
|
|
Nov 30 2004, 06:10
|
Знающий
   
Группа: Свой
Сообщений: 851
Регистрация: 28-08-04
Пользователь №: 559

|
Цитата(Slavik @ Nov 29 2004, 13:11) На мой субъективный взгляд использовать С++ темболее для микроконтроллеров неразумно. Почему бы и нет? Если Мы от использования Си++ только выигрываем? Из плюсов - 3 кита ООП. из минусов: вижу только "разбухание" исходников, и то что надо немножко "повернуть" голову  Но наша цель не компактность исходников а скомпилированного кода.  P.S. Код при компиляциии не увеличивается, если не использовать динамическое объявлении переменных.
|
|
|
|
|
Nov 30 2004, 09:44
|
Частый гость
 
Группа: Свой
Сообщений: 170
Регистрация: 30-09-04
Пользователь №: 746

|
Опять же, на мой субъективный взгляд, для встраиваемых приложений больше подходит именно структурное программирование. А проблема с C++ не в разбухании исходников, а в разбухании скомпилированного кода даже без динамически выделяемой памяти, и, как следствие уменьшение производительности. Но, придвидя, что разговор может скатится к теме типа "что лучьше, паскаль или си", умолкаю. Сам я ярый приверженец Asm, С, С++.  :D А наша цель - рабочее устройство, отвечающее заданными требованиям.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|