STM32: pengatur waktu dasar. STM32F3

Sebenarnya, oleh karena itu, mari kita langsung beralih ke pemrograman. Ambil salah satu pengatur waktu mikrokontroler dasar STM32F3, kami akan membuat pengaturan minimum dan mencoba menghasilkan interupsi secara berkala. Contoh paling sederhana

Jadi dari Perpustakaan Periferal Standar kita membutuhkan beberapa file yang mengimplementasikan interaksi dengan register timer:

#sertakan "stm32f30x_gpio.h" #sertakan "stm32f30x_rcc.h" #sertakan "stm32f30x_tim.h" #sertakan "stm32f30x.h" /*******************************************************************/ Timer TIM_TimeBaseInitTypeDef; /*******************************************************************/

Inisialisasi timer minimal terlihat seperti ini. Omong-omong, pada saat yang sama kami akan mengatur salah satu kaki pengontrol untuk bekerja dalam mode keluaran. Anda hanya perlu mengedipkan LED

/*******************************************************************/ batalkan initAll() ( // Clocking - di mana tanpanya RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, AKTIFKAN) ; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, AKTIFKAN) ; // Kami memiliki LED biru pada pin ini (STM32F3Discovery) gpio.GPIO_Mode = GPIO_Mode_OUT; gpio.GPIO_Pin = GPIO_Pin_8; gpio.GPIO_OType = GPIO_OType_PP; gpio.GPIO_Speed ​​​​= GPIO_Speed_50MHz; GPIO_Init(GPIOE, & gpio); // Dan inilah pengaturan timer TIM2 yang sudah lama ditunggu-tunggu TIM_TimeBaseStructInit(&timer) ; timer.TIM_Prescaler = 7200 ; timer.TIM_Period = 20000 ; TIM_TimeBaseInit(TIM2, & pengatur waktu); /*******************************************************************/

Di sini perlu memperhatikan dua angka yang datang entah dari mana - 7200 Dan 20000 . Sekarang mari kita cari tahu apa itu Timer saya memiliki frekuensi 72 MHz. Prescaler, juga dikenal sebagai prescaler, diperlukan untuk membagi frekuensi ini) Jadi, kita mendapatkan 72 MHz / 7200 = 10 kHz. Jadi satu centang pengatur waktu sesuai dengan (1/10000) detik, yang sama dengan 100 mikrodetik. Periode timer adalah nilai, setelah menghitung hingga program akan terbang ke pengendali interupsi pada timer overflow. Dalam kasus kami, penghitung waktu berdetak hingga 20000 , yang sesuai (100 * 20000) s atau 2 detik. Artinya, LED (yang kita nyalakan dan matikan di pengendali interupsi) akan berkedip dengan titik 4 detik (2 detik aktif, 2 detik tidak terbakar =)). Sekarang dengan ini semuanya jelas, kami melanjutkan ...

dalam fungsi utama() kami memanggil fungsi inisialisasi, dan juga mengaktifkan interupsi dan pengatur waktu. Dalam sebuah siklus sementara(1) bahkan lebih sedikit kode - hanya kosong

/*******************************************************************/ int main() ( __enable_irq() ; initAll() ; TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE) ; TIM_Cmd(TIM2, ENABLE) ; NVIC_EnableIRQ(TIM2_IRQn) ; while (1 ) ( ) ) /*******************************************************************/

Semuanya, tinggal menulis beberapa baris untuk penangan interupsi, dan pekerjaan selesai:

/*******************************************************************/ void TIM2_IRQHandler() ( TIM_ClearITPendingBit(TIM2, TIM_IT_Update) ; if (GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_8) == 1 ) ( GPIO_ResetBits(GPIOE, GPIO_Pin_8) ; GPIO_) else ( GPIO_)_ /*******************************************************************/

Setelah mem-flash program ke pengontrol, kami mengamati LED biru yang berkedip, oleh karena itu program berfungsi dengan benar! Pada prinsipnya, ini saja untuk hari ini, artikel yang begitu singkat ternyata)

