Stm8. описание gpio и библиотека spl

STM8 + SDCC + SPL: стандартная периферийная библиотека

разделы: STM8 , дата: 9 июля 2016г

После знакомства с внешними прерываниями, я почувствовал, что иду по неверному пути, в изучении STM8.

Я понял, что есть достаточное количество весьма не очевидных вещей, как например очистка EXTI_SRx записью единицы.

И даже при наличии полной оригинальной документации, я не чувствую уверенности в том, что начну с ходу писать достаточно хороший код для работы с тем или иным перифирийным модулем.

Это нерадостные мысли посетили меня после ознакомления с системой таймеров в STM8. Она довольно мощная, на мой взгляд. И тут я вспомнил про стандартную периферийную библиотеку (SPL), о которой упоминал еще в первом посте про STM8, почти год назад. Там весь код для работы с периферией уже написан, проверен и отлажен.

Короче говоря, я решил переписать/адаптировать ее под SDCC в процессе своего изучения STM8. Начать решил с модуля GPIO, и дальше добавлять модуль за модулем.

Напомню, что SPL для STM8S и для STM8L это разные библиотеки, синтаксис у них различается, хотя написаны они в одном стиле.

Итак, GPIO.

Библиотеки состоят из главного заголовочного файла stm8s.h и stm8l15x.h, где приписаны адреса регистров, основные структуры и константы.

На этом, начальном, этапе stm8s.h у меня получился довольно скромным:

#ifndef __STM8S_H
#define __STM8S_H typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t; #define __IO volatile typedef enum {FALSE = 0, TRUE = !FALSE} bool; typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus, BitStatus, BitAction; typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
#define IS_FUNCTIONALSTATE_OK(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) typedef struct GPIO_struct
{ __IO uint8_t ODR; __IO uint8_t IDR; __IO uint8_t DDR; __IO uint8_t CR1; 1 __IO uint8_t CR2; 2
}
GPIO_TypeDef; #define GPIO_ODR_RESET_VALUE ((uint8_t)0x00)
#define GPIO_DDR_RESET_VALUE ((uint8_t)0x00)
#define GPIO_CR1_RESET_VALUE ((uint8_t)0x00)
#define GPIO_CR2_RESET_VALUE ((uint8_t)0x00) #define GPIOA_BaseAddress 0x5000
#define GPIOB_BaseAddress 0x5005
#define GPIOC_BaseAddress 0x500A
#define GPIOD_BaseAddress 0x500F
#define GPIOE_BaseAddress 0x5014
#define GPIOF_BaseAddress 0x5019
#define GPIOG_BaseAddress 0x501E
#define GPIOH_BaseAddress 0x5023
#define GPIOI_BaseAddress 0x5028 #define GPIOA ((GPIO_TypeDef *) GPIOA_BaseAddress) #define GPIOB ((GPIO_TypeDef *) GPIOB_BaseAddress) #define GPIOC ((GPIO_TypeDef *) GPIOC_BaseAddress) #define GPIOD ((GPIO_TypeDef *) GPIOD_BaseAddress) #define GPIOE ((GPIO_TypeDef *) GPIOE_BaseAddress) #define GPIOF ((GPIO_TypeDef *) GPIOF_BaseAddress) #if defined(STM8S207) || defined (STM8S007) || defined(STM8S208) || defined(STM8S105) ||
defined(STM8S005) || defined (STM8AF52Ax) || defined (STM8AF62Ax) || defined (STM8AF626x)
#define GPIOG ((GPIO_TypeDef *) GPIOG_BaseAddress)
#endif #if defined(STM8S207) || defined (STM8S007) || defined(STM8S208) || defined (STM8AF52Ax) ||
defined (STM8AF62Ax)
#define GPIOH ((GPIO_TypeDef *) GPIOH_BaseAddress)
#define GPIOI ((GPIO_TypeDef *) GPIOI_BaseAddress)
#endif #endif

Модуль GPIO удалось перенести практически без изменений. Он состоит из заголовочного файла stm8s_gpio.h:

#ifndef __STM8S_GPIO_H
#define __STM8S_GPIO_H #include “stm8s.h” typedef enum
{ GPIO_MODE_IN_FL_NO_IT = (uint8_t)0x00, GPIO_MODE_IN_PU_NO_IT = (uint8_t)0x40, GPIO_MODE_IN_FL_IT = (uint8_t)0x20, GPIO_MODE_IN_PU_IT = (uint8_t)0x60, GPIO_MODE_OUT_OD_LOW_FAST = (uint8_t)0xA0, GPIO_MODE_OUT_PP_LOW_FAST = (uint8_t)0xE0, GPIO_MODE_OUT_OD_LOW_SLOW = (uint8_t)0x80, GPIO_MODE_OUT_PP_LOW_SLOW = (uint8_t)0xC0, GPIO_MODE_OUT_OD_HIZ_FAST = (uint8_t)0xB0, GPIO_MODE_OUT_PP_HIGH_FAST = (uint8_t)0xF0, GPIO_MODE_OUT_OD_HIZ_SLOW = (uint8_t)0x90, GPIO_MODE_OUT_PP_HIGH_SLOW = (uint8_t)0xD0 }GPIO_Mode_TypeDef; typedef enum
{ GPIO_PIN_0 = ((uint8_t)0x01), 0 GPIO_PIN_1 = ((uint8_t)0x02), 1 GPIO_PIN_2 = ((uint8_t)0x04), 2 GPIO_PIN_3 = ((uint8_t)0x08), 3 GPIO_PIN_4 = ((uint8_t)0x10), 4 GPIO_PIN_5 = ((uint8_t)0x20), 5 GPIO_PIN_6 = ((uint8_t)0x40), 6 GPIO_PIN_7 = ((uint8_t)0x80), 7 GPIO_PIN_LNIB = ((uint8_t)0x0F), GPIO_PIN_HNIB = ((uint8_t)0xF0), GPIO_PIN_ALL = ((uint8_t)0xFF) }GPIO_Pin_TypeDef; extern void GPIO_DeInit(GPIO_TypeDef* GPIOx);
extern void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, GPIO_Mode_TypeDef GPIO_Mode);
extern void GPIO_Write(GPIO_TypeDef* GPIOx, uint8_t PortVal); extern void GPIO_WriteHigh(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins);
extern void GPIO_WriteLow(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins);
extern void GPIO_WriteReverse(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins); uint8_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
uint8_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
BitStatus GPIO_ReadInputPin(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin);
void GPIO_ExternalPullUpConfig(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, FunctionalState NewState); #endif

и Си-файла c реализацей объявленных функций:

