В предыдущей статье на нашем сайте мы рассмотрели принципы работы АЦП в плате STM32. В этой же статье мы рассмотрим основы использования широтно-импульсной модуляции (ШИМ, в англ. PWM – Pulse Width Modulation) в плате STM32F103C8, которая также называется STM32 Blue Pill ("синяя таблетка"). С помощью изменения коэффициента заполнения ШИМ сигнала мы будем регулировать скорость вращения вентилятора постоянного тока (DC fan).
Ранее на нашем сайте мы рассматривали использование ШИМ в следующих микроконтроллерах (платах):
- в микроконтроллере AVR;
- в плате Arduino Uno;
- в плате Arduino Due;
- в плате Raspberry Pi;
- в модуле ESP32.
Основные принципы ШИМ
ШИМ (широтно-импульсная модуляция) – это способ управления аналоговыми сигналами с помощью цифровых значений. Таким образом, можно управлять скоростью вращения двигателей, яркостью свечения светодиода и т.д.
Внешний вид ШИМ сигнала при различных коэффициентах заполнения показан на следующих рисунке.
Важным параметром ШИМ сигнала является его коэффициент заполнения (скважность, в англ. - duty cycle). Коэффициент заполнения ШИМ сигнала представляет собой процент времени, в течение которого сигнал имеет высокий уровень (HIGH, ON). Если ШИМ сигнал всегда находится в состоянии HIGH, то его коэффициент заполнения равен 100%, а если ШИМ сигнал всегда находится в состоянии LOW, то его коэффициент заполнения равен 0%.
ШИМ в STM32
Плата STM32F103C8 содержит 15 ШИМ контактов и 10 контактов АЦП. Также в ней есть 7 таймеров и каждый выход ШИМ в ней обеспечен каналом, соединенным с 4 таймерами. Разрешение ШИМ сигнала в плате составляет 16 бит, что позволяет оперировать значениями вплоть до 65535. Учитывая частоту процессора равную 72 МГц получаем, что максимальный период ШИМ сигнала составляет примерно 1 миллисекунду.
Таким образом:
- значение 65535 обеспечивает полную яркость светодиода/полную скорость вращения вентилятора (коэффициент заполнения 100%);
- значение 32767 обеспечивает половинную яркость светодиода/половинную скорость вращения вентилятора (коэффициент заполнения 50%);
- значение 13107 обеспечивает 20% яркости светодиода/20% скорости вращения вентилятора (коэффициент заполнения 20%).
Внешний вид ШИМ сигнала в плате STM32F103C8 при различных коэффициентах заполнения показан на следующем рисунке.
В данном проекте мы будем использовать потенциометр, подключенный к плате STM32, для изменения яркости свечения светодиода и скорости вращения вентилятора с помощью изменения коэффициента заполнения ШИМ сигнала. ЖК дисплей 16x2 будет использоваться для отображения значения АЦП (0-4095) и значения ШИМ (0-65535).
Необходимые компоненты
- Плата разработки STM32F103C8 (STM32 Blue Pill) (купить на AliExpress).
- Вентилятор постоянного тока (DC fan).
- Микросхема драйвера двигателей ULN2003 (купить на AliExpress - в виде модуля, но можно найти и в виде отдельной микросхемы).
- Светодиод красного цвета (купить на AliExpress).
- ЖК дисплей 16x2 (купить на AliExpress).
- Потенциометр – 2 шт. (купить на AliExpress).
- Батарейка 9V.
- Макетная плата.
- Соединительные провода.
В качестве вентилятора постоянного тока мы использовали вентилятор BLDC типа от старого компьютера, которому требуется внешнее напряжение питания 9V.
Микросхема драйвера двигателей ULN2003: используется для управления вращения двигателем в одном направлении поскольку у нас двигатель вентилятора однополярный и для него требуется внешнее питание. Внутренняя схема соединений микросхемы ULN2003 представлена на следующем рисунке.
Контакты с IN1 до IN7 микросхемы ULN2003 являются ее входами, а контакты с OUT 1 по OUT 7 являются ее выходами. На контакт COM подается положительное напряжение источника питания, необходимое для устройств, подключаемых к выходам микросхемы.
В нашем проекте используется два потенциометра: один – для подачи аналогового напряжения на АЦП платы STM32, а второй – для управления контрастностью ЖК дисплея.
ШИМ контакты платы STM32
Распиновка платы STM32 Blue Pill показана на следующем рисунке.
ШИМ контакты на этом рисунке обозначены знаком волны (~). Всего таких контактов – 15. Контакты АЦП платы на представленной схеме обозначены зеленым цветом.
Схема проекта
Схема для демонстрации возможностей ШИМ в плате STM32 Blue Pill представлена на следующем рисунке.
Потенциометр в левой части схемы используется как регулятор напряжения, поступающего с контакта 3.3V платы. Центральный контакт потенциометра подключен к контакту АЦП PA4 платы STM32.
Светодиод подключен к ШИМ контакту PA9 платы STM32 через токоограничивающий резистор. Данный резистор и конденсатор, подключенный параллельно светодиоду, используются для формирования правильной аналоговой волны от ШИМ контакта – поскольку в чистом виде с данного контакта волна нам не очень подходит.
ШИМ контакт PA8 платы STM32 подключен к входному контакту IN1 микросхемы ULN2003, а соответствующий выходной контакт OUT1 микросхемы ULN2003 подключен к отрицательному выводу двигателя постоянного тока вентилятора.
Положительный вывод двигателя постоянного тока вентилятора подключен к контакту COM микросхемы ULN2003, к нему же подключена батарейка 9V. Общий провод (GND) микросхемы ULN2003 подключен к общему проводу платы STM32, к нему же подключен отрицательный вывод батарейки.
Соединения между платой STM32 и ЖК дисплеем 16x2 представлены в следующей таблице.
№ контакта ЖК дисплея | Обозначение контакта ЖК дисплея | Контакт платы STM32 |
1 | Ground (Gnd) | Ground (G) |
2 | VCC | 5V |
3 | VEE | средний контакт потенциометра |
4 | Register Select (RS) | PB11 |
5 | Read/Write (RW) | Ground (G) |
6 | Enable (EN) | PB10 |
7 | Data Bit 0 (DB0) | No Connection (NC) |
8 | Data Bit 1 (DB1) | No Connection (NC) |
9 | Data Bit 2 (DB2) | No Connection (NC) |
10 | Data Bit 3 (DB3) | No Connection (NC) |
11 | Data Bit 4 (DB4) | PB0 |
12 | Data Bit 5 (DB5) | PB1 |
13 | Data Bit 6 (DB6) | PC13 |
14 | Data Bit 7 (DB7) | PC14 |
15 | LED Positive | 5V |
16 | LED Negative | Ground (G) |
Потенциометр в правой части схемы используется для регулировки контрастности ЖК дисплея.
Внешний вид собранной конструкции проекта показан на следующем рисунке.
Объяснение программы для платы STM32
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Программировать плату STM32F103C8 мы будем с помощью Arduino IDE через USB порт, без использования FTDI программатора.
В нашей программе мы будем считывать значение с выхода АЦП контакта PA4 платы STM32, к которому подключен средний контакт потенциометра, и затем конвертировать аналоговое значение напряжения (0-3.3V) в цифровое значение в диапазоне от 0 до 4095. Это значение будет после еще одного преобразования передаваться в функцию формирования ШИМ сигнала для управления яркостью свечения светодиода и скоростью вращения вентилятора постоянного тока. ЖК дисплей 16x2 используется для отображения значения АЦП и сформированного значения ШИМ.
Первым делом в программе нам необходимо подключить библиотеку для работы с ЖК дисплеем, указать контакты платы, к которым подключен ЖК дисплей и создать объект для работы с дисплеем. Более подробно о подключении ЖК дисплея 16x2 к плате STM32F103C8 можно прочитать в этой статье.
1 2 3 |
#include <LiquidCrystal.h> // include the LCD library const int rs = PB11, en = PB10, d4 = PB0, d5 = PB1, d6 = PC13, d7 = PC14; //mention the pin names to with LCD is connected to LiquidCrystal lcd(rs, en, d4, d5, d6, d7); //Initialize the LCD |
Далее объявим используемые контакты платы STM32.
1 2 3 |
const int analoginput = PA4; // Input from potentiometer const int led = PA9; // LED output const int fan = PA8; // fan output |
Внутри функции setup() укажем тип дисплея (16х2), покажем приветственное сообщение на его экране и через 2 секунды очистим экран дисплея. Также укажем режимы работы используемых контактов.
1 2 3 4 5 6 7 8 9 10 11 |
lcd.begin(16,2); //Getting LCD ready lcd.clear(); //Clears LCD lcd.setCursor(0,0); //Sets cursor at row0 and column0 lcd.print("CIRCUIT DIGEST"); //Displays Circuit Digest lcd.setCursor(0,1); //Sets Cursor at column0 and row1 lcd.print("PWM USING STM32"); //Displays PWM using STM32 delay(2000); // Delay Time lcd.clear(); // Clears LCD pinMode(analoginput, INPUT); // set pin mode analoginput as INPUT pinMode(led, PWM); // set pin mode led as PWM output pinMode(fan, PWM); // set pin mode fan as PWM output |
Далее в функции void loop() мы будем считывать аналоговый сигнал с контакта АЦП PA4 с помощью функции analogRead(analoginput) и сохранять его в переменной целого типа valueadc. Значение этой переменной будет в диапазоне (0-4095).
Здесь необходимо отметить что ШИМ контакты платы STM32 имеют разрешение 16-бит, что соответствует диапазону чисел 0-65535, поэтому мы преобразуем наше значение с выхода АЦП в диапазоне 0-4095 в диапазон 0-65535 с помощью функции map.
1 |
int result = map(valueadc, 0, 4095, 0, 65535). |
Затем мы подадим это значение ШИМ на контакты, к которым подключены светодиод и вентилятор, с помощью функций pwmWrite(led, result) и pwmWrite(fan, result) соответственно.
И, наконец, мы выведем на экран ЖК дисплея значения с выхода АЦП и сформированное значение ШИМ.
1 2 3 4 5 6 |
lcd.setCursor(0,0); //Sets cursor at row0 and column0 lcd.print("ADC value= "); // prints the words “” lcd.print(valueadc); //displays valueadc lcd.setCursor(0,1); //Sets Cursor at column0 and row1 lcd.print("Output = "); //prints the words in "" lcd.print(result); //displays value result |
Исходный код программы (скетча)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
#include <LiquidCrystal.h> // подключаем библиотеку для работы с ЖК дисплеем const int rs = PB11, en = PB10, d4 = PB0, d5 = PB1, d6 = PC13, d7 = PC14; //контакты платы STM32, к которым подключен ЖК дисплей LiquidCrystal lcd(rs, en, d4, d5, d6, d7); // инициализируем ЖК дисплей const int analoginput = PA4; // Input from potentiometer (вход от потенциометра) const int led = PA9; // LED output (выход на светодиод) const int fan = PA8; // fan output (выход на вентилятор) void setup() { lcd.begin(16,2); // указываем тип ЖК дисплея lcd.clear(); // очищаем экран дисплея lcd.setCursor(0,0); // устанавливаем курсор в 1-ю строку 1-й столбец lcd.print("CIRCUIT DIGEST"); //Displays Circuit Digest lcd.setCursor(0,1); // устанавливаем курсор во 2-ю строку 1-й столбец lcd.print("PWM USING STM32"); //Displays PWM using STM32 delay(2000); // задержка 2 секунды lcd.clear(); // очищаем экран дисплея pinMode(analoginput, INPUT); // режим работы контакта на ввод данных pinMode(led, PWM); // режим работы контакта - выход ШИМ сигнала pinMode(fan, PWM); // режим работы контакта - выход ШИМ сигнала } void loop() { int valueadc = analogRead(analoginput); //считываем значение с выхода АЦП и сохраняем его в переменной int result = map(valueadc, 0, 4095, 0, 65535); // конвертируем число из диапазона (0-4095) в диапазон (0-65535) и сохраняем его в переменной result pwmWrite(led, result); //подаем ШИМ сигнал на светодиод pwmWrite(fan, result); // подаем ШИМ сигнал на вентилятор lcd.setCursor(0,0); // устанавливаем курсор в 1-ю строку 1-й столбец lcd.print("ADC value= "); // prints the words in "" lcd.print(valueadc); //отображаем значение с выхода АЦП lcd.setCursor(0,1); // устанавливаем курсор во 2-ю строку 1-й столбец lcd.print("Output = "); //prints the words in "" lcd.print(result); //отображаем значение ШИМ } |