<?xml version="1.0" encoding="utf-8"?>
<!-- generator="FeedCreator 1.7.2-ppt DokuWiki" -->
<?xml-stylesheet href="http://wiki.pic24.ru/lib/exe/css.php?s=feed" type="text/css"?>
<rdf:RDF
    xmlns="http://purl.org/rss/1.0/"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
    xmlns:dc="http://purl.org/dc/elements/1.1/">
    <channel rdf:about="http://wiki.pic24.ru/feed.php">
        <title>PIC24 articles:common</title>
        <description></description>
        <link>http://wiki.pic24.ru/</link>
        <image rdf:resource="http://wiki.pic24.ru/lib/images/favicon.ico" />
       <dc:date>2023-02-10T17:30:14+03:00</dc:date>
        <items>
            <rdf:Seq>
                <rdf:li rdf:resource="http://wiki.pic24.ru/doku.php/articles/common/embedded_coding_tips?rev=1276971580"/>
                <rdf:li rdf:resource="http://wiki.pic24.ru/doku.php/articles/common/nvparam_library?rev=1285589123"/>
            </rdf:Seq>
        </items>
    </channel>
    <image rdf:about="http://wiki.pic24.ru/lib/images/favicon.ico">
        <title>PIC24</title>
        <link>http://wiki.pic24.ru/</link>
        <url>http://wiki.pic24.ru/lib/images/favicon.ico</url>
    </image>
    <item rdf:about="http://wiki.pic24.ru/doku.php/articles/common/embedded_coding_tips?rev=1276971580">
        <dc:format>text/html</dc:format>
        <dc:date>2010-06-19T22:19:40+03:00</dc:date>
        <title>Советы по программированию для встраиваемых систем</title>
        <link>http://wiki.pic24.ru/doku.php/articles/common/embedded_coding_tips?rev=1276971580</link>
        <description>


&lt;h1&gt;&lt;a name=&quot;советы_по_программированию_для_встраиваемых_систем&quot; id=&quot;советы_по_программированию_для_встраиваемых_систем&quot;&gt;Советы по программированию для встраиваемых систем&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&quot;level1&quot;&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Советы по программированию для встраиваемых систем&quot; [1-111] --&gt;
&lt;h2&gt;&lt;a name=&quot;реентерабельность_атомарные_переменные_и_рекурсия&quot; id=&quot;реентерабельность_атомарные_переменные_и_рекурсия&quot;&gt;Реентерабельность, атомарные переменные и рекурсия&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Практически любое встраиваемое приложение использует прерывания, а многие - многозадачность и многопоточность. Такие приложения должны быть реализованы с учетом того факта, что контекст выполнения может измениться в любое время. Например, возникшее прерывание вызывает планировщик, который переключает контекст на более приоритетную задачу. Что случится, если задачи и функции используют общие переменные? С большой долей вероятности можно предположить, что произойдет катастрофа - одна из задач испортит данные другой задачи. &lt;span style='color:grey; '&gt;Прим. переводчика: конечно, то же самое можно сказать об общих переменных прерываний и основного цикла в обычных, однозадачных программах.&lt;/span&gt;
&lt;/p&gt;

&lt;p&gt;
Аккуратно распределяя ресурсы задач, мы можем использовать &lt;span class=&quot;important&quot;&gt;реентерабельные&lt;/span&gt; функции, допускающие множественные конкурентные вызовы без порчи данных. Реентерабельность была &amp;quot;придумана&amp;quot; для мейнфреймов, в дни когда память была драгоценным ресурсом, а операторы машин заметили, что часто в системной памяти оказываются абсолютно одинаковые программы, выполняемые разными пользователями. До сих пор захватывает дух от этой идеи: представьте память с объемом в 32 килослова. Если в этой памяти разместить реентерабельную функцию, то даже для 50 пользователей будет использоваться те же 32 килослова. Каждый из пользователей выполняет тот же самый код, находящийся по одному адресу, однако используя свои собственные данные. Операционная система переключая контекст меняет только адреса данных и информация одного пользователя не портится другим. Общая программа, но разные данные.
&lt;/p&gt;

&lt;p&gt;
В мире встраиваемых систем реентерабельная функция должна удовлетворять следующим правилам:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;strong&gt;Правило 1.&lt;/strong&gt; Функция осуществляет атомарный доступ к глобальным переменным, либо переменная создается для каждого вызова функции&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;strong&gt;Правило 2.&lt;/strong&gt; Функция не вызывает нереентерабельные функции&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;strong&gt;Правило 3.&lt;/strong&gt; Функция использует атомарный доступ к периферийным модулям&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Реентерабельность, атомарные переменные и рекурсия&quot; [112-3751] --&gt;
&lt;h3&gt;&lt;a name=&quot;атомарные_переменные&quot; id=&quot;атомарные_переменные&quot;&gt;Атомарные переменные&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

В &lt;strong&gt;Правилах 1&lt;/strong&gt; и &lt;strong&gt;3&lt;/strong&gt; встречается слово &amp;quot;атомарный&amp;quot;, в основе которого лежит греческое слово, означающее &amp;quot;неделимый&amp;quot;. В программировании термин &amp;quot;атомарный&amp;quot; используется для операций, которые не могут быть прерваны. Рассмотрим инструкцию:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;mov ax, bx&lt;/pre&gt;
&lt;p&gt;
Она является атомарной, так как ничего кроме сброса не может прервать выполнение это инструкции - иструкция выполняется независимо от других задач или прерываний. 
&lt;/p&gt;

&lt;p&gt;
Первая часть &lt;strong&gt;Правила 1&lt;/strong&gt; требует атомарного использования глобальных переменных. Пусть две функции используют общую глобальную переменную &lt;code&gt;foobar&lt;/code&gt;.  Если функция A содержит код
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;temp = foobar;
temp += 1;
foobar = temp;&lt;/pre&gt;
&lt;p&gt;
то она не является реентерабельной, так как доступ к переменной &lt;code&gt;foobar&lt;/code&gt; не является атомарным, потому что для изменения &lt;code&gt;foobar&lt;/code&gt; используется три действия а не одно. Этот код может прервать прерывание, в котором вызывается функция B, которая тоже выполняет какие-то действия с &lt;code&gt;foobar&lt;/code&gt;. После возврата из прерывания значение &lt;code&gt;temp&lt;/code&gt; может не соответствовать актуальному значению &lt;code&gt;foobar&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
Налицо конфликт, самолет падает и сотни людей кричат: &amp;quot;Почему этого &lt;del&gt;блядского&lt;/del&gt; программиста никто не научил использовать реентерабельные функции!!!&amp;quot;. Однако, представим, что функция А выглядит по другому:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;foobar += 1;&lt;/pre&gt;
&lt;p&gt;
Теперь операция атомарная, прерывание не остановит операцию над &lt;code&gt;foobar&lt;/code&gt; посередине, конфликт не возникнет, значит эта операция реентерабельная. 
&lt;/p&gt;