Kami telah melihat timer SysTick, yang merupakan bagian dari inti Cortex. Namun, itu tidak berakhir di situ. Ada banyak timer di stm32, dan mereka berbeda. Bergantung pada tujuannya, Anda harus memilih satu atau beberapa pengatur waktu:

  • SysTick;
  • pengatur waktu tujuan umum - TIM2, TIM3, TIM4, TIM15, TIM16, TIM17;
  • pengatur waktu lanjutan (pengatur waktu lanjutan bahasa Inggris) - TIM1;
  • pengatur waktu.

Satu-satunya hal yang layak disebutkan tentang yang terakhir adalah bahwa ia dirancang untuk mengontrol pembekuan sistem dan merupakan pengatur waktu yang perlu diatur ulang secara berkala. Jika timer tidak direset dalam selang waktu tertentu, watchdog timer akan mereset sistem (mikrokontroler).

Timer datang dalam ukuran bit yang berbeda: misalnya, SysTick adalah 24-bit, dan semua timer yang kami miliki adalah 16-bit (yaitu, mereka dapat menghitung hingga 2 16 = 65535), kecuali untuk WatchDog. Selain itu, setiap pengatur waktu memiliki sejumlah saluran, yang sebenarnya dapat bekerja untuk dua, tiga, dll. Pengatur waktu ini dapat bekerja dengan enkoder inkremental, sensor Hall, mereka dapat menghasilkan PWM (modulasi lebar pulsa, eng. Modulasi Lebar Pulsa - yang akan kita bicarakan nanti) dan banyak lagi. Selain itu, mereka dapat menghasilkan interupsi atau membuat permintaan ke modul lain (misalnya, ke DMA - Akses Memori Langsung) di berbagai acara:

  • overflow (bahasa Inggris overflow);
  • penangkapan sinyal (eng. penangkapan input);
  • perbandingan (perbandingan keluaran bahasa Inggris);
  • event-trigger (pemicu peristiwa bahasa Inggris).

Jika semuanya jelas bagi kami dengan limpahan timer (lebih tepatnya, mencapai "0") - kami menganggap SysTick - maka kami belum terbiasa dengan mode operasi lain yang mungkin. Mari kita lihat lebih detail.

Penangkapan sinyal

Mode ini sangat cocok untuk mengukur periode pulsa (atau jumlahnya, katakanlah, per detik). Ketika pulsa tiba di output MK, timer menghasilkan interupsi dari mana kita dapat menghapus nilai penghitung saat ini (dari register TIM_CCRx, di mana x adalah nomor saluran) dan menyimpannya ke variabel eksternal. Kemudian pulsa berikutnya akan datang, dan dengan pengurangan sederhana kita akan mendapatkan "waktu" antara dua pulsa. Anda dapat menangkap tepi awal dan akhir pulsa, atau bahkan keduanya sekaligus. Mengapa ini dibutuhkan? Katakanlah Anda memiliki magnet yang telah Anda rekatkan pada cakram pada roda, dan sensor efek Hall pada garpu sepeda. Kemudian, saat Anda memutar roda, Anda akan menerima impuls setiap kali magnet pada roda berada pada bidang yang sama dengan sensor Hall. Mengetahui jarak magnet terbang per putaran dan waktu, Anda dapat menghitung kecepatan gerakan.

Ada juga mode pengambilan PWM, tetapi ini lebih merupakan cara khusus untuk mengatur pengatur waktu daripada mode operasi terpisah: satu saluran menangkap tepi yang naik, dan yang kedua menangkap tepi yang turun. Kemudian saluran pertama mendeteksi periode, dan yang kedua - pengisian.

Bandingkan mode

Dalam mode ini, saluran pengatur waktu yang dipilih terhubung ke pin yang sesuai, dan segera setelah pengatur waktu mencapai nilai tertentu, status keluaran akan berubah tergantung pada pengaturan mode (dapat berupa "1" atau "0", atau keadaan keluaran hanya terbalik).

Mode pembuatan PWM

Sesuai dengan namanya, timer dalam mode ini menghasilkan modulasi lebar pulsa. Kita akan berbicara lebih banyak tentang mode ini, serta di mana mode ini dapat / harus digunakan, dalam pelajaran berikutnya setelah mempertimbangkan penangkapan sinyal.

