Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Как правильно организовать архитектуру программы?
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > MCS51, AVR, PIC, STM8, 8bit
Maxi_Man
Как правильно организовать архитектуру программы для часов?
Часы должны показывать время дату и температуру, по очереди с определённой задержкой.
Как организовать настройку времени?
Контроллер: Mega8;
IDE: Atmel Studio.
RabidRabbit
Архитектура программная, по-моему, сильно зависит от архитектуры аппаратной. Тут уж сами думайте, раз одна только Mega8 участвует...
Настройка времени,к примеру, автоматическая: http://www.ptb.de/cms/en/ptb/fachabteilung...time/dcf77.html
kolobok0
Цитата(Maxi_Man @ Aug 3 2015, 20:50) *
Как правильно организовать архитектуру программы для часов?..настройку времени?..


Архитектура программы под МК, как правило лучше делать придерживаясь ОО подхода.
на "нижнем уровне" - ярко выраженная зависимость от периферии и тех действий которые требуются делать с этой периферией. Иногда этот слой
обзывают "драйвера". Если задача не крупная - то над этим слоем достаточно одного цикла с не большим кол-вом специфики. Если есть
пользовательский интерфейс, протоколы верхнего уровня и иже - то код уже группируется по логическим сущностям, с требуемым к ним
программным интерфейсам. В принципе этот слой уже ничем не отличается от стандартного подхода ООА и ООП. При программировании
выбираете необходимый язык, от этого принципиально ничего меняться не должно.

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


CrimsonPig
Цитата(Maxi_Man @ Aug 3 2015, 18:50) *
Как правильно организовать архитектуру программы для часов?
Часы должны показывать время дату и температуру, по очереди с определённой задержкой.
Как организовать настройку времени?


Ну, идете, например на радиокота или еще куда, скачиваете 100500 проектов разных часов с описаниями и исходниками и изучаете.
Идете на easyelectronics и читаете статьи DiHalt'а по организации программ на микроконтроллерах (ну там, как сделать события по таймеру итп).

Вам могут надавать кучу абсолютно правильных абстрактных советов на все случаи, только они вам не пригодятся, поскольку, если вы бы смогли им следовать, то вышеозначенных вопросов бы не возникло sm.gif
mempfis_
Цитата(Maxi_Man @ Aug 3 2015, 20:50) *
Как правильно организовать архитектуру программы для часов?
Часы должны показывать время дату и температуру, по очереди с определённой задержкой.
Как организовать настройку времени?
Контроллер: Mega8;
IDE: Atmel Studio.


Делал недавно для ссебя такую программу на atmega16. Отображение времени на ин14, отображение даты, температуры. Настройка вариантов отображения - время, время-дата, время-дата-температура.
И некоторые другие функции.

Разделите вашу задачу на независимые подзадачи, которые условно не связаны друг с другом. Например:
- ведение часов (например опрос ds1337 с заданным периодом или внутренний таймер атмеги),
- задача индикации - отображение информации в зависимости от состояния или режима работы устройства
- опрос термодатчика с заданным периодом
- опрос кнопок управления
- задача динамической индикации - отображение данных на индикаторе
- какие-либо остальные задачи

Свяжите эти задачи друг с другом через глобальные флаги. Например - если в данны
Maxi_Man
Цитата(mempfis_ @ Aug 4 2015, 15:44) *
Делал недавно для ссебя такую программу на atmega16. Отображение времени на ин14, отображение даты, температуры. Настройка вариантов отображения - время, время-дата, время-дата-температура.
И некоторые другие функции.

Разделите вашу задачу на независимые подзадачи, которые условно не связаны друг с другом. Например:
- ведение часов (например опрос ds1337 с заданным периодом или внутренний таймер атмеги),
- задача индикации - отображение информации в зависимости от состояния или режима работы устройства
- опрос термодатчика с заданным периодом
- опрос кнопок управления
- задача динамической индикации - отображение данных на индикаторе
- какие-либо остальные задачи

Свяжите эти задачи друг с другом через глобальные флаги. Например - если в данны

Не могли бы вы скинуть исходник? Просто Ваш случай, практически, в точности копирует мой.
Jury093
Цитата(Maxi_Man @ Aug 4 2015, 17:56) *
Не могли бы вы скинуть исходник? Просто Ваш случай, практически, в точности копирует мой.

