آموزش STM32 رجیستری : مبانی برنامه نویسی رجیستری

  1. Home
  2. /
  3. آموزش STM32
  4. /
  5. آموزش STM32 : مبانی برنامه نویسی رجیستری

در این مقاله آموزش میبینید که برای برنامه نویسی رجیستری میکروکنترلرهای STM32 چطوری پوینتر میسازیم. ابتدا بررسی میکنیم که برای پروژه led چشمک زن با میکروکنترلر STM32F103C8 روی برد بلوپیل چه رجیسترهایی رو باید تغییر بدیم، سپس سه روش ساخت پوینتر برای دسترسی به رجیستر ها رو آموزش میبینید و سه بار پروژه led چشمک زن رو انجام میدیم. کد در نرم افزار STM32CubeIDE نوشته میشه و از پروگرمر ST-link v2 برای load کردن کد استفاده میکنیم.

این مقاله بخشی از ویدئوی آموزشی ” صفر تا صد برنامه نویسی با رجیسترها برای میکروکنترلر های STM32 ” هست که ویدئوی معرفی دوره جامع آموزش برنامه نویسی میکروکنترلر ARM با STM32 میباشد.

بخش اول : مقدمه

برنامه نویسی رجیستری میکروکنترلر های STM32 یعنی چی؟

ابتدا باید اجزا میکروکنترلر رو بشناسید و هدف از دسترسی به رجیسترهای میکروکنترلرهای STM32 رو بدونید

یک میکروکنترلر از چهار بخش اصلی تشکیل شده .

+ Cpu : که وظیفه ی اجرای کد رو به عهده داره

+ حافظه ها: مثل فلش برای ذخیره سازی کد و رم برای ذخیره سازی متغیرها

+ باس ها: برای جابجایی دیتا بین بخش های مختلف

+ پریفرال ها: مدار های الکترونیکی که برای انجام کار خاصی طراحی شده اند. مثلا هر پریفرال GPIO در میکروکنترلرهای stm32 در مورد تا 16 پین وظیفه تنظیم پین میکروکنترلر در حالت ورودی یا خروجی دیجیتال ، مشخص کردن وضعیت پین خروجی، اطلاع از وضعیت پین ورودی رو به عهده داره.

تنظیم پریفرال ها

فرض کنید میخواهیم یکی از پین های میکروکنترلر رو در حالت خروجی تنظیم کنیم چطور باید با پریفرال GPIO ارتباط برقرار کنیم و ازش بخواهیم تنظیمات مورد نیاز رو برای ما اعمال کنه؟

پریفرال GPIO هم مثل سایر پریفرال ها فضایی در حافظه مختص خورش داره که شامل تعدادی رجیستره، برای اینکه از پریفرال در راستای اهدافمون استفاده کنیم باید اعداد مشخصی رو در رجیستر های پریفرال بنویسیم. در میکروکنترلرهای STM32F1 رجیسترها فضای 16 یا 32 بیتی ( 2 یا 4 بایت ) در حافظه هستند.

بخش بزرگی از کاری که در برنامه نویسی میکروکنترلر ها انجام میدیم تنظیم پریفرال با تغییر محتوای رجیسترهای اونهاست. در پروژه هایی که با میکروکنترلر های STM32 انجام میدیم برای تغییر محتویات رجیسترها میتونیم  از کتابخونه ها مثلا کتابخونه hal استفاده کنیم، توابع hal رو فراخوانی میکنیم و در اون توابع مقدار رجیسترها تغییر داده میشه ، همچنین میتونیم خودمون بدون استفاده از کتابخونه ها مستقیما مقدار رجیسترها رو تغییر بدیم، به این کار میگن برنامه نویسی با رجیسترها .

تمام توضیحات مربوط به امکانات پریفرال ها ، رجیستر های هر پریفرال و اینکه برای رسیدن به تنظیم دلخواه چه اعدادی رو باید در رجیستر ها بنویسیم در رفرنس منوال میکروکنترلر های STM32F103 آورده شده.   

دانلود رفرنس منوال STM32F103

آموزشن STM32 ، پروژه Led چشمک زن با میکروکنترلر STM32F103C8 روی برد Blue pill

در این بخش برد بلوپیل رو برای انجام پروژه led چشمک زن بررسی میکنیم.

