در قسمت قبل با نحوهی ارسال و دریافت دادههای چند بایتی (مانند uint32_t، uint16_t، float و…) از طریق USB در میکروکنترلر آشنا شدیم. در این قسمت از آموزش میخواهیم با استفاده از پایتون از طریق پورت سریال، مقادیر چند بایتی ارسال و دریافت کنیم.
با استفاده از کتابخانه serial در پایتون میتوانیم از پورت سریال بایت به بایت داده ارسال و دریافت کنیم. میخواهیم در پایتون، بایتهای دریافت شده را در کنار هم قرار داده و آن را به یک مقدار چند بایتی مانند uint32_t ،float یا … تبدیل کنیم. همچنین برای ارسال داده چند بایتی در پایتون باید ابتدا بایتهای مقدار را به دست آورده و به ترتیب آنها را ارسال کنیم.
در پایتون با استفاده از کتابخانهی struct میتوان مقادیر موجود در پایتون را به نوع دادههایی که در C وجود دارد تبدیل کنیم و برعکس. از این کتابخانه استفاده میکنیم تا به بایتهای مقدار چند بایتی در پایتون دسترسی داشته باشیم تا بعداً بتوانیم آنها را بایت به بایت ارسال کنیم. همچنین با استفاده از این کتابخانه میتوان چند بایت را به یک مقدار چند بایتی با فرمت دلخواه تبدیل کرد.
برای بهدستآوردن بایتهای یک مقدار از تابع pack استفاده میکنیم. این تابع ابتدا در یک رشته، فرمت تبدیل بایتهای مقدار را دریافت میکند. در رشتهی فرمت میتوان نوع endian (ترتیب قرارگیری بایتها) را مشخص کرد. در صورت که بخواهیم در pack کردن بایتهای مقدار موردنظر، ترتیب قرارگیری بایتها بهصورت little-endian باشد در ابتدای رشته باید از < استفاده میکنیم و اگر بخواهیم بهصورت big-endian بستهبندی بایتها را انجام دهد از > استفاده میکنیم. بهصورت پیشفرض این تابع ترتیب بایتها را بهصورت little-endian قرار میدهد.
پس از مشخصکردن ترتیب قرارگیری بایتها (اختیاری)، تعداد داده (پیشفرض 1) و پس از آن نوع داده را باید مشخص کنیم. نوع داده با یک کاراکتر مشخص میشود. کاراکتر هر نوع داده را میتوانید در جدول موجود در داکیومنت کتابخانه مشاهده کنید. برای مثال برای اعداد صحیح علامتدار یک بایتی کاراکتر b و برای حالت بدون علامتدار از B باید استفاده شود.

در مثال زیر مقدار 0x1496 را به تابع ارسال کرده و بایتهای آن را در فرمت صحیح علامتدار دو بایتی (int16_t) به دست میآوریم. میتوان مشاهده کرد خروجی تابع از نوع bytes میباشد.

میخواهیم بایتهای سه مقدار را در فرمت صحیح بدون علامتدار دو بایتی (uint16_t) بهدست آوریم. در رشتهای که فرمت را مشخص میکنیم، تعداد داده را 3 مینویسیم و پس از رشتهی فرمت، سه مقدار را به تابع ارسال میکنیم. میتوان مشاهده کرد در خروجی توالی بایتهای سه مقدار موردنظر را برگردانده است.

در مثال زیر بایتهای یک مقدار را در فرمت عدد صحیح بدون علامتدار 32 بیتی بدست میآوریم. همانطور که قبلا هم اشاره کردیم، تابع pack در خروجی یک object از نوع bytes برمیگرداند. موقع چاپ کردن bytes، اگر بایتی قابل چاپ شدن باشد معادل آن نمایش داده میشود (موقع پرینت کردن هگز آن را نشان نمیدهد). برای اینکه معادل هگز خروجی را مشاهده کنیم از متد hex کلاس bytes استفاده میکنیم.

در مثال زیر بایتهای یک مقدار اعشاری را در فرمت float32_t بهدست میآوریم.