Dengan bantuan pengatur waktu lanjutan, Anda dapat membentuk PWM tiga fase, yang sangat berguna untuk mengendalikan motor tiga fase.

Mode waktu mati

Beberapa pengatur waktu memiliki fitur ini; diperlukan untuk membuat penundaan pada output, yang diperlukan, misalnya, untuk mengecualikan arus saat mengontrol sakelar daya.

Dalam kursus, kami hanya akan menggunakan "penangkapan sinyal" dan "pembuatan pwm".

Mode tangkap adalah mode khusus pengoperasian pengatur waktu, yang intinya adalah sebagai berikut, ketika level logika berubah pada output tertentu dari mikrokontroler, nilai register pencacah ditulis ke register lain, yang disebut daftar penangkapan.

Untuk apa?
Dengan menggunakan mode ini, Anda dapat mengukur durasi pulsa atau periode sinyal.

Mode pengambilan STM32 memiliki beberapa fitur:

  • kemampuan untuk memilih bagian depan mana yang akan aktif
  • kemampuan untuk mengubah frekuensi sinyal input menggunakan prescaler (1,2,4,8)
  • setiap saluran pengambilan memiliki filter input bawaan
  • sumber sinyal tangkapan bisa menjadi pengatur waktu lain
  • dua bendera disediakan untuk setiap saluran, yang pertama diatur jika penangkapan telah terjadi, yang kedua jika penangkapan telah terjadi dengan set bendera pertama

Register digunakan untuk mengatur mode pengambilan. CCMR1(untuk saluran 1 dan 2) dan CCMR2(untuk 3 dan 4), serta register CCER, DIER.

Mari kita lihat lebih dekat bidang bit register CCMR2, yang bertanggung jawab untuk mengatur 4 saluran pengatur waktu, kami akan mengonfigurasinya dalam contoh. Saya juga ingin mencatat bahwa dalam register yang sama ada bidang bit yang digunakan saat mengatur timer dalam mode perbandingan.

CC4S- menentukan arah saluran keempat (input atau output). Saat mengonfigurasi saluran sebagai input, petakan sinyal tangkapan ke sana

  • 00 - saluran berfungsi sebagai keluaran
  • 01 - saluran berfungsi sebagai input, menangkap sinyal - TI4
  • 10 - saluran berfungsi sebagai input, menangkap sinyal - TI3
  • 11 - saluran berfungsi sebagai input, menangkap sinyal - TRC
IC4PSC– tentukan faktor pembagian, untuk sinyal tangkap
  • 00 - pembagi tidak digunakan, sinyal penangkapan IC1PS dihasilkan untuk setiap acara
  • 01 - sinyal tangkap dihasilkan untuk setiap peristiwa kedua
  • 10 - sinyal penangkapan dihasilkan untuk setiap peristiwa keempat
  • 11 - sinyal penangkapan dihasilkan untuk setiap acara kedelapan
IC4F- dirancang untuk menyesuaikan filter input, selain jumlah sampel di mana mikrokontroler tidak akan merespons sinyal input, Anda juga dapat menyesuaikan laju pengambilan sampel. Intinya, kami menyesuaikan waktu tunda dari saat tepi tiba ke sampel "pengakuan".

Sekarang mari kita lihat registernya CCER.

CC4E- mengaktifkan/menonaktifkan mode pengambilan.
CC4P- menentukan bagian depan di mana penangkapan akan dilakukan, 0 - depan, 1 - belakang.

Dan daftar DIER.

CC4DE- memungkinkan untuk membentuk permintaan ke DMA.
CC4IE- Mengaktifkan interupsi penangkapan.

Setelah penangkapan terjadi, peristiwa penangkapan dihasilkan yang menetapkan bendera yang sesuai. Ini dapat menyebabkan interupsi dihasilkan dan permintaan DMA jika mereka diizinkan dalam daftar DIER. Selain itu, peristiwa penangkapan dapat dihasilkan secara terprogram dengan mengatur bidang bit dalam register pembangkitan peristiwa EGR:

bidang bit CC1G, CC2G, CC3G dan CC4G memungkinkan Anda membuat acara di saluran tangkap/bandingkan yang sesuai.