قراره برنامه نویسی با رجیستر ها برای میکروکنترلر های STM32 رو با مثال led چشمک زن روی برد blue pill آموزش ببینید. برد blue pill یک برد توسعه است که امکانات اولیه مورد نیاز برای راه اندازی میکروکنترلر STM32F103C8 رو برای ما فراهم میکنه . روی برد blue pill یک led سبز رنگ وجود داره که آند led به 3.3v و کاتد led با یک مقاومت به پین PC13 میکروکنترلر متصل شده. پس وقتی پین PC13 زمین بشه ، led روشن میشه.

دانلود شماتیک برد بلوپیل

میکروکنترلر STM32F103 چهار تا پریفرال GPIO داره:

GPIOA برای پین های PA0 تا PA15

GPIOB برای پین های PB0 تا PB15

GPIOC برای پین های PC13, PC14, PC15

GPIOD برای پین های PD0 و PD1

STM32F103

برای تنظیم پین PC13 میکروکنترلر STM32F103 باید از پریفرال GPIOC استفاده کنیم و مقدار رجیسترهای این پریفرال رو برای رسیدن به هدفمون تغییر بدیم.

آموزش STM32 ، پریفرال GPIO در میکروکنترلر STM32F103

در این بخش بررسی میکنیم برای انجام پروژه led چشمک زن با STM32F103C8 چه بیت هایی رو در چه رجیسترهایی رو باید تغییر بدیم.

هر پریفرال GPIO هفت تا رجیستر 32 بیتی داره ، دو تا رجیستر اول به نام های CRH و CRL برای تنظیم پین ها در حالت ورودی یا خروجی هستند و همچنین نوع ورودی یا خروجی رو هم مشخص میکنند. رجیستر CRL برای تنظیم پین های 0 تا 7 و رجیستر CRH برای پین های 8 تا 15 هستند. در تصویر زیر register map یا نقشه رجیسترهای پریفرال GPIO میکروکنترلرهای STM32F1 رو میبینید که از صفحه ی 194 رفرنس منوال برداشته شده.

STM32F103

برای تنظیمات هر پین هم 4 بیت اختصاص داده شده. دو بیت به نام MODE و دو بیت به نام CNF . مثلا در رجیستر GPIOC_CRH بیت های MODE13 و CNF13 رو داریم که برای تنظیمات پین PC13 هستند. 

STM32F103

برای تنظیم یک پین در حالت ورودی یا خروجی و تنظیم سرعت از بیت های MODE استفاده میشه. جهت تنظیم پین PC13 در حالت خروجی با کمترین سرعت مقدار MODE13 باید 10 باشه، یعنی بیت 20 صفر و بیت 21 باید یک بشه.

برای مشخص کردن حالت ورودی یا خروجی هم از بیت های CNF استفاده میشه ، با توجه به اینکه در مورد پین PC13 وقتی پین زمین بشه بار اکتیو هست، یعنی led روشن میشه ، خروجی push-pull یا open-drain هر دو کار میکنند. اینجا من انتخاب میکنم که خروجی رو open-drain تنظیم کنم پس باید مقدار 01 در بیت های CNF13 ثبت بشه، یعنی بیت 22 یک و بیت 23 باید صفر بشه.

STM32F103

قدم بعدی تغییر وضعیت پین هست ، که برای اینکار از رجیستر ODR استفاده میکنیم. بیت 13 رجیستر ODR از پریفرال GPIOC برای تعیین وضعیت خروجی پین PC13 اختصاص داره. اگر این بیت یک بشه پین PC13 هم 3.3v میشه و اگر بیت صفر بشه وضعیت پین هم 0v یا GND میشه.

STM32F103

آموزش STM32 فعالسازی کلاک پریفرال GPIOC

