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.
Недавні записи
- DShot receiver on STM32
- CRSF to PWM
- U-FOC PC Monitor для Chrome browser
- Фільтрація Back-EMF. Безсенсорні BLDC мотори
- Text to speech. Українська мова
- LCD Display ST7567S (IIC)
- Розпізнавання мови (Speech recognition)
- Selenium
- Комп'ютерний зір (Computer Vision)
- Деякі думки про точність вимірювань в електроприводі
Tags
bldc timer eeprom dht11 soldering stm32 html meteo avr rtc battery hih-4000 foc gps sensors dma mpu-6050 flask nodemcu st-link docker git esp8266 tim bkp eb-500 motor mongodb ssd1306 bluetooth pwm adc sms smd brushless css java-script pmsm rfid displays mpx4115a atmega barometer remap capture servo led web programmator uart 3d-printer encoder examples gpio books websocket wifi i2c watchdog solar usart piezo ngnix ssd1331 options nvic raspberry-pi bme280 usb lcd flash max1674 exti python mpu-9250 dc-dc ethernet bmp280 rs-232
Архіви