&lt;p&gt;
Стойте… А вы действительно знаете, что ваш Си компилятор сгенерирует для этой операции? На x86 процессоре этот код может выглядить следущим образом:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;mov ax, [foobar]
inc ax
mov [foobar], ax&lt;/pre&gt;
&lt;p&gt;
что конечно же не является атомарной опрацией, а значит выражение &lt;code&gt;foobar += 1;&lt;/code&gt; не является реентерабельным. Атомарная версия будет выглядеть так:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;inc [foobar]&lt;/pre&gt;
&lt;p&gt;
&lt;p&gt;&lt;div class=&quot;noteimportant&quot;&gt;Мораль в следующем: будьте очень осторожны в предположениях о генерации компилятором атомарного кода. В противном случае вы можете обнаружить репортеров программы &amp;quot;Максимум&amp;quot; под своей дверью - &amp;quot;Кто виновен в отказе тормозов у мопеда Филлипа Киркорова?&amp;quot;. &lt;span style='color:grey; '&gt;А вообще, всегда нужно исходить из того, что для подобных выражений компилятор всегда генерирует &lt;strong&gt;неатомарный&lt;/strong&gt; код&lt;/span&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;p&gt;
Вторая часть &lt;strong&gt;Правила 1&lt;/strong&gt; говорит о том, что если функция использует неаторманый доступ, то данные должны создаваться для каждого вызова функции. Под &amp;quot;вызовом&amp;quot; будем понимать непосредственное выполнение функции. В многозадачных приложениях функция может вызываться одновременно несколькими задачами.
&lt;/p&gt;

&lt;p&gt;
Рассмотрим следующий код:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;int&lt;/span&gt; foo;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; some_function&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    foo++;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;

&lt;code&gt;foo&lt;/code&gt; - глобальная переменная, область видимости которой выходит за пределы функции &lt;code&gt;some_function()&lt;/code&gt;. Даже если больше ни одна функция не использует &lt;code&gt;foo&lt;/code&gt;, данные могут быть повреждены, если &lt;code&gt;some_function()&lt;/code&gt; вызывается из разных задач &lt;span style='color:grey; '&gt;(ну и, естественно, может быть вызвана одновременно)&lt;/span&gt;. 
&lt;/p&gt;

&lt;p&gt;
Си и Си++ могут оградить нас от этой опасности. Используем локальную переменную. Т.е. определим &lt;code&gt;foo&lt;/code&gt; внутри функции. В этом случае каждый вызов &lt;code&gt;some_function()&lt;/code&gt; будет использовать переменную, выделенную в стеке &lt;span style='color:grey; '&gt;(что, конечно, не относится к PIC16 и PIC18. С последним правда можно использовать компилятор Microchip C18, который может реализовать программный стек и, соответственно, реентерабельность. Но нужна ли она там?)&lt;/span&gt;:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; some_function&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;int&lt;/span&gt; foo;
    foo++;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Другим вариантом может стать использование динамического выделения памяти. &lt;span style='color:grey; '&gt;Правда, при этом нужно убедиться, что сами библиотечные функции динамического выделения реентерабельные. Обычно нет&lt;/span&gt;. Как и в случае с локальными переменными для каждого вызова будет генерироваться свой кусок памяти - таким образом решается фундаментальная проблема реентерабельности. 
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Правило 2&lt;/strong&gt; говорит о том, что вызывающая функция наследует отсутствие реентерабельности в вызываемой. То есть если данные портятся в функции B которая была вызвана из функции A, говорить о реентерабельности А бессмысленно. 
&lt;/p&gt;

&lt;p&gt;
Используя комиляторы с языков высокого уровня мы наталкиваемся на коварную проблему. Вы уверены - действительно уверены - что библиотеки компилятора реентерабельны? Очевидно, что строковые &lt;span style='color:grey; '&gt;(к Си это не относится)&lt;/span&gt;и другие сложные операции вызывают функции из библиотеки компилятора. Большинство компиляторов генерируют вызовы библиотечных функций при математических операциях, даже для тривиального умножения и деления целых чисел.
&lt;/p&gt;

&lt;p&gt;
Если ваш код, использующий библиотечные функции, должен быть реентерабельным - проконсультируйтесь с тех. поддержкой производителя компилятора&lt;span style='color:grey; '&gt;и почитайте мануал - там обычно об этом пишут&lt;/span&gt;. Осторожность необходима и при использовании сторонних библиотек - стеков протоколов, файловых систем и пр.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Правило 3&lt;/strong&gt; относится только ко встраиваемым системам. Периферию можно рассматривать как глобальную переменную и если для обслуживания периферийного модуля требуется несколько действий, можно получить проблему совместного доступа.
&lt;/p&gt;

&lt;p&gt;
Рассмотрим последовательный модуль SCC в контроллерах Zilog. Доступ к любому внутреннему регистру устройства требует двух действий: записи адреса регистра в порт и чтения или записи из этого порта. Если между установкой адреса и доступом к регистру произойдет прерывание, другая функция может получить доступ к порту. Когда управление будет передано прерванной функции, установленный адрес может быть уже другим.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Атомарные переменные&quot; [3752-13344] --&gt;
&lt;h3&gt;&lt;a name=&quot;добиваемся_реентерабельности&quot; id=&quot;добиваемся_реентерабельности&quot;&gt;Добиваемся реентерабельности&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;

Какой самый лучший способ сделать функцию реентерабельной? Конечно же избежать использования глобальных переменных.
&lt;/p&gt;

&lt;p&gt;
&lt;p&gt;&lt;div class=&quot;noteimportant&quot;&gt;В общем случае глобальные переменные сильно усложняют отладку кода и вызывают трудноуловимые баги. Старайтесь использовать локальные переменные или динамическое выделение памяти.
&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;p&gt;
Тем не менее, глобальные переменные это наиболее быстрый способ передачи данных. Как правило, полностью избавиться от глобальных переменных во встраиваемых системах реального времени невозможно. Поэтому при использовании разделяемых ресурсов (глобальных переменных или периферии) мы должны использовать различные методы обеспечения атомарности.
&lt;/p&gt;