برای پروژه led چشمک زن مقدار یک رجیستر دیگه رو هم باید تغییر بدیم. همه ی پریفرال های میکروکنترلر برای عملکرد به کلاک نیاز دارند و در شروع کار کلاک تمام پریفرال ها قطعه و از هر پریفرالی بخواهیم استفاده کنیم قبل از تغییر رجیستر های اون پریفرال باید کلاکش رو وصل کنیم. کنترل کلاک میکروکنترلر به عهده ی پریفرال RCC هست. پریفرال RCC سه تا رجیستر داره برای قطع و وصل کردن کلاک سایر پریفرال ها. با توجه به اینکه باید از پریفرال GPIOC استفاده کنیم ، باید ابتدا کلاکش رو فعال کنیم. فعال کردن کلاک این پریفرال با یک کردن بیت IOPCEN ( بیت 4 ) در رجیستر RCC_APB2ENR انجام میشه.

STM32F103

تا اینجای کار میدونیم که برای پروژه led چشمک زن باید چه تغییراتی رو در کدوم رجیستر ها اعمال کنیم. چیزی که هنوز نمیدونیم آدرس این رجیستر هاست. در میکروکنترلرهای STM32F1 حافظه ی مربوط به پریفرال ها از آدرس 0x40000000  شروع میشه و به هر پریفرال 1kb حافظه اختصاص داده شده. هر پریفرال یک base address داره که آدرس اولین رجیستر اون پریفرال هست. Base address  تمام پریفرال ها رو میتونید در نقشه حافظه در صفحه 34 دیتاشیت یا در جدول صفحه ی 50 رفرنس منوال ببینید.

STM32F103

برای بدست آورده آدرس هر رجیستر به base address پریفرال و همچنین آفست اون رجیستر نیاز داریم. آفست یعنی فاصله ی آدرس رجیستر از آدرس اولین رجیستر پریفرال. آفست هر رجیستر رو هم در ستون اول جدول رجیستر مپ هر پریفرال میتونید پیدا کنید. آدرس هر رجیستر با جمع base address پریفرال و آفست رجیستر بدست میاد.

STM32F103

هدف مقاله تا اینجا این بود که بفهید اطلاعات جدول زیر از کجا اومده، الان میدونیم در چه آدرس هایی چه تغییراتی رو باید اعمال کنیم. در قدم بعدی برنامه نویسی رو شروع میکنیم و به محتویات رجیسترهای پریفرال ها دسترسی پیدا میکنیم.

STM32F103

آموزش STM32 ، ساخت پروژه خالی در STM32CubeIDE برای STM32F103C8

برای انجام پروژه باید در نرم افزار STM32CubeIDE یک پروژه خالی برای STM32F103C8 بسازیم.

نرم افزار STM32CubeIDE رو باز کنید و در صفحه launcher ابتدا یک پوشه رو به عنوان workspace ( پوشه ای که یک یا چند پروژه در اون هست ) انتخاب کنید و سپس روی دکمه launch کلیک کنید.

STM32F103

در صفحه ی information center روی start new stm32 project کلیک کنید.

STM32F103

صفحه ی target selection ابتدا در بخش part number اسم میکروکنترلر رو مینویسیم ( STM32F103 ) در قدم دوم میکروکنترلر رو انتخاب کنید و سپس روی next کلیک کنید.

STM32F103

در پنجره STM32 Project ابتدا در بخش project name اسم پروژه رو تایپ کنید ، targeted Project type رو empty انتخاب کنید و روی finish کلیک کنید.

STM32F103

با موفقیت پروژه ای ساختیم که حداقل نیازمندی لود شدن در میکروکنترلر رو داره. از پوشه Src فایل main.c رو باز کنید و قسمت های اضافی رو پاک کنید. در تابع main قبل از حلقه ی بینهایت باید تنظیمات اولیه پریفرال ها رو اعمال کنیم.

stm

بخش دوم : برنامه نویس رجیستری STM32

در بخش اول بررسی کردیم که برای پروژه led چشمک زن چه تغییراتی رو باید در رجیسترها اعمال کنیم ، میدونیم رجیسترهامون 32 بیتی هستند و آدرسشون رو هم داریم. در ادامه باید در زبان سی به محتوای آدرس ها دسترسی پیدا کنیم و مقدار رجیسترها رو تغییر بدیم. برای دسترسی به محتوایی که در آدرس ذخیره شده به پوینتر نیاز داریم.

پوینتر ها literal ( ثابت های عددی ) یا variable ( متغیر ) هایی هستند که مقدارشون آدرس جایی از حافظه است و هر پوینتر نوع و مقدار داره. چون آدرس رجیسترها قرار نیست تغییر کنه ، پوینتر ثابت میسازیم. برای ساخت پوینتر باید نوع و مقدارش رو بدونیم. 

