در قسمتهای قبل ابتدا با نحوهی راهاندازی واحد USB در میکروکنترلرهای STM32 آشنا شده و از طریق آن داده ارسال کردیم. سپس نحوهی دریافت داده در میکروکنترلر از طریق USB را یاد گرفته و بعد از آن دریافت داده و پردازش آن با بافر FIFO را پیادهسازی کردیم. در قسمت قبل (لینک قسمت چهارم) با نحوهی برقراری ارتباط بین میکروکنترلر و پایتون آشنا شدیم. در پایتون با استفاده از کتابخانه serial پورت سریال باز کرده و از طریق آن داده ارسال و دریافت کردیم.
در قسمتهای قبلی، دادههایی که ارسال و دریافت میکردیم یک بایتی بودند. در این قسمت میخواهیم ارسال و دریافت دادههای چند بایتی مانند نوع دادههای int32_t، int16_t، float و… را در میکروکنترلر یاد بگیریم. در انتهای این آموزش قادر خواهید بود دادههای چند بایتی از میکروکنترلر ارسال و دریافت کنید.
نوع Endian در سیستمهای کامپیوتری ترتیب ذخیرهسازی یا ارسال بایتهای مقدار چند بایتی را مشخص میکند. در فرمت Little-endian از مقدار چند بایتی، ابتدا کمارزشترین بایت ذخیره یا ارسال میشود. در فرمت Big-endian ابتدا پرارزشترین بایت ذخیره یا ارسال میشود.
ما هم از این موضوع برای ارسال و دریافت دادههای چند بایتی در میکروکنترلر استفاده میکنیم. بسته به نحوهی ذخیرهشدن مقادیر چند بایتی در حافظه، به بایتهای آن دسترسی پیدا کرده و بایت به بایت آن را ارسال میکنیم.
دسترسی به بایتهای مقادیر چند بایتی در Cیک فایل C در کامپیوتر ایجاد میکنیم. میخواهیم در این فایل نحوهی ذخیرهشدن و دسترسی به بایتهای مقادیر چند بایتی در حافظه را بررسی کنیم. یک متغیر 16 بیتی بدون علامتدار (a) تعریف کرده و در آن یک مقدار 16 بیتی قرار میدهیم. آدرس این متغیر (&a) که اشارهگر به یک مقدار 16 بیتی هست را به یک اشارهگر 8 بیتی (uint8_t) تبدیل میکنیم و مقدار اندیس 0 و 1 از این آدرس را چاپ میکنیم (بهصورت هگز “%X\n”).
با اجرای برنامه در خروجی مشاهده میکنیم که ابتدا مقدار CD هگز و سپس AB هگز چاپ میشود. بهعبارتدیگر ابتدا بایت کمارزش متغیر و سپس بایت پرارزش آن چاپ شده است. این موضوع نشان میدهد کامپیوتری که در آن برنامه را اجرا کردیم بهصورت little-endian کار میکند.
با این کار ما به محتوای 16 بیتی (دو بایتی) به صورت یک آرایهی 8 بیتی به طول 2 دسترسی پیدا میکنیم.

خروجی:

اسم متغیر آرایه در واقع یک اشارهگر به آدرس ابتدای حافظهای است که مقادیر آرایه در آن قرار گرفتهاند.
برنامه قبل را میتوانیم بهصورت زیر هم بنویسیم. آدرس a را به یک اشارهگر 8 بیتی تبدیل کرده و در یک متغییر اشارهگر به آدرس 8 بیتی ptr قرار میدهیم. اندیس های 0 و 1 از این آدرس را چاپ میکنیم. خروجی مشابه قبل بدست میآید.

یک متغیر 32 بیتی تعریف کرده و در آن یک مقدار 32 بیتی قرار میدهیم. مشابه قبل آدرس این متغییر را به آدرس یک بایتی (uint8_t) تبدیل کرده و 4 اندیس (32 بیت معادل 4 مقدار 8 بیتی هست) از این آدرس را چاپ میکنیم. با اجرای این برنامه در خروجی مشاهده میکنیم که به ترتیب از بایت کم ارزش متغییر 32 بیتی در خروجی چاپ شده است.
با این کار ما به محتوای 32 بیتی (چهار بایتی) به صورت یک آرایهی 8 بیتی به طول 4 دسترسی پیدا میکنیم.

خروجی:

در مثال جدید یک آرایهی 32 بیتی به طول 3 تعریف کرده و در آن سه مقدار قرار میدهیم. متغیر آرایهی c (اشارهگر به ابتدای آرایه 32 بیتی) را به اشارهگر از نوع uint8_t بیتی تبدیل کرده و از این آدرس 12 مقدار را چاپ میکنیم. آرایهی c شامل 3 مقدار 32 بیتی (4 بایت) است؛ بنابراین پس از تبدیل اشارهگر به uint8_t، با این اشارهگر میتوان بهصورت یک آرایهی 8 بیتی به طول 12 رفتار کرد.

خروجی:

با بررسی خروجی میتوان مشاهده کرد که به ترتیب از بایت کمارزش مقدار اندیس اول از آرایهی c سپس از بایت کمارزش مقدار اندیس دوم آرایه و… چاپ شده است.
این برنامه را بهصورت زیر نیز میتوان پیادهسازی کرد. همانطور که قبلاً هم اشاره کردیم اسم متغیر آرایه، یک اشارهگر به ابتدای آرایه است. آرایه از نوع uint32_t است بنابراین c را میتوان در یک اشارهگر 32 بیتی ptr32 ذخیره کرد. این اشارهگر را به یک اشارهگر uint8_t تبدیل کرده و در ptr ذخیره میکنیم. با ptr مثل یک آرایهی uint8_t به طول 12 رفتار کرده و مقادیر را چاپ میکنیم.

خروجی:

در این بخش نحوهی دسترسی به بایتهای مقدار چند بایتی را بررسی کردیم. حال میخواهیم چند بایت را به یک مقدار چند بایتی تبدیل کنیم. در آرایهی f چهار مقدار یک بایتی قرار میدهیم. این آرایه را به یک اشارهگر از نوع uint16_t تبدیل میکنیم و در g ذخیره میکنیم. با این کار به مقادیر آرایهی f بهصورت یک آرایه از نوع uint16_t به طول 2 دسترسی پیدا میکنیم. اندیس صفر و یک از g را چاپ میکنیم. میتوان مشاهده کرد اندیس صفر f بهعنوان بایت کمارزش و اندیس یک f بهعنوان بایت پر ارزش g[0] در نظر گرفته شده است.
محتوایی که در آرایهی f هست را این بار میخواهیم بهصورت مقدار 32 بیتی دسترسی داشته باشیم. آرایهی f را به اشارهگر از نوع uint32_t تبدیل میکنیم (h) و سپس محتوای این آدرس (*h) را چاپ میکنیم.
در روش دیگر پس از تبدیلکردن اشارهگر، محتوای آن را در یک متغیر 32 بیتی k ذخیره میکنیم. در خروجی میتوان مشاهده کرد مقادیر f از بایت کم ارزش در متغییر 32 بیتی دیده میشوند.

خروجی:

مثال اول:
میخواهیم میکروکنترلر با دریافت مقدار هگز BB یک مقدار 32 بیتی بدون علامتدار (4 بایت) دریافت کرده و سپس به آن یک واحد اضافه کند و بعد از آن نتیجه را ارسال کند (مقدار 32 بیتی).
میکروکنترلر stm32f103 که از آن استفاده میکنیم بهصورت little-endian میباشد؛ برای همین دادههای چند بایتی را از بایت کمارزش دریافت و ارسال میکنیم. با این کار پیادهسازی ارسال و دریافت مقادیر چند بایتی را بهراحتی میتوانیم انجام دهیم.
در فایل main.c درصورتیکه مقدار BB دریافت شود، 4 بایت دیگر هم میخوانیم. یک متغییر 32 بیتی تعریف میکنیم. آدرس این متغییر را به یک اشارهگر 8 بیتی تبدیل کرده و 4 بایت دریافتی را در این آدرس از حافظه مینویسیم.
به مقدار 32 بیتی که دریافت کردیم یک واحد اضافه کرده و نتیجه را ارسال میکنیم. برای ارسال نتیجه، آدرس متغییر را به اشارهگر 8 بیتی تبدیل کرده و از این آدرس، 4 بایت ارسال میکنیم. با تبدیل اشارهگر به متغییر 32 بیتی به یک اشارهگر از نوع uint8_t، به مقدار 32 بیتی به صورت یک آرایهی 4 تایی از مقادیر 8 بیتی (uint8_t) دسترسی پیدا میکنیم. به این روش بایت های مقدار 32 بیتی را بایت به بایت ارسال میکنیم.

برنامه را کامپایل کرده و میکروکنترلر را پروگرام میکنیم. میکروکنترلر را با کابل USB به کامپیوتر وصل کرده و در نرمافزار QCom پورت سریال را باز میکنیم.
مقدار 32 بیتی هگز 0xAB12CD34 را ارسال کنیم. پس از ارسال کردن BB، از بایت کم ارزش مقدار مورد نظر را ارسال میکنیم. با بررسی مقدار دریافتی (مقدار ارسال شده توسط میکروکنترلر) مشاهده میکنیم که یک واحد به مقدار ارسالی اضافه شده است.
خروجی:

بهاینترتیب توانستیم در میکروکنترلر یک مقدار 32 بیتی دریافت و ارسال کنیم.
مثال دوم:
میخواهیم میکروکنترلر با دریافت مقدار 0x07، سه مقدار 32 بیتی را ارسال کند. آرایهی c یک آرایهی 32 بیتی با سه مقدار میباشد. برای ارسال این مقادیر اشارهگر به ابتدای آرایه (همان اسم متغییر آرایه) را به اشارهگر از نوع uint8_t تبدیل میکنیم و از این آدرس از حافظه 12 بایت ارسال میکنیم (3 مقدار 4 بایتی).

برنامه را کامپایل کرده و میکروکنترلر را پروگرام میکنیم. در QCom مقدار 07 را ارسال میکنیم. میتوان مشاهده کرد که میکروکنترلر با دریافت این مقدار، 3 داده ی 32 بیتی را ارسال کرده است.
خروجی:

در قسمت بعدی آموزش میخواهیم با استفاده از پایتون، دادههای چند بایتی را ارسال و دریافت کنیم.
فایلهای این آموزش را میتوانید از لینک گیتهاب زیر دانلود نمایید:
https://github.com/sphrk/stm32_USB_CDC_Example
منابع:
https://en.wikipedia.org/wiki/Endianness
سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.