как говориться "погуглю за вас. дорого" (С) обитатели форума

зы google.ru->"atmega8 часы"
demiurg1978
1 - Модульность программ.
Опрос кнопок.
Вывод информации. Аппаратный. Семисегментник, дисплей. Его задача - вывод из буфера.
Меню.
Счетчик времени.
Взаимодействие человек-программа.
2 - Псевдопараллельность процессов. Никаких долгих циклов. Разбиение задачи-модуля на подзадачи. Условия, флаги, автоматное программирование. Добиться того, чтобы каждая задача за итерацию основного цикла выполняла часть кода. Этим мы добиваемся псевдопараллельности процессов. Грубое сравнение - windows. Как работают много программ в windows? Есть диспетчер, который каждой программе выделяет определенное время выполнения. Закончилось время, диспетчер переключается на следующую программу. Это происходит очень быстро. Для пользователя это выглядит, как будто все программы работают одновременно.
mempfis_
Цитата(Maxi_Man @ Aug 4 2015, 17:56) *
Не могли бы вы скинуть исходник? Просто Ваш случай, практически, в точности копирует мой.


Я думал сообщение не отправилось.... Оно и не дописано...
Скину Вам исходник, но там нет настроек времени т.к. я использую GPS-модуль для синхронизации времени.
проект под IAR AVR 5.10a
Maxi_Man
Цитата(mempfis_ @ Aug 6 2015, 11:09) *
Я думал сообщение не отправилось.... Оно и не дописано...
Скину Вам исходник, но там нет настроек времени т.к. я использую GPS-модуль для синхронизации времени.
проект под IAR AVR 5.10a

Спасибо огромное!
Подскажите, пожалуйста.Как реализовать такой режим отображения?
1)Время-отображается 20сек;
2)Дата-отображается 10сек;
и так по кругу.
mempfis_
Цитата(Maxi_Man @ Aug 6 2015, 13:18) *
Спасибо огромное!
Подскажите, пожалуйста.Как реализовать такой режим отображения?
1)Время-отображается 20сек;
2)Дата-отображается 10сек;
и так по кругу.


Посмотрите как это сделано в моём проекте. Там есть 3 режима отображения.
Если вопрос как это сделать в принципе - то заведите таймер длительности отображения. Отображаете время, устанавливаете таймер длительности отображения на 20 секунд. Мониторите таймер каждую секунду попутно обновляя время (если есть отображение секунд). Если вышел таймаут отображения времени, отображаете дату, устанавливаете таймер длительности отображения на 10 секунд. Мониторите истечение таймаута. Далее опять переходите на отображение времени.
Onkel
порядок гуглим "AVR. Учебный курс. Операционная система. Введение.", и не пугайтесь слов "операционная система" - это просто опыт нескольких десятилетий по программированию мелких мк, очень полезная и очень очень простая инфа.
demiurg1978
Крайне вредный совет и цикл статей. В этой "операционной системе" занесен большущий дамоклов меч. Мина непредсказуемого замедленного действия. Я о таймерной службе в этом опусе.
Onkel
Цитата(demiurg1978 @ Aug 7 2015, 13:11) *
Крайне вредный совет и цикл статей. В этой "операционной системе" занесен большущий дамоклов меч. Мина непредсказуемого замедленного действия. Я о таймерной службе в этом опусе.

Эээ, товарищ, если уж ругать - то с конкретикой, плиз. Где тут меч и где тут мина? Неужели моторола писала свои операционки для любимцев новых русских микротаков с мечами и минами?
demiurg1978
Конкретика? Пожалуйста: очередь таймеров, которая к тому же работает в прерывании. Такой способ вполне работоспособен, если устройство заточено на то, что задачи в очереди задач всегда одни и те же. И все действия которые будут происходить всегда предсказуемы. Но если у нас к примеру управляющее устройство. С разными режимами и так далее. Тем более, если еще есть аварийный режим. Представим, что мы положили в очередь задачу на исполнение через некоторое время. И тут аварийная ситуация, или просто режим сменился. Устройство работает себе, а тут срабатывает задача из очереди, которая в этом режиме никак не предусмотрена. Приплыли. Вы скажете, будем придумывать убийц задач. А откуда нам известно, какая задача должна работать в какой-то момент времени? Тем более, если задачи зависят от режима работы и так далее.
Так что, то что слямзено у моторолы - это никак не показатель.
Меня привлек в свое время этот "диспетчер". Но я столкнулся с его этой замедленной миной. В итоге от этого диспетчера у меня осталась таймерная служба, которая работает в ОСНОВНОМ цикле. Идем дальше. Переключение задач происходит гораздо дольше, чем простой список функций. Также примерно в то время мне указали на конечные автоматы.
Итог, я составил себе определенные правила ниписания проектов. И до нынешнего момента мне не потребовались ни подобные недодиспетчеры ни РТОС.
Пример основного цикла из действующего проекта:

CODE

//========================================================================
__C_task main ()
{
wdt_enable (WDTO_15_MS);

/*
dsp_buf [0] = 1;
dsp_buf [1] = 2;
dsp_buf [2] = 3;
dsp_buf [3] = 4;
dsp_buf [4] = 5;
dsp_buf [5] = 6;
*/

init_sys_timer ();

__enable_interrupt ();

Init_Events ();

while (1)
{
__watchdog_reset ();

service_timers ();

proc_amplifier ();

proc_7_segm_ind ();

Process_Events ();
}
}
//========================================================================


Запуск процесса каждое определенное время, на этом примере можно посмотреть, как запускать процессы периодически или через определенное время:
CODE

//========================================================================
void proc_7_segm_ind (void)
{
static u08 _proc_7_segm_ind;

static u08 cnt_7_segm_ind;

switch (_proc_7_segm_ind)
{
case 0:
ANODS_DDR = 0xFF;
cnt_7_segm_ind = 0;
set_timer (ST_PROC_7_SEGM_IND, NO_RERUN_TIMER, 1);
_proc_7_segm_ind = 1;
break;

case 1:
if (wait (ST_PROC_7_SEGM_IND))
{
u08 cnt = cnt_7_segm_ind;

volatile u08 anods;
volatile u08 katods;

ANODS_PORT = 0;
KATODS_DDR = 0;

cnt_7_segm_ind = tab_index_anods [cnt].i;
anods = tab_index_anods [cnt].anod;

katods = table_7_segm_char [dsp_buf [cnt_7_segm_ind]];

ANODS_PORT = anods;
KATODS_DDR = katods;

set_timer (ST_PROC_7_SEGM_IND, NO_RERUN_TIMER, 1);
}
break;

default:
_proc_7_segm_ind = 0;
break;
}
}
//========================================================================
Onkel
Цитата(demiurg1978 @ Aug 21 2015, 10:30) *
Конкретика? Пожалуйста: очередь таймеров, которая к тому же работает в прерывании. Такой способ вполне работоспособен, если устройство заточено на то, что задачи в очереди задач всегда одни и ....

не убедили. Вы привели пример плохой реализации алгоритма. Смена режима может быть прописана в коде самой функции задачи, ну вроде "если режим 1 выполняй если режим 2 на выход". А пример ваш не свидетельсвует о негодности алгоритма. На любом автомобиле можно въехать в стену - это не свидетельства плохого качества автомобиля.
demiurg1978
Представьте, что функции накидали задач в очередь. Светодиодами поморгать. Включить-выключить исп. устройство. И этих задач теперь в очереди болтается хренова куча. Да вы заколебетесь потом разгребать, что удалять из очереди, которая к тому же работает в прерываниях. Это такой винегрет получится из условий, что проект станет просто не читабелен. И вносить изменения, что-то добавить становится сложно. Да еще забудете второпях или не продумавши выкинуть задачи из очереди. Поэтому такой диспетчер нежизнеспособен в большинстве случаев. Также большое время переключения задач. Поэтому автоматное программирование выигрывает по всем пунктам такому недодиспетчеру. Есть состояния, в которых выполняются необходимые действия. И никаких коллизий быть не может в принципе. Только если не учел взаимосвязи и нюансы.
Onkel
Цитата(demiurg1978 @ Aug 21 2015, 11:06) *
Представьте, что функции накидали задач в очередь. Светодиодами поморгать. Включить-выключить исп. устройство. И этих задач теперь в очереди болтается хренова куча. Да вы заколебетесь потом разгребать, что удалять из очереди, которая к тому же работает в прерываниях. Это такой винегрет получится из условий, что проект станет просто не читабелен. И вносить изменения, что-то добавить становится сложно. Да еще забудете второпях или не продумавши выкинуть задачи из очереди. Поэтому такой диспетчер нежизнеспособен в большинстве случаев. Также большое время переключения задач. Поэтому автоматное программирование выигрывает по всем пунктам такому недодиспетчеру. Есть состояния, в которых выполняются необходимые действия. И никаких коллизий быть не может в принципе. Только если не учел взаимосвязи и нюансы.