روش اول : دسترسی به رجیسترها بصورت 32 بیتی با  ساخت پوینتر برای هر رجیستر برای میکروکنترلر های STM32

ساخت پوینتر برای هر رجیستر

فرض کنید میخواهیم پوینتری بسازیم برای دسترسی به رجیستر 32 بیتی RCC_APB2ENR. مقدار این پوینتر آدرس رجیستر RCC_APB2ENR خواهد بود یعنی 0x40021018 . برای ساخت پوینتر ثابت ابتدا مقدارش رو مینویسیم ، سپس در یک پرانتر قبل از مقدار باید نوعش رو بنویسیم ، به این کار میگن کست کردن . نوع پوینتر دو بخش داره، ابتدا نوع چیزی رو مینویسید که در آدرسی که مقدار پوینتر هست ذخیره شده. مثلا در در آدرس 0x40021018 یک رجیستر 32 بیتی وجود داره که نوعش میشه uint32_t  ( یا unsigned int ) بخش دوم هم علامت استریسک یا dereference operator هست.

stm

پوینتر رو ساختیم ، حالا برای اینکه با استفاده از این پوینتر به رجیستر RCC_APB2ENR دسترسی پیدا کنیم برای اینکه مقدارش رو بخونیم یا تغییر بدیم لازمه قبل از پوینتر علامت استریسک یا dereference operator بذاریم، در مثال اول عدد 10 در رجیستر ذخیره میشه و در مثال دوم مقدار رجیستر خونده میشه ، با 10 جمع میشه و در رجیستر ذخیره میشه. 

stm

در مورد رجیستر RCC_APB2ENR باید بیت چهارمش رو یک کنیم تا کلاک پریفرال GPIOC فعال بشه ، برای این منظور به ماسک بیت شماره چهار نیاز داریم که یک عدد 32 بیتی هست که فقط بیت چهارمش یکه. جهت ساخت این عدد از عملگر بیتی left shift استفاده میکنیم ، 1 رو left shift چهار میکنیم.

مقاله ی ” کاربرد عملگرهای بیتی در زبان سی ” رو مطالعه کنید.

 

stm

وقتی میخواهیم بیتی رو در یک رجیستر یک کنیم باید رجیستر رو bitwise or assignment ماسک بیت کنیم و وقتی میخواهیم بیتی رو صفر کنیم رجیستر رو bitwise and assignment میکنیم با نات ماسک بیت . برای اینکه این عملیات ها رو بهتر درک کنید مقاله کاربرد عملگر های بیتی رو مطالعه کنید.

stm

تا اینجا یادگرفتیم چطور باید پوینتر برای دسترسی به رجیستر رو بسازیم و چطور میتونیم بیت های دلخواهمون رو در یک رجیستر تغییر بدیم. تغییراتی که باید در رجیسترها اعمال بشه رو در قالب یک جدول در کامنت اول فایل main.c نوشتم.

stm

دسترسی به رجیسترها با ساخت پوینتر اختصاصی برای هر رجیستر برای انجام پروژه ی led چشمک زن

در قدم اول برای فعالسازی کلاک پریفرال GPIOC باید بیت IOPCEN ( بیت 4 ) در رجیستر RCC_APB2ENR رو یک کنیم. قبلا یادگرفتیم که چطور با کست کردن آدرس رجیستر پوینتر رو بسازیم. برای دسترسی به محتوای رجیستر پشت پوینتر علامت استریسک میذاریم. برای یک کردن بیت چهار رجیستر رو با ماسک بیت چهار bitwise or assignment میکنیم.

stm

