123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624 |
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ru-ru" dir="ltr" lang="ru-ru"><head>
- <!-- base href="http://easystm32.ru/for-beginners/11-mcu-ports" -->
- <meta http-equiv="content-type" content="text/html; charset=UTF-8">
- <meta name="keywords" content="Микроконтроллеры, электроника, STM32">
- <meta name="author" content="Medved">
- <meta name="description" content="Микроконтроллеры STM32">
- <meta name="generator" content="Joomla! - Open Source Content Management">
- <title>EasySTM32 - Порты микроконтроллера</title>
- <link href="http://easystm32.ru/templates/shoplab/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
- <link href="http://easystm32.ru/component/search/?Itemid=108&catid=10&id=11&format=opensearch" rel="search" title="Искать EasySTM32" type="application/opensearchdescription+xml">
- <style type="text/css">
- #wrapper { margin: 0 auto; width: 960px;padding:0;}
- .s-c-s #colmid { left:245px;}
- .s-c-s #colright { margin-left:-245px;}
- .s-c-s #col1pad { margin-left:245px;}
- .s-c-s #col2 { left:0px;width:245px;}
- .s-c-s #col3 { width:0px;}
- .s-c-x #colright { left:245px;}
- .s-c-x #col1wrap { right:245px;}
- .s-c-x #col1 { margin-left:245px;}
- .s-c-x #col2 { right:245px;width:245px;}
- .x-c-s #colright { margin-left:-0px;}
- .x-c-s #col1 { margin-left:0px;}
- .x-c-s #col3 { left:0px;width:0px;}
- </style>
- <script src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/mootools-core.js" type="text/javascript"></script>
- <script src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/core.js" type="text/javascript"></script>
- <script src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/caption.js" type="text/javascript"></script>
- <script src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/mootools-more.js" type="text/javascript"></script>
- <script type="text/javascript">
- window.addEvent('load', function() {
- new JCaption('img.caption');
- });
- function keepAlive() { var myAjax = new Request({method: "get", url: "index.php"}).send();} window.addEvent("domready", function(){ keepAlive.periodical(840000); });
- </script>
- <link type="text/css" rel="stylesheet" href="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/shCore.css">
- <link type="text/css" rel="stylesheet" href="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/shThemeDefault.css">
- <script type="text/javascript" src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/shCore.js"></script>
- <script type="text/javascript" src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/shBrushCpp.js"></script>
- <link rel="stylesheet" href="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/system.css" type="text/css">
- <link rel="stylesheet" href="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/styles.css" type="text/css" media="screen,projection">
- <script language="javascript" type="text/javascript">
- window.addEvent('domready', function(){
- var top_panel = document.id('top-panel');
- var sub_panel = document.id('sub-panel');
- var topFx = new Fx.Slide(top_panel);
- if (Cookie.read('top-panel') == '1') {
- topFx.show();
- } else {
- topFx.hide();
- }
- sub_panel.addEvents({
- 'click' : function(){
- if (topFx.open) {
- Cookie.write('top-panel', '0');
- } else {
- Cookie.write('top-panel', '1');
- }
- topFx.toggle();
- }
- });
- });
- </script>
- </head>
- <body>
- <div id="popup_name" class="popup_block">
- </div>
- <div class="topground"></div>
- <div id="main">
- <div id="wrapper">
- <div id="header"><div class="headtop"><div id="top-panel">
- <div class="currency"></div>
- </div>
- <div id="sub-panel">
- </div></div>
- <div class="logo">
- <a href="http://easystm32.ru/" id="logo" title="EasySTM32.ru"><img src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/logo.jpg" alt=""></a>
- </div>
- <div class="supertop"><div class="left"></div><div class="arm">
- <ul class="menu">
- <li class="item-106"><a href="http://easystm32.ru/donate">Donate!</a></li></ul>
- </div><div class="clr"></div></div>
- </div>
- <div id="navigace"><div class="levy">
- <img alt="" src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/levy.png">
- </div> <div class="pravy">
- <img alt="" src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/pravy.png">
- </div>
- <form action="/for-beginners" method="post">
- <div class="search">
- <input name="searchword" id="mod-search-searchword" maxlength="20" class="inputbox" size="20" value="Поиск..." onblur="if (this.value=='') this.value='Поиск...';" onfocus="if (this.value=='Поиск...') this.value='';" type="text"><input class="button" src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/buttonsearch.png" onclick="this.form.searchword.focus();" alt="submit" type="image"><input name="task" value="search" type="hidden">
- <input name="option" value="com_search" type="hidden">
- <input name="Itemid" value="108" type="hidden">
- </div>
- </form>
-
- <ul class="menu">
- <li class="item-122"><a href="http://easystm32.ru/soft">Программы</a></li><li class="item-120"><a href="http://easystm32.ru/library">Библиотека</a></li><li class="item-119"><a href="http://easystm32.ru/about">О сайте</a></li><li class="item-121"><a href="http://easystm32.ru/contacts">Обратная связь</a></li><li class="item-123"><a href="http://easystm32.ru/links">Ссылки</a></li><li class="item-148"><a href="http://easystm32.ru/?format=feed&type=rss">RSS</a></li></ul>
- </div>
- <div id="message">
-
- <div id="system-message-container">
- </div>
- </div>
- <div id="main-content" class="s-c-s">
- <div id="colmask">
- <div id="colmid">
- <div id="colright">
- <div id="col1wrap">
- <div id="col1pad">
- <div id="col1">
-
- <div class="component"><div class="breadcrumbs-pad">
- <script type="text/javascript">
- var begun_auto_pad = 353320856;
- var begun_block_id = 353320860;
- </script>
- <script src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/autocontext2.js" type="text/javascript"></script>
-
- </div><div class="item-page">
- <h2>
- <a href="http://easystm32.ru/for-beginners/11-mcu-ports">
- Порты микроконтроллера</a>
- </h2>
-
- <p style="text-align: justify;">Порты ввода/вывода пожалуй важнейшая
- часть микроконтроллера, без неё всё остальное просто бессмысленно.
- Сколько бы не было у контроллера памяти, периферии, какой бы высокой не
- была тактовая частота - это всё не имеет значения если он не может
- взаимодействовать с внешним миром. А взаимодействие это осуществляется
- через эти самые порты ввода/вывода. Далее для краткости будем называть
- их просто портами. Порт это некоторый именованный набор из 16-ти (как
- правило) ног контроллера, каждая из которых может быть индивидуально
- настроена и использована. Количество портов может различаться, например в
- контроллере установленном в отладочной плате STM32vl Discovery имеются
- три порта A,B,C. Существует два основных режима работы ног контроллера:
- вход и выход. Когда нога контроллера настроена на выход - к ней можно
- прицепить любой потребитель: светодиод, пищалку, да и вообще что угодно.
- Нужно понимать что ноги у контроллера не потянут большую нагрузку.
- Максимальный ток который может пропустить через себя одна нога
- составляет ~20 мА. Если планируется подключать что-то с более высоким
- энергопотреблением то нужно делать это через транзисторный ключ. В
- противном случае нога порта (а то и весь порт, чем черт не шутит) сгорит
- и перестанет выполнять свои функции. Чтобы обезопасить ногу порта можно
- прицепить к ней резистор номиналом примерно 220 ом. Таким образом при
- напряжении питания 3.3 вольта даже при коротком замыкании ноги на землю
- ток не превысит критического значения. Второй режим работы ноги
- контроллера - это вход. Благодаря этому режиму мы можем считывать
- например состояние кнопок, проверяя есть ли на ноге напряжение или нет.
- Это вкратце, а сейчас рассмотрим подробнее как работать с портами.
- Рассматривать будем конечно же на практике, благо что аппаратная часть
- (светодиоды и кнопка) для наших экспериментов уже реализована на плате
- STM32vl Discovery. Если же платы нет, то можно подключить к контроллеру
- светодиоды и кнопку следующим образом: </p>
- <p style="text-align: center;"><img style="display: block; margin-left: auto; margin-right: auto;" src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/schematic.png" alt="schematic" width="650"></p>
- <p style="text-align: center;"> </p>
-
- <p>Для начала попробуем зажечь светодиоды, для этого мы должны произвести аж целых три действия: </p>
- <ol>
- <li>Включить тактирование порта</li>
- <li>Настроить две ножки как выходы</li>
- <li>Установить логическую единицу на 2-х выводах порта</li>
- </ol>
- <p>Для начала создадим проект в CooCox'e точно так же как мы <a href="http://easystm32.ru/for-beginners/8-soft-for-stm32">[делали ранее]</a>. Запишем в файл main.c следующий код и будем разбираться: </p>
- <p><span style="text-align: justify;"><script type="text/javascript">
- SyntaxHighlighter.config.clipboardSwf = "http://easystm32.ru/plugins/content/CodeCitation/codecitation/scripts/clipboard.swf";
- SyntaxHighlighter.defaults["auto-links"] = true;
- SyntaxHighlighter.defaults["collapse"] = false;
- SyntaxHighlighter.defaults["gutter"] = true;
- SyntaxHighlighter.defaults["smart-tabs"] = true;
- SyntaxHighlighter.defaults["tab-size"] = 4;
- SyntaxHighlighter.defaults["toolbar"] = true;
- SyntaxHighlighter.defaults["wrap-lines"] = true;
- SyntaxHighlighter.all();
- </script></span></p><div style="overflow: hidden; display: block; height: auto; width: inherit;"><pre class="brush:cpp">#include <stm32f10x_rcc.h>
-
- int main(void) {
- RCC->APB2ENR |= RCC_APB2Periph_GPIOC;
- GPIOC->CRH |=0x33;
- GPIOC->CRH &= ~0xCC;
- GPIOC->ODR |= (GPIO_ODR_ODR9 | GPIO_ODR_ODR8);
- } </pre></div><p></p>
- <p> </p>
- <p style="text-align: justify;">Всего-то четыре строчки кода, но сколько
- смысла :) Для начала разберемся что значит "Включить тактирование
- порта". В контроллере полно периферии: Таймеры, АЦП, USART и т.д. Порт
- ввода/вывода является такой же периферией. Когда периферия включена
- (подаются тактовые импульсы) - она потребляет ток. Нет тактирования -
- нет потребления. По умолчанию вообще весь этот зоопарк периферии
- вырублен. Итак нас интересует порт C, ведь именно на нем висят наши
- светодиоды. Для включения/выключения периферии есть два регистра
- RCC_APB1ENR и RCC_APB2ENR. Нам нужен последний, потому что через него мы
- можем управлять тактированием порта C. Устроен этот регистр так: </p>
- <p><img style="border-style: initial; border-color: initial; border-image: initial; display: block; margin-left: auto; margin-right: auto; border-width: 0px;" src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/rcc_apb2enr.png" alt="rcc_apb2enr" border="0" width="650"></p>
- <p style="text-align: justify;"><span style="text-align: justify;">Как видно на картинке в нем есть бит IOPCEN. Установив его в единицу мы включим наш порт. Именно это и делает строчка кода </span></p>
- <p></p><div style="overflow: hidden; display: block; height: auto; width: inherit;"><pre class="brush:cpp">RCC->APB2ENR |= RCC_APB2Periph_GPIOC;
- </pre></div><p></p>
- <p style="text-align: justify;">После включения тактирования мы должны
- настроить некоторые (а именно 8-ю и 9-ю) ноги порта на
- выход. За конфигурирование вообще любого
- порта отвечают два регистра GPIOx_CRL и GPIOx_CRH где икс это
- буква порта (от A до G), в нашем случае это буква С. Оба регистра
- выполняют одну и ту же функцию, просто GPIOx_CRL отвечает за
- конфигурирование младшей половины порта (ножки с 0 по 7), а GPIOx_CRH
- старшей (ножки с 8 по 15). Наши светодиоды висят на ногах PC8 и PC9 а
- это значит что для настройки этих ног в режим выхода нам потребуется
- регистр GPIOC_CRH. Вот так он устроен: </p>
- <p style="text-align: justify;"><img style="border-style: initial; border-color: initial; border-image: initial; display: block; margin-left: auto; margin-right: auto; border-width: 0px;" src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/gpiox_crh.jpg" alt="gpiox_crh" border="0" width="650"><span style="text-align: justify;">Как
- видно из этой красивой и цветной картинки, на каждую ногу отводится по
- четыре бита. Причем биты объединены в две группы по два бита в каждой.
- первая группа - MODE. Собственно эти биты решают входм или выходом будет
- конкретная ножка порта, допустимы следующие комбинации: </span></p>
- <table border="0">
- <tbody>
- <tr>
- <td>MODE1 </td>
- <td>MODE0 </td>
- <td>Значение</td>
- </tr>
- <tr>
- <td>0</td>
- <td>0</td>
- <td>Вход (Состояние по умолчанию)</td>
- </tr>
- <tr>
- <td>0</td>
- <td>1</td>
- <td>Выход, максимальная частота 10 МГц</td>
- </tr>
- <tr>
- <td>1</td>
- <td>0</td>
- <td>Выход, максимальная частота 2 МГц</td>
- </tr>
- <tr>
- <td>1</td>
- <td>1</td>
- <td>Выход, максимальная частота 50 МГц</td>
- </tr>
- </tbody>
- </table>
- <p style="text-align: justify;">Максимальная частота в моём понимании
- это насколько быстро нога может менять свое состояние, скорее всего
- частота влияет на энергопотребление. Теперь для рассмотрим следующую
- группу бит CNF. Если мы настроили ногу на выход (биты MODE отличны от
- нуля) то биты группы CNF могут принимать следующие значения: </p>
- <table border="0">
- <tbody>
- <tr>
- <td>CNF1 </td>
- <td>CNF0 </td>
- <td>Значение</td>
- </tr>
- <tr>
- <td>0</td>
- <td>0</td>
- <td> Обычный режим. Push-pull</td>
- </tr>
- <tr>
- <td>0</td>
- <td>1</td>
- <td> Обычный режим. Открытый коллектор</td>
- </tr>
- <tr>
- <td>1</td>
- <td>0</td>
- <td> Альтернативный режим. Push-pull</td>
- </tr>
- <tr>
- <td>1</td>
- <td>1</td>
- <td> Альтернативный режим. Открытый коллектор</td>
- </tr>
- </tbody>
- </table>
- <p style="text-align: justify;">Тут всё немного сложнее, во-первых
- разберёмся что подразумевается под обычным и альтернативный режимами. В
- обычном режиме вы можете распоряжаться ногой как вам угодно, например
- установить единицу или ноль при помощи своего кода. В альтернативном
- режиме вы передаёте эту ножку контроллера в распоряжение какой-либо
- периферии контроллера например UART'у, SPI, I2c и всему прочему что
- нуждается в ножках. Теперь разберемся чем отличается push-pull от
- открытого коллектора. В режиме push-pull нога всегда находится в одном
- из двух состояний: На ней всегда либо земля либо полное напряжение
- питания. В режиме открытого коллектора: Земля или ничего, нога просто
- как-бы зависает в воздухе ни к чему не подключенная внутри контроллера.
- Теперь рассмотрим что означают те же самый два бита если наш порт
- настроен на вход (биты MODE обнулены):</p>
- <table border="0">
- <tbody>
- <tr>
- <td>CNF1 </td>
- <td>CNF0 </td>
- <td>Значение</td>
- </tr>
- <tr>
- <td>0</td>
- <td>0</td>
- <td> Аналоговый режим</td>
- </tr>
- <tr>
- <td>0</td>
- <td>1</td>
- <td> Вход без подтяжки</td>
- </tr>
- <tr>
- <td>1</td>
- <td>0</td>
- <td> Вход с подтяжкой</td>
- </tr>
- <tr>
- <td>1</td>
- <td>1</td>
- <td> Зарезервировано</td>
- </tr>
- </tbody>
- </table>
- <p style="text-align: justify;">Аналоговый режим предназначен для работы
- АЦП, если мы хотим чтоб АЦП мог производить измерения используя эту
- ногу мы должны выбрать этот режим. Вход без подтяжки делает ногу входом с
- Hi-z состоянием, это означает что сопротивление входа велико и любая
- электрическая наводка (помеха) может вызвать появление на таком входе
- единицу или ноль, причем сделать это не предсказуемо. Во избежание этого
- нужно использовать подтяжку, она позволяет установить на входе какое
- либо устойчивое состояние которое не будет зависеть от помех. Подтяжка
- представляет собой резистор большого сопротивления подключенный одним
- концом к земле или к плюсу питания, а другим концом ко входу. Например
- если включена подтяжка к плюсу питания, то когда нога контроллера ни
- куда не припаяна на ней всегда логическая единица. Если мы припаяем
- кнопку между этой ножкой и землёй, то всякий раз при нажатии кнопки на
- ноге будет появляться логический ноль. Если бы подтяжка была выключена,
- то в момент нажатия кнопки на ноге так же появлялся бы ноль, но при
- отпущенной кнопке нога могла бы легко поймать любую наводку и вызвать
- появление логической единицы на ноге. В результате, микроконтроллер бы
- думал что кто-то хаотично жмет на кнопку. Мы рассмотрим все это на
- практике чуть позже, а сейчас вернемся к нашему регистру <span style="text-align: justify;">GPIOC_CRH. Итак мы планируем установить биты этого регистра (для двух ножек <span style="text-align: justify;">PC8 и PC9)</span> следующим образом: </span></p>
- <p><span style="text-align: justify;"><img src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/gpioc_crh_config.png" alt="gpioc_crh_config" width="650"></span></p>
- <p style="text-align: justify;">Исходя из вышесказанного, такая
- комбинация бит настроит обе ножки на выход с максимальной частотой 50
- МГц в обычном режиме push-pull, что нам вполне подходит. Эта строчка
- устанавливает в единицы биты MODE:</p>
- <p></p><div style="overflow: hidden; display: block; height: auto; width: inherit;"><pre class="brush:cpp"> GPIOC->CRH |=0x33;
- </pre></div><p></p>
- <p>А вот эта, обнуляет биты CNF:</p>
- <p></p><div style="overflow: hidden; display: block; height: auto; width: inherit;"><pre class="brush:cpp"> GPIOC->CRH &= ~0xCC;
- </pre></div><p></p>
- <p>После выполнения этих двух строк, младшие 8 бит этого регистра будут
- такими как на рисунке выше: 00110011, при этом все остальные биты
- останутся в том состоянии в котором они и были, наш код их не затронет. В
- принципе, в данном случае не будет ничего страшного если вместо
- этих двух строк мы просто напишем: </p>
- <p></p><div style="overflow: hidden; display: block; height: auto; width: inherit;"><pre class="brush:cpp"> GPIOC->CRH = 0x33; // 0x33 это и есть 00110011
- </pre></div><p></p>
- <p>Но нужно понимать что во все остальные биты (кроме первых восьми)
- запишутся нули, и это повлияет на конфигурацию остальных пинов (они все
- станут аналоговыми входами). Теперь когда обе ножки сконфигурированы
- можно попробовать зажечь светодиоды. За вывод данных в порт C отвечает
- регистр GPIOC_ODR, записывая в определённый бит единицу, мы
- получаем логическую единицу на соответствующей ножке порта. Поскольку в
- порте С 16 ножек, а регистр 32-х битный, то используются только первые
- 16 бит. Светодиоды подключены к пинам <span style="text-align: justify;">PC8 и PC9, поэтому мы должны установить восьмой и девятый биты. Для этого служит строчка:</span></p>
- <p><span style="text-align: justify;"></span></p><div style="overflow: hidden; display: block; height: auto; width: inherit;"><pre class="brush:cpp"> GPIOC->ODR |= (GPIO_ODR_ODR9 | GPIO_ODR_ODR8);
- </pre></div><p></p>
- <p style="text-align: justify;"><span style="text-align: justify;">Очень
- надеюсь, что читатели знакомы с битовой арифметикой в Си :) ибо без неё
- может быть сложновато. Ну собственно все, после компиляции и загрузки
- программы в контроллер - на платке загорятся два светодиода: синий и
- зелёный. Использование регистра GPIOC_ODR - это не единственный
- способ изменить состояние порта С. Существует еще один регистр
- позволяющий сделать это - GPIOC_BSRR. Этот регистр позволят
- атомарно устанавливает состояние какой-либо ножки. Ведь в примере выше
- мы делали следующим образом: </span></p>
- <p style="text-align: justify;"><span style="text-align: justify;">1) Считывали текущее состояние регистра GPIOC_ODR в некоторую временную переменную </span></p>
- <p style="text-align: justify;"><span style="text-align: justify;">2) устанавливали в ней нужные биты (8-й и 9-й) </span></p>
- <p style="text-align: justify;"><span style="text-align: justify;">3) записывали то что получилось обратно в регистр <span style="text-align: justify;">GPIOC_ODR. </span></span></p>
- <p style="text-align: justify;"><span style="text-align: justify;"><span style="text-align: justify;">Чтение->модификация->запись
- это довольно долгая процедура, иногда надо делать это очень быстро. Вот
- тут то и выходит на сцену регистр <span style="text-align: justify;">GPIOC_BSRR. Посмотрим как он устроен: </span></span></span></p>
- <p><img style="display: block; margin-right: auto; margin-left: auto;" src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/gpioc_bsrr.png" alt="gpioc_bsrr" width="650"></p>
- <p>На каждую ножку порта выделяется по два бита: BRXX и BSXX. Далее всё
- просто: записывая единицу в бит BSXX мы устанавливаем на соответствующей
- ножке логическую единицу. Записывая единицу в бит BRXX мы сбрасываем в
- ноль соответствующую ножку. Запись нулей в любой из битов не приводит ни
- к чему. Если мы заменим последнюю строчку программы на : </p>
- <p><span style="text-align: justify;"></span></p><div style="overflow: hidden; display: block; height: auto; width: inherit;"><pre class="brush:cpp">GPIOC->BSRR=(GPIO_BSRR_BS8|GPIO_BSRR_BS9);
- </pre></div><p></p>
- <p><span style="text-align: justify;">то получим тот же результат, но
- работает оно быстрей :) Ну а для того чтоб сбросить в ноль определённые
- биты порта С необходим так же записать две единицы но уже в биты BR8 и
- BR9:</span></p>
- <p><span style="text-align: justify;"></span></p><div style="overflow: hidden; display: block; height: auto; width: inherit;"><pre class="brush:cpp">GPIOC->BSRR=(GPIO_BSRR_BR8|GPIO_BSRR_BR9);
- </pre></div><p></p>
- <p style="text-align: justify;"><span style="text-align: justify;">Но и
- это еще не всё :) Так же изменить состояние порта можно при помощи
- регистра GPIOC_BRR, установив в единицу какой либо из первых 16-бит, мы
- сбросим в ноль соответствующие ножки порта. Зачем он нужен - не понятно,
- ведь есть же регистр GPIOC_BSRR который может делать тоже самое да и
- еще плюс устанавливать логическую единицу на ноге (а не только
- сбрасывать в ноль как GPIOC_BRR). С выводом данных в порт теперь
- точно всё. Настало время что-то из порта прочитать. Ну а читать мы будет
- состояние кнопки, которая у нас подключена к ноге PA0. Когда кнопка не
- нажата - на ножке PA0 присутствует логический ноль за счёт резистора
- номиналом 10 кОм который подтягивает этот вывод к земле. После
- замыкания контактов кнопки, слабенькая подтяжка к земле будет подавлена
- напряжением питания и на входе появится логическая единица. Сейчас мы
- попробуем написать программу которая читает состояние ножки PA0 и в
- зависимости от наличия логической единицы, зажигает или гасит
- светодиоды. Управлять состоянием светодиодов мы уже научились из
- предыдущего примера, осталось только разобраться как читать что-то из
- порта. Для чтения из порта А используется регистр GPIOA_IDR. В его
- внутреннем устройстве нет ничего особо сложного и поэтому я не буду
- рисовать тут картинку, а объясню всё парой слов: Первые 16 бит регистра
- соответствуют 16 ногам порта. Что приходит в порт - то и попадает в этот
- регистр. Если на всех ногах порта А будут присутствовать логические
- единицы, то и из регистра GPIOA_IDR мы прочитаем 0xFFFF. Естественно, не
- надо забывать настраивать порт как вход, хотя по умолчанию он настроен
- именно так как нам надо, просто сделаем это для понимания сути дела.
- После этого в бесконечном цикле мы считываем регистр GPIOA_IDR, зануляем
- в все биты кроме нулевого (кнопка ведь висит на PA</span><strong style="text-align: justify;">0</strong><span style="text-align: justify;">)
- и сравниваем результат с единицей. Если результат равен единице значит
- кто-то удерживает нажатой кнопку (и надо зажечь светодиоды), в противном
- случае (если 0) кнопка отпущена и светодиоды надо погасить. Может
- возникнуть здравый вопрос: Зачем занулять все остальные биты кроме
- нулевого? А дело тут вот в чем, все остальные ноги порта (как и PA0) так
- же настроены на вход без подтяжки. Это означает что в любой момент
- времени там может быть вообще всё что угодно, всё зависит от количества
- вокруг контроллера наводок и помех. Следовательно при нажатой кнопке из
- регистра </span><span style="text-align: justify;">GPIOA_IDR может прочитаться не только 0000 0000 0000 0001 но и например 0000 0000 0<strong>1</strong>0<strong>1</strong> 0001 а следовательно сравнивать такое число с единицей нельзя, однако после зануления остальных битов вполне можно. </span>Посмотрим на код реализующий всё сказанное выше: </p>
- <p><span style="text-align: justify;"></span></p><div style="overflow: hidden; display: block; height: auto; width: inherit;"><pre class="brush:cpp">#include <stm32f10x_rcc.h>
- int main(void) {
- //Включим тактирование порта С (со светодиодами) и порта А (с кнопкой)
- RCC->APB2ENR |= (RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOA );
- //Настроим ножки со светодиодами как выходы
- GPIOC->CRH |=0x33;
- GPIOC->CRH &= ~0xCC;
- //Настроим ногу PA0 как вход без подтяжки (подтягивающий резистор уже есть на плате)
- GPIOA->CRL |= 0x04;
- GPIOA->CRL &= ~0x11;
- while(1) { //Бесконечный цикл
- if ((GPIOA->IDR & 0x01)==0x01) { //Кнопка нажата?
- GPIOC->BSRR=(GPIO_BSRR_BS8|GPIO_BSRR_BS9); //Зажигаем светодиоды
- } else {
- GPIOC->BSRR=(GPIO_BSRR_BR8|GPIO_BSRR_BR9); //Гасим светодиоды
- }
- }
- }
- </pre></div><p></p>
- <p style="text-align: justify;"><span style="text-align: justify;">Код
- не особо сложный, но если вдруг появились вопросы, то они принимаются в
- комментариях. Напоследок хотелось бы в двух словах рассказать о еще
- одном регистре с непонятной областью практического применения - </span><span style="text-align: justify;">GPIOx_LCKR.
- Он служит для блокировки настроек порта. Это означает что настроив
- какую либо ножку порта на выход и установив соответствующий бит
- блокировки в этом регистре, мы не сможем сделать её входом (только после
- сброса контроллера).</span></p>
- <p style="text-align: justify;"><span style="text-align: justify;"><img style="text-align: justify; display: block; margin-left: auto; margin-right: auto;" src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/gpiox_lckr.png" alt="gpiox_lckr" width="650"></span></p>
- <p>Как видно из рисунка, кроме битов блокировки для каждой ноги порта,
- тут есть еще бит LCKK. Он используется когда мы хотим установить
- какой-либо бит блокировки. Алгоритм работы с этим регистром следующий:</p>
- <ol>
- <li>Устанавливаем нужные биты блокировки</li>
- <li>Записываем в LCKK единицу</li>
- <li>Записываем в LCKK ноль</li>
- <li>Записываем в LCKK единицу</li>
- <li>Читаем из LCKK ноль</li>
- <li>Читаем из LCKK единицу (опционально, только для того, чтоб убедиться что блокировка сработала)</li>
- </ol>
- <p>Всё, после этого переназначить настройки ног порта (соответствующие
- установленным битам блокировки) уже не получится. Если вы смогли найти
- практическое применение этой фичи - сообщить мне об этом пожалуйста :)</p> </div>
- </div>
- </div>
- </div>
- </div>
- <div id="col2">
- <div class="moduletable_menu">
-
- <h3 class="module-title">Разделы сайта</h3>
- <div class="res">
- <div class="module-content">
-
- <ul class="menu">
- <li class="item-101"><a href="http://easystm32.ru/">Главная страница</a></li><li class="item-108 current active"><a href="http://easystm32.ru/for-beginners">Для начинающих</a></li><li class="item-107"><a href="http://easystm32.ru/stm32vl-discovery">STM32VL Discovery</a></li><li class="item-147"><a href="http://easystm32.ru/stm32f4-discovery">STM32F4 Discovery</a></li><li class="item-109"><a href="http://easystm32.ru/tools">Инструменты</a></li><li class="item-110"><a href="http://easystm32.ru/interfaces">Интерфейсы</a></li><li class="item-111"><a href="http://easystm32.ru/technologies">Технологии</a></li><li class="item-112"><a href="http://easystm32.ru/useful-things">Полезности</a></li><li class="item-113"><a href="http://easystm32.ru/indication">Индикация</a></li><li class="item-114"><a href="http://easystm32.ru/power-supplies">Питание</a></li><li class="item-115"><a href="http://easystm32.ru/projects">Проекты</a></li><li class="item-116"><a href="http://easystm32.ru/sensors">Датчики</a></li><li class="item-117"><a href="http://easystm32.ru/debug">Отладка</a></li></ul>
- </div>
- </div><div class="modul"></div></div>
- <div class="moduletable">
-
- <h3 class="module-title">Форма входа</h3>
- <div class="res">
- <div class="module-content">
- <form action="/for-beginners" method="post" id="login-form">
- <fieldset class="userdata">
- <p id="form-login-username">
- <label for="modlgn-username">Логин</label>
- <input id="modlgn-username" name="username" class="inputbox" size="18" type="text">
- </p>
- <p id="form-login-password">
- <label for="modlgn-passwd">Пароль</label>
- <input id="modlgn-passwd" name="password" class="inputbox" size="18" type="password">
- </p>
- <p id="form-login-remember">
- <label for="modlgn-remember">Запомнить меня</label>
- <input id="modlgn-remember" name="remember" class="inputbox" value="yes" type="checkbox">
- </p>
- <input name="Submit" class="button" value="Войти" type="submit">
- <input name="option" value="com_users" type="hidden">
- <input name="task" value="user.login" type="hidden">
- <input name="return" value="aW5kZXgucGhwP29wdGlvbj1jb21fY29udGVudCZ2aWV3PWFydGljbGUmY2F0aWQ9MTAmaWQ9MTEmSXRlbWlkPTEwOA==" type="hidden">
- <input name="7e65820915caf822baa45130272018ad" value="1" type="hidden"> </fieldset>
- <ul>
- <li>
- <a href="http://easystm32.ru/component/users/?view=reset">
- Забыли пароль?</a>
- </li>
- <li>
- <a href="http://easystm32.ru/component/users/?view=remind">
- Забыли логин?</a>
- </li>
- </ul>
- </form>
- </div>
- </div><div class="modul"></div></div>
-
- </div>
- </div>
- </div>
- </div>
- <div id="footer">
-
- <div class="copy">
- Copyright © 2012 <a href="http://easystm32.ru/component/xmap/xml?option=com_xmap&view=xml&id=1">EasySTM32.</a> All Rights Reserved. Запрещено копирование материалов без активной ссылки на этот сайт.<br>
- Реклама: <script type="text/javascript">
- <!--
- var _acic={dataProvider:10};(function(){var e=document.createElement("script");e.type="text/javascript";e.async=true;e.src="//www.acint.net/aci.js";var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t)})()
- //-->
- </script> <a href="http://ekaterinburg.viberu.ru/banki/sberbank-rossii/ipoteka/" target="_blank">Ипотека Сбербанк</a> воспользуйтесь предложениями, которые разработали наши специалисты. . <a href="http://www.absolutss.ru/Products/videonabludenie/videoregistratori/DSSL/tek_865/" target="_blank">TRASSIR QuattroStation</a> </div>
- <!-- Yandex.Metrika counter -->
- <script type="text/javascript">
- (function (d, w, c) {
- (w[c] = w[c] || []).push(function() {
- try {
- w.yaCounter14614684 = new Ya.Metrika({id:14614684});
- } catch(e) {}
- });
-
- var n = d.getElementsByTagName("script")[0],
- s = d.createElement("script"),
- f = function () { n.parentNode.insertBefore(s, n); };
- s.type = "text/javascript";
- s.async = true;
- s.src = (d.location.protocol == "https:" ? "https:" : "http:") + "//mc.yandex.ru/metrika/watch.js";
- if (w.opera == "[object Opera]") {
- d.addEventListener("DOMContentLoaded", f);
- } else { f(); }
- })(document, window, "yandex_metrika_callbacks");
- </script>
- <noscript><div><img title="[yandex.ru]" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" style="position: absolute; left: -9999px; border: 1px solid rgb(255, 204, 204); background-repeat: no-repeat; background-position: center center; background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9gMFRANL5LXnioAAAJWSURBVDjLnZI/ixtXFMV/972ZNzPSrmTtalexlsWBGMfEYOzaVciXyKdIkW/hFKnS22WafIDUxk0g2AQSgm0csIPWK42ktaSRNPP+pRBK5SLOqS7cew7ccw4xxrPJ+8XdHx4+7AE8e3Cj++zLm71fvrqT8x+QAK35dJr2n/x89urTa+eDm/cS+eI2y3eT+Lx/bt8u1vNqfDH++teXdk/6ThAfUUBIgL9ku75z/8WL7LOlhXIGJ0Pyw75wMcnGv//xSQ2DH4ddu9k01dXWsWzcofhYaiiViLjiWi9UWQa1gzcjWF7hgfzzW5ydnXB62JLjg0PTLfJertNepnQSIA+gE4Cs03UuNYYQYP4e5jPogmSG9vA6rrjC+0AxN2i5Qk0DpXVJhCQB0EVRrzqdFgB1DZfvCDHixiV2NqO6LHHKIKnQMoaWbFBgIrQVgIXaDc+JCHgP5QRZr4jzGWFbo6yncRYviiiQKUhBRch3Lyix4bgPWsAkcDkmZAV2OiE0DaI1WoEShRKF3sWnmt01pFBnJydEpZDEwHSGt47lYsls43AIXjTWV9R1Qx0DGahqLyAhbqrj0/ib0nRzXNoyCo0Kkor2llV0eKOwdUMg4pSQA7JPQXvnJv1B+GlwOvrGlaXB6fV2lb5t6qOtike56DSJgYDGBQcOAsQAfueBMeHR48fhadb1j/58HWARdt6yBv7+/vpBe2o5OogxlcaKdt5aKCNsk309W0WxKQjmQ33/9mJVAdWHdmo/tNvtRZIkfCz+ZQwGg6rT6Zj/LTAajTbD4bD5WIF/AAseEisPFO8uAAAAAElFTkSuQmCC");" alt="" height="50" width="50"></div></noscript>
- <!-- /Yandex.Metrika counter -->
- <div id="dummy"></div>
- <div id="debug">
-
- </div>
- </div>
- </div>
- </div>
- </div>
- <script type="text/javascript" src="EasySTM32%20-%20%D0%9F%D0%BE%D1%80%D1%82%D1%8B%20%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D0%BA%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D0%BB%D0%B5%D1%80%D0%B0_files/jquery.js"></script>
- <script type="text/javascript">
- $(document).ready(function(){
-
- //When you click on a link with class of poplight and the href starts with a #
- $('a.poplight[href^=#]').click(function() {
- var popID = $(this).attr('rel'); //Get Popup Name
- var popURL = $(this).attr('href'); //Get Popup href to define size
-
- //Pull Query & Variables from href URL
- var param= popURL.substr(1);
- var data = "<iframe width=\"500\" height=\"438\" src=\"http://easystm32.ru/getreg.php" + param + "\"></iframe>";
- document.getElementById('popup_name').innerHTML=data;
- //Добавить кнопку "Закрыть" в наше окно, прописываете прямой путь к картинке кнопки
- $('#' + popID).fadeIn().css({ 'width': Number( 500 ) }).prepend('<a href="#" class="close"><img src="/templates/shoplab/images/close_pop.png" class="btn_close" title="Закрыть окно" alt="Закрыть" /></a>');
-
- //Определяет запас на выравнивание по центру (по вертикали по горизонтали)мы добавим 80px к высоте / ширине, значение полей вокруг содержимого (padding) и ширину границы устанавливаем в CSS
- var popMargTop = ($('#' + popID).height() + 80) / 2;
- var popMargLeft = ($('#' + popID).width() + 80) / 2;
-
- //Применяем отступы в всплывающем окне
- $('#' + popID).css({
- 'margin-top' : -popMargTop,
- 'margin-left' : -popMargLeft
- });
-
- //Фон слоя затемнения
- $('body').append('<div id="fade"></div>'); //Добавляем слой затемнения.
- $('#fade').css({'filter' : 'alpha(opacity=80)'}).fadeIn(); //Постепенное исчезание слоя - .css({'filter' : 'alpha(opacity=80)'}) используется для фиксации в IE, фильтр для устранения бага тупого IE
-
- return false;
- });
-
-
- //Закрыть всплывающее окно и слой затемнения
- $('a.close, #fade').live('click', function() { //При нажатии рядом, окно и слой затемнения закрываются
- $('#fade , .popup_block').fadeOut(function() {
- $('#fade, a.close').remove();
- }); //fade them both out
-
- return false;
- });
-
-
- });
- </script>
-
-
- </body></html>
|