#include “stm8s.h”
#include “stm8s_gpio.h” void GPIO_DeInit(GPIO_TypeDef* GPIOx)
{ GPIOx->ODR = GPIO_ODR_RESET_VALUE; GPIOx->DDR = GPIO_DDR_RESET_VALUE; GPIOx->CR1 = GPIO_CR1_RESET_VALUE; 1 GPIOx->CR2 = GPIO_CR2_RESET_VALUE; 2
} void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, GPIO_Mode_TypeDef GPIO_Mode)
{ GPIOx->CR2 &= (uint8_t)(~(GPIO_Pin)); if ((((uint8_t)(GPIO_Mode)) & (uint8_t)0x80) != (uint8_t)0x00) { if ((((uint8_t)(GPIO_Mode)) & (uint8_t)0x10) != (uint8_t)0x00) { GPIOx->ODR |= (uint8_t)GPIO_Pin; } else { GPIOx->ODR &= (uint8_t)(~(GPIO_Pin)); } GPIOx->DDR |= (uint8_t)GPIO_Pin; } else { GPIOx->DDR &= (uint8_t)(~(GPIO_Pin)); } if ((((uint8_t)(GPIO_Mode)) & (uint8_t)0x40) != (uint8_t)0x00) { GPIOx->CR1 |= (uint8_t)GPIO_Pin; } else { GPIOx->CR1 &= (uint8_t)(~(GPIO_Pin)); } if ((((uint8_t)(GPIO_Mode)) & (uint8_t)0x20) != (uint8_t)0x00) { GPIOx->CR2 |= (uint8_t)GPIO_Pin; } else { GPIOx->CR2 &= (uint8_t)(~(GPIO_Pin)); }
} void GPIO_Write(GPIO_TypeDef* GPIOx, uint8_t PortVal)
{ GPIOx->ODR = PortVal;
} void GPIO_WriteHigh(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins)
{ GPIOx->ODR |= (uint8_t)PortPins;
} void GPIO_WriteLow(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins)
{ GPIOx->ODR &= (uint8_t)(~PortPins);
} void GPIO_WriteReverse(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef PortPins)
{ GPIOx->ODR ^= (uint8_t)PortPins;
} uint8_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx)
{ return ((uint8_t)GPIOx->ODR);
} uint8_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx)
{ return ((uint8_t)GPIOx->IDR);
} BitStatus GPIO_ReadInputPin(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin)
{ return ((BitStatus)(GPIOx->IDR & (uint8_t)GPIO_Pin));
} void GPIO_ExternalPullUpConfig(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, FunctionalState NewState)
{ if (NewState != DISABLE) { GPIOx->CR1 |= (uint8_t)GPIO_Pin; } else { GPIOx->CR1 &= (uint8_t)(~(GPIO_Pin)); }
}

Здесь я лишь закоментировал метафизику: “assert_param”, а все остальное перенеслось без изменения.

В архиве библиотеки есть пример Blink написанный с помощью SPL. Я пошел немного дальше и переписал программу индикации нажатой кнопки на основе опроса порта(Polling):