&lt;p&gt;
Самый распространенный способ - запрещать прерывания на время выполнения нереентерабельного кода. Если прерывания запрещены, система из многозадачной превращается в однозадачную. &lt;span style='color:grey; '&gt;На самом деле это не совсем так - кто мешает после запрещения прерывания вызвать сервис RTOS переключающий контекст?&lt;/span&gt; Запретите прерывания, выполните нереентерабельную часть кода, разрешите прерывания. Довольно часто это выглядит следующим образом:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;long&lt;/span&gt; i;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; do_something&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    disable_interrupts&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    i &lt;span class=&quot;sy2&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x1234&lt;/span&gt;;
    enable_interrupts&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Однако &lt;strong&gt;этот код опасен!&lt;/strong&gt; Если &lt;code&gt;do_something()&lt;/code&gt; - глобальная фукция, которая вызывается из разных мест, то в какой-то момент она может быть вызвана при запрещенных прерываниях. А перед возвратом прерывания будут разрешены, контекст будет изменен. Очень опасный способ, который может привести к серьезным проблемам.
&lt;/p&gt;

&lt;p&gt;
И не нужно использовать старую отговорку: &amp;quot;Да, но когда я пишу код, я очень аккуратен. Я вызываю эту функцию только когда уверен, что прерывания разрешены&amp;quot;. Программист, который вас заменит &lt;span style='color:grey; '&gt;(а с такими отговорками это может очень скоро произойти)&lt;/span&gt; может не знать о таком серьезном ограничении &lt;span style='color:grey; '&gt;(тем более, что вряд ли вы внесли его в документацию)&lt;/span&gt;.
&lt;/p&gt;

&lt;p&gt;
Гораздо лучше выглядит следующая функция:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;long&lt;/span&gt; i;
&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt; do_something&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    push_interrupt_state&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    disable_interrupts&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
    i&lt;span class=&quot;sy2&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nu12&quot;&gt;0x1234&lt;/span&gt;;
    pop_interrupt_state&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Запрещение прерываний увеличивают время реакции системы на внешние события &lt;span style='color:grey; '&gt;(что часто просто недопустимо)&lt;/span&gt;. Более мягким способом обеспечения реентерабельности является использование &lt;span class=&quot;important&quot;&gt;семафоров&lt;/span&gt;, индицирующих занятость ресурса. Семафор - это простейший двоичный индикатор типа &amp;quot;включено-выключено&amp;quot;, доступ к которому осуществляется атомарно. Семафор используется как флаг разрешения, удерживающий задачу в состоянии простоя, пока требуемый ресурс занят.
&lt;/p&gt;

&lt;p&gt;
Почти все коммерческие RTOS имеют объект синхронизации типа &amp;quot;семафор&amp;quot; &lt;span style='color:grey; '&gt;(часто семафор, реализующий защиту от одновременного доступа называют мютексом; мютекс имеет дополнительные свойства)&lt;/span&gt;. Если вы используете RTOS то семафоры - это ваш путь обеспечить реентерабельность. Не используете RTOS? Часто я вижу программы, использующие переменную-флаг для защиты ресурса:
&lt;/p&gt;
&lt;pre class=&quot;cpp code cpp&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw1&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;in_use&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;           &lt;span class=&quot;co1&quot;&gt;//wait till resource free&lt;/span&gt;
in_use &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;TRUE&lt;/span&gt;;            &lt;span class=&quot;co1&quot;&gt;//set resource busy&lt;/span&gt;
Do_non_reentrant_stuff&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;
in_use &lt;span class=&quot;sy1&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kw2&quot;&gt;FALSE&lt;/span&gt;;           &lt;span class=&quot;co1&quot;&gt;//set resource available&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Выгляди просто и элегантно, но &lt;strong&gt;этот код опасен!&lt;/strong&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://www.embedded.com/design/opensource/216800007?pgno=1&quot; class=&quot;urlextern&quot; title=&quot;http://www.embedded.com/design/opensource/216800007?pgno=1&quot;  rel=&quot;nofollow&quot;&gt;источник&lt;/a&gt;
&lt;img src=&quot;http://wiki.pic24.ru/lib/images/smileys/fixme.gif&quot; class=&quot;middle&quot; alt=&quot;FIXME&quot; /&gt;

&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Добиваемся реентерабельности&quot; [13345-] --&gt;</description>
    </item>
    <item rdf:about="http://wiki.pic24.ru/doku.php/articles/common/nvparam_library?rev=1285589123">
        <dc:format>text/html</dc:format>
        <dc:date>2010-09-27T16:05:23+03:00</dc:date>
        <title>Хранение параметров в энергонезависимой памяти</title>
        <link>http://wiki.pic24.ru/doku.php/articles/common/nvparam_library?rev=1285589123</link>
        <description>


&lt;h1&gt;&lt;a name=&quot;хранение_параметров_в_энергонезависимой_памяти&quot; id=&quot;хранение_параметров_в_энергонезависимой_памяти&quot;&gt;Хранение параметров в энергонезависимой памяти&lt;/a&gt;&lt;/h1&gt;
&lt;div class=&quot;level1&quot;&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Хранение параметров в энергонезависимой памяти&quot; [1-104] --&gt;
&lt;h2&gt;&lt;a name=&quot;требования_к_библиотеке&quot; id=&quot;требования_к_библиотеке&quot;&gt;Требования к библиотеке&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Большинство разработчиков сталкиваются с задачей хранения настроек или параметров прибора в энергонезависимой памяти. После пятой или десятой подобной задачи (в зависимости от количества лени в теле разработчика) в голову приходит гениальная идея - изобрести &lt;del&gt;велосипед&lt;/del&gt; удобный инструмент, который сократит количество рутины и одним нажатием на кнопку &amp;quot;шедевр&amp;quot; сформирует некий исходный код, заточенный под текущий проект.
&lt;/p&gt;

&lt;p&gt;
В этой статье рассматривается один из таких, как мне кажется, удобных инструментов. Это набор функций на языке Си и файл Excel, который по нажатию той самой кнопки формирует дополнительные .c и .h файлы, подключаемые к проекту.
&lt;/p&gt;

