Blue Pill 빠르게 시작하기 가이드에 오신 여러분을 환영합니다. 일단 가장 빠르게 블루필 보드에 관해 알아보고 진짜 사용법으로 넘어가겠습니다.
블루필(Blue Pill) 연결은 일반적으로 STM32F103C8T6 마이크로컨트롤러를 사용하는 보드인 블루필 보드를 다양한 개발 환경 및 하드웨어와 연결하는 것을 의미합니다. 주요 연결 방법은 ST-Link를 이용한 프로그래밍, 아두이노 IDE를 이용한 프로그래밍, 그리고 USB-UART 변환기를 이용한 프로그래밍 등이 있습니다.
1. ST-Link를 이용한 연결:
- 필요한 부품: ST-Link v2 또는 v3, 블루필 보드, 연결 케이블.
- 연결 방법: ST-Link와 블루필 보드의 SWDIO, SWCLK, GND, 3.3V 핀을 연결합니다.
- 프로그래밍: ST-Link Utility 또는 다른 프로그래밍 도구를 사용하여 펌웨어를 업로드합니다.
2. 아두이노 IDE를 이용한 연결:
필요한 부품:
USB-UART 변환기 (예: CH340), 블루필 보드, 점퍼 케이블, 아두이노 IDE.
연결 방법:
USB-UART 변환기와 블루필 보드의 RX, TX, GND, 3.3V 핀을 연결합니다.
부트모드 설정:
블루필 보드의 부트 핀을 설정하여 아두이노 부트로더를 통해 펌웨어를 업로드할 수 있도록 합니다.
프로그래밍:
아두이노 IDE에서 STM32 보드를 선택하고, 시리얼 통신을 통해 펌웨어를 업로드합니다.
3. USB-UART 변환기를 이용한 연결:
- 필요한 부품: USB-UART 변환기, 점퍼 케이블, 블루필 보드.
- 연결 방법: USB-UART 변환기와 블루필 보드의 RX, TX, GND, 3.3V 핀을 연결합니다.
- 프로그래밍: 터미널 프로그램을 사용하여 펌웨어를 업로드하거나, OpenOCD와 같은 도구를 사용할 수 있습니다.
참고사항:
블루필 보드는 일반적으로 디버깅을 위해 ST-Link를 사용하는 것이 일반적입니다.
아두이노 IDE를 사용하려면 부트로더를 설치해야 할 수 있습니다.
각 연결 방법마다 필요한 설정 및 소프트웨어 설치가 다를 수 있으므로, 사용하려는 방법에 대한 자세한 정보를 확인하는 것이 좋습니다.
참고정보: 안양시 동안구에서 블루필 보드 연결 관련 추가 정보: 안양시 동안구에서 블루필 보드 관련 부품이나 교육을 제공하는 곳을 찾으려면, 해당 지역의 전자 부품 상점이나 교육 기관을 검색해 볼 수 있습니다. 온라인 커뮤니티나 포럼에서 안양 지역 사용자들의 경험을 찾아보는 것도 도움이 될 수 있습니다. 캐어랩 031-479-6633
1. Blue Pill 모듈
산업 현장에선 우노나 메가에 들어간 ATmega328 이나 ATmega2560은 인기가 없습니다. 사양에 비해 비싸기도 하고 우선 느립니다. 수년전부터 STM8, STM32 시리즈가 실무 개발에서 인기가 많습니다.
STM32 시리즈를 사용한 BLUE PILL 모듈을 알아 봅니다.
<사양 정리>
Architecture 32 bit ARM Cortex M3
Operating Voltage 2.7V to 3.6V
CPU Frequency 72 MHz
Number of GPIO pins 37
Number of PWM pins 12
Analog Input Pins 10 (12 bit resolution)
I2C Peripherals 2
SPI Peripherals 2
CAN 2.0 Peripheral 1
Timers 3(16-bit), 1
Flash Memory 64KB
RAM 20KB
장점은 동작 속도가 빠릅니다. 램과 플래시도 더 넉넉합니다.
하드웨어 시리얼 포트도 3개 입니다.
저렴한 ST-LINK 라는 장비로 다운로드및 디버깅(ST 툴 사용시) 가능합니다.
그리고 BLUE PILL 보드를 실습하기 위해서 별도에 확장 보드를 제작 했습니다.
TFT 액정, W5500 유선랜 모듈, 버튼, LED, 부저 등을 배치 했습니다. 아래는 회로도 입니다.
2. 아두이노 개발 환경 설치
아두이노 IDE에서 사용하기 위한 환경을 설치 합니다.
아두이노 IDE 환경 설치
1. 보드 URL 추가
아두이노 IDE 에서 "파일 > 기본설정 > 추가 보드 관리자 URL"
부분에 아래 주소를 추가 합니다
https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json
설치후 보드 선택은 아래 그림과 같이 합니다.
2. 타겟 보드 선택
3. 업로드 방식 선택
펌웨어 업로드는 SWD 방식으로 합니다.
라이브러리 설치
STM32_TimerInterrupt
타이머 인터럽트를 사용하기 쉽게 쓸수 있습니다.
TFT_eSPI
SPI 방식의 인터페이스를 사용한 TFT액정을 제어 합니다.
이 라이브러리는 설치후 라이브러리 설치 폴더에 가서 User_Setup.h 파일을 수정해야 사용할 수 있습니다.
제작한 확장 보드에 맞게 수정한 파일입니다.
// User defined information reported by "Read_User_Setup" test & diagnostics example
#define USER_SETUP_INFO "User_Setup"
// Define to disable all #warnings in library (can be put in User_Setup_Select.h)
//#define DISABLE_ALL_LIBRARY_WARNINGS
// ##################################################################################
//
// Section 1. Call up the right driver file and any options for it
//
// ##################################################################################
// Define STM32 to invoke optimised processor support (only for STM32)
#define STM32
// Only define one driver, the other ones must be commented out
#define ILI9341_DRIVER // Generic driver for common displays
// For ST7789, ST7735, ILI9163 and GC9A01 ONLY, define the pixel width and height in portrait orientation
#define TFT_WIDTH 240
#define TFT_HEIGHT 320
// ##################################################################################
//
// Section 2. Define the pins that are used to interface with the display here
//
// ##################################################################################
// ###### EDIT THE PINs BELOW TO SUIT YOUR STM32 SPI TFT SETUP ######
// The TFT can be connected to SPI port 1 or 2
#define TFT_SPI_PORT 1 // SPI port 1 maximum clock rate is 55MHz
#define TFT_MOSI PA7
#define TFT_MISO PA6
#define TFT_SCLK PA5
//#define TFT_SPI_PORT 2 // SPI port 2 maximum clock rate is 27MHz
//#define TFT_MOSI PB15
//#define TFT_MISO PB14
//#define TFT_SCLK PB13
// Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select
#define TFT_CS PA4 // Chip select control pin to TFT CS
#define TFT_DC PB9 // Data Command control pin to TFT DC (may be labelled RS = Register Select)
#define TFT_RST PB8 // Reset pin to TFT RST (or RESET)
//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to processor reset
// Use an Arduino pin for initial testing as connecting to processor reset
// may not work (pulse too short at power up?)
// ##################################################################################
//
// Section 3. Define the fonts that are to be used here
//
// ##################################################################################
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
// Comment out the #define below to stop the SPIFFS filing system and smooth font code being loaded
// this will save ~20kbytes of FLASH
#define SMOOTH_FONT
// ##################################################################################
//
// Section 4. Other options
//
// ##################################################################################
// For the STM32 processor define the SPI port channel used (default 1 if undefined)
#define TFT_SPI_PORT 1 // Set to 1 for SPI port 1, or 2 for SPI port 2
// Define the SPI clock frequency, this affects the graphics rendering speed. Too
// fast and the TFT driver will not keep up and display corruption appears.
// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
// With an ILI9163 display 27 MHz works OK.
// #define SPI_FREQUENCY 1000000
// #define SPI_FREQUENCY 5000000
// #define SPI_FREQUENCY 10000000
// #define SPI_FREQUENCY 20000000
// #define SPI_FREQUENCY 27000000
//#define SPI_FREQUENCY 40000000
#define SPI_FREQUENCY 55000000 // STM32 SPI1 only (SPI2 maximum is 27MHz)
// #define SPI_FREQUENCY 80000000
// Optional reduced SPI frequency for reading TFT
#define SPI_READ_FREQUENCY 20000000
3. ST툴 설치 및 하드웨어 연결 방법
Blue Pill 보드는 부트로더가 설치되어있지 않습니다. 그래서 시리얼통신으로 펌웨어를 업로드 할 수 없습니다. 따라서 ST-Link 라는 장비를 써서 전용 핀을 통해서 업로드 합니다.
ST사에서 제공하는 유틸 두가지를 설치 해야 합니다.
1. STM32 ST-LINK Utility
https://www.st.com/en/development-tools/stsw-link004.html
페이지 하단에 다운로드 버튼이 있습니다 (회원 가입 필요)
설치후 ST-Link 유틸을 실행 해봅니다. 혹시 mfc140.dll 에러가 발생한다면 추가로 아래 파일을 설치 합니다.
Microsoft Visual C++ 2015 재배포 가능 패키지 Update 3
https://www.microsoft.com/ko-KR/download/details.aspx?id=53840
반드시 x86 버전을 설치 하세요.
2. STM32CubeProgrammer 설치
https://www.st.com/en/development-tools/stm32cubeprog.html
3. ST-Link 와 Blue Pill 보드 연결하기
타겟 보드의 전원은 USB-C 케이블에서 받기 때문에 3가닥의 선만 연결 합니다.
아래의 그림에서 2,4,6 번만 사용합니다.
Blue Pill 보드의 우측 4핀중 3핀을 이름과 일치되게 연결 합니다
반드시 사용중인 ST-Link 의 본체에 적힌 핀 이름을 확인하고 연결하세요. 호환 제품이므로 제조사 마다 GND핀의
위치가 다른 경우가 있습니다.
4. 펌웨어 올리기
업로드가 정상적으로 되는지 확인하기 위해서 데모 코드를 아래와 같이 만듭니다.
지금부터는 파일을 나누어서 코드를 만듭니다 main 에 너무 많은 코드가 들어가기 때문에 lcd, switch 파일을
프로젝트에 추가 합니다.
코드의 내용은 나중에 분석하고 우선 업로드가 정상적으로 되는 환경을 검증 합니다.
main.ino
#include "STM32TimerInterrupt.h"
#include <TFT_eSPI.h>
#include <SPI.h>
#include <IWatchdog.h>
// system
#define BUILTIN_LED PC13 // A.L
STM32Timer ITimer(TIM1);
uint32_t start = 0;
uint32_t loop_time = 0;
uint32_t max_loop_time = 0;
uint8_t count100us = 0;
// buzzer
#define BUZZER PA8
// switch
#define SW_0_PIN PB5
#define SW_1_PIN PB4
#define SW_2_PIN PB3
#define SW_3_PIN PA15
struct SW {
uint8_t pin;
bool flag;
uint8_t delay;
};
SW sw_0;
SW sw_1;
SW sw_2;
SW sw_3;
uint16_t test_number;
// network
#define W5500_RESET PB7
#define W5500_CS PB6 // nSS
// TFT LCD
#define TFT_RESET PB8
#define TFT_CS PA4 // NSS1
TFT_eSPI tft = TFT_eSPI();
bool flag_start_paint = false;
uint8_t seqRefreshTFT = 0;
uint16_t delayRefreshTFT = 0;
void TimerHandler() // 100us
{
count100us++;
}
void setup() {
// put your setup code here, to run once:
start = micros();
tone(BUZZER, 500, 500);
IWatchdog.begin(500000); // 500ms
Serial.begin(115200);
while (!Serial)
;
sw_0.pin = SW_0_PIN;
sw_1.pin = SW_1_PIN;
sw_2.pin = SW_2_PIN;
sw_3.pin = SW_3_PIN;
pinMode(sw_0.pin, INPUT);
pinMode(sw_1.pin, INPUT);
pinMode(sw_2.pin, INPUT);
pinMode(sw_3.pin, INPUT);
pinMode(BUILTIN_LED, OUTPUT);
digitalWrite(BUILTIN_LED, HIGH); // OFF
pinMode(BUZZER, OUTPUT);
digitalWrite(BUZZER, HIGH); // OFF
pinMode(W5500_CS, OUTPUT);
pinMode(W5500_RESET, OUTPUT);
pinMode(TFT_RESET, OUTPUT);
pinMode(TFT_CS, OUTPUT);
tft.init();
tft.fillScreen(TFT_RED);
tft.setRotation(0);
digitalWrite(W5500_RESET, LOW); // 리셋 A.L
digitalWrite(TFT_RESET, HIGH); // 리셋 A.L
ITimer.attachInterruptInterval(100, TimerHandler); // 100us
loop_time = micros() - start;
Serial.println("setup time: " + String(loop_time) + "us");
IWatchdog.reload();
IWatchdog.begin(50000); // 50ms
}
void loop() {
// put your main code here, to run repeatedly:
if (count100us >= 50) { // 5ms
count100us = 0;
start = micros();
digitalWrite(BUILTIN_LED, LOW); // ON
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
refresh_TFT();
check_SW_0();
check_SW_1();
check_SW_2();
check_SW_3();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
loop_time = micros() - start;
if (loop_time > max_loop_time) {
max_loop_time = loop_time;
Serial.println("max loop time: " + String(max_loop_time) + "us");
}
digitalWrite(BUILTIN_LED, HIGH); // OFF
}
IWatchdog.reload();
}
lcd.ino
// lcd
void refresh_TFT(void) { // 5ms
if (flag_start_paint == true) {
//start = micros();
uint8_t thousands_digit;
static uint8_t last_thousands_digit;
uint8_t hundreds_digit;
static uint8_t last_hundreds_digit;
uint8_t tens_digit;
static uint8_t last_tens_digit;
uint8_t ones_digit;
static uint8_t last_one_digit;
thousands_digit = test_number / 1000; // 천의 자릿수 계산
hundreds_digit = (test_number % 1000) / 100; // 백의 자릿수 계산
tens_digit = (test_number % 100) / 10; // 십의 자릿수 계산
ones_digit = test_number % 10; // 일의 자릿수 계산
switch (seqRefreshTFT) {
case 0:
tft.setViewport(0, 0, 26, 36);
//tft.fillScreen(TFT_BLACK); // 1090us
tft.setTextDatum(TL_DATUM);
tft.drawChar(3, 3, last_thousands_digit + 0x30, TFT_BLACK, TFT_BLACK, 4); // 2900us
seqRefreshTFT = 1;
break;
case 1:
tft.drawChar(3, 3, thousands_digit + 0x30, TFT_WHITE, TFT_BLACK, 4); // 2900us
last_thousands_digit = thousands_digit;
seqRefreshTFT = 2;
break;
case 2:
tft.setViewport(26, 0, 26, 36);
//tft.fillScreen(TFT_BLACK); // 1090us
tft.setTextDatum(TL_DATUM);
tft.drawChar(3, 3, last_hundreds_digit + 0x30, TFT_BLACK, TFT_BLACK, 4); // 2900us
seqRefreshTFT = 3;
break;
case 3:
tft.drawChar(3, 3, hundreds_digit + 0x30, TFT_GREEN, TFT_BLACK, 4); // 2900us
last_hundreds_digit = hundreds_digit;
seqRefreshTFT = 4;
break;
case 4:
tft.setViewport(52, 0, 26, 36);
//tft.fillScreen(TFT_BLACK); // 1090us
tft.setTextDatum(TL_DATUM);
tft.drawChar(3, 3, last_tens_digit + 0x30, TFT_BLACK, TFT_BLACK, 4); // 2900us
seqRefreshTFT = 5;
break;
case 5:
tft.drawChar(3, 3, tens_digit + 0x30, TFT_YELLOW, TFT_BLACK, 4); // 2900us
last_tens_digit = tens_digit;
seqRefreshTFT = 6;
break;
case 6:
tft.setViewport(78, 0, 26, 36);
//tft.fillScreen(TFT_BLACK); // 1090us
tft.setTextDatum(TL_DATUM);
tft.drawChar(3, 3, last_one_digit + 0x30, TFT_BLACK, TFT_BLACK, 4); // 2900us
seqRefreshTFT = 7;
break;
case 7:
tft.drawChar(3, 3, ones_digit + 0x30, TFT_BLUE, TFT_BLACK, 4); // 2900us
last_one_digit = ones_digit;
seqRefreshTFT = 0;
flag_start_paint = false;
break;
}
}
}
switch.ino
// switch
void check_SW_0(void) {
if (digitalRead(sw_0.pin) == HIGH) { // 버튼 누름
if (sw_0.delay++ >= 10) { // 5ms 마다 증가해서 누른채로 50ms지나면
if (sw_0.flag == false) {
sw_0.flag = true;
Serial.println("sw_0");
tone(BUZZER, 1000, 100);
//if (flag_start_paint == false) flag_start_paint = true;
}
}
} else // 버튼 놓음, 또는 채터링시에도 변수 리셋
{
sw_0.delay = 0;
sw_0.flag = false;
}
}
void check_SW_1(void) {
if (digitalRead(sw_1.pin) == HIGH) { // 버튼 누름
if (sw_1.delay++ >= 10) { // 5ms 마다 증가해서 누른채로 50ms지나면
if (sw_1.flag == false) {
sw_1.flag = true;
Serial.println("sw_1");
tone(BUZZER, 1000, 100);
test_number++;
if (flag_start_paint == false) flag_start_paint = true;
}
}
} else // 버튼 놓음, 또는 채터링시에도 변수 리셋
{
sw_1.delay = 0;
sw_1.flag = false;
}
}
void check_SW_2(void) {
if (digitalRead(sw_2.pin) == HIGH) { // 버튼 누름
if (sw_2.delay++ >= 10) { // 5ms 마다 증가해서 누른채로 50ms지나면
if (sw_2.flag == false) {
sw_2.flag = true;
Serial.println("sw_2");
tone(BUZZER, 1000, 100);
test_number++;
if (flag_start_paint == false) flag_start_paint = true;
}
}
} else // 버튼 놓음, 또는 채터링시에도 변수 리셋
{
sw_2.delay = 0;
sw_2.flag = false;
}
}
void check_SW_3(void) {
if (digitalRead(sw_3.pin) == HIGH) { // 버튼 누름
if (sw_3.delay++ >= 10) { // 5ms 마다 증가해서 누른채로 50ms지나면
if (sw_3.flag == false) {
sw_3.flag = true;
Serial.println("sw_3");
tone(BUZZER, 1000, 100);
if (flag_start_paint == false) flag_start_paint = true;
}
}
} else // 버튼 놓음, 또는 채터링시에도 변수 리셋
{
sw_3.delay = 0;
sw_3.flag = false;
}
}
위 참고 자료는 위키독 알고 쓴 아두이노 교제입니다. ㅎㅎ 교제~
전자 명장 김랑기 노션
linkbay.co.kr 주소는 네이버 스마트 스토어로 연결
참고 책은 ARM 프로그래밍 실무
AIoT의 시작, 아두이노 우노 R4 WIFI 실전 가이드
ShareTechnote 기술 자료https://www.sharetechnote.com/
'STM32' 카테고리의 다른 글
STM32 중급 과정 Peripheral Hands-On: I2C 7-1 (0) | 2025.08.21 |
---|---|
STM32 중급 과정 I2C 개요 7 (0) | 2025.08.20 |
STM32 중급 과정 Peripheral Hands-On: SPI 6-1 (0) | 2025.08.19 |
STM32 중급 과정 SPI 개요 6 (2) | 2025.08.18 |
STM32 입문 마스터 과정 6, External Interrupt 실습 (0) | 2025.08.14 |
STM32 입문 마스터 과정 5, GPIO 실습 (0) | 2025.08.14 |
STM32 입문 마스터 과정 4, STM32U0 Microcontroller (0) | 2025.08.14 |
STM32 입문 마스터 과정 3, STM32CubeMX Configuration (0) | 2025.08.14 |
더욱 좋은 정보를 제공하겠습니다.~ ^^