#include “stm8s.h”
#include “stm8s_gpio.h” #define LED_PORT GPIOB
#define LED GPIO_PIN_5 #define BTN_LED_PORT GPIOC
#define BTN_LED GPIO_PIN_4 #define BTN_PORT GPIOD
#define BTN GPIO_PIN_2 static void delay(uint32_t t)
{ while(t–);
} uint8_t i;
int main( void )
{ GPIO_DeInit(LED_PORT); GPIO_Init(LED_PORT, LED, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_DeInit(BTN_LED_PORT); GPIO_Init(BTN_LED_PORT, BTN_LED, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_DeInit(BTN_PORT); GPIO_Init(BTN_PORT, BTN, GPIO_MODE_IN_FL_NO_IT); i=0; for(;;) { if(GPIO_ReadInputPin(BTN_PORT, BTN)) GPIO_WriteHigh(BTN_LED_PORT, BTN_LED); else GPIO_WriteLow(BTN_LED_PORT, BTN_LED); delay(1000); i++; if (i > 50) { GPIO_WriteReverse(LED_PORT, LED); i=0; } }
}
структура проекта вышла какой-то такой:
.
├── examples
│   ├── blink
│   │   ├── Makefile
│   │   └── main.c
│   └── button
│   ├── Makefile
│   └── main.c
├── hex
│   ├── blink.ihx
│   └── button.ihx
└── libs ├── stm8s.h ├── stm8s_gpio.c └── stm8s_gpio.h 5 directories, 9 files

Makefile

MCU=stm8
DEVICE=stm8s103
FLASHER=stlinkv2
CFLAGS=-I ../../libs -DSTM8S103 -c
CC=sdcc
LIB=stm8s_gpio.rel
OBJ=main.rel
TARGET=button .PHONY: all clean %.rel: %.c
$(CC) -m$(MCU) $(CFLAGS) $(LDFLAGS) $

Источник: http://www.count-zero.ru/2016/stm8_sdcc_spl/

8L-Курс, Часть 2 – GPIO

← Часть 1 — Hello светодиод! Содержание Часть 3 — Прерывания → В прошлой части мы запустили мигалку светодиодом. Теперь пришла пора разобраться с тем, как она работает и как устроен модуль GPIO в STM8.

Железо
Порты у STM8 обозначаются так-же как и у AVR — буквой. В нашей мигалке использовался порт D.

Каждый порт состоит из 8 пинов, что тоже напоминает AVR, да и вообще любые восьмибитные МК. Впрочем, на корпусах с небольшим количеством выводов, некоторые порты обрезаны и половины пинов нету. В МК на модуле для PB2 именно такая фигня:
Зато вся периферия (входы АЦП, входы/выходы таймеров) осталась на тех-же ножках, что и в более крупных корпусах.

А значит, можно без проблем переносить программы с одного МК на другой (к примеру прошивка для дискавери будет нормально работать и на модуле). Несколько выводов заняты под питание. На картинке их всего два (Vss1 и Vdd1), но в многоногих корпусах бывает несколько пар. Тогда подключать надо их все, не забывая ни одной пары. Иначе потом можно получить странные глюки в работе МК.

Один вывод занят под сигнал сброса — NRST. Причем его можно программно перевести в обычный режим и он станет (почти) нормальным пином GPIO под названием A1. «Почти» — т.к. на него нельзя повесить прерывание, и нельзя отключить подтягивающий резистор. Еще один вывод занят под питание для встроенного LCD-контроллера. Если LCD не используется, то этот пин можно не трогать.

В итоге, из 32 выводов у нас остается 28 (или 29 если выключить сброс) под GPIO. Вот о них и будет рассказ.

Электрика

На картинке с распиновкой, что висит чуть выше, указаны только названия выводов, без лишних подробностей. Все подробности собраны в таблице ниже («Medium density STM8L15x pin description», в даташите на МК). Для каждого вывода там указано несколько параметров.

I/O level — обозначает максимальное напряжение, которое можно подавать на пин. TT — значит, что пин спокойно выдержит напряжение в 3.6V (не зависимо от напряжения питания МК). А FT означает, что и 5V ему не страшны. Правда FT-пинов всего два — это C0 и C1, которые используются для работы с шиной I2C.

Если в этой колонке ничего не написано, значит на вывод нельзя подавать напряжение выше чем напряжение питания МК.

Floating Input — показывает, может ли пин работать как вход без подтягивающего резистора (A1 — на котором NRST, не может — там подтяжка включена всегда), а wpu (weak pull-up) — есть ли на этом пине подтягивающий резистор (на пинах C1 и C0 его нет). Жирным тут выделен тот режим, в котором пин будет находится при старте МК — почти для всех это вход без подтяжки. Номинал подтянивающего резистора около 40кОм, для всех пинов (в том числе и NRST).

Не все пины могут отдавать одинаковый ток, когда настроены на выход. Те, что могут отдать до 20мА, обозначены SH (в графе High sink/source), а «слабые» остались без этой отметки.

И это опять C0 и C1 — которые могут пропустить через себя ток всего в 5мА. А еще есть пин A0, который кроме отладки через SWIM, предназначен для подключения ИК светодиода или похожей мощной нагрузки и может «втянуть» ток до 80mA (т.е.

такой он может пропустить через себя, когда выдает низкий уровень).

Колонки OD (open drain) и PP (push-pull) показывают может ли вывод работать в режиме открытого коллектора (или «открытого стока»), когда вместо высокого уровня он переключается на вход.

PP, соответсвенно обозначает возможность работы в режиме Push-pull, когда пин может выдавать и низкий, и высокий уровни. Почти все пины могут работать в режиме Push-pull, и если нужно переключаться в режим open-drain.

Исключение составляют, опять-же, C0 и C1, которые кроме open-drain, больше никак работать не могут. Имейте это ввиду, при распределении выводов.

Еще раз, кратко, об электрике:

Максимальный ток, выдаваемый ножкой — 20мА (кроме C1 и C0 — у которых 5мА, и A0 — способного «втянуть» до 80мА) Общий максимальный ток камня — 80мА (т.е. ток через все пины не должен превышать эту отметку).

Максимальное напряжение питания — 3.6V для STM8L и 5.5V для STM8S. Минимальное — 1.8V для STM8L и 2.7V для S. Причем в STM8L можно отключить flash память и выполнять код из оперативки — тогда они могут работать и при напряжении 1.55V.

Программирование

C точки зрения программиста, GPIO порт в STM8 это пять регистров:

Px_ODR — значение, которое выдается в порт

Px_IDR — текущее состояние порта
Px_DDR — направление (вход или выход)
Px_CR1 — настройки раз
Px_CR2 — настройки два (вместо x — буква порта) Первые три регистра наверное ничего нового ни для кого не представляют. На всякий случай устрою ликбез:

Каждый бит Px_DDR отвечает за направление соответствующей ножки МК. 1 — ножка настроена на выход, 0 — на вход.

Биты в Px_ODR устанавливают уровень на ножке (если она настроена на выход). 0 — низкий уровень, 1 — высокий. Причем в зависимости от значения в CR1 (см. ниже), высокий уровень может быть упразднен — пин работает в режиме открытого стока. Уровни STM8 держит очень неплохо — без нагрузки ножка прижатая к земле выдает 2.

3мВ (и скорее всего, это погрешность моего мультиметра). Под нагрузкой в 1мА напряжение уже составляет 26мВ, а при нагрузке 20мА (предельное значение) — 556мВ. Если же наш пин настроен на вход, то запись в ODR ничего не даст.

Чтение из Px_ODR тоже возможно и тогда мы прочитаем последнее записанное туда значение (даже если на ножке сейчас другой уровень).

А вот из Px_IDR можно прочитать текущий уровень на ножках. И на этом можно лаконично закончить описание этого регистра, ибо больше тут ловить нечего 🙂

Регистры CR1 и CR2 работают по-разному в зависимости от значения соответсвующего бита в регистре DDR (то есть от того, на вход настроен пин или на выход).

Если пин настроен на вход, то бит в CR1 управляет внутренним подтягивающим резистором. Единица включает его, а ноль отключает — и пин просто болтается в воздухе. Вход без подтяжки (и ни к чему не подключенный) ловит помехи, которые переключают триггеры во входном каскаде порта.

А триггеры, переключаясь, кушают неслабый ток. Сотню микроампер висящие без подтяжки выводы могут накинуть запросто. Словом, если устройство должно потреблять как можно меньше тока, надо прибить все пины к какому-либо постоянному уровню.

Не важно, при помощи подтяжки или как либо иначе — главное чтобы не переключались от помех.

Подтягивающие резисторы тут довольно хилые — около 38-40 кОм (это при комнатной температуре). В реальных устройствах (а не макетах на столе) лучше ставить внешние подтягивающие резисторы на кнопки. Номиналом 10к или меньше. Особенно это важно если до кнопок идут длинные провода, и/или рядом есть источники помех.

Иначе можно получить ложные срабатывания.

Регистр CR2 в этом случае [когда пин настроен на вход] отвечает за прерывание от пина — если там единица, то прерывание разрешено. В STM8 можно ловить прерывания с любой ножки (кроме A1 — NRST). Хотя и тут есть свои хитрости, которые ограничивают свободу действий.

Но о прерываниях в следующей части.

Когда пин работает на выход, CR1 отвечает за режим работы.

Единичка — push-pull (то есть ножка может с одинаковым успехом выдавать низкий и высокий уровень), ноль — пародия на выход с открытым стоком (в оригинале «pseudo open-drain» :)) — низкий уровень выдается по-прежнему, а вместо высокого пин переключается в режим входа (в регистре DDR при этом ничего не меняется, естественно). В таком режиме удобно работать с 1-wire, или с программной реализацией I2C.

CR2, когда пин настроен на выход, отвечает за «максимальную скорость переключения». Ну это так в даташите написано, а по факту от значения в этом регистре будет зависеть крутизна фронтов. Вот так:

Желтый канал прицеплен к пину с высокой скоростью переключения (единичка в CR2), а красный — к пину с низкой. Переключение происходит одновременно (одной командой), а вот скорость нарастания напряжения оказывается разной. В итоге быстрый пин поднимается примерно на 15-20 наносекунд раньше медленного. Обычно такая маленькая разница никого не волнует, но если нужно выдавать высокочастотный сигнал с ножки МК, или надо получить сигнал с крутыми фронтами, то установка бита в CR2 решит почти все проблемы (кроме проблем с наводками на соседние дорожки от этого сигнала — при крутых фронтах они только возрастут :)) В STM8S у некоторых пинов максимальная скорость не настраивается, а задана жестко:Имейте это ввиду, если будете с ними работать. С устройством GPIO вроде разобрались. Теперь можно посмотреть на код из предыдущей части свежим взглядом, уже точно понимая за что отвечают все эти регистры. Мигание светодиодом это классика, но весьма скучно. Сделаем что-то более сложное. К примеру, электронную игральную «кость»: Генератор случайной цифры. Возьмем семисегментный индикатор, на который будем по-очереди выводить цифры 0 — 9. Этот счет будет останавливаться при нажатии на кнопку, и на индикаторе останется гореть одна цифра. И так до следующего нажатия кнопки. Цифры меняются с большой скоростью, и человек, нажимающий на кнопку не может специально подгадать момент и остановить счетчик на нужной цифре. Я использовал индикатор, установленный на PINBOARD. Сегменты у него выведены на те-же пины, где находится шина данных от ЖК дисплея, и зажигаются высоким уровнем (т.е. индикатор с общим катодом). Сегменты подключаются к порту B на МК:B0 – D0 (Сегмент E) B1 – D1 (D) B2 – D2 (Точка) B3 – D3 (C) B4 – D4 (G) B5 – D5 (B) B6 – D6 (F) B7 – D7 (A)Потому, что порт B это вообще единственный «полный» порт в МК в корпусе TQFP32. У остальных не хватает одного или пары пинов. Общие выводы от разрядов подключены через транзисторы к земле (для активации разряда надо подать высокий уровень, чтобы открыть транзистор) и заведены на штырьки RS, R/W и E. Нам пока нужен всего один разряд, поэтому просто подключим нужный вывод к MAIN PWR — транзистор будет постоянно открыт.Чтобы не считать вручную коды, отвечающие за символ каждой цифры, заюзаем вот такую табличку://Закомментировать, если используется индикатор с общим анодом (0 = зажечь сегмент) #define COMMON_CATHODE // Сегмент индикатора Пин #define segment_A 7 #define segment_B 5 #define segment_C 3 #define segment_D 1 #define segment_E 0 #define segment_F 6 #define segment_G 4 #define segment_DP 2 #ifdef COMMON_CATHODE extern const char numbers[10] = { /*0*/ (1