در قدم بعدی برای اینکه پین PC13 در حالت خروجی با سرعت 2MHz تنظیم بشه باید بیت های MODE13 در رجیستر GPIOC_CRH رو 10 کنیم ، یعنی بیت 20 صفر و بیت 21 باید یک بشه. مشابه رجیستر RCC_APB2ENR برای دسترسی به محتوای رجیستر GPIOC_CRH هم پوینتر میسازیم ، آدرس رجیستر GPIOC_CRH رو مینویسیم و قبل مقدار پوینتر در یک پرانتز نوعش رو مشخص میکنیم. نوع این پوینتر هم مشابه قبلی * uint32_t  هست. برای دسترسی به محتوای رجیستر GPIOC_CRH پشت پوینتر علامت استریسک میذاریم. جهت یک کردن بیت 21 رجیستر رو bitwise or assignment میکنیم با ماسک بیت 20 که میشه 20<<1 و برای صفر کردن بیت 20 رجیستر رو bitwise and assignment میکنیم با نات ماسک بیت 21 که میشه (21<<1)~ . 

stm

برای تنظیم پین PC13 در حالت خروجی Open drain باید بیت های CNF13 در رجیستر GPIOC_CRH رو 01 کنیم ، یعنی بیت 22 یک و بیت 23 باید صفر بشه. مشابه قبل تغییرات رو اعمال میکنیم. 

stm

تا الان اقدامات مورد نیاز برای تنظیم پین PC13 در حالت خروجی دیجیتال انجام شده. در قدم بعدی در حلقه ی بینهایت باید خروجی پین PC13 رو با یک تاخیر زمانی صفر و یک کنیم تا led چشمک زن بشه. برای این منظور یک تابع تاخیر با دو for تعریف میکنم تا بعد از صفر کردن و بعد از یک کردن پین این تابع رو فراخوانی کنیم.

stm

برای اینکه led سبز رنگ روی برد Blue pill چشمک زن بشه باید پین PC13 رو در حلقه ی بینهایت متناوبا صفر و یک کنیم ، جهت یک کردن خروجی PC13 باید بیت 13 رجیستر GPIOC_ORD یک بشه و برای صفر کردن پین PC13 باید بیت 13 رجیستر GPIOC_ODR رو صفر کنیم. مشابه رجیستر های قبلی برای GPIOC_ODR هم پوینتر میسازیم و تغییرات رو در بیت 13 اعمال میکنیم. برای اینکه سرعت خاموش و روشن شدن led رو کم کنیم تا با چشمک زدن led رو با چشم ببینیم بعد از صفر و یک کردن باید تابع تاخیر رو فراخوانی کنیم.   

stm

پروژه led چشمک زن با روش اول برنامه نویسی رجیستری برای میکروکنترلر های  STM32 به پایان رسید. در روش اول برنامه نویسی رجیستری برای هر رجیستر به صورت جداگانه پوینتر ساختیم و با این پوینتر ها به رجیسترها دسترسی پیدا کردیم و با عملگرهای بیتی مقدار بیت ها رو تغییر دادیم.  

stm

روش دوم : دسترسی به رجیسترها بصورت 32 بیتی در  قالب اعضای استراکچر برای میکروکنترلرهای STM32

در نرم افزار STM32CubeIDE یک پروژه ی جدید به نام structure ایجاد و تابع delay رو هم اضافه کنید.  

stm

آموزش STM32 ، ساخت استراکچر قالب رجیسترهای پریفرال GPIO

روش قبلی دسترسی به رجیسترها برای هر رجیستر یک پوینتر درست کردیم، در روش دوم برای دسترسی به همه ی رجیسترهای یک پریفرال فقط به یک پوینتر نیاز داریم و برای هر پریفرال یک پوینتر طراحی میکنیم. پریفرال های GPIO رو در نظر بگیرید، این پریفرال 7 تا رجیستر 32 بیتی داره که پشت سر هم در حافظه قرار دارند، مشابه استراکچری که هفت ها عضو 32 بیتی داره. 

stm

پریفرال GPIOC رو در نظر بگیرید ،آدرس اولین رجیستر این پریفرال 0x40011000 و این پریفرال 7 تا رجیستر 32 بیتی داره که پشت سر هم در حافظه قرار دارند، مشابه استراکچری که هفت تا عضو 32 بیتی داره و در آدرس 0x40011000 ذخیره شده. با توجه به رجیستر مپ پریفرال های GPIO یک نوع متغیر استراکچر به نام GPIO_TypeDef قالب رجیسترهای پریفرال های GPIO طراحی میکنیم که هفت تا عضو 32 بیتی از نوع uint32_t داره و اعضای این استراکچر رو هم مثل رجیسترهای پریفرال های GPIO نامگذاری میکنیم. 

