نلاحظ مجتمعًا يعتمد بشكل متزايد على الآلات ، ولكن في نفس الوقت يستخدمها بشكل أكثر فاعلية. - دوجلاس روشكوف
يجب أن تكون هذه العبارة بمثابة حافز لكل مبرمج. بعد كل شيء ، أنت من يقرر كيف تستخدم الآلة مواردها. ولكن اعتبارًا من بداية الوقت ، يعهد الشخص بحقه في اتخاذ القرار لأطراف ثالثة مقابل الطريقة السهلة. قبل أن تسألني عن مزايا مقالاتي عندما يكون هناك "مكعب" ، اسأل نفسك لماذا يقرر "المكعب" بالنسبة لي.STM32 الجزء الأول: أساسياتSTM32 الجزء 2: التهيئةلذا ، دعنا نواصل مغامرتنا. لقد كتبنا بالفعل نص التهيئة ، اكتشفنا الرابط والمترجم. حان الوقت وميض LED. في هذه المقالة ، سنستعرض أساسيات كتلة RCC و GPIO ، ونضيف زوجين من العناوين ، التي سنستخدمها في المشاريع المستقبلية. اذهب.RCC - إعادة الضبط والتحكم في الساعة ، كتلة من السجلات التي تتحكم في ساعة المعالج والأجهزة الطرفية. يتم التحكم في العديد من مصادر الساعة بواسطة هذه الوحدة: HSI (داخلي عالي السرعة) ، HSE (خارجي عالي السرعة) ، PLL / PLLSAI / PLLI2S (قفل حلقة متدرجة). يمكن للمعالج استخدام جميع مصادر الساعة الثلاثة هذه ، بالطبع ، إذا تم تكوين سجلات كتلة RCC بشكل صحيح. سنتحدث عن هذا بالتفصيل في المقالة التالية.GPIO - الإدخال والإخراج للأغراض العامة. كتلة السجلات التي تم إنشاؤها لمصابيح LED الوامضة ، أي أنها كتلة للتحكم في أرجل ميكروناتنا ، وهي بوابة للعالم الحقيقي. على عكس Atmega328p (Arduino) المألوف ، يقدم stm32 تخصيصًا أوسع للأرجل. على سبيل المثال ، وظيفة القدم المفتوحة غير متاحة في ميجا. أيضا ، يمكن تكوين التحكم في السرعة الذي ترفع فيه المملكة المتحدة الجهد على الساق.لذا ، فلنومض بالفعل ، نعم. نحتاج أولاً إلى عنوانين نصف فيهما بنية هذه السجلات. لذلك ، نحصل على الدليل المرجعي وندرسه بحثًا عن المعلومات التي نحتاجها. أنا أعمل على STM32F746NG - اكتشاف حتى كل التعليمات البرمجية لهذا المنتدى.أول شيء نحتاجه هو عناوين هذه الكتل ، الأساسية. لنبدأ مع كتلة RCC وإنشاء رأس rcc.h. سنقوم فيه بإنشاء ماكرو RCC_BASE ، وكذلك وصف بنية كتلة التسجيل ، وإنشاء مؤشر للبنية.rcc.h#define RCC_BASE 0x40023800
typedef struct
{
volatile unsigned int CR;
volatile unsigned int PLLCFGR;
volatile unsigned int CFGR;
volatile unsigned int CIR;
volatile unsigned int AHB1RSTR;
volatile unsigned int AHB2RSTR;
volatile unsigned int AHB3RSTR;
unsigned int RESERVED0;
volatile unsigned int APB1RSTR;
volatile unsigned int APB2RSTR;
unsigned int RESERVED1[2];
volatile unsigned int AHB1ENR;
volatile unsigned int AHB2ENR;
volatile unsigned int AHB3ENR;
unsigned int RESERVED2;
volatile unsigned int APB1ENR;
volatile unsigned int APB2ENR;
unsigned int RESERVED3[2];
volatile unsigned int AHB1LPENR;
volatile unsigned int AHB2LPENR;
volatile unsigned int AHB3LPENR;
unsigned int RESERVED4;
volatile unsigned int APB1LPENR;
volatile unsigned int APB2LPENR;
unsigned int RESERVED5[2];
volatile unsigned int BDCR;
volatile unsigned int CSR;
unsigned int RESERVED6[2];
volatile unsigned int SSCGR;
volatile unsigned int PLLI2SCFGR;
volatile unsigned int PLLSAICFGR;
volatile unsigned int DCKCFGR1;
volatile unsigned int DCKCFGR2;
} RCC_Struct;
#define RCC ((RCC_Struct *) RCC_BASE)
دعنا نقوم بنفس العملية مع كتلة تسجيل GPIO ، فقط بدون مؤشر ، وإضافة ماكرو آخر ، GPIO_OFFSET. نتحدث عنه أدناه.gpio.h#define GPIO_BASE 0x40020000
#define GPIO_OFFSET 0x400
typedef struct
{
volatile unsigned int MODER;
volatile unsigned int OTYPER;
volatile unsigned int OSPEEDR;
volatile unsigned int PUPDR;
volatile unsigned int IDR;
volatile unsigned int ODR;
volatile unsigned int BSRR;
volatile unsigned int LCKR;
volatile unsigned int AFR[2];
} GPIO_Struct;
دعونا نرى ما هو الأمر هنا ولماذا نحتاج إلى الهياكل. والحقيقة هي أنه يمكننا الوصول إلى السجل من خلال مؤشر إلى هيكل ، ولا نحتاج إلى تهيئته لأنه موجود بالفعل فعليًا. فمثلا:RCC->AHB1ENR = 0;
هذا يوفر مساحة الذاكرة ، وأحيانًا لا يتطلبها على الإطلاق. ولكن ليس عن إنقاذ اليوم.لذا لدينا رأسان جاهزان ، يبقى تعلم كيفية القفز بمساعدة هذه السجلات وإنشاء int main();
. كل شيء بسيط وليس تمامًا. في STM32 ، للوصول إلى كتلة التسجيل ، يجب علينا أولاً تطبيق ساعة عليها ، وإلا ستصل البيانات إليها. لن أتعمق في هيكل الإطار ، ولكن فقط أقول كما هو. توضع الكتل على إطارات مختلفة. تقع وحدتنا في حافلة AHB1. أي أننا بحاجة إلى تمكين منفذ معين على ناقل AHB1 ، في حالتي هو المنفذ الأول. بالنسبة للمبتدئين ، بالطبع نحتاج إلى الوظيفة الرئيسية.دعونا نقوم بتحديث ملف بدء التشغيل الخاص بنا قليلاً ونضيف int main () ؛ إليه. ثم قم بإنشاء ملف main.c نفسهextern void *_estack;
void Reset_Handler();
void Default_Handler();
int main();
void NMI_Handler() __attribute__ ((weak, alias ("Default_Handler")));
void HardFault_Handler() __attribute__ ((weak, alias ("Default_Handler")));
void *vectors[] __attribute__((section(".isr_vector"), used)) = {
&_estack,
&Reset_Handler,
&NMI_Handler,
&HardFault_Handler
};
extern void *_sidata, *_sdata, *_edata, *_sbss, *_ebss;
void __attribute__((naked, noreturn)) Reset_Handler()
{
void **pSource, **pDest;
for (pSource = &_sidata, pDest = &_sdata; pDest != &_edata; pSource++, pDest++)
*pDest = *pSource;
for (pDest = &_sbss; pDest != &_ebss; pDest++)
*pDest = 0;
main();
while(1);
}
void __attribute__((naked, noreturn)) Default_Handler(){
while(1);
}
والآن نقوم بإنشاء ملف main.c. نفسه في الملف ، حاولت أن أرسم كل شيء في التعليقات على الشفرة ، لذلك نقرأها ونتعمق فيها. إذا كانت لديك أسئلة ، فاكتب في التعليقات أدناه وسأجيب.#include "rcc.h"
#include "gpio.h"
int main()
{
RCC->AHB1ENR |= (1<<8);
volatile GPIO_Struct *GPIOI = (GPIO_Struct *)(GPIO_BASE + (GPIO_OFFSET*8));
GPIOI->MODER |= (1<<2);
GPIOI->OTYPER &= ~(1<<1);
GPIOI->OSPEEDR |= (2<<2);
while(1){
for(volatile int i = 0; i < 1000000; i++){
}
GPIOI->ODR ^= (1<<1);
}
return 0;
}
الآن علينا أن نضع مشروعًا ونضعه على الميكرونات للتحقق. لقد قمت بنشر مستودع على Github كل ما عليك القيام به هو تشغيل الأداة المساعدة Make.make
شكرًا لكم جميعًا على اهتمامكم ، في المقالة التالية سنتحدث أكثر عن وحدة RCC وكيفية العمل معها.