Источник: http://we.easyelectronics.ru/STM8/8l-kurs-chast-2-gpio.html

Изучаем STM8 (Часть 3). Работа с портами Ввода-Вывода (GPIO) — DRIVE2

Для начала – что такое GPIO.Расшифровуется это вот так — (General Purpose Input/Ouput) это двунаправленный регистр ввода/вывода который нужен для реализации функций заложенных в микроконтроллере, либо функций которые разработчик написал сам. То есть регистр определяющий какую функцию будет выполнять пин(ножка) микроконтроллера, будет входом или выходом.

Порты у STM8 обозначаются так же как и у AVR, то есть буквами – A, B, C, D… и т.д. Каждый порт состоит из 8 пинов. Пины VSS (GND), VDD(VCC), VCAP – заняты под питание микроконтроллера.Вывод VCAP присутствует только в микроконтроллерах серии STM8S и STM8A. Он нужен для стабилизации питания внутреннего регулятора на 1.8В.

Этот вывод подключается к «массе» через керамический конденсатор 100nF.

С выводам VSS и VDD я думаю объяснять не нужно? VSS – подключаем на массу, VDD — к +5Вольт.

Вернёмся обратно к описанию функционала портов, а то немного отвлеклись…

На картинке, которая показана ниже мы видим описание параметров портов нашего микроконтроллера. Эта табличка взята из даташита, который вы с лёгкостью найдёте на просторах интернета.

Немного опишу некоторые параметры
Floating Input — обозначает, может ли данный пин работать без подтягивающего (pull-up) резистора
WPU – Обозначает, есть ли на данном пине подтягивающий резистор.
Эти два выше написанных параметра используются если пин настроен на — ВХОД!

Ext. interrupt – Обозначает, может ли на данный пин приниматься внешнее прерываниеHigh Sink – Обозначает, может ли данный пин выдавать большой ток (20мА). «Слабые» пины будут без этой отметки и будут выдавать ток около 5мА.

Speed — Здесь указано скорость работы порта. Есть несколько вариантов – а)До 2MHz, б)До 10MHz и остальные два, которые программно выставляются, и могут при перезагрузке процессора быть в стоке или быстрым или медленным.

OD (open drain) и PP(push-pull) – Обозначает, может ли вывод работать в режиме Открытого Коллекстора или в режиме Push-Pull соответственно выдавая низкий или высокий уровень А эти параметры используются, если пин настроен на – ВЫХОД!

Теперь мы начнём программировать наши порты. Тут всё примерно как и у AVR, но ясное дело есть отличия. Итак
Для управления GPIO есть 5 регистров

Px_DDR — направление (вход или выход)
Px_ODR — значение, которое выдается в порт (Выдаём 1 или 0)
Px_IDR — текущее состояние порта (Чтение порта)
Px_CR1 — регистр конфигурации 1
Px_CR2 — регистр конфигурации 2

Px_DDR – тут всё просто, если мы сюда пишем -1, то соответствующая ножка будет – выходом. А если пишем — 0, то ножка будет входом.

Px_ODR – здесь мы устанавливаем то, что хотим видеть на ножке, если ножка настроена на выход. Если ставим — 1, то на ножке у нас появиться +5В, если 0, то на ножке появиться 0В (выход притянется к массе).

При этом, тут есть ещё варианты в зависимости от конфигурации битов CR1.
Px_IDR – тут всё просто. Из этого регистра мы просто читаем текущий уровень на ножках микроконтроллерах.

Биты CR1 и CR2 настраиваются по разному, в зависимости от того настроен пин на выход или на входЕсли пин настроен на ВХОД:

Бит CR1 — управляет внутренним подтягивающим резистором – единица его включает, ноль выключает, и пин просто болтается в воздухе . Старайтесь на неиспользуемых пинах включать подтяжку, чтобы пин не ловил непонятные уровни.

Бит CR2 в режиме входа разрешает или запрещает прерывания на данной ножке. Если единица – прерывание разрешено, если ноль – запрещено.Если пин настроен на ВЫХОД:

Бит CR1 — если установлена единица – устанавливает режим работы Push-Pull, то есть выход может выдавать высокий и низкий уровень. Ноль — выход работает в режиме открытого стока. То есть низкий уровень ножка как выдавала, так и выдаёт, а вот вместо высокого уровня, пин переключатся в режим входа.

Бит CR2— в режиме выхода управляет скорость переключения. То о чём было написано выше. То есть мы може установить скорость переключения до 2мГц и до 10мГц. А вообще по факту, от данного бита зависит не скорость работы пина, а крутизна фронта сигнала.
Вот табличка для простоты понимания настройки битов CR1 и CR2

РегистрРежимЗначение ОписаниеCR1 Вход 0 Плавающий вход (Floating input)CR1 Вход 1 Вход с подтягивающим резисторомCR1 Выход 0 Открытый сток (Open drain)CR1 Выход 1 Выход Push-PullCR2 Вход 0 Прерывания запрещеныCR2 Вход 1 Прерывания разрешеныCR2 Выход 0 Выход до 2 мГц

CR2 Выход 1 Выход до 10мГц

А теперь подытожим. Если мы хотим ножку PB7 входом, то мы должны написать вот так
PB_DDR_DDR7 = 0; //Назначаем ножку PB7 входом
PB_CR1_bit.C17 = 1; //Подключаем подтягивающий резистор
PB_CR2_bit.C27 = 1; //Разрешаем внешние прерывания на этой ножке

А если бы мы хотели сделать эту ножку выходом, то записали бы вот так.

PB_DDR_DDR7 = 1; //Назначаем ножку PB7 выходом
PB_CR1_bit.C17 = 1; //Делаем выход Push-Pull, то есть выход может выдавать высокий и низкий уровень
PB_CR2_bit.C27 = 1; //скорость работы пина до 10 МГц

Как мы видим, пока ничего сложного.

Источник: https://www.drive2.ru/b/1319133/

Статьи о STM32 с примерами (SPL)

Список статей который поможет изучить микроконтроллер STM32 даже начинающему. Подробно обо всем с примерами начиная от мигания светодиодом до управления бесколлекторным двигателем. В примерах используется стандартная библиотека SPL (Standard Peripheral Library).

Тестовая плата STM32F103, ST-Link программатор, и программное обеспечение для прошивки под Windows и Ubuntu.

Установка и настройка IDE CooCox для разработки программ для микроконтроллеров STM32

Установка и настройка Keil uVision5