***Только если не учел взаимосвязи и нюансы.*** - это относится к любому применению любого алгоритма. Я нелюбимый вами диспетчер юзаю и проблем не имею, в том числе и на задачах уровня автоматизации цеха или контроллера умного дома. Засим предлагаю пофиксить дискуссию в связи с наметившимся переходом во флейм / халивар.
demiurg1978
Не торопитесь. Давайте продуктивно обсудим.

Во-первых, как у вас реализуются выполнения чего-нибудь по времени? Скажем, моргать светодиодом каждые 1 с. Пусть это будет устройство световых эффектов. Пусть у нас играет 1 режим. Мы решили поменять режим. В этом режиме задается шаблон. А в очереди в этот момент болтается выполнение предыдущего режима. И он исправно из очереди сработает по истечении заданного времени.

Или такой пример. Станок. В очереди болтаются задачи. И тут аварийная ситуация. Нужно все остановить. Ну мы остановили. А тут бац, сработали из прерывания задачи на исполнение чего-либо. Расскажите, как это у вас реализовано.
Onkel
Цитата(demiurg1978 @ Aug 21 2015, 11:27) *
Не торопитесь. Давайте продуктивно обсудим.

Во-первых, как у вас реализуются выполнения чего-нибудь по времени? Скажем, моргать светодиодом каждые 1 с. Пусть это будет устройство световых эффектов. Пусть у нас играет 1 режим. Мы решили поменять режим. В этом режиме задается шаблон. А в очереди в этот момент болтается выполнение предыдущего режима. И он исправно из очереди сработает по истечении заданного времени.

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

1 моргать - ну примерно моргать, но посложнее- у меня шим светодиодный, прерывание по таймеру смотрит - включить, выключить, или ничего не делать, сравнивает текущую переменную (счетчик) с установкой шим (0-255), если счетчик <установки - включате, иначе- выключает. Меняем режим - меняем установку шим, приходит время обработать , вызывается прерывание по таймеру - а у нас установка шим стоит какая надо для этого режима. Так и работают 8 канальные шимы, 8же (2х4 фазные обмотки) контроллеры шаговых 4хфазных униполярных двигателей. В вашем примере - раз в секунду вызываем функцию "моргать светодиодом", а в функции этой есть свич (например) по переменной "режим".
2 похожая задача - управление шаговым двигателем с концевиками. Данные с концевиков обрабатываются раз в миллисекунду (по главному таймеру прерывание ), вызывается по другому таймеру периодически (собственно период есть период переключения обмоток шаговиков) функция управления выходами подачи напряжения на шаговики, если переменная "концевик начало" или "концевик конец" единица то прокрутку (шаг шаговика) в "ненужную" сторону не делаем. Теперь , если у нас сработал концевик "конец по часовой", мы можем хоть тысячу раз командовать "100 шагов по часовой" - шаговики по часовой не повернутся. Собственно как я и писал - параметр "номер режима" обрабатывается и внутри функции.

Да, про режим "авария" - имхо тут должна быть не просто остановка, ведь у вас же не один параметр вызывает режим "авария" - скажем, при опускнии напряжения ниже 180 В -один алгоритм остановки, при потере герметичности пневмосистемы - другой, при получении сигнала "авария" от частотника - третий и т.д., истина она всегда конкретна. Но про два ваших случая я вроде ответил?
demiurg1978
Цитата(Onkel @ Aug 21 2015, 16:03) *
...

В том вы сейчас написали, ключевое слово свитч. И если у вас в функциях уже есть все требуемое, то объясните мне смысл диспетчера? sm.gif
Раз в 1 мс датчики опрашивать? Обновлять экран? Светодиодиками по времени моргать? Это все спокойно можно сделать по условиям, на свитчах, или индексному переходу по переменной состоянию. И нет никаких потерь на переключениях процессов.

