STM32 ile DC, Step ve Servo motor kontrolü
Merhabalar,
Bu yazımda, sürücü kartlarının da desteği ile Encoder ve Potansiyometre kullanarak DC, Step ve Servo motor kontrolünden bahsederken, ADC ile veri okuma, Encoder kullanımı, OLED ekran kullanımı ve PWM üretimi gibi konulara da değineceğiz.
Deneyde kullanılan malzemeler
- STM32F401RE Nucleo deney kartı
- 128*64 I²C SSD1306 OLED ekran
- KY-040 Rotary Encoder
- 10K Potansiyometre
- L298N Motor sürücü
- A4988 Step motor sürücüsü
- 12v DC motor
- Nema 17 step motor
- SG90 servo motor
- 12v Güç kaynağı
- 5mm led
- 220 Ohm direnç
- Breadboard ve kablo
Devre Şeması
BAĞLANTILAR
Potansiyometre orta uç --> PA6 ADC 1
Encoder -->PA8,PA9 TIM1_CH1,CH2
Oled
scl-->PB6 I2C1_SCL
sda-->PB7 I2C1_SDA
L298N DC MOTOR
in1-->PC2
in2-->PC3
ena-->PA15 TIM2_CH1
A4988 STEP MOTOR
step-->PC1
SERVO
pwm-->PB0 TIM3_CH3
BLOK DİYAGRAM
YAZILIM
Not: STM32 F401RE Nucleo kartına sahipseniz ve ayarlarda değişiklik yapmak istemiyorsanız sayfa sonuna geçerek "Proje dosyaları" adlı linkte ki dosyayı indirdikten sonra doğrudan keil üzerinden karta yükleme yapabilirsiniz.
Manuel ayarlar:
STM32F401 NUCLEO kartımızın gerekli ayarlamalarını yapmak için "CubeMX", yazılım derleyicisi için ise "KEİL" programını kullanıyoruz. Program linklerini yazı sonunda bulabilirsiniz.
CubeMX Ayarları
Adım 1: STM32CubeMX programımızı açıyoruz, ardından nucleo deney kartımızı kullanacağımızdan dolayı ACCES TO BOARD SELECTOR seçeneğine tıklıyoruz.
Adım 2: Bizim projede kullanacağımız kart STM32 F401RE modeli olduğu için arama kısmına 401re yazdıktan sonra nucleo deney kartımızı seçerek projemizi başlatıyoruz. Eğer farklı bir kart kullanıyorsanız ACCESS TO MCU SELECTOR kısmından kendi modelinizi seçerek devam edebilirsiniz.
!! Nucleo kartı için varsayılan ayarlarla başlatılsın mı ? gibi bir soru gelirse evet diyerek devam edebilirsiniz.
Adım 3: Kristal ayarlarını yapmak üzere System Core kısmından RCC bölümüne giriyoruz, 401RE Nucleo modelinde fabrika çıkışında deney kartı üzerinde yüksek hız kristali yer almadığından dolayı yüksek hız kristali ayarını BYPASS CLOCK SOURCE olarak seçiyoruz(401RE için varsayılan ayardır) eğer kartınızda kristal var ise Crystal/Ceramic Resonator seçebilirsiniz(401CCU için varsayılan ayardır).
Adım 4: 401CCU gibi bir karta sahip iseniz SYS bölümündeki Debug kısmını Serial Wire yapmanız kartınıza yazılım yükleyebilmeniz için gerekli ve çok önemlidir.(401RE Nucleo varsayılan ayardır yinede kontrol etmenizde fayda var) Eğer bu ayarı yapmayı unutup bir sonraki yazılım yükleme işleminde sorun yaşarsanız Mail yoluyla benimle iletişime geçebilirsiniz.
Adım 5: Potansiyometre den veri okuyabilmek için Analog bölümünden ADC1 kısmına giriyoruz, buradan IN0 ve IN6 kanallarını aktif ediyoruz projenize göre kanal sayısını arttırıp azaltabilirsiniz kanal numara seçimleri kullanıcı iradesindedir kırmızı olanlar hariç istediğinizi seçebilirsiniz.(Buna göre kanal portları değişir)
!! İki ve üzeri kanal seçimlerinde "Scan Conversion Mode" seçeneği aktif edilmelidir.
Adım 6: Kanal sayısına göre "Number Of Conversion" değeri seçilerek Rank bölümündeki ayarlar şekildeki gibi yapılmalıdır.(kanal numaraları kullanıcı seçimine göre değişkenlik gösterebilir)
!! Örnekleme hızı potansiyometre den okunan verinin daha kararlı olması için 480 saykıl seçilmiştir daha hızlı okuma için küçültülebilir, çok küçük değerler kanallar arasında verilerin karışmasına neden olur.
Adım 7: Encoder ayarlarını yapmak üzere "Timers" sekmesinden TIM1 bölümüne giriyoruz, "Combined Channels "seçeneğini "Encoder Mode" yapıyoruz ve alt bölümden Encoder Mod'u Timer input1 ve Timer input 2 seçiyoruz(TI1 and TI2), bu ayar Encoder'in sağa ve sola hareketini okumak için gereklidir.
Prescaler ve Counter Period bizim PWM sinyalindeki frekans ve görev döngüsü ayarlamalarını belirlememiz içindir ve şu formül yoluyla bulunur ;
ARR=f_TIM/(f_PWM (PSC+1))-1
Burada öncelikle
PSC=0 ile başlanır hesaplanan değer 16 bit ile ifade edilebiliyorsa (0-65535 aralığında
ise) sonuç doğrudur, aksi halde PSC=1 yapılır ve tekrar hesaplanır. İstenilen
değere kadar arttırmaya devam edilir.
Bizim kartımızın çalışma frekansı 84 MHz olduğundan ve PWM frekansımızın 1 kHz olmasını istediğimizden dolayı
ARR=84.10*6/1.10*3.(69+1))-1
formülünü kullanarak ARR (Auto Reload Register) yani Counter Period değerimizi 1199 buluyoruz, Prescelar değerimizi formül yoluyla 69 olarak belirlemiştik bu değerleri yazarak devam ediyoruz.
Adım 10: Oled ekranımızın kullandığı haberleşme yöntemi olan I2C modülasyonunu aktifleştirmek için Connectivity sekmesinden I2C1 bölümüne girerek Mod seçimini I2C ve alt bölümde bulunan Hız modunu Fast Mode olarak değiştiriyoruz.(sizin kullandığınız ekranda farklı bir haberleşme yöntemi var ise onu aktifleştirmeniz gereklidir)
Adım 11: Son olarak l298n sürücüde yön seçiminde gerekli olan ve step motorda gereken palsleri iletmek için kullanacağımız 3 adet portumuzu da çıkış olarak ayarlayarak (GPIO_Output) port ayarlarını bitirmiş oluyoruz.
Adım 12: Üst sekmede yer alan Clock Configuration sekmesinde AHB Clock frekansımızı nucleo kartımızın izin verdiği maks hız olan 84 MHz değerini yazarak bizim için optimal ayarları otomatik olarak belirleyecek ve sorunları çözecek olan Resolve Clock Issues seçeneğine tıklayarak proje ayarları bölümüne geçiyoruz.
Adım 14: Son olarak GENERATE CODE diyerek projemizin oluşturulmasını ve sonrasında çıkan Open Project seçeneğine tıklayarak derleyicimizde çalışmak üzere kod bölümüne geçiyoruz.(Eğer Keil programı yüklü değil ise open project seçeneğine tıkladığınızda projeniz açılmayacaktır, programı yükledikten sonra belirlediğiniz proje kayıt klasörüne giderek manuel olarak açabilirsiniz)
KOD bölümü
Adım 15: Keil programı açıldıktan sonra Application/User/Core klasörüne sağ tıklayarak Add Existing File seçeneğini seçiyoruz.
Adım 16: Core bölümündeki Inc ve Src klasörlerine girerek yazı sonundaki açıklamalarda linkini verdiğim .c ve .h dosyalarını ekliyoruz.
!! Bu bölümde dosyaların gözükmesi için açıklamada verilen dosyaları daha önceden Projenin kayıtlı olduğu klasöre girerek Core klasörünün içine eklemelisiniz
Adım 17: Dosyaları ekledikten ve main.c bölümüne girdikten sonra şekilde belirtilen Rebuild seçeneğine bir kez tıklayarak ekledğimiz dosyaların derlenmesini sağlıyoruz bu işlem sonrasında verilen kodları gerekli bölümlere yazarak kodumuzu yüklemeye hazır hale getiriyoruz.
Kodlar
Adım 18: Genel kütüphane tanımlamalarını yapıyoruz, eğer oled ekran kullanmayacaksanız Oled küpühane yazılı kütüphaneleri silebilirsiniz.
Değişken tanımlamalarını aşağıdaki gibi yapıyoruz:
/* USER CODE BEGIN PV */
uint16_t ort,ort2,pwmd,pwm1,step1,k,adimm=0,say=0,tur=0,selamlama=0,potkararlilik=0;
uint32_t adc1,adc2,motorhizi,motorhizort;
int16_t adim_sayisi=0;
char buf[4];
char buf2[4];
char karakter_dizisi[16];
/* USER CODE END PV */
/* USER CODE BEGIN PFP */
void selamlama_durumu(unsigned int);
/* USER CODE END PFP */
Ayarlarımızı çağırıyoruz:
/* USER CODE BEGIN 2 */
HAL_TIM_Encoder_Start(&htim1,TIM_CHANNEL_ALL); //Modul baslatilir
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); //Modul baslatilir
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); //Modul baslatilir
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3); //Modul baslatilir
SSD1306_Init (); //OLED ayarlarini cagirir, ekran kullanılmayacaksa gerekli değil.
lcd_init (); //OLED ayarlarini cagirir, ekran kullanılmayacaksa gerekli değil.
selamlama_durumu(1); //1-aktif,0-pasif, Motorlari baslangicta test eder
SSD1306_Fill (0);
SSD1306_UpdateScreen(); //display
/* USER CODE END 2 */
Döngü içerisindeki kodlar:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_TogglePin (GPIOA, GPIO_PIN_5); // LED'i aç/kapa
HAL_Delay (10 );
//ADC Ve Encoder veri okuma
adim_sayisi= __HAL_TIM_GET_COUNTER(&htim1);
adimm=TIM_COUNTERMODE_CENTERALIGNED1;
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1000);
adc1 = HAL_ADC_GetValue(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 1000);
adc2 = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop (&hadc1);
//DC Motor kontrol bolumu
//********************************************************************************************
//Potansiyometrenin kararli calismasi icin 5 kez veri okunup ortalamasi alinir
motorhizi=adc2/20;
motorhizort+=motorhizi;
ort2++;
potkararlilik=5; //kararlilik degeri (yukseltildikce okuma hizi duser)(onerilen=5)
while(ort2==potkararlilik)
{
ort2=0;
motorhizort/=potkararlilik;
if((95<=motorhizort)&&(105>=motorhizort))
{
TIM2->CCR1=0;
motorhizort=100;
SSD1306_GotoXY (70,30);
sprintf(buf, " %%%d ", motorhizort-100);
SSD1306_Puts (buf, &Font_7x10, 1);
SSD1306_UpdateScreen();
GPIOC->ODR &=0x00;
}
if((105<motorhizort)&&(200>motorhizort))
{
GPIOC->ODR &=0x00;
GPIOC->ODR |=0x08;
TIM2->CCR1=(motorhizort-100)*10;
SSD1306_GotoXY (70,30);
sprintf(buf, "CW %%%d ", motorhizort-100);
SSD1306_Puts (buf, &Font_7x10, 1);
SSD1306_UpdateScreen();
}
if((1<=motorhizort)&&(95>motorhizort))
{ GPIOC->ODR &=0x00;
GPIOC->ODR |=0x04;
TIM2->CCR1=(100-motorhizort)*10;
SSD1306_GotoXY (70,30);
sprintf(buf, "CCW %%%d ", 100-motorhizort);
SSD1306_Puts (buf, &Font_7x10, 1);
SSD1306_UpdateScreen();
}
motorhizort=0;
}
//******************************************************************************************
//Servo kontrol bolumu
if(adim_sayisi>90)
{
adim_sayisi=90;
}
//SSD1306_Fill (0);
SSD1306_GotoXY (3,15);
SSD1306_Puts ("Servo Derece=", &Font_7x10, 1);
SSD1306_GotoXY (100,15);
sprintf(buf, "%d ", adim_sayisi*2);
SSD1306_Puts (buf, &Font_7x10, 1);
TIM3->CCR3=adim_sayisi+24;
SSD1306_GotoXY (3,30);
SSD1306_Puts ("DC Motor=", &Font_7x10, 1);
HAL_Delay(1);
SSD1306_UpdateScreen(); //display
}
Selamlama alt programı:
void selamlama_durumu(unsigned int selamlama)
{
if(selamlama==1)
{
SSD1306_Fill (0);
SSD1306_GotoXY (10,20);
SSD1306_Puts ("DC Motor Testi", &Font_7x10, 1);
SSD1306_GotoXY (50,40);
SSD1306_Puts ("Test ", &Font_7x10, 1);
SSD1306_UpdateScreen(); //display
GPIOC->ODR |=0x08;
for(pwmd=0;pwmd<500;pwmd+=50)
{
TIM2->CCR1=pwmd;
HAL_Delay (100);
}
HAL_Delay (100);
SSD1306_GotoXY (50,40);
SSD1306_Puts ("Test .", &Font_7x10, 1);
SSD1306_UpdateScreen(); //display
for(pwmd=500;pwmd>0;pwmd-=50)
{
TIM2->CCR1=pwmd;
HAL_Delay (100);
}
GPIOC->ODR &=0x00;
HAL_Delay (10);
GPIOC->ODR |=0x04;
SSD1306_GotoXY (50,40);
SSD1306_Puts ("Test ..", &Font_7x10, 1);
SSD1306_UpdateScreen(); //display
for(pwmd=0;pwmd<500;pwmd+=50)
{
TIM2->CCR1=pwmd;
HAL_Delay (100);
}
HAL_Delay (2000);
for(pwmd=500;pwmd>0;pwmd-=50)
{
TIM2->CCR1=pwmd;
HAL_Delay (100);
}
GPIOC->ODR &=0x00;
SSD1306_GotoXY (50,40);
SSD1306_Puts ("BITTI ", &Font_7x10, 1);
SSD1306_UpdateScreen(); //display
HAL_Delay (1000);
SSD1306_Fill (0);
SSD1306_GotoXY (10,20);
SSD1306_Puts ("Step Motor Testi", &Font_7x10, 1);
SSD1306_GotoXY (50,40);
SSD1306_Puts ("Test ", &Font_7x10, 1);
SSD1306_UpdateScreen(); //display
while(tur!=8)
{
for(step1=0;step1<50; step1++)
{
GPIOC->ODR |=0x02;
HAL_Delay (3);
GPIOC->ODR &=0x00;
HAL_Delay (3);
}
HAL_Delay (1000);
tur++;
}
SSD1306_GotoXY (50,40);
SSD1306_Puts ("BITTI ", &Font_7x10, 1);
SSD1306_UpdateScreen(); //display
HAL_Delay (1000);
SSD1306_Fill (0);
SSD1306_GotoXY (10,20);
SSD1306_Puts ("Servo Motor Testi", &Font_7x10, 1);
SSD1306_GotoXY (50,40);
SSD1306_Puts ("Test ", &Font_7x10, 1);
SSD1306_UpdateScreen(); //display
TIM3->CCR3=0;
HAL_Delay(1000);
TIM3->CCR3=30;
HAL_Delay(1000);
TIM3->CCR3=0;
SSD1306_GotoXY (50,40);
SSD1306_Puts ("BITTI ", &Font_7x10, 1);
SSD1306_UpdateScreen(); //display
HAL_Delay(1000);
}
}
Linkler
Keil programı https://www.keil.com/demo/eval/arm.htm
Proje dosyaları https://drive.google.com/drive/folders/1LG9l7N-1dRMrwFlZGybg_-vEwkICoHGb?usp=sharing
Core dosyaları https://drive.google.com/file/d/1EeeW_GvcrCamsp9I6XMe5HSqcDjvyOHT/view?
usp=sharing






















Yorumlar
Yorum Gönder