Программирование и прошивка STM32 на примере STM32F103C8T6

Я приобрел на AliExpress  плату с микроконтроллером STM32F103C8T6 - ту самую "Blue Pill":
STM32 распиновка

Расшифруем обозначение этого микроконтроллера:

STM32 - семейство 32-битных ARM-микроконтроллеров на ядре Cortex;
F - микроконтроллер общего назначения;
103 - линейка Performance Line;
C - 48/49 выводов;
8 - объем флэш-памяти 64 килобайта;
T - корпус LQFP;
6 - диапазон температур -40...+85 °C

Микроконтроллер STM32F103C8T6 основан на ядре Cortex-M3.
Особенности этого ядра:

  • однотактное умножение данных;
  • аппаратное деление данных;
  • поддержка набора инструкций Thumb-2.

Распиновка платы микроконтроллера:

распиновка STM32

Программирование микроконтроллера STM32F103C8T6

Среда программирования

В качестве среды программирования я выбрал легковесную EmBitz - инсталлятор версии 1.11 для Windows доступен (был доступен для жителей и ) для скачивания на www.embitz.org.

Для поддержки современных микроконтроллеров необходимо загрузить обновление (доступно (было доступно для жителей и ) для скачивания на Update for EmBitz 1.11) и распаковать его в папку с установленной средой EmBitz.

!!! Использование более свежих версий EmBitz жителями  и  проблематично из-за встроенных ограничений (предложения программы о скачивании новой версии 2.41 следует игнорировать).

В качестве примера создания программы разберем традиционный для микроконтроллеров Hello, World! - мигание светодиодом.

Выбираем в меню команду File ► New ► Project... для создания проекта:
программирование STM32

Задаем требуемую категорию проекта - STmicro-ARM - и нажимаем кнопку Go:
программы для STM32

Указываем имя проекта (Project title) и папку (Folder ...), в которой будет создана папка с проектом:
EmBitz
(остальные поля заполнятся автоматически, файл проекта имеет расширение ebp). Нажимаем кнопку Next >.

В открывшемся окне будет указан используемый компилятор - ARM GCC Compiler .... Нажимаем кнопку Next >.

Выбираем семейство микроконтроллеров - Cortex_M3 (...) - и нажимаем кнопку Next >:
как программировать STM32

Выбираем серию микроконтроллеров - STM32F10x - и нажимаем кнопку Next >:
программирование STM32F103C8T6

Выбираем процессор микроконтроллера - STM32F103C8 - и нажимаем кнопку Finish:
программы для STM32F103C8T6

"Галочки" указывают на использование библиотеки SPL и создание hex-файла с прошивкой для цели Release.

Затем в двух открывшихся окнах, связанных с отладкой, нажимаем кнопки OK.

В левой части среды появляется дерево файлов проекта:
среда EMBitz

  • Sources
  • Headers
  • ASM Sources
  • Others

Редактируем файл stm32f10.h в , раскомментируя строку :
написание программ в среде EmBitz

Код программы для мигания светодиодом, подключенным на плате , вводим в файле main.c:

#include "stm32f10x_conf.h"
#include "stm32f10x.h"

volatile uint64_t msecs; //current msecs storage

uint64_t get_msecs(void)
{
    volatile uint64_t now;
    __disable_irq();
    now=msecs;
    __enable_irq();
    return now;
}

void SysTick_Handler(void)
{
    msecs++; //current msecs increment
}

void delay_ms(uint64_t delay)
{
    uint64_t start; //variable to store the time
    start=get_msecs();
    while(1)
    {
        if((get_msecs()-start)>delay) //if current time is elapsed, execute the if condition
        {
            break;
        }
    }
}

int main(void)
{
    const uint64_t DELAY_MS = 500;

    __disable_irq();

    SystemInit(); //init

    //systick init
    SysTick->LOAD=(SystemCoreClock / 1000)-1;
    SysTick->VAL=0;
    SysTick->CTRL=7; //0b00000111;

    //LED init
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //enable GPIOC clock
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //set LED pin as PC13
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //output push-pull
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //medium speed
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    __enable_irq();

    GPIO_ResetBits(GPIOC, GPIO_Pin_13); //LED on
    while(1)
    {
        GPIO_SetBits(GPIOC, GPIO_Pin_13);  //LED off
        delay_ms(DELAY_MS);
        GPIO_ResetBits(GPIOC, GPIO_Pin_13);  //LED on
        delay_ms(DELAY_MS);
    }
}

Считывание dummy=GPIOC->ODR вставлено в код задержки для предотвращения удаления цикла задержки при оптимизации.

Переключаем цель проекта на Release:
STM32 EmBitz

Для компиляции и генерации hex-файла, который мы и будем использовать для прошивки, выбираем команду меню Build target:

После успешного завершения в журнале событий отображается отладочное сообщение - пример сообщения:
программирование STM32

Прошивка микроконтроллера STM32F103C8T6

Программатор

Я использую тот же программатор ST-LINK V2 , который я применяю для прошивки STM8-микроконтроллеров:
ST-LINK V2

Для соединения программатора с микроконтроллером STM32 требуются четыре провода (интерфейс SWD):

  • SWCLK - линия тактирования
  • SWDIO - линия данных
  • GND - "земля"
  • 3.3V - напряжение питания 3,3 В

С помощью утилиты, доступной для загрузки на сайте ST - STSW-LINK007, я обновил прошивку программатора до версии 2.J37.S7.

Загрузка прошивки в микроконтроллер

Для прошивки я использую утилиту STM32CubeProgrammer, доступную для загрузки на сайте ST.

Присоединяем плату микроконтроллера к программатору и подключаем программатор к USB-порту компьютера:
прошивка STM32

Запускаем приложение и нажимаем кнопку  для установления соединения приложения с программатором (если соединение не устанавливается, нужно повторить попытку!). После успешного установления соединения отображается надпись  и отображается информация о программаторе и микроконтроллере:

Выбираем и загружаем hex-файл (hello.hex в папке src/hello/bin/Release) с прошивкой, нажимая на Open file или нажимая на + и выбирая команду Open file:

Нажимаем кнопку  для загрузки прошивки в микроконтроллер:

После успешного завершения процесса прошивки выдается сообщение (если выдается сообщение об ошибке, нужно повторить попытку!):
прошивка STM32

Нажимаем кнопку  для разрыва соединения приложения с программатором.

Перезагружаем микроконтроллер, нажимая кнопку сброса на плате:
как прошить STM32

Вуаля - светодиод мигает (частота мигания составляет 1 Гц (период равен 1 с = 500 мс (горит) + 500 мс (погашен)), загруженная прошивка работает!
STM32 мигание светодиодом

Подключение дисплея от Nokia 5110

Подключим к МК дисплей от Nokia 5110 (такие дисплеи доступны на AliExpress, я использовал такой дисплей в своем импульсном металлодетекторе на Arduino):

дисплей МК
RST A3
CE A4
DC A2
DIN A1
CLK A0
VCC 3.3
LIGHT x
GND G

Исходный код (main.c):

#include "stm32f10x_conf.h"
#include "stm32f10x.h"

#include "f10x-pcd8544.h"

#include <stdio.h>

/* LCD pins:
RST -> A3
CE (SCE)  -> A4
DC  -> A2
DIN (MOSI) -> A1
CLK (SCLK) -> A0
VCC -> 3.3V
LIGHT -> x
GND -> GND
*/
volatile uint64_t msecs; //current msecs storage

uint64_t get_msecs(void)
{
    volatile uint64_t now;
    __disable_irq();
    now=msecs;
    __enable_irq();
    return now;
}

void SysTick_Handler(void)
{
    msecs++; //current msecs increment
}

void delay_ms(uint64_t delay)
{
    uint64_t start; //variable to store the time
    start=get_msecs();
    while(1)
    {
        if((get_msecs()-start)>delay) //if current time is elapsed, execute the if condition
        {
            break;
        }
    }
}

int main(void)
{
    const uint64_t DELAY_MS = 500;

    __disable_irq();

    SystemInit(); //init

    //systick init
    SysTick->LOAD=(SystemCoreClock / 1000)-1;
    SysTick->VAL=0;
    SysTick->CTRL=7; //0b00000111;

    lcd8544_init(); //LCD init

    //LED init
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //enable GPIOC clock
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //set LED pin as PC13
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //output push-pull
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //medium speed
    GPIO_Init(GPIOC, &GPIO_InitStructure);

    __enable_irq();

    lcd8544_clear();
    lcd8544_putstr(0,0,"HELLO, WORLD!",0);
    lcd8544_refresh(); //LCD out

    GPIO_ResetBits(GPIOC, GPIO_Pin_13); //LED on
    while(1)
    {
        GPIO_SetBits(GPIOC, GPIO_Pin_13);  //LED off
        delay_ms(DELAY_MS);
        GPIO_ResetBits(GPIOC, GPIO_Pin_13);  //LED on
        delay_ms(DELAY_MS);
    }
}

Использование АЦП

Продолжение следует

Яндекс.Метрика