STM8S управление коллекторным двигателем и индикацией на модуле TM1638.
Ссылка на видео в YouTube Пора перейти к более чему то серьезному например управление коллекторным двигателем с помощью ШИМ(широтно-импульсная модуляция или PWM).
Не много теории о ШИМе, ШИМ состоит из двух частей это период(отрезок времени например 1 секунд) который неизменный и импульса(часть периода) который будет меняться но не должен превышать период.
Выглядит это на практике следующим образом(период 1 секунда, импульс 0.4 секунды), после включения ШИМ начинается отсчет периода и так как импульс больше нуля на выводе будет высокий уровень, после отсчета 0.4 секунды(продолжительность импульса) вывод переходит в низкий уровень и ждет пока отсчитывается период, после начинается с начало, если импульс будет равен нулю то на выводе всегда будет низкий уровень но если импульс равен периоду будет всегда высокий.
Ниже на рисунке показано как это влияет на ток проходящий через обычный резистор.
Управление током двигателя будет происходить также, чем больше импульс тем быстрее крутится двигатель или мощнее момент на валу.
Обращаю внимание что у двигателей так как являются индуктивной нагрузкой имеется два вида сопротивлений это активное как у резистора и реактивное из за индуктивности, с активным нам все понятно а вот про реактивное почитайте если интересно в интернете.
Если вы не обладаете знаниями электротехники или лень высчитывать параметр периода(частота ШИМ) то сможете подобрать его опытным путем на готовом устройстве, через эксперимент.
Для этого проекта я использую контроллер STM8S003F3P6 которого с избытком хватает для этих целей, наш любимый модуль для управления на чипе TM1638 и буду использовать следующую схему для управления двигателем, подключение самого контроллера стандартно без внешнего кварца.
В схеме я использую полевой транзистор HUF75307D3 другого подходящего не было, вы можете заменить на любой другой похожий(например IRF510, IRF540) с напряжением от 45 до 100 вольт и более 3 ампер.
Теперь про настройку контроллера, использовать для генерации ШИМ будем TIM2_CH3(вывод PA3). Частота тактирования контроллера 2MHz, период(TIM2_Period) будет равен 100, частота генерации ШИМ будет 2000000/100=20KHz.
Ну и конечно код самой программы в котором я попытаюсь описать настройки комментариями.
#include "stm8s.h"
void send_command(uint8_t com);
void send_data(uint8_t *send_data_display);
void display_data(uint32_t multiplier);
uint8_t scan_button(void);
void pause(uint32_t p);
uint8_t result=0;
uint32_t pwm_moto=0;
//Массив для отправки данных
uint8_t send_data_display[16];
//Массив наших символы для индикации 1,2,3 и так далее
uint8_t symbol[10]={63,6,91,79,102,109,125,7,127,111};
int main( void ){
//Настраиваем порты для SPI
GPIO_Init(GPIOC,GPIO_PIN_5, GPIO_MODE_OUT_OD_HIZ_FAST);
GPIO_Init(GPIOC,GPIO_PIN_4, GPIO_MODE_OUT_OD_HIZ_FAST);
SPI_Init( SPI_FIRSTBIT_LSB, SPI_BAUDRATEPRESCALER_16, SPI_MODE_MASTER, SPI_CLOCKPOLARITY_LOW,
SPI_CLOCKPHASE_1EDGE, SPI_DATADIRECTION_1LINE_TX, SPI_NSS_SOFT, 0x07);
SPI_Cmd(ENABLE);
//Включаем модуль и задаем автоматический инкремент адреса для данных
send_command(137);
send_command(64);
//Настраиваем вывод PA3, TIM2 для генерации ШИМ и включаем
GPIO_Init(GPIOA,GPIO_PIN_3, GPIO_MODE_OUT_OD_HIZ_FAST);
TIM2_TimeBaseInit(TIM2_PRESCALER_1, 100);
TIM2_OC3Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_ENABLE, 0, TIM2_OCPOLARITY_LOW);
TIM2_Cmd(ENABLE);
while(1){
//Опрашиваем модуль на нажатие кнопок и присваиваем значение result
result=scan_button();
pause(100);
//Если нажата кнопка, тогда определяем какая и выберем действие
if(result!=0){
//Если кнопка 1 импульс(pwm_moto) равен нулю, значит мотор не работает
if(result==1){pwm_moto=0;}
//Если кнопка 2 то увеличиваем время импульса но не больше 100
if(result==2){if(pwm_moto<100){pwm_moto++;}}
//Если кнопка 3 уменьшаем импульс но не меньше 0
if(result==4){if(pwm_moto>0){pwm_moto--;}}
//Следующие кнопки выбирают значения импульса 20, 40, 60, 80 и 100
if(result==8){pwm_moto=20;}
if(result==16){pwm_moto=40;}
if(result==32){pwm_moto=60;}
if(result==64){pwm_moto=80;}
if(result==128){pwm_moto=100;}
//Устанавливаем новое значение импульса
TIM2_SetCompare3(pwm_moto);
//Отображаем новое значение
display_data(pwm_moto);
pause(10000);
}
}
}
//Функция для отправки команды
void send_command(uint8_t com){
GPIO_WriteLow(GPIOC, GPIO_PIN_4);
SPI_SendData(com);
while( (SPI->SR & SPI_FLAG_BSY) );
GPIO_WriteHigh(GPIOC, GPIO_PIN_4);
}
//Функция для опроса кнопок
uint8_t scan_button(void){
uint8_t scan_result;
GPIO_WriteLow(GPIOC, GPIO_PIN_4);
SPI_SendData(66);
while( (SPI->SR & SPI_FLAG_BSY) );
//Перенастраиваем SPI на прием данных, принимаем 4байта и сокращаем их до 1байта
SPI_BiDirectionalLineConfig(SPI_DIRECTION_RX);
while( !(SPI->SR & SPI_FLAG_RXNE) );
scan_result=SPI->DR;
while( !(SPI->SR & SPI_FLAG_RXNE) );
scan_result|=(SPI->DR<<1);
while( !(SPI->SR & SPI_FLAG_RXNE) );
scan_result|=(SPI->DR<<2);
while( !(SPI->SR & SPI_FLAG_RXNE) );
scan_result|=(SPI->DR<<3);
GPIO_WriteHigh(GPIOC, GPIO_PIN_4);
//Перенастраиваем SPI на передачу данных
SPI_BiDirectionalLineConfig(SPI_DIRECTION_TX);
return scan_result;
}
//Функция для отправки данных
void send_data(uint8_t *send_data_display){
GPIO_WriteLow(GPIOC, GPIO_PIN_4);
SPI_SendData(192);
while( (SPI->SR & SPI_FLAG_BSY) );
for( uint8_t i=0;i<16;i++){
SPI_SendData(send_data_display[i]);
while( !(SPI->SR & SPI_FLAG_TXE) );
}
while( (SPI->SR & SPI_FLAG_BSY) );
GPIO_WriteHigh(GPIOC, GPIO_PIN_4);
}
//Вычисляем значения и заполняем ими массив для отправки в модуль для отображения
void display_data(uint32_t multiplier){
send_data_display[0]= symbol[multiplier/10000000];
multiplier= multiplier-(multiplier/10000000*10000000);
send_data_display[2]= symbol[multiplier/1000000];
multiplier=multiplier-(multiplier/1000000*1000000);
send_data_display[4]= symbol[multiplier/100000];
multiplier= multiplier-(multiplier/100000*100000);
send_data_display[6]= symbol[multiplier/10000];
multiplier= multiplier-(multiplier/10000*10000);
send_data_display[8]= symbol[multiplier/1000];
multiplier= multiplier-(multiplier/1000*1000);
send_data_display[10]= symbol[multiplier/100];
multiplier= multiplier-(multiplier/100*100);
send_data_display[12]= symbol[multiplier/10];
multiplier= multiplier-(multiplier/10*10);
send_data_display[14]= symbol[multiplier];
send_data(send_data_display);
}
void pause(uint32_t p){
for(uint32_t i=0; i<p; i++){}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
while (1){}
}
#endif
Управление индикатором как и в других статьях только изменил функцию void display_data(uint32_t multiplier); теперь она выводит десятичные от 10000000 до 1 то есть реальные цифры.
Опишу настройку TIM2.
TIM2_TimeBaseInit(TIM2_PRESCALER_1, 100);
Тут устанавливаем предделитель(TIM2_PRESCALER_1) равный 1, тактирование таймера равна 2MHz и второй параметр это наш период буде 100 отсчетов тактов.
TIM2_OC3Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_ENABLE, 0, TIM2_OCPOLARITY_LOW);
В этой функции первый параметр TIM2_OCMODE_PWM1 переводит канал 3 таймера в режим генерации ШИМ, следующий TIM2_OUTPUTSTATE_ENABLE включает пин, далее устанавливаем значение импульса тут он равен 0 и устанавливаем полярность вывода TIM2_OCPOLARITY_LOW (импульс будет низкий уровень).
Последняя функция включает таймер.
TIM2_Cmd(ENABLE);