&lt;p&gt;
Какие требования предъявлялись к инструменту в ходе разработки?
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; параметр - это переменная одного из стандартных типов языка Си или пользовательская структура&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; параметр имеет &lt;strong&gt;рабочую копию&lt;/strong&gt; в ОЗУ. Это позволяет быстро обращаться к параметру, использовать его в выражениях, а не загружать каждый раз по необходимости. Конечно, при каждом изменении параметра придется вызывать функцию сохранения и следить за конкурентным доступом - но это редкая ситуация изменения настроек&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; параметр имеет &lt;strong&gt;значение по умолчанию&lt;/strong&gt; - переменную того же типа, что и рабочая копия, только расположенную в секции &lt;code&gt;const&lt;/code&gt; (программной памяти). Таким образом возможен сброс параметра при детектировании ошибки записи в NVRAM, а так же реализация функции &amp;quot;сброс на заводские настройки&amp;quot;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; должна быть возможность определять значение по умолчанию в виде &lt;code&gt;#define&lt;/code&gt; - для контроллеров с небольшим объемом набортной flash&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; автоматическая инициализация параметров при первом включении&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; возможность добавления параметров, например, при обновлении прошивки. При этом старые параметры не должны сбрасываться&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; всеядность типов NVRAM - работа как с Flash, так и с EEPROM&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; повышенная надежность - защита параметра контрольной суммой (с выбором размерности), дублирование, троирование&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; ну и как обычно - небольшой объем кода, минимальное использование ОЗУ, быстрое выполнение&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

&lt;br/&gt;
 
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Требования к библиотеке&quot; [105-3810] --&gt;
&lt;h2&gt;&lt;a name=&quot;а_что_внутри&quot; id=&quot;а_что_внутри&quot;&gt;А что внутри?&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Ядром инструмента является специально подготовленный файл электронных таблиц Excel, в который разработчик в удобной табличной форме вносит список существующих в его устройстве настроек или параметров - всего того, что требует сохранения при выключении питания устройства. С помощью штатных формул Excel, пакета &lt;a href=&quot;http://office.microsoft.com/en-us/excel-help/load-the-analysis-toolpak-HP001127724.aspx&quot; class=&quot;urlextern&quot; title=&quot;http://office.microsoft.com/en-us/excel-help/load-the-analysis-toolpak-HP001127724.aspx&quot;  rel=&quot;nofollow&quot;&gt;Analysis ToolPack VBA&lt;/a&gt; и написанной на &lt;acronym title=&quot;Visual Basic for Applications&quot;&gt;VBA&lt;/acronym&gt; функции из этой таблицы формируется несколько файлов, которые подключаются к проекту и полностью описывают структуру параметров устройства. Два дополнительных файла (модуль на Си &lt;code&gt;tparam.c&lt;/code&gt; и заголовочный файл &lt;code&gt;tparam.h&lt;/code&gt;) обеспечивают интерфейс пользовательского приложения к структуре параметров.
&lt;/p&gt;

&lt;p&gt;
Каждый параметр описывается следующим дескриптором:

&lt;/p&gt;
&lt;pre class=&quot;c code c&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;struct&lt;/span&gt; _TPARAM_DESC
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    TPARAM_ADDR addr;       &lt;span class=&quot;coMULTI&quot;&gt;/* смещение параметра относительно базового адреса в NVRAM */&lt;/span&gt;
    U08         attr;       &lt;span class=&quot;coMULTI&quot;&gt;/* атрибуты параметра                                      */&lt;/span&gt;
    U08         size;       &lt;span class=&quot;coMULTI&quot;&gt;/* размер параметра в байтах (без учета контрольной суммы) */&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;        &lt;span class=&quot;sy0&quot;&gt;*&lt;/span&gt;val;       &lt;span class=&quot;coMULTI&quot;&gt;/* указатель на рабочую копию параметра в ОЗУ              */&lt;/span&gt;
    &lt;span class=&quot;kw4&quot;&gt;void&lt;/span&gt;  &lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;*&lt;/span&gt;def;       &lt;span class=&quot;coMULTI&quot;&gt;/* указатель на значение параметра по умолчанию            */&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt; TPARAM_DESC;&lt;/pre&gt;
&lt;p&gt;
&lt;p&gt;&lt;div class=&quot;noteclassic&quot;&gt;
Размер параметра объявлен типом U08. Таким образом, если в качестве параметра используется объявленная пользователем структура, ее размер не должен превышать 255 байт

&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;p&gt;
Дескрипторы параметров располагаются в программной памяти в виде массива, таким образом каждый параметр имеет уникальный индекс - положение в массиве дескрипторов. Массив дескрипторов выглядит следующим образом:

&lt;/p&gt;
&lt;pre class=&quot;c code c&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; TPARAM_DESC param_desc_table&lt;span class=&quot;br0&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#93;&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
&lt;span class=&quot;coMULTI&quot;&gt;/* (  0) */&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x0&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;  TPARAM_SAFETY_LEVEL_2&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;nu0&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_1&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_1_def&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 1&lt;/span&gt;
&lt;span class=&quot;coMULTI&quot;&gt;/* (  1) */&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0xA&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;  TPARAM_SAFETY_LEVEL_1&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;nu0&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_2&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_2_def&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 2&lt;/span&gt;
&lt;span class=&quot;coMULTI&quot;&gt;/* (  2) */&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0xF&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;  TPARAM_SAFETY_LEVEL_1&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;nu0&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_3&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_3_def&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 3&lt;/span&gt;
&lt;span class=&quot;coMULTI&quot;&gt;/* (  3) */&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x14&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; TPARAM_SAFETY_LEVEL_1&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_4&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_4_def&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 4&lt;/span&gt;
&lt;span class=&quot;coMULTI&quot;&gt;/* (  4) */&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x16&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; TPARAM_SAFETY_LEVEL_1&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;nu0&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_5&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_5_def&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 5&lt;/span&gt;
&lt;span class=&quot;coMULTI&quot;&gt;/* (  5) */&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x1B&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; TPARAM_SAFETY_LEVEL_1&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;nu0&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_6&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_6_def&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 6&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;
В NVRAM параметры хранятся так же в виде массива без пропусков. Это позволяет добавлять новые параметры в конец массива, например, при обновлении прошивки устройства. Старые параметры при этом не затрагиваются.
&lt;/p&gt;

&lt;p&gt;
&amp;quot;Точкой входа&amp;quot; является таблица параметров (не путать с массивом дескрипторов), которая описывается следующей структурой:

&lt;/p&gt;
&lt;pre class=&quot;c code c&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;struct&lt;/span&gt; _TPARAM_TBL
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    U32                 addr;   &lt;span class=&quot;coMULTI&quot;&gt;/* базовый адрес таблицы параметров в энергонезависимой памяти   */&lt;/span&gt;
    TPARAM_ADDR         size;   &lt;span class=&quot;coMULTI&quot;&gt;/* размер таблицы параметров в энергонезависимой памяти в байтах */&lt;/span&gt;
    U16_FAST            pnum;   &lt;span class=&quot;coMULTI&quot;&gt;/* количество параметров в таблице                               */&lt;/span&gt;
    TPARAM_DESC &lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt;   &lt;span class=&quot;sy0&quot;&gt;*&lt;/span&gt;dt;    &lt;span class=&quot;coMULTI&quot;&gt;/* указатель на массив дескрипторов                              */&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt; TPARAM_TBL;&lt;/pre&gt;
&lt;p&gt;
Тип &lt;code&gt;TPARAM_ADDR&lt;/code&gt; определяет разработчик. Размерности этого типа должно хватить для адресации всех параметров. Понятно, что чем меньше разрядность, тем меньше параметров можно обслуживать. Использование типа U16_FAST для переменной числа параметров в таблице определяет максимальное число параметров как 65535 - более чем достаточно. Перменная &lt;code&gt;dt&lt;/code&gt; должна указывать на массив дескрипторов (например, &lt;code&gt;param_desc_table&lt;/code&gt;).
&lt;/p&gt;

&lt;p&gt;
Таблица параметров может выглядеть следующим образом:

&lt;/p&gt;
&lt;pre class=&quot;c code c&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; TPARAM_TBL param_table &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;nu12&quot;&gt;0x0&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;nu0&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nu0&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;
    param_desc_table
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;;&lt;/pre&gt;
&lt;/div&gt;
&lt;!-- SECTION &quot;А что внутри?&quot; [3811-9589] --&gt;
&lt;h2&gt;&lt;a name=&quot;автоматизация&quot; id=&quot;автоматизация&quot;&gt;Автоматизация&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;

Все написанное выше - очевидное, но неудобное решение. Поддержка такой структуры вручную - нудное занятие, результатом которого будет множество трудноуловимых ошибок. Как же свести рутину к минимуму и избавится от опечаток и багов?
&lt;/p&gt;

&lt;p&gt;
Один из вариантов - использовать наиболее уместный способ ввода табличных данных - программу Excel, а затем преобразовывать таблицу в исходный код и заголовочные файлы. Конечно таблица должна быть специальным образом подготовлена, содержать необходимые формулы и макросы экспорта. Для этого проекта был сделан шаблон таблицы, который можно использовать в реальных проектах.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://wiki.pic24.ru/lib/exe/detail.php/articles/common/tparam_fig1.png?id=articles%3Acommon%3Anvparam_library&quot; class=&quot;media&quot; title=&quot;articles:common:tparam_fig1.png&quot;&gt;&lt;img src=&quot;http://wiki.pic24.ru/lib/exe/fetch.php/articles/common/tparam_fig1.png&quot; class=&quot;media&quot; title=&quot;Таблица Excel&quot; alt=&quot;Таблица Excel&quot; /&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
Каждая строка таблицы (выделено на рисунке) формирует дескриптор параметра. Разберем назначение столбцов:

&lt;/p&gt;
&lt;table class = &quot;fpl&quot;&gt;
	&lt;tr&gt;
		&lt;td&gt;
 &lt;code&gt;ID&lt;/code&gt;		&lt;/td&gt;
		&lt;td&gt;
 Индекс параметра в таблице дескрипторов. Начинается с 0, максимальное значение 65535. Отображается автоматически и только в том случае, если введено имя параметра &lt;code&gt;Name&lt;/code&gt;		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
 &lt;code&gt;Name&lt;/code&gt;		&lt;/td&gt;
		&lt;td&gt;
 Имя параметра. Именно с таким именем будет объявлена рабочая копия параметра в ОЗУ		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
 &lt;code&gt;Safety&lt;/code&gt;		&lt;/td&gt;
		&lt;td&gt;
 Уровень надежности. Может принимать одно из четырех значений (выпадающий список). Если Safety = &lt;strong&gt;Simple&lt;/strong&gt; - в NVRAM сохраняется только значение параметра без контрольной суммы. Если Safety = &lt;strong&gt;1 + CRC&lt;/strong&gt;, то вместе со значением параметра сохраняется так же контрольная сумма. Если Safety = &lt;strong&gt;2 + CRC&lt;/strong&gt;, то параметр дублируется в NVRAM вместе с контрольной суммой, что позволяет восстановить значение параметра при потере одной из копий. Safety = &lt;strong&gt;3 + CRC&lt;/strong&gt; - пока не реализовано.		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
 &lt;code&gt;Type&lt;/code&gt;		&lt;/td&gt;
		&lt;td&gt;
 Тип параметра, выбирается из выпадающего списка: &lt;code&gt;U08&lt;/code&gt;, &lt;code&gt;S08&lt;/code&gt;, &lt;code&gt;U16&lt;/code&gt;, &lt;code&gt;S16&lt;/code&gt;, &lt;code&gt;U32&lt;/code&gt;, &lt;code&gt;S32&lt;/code&gt;, &lt;code&gt;U64&lt;/code&gt;, &lt;code&gt;S64&lt;/code&gt;, &lt;code&gt;float&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt;, &lt;code&gt;struct&lt;/code&gt;. Последний вариант позволяет назначить параметру пользовательский тип.		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
 &lt;code&gt;User Type&lt;/code&gt;		&lt;/td&gt;
		&lt;td&gt;
 Выбор одного из пользовательских типов (если Type = &lt;code&gt;struct&lt;/code&gt;). Пользовательские типы вводятся на втором листе файла (лист так и называется &amp;quot;Пользовательские типы&amp;quot;). Выпадающий список		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
 &lt;code&gt;User Size&lt;/code&gt;		&lt;/td&gt;
		&lt;td&gt;
 В это поле автоматически подставляется размер пользовательского типа. Подробнее об использовании пользовательских типов ниже.		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
 &lt;code&gt;Size&lt;/code&gt;		&lt;/td&gt;
		&lt;td&gt;
 Размер параметра в байтах. Рассчитывается автоматически в зависимости от типа параметра		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
 &lt;code&gt;Total Size&lt;/code&gt;		&lt;/td&gt;
		&lt;td&gt;
 Размер параметра в байтах с учетом дублирования и контрольных сумм. Рассчитывается автоматически в зависимости от типа параметра и уровня надежности		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
 &lt;code&gt;Addr&lt;/code&gt;		&lt;/td&gt;
		&lt;td&gt;
 Смещение параметра в энергонезависимой памяти относительно базового адреса. Рассчитывается автоматически в зависимости от общего размера параметра		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
 &lt;code&gt;Default&lt;/code&gt;		&lt;/td&gt;
		&lt;td&gt;
 Значение параметра по умолчанию. В этом поле можно инициализировать даже структуры. А можно игнорировать это поле, о том что произойдет в этом случае - ниже.		&lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt;
 &lt;code&gt;Description&lt;/code&gt;		&lt;/td&gt;
		&lt;td&gt;
 Описание параметра. Добавляется в генерируемые файлы как комментарий.		&lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;

