3. STM32. Програмування STM32F103. GPIO
У попередній статті ми використовували простеньку програму, яка блимає світлодіодом. Трохи модифікуємо її і спробуємо розібратися, як налаштувати виводи мікроконтролера для роботи на вхід і вихід. C13 налаштуємо як вихід. До нього підключений світлодіод на тестовій платі. B0 налаштуємо на вхід і підключимо до нього кнопку. У натиснутому положенні кнопка має замикати ногу B0 на землю.
Код програми
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
int main(void)
{
int i;
GPIO_InitTypeDef GPIO_InitStructure;
/* Initialize LED which connected to PC13 */
// Enable PORTC Clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
/* Configure the GPIO_LED pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
//GPIO_SetBits(GPIOC, GPIO_Pin_13); // Set C13 to High level ("1")
GPIO_ResetBits(GPIOC, GPIO_Pin_13); // Set C13 to Low level ("0")
/* Initialize Button input PB0 */
// Enable PORTB Clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/* Configure the GPIO_BUTTON pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
while (1) {
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) != 0) {
/* Toggle LED which connected to PC13*/
GPIOC->ODR ^= GPIO_Pin_13; // Invert C13
/* delay */
for(i=0;i<0x100000;i++);
/* Toggle LED which connected to PC13*/
GPIOC->ODR ^= GPIO_Pin_13;
/* delay */
for(i=0;i<0x100000;i++);
}
else {
GPIO_SetBits(GPIOC, GPIO_Pin_13);
}
}
}
Перш за все роздивимось, що ми інклудимо:
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
stm32f10x.h - стосується конкретної серії мікроконтролера; stm32f10x_gpio.h - стосується GPIO виводів портів, з чим ми і будемо працювати; stm32f10x_rcc.h - А це що таке? Справа у тому, що у STM32 усі модулі (GPIO, ADC, EXTI, USART, I2C, SPI, та інші) після включення мікроконтролера відключені від тактування. І ми маємо програмно вмикати тактування тій периферії, яку плануємо використовувати. Крім того, ми можемо налаштувати частоту тактування деяких модулів окремо. Докладно про тактування буде у наступній статті.
Зараз нам треба засвоїти, що перед тим, як використовувати чи то порт, чи то інтерфейс, чи то який-небудь модуль, треба подати на нього тактування. У stm32f10x_rcc.h описані функції, які керують тактуванням.
Дивимося у програмі рядок, який вмикає тактування порту GPIOC:
/* Initialize LED which connected to PC13 */
// Enable PORTC Clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
Далі виконуємо налаштування вивода порта. В нашому випадку PC13 (на тестовій платі до нього підключений світлодіод) налаштовуємо як вихід. Налаштування виконуються через структуру GPIO_InitTypeDef.
/* Configure the GPIO_LED pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
Нарешті можемо задати високий чи низький рівень на виході PC13:
//GPIO_SetBits(GPIOC, GPIO_Pin_13); // Set C13 to High level ("1")
GPIO_ResetBits(GPIOC, GPIO_Pin_13); // Set C13 to Low level ("0")
Коли задаємо високий рівень, світлодіод не горить, низький - горить.
Далі виконуємо конфігурацію PB0. Він буде працювати як вхід з підтяжкою до "1" (GPIO_Mode_IPU). Тобто, коли кнопка не натиснута (нога PB0 висить у повітрі), на вході PB0 буде "1".
/* Initialize Button input PB0 */
// Enable PORTB Clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/* Configure the GPIO_BUTTON pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
Стан кнопки опитується функцією:
GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0)
Програма опитує стан кнопки і блимає світлодіодом тільки коли кнопка не натиснута, тобто коли на вході B0 високий рівень.
Підключимо замість кнопки датчик руху HC-SR501. Зверніть увагу, живлення датчика 5В. Тепер світлодіод буде блимати, коли сенсор руху зафіксує рух. Вітаю! Тепер можна трохи погратися: помахати перед сенсором руху руками, поганяти перед ним кота, собаку, інших домашніх тварин.
Пам`ятка
Структура GPIO_InitTypeDef для налаштування виводів порта має наступні параметри:- GPIO_Pin - номера пінів, які конфігуруються. Приклад для декількох пінів: GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
- GPIO_Speed - задає швидкість для обраних пінів. Може мати наступні значення: GPIO_Speed_10MHz, GPIO_Speed_2MHz, GPIO_Speed_50MHz
- GPIO_Mode - задає режим роботи пінів. Може мати наступні значення:
- GPIO_Mode_AIN — аналоговий вхід;
- GPIO_Mode_IN_FLOATING — вхід без підтяжки (Float)
- GPIO_Mode_IPD — вхід з підтяжкою до землі (Pull-down)
- GPIO_Mode_IPU — вхід з підтяжкою до живлення (Pull-up)
- GPIO_Mode_Out_OD — вихід з відкритим стоком (Open Drain)
- GPIO_Mode_Out_PP — вихід з двома станами (Push-Pull)
- GPIO_Mode_AF_OD — вихід з відкритим стоком для альтернативних функцій (Alternate Function). Використовується коли виводи керуються периферією, яка може бути задіяна на цьому виводі. Наприклад USART, I2C тощо.
- GPIO_Mode_AF_PP — те саме що і перед цим, але з двома станами.
Зауваження
Ви могли звернути увагу, що у програмі ми двічі викликаємо функцію RCC_APB2PeriphClockCmd для різних портів:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
Це можна зробити і один раз таким чином:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOB, ENABLE);
Програма буде менша за розміром. Так зазвичай і роблять. Вмикають тактування усім модулям, налаштовують усі переривання і так далі. Це правильний шлях до оптимізації програми. Але на етапі вивчення мікроконтролера, тільки задля наочності, я буду писати саме так, як у цьому прикладі. Щоб було ясно: що і за чим треба увімкнути і як налаштувати, щоб налаштувати ту чи іншу периферію. Це буде не завжди раціонально, але завжди зрозуміло.
Бажаю успіхів!
Дивись також:
- 1. STM32. Програмування STM32F103. Тестова плата. Прошивка через UART та через ST-Link
- 2. STM32. Програмування. IDE для STM32
- 3. STM32. Програмування STM32F103. GPIO
- 4. STM32. Програмування STM32F103. Тактування
- 5. STM32. Програмування STM32F103. USART
- 6. STM32. Програмування STM32F103. NVIC
- 7. STM32. Програмування STM32F103. ADC
- 8. STM32. Програмування STM32F103. DMA
- 9. STM32. Програмування STM32F103. TIMER
- 10. STM32. Програмування STM32F103. TIMER. Захоплення сигналу
- 11. STM32. Програмування STM32F103. TIMER. Encoder
- 12. STM32. Програмування STM32F103. TIMER. PWM
- 13. STM32. Програмування STM32F103. EXTI
- 14. STM32. Програмування STM32F103. RTC
- 15. STM32. Програмування STM32F103. BKP
- 16. STM32. Програмування STM32F103. Flash
- 17. STM32. Програмування STM32F103. Watchdog
- 18. STM32. Програмування STM32F103. Remap
- 19. STM32. Програмування STM32F103. I2C Master
- 20. STM32. Програмування STM32F103. I2C Slave
- 21. STM32. Програмування STM32F103. USB
- 22. STM32. Програмування STM32F103. PWR
- 23. STM32. Програмування STM32F103. Option bytes
- 24. STM32. Програмування STM32F103. Bootloader
- STM32. Скачати приклади
- System Workbench for STM32 Інсталяція на Ubuntu
- Keil uVision5 – IDE для STM32
- IAR Workbench – IDE для STM32
- Керування безколекторним двигуном постійного струму (BLDC) за допомогою STM32
- Керування PMSM за допомогою STM32
Всередині нескінченного циклу код поплив, ну і зайве треба видалити. А можливо краще в цьому прикладі блимати світлодіодом не toggle, а саме "підняти, почекати, опустити, почекати". Так наглядніше буде і завжди під рукою команди для "підняти" та "опустити".
"stm32f10x.h – стосується GPIO виводів портів, з чим ми і будемо працювати;" - потрібно виправити помилку.
Дякую. Виправив.
В циклі красоту наведіть будь ласка. Там зайвий код, про який я вде писав і в попередній статті вже пофіксили. І окріми того сам код поплив (пару переносів строки не вистачає)
Коли вмикати переферію не застосовуючи функцію RCC_APB2PeriphClockCmd. Треба робити затримку після вмикання переферії, чи відразу можна перейти до інших маніпуляцій з портом?
GPIO_InitTypeDef GPIO_InitStructure; Я так розумію що це "GPIO_InitStructure" створення указника на структуру "GPIO_InitTypeDef". У даному разі нема значення як налаштовані всі інші пині порта. Якщо потрібно налаштувати один пін з порта, то указник треба стровати якось так: "GPIOC_InitPinLed"?
#define GPIO_Pin_13 ((uint16_t)0x2000) /*!< Pin 13 selected */ Для зручності написання коду можливо міняти ці дефайни в проєкті? Або створювати свої з тими значеннями зсунення біт?
Можете назвати і GPIOC_InitPinLed - як завгодно. Та коли на цьому ж порту доведеться додати, скажімо, кнопки, тоді доведеться знов якось перейменувати. Для зручності можна робити так: #define LED_PIN GPIO_Pin_13 І далі у коді використовувати LED_PIN, а не GPIO_Pin_13. GPIO_Pin_13 чіпати не треба. Його зроблено, щоб полегшити життя і не морочити собі голову з бітами.
Вчора почав займатися стм, вирішив глянути ці статті, бо по двигунам все було дуже добре розказано. Але взагалі не можу зрозуміти на якій бібліотеці пише тут автор? Типу hal, cmsis, LL, spl?
Шановний Дмитро, код написаний на SPL. Хочу зауважити, що цим статтям більше ніж 8 років, тому рекомендую розглядати ці статті як загальний опис по роботі з периферією мікроконтролера. Сам код на оновлених бібліотеках може працювати не так, я то було 8 років тому. На жаль у світі програмування все занадто швидко змінюється. У сучасних реаліях я б рекомендував писати на HAL та LL.
Недавні записи
- Фільтрація Back-EMF. Безсенсорні BLDC мотори
- Text to speech. Українська мова
- LCD Display ST7567S (IIC)
- Розпізнавання мови (Speech recognition)
- Selenium
- Комп'ютерний зір (Computer Vision)
- Деякі думки про точність вимірювань в електроприводі
- Датчики Холла 120/60 градусів
- Модуль драйверів напівмосту IGBT транзисторів
- Драйвер IGBT транзисторів на A316J
Tags
barometer dht11 wifi bmp280 meteo ssd1306 uart books dc-dc lcd tim ssd1331 timer programmator battery exti mpx4115a motor flask nodemcu usb dma html java-script rs-232 st-link 3d-printer rfid esp8266 nvic encoder gpio piezo eb-500 brushless docker sms pmsm ngnix servo examples avr led smd i2c bkp eeprom usart solar soldering python flash stm32 raspberry-pi bme280 mpu-9250 hih-4000 foc bldc sensors rtc pwm capture adc max1674 atmega gps bluetooth remap mongodb mpu-6050 websocket css git watchdog displays ethernet web options
Архіви