پس از بهدستآوردن بایتهای مقادیر چند بایتی میتوانیم آن بایتها را یکبهیک از طریق پورت سریال ارسال کنیم.
با استفاده از کتابخانه struct میتوانیم چند بایت را به نوع دادههای مطلوب در پایتون تبدیل کنیم. برای مثال فرض کنید میکروکنترلر، دو مقدار 16 بیتی بدون علامتدار 0xABCD و 0x1234 را با ترتیب بایت little-endian ارسال کرده است و در پایتون هم ما 4 بایت ارسال شده را دریافت کردهایم. میخواهیم از روی این توالی بایت دریافت شده، دو مقدار 16 بیتی ارسال شده را بهدست آوریم. برای اینکار از تابع unpack استفاده میکنیم. ابتدا در یک رشته، فرمت خروجی را مشخص کرده (“2H” یا “HH” یعنی دو مقدار 16 بیتی بدون علامتدار) و در آرگومان دوم، توالی بایت ها را ارسال میکنیم. این تابع با توجه به رشتهی فرمت، بایتها را در کنار هم قرار داده و در خروجی مقادیر موردنظر را در یک tuple برمیگرداند.

اگر در رشتهی فرمت I را قرار دهیم، 4 بایت دریافت شده را به یک مقدار 32 بیتی بدون علامتدار تبدیل میکند.

پس از دریافت بایتهای ارسال شده توسط میکروکنترلر از طریق پورت سریال در پایتون، میتوانیم با استفاده از unpack مقادیر چند بایتی که ارسال شده است را بهدست آوریم.
مثال اول:
برنامهای که در قسمت قبلی آموزش برای میکروکنترلر نوشتیم، میکروکنترلر با دریافت مقدار هگز BB یک مقدار 32 بیتی بدون علامتدار دریافت کرده و سپس به آن یک واحد اضافه میکند و سپس نتیجه را ارسال میکند (مقدار 32 بیتی). در پایتون ابتدا از طریق پورت سریال مقدار BB را ارسال کرده و پس از آن بایتهای مقدار 32 بیتی موردنظر را ارسال میکنیم. برای بهدست آوردن بایتهای مقدار 32 بیتی، از تابع pack استفاده میکنیم. سپس در پایتون، نتیجهی ارسال شده توسط میکروکنترلر را از پورت سریال دریافت میکنیم (4 بایت از پورت سریال میخوانیم). بایتهای دریافت شده را با استفاده از unpack به یک مقدار 32 بیتی تبدیل میکنیم.
با بررسی خروجی میتوان مشاهده کرد میکروکنترلر به مقدار ارسال شده، یک واحد اضافه کرده و نتیجه را از طریق USB ارسال کرده است.

خروجی:

مثال دوم:
میخواهیم به دستور BB در میکروکنترلر، 3 مقدار 7، 123 و 255 را ارسال کنیم. برای اینکار میتوانیم مشابه قبل هر مقدار را ارسال کرده و نتیجه را دریافت کنیم. برای انجام اینکار همچنین میتوانیم ابتدا توالی بایتهایی که باید ارسال کنیم را بهدست آورده و سپس آنها را ارسال کنیم. برای هر مقدار بایستی ابتدا BB و سپس 4 بایت مقدار را ارسال کنیم. از pack استفاده کرده و توالی بایتها را بهدست میآوریم. نوع endian را هم مشخص میکنیم.

توالی بایتها را از پورت سریال ارسال کرده و نتیجه 12 بایتی (3 مقدار 4 بایتی) را در پایتون از پورت سریال دریافت میکنیم. توالی بایتهای دریافت شده را با استفاده از unpack به 3 مقدار 4 بایتی بدون علامتدار تبدیل میکنیم.
با بررسی خروجی میتوان مشاهده کرد که به هر یک از مقدار ارسال شده یک واحد اضافه شده است.

خروجی:

فایلهای این آموزش را میتوانید از لینک گیتهاب زیر دانلود نمایید:
https://github.com/sphrk/stm32_USB_CDC_Example
داکیومنت کتابخانه struct:
سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.