Omong-omong, CCR1, CCR2, CCR3 dan CCR4- register tangkap, yang menyimpan nilai pengatur waktu pada sinyal tangkap.

Untuk mengontrol pembentukan sinyal tangkap, di register SR Setiap saluran memiliki dua bendera.

CC4IF- disetel saat sinyal tangkap dihasilkan, tanda ini direset oleh perangkat lunak atau dengan membaca register tangkap/bandingkan yang sesuai.
CC4OF- disetel jika bendera CC4IF belum dihapus, tetapi sinyal penangkapan lain telah tiba. Bendera ini dihapus secara terprogram dengan menulis nol.

Sekarang mari kita terapkan pengetahuan yang diperoleh dalam praktik, dari generator sinyal ke input TIM5_CH4 kita akan menerapkan sinusoid dengan frekuensi 50 Hz dan mencoba mengukur periodenya. Untuk mempercepat proses, saya sarankan menggunakan DMA. Output MK mana yang sesuai dengan saluran ke-4 TIM5 dapat ditemukan di lembar data di MK di bagian Pinouts dan deskripsi pin.

Untuk DMA alamat pendaftaran diperlukan CCR4, berikut cara menemukannya. Kita buka RM0008 dan di meja Daftarkan alamat batas temukan alamat awal TIM5.


daftar offset CCR4 dapat ditemukan di dokumen yang sama di bawah daftar peta.

#include "stm32f10x.h" #define TIM5_CCR4_Address ((u32)0x40000C00+0x40) #define DMA_BUFF_SIZE 2 uint16_t buff;//Buffer uint16_t volatile T; void DMA2_Channel1_IRQHandler (void) ( T = (buff > buff) ? (buff - buff) : (65535+ buff - buff); DMA2->IFCR |= DMA_IFCR_CGIF1; ) void Init_DMA(void) ( RCC->AHBENR |= RCC_AHBENR_DMA2ENAHBENR_DMA2 ; //Aktifkan clocking modul DMA pertama DMA2_Channel1->CPAR = TIM5_CCR4_Address; //Tentukan alamat periferal - register hasil konversi ADC untuk saluran reguler DMA2_Channel1->CMAR = (uint32_t)buff; //Setel alamat memori - alamat dasar array di RAM DMA2_Channel1 ->CCR &= ~DMA_CCR1_DIR; //Menentukan arah transfer data, dari periferal ke memori DMA2_Channel1->CNDTR = DMA_BUFF_SIZE; //Jumlah nilai yang ditransfer DMA2_Channel1->CCR & = ~DMA_CCR1_PINC; //Jangan menambah alamat periferal setelah setiap transfer DMA2_Channel1 ->CCR |= DMA_CCR1_MINC; //Menambahkan alamat memori setelah setiap transfer DMA2_Channel1->CCR |= DMA_CCR1_PSIZE_0; //Ukuran data periferal - 16 bit DMA2_Channel CCR |= DMA_CCR1_MSIZE_0; //Ukuran data memori - 16 bit DMA2_Channel1- >CCR |= DMA_CCR1_PL; //Prioritas sangat tinggi DMA2_Channel1->CCR |= DMA_CCR1_CIRC; //Aktifkan DMA dalam mode siklik DMA2_Channel1->CCR |= DMA_CCR1_TCIE;//Aktifkan interupsi di akhir transfer DMA2_Channel1->CCR |= DMA_CCR1_EN; // Aktifkan saluran DMA pertama ) int main(void) ( Init_DMA(); // aktifkan clocking port A, fungsi alternatif dan timer RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN; RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; >PSC = 56000-1;//frekuensi baru 1Khz TIM5->CCMR2 |= TIM_CCMR2_CC4S_0;//pilih TI4 untuk TIM5_CH4 TIM5->CCMR2 &= ~(TIM_CCMR2_IC4F | TIM_CCMR2_IC4PSC);//jangan filter dan sekat gunakan TIM5- >CCER &= ~TIM_CCER_CC4P;//pilih tangkap di tepi naik TIM5->CCER |= TIM_CCER_CC4E;//aktifkan mode tangkap untuk saluran ke-4 TIM5->DIER |= TIM_DIER_CC4DE;//izinkan untuk membuat permintaan ke DMA //TIM5 ->DIER |= TIM_DIER_CC4IE; //aktifkan interupsi capture TIM5->CR1 |= TIM_CR1_CEN; //aktifkan counter //NVIC->ISER |= NVIC_ISER_SETENA_18; //TIM5 Interrupt NVIC->ISER |= NVIC_ISER_SETENA_24 ; //DMA Interupsi sementara(1) ( ) )