stm

در نظر بگیرید که یک استراکچر فرضی از نوع GPIO_TypeDef در آدرس 0x40011000 ذخیره شده. اگر به اعضای این استراکچر دسترسی پیدا کنیم مثل اینه که به رجیستر های پریفرال GPIOC دسترسی پیدا کردیم. اگر بخواهیم به رجیستر های پریفرال GPIOC در قالب اعضای این استراکچر فرضی دسترسی پیدا کنیم به پوینتر نیاز داریم .

آمورش STM32 ، ساخت پوینتر به استراکچر برای دسترسی به رجیسترهای پریفرال GPIOC

برای ساخت این پوینتر باید نوع و مقدارش رو بدونیم. مقدار این پوینتر آدرس استراکتراکچر فرضی خواهد بود که آدرس اولین رجیستر پریفرال GPIOC یعنی 0x40011000 هست. نوع پوینتر هم دو قسمت داره ، قسمت اول نوع متغیری که در نظر میگیریم در آدرسی کم مقدار پوینتر هست ذخیره شده و قسمت دوم هم علامت استریسک هست. الان ما میخواهیم فرض کنیم در آدرس 0x40011000 یک استراکچر از نوع GPIO_TypeDef هست ، پس نوع پوینتر میشه * GPIO_TypeDef . 

stm

میدونیم برای دسترسی به اعضای استراکچر باید بعد از اسم استراکچر عملگر دات ( . ) بذاریم ولی چطور با استفاده از پوینتر به استراکچر، به اعضا دسترسی پیدا کنیم. 

برای دسترسی به محتوای آدرس پوینتر باید قبل از پوینتر عملگر استریسک رو قرار بدیم ، نکته ای که وجود داره اینه که برای استراکچر حتما استریسک پوینتر باید داخل پرانتز باشه ، بعد از پرانتر دات ( . ) میذاریم و اینجوری میتونیم با پوینتر به استراکچر به اعضاش دسترسی پیدا کنیم.

البته راه بهتری هم وجود داره و اون استفاده از عملگر پیکان یا arrow operator هست. اگر پوینتر به استراکچر رو داشته باشیم ، برای دسترسی به اعضای استراکچر کافیه بعد از پوینتر عملگر پیکان <- بذاریم.  

stm

با استفاده از یک definition میتونیم کدمون رو خواناتر کنیم. در کد عبارت GPIOC که اسم پریفرال هست رو ((GPIO_TypeDef *) 0x40011000)  که پوینتر به رجیسترهای پریفرال هست define میکنم. یعنی هر جا در کد GPIOC رو بنویسی با پوینتر جایگزین میشه. 

stm
stm

آموزش STM32 ، دسترسی به رجیسترهای پریفرال GPIOC درقالب اعضای استراکچر

در روش دوم برنامه نویسی رجیسترسی برای میکروکنترلر های STM32 ، قالب رجیسترهای پریفرال GPIO یک نوع متغیر استراکچر ساختیم چون به این نوع متغیر برای ساخت پوینتر به استراکچر فرضی نیاز داریم. با استفاده از پوینتر GPIOC می تونیم به اعضای استراکچر فرضی که در آدرس 0x40011000 ( آدرس اولین رجیستر پریفرال GPIOC ) ذخیره شده دسترسی پیدا کنیم و رجیستر های پریفرال GPIOC رو تغییر بدیم. 

در پروژه ی led چشمک زن لازمه رجیستر های CRH و ODR از پریفرال GPIOC رو تغییر بدیم .برای دسترسی به رجیسترهای پریفرال GPIOC که اعضای استراکچر فرضی از نوع GPIO_TypeDef  هستند کافیه بعد از پوینتر به استراکچر عملگر پیکان بذاریم ، اینطوری برای هفت ها رجیستر پریفرال GPIOC فقط به یک پوینتر نیاز داریم. 

stm

روش دوم برنامه نویسی با رجیستری برای STM32 به پایان رسید ، این روش رو برای رجیستر RCC_APB2ENR از پریفرال RCC اعمال نکردم ، اگر برای این رجیستر هم بخواهیم از روش دوم استفاده کنیم باید قالب رجیسترهای پریفرال RCC یک نوع متغیر استراکچر بسازیم.