Установка и настройка IAR Workbench

Работа с GPIO выводами микроконтроллера. Вход / выход

Схема тактирования STM32. Настройка тактирования микроконтроллера и периферии.

Использование последовательного порта USART. Прием и передача данных, обработка команд.

VIC (Nested vectored interrupt controller) – модуль контроля прерываний. Настройка и использование прерываний. Приоритеты прерываний. Вложенные прерывания.

АЦП (аналого-цифровой преобразователь). Схема питания и примеры использования АЦП в различных режимах. Regular и Injected каналы. Использование АЦП вместе с DMA. Внутренний термометр. Аналоговый watchdog.

DMA (Direct Memory Access) контроллер прямого доступа к памяти. Пример USART через DMA.

Таймеры общего назначения. Генерирование прерывания через равные промежутки времени. Измерение времени между двумя событиями.

Генерация ШИМ. Управление яркостью светодиода. Управление сервоприводом (сервомашинками). Генерация звука.

Внешние прерывания. Interrupt / Event.

Часы реального времени (RTC). Battery backup domain.

Backup registers (BKP). Использование BKP регистров для хранения данных.

Работа с Flash памятью. Пример хранения настроек.

IWDG – Independent Watchdog и WWDG – Window Watchdog. Примеры использования Watchdog.

Использование альтернативного функционала выводов микроконтроллера.

Использование шины I2C (IIC) (TWI) на примере работы с датчиком атмосферного давления BMP280

Микроконтроллер в качестве IIC устройства (Slave).

Библиотека STM32 USB FS Device Lib. Виртуальный последовательный порт. Эмуляция клавиатуры и мышки. USB Mass Srorage.

Схема питания. Домены питания. Режимы пониженного энергопотребления Sleep, Stop, Standby. Выход из режима пониженного энергопотребления с помощью RTC.

Option bytes, защита прошивки от чтения / записи.

Собственный Bootloader. Bootloader в режиме USB Mass Storage.

Управление бесколлекторным двигателем постоянного тока (BLDC) с помощью STM32. Демонстрация возможностей таймеру TIM1 (advanced-control timer)

Управление PMSM с помощью STM32. Демонстрация возможностей таймеру TIM1 (advanced-control timer)

Если у Вас возникли замечания, вопросы, предложения, обращайтесь к автору:
Андрей Корягин andre@avislab.com

Источник: http://www.avislab.com/blog/stm32-list_ru/

Изучаем STM32. Урок 5. SPL — Standard Peripherals Library — DRIVE2

Добрый день. Решил написать ещё одну статейку по STM32. На этот раз мы поговорим о SPL -Standard Peripherals Library. Вообще на данный момент у нас есть 3 варианта написания наших программ для STM32

1)CMSIS — это стандартная библиотека для кортексов. То есть это стандарт. С помощью этой библиотеки мы можем писать наши программы — но только с прямой записью в регистры.

Это самый профессиональный способ написания программ, и кстати самый правильный, но сложный, так как придётся от а до я учить даташиты, постоянно сидеть с открытыми доками на процессор чтобы найти куда записать тот или иной бит в регистры.

2)SPL -Standard Peripherals Library — это попытка ST Electronics выпустить одну общую библиотеку для объединения всех своих процессоров. ЧТобы было проще переносить код и т.д и т.п. Работать проще как для начинающего, но всё равно всё вбиваем ручками — Никакой Автоматики!

3)HAL — Hardware Acess Level — это вторая попытка ST Electronics выпустить единую библиотеку для разработки. Заодно с ней вышла и программа CubeMX для настройки всего этого хозяйства.Всё гладко и хорошо по началау, но только по началу — дальше всё, приехали — ни примеров, ни обзоров. Поэтому пока не исследуют эту библиотеку вдоль и поперёк- делов не будет)))

То есть смысл в том что SPL уже вдоль и поперёк всю распилили и изучили. Поэтому, хочешь не хочешь а учить нужно. И вообще нужно стремиться к CMSIS. Но это уже кому захочется))

Итак, давайте попробуем написать простейшую программу для мигания светодиодом с помощью SPL. Первое что нам понадобиться — Reference Manual и Datasheet на наш контроллер. Я этот пример буду писать для контроллера установленного на отладочной плате STM32F4 Discovery — STM32F407VGT6

Идём на сайт ST.com и вбиваем в поиск наш процессор. Качаем в найденном Datasheet и далее переходим на вкладку Design Resources и ниже ищем Reference Manual.

Далее, думаем, что нам нужно. Нужно нам помигать светодиодом. Раз помигать светодиодом, значит мы должны настроить нашу ножку к которой этот светодиод подключён.

Вспоминаем (ну или если не знали то читаем) — что изначально все порты микроконтроллера отключены от тактирования, для экономии энергии. Нам же нужно включить тактирование на нужный нам порт.

Светодиод у нас подключен к пину 12 порта D.

Открываем Reference Manual и пробцем искать интересные нам слова как GPIO, Bus, AHB…
Я в самом начале документа нашёл вот такую интересную информацию

Далее. Переходим уже к практике, чтобы сразу и писать программу и читать. Создаём проект в CooCox — Create New Project. Даём название проекту

Далее выбираем для чего мы пишем — Процессор или демо плата. В нашем случае Chip

Выбираем нужный нам контроллер и нажимаем FINISH

Открывается окно репозитория, где нам предлагают выбрать нужные нам библиотеки. Так как нам нужно подать тактирование на порт подключаем библиотеку RCC, Далее — мы же будем работать с портами ввода-вывода, значит подключаем библиотеку GPIO. Также включаем CMSIS BOOT.

Первым делом нам нужно подключить заголовочные файлы
#include “stm32f4xx.h”#include “stm32f4xx_gpio.h”

#include “stm32f4xx_rcc.h”

Далее, нам нужно проинициализировать нужную переферию. Можно для этого написать отдельную функцию типа init_gpio(), в ней описать всю инициализацию, и потом вызвать её в mainn(), а можно чтобы по простому пока — прямо в main() и написать всю инициализацию. Так и сделаем.

Первое что нам нужно, это подать тактирование на наш portD. Как мы помним — порты ввода-вывода у нас сидят на шине AHB1. Для простоты в CooCox есть примеры инициализаций прямо в репозитории. Вверху на вкладке открываем опять страницу репозитория, где мы библиотеки подключали.

Нажимаем на библиотеку RCC, и справа мы видим большой перечень функций. Ищем вот такую RCC_AHB1PeriphClockCmd, нажимаем на неёи видим её полное описание.

Выделяем и копируем её в наш проект
void RCC_AHB1PeriphClockCmd ( uint32_t RCC_AHB1Periph, FunctionalState NewState);

Убираем слово void из начала нашей строчки, и далее вписываем два аргумента. Первый Что мы включаем, второй Enable — типо включаем. Кстати начиная писать начало аргумента, нижимете Ctrl+Пробел и у вас вылазит подсказка для упрощения работы.

Итак, тактирование на наш порт D подали. Теперь нам нужно настроить ножку нашего порта. Параметры нашей ножки такие — Выход, Push-Pull, Низкая скорость до 2MHz

Первое, что нам нужно, это обозначить структуру, которая будет хранить настройки нашего порта.Давайте её назовём PIN_INIT.