STM32 memiliki banyak pengatur waktu yang sangat nyaman dan fleksibel untuk diatur. Bahkan mikrokontroler termuda (STM32F030F4P6) memiliki 4 pengatur waktu seperti itu.

8. Siapkan proyek - tambahkan file yang diperlukan

Untuk menggunakan timer, kita perlu menyertakan file library periferal stm32f10x_tim.c. Dengan cara yang sama, klik kanan di Workspace (jendela di sebelah kiri) pada grup StdPeriphLib, Add -> Add files, file LibrariesSTM32F10x_StdPeriph_Driversrcstm32f10x_tim.c.

Anda juga perlu mengaktifkan penggunaan header untuk file ini. Buka stm32f10x_conf.h (klik kanan pada nama file ini dalam kode, "Open stm32f10x_conf.h". Batalkan komentar pada baris #include "stm32f10x_tim.h".

9. Tambahkan pengatur waktu

Penundaan dengan siklus kosong adalah penistaan, terutama pada kristal yang kuat seperti STM32, dengan banyak pengatur waktu. Oleh karena itu, kami akan membuat penundaan ini menggunakan timer.

STM32 memiliki timer berbeda yang berbeda dalam set propertinya. Yang paling sederhana adalah pengatur waktu dasar, yang lebih sulit adalah pengatur waktu tujuan umum, dan yang paling sulit adalah pengatur waktu tingkat lanjut. Penghitung waktu sederhana terbatas hanya menghitung siklus. Di penghitung waktu yang lebih kompleks, PWM muncul. Timer paling canggih, misalnya, dapat menghasilkan PWM 3 fase dengan output maju dan mundur serta waktu mati. Pengatur waktu sederhana, nomor 6, sudah cukup bagi kita.

Sedikit teori

Yang kita butuhkan dari pengatur waktu adalah menghitung hingga nilai tertentu dan menghasilkan interupsi (ya, kita juga akan belajar cara menggunakan interupsi). Timer TIM6 di-clock dari bus sistem, tetapi tidak secara langsung, tetapi melalui prescaler - pembagi penghitung sederhana yang dapat diprogram (bayangkan saja, penghitung sirkuit mikro khusus diproduksi di USSR, dan penghitung yang dapat diprogram adalah defisit khusus - dan sekarang saya sedang berbicara tentang penghitung seperti itu dengan santai). Prescaler dapat diatur ke nilai apa pun dari 1 (yaitu, frekuensi bus penuh, 24 MHz, akan mencapai penghitung) hingga 65536 (yaitu, 366 Hz).

Sinyal jam, pada gilirannya, meningkatkan penghitung waktu internal, mulai dari nol. Segera setelah nilai penghitung mencapai nilai ARR, penghitung meluap dan peristiwa yang sesuai terjadi. Pada terjadinya peristiwa ini, timer memuat 0 ke counter lagi, dan mulai menghitung dari nol. Pada saat yang sama, ini dapat memicu interupsi (jika dikonfigurasi).

Faktanya, prosesnya sedikit lebih rumit: ada dua register ARR - eksternal dan internal. Selama perhitungan, nilai saat ini dibandingkan dengan tepat dengan register internal, dan hanya ketika meluap adalah yang internal diperbarui dari yang eksternal. Jadi, aman untuk mengubah ARR saat timer sedang berjalan - kapan saja.

Kode

Kode akan sangat mirip dengan yang sebelumnya, karena. inisialisasi semua periferal terjadi dengan cara yang sama - dengan satu-satunya pengecualian bahwa timer TIM6 hang di bus APB1. Oleh karena itu, aktifkan timer: RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);