Над самой таблицей можно увидеть пять полей ввода. Четыре из них выделены зеленым цветом - в них вводятся необходимые настройки. Пятое красное поле отображает общий объем базы параметров в энергонезависимой памяти с учетом всех контрольных сумм и дублирований.
&lt;/p&gt;

&lt;p&gt;
Ячейка &lt;strong&gt;C1&lt;/strong&gt; (Start Address (HEX)) служит для ввода базового адреса параметров в энергонезависимой памяти. Этот адрес нужен для передачи абсолютного адреса в функции низкоуровневого чтения/записи.
В ячейку &lt;strong&gt;С2&lt;/strong&gt; (Table Index) вводится индекс, который добавляется к названию генерируемых файлов и имен переменных. Этот параметр можно использовать, если в приборе используется несколько таблиц параметров, об этом ниже. В ячейку &lt;strong&gt;E1&lt;/strong&gt; (CRC Size) вводится размер контрольной суммы (в байтах). Ячейка &lt;strong&gt;E2&lt;/strong&gt; (Def in flash?) служит для определения стратегии размещения значений по умолчанию.
&lt;/p&gt;

&lt;p&gt;
Нажатие на кнопку &lt;strong&gt;Export&lt;/strong&gt; запускает макрос, формирующий в рабочей папке три файла:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;code&gt;param_[indx]_tbl.c&lt;/code&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;code&gt;param_[indx]_list.c&lt;/code&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; &lt;code&gt;param_[indx]_list.h&lt;/code&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;

&lt;code&gt;[indx]&lt;/code&gt; это значение которое вводится в ячейку &lt;strong&gt;C2&lt;/strong&gt;. Оно может быть как буквенным, так и числовым. Например, если в ячейке &lt;strong&gt;С2&lt;/strong&gt; введено &amp;quot;01&amp;quot;, то будут формироваться файлы &lt;code&gt;param_01_tbl.c&lt;/code&gt; и т.д. Если ячейка &lt;strong&gt;C2&lt;/strong&gt; пустая, поле &lt;code&gt;[indx]&lt;/code&gt; не вставляется: &lt;code&gt;param_tbl.c&lt;/code&gt;. 
&lt;/p&gt;

&lt;p&gt;
&lt;p&gt;&lt;div class=&quot;notewarning&quot;&gt;
Если файлы уже существуют, их содержимое будет утеряно. Поэтому не рекомендуется эти файлы изменять и добавлять туда свою информацию. Для этого предусмотрен отдельный прием, который будет описан ниже.

&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;p&gt;
Для таблицы, приведенной на скриншоте файлы будут содержать следующее
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Автоматизация&quot; [9590-17186] --&gt;
&lt;h3&gt;&lt;a name=&quot;param_tbl.c&quot; id=&quot;param_tbl.c&quot;&gt;param_tbl.c&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;pre class=&quot;c code c&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;coMULTI&quot;&gt;/* Таблица параметров */&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#include &amp;quot;param_list.h&amp;quot;	// список параметров&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; TPARAM_DESC param_desc_table&lt;span class=&quot;br0&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#93;&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
&lt;span class=&quot;coMULTI&quot;&gt;/* (  0) */&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x0&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; TPARAM_SAFETY_LEVEL_2&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;nu0&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_1&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;         &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_1_def&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 1&lt;/span&gt;
&lt;span class=&quot;coMULTI&quot;&gt;/* (  1) */&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0xA&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; TPARAM_SAFETY_LEVEL_1&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;nu0&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_2&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;         &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_2_def&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 2&lt;/span&gt;
&lt;span class=&quot;coMULTI&quot;&gt;/* (  2) */&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0xF&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; TPARAM_SAFETY_LEVEL_1&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;nu0&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_3&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;         &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_3_def&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 3&lt;/span&gt;
&lt;span class=&quot;coMULTI&quot;&gt;/* (  3) */&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x24&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; TPARAM_SAFETY_LEVEL_1&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_4&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;         &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_4_def&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 4&lt;/span&gt;
&lt;span class=&quot;coMULTI&quot;&gt;/* (  4) */&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x26&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; TPARAM_SAFETY_LEVEL_1&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;nu0&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_5&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;         &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_5_def&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 5&lt;/span&gt;
&lt;span class=&quot;coMULTI&quot;&gt;/* (  5) */&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x2B&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; TPARAM_SAFETY_LEVEL_1&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;nu0&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_6&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt;         &lt;span class=&quot;sy0&quot;&gt;&amp;amp;&lt;/span&gt;test_param_6_def&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 6&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; TPARAM_TBL param_table &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    &lt;span class=&quot;nu12&quot;&gt;0x0&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// абсолютный адрес таблицы в NVRAM (U32)&lt;/span&gt;
    &lt;span class=&quot;nu0&quot;&gt;48&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// размер таблицы в NVRAM в байтах&lt;/span&gt;
    &lt;span class=&quot;nu0&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;co1&quot;&gt;// количество параметров в таблице&lt;/span&gt;
    param_desc_table
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;
Первым делом включается заголовочный файл &lt;code&gt;param_[indx]_list.h&lt;/code&gt;. Далее объявляется массив дескрипторов param_[indx]_desc_table. Для удобства каждая строка обозначается комментарием в виде индекса в массиве и описанием параметра из столбца Description таблицы Excel.
&lt;/p&gt;

