IAR ile STM8S – Beeper ve Timer
- 7 sene önce, Baran EKREM yazdı.
- 5 Yorum
- 4.028 Kişi Okudu
STM8S serisine kaldığımız yerden devam edecek olursak öncelikle hoşuma giden bir özelliği inceleyeceğiz. Sanırım sesi geldi bile BEEEP ! 🙂 Beeper modülü işlemci içerisinde bulunan bir buzzer kontrolcüsü gibi düşünülebilir. 3 farklı frekans da sinyal üreterek farklı ses ihtiyaçlarınızı oldukça hızlı bir şekilde karşılar. Normalde bu işi yapmak için bir tane Timer harcamak küçük işlemcilerde biraz fazla olabilir. Beeper 1, 2 ve 4kHz’lik çıkış sinyalleri mevcuttur. Kullanımı oldukça basit olan bu modül sadece kalibrasyon fonksiyonunu ihtiyaç duyar. Kalibrasyon işlemini bir kere yaptıktan sonra frekans’ı seçip modülü çalıştırabilirsiniz. Beeper kalibrasyon için bir tane Timer’a ihtiyaç duyar.
Kalibrasyon işlemi bitince Timer’ı kapatır ve siz daha sonra bu Timer’ı kullanabilirsiniz.
1 ) Beeper
Clock ayarlarını yaptığınızı varsayarak başlayalım. Öncelikle projemize şu kütüphaneleri ekleyelim.
- stm8s_clk.c
- stm8s_beep.c
- stm8s_tim1.c
- stm8s_tim3.c
- stm8s_tim4.c
Diğer modüllerde olduğu gibi beeper DeInit() işlemini yapıyoruz. Ardından kalibrasyonu yaptıktan sonra frekansı seçip Disable konumunda tutuyoruz.
1 2 3 4 |
BEEP_DeInit(); BEEP_LSICalibrationConfig(LSIMeasurment()); BEEP_Init(BEEP_FREQUENCY_1KHZ); BEEP_Cmd(DISABLE); |
Burada kalibrasyon için gerekli olan fonksiyon LSI_Measurement() aşağıda mevcut. Bu standart fonksiyonun detaylarına girmeyeceğim. Yapısı oldukça basit. Boş bir vakitte incelenebilir.
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
uint32_t LSIMeasurment(void) { uint32_t lsi_freq_hz = 0x0; uint32_t fmaster = 0x0; uint16_t ICValue1 = 0x0; uint16_t ICValue2 = 0x0; /* Get master frequency */ fmaster = CLK_GetClockFreq(); /* Enable the LSI measurement: LSI clock connected to timer Input Capture 1 */ AWU->CSR |= AWU_CSR_MSR; #if defined (STM8S903) || defined (STM8S103) || defined (STM8S003) /* Measure the LSI frequency with TIMER Input Capture 1 */ /* Capture only every 8 events!!! */ /* Enable capture of TI1 */ TIM1_ICInit(TIM1_CHANNEL_1, TIM1_ICPOLARITY_RISING, TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV8, 0); /* Enable TIM1 */ TIM1_Cmd(ENABLE); /* wait a capture on cc1 */ while((TIM1->SR1 & TIM1_FLAG_CC1) != TIM1_FLAG_CC1); /* Get CCR1 value*/ ICValue1 = TIM1_GetCapture1(); TIM1_ClearFlag(TIM1_FLAG_CC1); /* wait a capture on cc1 */ while((TIM1->SR1 & TIM1_FLAG_CC1) != TIM1_FLAG_CC1); /* Get CCR1 value*/ ICValue2 = TIM1_GetCapture1(); TIM1_ClearFlag(TIM1_FLAG_CC1); /* Disable IC1 input capture */ TIM1->CCER1 &= (uint8_t)(~TIM1_CCER1_CC1E); /* Disable timer2 */ TIM1_Cmd(DISABLE); #else /* Measure the LSI frequency with TIMER Input Capture 1 */ /* Capture only every 8 events!!! */ /* Enable capture of TI1 */ TIM3_ICInit(TIM3_CHANNEL_1, TIM3_ICPOLARITY_RISING, TIM3_ICSELECTION_DIRECTTI, TIM3_ICPSC_DIV8, 0); TIM3_Cmd(ENABLE); /* wait a capture on cc1 */ while ((TIM3->SR1 & TIM3_FLAG_CC1) != TIM3_FLAG_CC1); /* Get CCR1 value*/ ICValue1 = TIM3_GetCapture1(); TIM3_ClearFlag(TIM3_FLAG_CC1); /* wait a capture on cc1 */ while ((TIM3->SR1 & TIM3_FLAG_CC1) != TIM3_FLAG_CC1); /* Get CCR1 value*/ ICValue2 = TIM3_GetCapture1(); TIM3_ClearFlag(TIM3_FLAG_CC1); /* Disable IC1 input capture */ TIM3->CCER1 &= (uint8_t)(~TIM3_CCER1_CC1E); /* Disable timer3 */ TIM3_Cmd(DISABLE); #endif /* Compute LSI clock frequency */ lsi_freq_hz = (8 * fmaster) / (ICValue2 - ICValue1); /* Disable the LSI measurement: LSI clock disconnected from timer Input Capture 1 */ AWU->CSR &= (uint8_t)(~AWU_CSR_MSR); return (lsi_freq_hz); } static void GPIO_Config(void) { GPIO_Init(LED_GPIO_PORT, (GPIO_Pin_TypeDef)LED_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(BUTTON_GPIO_PORT, (GPIO_Pin_TypeDef)BUTTON_GPIO_PINS, GPIO_MODE_IN_PU_NO_IT); } |
Beeper için kalibrasyonu yaptıktan sonra yapmamız gereken tek şey BEEP_Cmd() Enable yada Disable değerini vererek kullanmak. Farklı frekans değerleri için tanımlanan değerler şunlar.
1 2 3 4 5 |
typedef enum { BEEP_FREQUENCY_1KHZ = (uint8_t)0x00, /*!< Beep signal output frequency equals to 1 KHz */ BEEP_FREQUENCY_2KHZ = (uint8_t)0x40, /*!< Beep signal output frequency equals to 2 KHz */ BEEP_FREQUENCY_4KHZ = (uint8_t)0x80 /*!< Beep signal output frequency equals to 4 KHz */ } BEEP_Frequency_TypeDef; |
Ve beeper işte bu kadar. Bir buton ile Beeper’ı kontol edelim.
1 2 3 4 5 6 |
uint8_t button_state = GPIO_ReadInputPin(BUTTON_GPIO_PORT, (GPIO_Pin_TypeDef)BUTTON_GPIO_PINS); if (button_state == 0) BEEP_Cmd(ENABLE); else BEEP_Cmd(DISABLE); |
2) Timer
Timerlara genel olarak bakacak olursak. Standart olarak bildiğimiz periyodik kesmelerinin yanı sıra, çeşitli PWM modlarıda mevcut. STM8S de bulunan Timerlar 8 ve 16 bitliktir. Biz bu yazıda 8 bitlik olan TIM4’ü ele alacağız.
Daha önce MCU ile çalıştıysanız bilirsiniz. Oldukça basit bir formülü var.
- F_Timer = F_Master / Prescaler
- T_Timer = (Period + 1 ) / F_Timer
Burada 1 mS kesme elde etmek için Bölücü değerini 128 seçip periyot değerine 124 verirsek tam olarak 1 mS elde ederiz.
Timer kesmesi kullanmak için DeInit() yaptık dan sonra Precaler ve Period değerimizi init edelim.
1 2 3 4 |
/* Default configuration */ TIM4_DeInit(); /* Time base configuration */ TIM4_TimeBaseInit(TIM4_PRESCALER_128, 124); |
Timer bayrağını temizleyip “Update” kesmesini aktif ediyoruz. Genel kesmeleride aktif ettikten sonra TIM4’ü çalıştırabiliriz.
1 2 3 4 5 6 7 8 |
/* Clear TIM4 update flag */ TIM4_ClearFlag(TIM4_FLAG_UPDATE); /* Enable update interrupt */ TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE); /* enable interrupts */ enableInterrupts(); /* Enable TIM4 */ TIM4_Cmd(ENABLE); |
Kesme fonksiyonu şu şekilde tanımlanıyor.
1 2 3 4 5 |
INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23) { /* Cleat Interrupt Pending bit */ TIM4_ClearITPendingBit(TIM4_IT_UPDATE); } |
Kesmeye girdiğimizde mutlaka bayrağı temizleyelim. Bunu yapmaz ise yeni kesme gelmez. Şimdi statik bir değişken oluşturup 500 kere tekrarlayarak 500 mS’lik bir kesme elde ettim. Bunu LED çıkışı ile gözlemleyebiliriz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23) { /* Cleat Interrupt Pending bit */ TIM4_ClearITPendingBit(TIM4_IT_UPDATE); static uint32_t timerTick = 0; if (timerTick == 500) { timerTick = 0; GPIO_WriteReverse(LED_GPIO_PORT, LED_GPIO_PINS); } else timerTick++; } |
Kodların tamamını şurada paylaşalım.
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
#include "stm8s.h" #define LED_GPIO_PORT (GPIOB) #define LED_GPIO_PINS (GPIO_PIN_5) #define BUTTON_GPIO_PORT (GPIOB) #define BUTTON_GPIO_PINS (GPIO_PIN_4) static void CLK_Config(void); static void GPIO_Config(void); static void TIM4_Config(void); static void Beeper_Config(void); static uint32_t LSIMeasurment(void); ErrorStatus status = ERROR; INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23) { /* Cleat Interrupt Pending bit */ TIM4_ClearITPendingBit(TIM4_IT_UPDATE); static uint32_t timerTick = 0; if (timerTick == 500) { timerTick = 0; GPIO_WriteReverse(LED_GPIO_PORT, LED_GPIO_PINS); } else timerTick++; } void main(void) { CLK_Config(); GPIO_Config(); TIM4_Config(); Beeper_Config(); for (;;) { if (status) { uint8_t button_state = GPIO_ReadInputPin(BUTTON_GPIO_PORT, (GPIO_Pin_TypeDef)BUTTON_GPIO_PINS); if (button_state == 0) BEEP_Cmd(ENABLE); else BEEP_Cmd(DISABLE); } } } uint32_t LSIMeasurment(void) { uint32_t lsi_freq_hz = 0x0; uint32_t fmaster = 0x0; uint16_t ICValue1 = 0x0; uint16_t ICValue2 = 0x0; /* Get master frequency */ fmaster = CLK_GetClockFreq(); /* Enable the LSI measurement: LSI clock connected to timer Input Capture 1 */ AWU->CSR |= AWU_CSR_MSR; #if defined (STM8S903) || defined (STM8S103) || defined (STM8S003) /* Measure the LSI frequenc y with TIMER Input Capture 1 */ /* Capture only every 8 events!!! */ /* Enable capture of TI1 */ TIM1_ICInit(TIM1_CHANNEL_1, TIM1_ICPOLARITY_RISING, TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV8, 0); /* Enable TIM1 */ TIM1_Cmd(ENABLE); /* wait a capture on cc1 */ while((TIM1->SR1 & TIM1_FLAG_CC1) != TIM1_FLAG_CC1); /* Get CCR1 value*/ ICValue1 = TIM1_GetCapture1(); TIM1_ClearFlag(TIM1_FLAG_CC1); /* wait a capture on cc1 */ while((TIM1->SR1 & TIM1_FLAG_CC1) != TIM1_FLAG_CC1); /* Get CCR1 value*/ ICValue2 = TIM1_GetCapture1(); TIM1_ClearFlag(TIM1_FLAG_CC1); /* Disable IC1 input capture */ TIM1->CCER1 &= (uint8_t)(~TIM1_CCER1_CC1E); /* Disable timer2 */ TIM1_Cmd(DISABLE); #else /* Measure the LSI frequency with TIMER Input Capture 1 */ /* Capture only every 8 events!!! */ /* Enable capture of TI1 */ TIM3_ICInit(TIM3_CHANNEL_1, TIM3_ICPOLARITY_RISING, TIM3_ICSELECTION_DIRECTTI, TIM3_ICPSC_DIV8, 0); TIM3_Cmd(ENABLE); /* wait a capture on cc1 */ while ((TIM3->SR1 & TIM3_FLAG_CC1) != TIM3_FLAG_CC1); /* Get CCR1 value*/ ICValue1 = TIM3_GetCapture1(); TIM3_ClearFlag(TIM3_FLAG_CC1); /* wait a capture on cc1 */ while ((TIM3->SR1 & TIM3_FLAG_CC1) != TIM3_FLAG_CC1); /* Get CCR1 value*/ ICValue2 = TIM3_GetCapture1(); TIM3_ClearFlag(TIM3_FLAG_CC1); /* Disable IC1 input capture */ TIM3->CCER1 &= (uint8_t)(~TIM3_CCER1_CC1E); /* Disable timer3 */ TIM3_Cmd(DISABLE); #endif /* Compute LSI clock frequency */ lsi_freq_hz = (8 * fmaster) / (ICValue2 - ICValue1); /* Disable the LSI measurement: LSI clock disconnected from timer Input Capture 1 */ AWU->CSR &= (uint8_t)(~AWU_CSR_MSR); return (lsi_freq_hz); } static void GPIO_Config(void) { GPIO_Init(LED_GPIO_PORT, (GPIO_Pin_TypeDef)LED_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST); GPIO_Init(BUTTON_GPIO_PORT, (GPIO_Pin_TypeDef)BUTTON_GPIO_PINS, GPIO_MODE_IN_PU_NO_IT); } static void CLK_Config(void) { CLK_DeInit(); CLK_HSICmd(ENABLE); status = CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI, DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE); CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1); CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1); //CLK_CCOConfig(CLK_OUTPUT_CPUDIV64); //CLK_CCOCmd(ENABLE); } static void TIM4_Config(void) { /* TIM4 configuration: - TIM4CLK is set to 16 MHz, the TIM4 Prescaler is equal to 128 so the TIM1 counter clock used is 16 MHz / 128 = 125 000 Hz - With 125 000 Hz we can generate time base: max time base is 2.048 ms if TIM4_PERIOD = 255 --> (255 + 1) / 125000 = 2.048 ms min time base is 0.016 ms if TIM4_PERIOD = 1 --> ( 1 + 1) / 125000 = 0.016 ms - In this example we need to generate a time base equal to 1 ms so TIM4_PERIOD = (0.001 * 125000 - 1) = 124 */ TIM4_DeInit(); /* Time base configuration */ TIM4_TimeBaseInit(TIM4_PRESCALER_128, 124); /* Clear TIM4 update flag */ TIM4_ClearFlag(TIM4_FLAG_UPDATE); /* Enable update interrupt */ TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE); /* enable interrupts */ enableInterrupts(); /* Enable TIM4 */ TIM4_Cmd(ENABLE); } static void Beeper_Config(void) { BEEP_DeInit(); BEEP_LSICalibrationConfig(LSIMeasurment()); BEEP_Init(BEEP_FREQUENCY_1KHZ); BEEP_Cmd(DISABLE); } #ifdef USE_FULL_ASSERT void assert_failed(uint8_t* file, uint32_t line) { while (1); } #endif |
Bu kodda 500 mS’de bir yanıp sönen LED butona basıldığında 1 kHz frekansında öten bir buzzer mevcut. Unutamadan buton ve LED Bağlantısını program içerisinde görüp değiştirebilirsiniz. Ben sadece buton bağlantısı yaptım kartın üzerinde bir adet LED mevcut. Buzzer için ise mutlaka bir transistör kullanın yoksa işlemciye yüklenebilir. Bir sonraki yazıda PWM’i ele alacağım. Şimdilik bu kadar.
Esen kalın !
Bu bölüm özellikle keypad uygulamalarında ya da butonlu davranışlarda, beyaz eşya bölümünde çok yararlı olabiliyor. Bunun yanında ucuz buzzerları kullanmak için de gerekli bir yapı.
Güzel anlatım!
Fırat hocam yorumunuz için çok teşekkür ederim.
Merhaba hocam stm8s0003f3 işlemci kullanıyorum yapmak istediğim işlem tam olarak şu akış sensöründen gelen dalgaları okuyup bu dalgalara göre röleyi aç kapa yapmasıdır.ADC ile denedim değeri alıyorum fakat röle açma kapama işlemi olmuyor acaba tımerlamı yapacağım bilemiyorum Yardımcı olabilir misiniz ?
Merhaba Yusuf Bey,
Kodlarınızı mail adresime yollarsanız inceleyebilirim.
baranekrem@outlook.com
Merhabalar bende stm8s103f3p ile çalışmaya başladım ucuz mavi olanlardan 😀
timer4 ile mikro ve mili saniye cinsinden delay fonksiyonlarını yazarken bir şey fark ettim sinir bozucuydu ilk başlarda, kesme bayrağını handler fonksiyonunun en sonunda sıfırlamanızı öneririm özellikle mikrosaniye cinsinden olan fonksiyonda handler’ın en başında reset ediyordum bu bayrağı ve fonksiyon içerisinde yapılan tek şey flag reset ve delay +=1; idi.Oluşan problem ise daha handler fonksiyonundan çıkmadan tekrar keseme geliyordu ve program sanki handler içinde sonsuz bir döngü yaratıyordu ama döngü delay+=1 e gelmeden tekrar dönüyordu yani sürekli handler içerisinde bayrak sıfırlanıyor gibi bir şey oluyordu belki geç olsa bile sadece deneyimimi paylaşmak istedim.