Sekarang kita membuat struktur tipe TIM_TimeBaseInitTypeDef, menginisialisasinya (TIM_TimeBaseStructInit), mengaturnya, meneruskannya ke fungsi inisialisasi timer (TIM_TimeBaseInit) dan akhirnya mengaktifkan timer (TIM_Cmd).

TIM_TimeBaseInitTypeDef TIM_InitStructure; // Siapkan struktur TIM_TimeBaseStructInit(&TIM_InitStructure); // Inisialisasi struktur TIM_InitStructure TIM_Prescaler = 24000; // Prescaler TIM_InitStructure.TIM_Period = 1000; // Periode pengatur waktu TIM_TimeBaseInit(TIM6, &TIM_InitStructure); // Fungsi pengaturan timer TIM_Cmd(TIM6, ENABLE); // Nyalakan pengatur waktu

Apa angka ajaibnya? Seperti yang kita ingat, ada frekuensi clock 24 MHz di bus (dengan pengaturan proyek kami). Dengan mengatur timer prescaler ke 24000, kami membagi frekuensi ini dengan 24 ribu, dan kami mendapatkan 1kHz. Frekuensi inilah yang akan masuk ke input penghitung waktu.

Nilai di penghitung adalah 1000. Ini berarti penghitung akan meluap dalam 1000 siklus, mis. tepat 1 detik.

Setelah itu, kami benar-benar memiliki pengatur waktu yang berfungsi. Tapi itu tidak semua.

10. Menangani interupsi

Oke, gangguan. Bagi saya, sekali (selama hari-hari PIC) mereka adalah hutan yang gelap, dan saya mencoba untuk tidak menggunakannya sama sekali - dan saya tidak tahu bagaimana sebenarnya. Namun, mereka mengandung kekuatan yang umumnya tidak layak untuk diabaikan. Benar, interupsi di STM32 adalah hal yang lebih rumit, terutama mekanisme untuk mendahuluinya; tetapi lebih pada itu nanti.

Seperti yang kami catat sebelumnya, timer menghasilkan interupsi pada saat penghitung meluap - jika pemrosesan interupsi perangkat ini diaktifkan sama sekali, interupsi khusus ini diaktifkan dan yang sebelumnya disetel ulang. Menganalisis frasa ini, kami memahami apa yang kami butuhkan:

  1. Aktifkan interupsi timer TIM6 sama sekali;
  2. Aktifkan timer interupsi TIM6 untuk counter overflow;
  3. Tulis prosedur penanganan interupsi;
  4. Setelah memproses interupsi, setel ulang.

Aktifkan interupsi

Sejujurnya, tidak ada yang rumit sama sekali. Pertama-tama, aktifkan interupsi TIM6: NVIC_EnableIRQ(TIM6_DAC_IRQn); Mengapa nama seperti itu? Karena pada inti STM32, interupsi dari TIM6 dan dari DAC memiliki nomor yang sama. Saya tidak tahu mengapa dilakukan dengan cara ini - penghematan, kekurangan jumlah, atau hanya semacam warisan - dalam hal apa pun, ini tidak akan membawa masalah, karena proyek ini tidak menggunakan DAC. Bahkan jika DAC digunakan dalam proyek kami, kami dapat mengetahui siapa yang secara khusus memanggilnya saat memasuki interupsi. Hampir semua timer lain memiliki satu interupsi.

Mengganggu konfigurasi acara sumber: TIM_ITConfig(TIM6, TIM_DIER_UIE, ENABLE); - nyalakan interupsi pengatur waktu TIM6 pada acara TIM_DIER_UIE, mis. Acara pembaruan nilai ARR. Seperti yang kita ingat dari gambar, ini terjadi pada saat yang sama dengan counter overflow - jadi inilah acara yang kita butuhkan.

Saat ini, kode kasus timer adalah sebagai berikut:

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, AKTIFKAN); TIM_TimeBaseInitTypeDef TIM_InitStructure; TIM_TimeBaseStructInit(&TIM_InitStructure); TIM_InitStructure.TIM_Prescaler = 24000; TIM_InitStructure.TIM_Period = 1000; TIM_TimeBaseInit(TIM6, &TIM_InitStructure); TIM_Cmd(TIM6, AKTIFKAN); NVIC_EnableIRQ(TIM6_DAC_IRQn); TIM_ITConfig(TIM6, TIM_DIER_UIE, AKTIFKAN);

