STM32 STM32VL Discovery STM32F100RBT6 (урок 2) GPIO, порты ввода-вывода
Восстановленные материалы удаленного сайта www.doneathome.ru
По многочисленным просьбам пользователей попробую восстановить
Микроконтроллеры семейства STM32 содержат в своём составе до семи 16-разрядных портов ввода-вывода c именами от PORTA до PORTG. В конкретной модели микроконтроллера без исключений доступны все выводы портов, общее количество которых зависит от типа корпуса и оговорено в DataSheet на соответствующее подсемейство. Для нашего микроконтроллера (STM32F100RBT6) доступна 51 ножка.
Режимы работы ножек портов GPIO
Input floating [GPIO_Mode_IN_FLOATING]
Высоко импедансное состояние или Z-состояние — такое состояние контакта логической схемы, при котором сопротивление между этим контактом и остальной схемой очень велико. Физически реализуется закрытым транзистором, работающим в ключевом режиме.
Вывод, переведённый в Z-состояние, ведёт себя как не подключенный к схеме. Внешние устройства, подключенные к этому выводу, могут изменять напряжение на нём по своему усмотрению (в некоторых рамках), не влияя на работу схемы. И наоборот — схема не мешает внешним устройствам менять напряжение на контакте.
Input pull-up [GPIO_Mode_IPU]
Это вход с подтяжкой к питанию, т.е. между входом и питанием включен подтягивающий резистор. Подтягивающий резистор позволяет выходу находиться в высоком(подтянут к питанию) состоянии и не запрещает подключение этой ножки к земле (так как в цепи будет включено сопротивление).
Input-pull-down [GPIO_Mode_IPD]
Тот же самый режим что и был выше только с одним отличием: теперь подтяжкой к земле, а не к питанию.
Analog [GPIO_Mode_AIN]
Вывод может быть сконфигурирован как аналоговый вход или выход. Это касается отдельных периферийных блоков(АЦП, ЦАП), так что пока просто запомним, что такой режим есть.
Output open-drain [GPIO_Mode_Out_OD]
Выход с открытым коллектором (также называют выход с открытым стоком) [все зависит от типа транзистора].
Output push-pull [GPIO_Mode_Out_PP]
Двухтактный выход. Можно сказать что это некий базовый режим работы ножки. Так как в этом режиме мы подключаем ножку либо к потенциалу питания либо земли.
Alternate function push-pull [GPIO_Mode_AF_PP]
Тот же режим что и выше, только для альтернативной функции.
Alternate function open-drain [GPIO_Mode_AF_OD]
И также есть режим: выход с открытым коллектором для альтернативной функции. так же пока не трогаем.
Устройство ножки порта GPIO
Режимы работы ножки порта GPIO
Регистры портов GPIO
Описание: Это регистр настройки режима работы ножки порта (один из 8-ми). Заметим что на каждую ножку требуется 8бит. Из этого следует, что одного 32-ух разрядного регистра недостаточно для определения 16-ти ножек. Поэтому таких регистров два (для старшей и младшей части порта по регистру [GPIOx_CRL и GPIOx_CRH])
Биты:
MODEx[1:0] – Биты MODEx определяют направление вывода и ограничение скорости переключения в режиме выхода:
MODEx[1:0] = 00: Режим входа (состояние после сброса);
MODEx[1:0] = 01: Режим выхода, максимальная скорость – 10МГц;
MODEx[1:0] = 10: Режим выхода, максимальная скорость – 2МГц;
MODEx[1:0] = 11: Режим выхода, максимальная скорость – 50МГц;
CNFx[1:0] – Биты CNF задают конфигурацию соответствующих выводов:
В режиме входа (MODE[1:0]=00):
CNFx[1:0] = 00: Аналоговый вход;
CNFx[1:0] = 01: Вход в третьем состоянии (состояние после сброса);
CNFx[1:0] = 10: Вход с притягивающим резистором pull-up (если PxODR=1) или pull-down (если PxODR=0);
CNFx[1:0] = 11: Зарезервировано;
В режиме выхода (MODE[1:0] > 00):
CNFx[1:0] = 00: Двухтактный выход общего назначения;
CNFx[1:0] = 01: Выход с открытым стоком общего назначения;
CNFx[1:0] = 10: Двухтактный выход с альтернативной функцией;
CNFx[1:0] = 11: Выход с открытым стоком с альтернативной функцией;
GPIOx_CRH [0x4444 4444]
Описание: Это регистр настройки режима работы ножки порта (один из 8-ми). Заметим что на каждую ножку требуется 8бит. Из этого следует, что одного 32-ух разрядного регистра недостаточно для определения 16-ти ножек. Поэтому таких регистров два (для старшей и младшей части порта по регистру [GPIOx_CRL и GPIOx_CRH])
Биты:
MODEx[1:0] – Биты MODEx определяют направление вывода и ограничение скорости переключения в режиме выхода:
MODEx[1:0] = 00: Режим входа (состояние после сброса);
MODEx[1:0] = 01: Режим выхода, максимальная скорость – 10МГц;
MODEx[1:0] = 10: Режим выхода, максимальная скорость – 2МГц;
MODEx[1:0] = 11: Режим выхода, максимальная скорость – 50МГц;
CNFx[1:0] – Биты CNF задают конфигурацию соответствующих выводов:
В режиме входа (MODE[1:0]=00):
CNFx[1:0] = 00: Аналоговый вход;
CNFx[1:0] = 01: Вход в третьем состоянии (состояние после сброса);
CNFx[1:0] = 10: Вход с притягивающим резистором pull-up (если PxODR=1) или pull-down (если PxODR=0);
CNFx[1:0] = 11: Зарезервировано;
В режиме выхода (MODE[1:0] > 00):
CNFx[1:0] = 00: Двухтактный выход общего назначения;
CNFx[1:0] = 01: Выход с открытым стоком общего назначения;
CNFx[1:0] = 10: Двухтактный выход с альтернативной функцией;
CNFx[1:0] = 11: Выход с открытым стоком с альтернативной функцией;
GPIOx_IDR [0x0000 XXXX]
Описание: Это регистр входа, регистр входа имеет толь 16 младших действующих бит из 32-ух. Чтение GPIOx_IDR возвращает значение состояния всех линий (напряжение на ножках) порта. Биты регистра доступны только для чтения.
Биты:
[“0” – Ноль в регистре (бите) == Лог “0” на ножке]
[“1” – Единица в регистре (бите) == Лог “1” на ножке]
GPIOx_ODR [0x0000 0000]
Описание: Это регистр выхода, регистр входа имеет толь 16 младших действующих бит из 32-ух. Запись сюда значений поменяет состояние ножки в соответствии с его конфигурацией. (Напоминаю что при настройке ножки как вход с подтяжкой то бит в этом регистре определяет к чему будет подтянута ножка).
Чтение GPIOx_ODR возвращает значение НЕ состояния всех лог уровней на ножках, а значение ранее записанное в этот регистр. Биты регистра доступны как для чтения, так и для записи.
Значение битов этих регистров может быть изменено через регистры: GPIOx_BSRR и GPIOx_BRR
Биты:
Режим Output push-pull [GPIO_Mode_Out_PP]
[“0” – Ноль в регистре (бите) == Лог “0” на ножке]
[“1” – Единица в регистре (бите) == Лог “1” на ножке]
Режим Output open-drain [GPIO_Mode_Out_OD]
[“0” – Ноль в регистре (бите) == Транзистор закрыт (3-сост на ножке)]
[“1″ – Единица в регистре (бите) == Транзистор открыт (Лог”0” на ножке)]
GPIOx_BSRR [0x0000 0000]
Описание: Это очень хитрый регистр)) видим тут только два типа битов BSx и BRx. Эти биты необходимы для управления регистром GPIOx_ODR. Cуть в том, что записав в бит BS0 единицу, мы установим единицу в бите ODR0 в регистре GPIOx_ODR. Также дела обстоят при использовании битов сброса BRx, только единица в этом бите сбрасывает соответствующий бит в регистре GPIOx_ODR в ноль.
Значения этих битов управляют регистром: GPIOx_ODR
Биты:
BSx
[“0” – Ноль в регистре (бите) == не приведет ни к какому эффекту]
[“1” – Единица в регистре (бите) == Лог “1” в соответствующем бите регистра GPIOx_ODR ]
BRx
[“0” – Ноль в регистре (бите) == не приведет ни к какому эффекту]
[“1” – Единица в регистре (бите) == Лог “0” в соответствующем бите регистра GPIOx_ODR ]
GPIOx_BRR [0x0000 0000]
Описание: Это очень хитрый регистр)) видим тут только один тип битов BRx. Эти биты необходимы для управления регистром GPIOx_ODR. Cуть в том, что записав в бит BRx единицу,будет произведен сброс соответствующего бита в регистре GPIOx_ODR в ноль. То есть это половинка регистра GPIOx_BSRR.
Значения этих битов управляют регистром: GPIOx_ODR
Биты:
BRx
[“0” – Ноль в регистре (бите) == не приведет ни к какому эффекту]
[“1” – Единица в регистре (бите) == Лог “0” в соответствующем бите регистра GPIOx_ODR ]
GPIOx_LCKR [0x0000 0000]
Описание: Это очередной очень хитрый регистр)) Про него отдельно надо разговаривать… В паре слов этот регистр позволяет запретить изменение значений в регистре GPIOx_ODR
Значения этих битов управляют регистром (БЛОК): GPIOx_ODR
Программирование портов GPIO
Сейчас на примерах можно немного освоится с принципами программирования GPIO. Так же как и при программировании чего угодно другого необходимо добиваться стиля при котором можно легко читать код. Это достигается обилием комментариев и прозрачностью действий (не надо лепить кучу всего в одну строчку). Присвоение голых чисел должно быть минимальным (пользуйтесь текстовыми заменами, что бы каждое число имело имя).
1) Вариант № 1 (библиотека stm32f10x.h)
#include "stm32f10x.h"
void Delay (unsigned int t) // функция задержки
{
unsigned int i;
for (i = 0;i<t; i++);
}
int main(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; //Затактировали порт (регистор = RCC_APB2RSTR + бит разрешения тактирования порта IOPCRST)
// НОЖКА 8
GPIOC->CRH &= ~GPIO_CRH_CNF8_0 & ~GPIO_CRH_CNF8_1;//определили режим работы CNF[1:0] = {0,0} = General purpose output push-pull
GPIOC->CRH |= GPIO_CRH_MODE8_0 | GPIO_CRH_MODE8_1; //определили направление + частоту в 50MHz
// НОЖКА 9
GPIOC->CRH &= ~GPIO_CRH_CNF9_0 & ~GPIO_CRH_CNF9_1;//определили режим работы CNF[1:0] = {0,0} = General purpose output push-pull
GPIOC->CRH |= GPIO_CRH_MODE9_0 | GPIO_CRH_MODE9_1; //определили направление + частоту в 50MHz
while (1) {
// ножку 8 - лог "0" ножку 9 - лог "1"
GPIOC->ODR &= ~GPIO_ODR_ODR8;
GPIOC->ODR |= GPIO_ODR_ODR9;
Delay(0xFFFFF); //задержечка (а на сколько?)
// ножку 8 - лог "1" ножку 9 - лог "0"
GPIOC->ODR |= GPIO_ODR_ODR8;
GPIOC->ODR &= ~GPIO_ODR_ODR9;
Delay(0xFFFFF); //задержечка (а на сколько?)
}
return 0;
}
2) Вариант № 2 (библиотека stm32f10x.h + BSRR и BRR)
#include "stm32f10x.h"
void Delay (unsigned int t) // функция задержки
{
unsigned int i;
for (i = 0;i<t; i++);
}
int main(void) {
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; //Затактировали порт (регистор = RCC_APB2RSTR + бит разрешения тактирования порта IOPCRST)
// НОЖКА 8
GPIOC->CRH &= ~GPIO_CRH_CNF8_0 & ~GPIO_CRH_CNF8_1;//определили режим работы CNF[1:0] = {0,0} = General purpose output push-pull
GPIOC->CRH |= GPIO_CRH_MODE8_0 | GPIO_CRH_MODE8_1; //определили направление + частоту в 50MHz
// НОЖКА 9
GPIOC->CRH &= ~GPIO_CRH_CNF9_0 & ~GPIO_CRH_CNF9_1;//определили режим работы CNF[1:0] = {0,0} = General purpose output push-pull
GPIOC->CRH |= GPIO_CRH_MODE9_0 | GPIO_CRH_MODE9_1; //определили направление + частоту в 50MHz
while (1) {
// ножку 8 - лог "0" ножку 9 - лог "1"
GPIOC->BRR = GPIO_ODR_ODR8;
GPIOC->BSRR = GPIO_ODR_ODR9;
Delay(0xFFFFF); //задержечка (а на сколько?)
// ножку 8 - лог "1" ножку 9 - лог "0"
GPIOC->BSRR = GPIO_ODR_ODR8;
GPIOC->BRR = GPIO_ODR_ODR9;
Delay(0xFFFFF); //задержечка (а на сколько?)
}
return 0;
}
3) Вариант № 3 (библиотека stm32f10x.h + stm32f10x_gpio.h и stm32f10x_rcc.h)
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
void Delay (unsigned int t) // функция задержки
{
unsigned int i;
for (i = 0;i<t; i++);
}
int main(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); // это функция разрешения тактирования порта С
GPIO_InitTypeDef Pinyshka; // создаём переменную (структуру) для ножки
// заполняем поля структуры для определения режима ножки
Pinyshka.GPIO_Pin = GPIO_Pin_9; // определяем ножку порта
Pinyshka.GPIO_Mode = GPIO_Mode_Out_PP; // определяем режим работы ножки
Pinyshka.GPIO_Speed = GPIO_Speed_50MHz; // так как режим на выход то определяем скорость работы ножки
// этой функцией мы определяем работу ножки (ссылка на заполненную структуру ножки) + (указываем порт необходимой нам ножки)
GPIO_Init( GPIOC , &Pinyshka);
// чтобы занова не заполнять структуру (меняем только поле определяющее ножку на порте)
Pinyshka.GPIO_Pin = GPIO_Pin_8;
// этой функцией мы определяем работу ножки (ссылка на заполненную структуру ножки) + (указываем порт необходимой нам ножки)
GPIO_Init( GPIOC , &Pinyshka);
while (1) {
// ножку 8 - лог "0" ножку 9 - лог "1"
GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_RESET);
GPIO_WriteBit(GPIOC, GPIO_Pin_9, Bit_SET);
Delay(0xFFFFF); //задержечка (а на сколько?)
// ножку 8 - лог "1" ножку 9 - лог "0"
GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_SET);
GPIO_WriteBit(GPIOC, GPIO_Pin_9, Bit_RESET);
Delay(0xFFFFF); //задержечка (а на сколько?)
}
return 0;
}
4) Пример № 4 (Используем кнопку)
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
void Delay (unsigned int t) // функция задержки
{
unsigned int i;
for (i = 0;i<t; i++);
}
int main(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); // это функция разрешения тактирования порта A
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE); // это функция разрешения тактирования порта С
GPIO_InitTypeDef Pinyshka; // создаём переменную (структуру) для ножки
// заполняем поля структуры для определения режима ножки(ЗАМЕТИМ определение 2-ух ножек)
Pinyshka.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_8; // определяем ножки!!! порта
Pinyshka.GPIO_Mode = GPIO_Mode_Out_PP; // определяем режим работы ножки
Pinyshka.GPIO_Speed = GPIO_Speed_50MHz; // так как режим на выход то определяем скорость работы ножки
// этой функцией мы определяем работу ножек (ссылка на заполненную структуру ножки) + (указываем порт необходимых нам ножек)
GPIO_Init( GPIOC , &Pinyshka);
// заполняем поля структуры для определения режима ножки
Pinyshka.GPIO_Pin = GPIO_Pin_0; // определяем ножку порта
Pinyshka.GPIO_Mode = GPIO_Mode_IN_FLOATING; // определяем режим работы ножки
// этой функцией мы определяем работу ножки (ссылка на заполненную структуру ножки) + (указываем порт необходимой нам ножки)
GPIO_Init( GPIOA , &Pinyshka);
while (1) {
if ( GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) ) //условие что кнопка нажата
{
GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_SET);
GPIO_WriteBit(GPIOC, GPIO_Pin_9, Bit_SET);
}
else {
GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_RESET);
GPIO_WriteBit(GPIOC, GPIO_Pin_9, Bit_RESET);
}
}
return 0;
}