Источник: https://www.drive2.com/b/2253235/

Компилятор SDCC для STM8 в linux

STM8 это дешевые 8и-битные микроконтроллеры от фирмы ST.

По начинке и цене эти контроллеры превосходят популярные AVR, но одной из больших проблем в их использовании является отсутствие  открытого компилятора, в том числе для ОС linux, под которой работает достаточно много программистов встраиваемых систем.

Одним из свежих, и еще толком не испытанных решений является мультицелевой компилятор SDCC – Small Device C Compiler, поддерживающий стандарт ANSI C. Поддержка STM8 еще официально даже не объявлена, однако уже частично реализована.

Я решил попробовать компилятор в действии и скомпилировать им простой код, мигающий светодиодами на STM8S. Прошивку я выполнял с помощью программатора Versaloon так как под St-link я пока не нашел linux-софта, способного работать по SWIM.

Я купил дешевые контроллеры STM8S с памятью всего в 8 Кб флеша, по этому в них нету встроенного UART-бутлоадера. Для обладателей камней с бутлоадером – 32K (Medium Density) and 128K (High Denisty) – можно в качестве программатора использовать обычный UART преобразователь (например USB-UART на cp1202), а в качестве прошивающего софта попробовать stm8flash (порт бутлоадеровской прошивалки под STM32 stm32flash).

Для того чтобы использовать структуры с периферией и дефайны битов я использовал стандартную библиотеку от ST STM8S/A Standard peripheral library 2.1.0. Так как библиотека не поддерживает компилятор SDCC, мне ее пришлось немного доработать напильником.

Скачать плату, библиотеку STM8 SPL для sdcc, и пример.

Демоплатка

Большинство разработчиков знакомятся с STM8 с помощью отладочной платы STM8*Discovery от ST. Мне как всегда лень покупать готовые отладочные платы, по этому я прикупил пару дешевых камней и сам сделал для них простенькую платку:

Первый камень STM8S00F3P6 (цена в местном магазине меньше 0.5 $). Параметры: 

  • корпус: TSSOP 20 
  • макс. частота ядра: 16 МГц
  • 8 kB флеша
  • 1 kB RAM
  • 128 B EEPROM
  • 1х – 8и битный таймер
  • 2х 16и битный таймера
  • 5х 10-ибитных АЦП
  • 1x UART, SPI, I2C
  • Напряжение питания от 2.95 до 5.5

Второй микроконтроллер STM8S10F3P6 (~1$, сам камень точно такой же как и прошлый, только в 5 раз больше EEPROM – 640 Байт вместо 128).

Собственно плата маленькая: штырьки, пару светодиодов, кнопка, место под кварц. Схема:

Плата:

Запаять можно кнопку обычную(слева) или SMD(справа):

Слева платка с STM8S003F3P6, справа STM8S103F3P6. Кварцы пока не запаивал, так как для теста хватит и встроенного. В примере буду все показывать для STM8S003F3P6, но работоспособность уода я проверил на обоих чипах.

Скачать плату, библиотеку STM8 SPL для sdcc, и пример.

Установка SDCC

Для начала нужно скачать архив с бинарниками со страницы http://sdcc.sourceforge.net/snap.php#Linux. Там нужно найти список файлов для своей платформы и выбрать самую последнюю сборку.

Далее разархивируем архив и просто копируем его в систему с помощью следующих команд:

tar -xf sdcc-snapshot-amd64-unknown-linux2.5-20140123-8938.tar.bz2
cd sdcc
sudo cp -R * /usr/local/

Пример компиляции с помощью SDCC

Для быстрой и удобной компиляции и прошивки я использовал make. Конечно компилятор можно несложно прикрутить к eclipse, но так как возможности отладки на данный момент нет, то смысла в eclipse не сильно много.

Для начала создадим папку, например example. В нее поместим библиотеку SPL из архива (всю папку STM8S_StdPeriph_Lib_V2.1.0).

Далее создадим в ней файл leds.c со следующим содержанием:

#include “stm8s.h”
#include “stm8s_gpio.h”
static void delay(uint32_t t)
{ while(t–);
}
int main( void )
{ GPIOC->DDR |= GPIO_PIN_3 | GPIO_PIN_4; GPIOC->CR1 |= GPIO_PIN_3 | GPIO_PIN_4; GPIOC->ODR |= GPIO_PIN_3; while(1) { delay(20000); GPIOC->ODR ^= GPIO_PIN_3 | GPIO_PIN_4; }
}

Там же создадим файл Makefile

CC=sdcc
CFLAGS=-mstm8 INCLUDEPATH=STM8S_StdPeriph_Lib_V2.1.0/Libraries/STM8S_StdPeriph_Driver/inc/
DEFINES= STM8S003
SOURCE=leds
OUTPUT_DIR=build/
all: flash
compile: mkdir -p $(OUTPUT_DIR) $(CC) $(CFLAGS) -I $(INCLUDEPATH) -D $(DEFINES) -o $(OUTPUT_DIR) $(SOURCE).c prepare: packihx $(OUTPUT_DIR)/$(SOURCE).ihx > $(OUTPUT_DIR)/$(SOURCE).hex
clean: rm -Rrf $(OUTPUT_DIR)
erase: vsprog -cstm8s103f3 -ms -oe -V”tvcc.set 3300″ vsprog -V”tvcc.set 0″ -V”tvcc.set 3300″
flash: compile prepare erase vsprog -cstm8s103f3 -ms -owf -I $(OUTPUT_DIR)/$(SOURCE).hex -V”tvcc.set 3300″ vsprog -V”tvcc.set 0″ -V”tvcc.set 3300″

Обратите внимание, что отступы должны быть сделаны знаком табуляции а не пробелами. 

Если вы не понимаете как выполняются Makefile-ы, можете прочитать про них в моей статье.

Для компиляции нужно выполнить:

make compile

Для очистки всего собранного:

make clean

Для одновременной компиляции и прошивки с помощью Versaloon:

make

Подключение демоплатки к Versaloon

Распиновка разъема Versaloon приведена тут. Подключаем SWIM (Зеленый), GND(Черный), VCC(Желтый), Reset (Синий). Теперь небольшое объяснение команд Makefile. В 16ой строке выполняется erase, в 17 и 20 выполняется включение и включения питания микроконтроллера, таким образом перезагружая его (Почему-то после прошивки или очистки, чип зависает, и для запуска его приходится перезагружать).

В строке 19 происходит прошивка. Обратите внимание, что для микроконтроллера stm8s003f3 нет записи в конфиге vsprog config/stm8.xml, однако чип  stm8s003f3 имеет идентичные параметры как и stm8s103f3, по этому я указал его в параметре -c и все успешно прошилось.

Единственное отличие stm8s003f3, которое может быть принципиально при прошивке, это меньший размер памяти EEPROM (128 байт вместо 640). По этому если кто-то захочет добавить себе в конфиг чип , то все параметры можете скопировать из и поменять один параметр 10 на 2 (всего 2 страницы по 64 байта).

Источник: https://bovs.org/post/111/

Метка: STM32F10x SPL

При компиляции core_cm3.c из STM32F10x SPL v3.5.0 компилятор (gcc из Sourcery CodeBench) выдает ошибки:

Микроконтроллеры серии STM32F10x содержат богатую периферию, которая тактируется с разными частотами. Вычислить тактовые частоты можно с помощью функции RCC_GetClocksFreq(), которая содержится в модуле RCC библиотеки STM32F10x SPL.

Функция производит вычисления на основе данных в регистрах RCC.

Прототип функции:

void RCC_GetClocksFreq(RCC_ClocksTypeDef * RCC_Clocks)

Функция заполняет структуру типа RCC_ClocksTypeDef, указатель на которую передается в функцию в качестве аргумента. Структура содержит следующие поля:

uint32_t ADCCLK_Frequency Тактовая частота АЦП в Гц
uint32_t HCLK_Frequency Тактовая частота шины AHB в Гц
uint32_t PCLK1_Frequency Тактовая частота периферии APB1 в Гц
uint32_t PCLK2_Frequency Тактовая частота периферии APB2 в Гц
uint32_t SYSCLK_Frequency Системная тактовая частота в Гц

Если используется внешнее тактирование, то функция должна знать частоту этого тактирования. Частота задается константой HSE_VALUE.

Лучше всего, определить константу опцией -D компилятора:

-DHSE_VALUE=4000000

В этом примере задается частота 4 МГц.

Если не определить константу в опциях компилятора, то она определится в файле stm32f10x.h и ей присвоится значение по умолчанию: 8000000 (8 МГц). Это значение можно отредактировать, прописав свою частоту.

Еще один способ задать собственное значение частоты: прописать в файле stm32f10x_conf.h следующие строки:

#if defined HSE_VALUE #undef HSE_VALUE #endif #define HSE_VALUE ((uint32_t)4000000) // 4 МГц

Во всех способах частота задается целым числом Герц.

Пример вызова функции RCC_GetClocksFreq():

RCC_ClocksTypeDef clocks; RCC_GetClocksFreq(&clocks);

Кроме того, чтобы узнать источник системного тактирования микроконтроллера, можно воспользоваться функцией RCC_GetSYSCLKSource().

Прототип функции:

uint8_t RCC_GetSYSCLKSource(void)

Функция возвращает одно из значений:

  • 0x00: внутренний тактовый генератор (HSI)
  • 0x04: внешний тактовый источник (HSE)
  • 0x08: умножитель (PLL)

К сожалению библиотека SPL не имеет функций для вычисления тактовых частот конкретных периферийных устройств.
Код вычисляющий тактовые частоты таймеров:

uint32_t APB1_TIMCLK_Frequency; uint32_t APB2_TIMCLK_Frequency; RCC_ClocksTypeDef clocks; RCC_GetClocksFreq(&clocks); if (clocks.HCLK_Frequency == clocks.PCLK1_Frequency) APB1_TIMCLK_Frequency = clocks.PCLK1_Frequency; else APB1_TIMCLK_Frequency = 2 * clocks.PCLK1_Frequency; if (clocks.HCLK_Frequency == clocks.PCLK2_Frequency) APB2_TIMCLK_Frequency = clocks.PCLK2_Frequency; else APB2_TIMCLK_Frequency = 2 * clocks.PCLK2_Frequency;

  1. PPP — обозначение периферийного устройства, например ADC (аналого-цифровой преобразователь)
  2. Файлы исходного кода библиотеки начинаются с приставки stm32f10x_.
  3. Имена констант прописаны заглавными буквами. Если константа используется в единственном файле, то она определяется в этом файле. Константа, используемая в более, чем одном файле, определяются в заголовочном файле.
  4. Имена регистров, как и констант, прописаны заглавными буквами. Регистры именуются так же, как в документации на микроконтроллеры.
  5. Имена функций начинаются с PPP, после чего идет одно нижнее подчеркивание. Далее идут слитные слова, начинающиеся с заглавной буквы. Например: USART_SendData().
  6. Для настройки периферии PPP используется функция PPP_Init(), в которую передается указатель на структуру типа PPP_InitTypeDef, содержащую настройки периферии.
  7. Функция PPP_DeInit() сбрасывает регистры периферии в их начальное состояние.
  8. Функция PPP_StructInit() заполняет поля структуры типа PPP_InitTypeDef значениями по умолчанию, которые описывают начальное состояние периферии (состояние после сброса).
  9. Функция PPP_Cmd() включает или отключает периферию.
  10. Функция PPP_ITConfig() включает или отключает прерывания.
  11. Функция PPP_DMAConfig() включает или отключает DMA-интерфейс.
  12. Функции, оканчивающиеся на Config, настраивают отдельные функции периферии. Например GPIO_PinRemapConfig().
  13. Функция PPP_GetFlagStatus() служит для получения состояния флагов.
  14. Функция PPP_ClearFlag() сбрасывает флаги.
  15. Функция PPP_GetITStatus() сообщает о том произошло ли прерывание или нет.
  16. Функция PPP_ClearITPendingBit() сбрасывает бит захвата прерывания.

Статья написана на основе этой документации:
STM32F10x Standard Peripherals Library версии 3.5.0

В следующих разделах статьи будет представлено описание функций модуля GPIO и описание структуры GPIO_InitTypeDef.

Содержание

Обзор функций

В этом разделе, кликнув на имя функции, можно перейти к её подробному описанию.

void GPIO_AFIODeInit(void)
Сбрасывает в начальное состояние регистры альтернативных функций

void GPIO_DeInit(GPIO_TypeDef *GPIOx)
Сбрасывает в начальное состояние регистры GPIOx

void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface)
Выбирает Ethernet media interface

void GPIO_EventOutputCmd(FunctionalState NewState)
Разрешает или запрещает событийный выход (Event Output)

void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
Выбирает вывод для событийного выхода

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
Назначает вывод GPIO_PinSource порта GPIO_PortSource источником внешнего прерывания

void GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_InitStruct)
Настраивает порт GPIOx в соответствии с параметрами из структуры GPIO_InitStruct

void GPIO_StructInit(GPIO_InitTypeDef *GPIO_InitStruct)
Заполняет поля структуры GPIO_InitStruct значениями по умолчанию

void GPIO_PinLockConfig(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Защищает настройки выводов

void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState)
Разрешает или запрещает переназначение GPIO_Remap

uint16_t GPIO_ReadInputData(GPIO_TypeDef *GPIOx)
Возвращает входные данные порта GPIOx

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Возвращает входное состояние вывода GPIO_Pin порта GPIOx

uint16_t GPIO_ReadOutputData(GPIO_TypeDef *GPIOx)
Возвращает выходные данные порта GPIOx

uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Возвращает выходное состояние вывода GPIO_Pin порта GPIOx