Ладно, закончен спор, так закончен. В данном случае всего лишь дело вкуса, не более. О целесообразности и речи нет.
Onkel
Цитата(demiurg1978 @ Aug 21 2015, 12:31) *
В том вы сейчас написали, ключевое слово свитч. И если у вас в функциях уже есть все требуемое, то объясните мне смысл диспетчера? sm.gif
Раз в 1 мс датчики опрашивать? Обновлять экран? Светодиодиками по времени моргать? Это все спокойно можно сделать по условиям, на свитчах, или индексному переходу по переменной состоянию. И нет никаких потерь на переключениях процессов.

Ладно, закончен спор, так закончен. В данном случае всего лишь дело вкуса, не более. О целесообразности и речи нет.

диспетчер расставляет задачи по приоритетности и вызывает соотвутствующие функции. Если на очереди задачи 1 4 6, то он сначала вызывает функцию задачи с наивысшим приоритетом и т.д. Собственно да, дело вкуса- но речь идет именно о мини - операционке, и если я хочу симисторный диммер переделать в светодиодный диммер, мне нужно будет поменять лишь одну функцию, не затрагивая прием / передачу по uart, анализ входов и т.д., то же самое если нужен контроллер шаговых двигателей - в готовой программе меняем лишь одну функцию. Я когда задумал серию периферийных модулей для своих задач ( 8 реле, 8 входов, 8 светодиодных светильников, 8 симисторов, ...8 датчиков температуры/8 реле, смс.. ...) сначала разработал скелет - как раз ту операционку, которой вы приписали дамокловость меча, а потом уже писал функции под конкретные модули. А пришел я к этой "операционке" как раз потому, что начал запутываться в "условиях, свичах или индексных переходах по переменной состояния"....
Onkel
пы сы что- то не могу из ящика, дублирую тут
не, самописанный. Идея очень простая
- 8 функций, например
прием и обработка байта уарт
отправка 8 байт через уарт
посылка данных на дисплей
...
8 - потому что 8 бит в char переменной zadania, диспетчер (он только и есть в теле, все остальное - в функциях и программах обработки прерываний по таймерам) постоянно крутиться в main(), вычисляет задачу из переменной zadania с максимальным приоритетом (это нетрудно - чем выше бит выставлен в 1 - тем приоритетнее задача) и вызывает соотв. функцию. Чтобы задачи с малым приоритетом не завешивали, все функции написаны так, что они за вызов делают (возможно) не всю работу, занимая не больше отведенного им времени, и возвращают управление диспетчеру, не выставляя свой бит в нуль - если функция не завершила работу. Если более высокоприоритетных задач не появилось, то менее приоритетные задачи продолжают, пока не сделают что нужно и не выставят свой бит в 0. Ну а биты функций выставляет либо таймер(это для ацп, актуализации реле/мосфитов (выходов мк), либо прерывание по получению байта uart, либо прерывание внешнего прерывания. Вот так они и крутятся, не мешая друг другу, в полном соответсвии с оригинальной идеей. Сам я ее читал не на сайте, а в журнале хакер (бумажном) году так еще в 2006-2007, соответсвенно потом его посеял и делал по памяти. Но потом, по прочтении ряда книжек по эмбеддингу оказалось, что все не противоречит и высокой науке тоже.
demiurg1978
Мои правила написания программ:

Весь набор правил подчиняется главному условию - псевдопараллельность процессов. Каждый процесс при каждой итерации выполняет часть кода.

Модульность. Стараемся делать все модули самостоятельными.

Никаких долгих циклов.

Разбиение функций на подзадачи. Стремимся к тому, чтобы все модули быстро выполняли свой код. Вход в функцию, выполнение кода, выход. Проверка условий, выполнение кода, выход. Разбиение на подзадачи осуществляется флагами, условиями, состояниями конечных автоматов.

Автоматное программирование. У конечных автоматов помимо всего прочего есть отличная фича. Нулевое состояние можно сделать состоянием самоинициализации модуля. Инициализация ввода-вывода, переменных.

Программные таймеры. Я перелопатил таймерную службу взятую у ди хальта. И перенес ее в основной цикл. Настриваем аппаратный таймер на 1 мс, если кварц на 8 или 16 МГц. Или 10 мс, если кварц для uart. В прерывании выставляется флаг. В службе проверяется флаг. если флаг установлен, сброс и перебор очереди программный таймеров. Структура таймера - статус, 16-битный счетчик.

Итерация основного цикла должна с запасом впаковаться в тик системного таймера. То есть, 1 мс или 10 мс.

Проекты при таком подходе создаются как конструктор из кирпичиков модулей.

Нет затрат на перебор диспетчером задач. Установку задач в очередь, удаление задач из очереди.

В итоге основной цикл представляет из себя список необходимых функций. Пример я показал выше. У меня нет диспетчеров. Нужно поправить проект? Вписываем нужные функции. Удаляем ненужные функции. Видео одного из последних проектов.

Основной цикл этого проекта:
CODE

//========================================================================
void main (void)
{
// wait_500_ms (); // После включения питания задержка 500 мс.

wdt_enable (WDTO_15_MS);

init_sys_timer ();

__enable_interrupt ();

// logo (); // Что-то вроде заставки.

Init_Events ();

while (1)
{
__watchdog_reset ();

service_timers (); // Программные таймеры.

proc_eds (); // Управление циклом работы станка.

tui_service (); // Модуль вывода информации на дисплей.

drv_char_dsp (); // Модуль дисплея VFD. Аппаратная часть.

Process_Events (); // Служба сообщений. Взаимодействие модулей.
}
}
//========================================================================
sigmaN
Конечно от конкретной задачи таймера это делеко, но понять вообще в каком ключе нужно мыслить, разрабатывая рахитектуру помогают книги
1. Совершенный код(макконнелл)
2. Паттерны проектирования(банда четверых) http://www.ozon.ru/context/detail/id/2457392/

Вот после прочтения этих книг вы качественно измените свой взгляд на проектирование.
Но прочтение этих книг это, так сказать, стратегическая задача. Если таймер нужен уже завтра - пишите как умеете и на чем умеете.
Onkel
Цитата(sigmaN @ Aug 30 2015, 08:50) *
Конечно от конкретной задачи таймера это делеко, но понять вообще в каком ключе нужно мыслить, разрабатывая рахитектуру помогают книги
1. Совершенный код(макконнелл)
2. Паттерны проектирования(банда четверых) http://www.ozon.ru/context/detail/id/2457392/

Вот после прочтения этих книг вы качественно измените свой взгляд на проектирование.
Но прочтение этих книг это, так сказать, стратегическая задача. Если таймер нужен уже завтра - пишите как умеете и на чем умеете.

вряд ли эти книги будут полезны в работе с мелкими мк. По мелким мк есть свои книги.
NicholasR
Цитата(Onkel @ Sep 4 2015, 13:00) *
вряд ли эти книги будут полезны в работе с мелкими мк. По мелким мк есть свои книги.



Подскажите какие именно книги по мелким МК ?
Onkel
Цитата(NicholasR @ Sep 28 2015, 08:43) *
Подскажите какие именно книги по мелким МК ?

сейчас уже не помню, я на языке оригинала читал. Сначала придумал (на основе содранной с моторолы микрооперационки) свою систему, потом (в названии есть embedded...) книжки читал и оказалось что в общем я все правильно сделал.
demiurg1978
Цитата(Onkel @ Sep 30 2015, 05:52) *
(на основе содранной с моторолы микрооперационки) свою систему

Знакомое сочетание. easyelectronics.ru?
NicholasR
Цитата(Onkel @ Sep 30 2015, 02:52) *
сейчас уже не помню, я на языке оригинала читал. Сначала придумал (на основе содранной с моторолы микрооперационки) свою систему, потом (в названии есть embedded...) книжки читал и оказалось что в общем я все правильно сделал.


Я понял,спасибо!
Onkel
Цитата(demiurg1978 @ Sep 30 2015, 07:02) *
Знакомое сочетание. easyelectronics.ru?

читал в журнале "хакер", когда он был еще читаемым.

Цитата(NicholasR @ Sep 30 2015, 08:55) *
Я понял,спасибо!

во, поднял свой список шиндлера освоенного
O'Reilly Programming Embedded Systems in C and C++
Barr Programming Embedded Systrems in C and C++
Li Real-Time Concepts for Embedded Systems
Embedded Controlled Hardware Design
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.