&lt;p&gt;
После массива дескрипторов объявляется таблица параметров с именем param_[indx]_table. Все константы рассчитываются автоматически и не нуждаются в правке.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;param_tbl.c&quot; [17187-19135] --&gt;
&lt;h3&gt;&lt;a name=&quot;param_list.c&quot; id=&quot;param_list.c&quot;&gt;param_list.c&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;pre class=&quot;c code c&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;coMULTI&quot;&gt;/* Список параметров, объявления значений параметров по умолчанию */&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#include &amp;quot;param_list.h&amp;quot;&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 1&lt;/span&gt;
      S32		test_param_1;
&lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; S32		test_param_1_def &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x10101010&lt;/span&gt;;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 2&lt;/span&gt;
      U32		test_param_2;
&lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; U32		test_param_2_def &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x20202020&lt;/span&gt;;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 3&lt;/span&gt;
      USER_PARAM_TYPE		test_param_3;
&lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; USER_PARAM_TYPE		test_param_3_def &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;&lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nu16&quot;&gt;1.2&lt;/span&gt;&lt;span class=&quot;sy0&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nu16&quot;&gt;5.65&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt;;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 4&lt;/span&gt;
      U08		test_param_4;
&lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; U08		test_param_4_def &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt; TEST_PARAM_4_DEF_INIT;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 5&lt;/span&gt;
      &lt;span class=&quot;kw4&quot;&gt;float&lt;/span&gt;		test_param_5;
&lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;float&lt;/span&gt;		test_param_5_def &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu16&quot;&gt;1.5568&lt;/span&gt;;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;// Тестовый параметр 6&lt;/span&gt;
      U32		test_param_6;
&lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; U32		test_param_6_def &lt;span class=&quot;sy0&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nu12&quot;&gt;0x12345678&lt;/span&gt;;&lt;/pre&gt;
&lt;p&gt;
В этом файле объявляются рабочие копии параметров и значения параметров по умолчанию. Рабочая копия - это глобальная переменная с именем, которое вводится в столбце Name таблицы Excel. Значение по умолчанию объявляется с квалификатором const - для большинства контроллеров это значение означает использование внутренней Flash памяти для хранения.
&lt;/p&gt;

&lt;p&gt;
Имя значения по умолчанию соответствует имени параметра с суффиксом &lt;code&gt;_def&lt;/code&gt;. Т.е. если имя параметра названо как &lt;code&gt;my_param&lt;/code&gt;, то для него будет сгенерировано значение по умолчанию с именем &lt;code&gt;my_param_def&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
Значения по умолчанию инициализируются текстом, который вводится в столбец Default таблицы Excel. Таким образом можно инициализировать даже структуры.
&lt;/p&gt;

&lt;p&gt;
&lt;p&gt;&lt;div class=&quot;notewarning&quot;&gt;
Будьте внимательны! При иницилизации переменных типа &lt;code&gt;float&lt;/code&gt; и &lt;code&gt;double&lt;/code&gt; используйте в качестве разделителя точку, а не запятую. Значения введенные в столбец Default не проверяются на синтаксическое соответствие!

&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;p&gt;
Если в таблице Excel поле Defaul оставить пустым, то вместо его содержимого будет подставлена литеральная константа. Ее имя будет соответствовать имени рабочей копии в верхнем регистре плюс суффикс &lt;code&gt;_DEF_INIT&lt;/code&gt;. Таким образом, если название параметра &lt;code&gt;my_param&lt;/code&gt;, то значению по умолчанию будет присвоено имя &lt;code&gt;my_param_def&lt;/code&gt;, а литеральной константе-инициализатору - &lt;code&gt;MY_PARAM_DEF_INIT&lt;/code&gt;. Определить эту константу можно в специальном файле &lt;code&gt;param_types.h&lt;/code&gt; - об этом ниже.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;param_list.c&quot; [19136-22454] --&gt;
&lt;h3&gt;&lt;a name=&quot;param_list.h&quot; id=&quot;param_list.h&quot;&gt;param_list.h&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;
&lt;pre class=&quot;c code c&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#ifndef _PARAM_LIST_H&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define _PARAM_LIST_H&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;utils\tparam.h&amp;gt;	// подключение библиотеки&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#include &amp;quot;param_types.h&amp;quot;	// пользовательские типы параметров&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;kw2&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; TPARAM_TBL  param_table;	&lt;span class=&quot;co1&quot;&gt;// таблица параметров&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;// (0) - Тестовый параметр 1&lt;/span&gt;
&lt;span class=&quot;kw2&quot;&gt;extern&lt;/span&gt;       S32		test_param_1;
&lt;span class=&quot;kw2&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; S32		test_param_1_def;
&lt;span class=&quot;co2&quot;&gt;#define      TEST_PARAM_1_INDX		0&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;// (1) - Тестовый параметр 2&lt;/span&gt;
&lt;span class=&quot;kw2&quot;&gt;extern&lt;/span&gt;       U32		test_param_2;
&lt;span class=&quot;kw2&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; U32		test_param_2_def;
&lt;span class=&quot;co2&quot;&gt;#define      TEST_PARAM_2_INDX		1&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;// (2) - Тестовый параметр 3&lt;/span&gt;
&lt;span class=&quot;kw2&quot;&gt;extern&lt;/span&gt;       USER_PARAM_TYPE		test_param_3;
&lt;span class=&quot;kw2&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; USER_PARAM_TYPE		test_param_3_def;
&lt;span class=&quot;co2&quot;&gt;#define      TEST_PARAM_3_INDX		2&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;// (3) - Тестовый параметр 4&lt;/span&gt;
&lt;span class=&quot;kw2&quot;&gt;extern&lt;/span&gt;       U08		test_param_4;
&lt;span class=&quot;kw2&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; U08		test_param_4_def;
&lt;span class=&quot;co2&quot;&gt;#define      TEST_PARAM_4_INDX		3&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;// (4) - Тестовый параметр 5&lt;/span&gt;
&lt;span class=&quot;kw2&quot;&gt;extern&lt;/span&gt;       &lt;span class=&quot;kw4&quot;&gt;float&lt;/span&gt;		test_param_5;
&lt;span class=&quot;kw2&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;float&lt;/span&gt;		test_param_5_def;
&lt;span class=&quot;co2&quot;&gt;#define      TEST_PARAM_5_INDX		4&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co1&quot;&gt;// (5) - Тестовый параметр 6&lt;/span&gt;
&lt;span class=&quot;kw2&quot;&gt;extern&lt;/span&gt;       U32		test_param_6;
&lt;span class=&quot;kw2&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;const&lt;/span&gt; U32		test_param_6_def;
&lt;span class=&quot;co2&quot;&gt;#define      TEST_PARAM_6_INDX		5&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#define PARAM_IMBUF_SIZE  21 // размер буфера для загрузки-сохранения параметров&lt;/span&gt;
STATIC_ASSERT&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;PARAM_IMBUF_SIZE &lt;span class=&quot;sy0&quot;&gt;==&lt;/span&gt; TPARAM_BUF_SIZE&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;;     &lt;span class=&quot;coMULTI&quot;&gt;/* Проверка на правильность установки настройки в файле poram_conf.h */&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#endif //_PARAM_LIST_H&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
Этот файл включается в любой программный модуль, который будет использовать какую-либо рабочую копию параметра, а так же &lt;acronym title=&quot;Application Programming Interface&quot;&gt;API&lt;/acronym&gt; для обслуживания параметров.
&lt;/p&gt;