void GPIO_ResetBits(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Присваивает лог. 0 выходному состоянию выводов GPIO_Pin порта GPIOx

void GPIO_SetBits(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
Присваивает лог. 1 выходному состоянию выводов GPIO_Pin порта GPIOx

void GPIO_Write(GPIO_TypeDef *GPIOx, uint16_t PortVal)
Присваивает значение PortVal выходным данным порта GPIOx

void GPIO_WriteBit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, BitAction BitVal)
Присваивает значение BitVal выходному состоянию вывода GPIO_Pin порта GPIOx

Подробное описание функций

void GPIO_AFIODeInit(void)
Сбрасывает в начальное состояние регистры альтернативных функций порта

void GPIO_DeInit(GPIO_TypeDef *GPIOx) Сбрасывает в начальное состояние регистры порта GPIOx

Аргументы:

Источник: https://bravikov.wordpress.com/tag/stm32f10x-spl/

Ссылка на основную публикацию
Adblock
detector
",css:{backgroundColor:"#000",opacity:.6}},container:{block:void 0,tpl:"
"},wrap:void 0,body:void 0,errors:{tpl:"
",autoclose_delay:2e3,ajax_unsuccessful_load:"Error"},openEffect:{type:"fade",speed:400},closeEffect:{type:"fade",speed:400},beforeOpen:n.noop,afterOpen:n.noop,beforeClose:n.noop,afterClose:n.noop,afterLoading:n.noop,afterLoadingOnShow:n.noop,errorLoading:n.noop},o=0,p=n([]),h={isEventOut:function(a,b){var c=!0;return n(a).each(function(){n(b.target).get(0)==n(this).get(0)&&(c=!1),0==n(b.target).closest("HTML",n(this).get(0)).length&&(c=!1)}),c}},q={getParentEl:function(a){var b=n(a);return b.data("arcticmodal")?b:(b=n(a).closest(".arcticmodal-container").data("arcticmodalParentEl"),!!b&&b)},transition:function(a,b,c,d){switch(d=null==d?n.noop:d,c.type){case"fade":"show"==b?a.fadeIn(c.speed,d):a.fadeOut(c.speed,d);break;case"none":"show"==b?a.show():a.hide(),d();}},prepare_body:function(a,b){n(".arcticmodal-close",a.body).unbind("click.arcticmodal").bind("click.arcticmodal",function(){return b.arcticmodal("close"),!1})},init_el:function(d,a){var b=d.data("arcticmodal");if(!b){if(b=a,o++,b.modalID=o,b.overlay.block=n(b.overlay.tpl),b.overlay.block.css(b.overlay.css),b.container.block=n(b.container.tpl),b.body=n(".arcticmodal-container_i2",b.container.block),a.clone?b.body.html(d.clone(!0)):(d.before("
"),b.body.html(d)),q.prepare_body(b,d),b.closeOnOverlayClick&&b.overlay.block.add(b.container.block).click(function(a){h.isEventOut(n(">*",b.body),a)&&d.arcticmodal("close")}),b.container.block.data("arcticmodalParentEl",d),d.data("arcticmodal",b),p=n.merge(p,d),n.proxy(e.show,d)(),"html"==b.type)return d;if(null!=b.ajax.beforeSend){var c=b.ajax.beforeSend;delete b.ajax.beforeSend}if(null!=b.ajax.success){var f=b.ajax.success;delete b.ajax.success}if(null!=b.ajax.error){var g=b.ajax.error;delete b.ajax.error}var j=n.extend(!0,{url:b.url,beforeSend:function(){null==c?b.body.html("
"):c(b,d)},success:function(c){d.trigger("afterLoading"),b.afterLoading(b,d,c),null==f?b.body.html(c):f(b,d,c),q.prepare_body(b,d),d.trigger("afterLoadingOnShow"),b.afterLoadingOnShow(b,d,c)},error:function(){d.trigger("errorLoading"),b.errorLoading(b,d),null==g?(b.body.html(b.errors.tpl),n(".arcticmodal-error",b.body).html(b.errors.ajax_unsuccessful_load),n(".arcticmodal-close",b.body).click(function(){return d.arcticmodal("close"),!1}),b.errors.autoclose_delay&&setTimeout(function(){d.arcticmodal("close")},b.errors.autoclose_delay)):g(b,d)}},b.ajax);b.ajax_request=n.ajax(j),d.data("arcticmodal",b)}},init:function(b){if(b=n.extend(!0,{},a,b),!n.isFunction(this))return this.each(function(){q.init_el(n(this),n.extend(!0,{},b))});if(null==b)return void n.error("jquery.arcticmodal: Uncorrect parameters");if(""==b.type)return void n.error("jquery.arcticmodal: Don't set parameter \"type\"");switch(b.type){case"html":if(""==b.content)return void n.error("jquery.arcticmodal: Don't set parameter \"content\"");var e=b.content;return b.content="",q.init_el(n(e),b);case"ajax":return""==b.url?void n.error("jquery.arcticmodal: Don't set parameter \"url\""):q.init_el(n("
"),b);}}},e={show:function(){var a=q.getParentEl(this);if(!1===a)return void n.error("jquery.arcticmodal: Uncorrect call");var b=a.data("arcticmodal");if(b.overlay.block.hide(),b.container.block.hide(),n("BODY").append(b.overlay.block),n("BODY").append(b.container.block),b.beforeOpen(b,a),a.trigger("beforeOpen"),"hidden"!=b.wrap.css("overflow")){b.wrap.data("arcticmodalOverflow",b.wrap.css("overflow"));var c=b.wrap.outerWidth(!0);b.wrap.css("overflow","hidden");var d=b.wrap.outerWidth(!0);d!=c&&b.wrap.css("marginRight",d-c+"px")}return p.not(a).each(function(){var a=n(this).data("arcticmodal");a.overlay.block.hide()}),q.transition(b.overlay.block,"show",1*")),b.overlay.block.remove(),b.container.block.remove(),a.data("arcticmodal",null),n(".arcticmodal-container").length||(b.wrap.data("arcticmodalOverflow")&&b.wrap.css("overflow",b.wrap.data("arcticmodalOverflow")),b.wrap.css("marginRight",0))}),"ajax"==b.type&&b.ajax_request.abort(),p=p.not(a))})},setDefault:function(b){n.extend(!0,a,b)}};n(function(){a.wrap=n(document.all&&!document.querySelector?"html":"body")}),n(document).bind("keyup.arcticmodal",function(d){var a=p.last();if(a.length){var b=a.data("arcticmodal");b.closeOnEsc&&27===d.keyCode&&a.arcticmodal("close")}}),n.arcticmodal=n.fn.arcticmodal=function(a){return e[a]?e[a].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof a&&a?void n.error("jquery.arcticmodal: Method "+a+" does not exist"):q.init.apply(this,arguments)}}(jQuery)}var debugMode="undefined"!=typeof debugFlatPM&&debugFlatPM,duplicateMode="undefined"!=typeof duplicateFlatPM&&duplicateFlatPM,countMode="undefined"!=typeof countFlatPM&&countFlatPM;document["wri"+"te"]=function(a){let b=document.createElement("div");jQuery(document.currentScript).after(b),flatPM_setHTML(b,a),jQuery(b).contents().unwrap()};function flatPM_sticky(c,d,e=0){function f(){if(null==a){let b=getComputedStyle(g,""),c="";for(let a=0;a=b.top-h?b.top-h{const d=c.split("=");return d[0]===a?decodeURIComponent(d[1]):b},""),c=""==b?void 0:b;return c}function flatPM_testCookie(){let a="test_56445";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(a){return!1}}function flatPM_grep(a,b,c){return jQuery.grep(a,(a,d)=>c?d==b:0==(d+1)%b)}function flatPM_random(a,b){return Math.floor(Math.random()*(b-a+1))+a}