لایه ی نرم افزاری CMSIS همین روش رو برای دسترسی به رجیسترهای پریفرال های ارائه میده و توابع HAL و سایر کتابخونه های مشابه هم از همین روش برای دسترسی به رجیسترهای پریفرال ها استفاده میکنند.

stm

روش سوم : دسترسی به بیت رجیسترها با بیت فیلد و یونیون برای میکروکنترلرهای STM32

تا حالا دو روش برنامه نویسی رجیستری برای STM32 ها رو بررسی کردیم، در روش اول برای هر رجیستر یک پوینتر ساختیم و در روش دوم به رجیسترهای در قالب اعضای استراکچر دسترسی پیدا کردیم. چیزی در این دو روش یکسان بود اینه که به رجیسترها بصورت 32 بیتی دسترسی پیدا میکنیم و باید از عملگرهای بیتی برای تغییر بیت رجیسترها استفاده کنیم. در روش سوم دیگه به عملگرهای بیتی نیازی نیست ، مستقیم به بیت ها دسترسی پیدا میکنیم و اعداد مورد نظر رو در اونها مینویسیم. قبل از اینکه به روش سوم بپردازیم باید راجع به بیت فیلد صحبت کنیم.

بیت فیلد

بیت فیلد ها اعضای استراکچر هستند که تعداد بیت هاشون رو خودمون مشخص میکنیم، برای تعریف عضو بیت فیلد در استراکچر ابتدا نوعش رو مینویسیم ، نوع بیت فیلد فقط میتونه اینتیجر باشه و علامت ( signed or un-signed ) و alignment رو برای بیت فیلد مشخص میکنه . در مورد نوع بیت فیلد خیلی نکته وجود داره ولی برای کاری که الان انجام میدیم نوع بیت فیلد همیشه uint32_t هست. بعد از نوع بیت فیلد با یک فاصله اسم بیت فیلد رو مینویسیم ، بعدش دو نقطه میذاریم و تعداد بیت های بیت فیلد رو مشخض میکنیم.

در مثال زیر عضو x و y به ترتیب 5 و 13 بیت دارند. در مثال زیر ابتدا نوع متغیر استراکچر bit_type تعریف شده که شامل دو عضو بیت فیلد هست سپس استراکچر mybit با نوع bit_type تعریف شده و اعضاش هم مقدار دهی اولیه شده اند ، عضو بیت مقدارش 3 شده و عضو y مقدارش 8 شده. در تابع main هم نشون دادم دسترسی به اعضایی که بیت فیلد هستند مشابه دسترسی به اعضای عادی استراکچر هست.

stm

اگر استراکچر mybit دو عضو معمولی از نوع uint32_t داشت 8 بایت در حافظه رو اشغال میکرد ولی الان فقط چهار بایت یا 32 بیت رو اشغال میکنه که 14 بیتش هم استفاده نمیشه. در استراکچر mybit عضو x اولین عضو  هست و 5 بیت داره ، 5 بیت کم ارزش به x اختصاص داده میشه یعنی بیت های 0 تا 4 و با توجه به اینکه عضو x پنج بیت داره فقط اعداد 0 تا 31 رو میتونیم در این عضو بریزیم. بعد از عضو x عضو y هست با 8 بیت و بیتهای 5 تا 17 به عضو y اختصاص داده میشه ، کم ارزش ترین بیت عضو y بیت 5 هست و میبینید که عدد 8 چطور در y ذخیره شده. بیت های 18 تا 31 هم خالی میمونند.

stm

آموزش STM32 طراحی استراکچر بیت فیلد دار قالب بیت های رجیستر ODR

رجیستر ODR که برای تعیین وضعیت خروجی پین های ازش استفاده میشه رو در نظر بگیرید. قراره یک نوع استراکچر بیت فیلد دار قالب رجیستر ODR طراحی کنیم.

stm

از کم ارزش ترین بیت رجیستر ODR شروع میکنیم و اعضای بیت فیلد رو مینویسیم ، اولین بیت ODR به نام ODR0 یک بیت داره ، اولین عضو استراکچر هم یک بیت فیلد هست به نام ODR0 که یک بیت داره. اعضای ODR1 تا ODR15 هم همشون یک بیت دارند ، از بیت 16 تا بیت 31 بیت های reserved هستند که استفاده نمیشن ، برای بیت های reserved هم یک عضو بیت فیلد مینویسیم با 16 بیت ولی اسمی براش نمینویسیم ، به اعضای بدون اسم میگن padding که برای پر کردن جاهای خالی استفاده میشن.