&lt;p&gt;
Вначале включается заголовочный файл &lt;code&gt;tparam.h&lt;/code&gt; в котором описан интерфейс библиотеки параметров. Затем заголовочный файл &lt;code&gt;param_types.h&lt;/code&gt;, создаваемый пользователем. Этот файл должен быть один на весь проект, даже если используются несколько таблиц параметров (несколько файлов Excel).
&lt;/p&gt;

&lt;p&gt;
В файле &lt;code&gt;param_types.h&lt;/code&gt; определяются пользовательские типы параметров, а так же в этом файле я рекомендую определять значения параметров по умолчанию в виде #define. Файл &lt;code&gt;param_types.h&lt;/code&gt; может выглядеть следующим образом:
&lt;/p&gt;
&lt;pre class=&quot;c code c&quot; style=&quot;font-family:monospace;&quot;&gt;&lt;span class=&quot;co2&quot;&gt;#ifndef _PARAM_TYPES_H&lt;/span&gt;
&lt;span class=&quot;co2&quot;&gt;#define _PARAM_TYPES_H&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#include &amp;lt;csp\types.h&amp;gt;&lt;/span&gt;
&amp;nbsp;
&amp;nbsp;
&lt;span class=&quot;kw4&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;kw4&quot;&gt;struct&lt;/span&gt;
&lt;span class=&quot;br0&quot;&gt;&amp;#123;&lt;/span&gt;
    U08     mem1;
    U16     mem2;
    U32     mem3;
    &lt;span class=&quot;kw4&quot;&gt;float&lt;/span&gt;   mem4;
    &lt;span class=&quot;kw4&quot;&gt;double&lt;/span&gt;  mem5;
&amp;nbsp;
&lt;span class=&quot;br0&quot;&gt;&amp;#125;&lt;/span&gt; USER_PARAM_TYPE;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#define TEST_PARAM_4_DEF_INIT       0x40&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;co2&quot;&gt;#endif //_PARAM_TYPES_H&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;
После включения необходимых заголовочных файлов объявляются внешние переменные рабочих копий и значений по умолчанию. Так же для каждого параметра генерируется значение индекса в массиве дескрипторов. Имя литеральной константы соответствует имени параметра в верхнем регистре плюс суффикс &lt;code&gt;_INDX&lt;/code&gt;.
&lt;/p&gt;

&lt;p&gt;
В конце определяется константа &lt;strong&gt;&lt;code&gt;PARAM_[indx]_IMBUF_SIZE&lt;/code&gt;&lt;/strong&gt;. Значение этой константы соответствует размеру внутреннего массива в ОЗУ (в байтах), который используется для загрузки и сохранения параметров в NVRAM.
&lt;/p&gt;

&lt;p&gt;
&lt;p&gt;&lt;div class=&quot;noteclassic&quot;&gt;
Если вы используете в проекте несколько таблиц (фалов Excel), то для каждой таблицы будет рассчитано свое значение размера массива

&lt;/div&gt;&lt;/p&gt;
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;param_list.h&quot; [22455-26643] --&gt;
&lt;h2&gt;&lt;a name=&quot;flash_vs._eeprom&quot; id=&quot;flash_vs._eeprom&quot;&gt;Flash vs. EEPROM&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
Для работы с параметрами используется всего несколько функций:

&lt;/p&gt;
&lt;table class=&quot;inline&quot;&gt;
	&lt;tr class=&quot;row0&quot;&gt;
		&lt;th class=&quot;col0 centeralign&quot;&gt;  Функция  &lt;/th&gt;&lt;th class=&quot;col1 centeralign&quot;&gt;  Описание  &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row1&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt;   &lt;code&gt;TPARAM_ERR  tparam_init(TPARAM_TBL const *tbl)&lt;/code&gt; &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Инициализация всех рабочих копий &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row2&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt;   &lt;code&gt;TPARAM_ERR  tparam_load(TPARAM_TBL const *tbl, U16_FAST i)&lt;/code&gt; &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Загрузка параметра в рабочую копию по индексу &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row3&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt;   &lt;code&gt;TPARAM_ERR  tparam_load_p(TPARAM_TBL const *tbl, void *val)&lt;/code&gt; &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Загрузка параметра в рабочую копию по указателю &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row4&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt;   &lt;code&gt;TPARAM_ERR  tparam_save(TPARAM_TBL const *tbl, U16_FAST i)&lt;/code&gt; &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Сохранение рабочей копии в NVRAM по индексу &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row5&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt;   &lt;code&gt;TPARAM_ERR  tparam_save_p(TPARAM_TBL const *tbl, void *val)&lt;/code&gt; &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Сохранение рабочей копии в NVRAM по указателю &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row6&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt;   &lt;code&gt;TPARAM_ERR  tparam_reset(TPARAM_TBL const *tbl, U16_FAST i)&lt;/code&gt; &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Сброс параметра на значение по умолчанию по индексу &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr class=&quot;row7&quot;&gt;
		&lt;td class=&quot;col0&quot;&gt;   &lt;code&gt;TPARAM_ERR  tparam_reset_p(TPARAM_TBL const *tbl, void *val)&lt;/code&gt; &lt;/td&gt;&lt;td class=&quot;col1&quot;&gt; Сброс параметра на значение по умолчанию по указателю &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;

&lt;/div&gt;
&lt;!-- SECTION &quot;Flash vs. EEPROM&quot; [26644-] --&gt;</description>
    </item>
</rdf:RDF>
