<p>Начнем с теории. Интерфейс ввода/вывода (далее GPIO) является важной составляющей МК, без которой нам попросту не обойтись. Любая подключаемая внешняя периферия не обходится без настройки GPIO. Поэтому необходимо четко представлять работу GPIO и уметь правильно его настроить. Понимание интерфейса, не раз спасет ваше драгоценное время.</p>
<p>GPIO представляет собой токопроводящие выводы (контакты) МК сгруппированные по портам и имеющие возможность конфигурации на вход или выход.</p>
<p>Рассмотрим как GPIO устроен в STM32.</p>
<a class="highslide" href="http://stm32dev.ru/uploads/posts/2017-06/1498043633_gpio1.png"><img class="fr-dib fr-draggable" src="/uploads/posts/2017-06/medium/1498043633_gpio1.png" alt=""></a>
<p>Казалось бы что там сложного, всего лишь ввод и вывод, а нет, не все так просто.</p>
<p>Pin(вывод МК) может работать в логическом режиме и в аналоговом.</p>
<p>В логическом режиме значение 0 или 1 принимается в зависимости от напряжения. Важно отметить, что STM32 работает с напряжением 3.3В, но многие модели толерантны к 5В.</p>
<a class="highslide" href="http://stm32dev.ru/uploads/posts/2017-06/1498046523_gpio2.png"><img class="fr-dib fr-draggable" src="/uploads/posts/2017-06/thumbs/1498046523_gpio2.png" alt=""></a>
<p>Для входа, преобразователем уровней напряжения служит <b>TTL Shmitt trigger</b>. Для выхода реализована схема на транзисторах. Т.е. при подаче логической единицы открывается транзистор <b>P-MOS</b> и на выход поступает питание от Vdd(3.3В), при 0 открывается <b>N-MOS</b>, соответственно на выходе устанавливается 0В.</p>
<p>В аналоговом режиме сигнал от GPIO поступает на вход аналого-цифрового преобразователя(<b>ADC</b>).</p>
<p>Данные о состоянии порта, хранятся в регистрах <b>Output data register</b> и <b>Input data register</b>. Регистры являются 16 разрядными, т.е. хранят информацию о 16 выводах (например PA0-PA15). При этом <b>Input data register</b> можно использовать только для чтения, а <b>Output data register</b>, как для записи, так и для чтения. Так как информация хранится в регистрах, можно производить такие же операции, как и с другими регистрами, например операции сдвига. Что в свою очередь не потребует создание промежуточных переменных и сократит количество операций.</p>
<p>По мимо основных режимов работы, GPIO так же имеет режим <b>Alternate Function</b>(Режим альтернативной функции). Данный режим необходим МК для передачи управления выводом внутреннему периферийному устройству. В таком случае, после соответствующей настройки, мы можем не заботиться о состоянии вывода, всю ответственность берет на себя периферийное устройство. Стоит добавить что периферийные устройства могут работать только со строго фиксированными выводами. Например <b>UART1</b> в STM32F107VC может с выводами <b>PA9/PA10</b> или <b>PB6/PB7</b>. От сюда всплывает термин <b>Remapping</b>, так как появляется необходимость выбора варианта подключения. Для каждого периферийного устройства имеется значение по умолчанию(<b>XXX_REMAP</b> = 0), например для UART1, <b>USART1_REMAP</b> = 0 соответствует выводам <b>PA9/PA10</b>. Может возникнуть вопрос, зачем это нужно? Для ответа на данный вопрос, представим ситуацию. Собрали мы довольно сложную схему, справа от МК поставили микросхему RS232(Uart to RS232), подключив ее к выводам <b>PA9/PA10</b>. И так получилось, что с правой стороны что-то не помещается. Тогда мы можем разместить микросхему сверху от МК и подключить ее к выводам <b>PB6/PB7</b>. Все поместилось и мы довольны работой.</p>
<p>Не рассмотренными из выше приведенной схемы остались только два резистора в секции <b>Input driver</b>. Резисторы одной стороной подключены непосредственно к выводу, а другой, через включатель идут к <b>Vdd</b>(3.3В) и <b>Vss</b>(0В или GND). Включатели управляются программно. Стоит отметить, что оба резистора не могут быть включены в цепь одновременно. Предназначены они для подтяжки вывода к питанию или к нулю. Необходимость в подтяжки линии связана с уменьшением помех на линии, либо с требованием, периферийного устройства (некоторые устройства требую высокого уровня на линии).</p>
<p>Последними остались диоды <b>Protection diode</b>. Не сложно догадаться, что они служат для защиты входа от превышения напряжения. Соответственно положительное превышение уйдет вниз на <b>Vss</b>(Gnd), а отрицательное вверх на <b>Vdd</b>.</p>
<p>С теорией закончили, пора переходить к практике.</p>
<p>Создадим проект для STM32F107VC (макетная плата Open107V) в CubeMX. Рассмотрим схему к макетной плате.</p>
<a class="highslide" href="http://stm32dev.ru/uploads/posts/2017-06/1498126620_gpio.png"><img class="fr-dib fr-draggable" src="/uploads/posts/2017-06/medium/1498126620_gpio.png" alt=""></a>
<p>У нас имеются 4 светодиода на выводах <b>PB0, PB1, PB14, PB15</b>, кнопка User Key на выводе <b>PC13</b>, Joystick, с которого мы возьмем только кнопку <b>JSTICK_K5</b>(центральное нажатие) на выводе <b>PC9</b> и <b>USART1</b>, в котором TX заведен на <b>PB6</b>, а RX на <b>PB7</b>. Также имеется внешний кварц с частотой 25 МГц.</p>
<p>В CubeMX выберем внешний источник тактирования: <b>RCC-&gt;High Speed Clock (HSE)-&gt;Crystal/Ceramic Resonator</b>.</p>
<p>Ниже выберем <b>USART1</b> и выставим <b>Mode-&gt;Asynchronous</b>. Обратите внимание, CubeMX, как и положена, по умолчанию для <b>USART1</b> назначила выводы <b>PA9/PA10</b>, что не соответствует нашей схеме. Для смены нажимаем на выводе <b>PB6</b> левой кнопкой мыши и выбираем <b>USART1_TX</b>, второй вывод установится автоматически.</p>
<p>Назначим выводы <b>Led1-Led4</b>. Для этого левой кнопкой мыши нажимаем на <b>PB0</b> и выбираем <b>GPIO_Output</b>, то же самое для выводов <b>PB1</b>, <b>PB14</b> и <b>PB15</b>. Так же еще раз пройдемся по этим выводам, но нажмем правую кнопку мыши и выберем <b>Enter User Label</b>, в появившемся окне введем имя светодиода <b>Led1-Led4</b> соответственно.</p>
<p>Назначим вывод для <b>User_key</b>. Для этого левой кнопкой мыши нажимаем на <b>PС13</b> и выбираем <b>GPIO_Input</b>. Так же назначим Label <b>User_key</b>.</p>
<p>Назначим вывод для <b>JSTICK_K5</b>. Так как мы уже изучили прерывания, вместо обычного входа (<b>GPIO_Input</b>) выберем режим <b>GPIO_EXTI</b>. Для этого левой кнопкой мыши нажимаем на <b>PС9</b>, выбираем <b>GPIO_EXTI9</b> и назначим Label <b>JSTICK_K5</b>.</p>
<a class="highslide" href="http://stm32dev.ru/uploads/posts/2017-06/1498127100_gpio3.png"><img class="fr-dib fr-draggable" src="/uploads/posts/2017-06/medium/1498127100_gpio3.png" alt=""></a>
<p>Перейдем во вкладку <b>Clock Configuration</b> для настройки тактирования. <b>Input frequency</b> меняем на 25 МГц, а <b>HCLK</b> (MHz) на 72 МГц. После нажатия Enter, CubeMX подберет необходимы коэффициенты на <b>PLL</b>. Остается только убедится, что мы можем проследовать от внешнего кварца, до <b>HCLK</b>.</p>
<a class="highslide" href="http://stm32dev.ru/uploads/posts/2017-06/1498124933_gpio4.png"><img class="fr-dib fr-draggable" src="/uploads/posts/2017-06/medium/1498124933_gpio4.png" alt=""></a>
<p>Перейдем во вкладку <b>Configuration</b>. В разделе <b>System</b> выберем <b>GPIO</b>. Здесь мы можем выбрать дополнительные настройки для выводов МК. Начнем по порядку.</p>
<p>Светодиоды, согласно схемы подключены одной стороной к МК, другой к <b>GND</b>, значит включать их будем высоким уровнем на выводе, а при инициализации на выводе необходим низкий уровень. Соответственно <b>GPIO output level</b> для них должен быть <b>Low</b>. Обращаю на это внимание, так как существует множество периферии, которая включается низким уровнем.</p>
<p><b>User_key</b> подключен к <b>GND</b>, при нажатии на кнопку на выводе МК установится низкий уровень, значит в обычном состоянии на выводе должен быть высокий уровень. Для этого нам необходимо подтянуть вывод к питанию (к верху). Выберем в <b>GPIO Pull-up/Pull-down -&gt; Pull-up</b>.</p>
<p><b>JSTICK_K5</b> так же подключен к <b>GND</b>, соответственно вывод, таким же методом, необходимо подтянуть к питанию. Так как на данном выводе у нас будет настроено прерывание, необходимо выбрать по какому фронту оно будет срабатывать. Под фронтом подразумевается смена сигнала с высокого на низкий или наоборот. В нашем случае из-за подтяжки к питанию изначально на выводе высокий уровень, а после нажатия на кнопку, уровень станет низким. Т.е. сигнал изменится от высокого к низкому уровню, что соответствует спадающему фронту (<b>Falling edge</b>). Но мы будем реагировать не на нажатие, а на отпуск кнопки (<b>Rising edge</b>). Поэтому в <b>GPIO mode</b> выбираем <b>External Interrupt Mode with Rising edge trigger detection</b>.</p>
<a class="highslide" href="http://stm32dev.ru/uploads/posts/2017-06/1498130588_gpio5.png"><img class="fr-dib fr-draggable" src="/uploads/posts/2017-06/medium/1498130588_gpio5.png" alt=""></a>
<p>Нажимаем Ok и в разделе <b>System</b> выберем <b>NVIC</b> (настройка прерываний). Здесь нам необходимо только поставить галачку на <b>EXTI line[9:5] interrupts</b>. Тем самым мы включили прерывание от <b>JSTICK_K5</b>.</p>
<a class="highslide" href="http://stm32dev.ru/uploads/posts/2017-06/1498130640_gpio6.png"><img class="fr-dib fr-draggable" src="/uploads/posts/2017-06/medium/1498130640_gpio6.png" alt=""></a>
<p>Работа с CubeMX закончена. Генерируем код и смотрим что получилось.</p>
<p>main.c</p><pre class="language-markup"><code>static void MX_GPIO_Init(void)
{

&nbsp; GPIO_InitTypeDef GPIO_InitStruct;

&nbsp; /* Включаем тактирование порта PB и PC */
&nbsp; __HAL_RCC_GPIOC_CLK_ENABLE();
&nbsp; __HAL_RCC_GPIOB_CLK_ENABLE();

&nbsp; /*Configure GPIO pin : User_key_Pin */
&nbsp; GPIO_InitStruct.Pin = User_key_Pin;
&nbsp; GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
&nbsp; GPIO_InitStruct.Pull = GPIO_PULLUP;
&nbsp; HAL_GPIO_Init(User_key_GPIO_Port, &amp;GPIO_InitStruct);

&nbsp; /*Configure GPIO pins : Led1_Pin Led2_Pin Led3_Pin Led4_Pin */
&nbsp; GPIO_InitStruct.Pin = Led1_Pin|Led2_Pin|Led3_Pin|Led4_Pin;
&nbsp; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
&nbsp; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
&nbsp; HAL_GPIO_Init(GPIOB, &amp;GPIO_InitStruct);

&nbsp; /*Configure GPIO pin : JSTICK_K5_Pin */
&nbsp; GPIO_InitStruct.Pin = JSTICK_K5_Pin;
&nbsp; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
&nbsp; GPIO_InitStruct.Pull = GPIO_PULLUP;
&nbsp; HAL_GPIO_Init(JSTICK_K5_GPIO_Port, &amp;GPIO_InitStruct);

&nbsp; /*Configure GPIO pin Output Level */
&nbsp; HAL_GPIO_WritePin(GPIOB, Led1_Pin|Led2_Pin|Led3_Pin|Led4_Pin, GPIO_PIN_RESET);

&nbsp; /* EXTI interrupt init*/
&nbsp; HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0);
&nbsp; HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);

}</code></pre>Как видим CubeMX вместо значений выводов подставил наши Labels. Их значения определены в файле mxconstants.h
<br><pre class="language-markup"><code>#define User_key_Pin GPIO_PIN_13
#define User_key_GPIO_Port GPIOC
#define Led1_Pin GPIO_PIN_0
#define Led1_GPIO_Port GPIOB
#define Led2_Pin GPIO_PIN_1
#define Led2_GPIO_Port GPIOB
#define Led3_Pin GPIO_PIN_14
#define Led3_GPIO_Port GPIOB
#define Led4_Pin GPIO_PIN_15
#define Led4_GPIO_Port GPIOB
#define JSTICK_K5_Pin GPIO_PIN_9
#define JSTICK_K5_GPIO_Port GPIOC</code></pre>Настройки портов периферийных устройств расположены в файле stm32f1xx_hal_msp.c
<br><pre class="language-markup"><code>void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{

&nbsp; GPIO_InitTypeDef GPIO_InitStruct;
&nbsp; if(huart-&gt;Instance==USART1)
&nbsp; {
&nbsp; /* USER CODE BEGIN USART1_MspInit 0 */

&nbsp; /* USER CODE END USART1_MspInit 0 */
&nbsp; &nbsp; /* Peripheral clock enable */
&nbsp; &nbsp; __HAL_RCC_USART1_CLK_ENABLE();
&nbsp; 
&nbsp; &nbsp; /**USART1 GPIO Configuration &nbsp; &nbsp;
&nbsp; &nbsp; PB6 &nbsp; &nbsp; ------&gt; USART1_TX
&nbsp; &nbsp; PB7 &nbsp; &nbsp; ------&gt; USART1_RX 
&nbsp; &nbsp; */
&nbsp; &nbsp; GPIO_InitStruct.Pin = GPIO_PIN_6;
&nbsp; &nbsp; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
&nbsp; &nbsp; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
&nbsp; &nbsp; HAL_GPIO_Init(GPIOB, &amp;GPIO_InitStruct);

&nbsp; &nbsp; GPIO_InitStruct.Pin = GPIO_PIN_7;
&nbsp; &nbsp; GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
&nbsp; &nbsp; GPIO_InitStruct.Pull = GPIO_NOPULL;
&nbsp; &nbsp; HAL_GPIO_Init(GPIOB, &amp;GPIO_InitStruct);

&nbsp; &nbsp; __HAL_AFIO_REMAP_USART1_ENABLE();

&nbsp; /* USER CODE BEGIN USART1_MspInit 1 */

&nbsp; /* USER CODE END USART1_MspInit 1 */
&nbsp; }

}</code></pre>
<p>Рассказывать о назначении функций инициализации и о структурах, не вижу смысла, т.к. считаю их интуитивно понятными. Если вы сомневаетесь во входящих аргументах функции, вы можете прочитать описание функции в соответствующем хидере нажав правой кнопкой по функции и выбрав пункт <b>Go To Reference To...</b></p>
<p>Дополним код для функциональности.</p><pre class="language-markup"><code>/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#include &lt;stdbool.h&gt;
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
volatile bool pressed_JSTICK_K5;
uint8_t ledPos;
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void Error_Handler(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
/* Private function prototypes -----------------------------------------------*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
&nbsp; &nbsp; if (GPIO_Pin == JSTICK_K5_Pin)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; if (!pressed_JSTICK_K5) 
&nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HAL_UART_Transmit(&amp;huart1, (uint8_t*)"Working Toggle\n\r", 16, 100);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pressed_JSTICK_K5 = true;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
}
//============================================================================//
void Leds_Snake(bool direct)//мигаем светодиодами в заданном направлении
{
&nbsp; &nbsp; if (direct)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; if (ledPos &gt; 0) ledPos--;
&nbsp; &nbsp; &nbsp; &nbsp; else ledPos = 3;
&nbsp; &nbsp; }
&nbsp; &nbsp; else
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; if (ledPos &lt; 3) ledPos++;
&nbsp; &nbsp; &nbsp; &nbsp; else ledPos = 0;
&nbsp; &nbsp; }
&nbsp; &nbsp; 
&nbsp; &nbsp; switch (ledPos)
&nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; case 0: HAL_GPIO_TogglePin(GPIOB, Led1_Pin); break;
&nbsp; &nbsp; &nbsp; &nbsp; case 1: HAL_GPIO_TogglePin(GPIOB, Led2_Pin); break;
&nbsp; &nbsp; &nbsp; &nbsp; case 2: HAL_GPIO_TogglePin(GPIOB, Led3_Pin); break;
&nbsp; &nbsp; &nbsp; &nbsp; case 3: HAL_GPIO_TogglePin(GPIOB, Led4_Pin); break;
&nbsp; &nbsp; }
}
//============================================================================//
int main(void)
{
&nbsp; &nbsp; bool working = true;
&nbsp; &nbsp; bool direct = false;
&nbsp; &nbsp; bool pressed_User_key = false;
&nbsp; &nbsp; uint8_t timerLeds = 20;

&nbsp; /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
&nbsp; HAL_Init();

&nbsp; /* Configure the system clock */
&nbsp; SystemClock_Config();

&nbsp; /* Initialize all configured peripherals */
&nbsp; MX_GPIO_Init();
&nbsp; MX_USART1_UART_Init();

&nbsp; &nbsp; ledPos = 4;
&nbsp; &nbsp; HAL_UART_Transmit(&amp;huart1, (uint8_t*)"Start Ok\n\r", 10, 100);

&nbsp; while (1)
&nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; //Отслеживаем нажатие кнопки User_key
&nbsp; &nbsp; &nbsp; &nbsp; if (HAL_GPIO_ReadPin(User_key_GPIO_Port, User_key_Pin) == GPIO_PIN_RESET)
&nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!pressed_User_key)
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pressed_User_key = true;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (direct) 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HAL_UART_Transmit(&amp;huart1, (uint8_t*)"Direction Right\n\r", 17, 100);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; direct = false;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ledPos = 4;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else 
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HAL_UART_Transmit(&amp;huart1, (uint8_t*)"Direction Left\n\r", 16, 100);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; direct = true;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ledPos = 0;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; HAL_GPIO_WritePin(GPIOB, Led1_Pin|Led2_Pin|Led3_Pin|Led4_Pin, GPIO_PIN_RESET);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; else pressed_User_key = false;
&nbsp; &nbsp; &nbsp; &nbsp; //
&nbsp; &nbsp; &nbsp; &nbsp; if (pressed_JSTICK_K5)
&nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; working = !working;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pressed_JSTICK_K5 = false;
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; //
&nbsp; &nbsp; &nbsp; &nbsp; if (working)
&nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (timerLeds) timerLeds--;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; timerLeds = 20;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Leds_Snake(direct);
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; HAL_Delay(10);
&nbsp; }
}
//============================================================================//</code></pre>
<p>В программе мы мигаем светодиодами в заданном направлении и с возможностью остановки работы. Направление меняется с помощью кнопки <b>User_key</b>. Остановка или запуск осуществляется с помощью кнопки <b>JSTICK_K5</b>. Значение направления хранится в переменной direct. , а состояния работы в working. Нажатие кнопки <b>User_key</b> обрабатывается в основном цикле с периодичностью 10 мс. Ее значение считывается с помощью функции <b>HAL_GPIO_ReadPin</b>.</p>
<p>Значение переменной working инвертируется так же в основном цикле при <b>pressed_JSTICK_K5</b> = true. Переменная <b>pressed_JSTICK_K5</b> является глобальной и меняет свое значение в обработчике прерываний <b>HAL_GPIO_EXTI_Callback</b>. Такая конструкция обеспечивает снижение реакции на "дребезг контакта". Под дребезгом контакта подразумевается множество скачкообразных изменений сигнала в короткое время, что ведет к нескольким срабатываниям прерывания. Это связано с несовершенством работы контактной группы. Для полного исключения дребезга необходимо применять специализированные алгоритмы.</p>
<p>В основном цикле при <b>working</b> = true, производится декремент <b>timerLeds</b>. При достижении 0, сбрасываем счетчик на 20 и выполняем функцию <b>Leds_Snake</b>. Это обеспечивает выполнение функции <b>Leds_Snake</b> с периодичностью 200 мс.</p>
<p>Функция <b>Leds_Snake</b> в зависимости от входящего параметра направления движения (bool <b>direct</b>), выполняет смену состояния выводов в соответствующем направлении светодиодов посредством функции <b>HAL_GPIO_TogglePin</b>.</p>
<p>Помимо работы со светодиодами, в <b>USART1</b> отправляются сообщения о старте программы и о смене режимов с помощью функции <b>HAL_UART_Transmit</b>.</p>
<p>Проект закончен, компилируем и зашиваем в МК.</p>
<br>
<p>Архив с проектом &nbsp;- <a href="https://yadi.sk/d/Uq_6GVBT3KPRBs" target="_blank">ссылка на скачивание</a>.</p>
<p>Схема макетной платы Open107V - <a href="https://yadi.sk/i/RqVVYCCd3KPQmp" target="_blank">ссылка на скачивание</a>.</p>
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.


© Copyright 2017. Все права защищены.
Яндекс.Метрика