﻿define('DISALLOW_FILE_EDIT', true);
define('DISALLOW_FILE_MODS', true);<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>/dev/head &#187; gcc</title>
	<atom:link href="http://devhead.ru/cat/gcc/feed" rel="self" type="application/rss+xml" />
	<link>http://devhead.ru</link>
	<description>Статьи и видео уроки</description>
	<lastBuildDate>Mon, 30 Jan 2017 11:12:34 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.37</generator>
	<item>
		<title>Способы отладки gdb&#8217;ом или ddd&#8217;ом приложения с fork()</title>
		<link>http://devhead.ru/main/sposoby-otladki-gdbom-ili-dddom-prilozheniya-s-fork</link>
		<comments>http://devhead.ru/main/sposoby-otladki-gdbom-ili-dddom-prilozheniya-s-fork#comments</comments>
		<pubDate>Thu, 08 Nov 2012 06:22:04 +0000</pubDate>
		<dc:creator><![CDATA[andreykyz]]></dc:creator>
				<category><![CDATA[Главная]]></category>
		<category><![CDATA[Статьи]]></category>
		<category><![CDATA[ddd]]></category>
		<category><![CDATA[fork]]></category>
		<category><![CDATA[gcc]]></category>
		<category><![CDATA[gdb]]></category>
		<category><![CDATA[баг]]></category>
		<category><![CDATA[Си]]></category>

		<guid isPermaLink="false">http://devhead.ru/?p=1637</guid>
		<description><![CDATA[Я разрабатываю клиент серверное приложение на языке программирования C (Си). У меня как и у всех разработчиков возникает необходимость запуска приложения под отладчиком. В однопоточном приложении и приложении с thread'ами (нитями) все достаточно стандартно - просто запускаем его через $ gdb мое_приложение. Но в случае если отладчик наткнется на вызов fork() он переключится на parent [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Я разрабатываю клиент серверное приложение на языке программирования C (Си). У меня как и у всех разработчиков возникает необходимость запуска приложения под отладчиком. В однопоточном приложении и приложении с thread'ами (нитями) все достаточно стандартно - просто запускаем его через $ gdb мое_приложение. Но в случае если отладчик наткнется на вызов fork() он переключится на parent (родитель) процесс, хотя обычно, в демонах, после первого fork()'а родитель завершает свою работу и по смылу нужно отлаживать child процесс. Для ddd и gbd можно писать скрипты при помощи которых можно указывать отладчику идти по parent пути или по child, также можно цепляться уже к запущенному и работающему приложению. Сейчас мы и разберем все эти способы отладки.</p>
<p><span id="more-1637"></span></p>
<h3>Отладка с выбором пути следования по вызовам fork()</h3>
<p>Первый способ, он описан в <a href="http://www.delorie.com/gnu/docs/gdb/gdb_26.html" target="_blank">документации к gdb.</a> Весь смысл метода в том чтобы описать по какой ветке идти после вызова fork() и скормить это описание отладчику. Вот пример кода для запуска под отладчиком:</p>
<pre class="brush: cpp">#include
#include
#include
#include 

#define I_CHILD 1
#define I_PARENT 2

void dummy_function(int who_i) {
    pid_t pid;
    if (who_i == I_CHILD) {
        printf("Child after first fork() call dummy_function() my pid is %i\n", getpid());
    } else {
        printf("Parent after first fork() call dummy_function() my pid is %i\n", getpid());
    }
    switch (pid = fork()) {
    case -1:
        printf("Second fork() ERROR\n");
        if (errno == ENOMEM) {
            printf("Memory is tight\n");
        }
        exit(-1);
    case 0:
        printf("I'm child after second fork() My pid is %i\n", getpid());
        break;
    default:
        printf("I'm parent after second fork() My pid is %i My child's pid is %i\n", getpid(), pid);
        break;
    }
    printf("PID %i exit\n", getpid());
    exit(0);
}

int main(int argc, char *argv[]) {
    pid_t pid;
    printf("Example started with pid %i\n", getpid());
    printf("Commandline args: ");
    while (--argc &gt; 0) {
        printf("%s ", argv[argc]);
    }
    printf("\n");
    switch (pid = fork()) {
    case -1:
        printf("First fork() ERROR\n");
        if (errno == ENOMEM) {
            printf("Memory is tight\n");
        }
        exit(-1);
    case 0:
        printf("I'm child after first fork() My pid is %i\n", getpid());
        dummy_function(I_CHILD);
    default:
        printf("I'm parent after first fork() My pid is %i My child's pid is %i\n", getpid(), pid);
        dummy_function(I_PARENT);
    }
}</pre>
<p>Сохраняем в файл fork.c компилим с ключами: -O0 - отключение оптимизации и -g - для сохранения кода в исполняемый файл (они нужны для отладчика):</p>
<blockquote><p>$ gcc fork.c -O0 -g</p></blockquote>
<p>запускаем:</p>
<blockquote><p>$ ./a.out 1 2 3 4 5 6 7 8 9 10 11 12 13</p></blockquote>
<p>Получаем что-то вроди этого:</p>
<blockquote><p>Example started with pid 6990<br />
Commandline args: 13 12 11 10 9 8 7 6 5 4 3 2 1<br />
I'm parent after first fork() My pid is 6990 My child's pid is 6991<br />
Parent after first fork() call dummy_function() my pid is 6990<br />
I'm child after first fork() My pid is 6991<br />
Child after first fork() call dummy_function() my pid is 6991<br />
I'm parent after second fork() My pid is 6990 My child's pid is 6992<br />
PID 6990 exit<br />
I'm parent after second fork() My pid is 6991 My child's pid is 6993<br />
PID 6991 exit<br />
user@server-32:~/sandbox/gdb_fork_example$ I'm child after second fork() My pid is 6993<br />
PID 6993 exit<br />
I'm child after second fork() My pid is 6992<br />
PID 6992 exit</p></blockquote>
<p>Все программа работает, но вот незадача если мы запустим её под отладчиком то сможем отлаживать лишь самый первый процесс, в предыдущем примере у него был pid 6990. И так приступим</p>
]]></content:encoded>
			<wfw:commentRss>http://devhead.ru/main/sposoby-otladki-gdbom-ili-dddom-prilozheniya-s-fork/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Компиляция/портирование своей программы под OpenWRT</title>
		<link>http://devhead.ru/read/kompilyaciyaportirovanie-svoej-programmy-pod-openwrt</link>
		<comments>http://devhead.ru/read/kompilyaciyaportirovanie-svoej-programmy-pod-openwrt#comments</comments>
		<pubDate>Fri, 23 Dec 2011 06:45:59 +0000</pubDate>
		<dc:creator><![CDATA[andreykyz]]></dc:creator>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[gcc]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[openwrt]]></category>
		<category><![CDATA[svn]]></category>

		<guid isPermaLink="false">http://devhead.ru/read/kompilyaciyaportirovanie-svoej-programmy-pod-openwrt/</guid>
		<description><![CDATA[Недавно мне понадобилось установить мою программу написанную на C(Си) на точку доступа под управлением OpenWRT. Уже была написана статья по сборке этой программы под Windows при помощи GCC из Cygwin. Для сборки же OpenWRT и всех поставляемых программ используется система сборки Buildroot и система пакетов ipkg. После долгих исследований OpenWrt Wiki и других сайтов найти [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Недавно мне понадобилось установить мою программу написанную на C(Си) на точку доступа под управлением OpenWRT. Уже была написана <a target="_blank" title="Компиляция программы из Linux в Windows при помощи Сygwin, GCC и Eclipse CDT " href="../kompilyaciya-programmy-iz-linux-v-windows-pri-pomoshhi-sygwin-gcc-i-eclipse-cdt/">статья</a> по сборке этой программы под Windows при помощи GCC из Cygwin. Для сборки же OpenWRT и всех поставляемых программ используется система сборки <a target="_blank" title="Buildroot: making Embedded Linux easy" href="http://buildroot.uclibc.org/">Buildroot</a> и система пакетов <a target="_blank" href="http://www.dd-wrt.com/wiki/index.php/Ipkg">ipkg</a>. После долгих исследований <a target="_blank" href="http://wiki.openwrt.org/">OpenWrt Wiki</a> и других сайтов найти актуальную документации не удалось. В итоге после сборки информации по крупицам я всетаки собрал пакет ipkg со своей программой. Дабы не пропасть приобретенным знаниям я решил написать данную статью.</p>
<p><span id="more-1467"></span></p>
<p><strong>Получение исходных кодов</strong></p>
<p>Я собираю OpenWrt из исходных кодов ветки trunk. Получить её можно либо при помощи git:</p>
<blockquote>
<p>git clone git://nbd.name/openwrt.git</p>
</blockquote>
<p>Либо при помощи svn:</p>
<blockquote>
<p>svn co svn://svn.openwrt.org/openwrt/trunk/ openwrt/</p>
</blockquote>
<p>Как получить другие ветки, в том числе с пакетами, написано <a target="_blank" href="https://dev.openwrt.org/wiki/GetSource" title="OpenWrt source repository downloads">т</a><a target="_blank" title="OpenWrt source repository downloads" href="https://dev.openwrt.org/wiki/GetSource">ут</a>.</p>
<p><strong>Подготовка к добаленю своего пакета</strong></p>
<p>Переходим в полученный каталог</p>
<blockquote>
<p>cd openwrt</p>
</blockquote>
<p>и получаем так называетмые <a target="_blank" title="OpenWrt Feeds" href="http://wiki.openwrt.org/doc/devel/feeds">feeds(дополнительные пакеты)</a>. Получаемые feeds можно отредактировать в файле feeds.conf.default</p>
<blockquote>
<p>./scripts/feeds update -a &amp;&amp; ./scripts/feeds install -a</p>
</blockquote>
<p>Потом выполняем комадну</p>
<blockquote>
<p>make preq</p>
</blockquote>
<p>И мы узнаем каких пакетов нехватает у нас в системе(в операционной системе)</p>
<p><strong>Добавление своего пакета</strong></p>
<p>Переходим в каталог package</p>
<blockquote>
<p>cd package/</p>
</blockquote>
<p>Создаем коталог под наш пакет(у меня он называется ecu)</p>
<blockquote>
<p>mkdir ecu</p>
</blockquote>
<p>Копируем исходники нашей программы. Я собираю простую программу которая собирается простым Makefile'ом</p>
<blockquote>
<p>mkdir ecu/ecu-src/</p>
<p>cp -r моя_программа/* ecu/ecu-src/</p>
</blockquote>
<p>Содержимое каталога ecu-src/</p>
<blockquote>
<p>$ ls -R ecu-src/<br />ecu-src/:<br />Makefile  src</p>
<p>ecu-src/src:<br />crc.c  crc.h  main.c</p>
</blockquote>
<p>Содержимое ecu-src/Makefile</p>
<blockquote>
<p>cat ecu-src/Makefile</p>
</blockquote>
<p>&nbsp;</p>
<pre class="brush: bash">ecu: main.o crc.o
        $(CC) $(LDFLAGS) main.o crc.o -o ecu
main.o: src/main.c src/crc.h
        $(CC) $(CFLAGS) -c src/main.c
crc.o: src/crc.c
        $(CC) $(CFLAGS) -c src/crc.c
clean:
        rm *.o ecu</pre>
<p>&nbsp;</p>
<p>Теперь на нужно интегрировать исходники с Makefile'ом в систему сбоки OpenWRT. Для этого нужно создать специальный Makefile в каталоге ecu/. Содержимое моего файла:</p>
<blockquote>
<p>include $(TOPDIR)/rules.mk</p>
<p>PKG_NAME:=ecu<br />PKG_RELEASE:=1<br />PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)</p>
<p>include $(INCLUDE_DIR)/package.mk</p>
<p>&nbsp;</p>
<p>define Package/ecu<br /> SECTION:=utils<br /> CATEGORY:=Utilities<br /> TITLE:=Embedded clock updater<br />endef</p>
<p>&nbsp;</p>
<p>define Package/ecu/description<br />Big comments....<br /> ...<br />endef</p>
<p>define Build/Prepare<br /> mkdir -p $(PKG_BUILD_DIR)<br /> $(CP) ./ecu-src/* $(PKG_BUILD_DIR)/<br />endef</p>
<p>define Package/ecu/install<br /> $(INSTALL_DIR) $(1)/bin<br /> $(INSTALL_BIN) $(PKG_BUILD_DIR)/ecu $(1)/bin/<br />endef</p>
<p>$(eval $(call BuildPackage,ecu))</p>
</blockquote>
<p><strong>Сборка OpenWRT с добавленным пакетом пакетом</strong></p>
<p>Переходим в корневой каталог openwrt/ и открываем menuconfig</p>
<blockquote>
<p>make menuconfig</p>
</blockquote>
<p>Далее выбираем все что нам нужно для дистрибутива( на эту тему есть <a title="Видеонаблюдение на основе роутера " href="../videonablyudenie-na-osnove-routera/">статья</a>)  и самое главное наш новый пакет. Я добавил свою программу в секцию utils то я ищу её в ней</p>
<p><img src="../../wp-content/uploads/2011/12/openwrt_utils.png" height="146" width="340" /></p>
<p>Выбираю, собирать отдельным пакетом:</p>
<p><img src="../../wp-content/uploads/2011/12/openwrt_ecu.png" /></p>
<p>Все, теперь выходим и запускаем сборку</p>
<blockquote>
<p>make</p>
</blockquote>
<p>или если у вас многоядерный процессор</p>
<blockquote>
<p>make -jn</p>
</blockquote>
<p>где n - колличество ядер + 1</p>
<p>А вот и наш пакетик</p>
<blockquote>
<p><strong>bin/ar71xx/packages/ecu_1_ar71xx.ipk</strong></p>
</blockquote>
<p><strong>Возможные проблемы</strong></p>
<p>Если в ходе сборки появляется это<strong><br /></strong></p>
<blockquote>
<p>...<br /> make[3] -C package/ecu compile<br />make -r world: build failed. Please re-run make with V=99 to see what's going on<br />make: *** [world] Ошибка 1</p>
</blockquote>
<p>то перезапускаем сборку с рекомендованным ключем(очень подробный вывод)</p>
<p>make V=99</p>
<p>и ждем, у меня, например была такая ошибка</p>
<blockquote>
<p>...<br />src/main.c: In function 'main':<br />src/main.c:113:2: error: 'for' loop initial declarations are only allowed in C99 mode<br />src/main.c:113:2: note: use option -std=c99 or -std=gnu99 to compile your code<br />src/main.c:118:4: error: 'for' loop initial declarations are only allowed in C99 mode<br />...</p>
</blockquote>
<p>не понравился синтаксис моего файла, я добавил рекомендуемый ключ компиляции, так:</p>
<blockquote>
<p>cat package/ecu/ecu-src/Makefile</p>
</blockquote>
<p>&nbsp;</p>
<pre class="brush: bash">ecu: main.o crc.o
	$(CC) $(LDFLAGS) main.o crc.o -o ecu
main.o: src/main.c src/crc.h
	$(CC) $(CFLAGS) -std=gnu99 -c src/main.c
crc.o: src/crc.c
	$(CC) $(CFLAGS) -std=gnu99 -c src/crc.c
clean:
	rm *.o ecu</pre>
]]></content:encoded>
			<wfw:commentRss>http://devhead.ru/read/kompilyaciyaportirovanie-svoej-programmy-pod-openwrt/feed</wfw:commentRss>
		<slash:comments>53</slash:comments>
		</item>
		<item>
		<title>Компиляция программы из Linux в Windows при помощи Сygwin, GCC и Eclipse CDT</title>
		<link>http://devhead.ru/read/kompilyaciya-programmy-iz-linux-v-windows-pri-pomoshhi-sygwin-gcc-i-eclipse-cdt</link>
		<comments>http://devhead.ru/read/kompilyaciya-programmy-iz-linux-v-windows-pri-pomoshhi-sygwin-gcc-i-eclipse-cdt#comments</comments>
		<pubDate>Mon, 19 Dec 2011 06:05:15 +0000</pubDate>
		<dc:creator><![CDATA[andreykyz]]></dc:creator>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[Cygwin]]></category>
		<category><![CDATA[Eclipse CDT]]></category>
		<category><![CDATA[gcc]]></category>
		<category><![CDATA[win32]]></category>

		<guid isPermaLink="false">http://devhead.ru/read/kompilyaciya-programmy-iz-linux-v-windows-pri-pomoshhi-sygwin-gcc-i-eclipse-cdt/</guid>
		<description><![CDATA[Недавно мне срочно понадобилось установить небольшое написанное мною консольное приложение на машину с Windows которое изначально предназначаось для Linux. При разработке я использовалал среду Eclipse CDT. Особенность приложения было в том, что оно работало с com портом при помощи стандартных средств из Linux (termios.h). Сначала я обнаружил, что под windows используются немного другие средства работы [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Недавно мне срочно понадобилось установить небольшое написанное мною консольное приложение на машину с Windows которое изначально предназначаось для Linux. При разработке я использовалал среду Eclipse CDT. Особенность приложения было в том, что оно работало с com портом при помощи стандартных средств из Linux (termios.h). Сначала я обнаружил, что под windows используются немного другие средства работы с последовательным интерфейсом изучать который не было ни какого интереса. Я немного поразмыслил и вспомнил, что есть такая штука как Cygwin и в его компонентах есть специальная версия компилятора gcc которая может компилировать приложения использующие POSIX api как win32 приложения.</p>
<p><span id="more-1440"></span>И так что мы имеем. Проект из Eclipse c исходниками на C (Си). Для начала нужно установить<strong> Cygwin c GCC</strong>. Качаем его с сайта проекта http://cygwin.org/ (<a title="Cygwin setup" href="http://cygwin.com/setup.exe">Прямая ссылка</a>). Запускаем setup.exe, выбираем зеркало и следующие обязательные пакеты:</p>
<ul>
<li>gcc4-core</li>
<li>make</li>
<li>git-core</li>
</ul>
<p>Установку Cygwin устанавливаем в каталог c:/cygwin</p>
<p><img src="../../wp-content/uploads/2011/12/cygwinProcess.png" style="vertical-align: middle;" height="397" width="540" /></p>
<p>После установки добавляем в системную. переменную окружения Path путь к Cygwin:</p>
<p><img src="../../wp-content/uploads/2011/12/systemPath.png" /></p>
<p>Далее, качаем с сайта http://www.eclipse.org/ (<a href="http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/indigo/SR1/eclipse-cpp-indigo-SR1-incubation-win32.zip">прямая ссылка</a>) <strong>Eclipse с CDT</strong> плагином. Распаковываем его куда-нибудь(например в корень диска C:) Кидаем ярлык на рабочий стол. Закускаем Eclipse и импортируем наш проект:</p>
<ol>
<li><img src="../../wp-content/uploads/2011/12/importProgect.png" height="213" width="245" /></li>
<li><img src="../../wp-content/uploads/2011/12/import_1.png" /></li>
<li><img src="../../wp-content/uploads/2011/12/import_2.png" height="522" width="514" /></li>
</ol>
<p>После импорта проекта настраиваем пути к компилятору и Includes.</p>
<p>Нажимаем правой кнопкой на проекте и выбираем - Properties:</p>
<p><img src="../../wp-content/uploads/2011/12/openProperties.png" height="114" width="298" /></p>
<p>Сначала я выбрал правильную кодировку моего проекта:</p>
<p><img src="../../wp-content/uploads/2011/12/properties.png" height="542" width="706" /></p>
<p>Далее выбирал соответствующий Cygwin GCC toolchain</p>
<p><img src="../../wp-content/uploads/2011/12/chooseToolChain.png" /></p>
<p>Если все выбрано правильно, то должен появиться соответствующие Includes</p>
<p><img src="../../wp-content/uploads/2011/12/includes.png" height="204" width="359" /></p>
<p>Теперь выбираем в Build configuration  - Release:</p>
<p><img src="../../wp-content/uploads/2011/12/setR.png" /></p>
<p>Также хочу отметить в Windows существует понятие оконного и консольного приложения для того чтобы сорать оконное, я добавил ключ ﻿-mwindows для линковщика, т.к. по умолчанию собирается консольное приложение(ключ -mconsole) и при запуске мигает консоль. Можно запускать компиляцию.</p>
<p><strong>Возможные проблемы</strong>:</p>
<p><img src="../../wp-content/uploads/2011/12/pathProblem.png" height="92" width="343" /></p>
<p><img src="../../wp-content/uploads/2011/12/pathMakeError.png" height="59" width="252" /></p>
<p>Подобные ошибки могут возникать, либо по тому что вы не выбрали все нужные компонены при установке Cygwin, либо у вас не прописан путь к Cygwin/bin в переменной окружения Path.</p>
]]></content:encoded>
			<wfw:commentRss>http://devhead.ru/read/kompilyaciya-programmy-iz-linux-v-windows-pri-pomoshhi-sygwin-gcc-i-eclipse-cdt/feed</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>Опрос датчика температуры по 1-wire контроллером AVR на Си с avr-libc</title>
		<link>http://devhead.ru/read/opros-datchika-temperatury-po-1-wire-kontrollerom-avr-na-si-s-avr-libc</link>
		<comments>http://devhead.ru/read/opros-datchika-temperatury-po-1-wire-kontrollerom-avr-na-si-s-avr-libc#comments</comments>
		<pubDate>Mon, 29 Aug 2011 07:48:54 +0000</pubDate>
		<dc:creator><![CDATA[andreykyz]]></dc:creator>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[1-wire]]></category>
		<category><![CDATA[avr]]></category>
		<category><![CDATA[avr-libc]]></category>
		<category><![CDATA[gcc]]></category>

		<guid isPermaLink="false">http://devhead.ru/read/opros-datchika-temperatury-po-1-wire-kontrollerom-avr-na-si-s-avr-libc/</guid>
		<description><![CDATA[Недавно мне по работе нужно было реализовать на AVR опрос датчика температуры Dallas DS18B20 для управления частотным приводом насоса системы охлаждения. В интернете нашел много статей как всё это сделать на ассемблере, но по некоторым обстоятельствам мне нужно было на Си. В начале добавим заголовочные файлы: &#160; #include &#60;avr/io.h&#62; #include &#60;util/crc16.h&#62; #include &#60;util/delay.h&#62; #include &#60;avr/interrupt.h&#62; [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Недавно мне по работе нужно было реализовать на AVR опрос датчика температуры <a href="http://datasheets.maxim-ic.com/en/ds/DS18B20.pdf">Dallas DS18B20 </a>для управления частотным приводом насоса системы охлаждения. В интернете нашел много статей как всё это сделать на ассемблере, но по некоторым обстоятельствам мне нужно было на Си. <span id="more-1338"></span></p>
<p>В начале добавим заголовочные файлы:</p>
<p>&nbsp;</p>
<pre class="brush: cpp">#include &lt;avr/io.h&gt;
#include &lt;util/crc16.h&gt;
#include &lt;util/delay.h&gt;
#include &lt;avr/interrupt.h&gt;</pre>
<p>&nbsp;</p>
<p>После этого я обычно объявляю макросы для работы с отдельными выводами портов ввода/вывода. На моей схеме датчик был подкулючен через согласующий транзистор к разным выводам. У меня получился такой код:</p>
<p>&nbsp;</p>
<pre class="brush: cpp">#define RX() bit_is_set(PINC,0)
#define TX1() PORTC &amp;= ~_BV(1) //выходной сигнал инвертирован
#define TX0() PORTC |= _BV(1)</pre>
<p>&nbsp;</p>
<p>Из datasheet на датчики температуры фирмы Dallas ясно, что все команды общения с датчиком посылаются после инициализация. Она нужна для того чтобы датчик понял, что ему сейчас будет послана команда. И написал такую функцию:</p>
<p>&nbsp;</p>
<pre class="brush: cpp">/*Сброс и ожидание начала presence pulse*/
uint8_t oneWireInit() {
	cli();
	TX0();
	_delay_us(500);
	TX1();
	_delay_us(60);
	sei();
	return RX() ; //если на выводе 1 - ошибка
}</pre>
<p>&nbsp;</p>
<p>Далее напишем фунцию отправки массива данных. т.к. вся работа с датчиком происходит в пределах одного пространтва имен я объявил глобальный массив:</p>
<p>&nbsp;</p>
<pre class="brush: cpp">uint8_t frame[9] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};</pre>
<p>&nbsp;</p>
<p>как разделяемые данные для разных функций. И так функция отправки(как аргумент функция получает байт который необходимо отправить):</p>
<p>&nbsp;</p>
<pre class="brush: cpp">/* Передача 1 байта. Передача осуществляется
 * младшим битом вперед
 */
void oneWireTans(uint8_t data) {
	cli();
	for (uint8_t i = 0; i&lt;8;i++) {
		TX0(); //импульс сброса (1-15мкс) - начало интервала передачи
		_delay_us(5);
		if (data &amp; 0x01) {
			TX1();
		}
		else {
			TX0();
		}
		_delay_us(60);//пауза для считывания данных таблеткой (60-120мкс)
		TX1();//импульс сброса "1"(1мкс)
		_delay_us(10);
		data &gt;&gt;= 1;
	}
	sei();
}</pre>
<p>&nbsp;</p>
<p>Прием данных осуществляется в массив frame в качестве аргумента функция получает колличество байт, оно зависит от типа команды которую мы послали датчику:</p>
<p>&nbsp;</p>
<pre class="brush: cpp">/*Чтение length байт данных младшим байтом вперед*/
void oneWireRecv(uint8_t length) {
	cli();
	_delay_us(60);
	for (uint8_t i = 0;i&lt;length;i++) {
		frame[i] = 0x00; //Очистка буфера приема
		/*Цикл для приема очередного байта*/
		for (uint8_t j = 0;j&lt;8;j++) {
			frame[i] &gt;&gt;= 1;
			TX0();			//импульс сброса "0"(1-15мкс) - начало интервала приема
			_delay_us(10);
			TX1();			//импульс сброса "1"
			_delay_us(9);
			frame[i] |= RX() ? 0x80:0;
			_delay_us(50);
		}

	}
	sei();
}</pre>
<p>&nbsp;</p>
<p>В нутри каждой функции есть макросы cli() и sei() для запрета прерываний на время общения с датчиком.</p>
<p>Все базовые функции написаны. Теперь напишем функцию которая мопожет нам обстрагироваться от всех внутренних команд датчика и просто возвратит температуру. Я назавал функцию getT() --&gt; get Temperature вот её содержимое:</p>
<p>&nbsp;</p>
<pre class="brush: cpp">uint16_t getT() {

	/*Чение адреса термо датчика*/
	if (oneWireInit()) return 255;
	_delay_us(110);			//Ожидание конца presence pulse
	oneWireTans(0x33);		//Чтение ROM подчиненного устройства
	oneWireRecv(8);			//Читаем ROM

	/*Расчет CRC*/
	uint8_t crcResult = 0;
	for (uint8_t i = 0; i&lt;7;i++) {
		crcResult = _crc_ibutton_update(crcResult,frame[i]);
	}
	if (crcResult != frame[7]) return 254;

	/*даем команду конвертации температуры нужному устройсту*/
	if (oneWireInit()) return 253;
	_delay_us(110);			//Ожидание конца presence pulse
	oneWireTans(0x55);
	for (uint8_t i = 0; i&lt;8; i++) {
		oneWireTans(frame[i]);
	}
	oneWireTans(0x44);		//Команда конвертации и записи температуры в регистр

	/*Чтение температуры*/
	if (oneWireInit()) return 252;
	_delay_us(110);			//Ожидание конца presence pulse
	oneWireTans(0x55);
	for (uint8_t i = 0; i&lt;8; i++) {
		oneWireTans(frame[i]);
	}
	oneWireTans(0xBE);		//Комманда чтения регистра с температурой
	oneWireRecv(9);
	crcResult = 0;
	for (uint8_t i =0; i&lt;8;i++) {
		crcResult = _crc_ibutton_update(crcResult,frame[i]);
	}
	if(crcResult != frame[8]) return 251;

	//Store integer
	uint16_t digit=frame[0]&gt;&gt;4;
	digit|=(frame[1]&amp;0xf)&lt;&lt;4;
	//Store decimal digits
	uint8_t decimal=frame[0]&amp;0xf;
	decimal= (decimal*5)/8;

	/*Возвращается только цело значение*/
	return ((uint16_t)digit);
}</pre>
<p>&nbsp;</p>
<p>При проектировании я знал, что теперература возвращаемая датчиком не может быть больше 125С. И все значаения выше 200 я возвращал как сигнал о той или иной ошибке. Используем функцию так. Считываем значение в переменную. Если значение больше 200 значит произошла та или иная ошибка чтения. Если меньше значит все Ок и это искомая температура. Если есть предложения по улучшению кода, пишите в комментариях к статье.</p>
<p><a href="../../wp-content/uploads/2011/08/onewire.zip">Архив с исходниками.</a></p>
<p>Дополнительная информация:</p>
<ul>
<li><a href="http://www.nongnu.org/avr-libc/user-manual/pages.html">Документация по библиотеке avr-libc</a></li>
<li><a href="http://www.avrfreaks.net/">Форум посвященный AVR</a></li>
<li><a href="http://datasheets.maxim-ic.com/en/ds/DS18B20.pdf">Datasheet Dallas 18B20</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://devhead.ru/read/opros-datchika-temperatury-po-1-wire-kontrollerom-avr-na-si-s-avr-libc/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->