Penanganan interupsi

Sekarang Anda tidak dapat memulai proyek - interupsi pertama dari timer tidak akan menemukan handler-nya, dan controller akan hang (lebih tepatnya, itu akan jatuh ke handler HARD_FAULT, yang pada dasarnya adalah hal yang sama). Anda perlu menulisnya.

Sedikit teori

Itu harus memiliki nama yang sangat spesifik, void TIM6_DAC_IRQHandler(void). Nama ini, yang disebut vektor interupsi, dijelaskan dalam file startup (dalam proyek kami ini adalah startup_stm32f10x_md_vl.s - Anda dapat melihatnya sendiri, baris 126). Faktanya, vektor adalah alamat pengendali interupsi, dan ketika interupsi terjadi, inti ARM merangkak ke area awal (ke mana file startup diterjemahkan - yaitu lokasinya diatur sepenuhnya secara kaku, di awal memori flash), mencari vektor di sana dan pergi ke tempat yang tepat dalam kode.

Pemeriksaan Acara

Hal pertama yang perlu kita lakukan saat memasukkan handler seperti itu adalah memeriksa event mana yang menyebabkan interupsi. Sekarang kami hanya memiliki satu acara, tetapi dalam proyek nyata mungkin ada beberapa acara dalam satu pengatur waktu. Oleh karena itu, kami memeriksa acara tersebut, dan menjalankan kode yang sesuai.

Dalam program kami, pemeriksaan ini akan terlihat seperti ini: if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) - semuanya jelas, fungsi TIM_GetITStatus memeriksa apakah timer memiliki peristiwa yang ditentukan dan mengembalikan 0 atau 1.

Membersihkan Bendera UIF

Langkah kedua adalah menghapus flag interupsi. Kembali ke gambar: grafik UIF terakhir adalah flag interupsi. Jika tidak dibersihkan, interupsi berikutnya tidak akan dapat dipanggil, dan pengontrol akan kembali jatuh ke HARD_FAULT (apa itu!).

Melakukan tindakan dalam interupsi

Kami hanya akan mengganti status LED, seperti pada program pertama. Bedanya, sekarang program kami membuatnya lebih sulit! Sebenarnya, jauh lebih tepat untuk menulis dengan cara ini.

If(state) GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_SET); else GPIO_WriteBit(GPIOC, GPIO_Pin_8, Bit_RESET); negara bagian = 1 - negara bagian;

Kami menggunakan variabel global int state=0;

11. Semua kode proyek dengan pengatur waktu

#include "stm32f10x_conf.h" int state=0; void TIM6_DAC_IRQHandler(void) ( if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) ( TIM_ClearITPendingBit(TIM6, TIM_IT_Update); if(state) GPIO_WriteBit(GPIOC, GPIO_Pin_8); = 1 - negara;)) void main () (RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_StructInit (& GPIO_InitStructure); GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_Init (GPIOC, & GPIO_InitStructure); GPIO_WriteBit (GPIOC, GPIO_Pin_8, Bit_SET); RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM6, ENABLE); TIM_TimeBaseInitTypeDef TIM_InitStructure; TIM_TimeBaseStructInit (& TIM_InitStructure); TIM_InitStructure.TIM_Prescaler = 24000; TIM_InitStructure.TIM_Period = 1000; TIM_TimeBaseInit (TIM6, & TIM_InitStructure); TIM_Cmd (TIM6, ENABLE ); NVIC_EnableIRQ(TIM6_DAC_IRQn); TIM_ITConfig(TIM6, TIM_DIER_UIE, ENABLE); while(1) ( ) )

Arsipkan dengan proyek pengatur waktu.

Omong-omong, penghitung waktu dapat mengganti kaki itu sendiri, tanpa gangguan dan pemrosesan manual. Ini akan menjadi proyek ketiga kami.

Seluruh siklus:

1. Port I/O

2. Timer dan interupsi

3. Keluaran pengatur waktu

4. Interupsi eksternal dan NVIC

5. Instal FreeRTOS

Tampilan Postingan: 235