الان یک نوع متغیر استراکچر به نام ODR_T تعریف کردم که اندازش 32 بیت هست ، مشابه رجیستر ODR و اعضای بیت فیلد این نوع استراکچر هم مطابق بیت های رجیستر ODR طراحی شدن.

stm

آموزش STM32 ، دسترسی به بیت های رجیستر بدون نیاز به ماسک بیت و عملگرهای بیتی

یک پروژه جدید بسازید و تمام محتویات فایل main.c پروژه قبلی رو درش کپی کنید. تعریف نوع متغیر ODR_T رو هم قبل از تعریف نوع متغیر GPIO_TypeDef اضافه کنید. قراره روش سوم برنامه نویسی رجیستر ها رو فقط برای رجیستر ODR اعمال کنیم.

stm

در نوع GPIO_TypeDef عضو ODR از نوع uint32_t هست ، نوع عضو ODR رو از uint32_t به ODR_T تغییر میدیم. دقت کنید که ODR_T و uint32_t  هر دو 32 بیتی هستند و اندازشون 4 بایته و اعضای استراکچر ODR_T رو هم مطابق بیت های رجیستر ODR طراحی کردیم.

stm

قبلا عضو ODR از نوع uint32_t بود، الان خود ODR یک استراکچر از نوع ODR_T هست ، بعد از ODR عملگر دات میذاریم تا به اعضاش دسترسی پیدا کنیم ، اعضای ODR بیت های رجیستر ODR هستند. به عضو ODR13 دسترسی پیدا میکنیم و برای یک کردن این بیت کافیه عدد یک رو در اون بنویسیم و برای صفر کردن بیت ODR13 کافیه عدد صفر رو در اون بنویسیم و دیگه به عملگرهای بیتی و ماسک بیت نیازی نیست.

stm

آموزش STM32 دسترسی به بیت های رجیستر و دسترسی 32 بیتی همزمان با یونیون

با تغییراتی که ایجاد کردیم عضو ODR یک استراکچر شده و دیگه نمیتونیم مثل قبل به رجیستر ODR بصورت 32 بیتی دسترسی پیدا کنیم. هدف اینه که بتونیم به ODR هم بصورت استراکچر و هم بصورت 32 بیتی دسترسی پیدا کنیم برای این منظور باید یک نوع یونیون طراحی کنیم.

یونیون مشابه استراکچر یک نوع متغیر هست که اعضاش انواع دیگه ی متغیر هستند ، فرق یونیون با استراکچر اینه که تمام اعضای یونیون یک آدرس دارند پس وقتی میخواهیم به یک آدرس به دو شکل دسترسی پیدا کنیم از یونیون استفاده میکنیم. یک نوع یونیون به نام ODR_UNION_T تعریف کردم که دو عضو داره. عضو reg از نوع uint32_t و عضو bit از نوع ODR_T.

stm

حالا نوع عضو ODR در نوع استراکچر GPIO_TypeDef رو به ODR_UNION_T تغییر میدیم.

stm

عضو ODR یک یونیون هست، برای دسترسی به اعضای یونیون بعد از اسمش دات میذاریم. این یونیون دو عضو به نام های bit و reg داره. اگر بخواهیم به رجیستر ODR بصورت 32 بیتی دسترسی پیدا کنیم از عضو reg که نوعش uint32_t هست ، استفاده میکنیم. اگر بخواهیم به بیت های رجیستر ODR دسترسی پیدا کنیم از عضو بیت استفاده میکنیم که نوعش ODR_T هست که یک نوع استراکچر با اندازه ی 4 بایته که با توجه به بیت های رجیستر ODR طراحی کردیم. عضو بیت خودش یک استراکچره و برای دسترسی به اعضای این استراکچر که بیت های رجیستر ODR هستند بعدش دات میذاریم و میتونیم به بیتها دسترسی پیدا کنیم.

stm

0 Comments

Submit a Comment

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *