Я приобрел на AliExpress плату с микроконтроллером STM32F103C8T6 - ту самую "Blue Pill":
Расшифруем обозначение этого микроконтроллера:
STM32 - семейство 32-битных ARM-микроконтроллеров на ядре Cortex;
F - микроконтроллер общего назначения;
103 - линейка Performance Line;
C - 48/49 выводов;
8 - объем флэш-памяти 64 килобайта;
T - корпус LQFP;
6 - диапазон температур -40...+85 °C
Микроконтроллер STM32F103C8T6 основан на ядре Cortex-M3.
Особенности этого ядра:
- однотактное умножение данных;
- аппаратное деление данных;
- поддержка набора инструкций Thumb-2.
Распиновка платы микроконтроллера:
Программирование микроконтроллера STM32F103C8T6
Среда программирования
В качестве среды программирования я выбрал легковесную EmBitz - инсталлятор версии 1.11 для Windows доступен (был доступен для жителей и ) для скачивания на www.embitz.org.
Для поддержки современных микроконтроллеров необходимо загрузить обновление (доступно (было доступно для жителей и ) для скачивания на Update for EmBitz 1.11) и распаковать его в папку с установленной средой EmBitz.
!!! Использование более свежих версий EmBitz жителями и проблематично из-за встроенных ограничений (предложения программы о скачивании новой версии 2.41 следует игнорировать).
В качестве примера создания программы разберем традиционный для микроконтроллеров Hello, World! - мигание светодиодом.
Выбираем в меню команду File ► New ► Project... для создания проекта:
Задаем требуемую категорию проекта - STmicro-ARM - и нажимаем кнопку Go:
Указываем имя проекта (Project title) и папку (Folder ...), в которой будет создана папка с проектом:
(остальные поля заполнятся автоматически, файл проекта имеет расширение ebp). Нажимаем кнопку Next >.
В открывшемся окне будет указан используемый компилятор - ARM GCC Compiler .... Нажимаем кнопку Next >.
Выбираем семейство микроконтроллеров - Cortex_M3 (...) - и нажимаем кнопку Next >:
Выбираем серию микроконтроллеров - STM32F10x - и нажимаем кнопку Next >:
Выбираем процессор микроконтроллера - STM32F103C8 - и нажимаем кнопку Finish:
"Галочки" указывают на использование библиотеки SPL и создание hex-файла с прошивкой для цели Release.
Затем в двух открывшихся окнах, связанных с отладкой, нажимаем кнопки OK.
В левой части среды появляется дерево файлов проекта:
- Sources
- Headers
- ASM Sources
- Others
Редактируем файл stm32f10.h в , раскомментируя строку :
Код программы для мигания светодиодом, подключенным на плате , вводим в файле 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:
Для компиляции и генерации hex-файла, который мы и будем использовать для прошивки, выбираем команду меню Build target:
После успешного завершения в журнале событий отображается отладочное сообщение - пример сообщения:
Прошивка микроконтроллера STM32F103C8T6
Программатор
Я использую тот же программатор ST-LINK V2 , который я применяю для прошивки STM8-микроконтроллеров:
Для соединения программатора с микроконтроллером STM32 требуются четыре провода (интерфейс SWD):
- SWCLK - линия тактирования
- SWDIO - линия данных
- GND - "земля"
- 3.3V - напряжение питания 3,3 В
С помощью утилиты, доступной для загрузки на сайте ST - STSW-LINK007, я обновил прошивку программатора до версии 2.J37.S7.
Загрузка прошивки в микроконтроллер
Для прошивки я использую утилиту STM32CubeProgrammer, доступную для загрузки на сайте ST.
Присоединяем плату микроконтроллера к программатору и подключаем программатор к USB-порту компьютера:
Запускаем приложение и нажимаем кнопку для установления соединения приложения с программатором (если соединение не устанавливается, нужно повторить попытку!). После успешного установления соединения отображается надпись и отображается информация о программаторе и микроконтроллере:
Выбираем и загружаем hex-файл (hello.hex в папке src/hello/bin/Release) с прошивкой, нажимая на Open file или нажимая на + и выбирая команду Open file:
Нажимаем кнопку для загрузки прошивки в микроконтроллер:
После успешного завершения процесса прошивки выдается сообщение (если выдается сообщение об ошибке, нужно повторить попытку!):
Нажимаем кнопку для разрыва соединения приложения с программатором.
Перезагружаем микроконтроллер, нажимая кнопку сброса на плате:
Вуаля - светодиод мигает (частота мигания составляет 1 Гц (период равен 1 с = 500 мс (горит) + 500 мс (погашен)), загруженная прошивка работает!
Подключение дисплея от 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);
}
}
Использование АЦП
Продолжение следует