در قسمت قبل (لینک قسمت دوم) با نحوهی دریافت داده از طریق USB آشنا شدیم. در این قسمت میخواهیم دادههای دریافت شده از USB را در FIFO بنویسیم و سپس دادههای نوشته شده در FIFO را خوانده و آنها را پردازش کنیم. برای این کار ابتدا نیاز هست که یک FIFO پیادهسازی کنیم و در Callback مربوط به دریافت داده، دادههای دریافت شده را در FIFO بنویسیم.
میخواهیم کدهای مربوط به FIFO را در فایل جداگانهای بنویسیم. ابتدا در مسیر USB_DEVICE\App از پروژه دو فایل usb_serial.c و usb_serial.h را ایجاد میکنیم. در usb_serial.h ، هدر فایلهای موردنظر را اضافه کرده و امضای توابعی که میخواهیم پیادهسازی کنیم را مینویسیم. یک ماکرو برای تعیینکردن سایز FIFO در نظر میگیریم.
در فایل usb_serial.c ابتدا هدر فایل usb_serial.h را اضافه کرده و یک ساختار تعریف میکنیم. در این ساختار یک اندیس برای خواندن یک اندیس برای نوشتن و یک آرایه به طول USB_FIFO_SIZE در نظر میگیریم. متغیر usb_fifo را از نوع این ساختار تعریف میکنیم و سپس توابع موردنیاز را پیادهسازی میکنیم.
یک تابع به نام USB_write_fifo برای نوشتن در FIFO مینویسیم. این تابع یک آرایه دریافت کرده و به تعداد len مقدار از آرایهی ارسال شده را در FIFO مینویسد. موقع نوشتن در FIFO در اندیس write_index مینویسیم و سپس یک واحد این اندیس را افزایش میدهیم و پس از آن مقدار write_index را بررسی میکنیم، اگر بزرگتر از طول آرایه (USB_FIFO_SIZE) باشد در آن مقدار صفر را قرار میدهیم تا مقادیر بعدی را از ابتدای آرایه بنویسد.
در تابع USB_get_fifo_count از روی اندیسهای نوشتن و خواندن، تعداد مقادیری که در FIFO قرار دارد را به دست آورده و بر میگردانیم. برای خواندن مقادیر دریافت شده از USB از تابع USB_Read استفاده میکنیم. این تابع یک آرایه و تعداد داده (بایت) موردنظر را دریافت کرده و به تعداد داده موردنظر، از FIFO میخواند و در آرایهی ارسال شده مینویسد. کاربر میتواند پس از فراخوانی این تابع، به دادههای موردنظر در آرایهای که ارسال کرده است دسترسی داشته باشد. این تابع ابتدا تعداد مقادیر موجود در آرایه را بررسی میکند و درصورتیکه تعداد داده کافی در FIFO وجود نداشته باشد مقدار 0 را برمیگرداند. اگر تعداد داده کافی وجود داشته باشد آنها را از FIFO خوانده و در آرایهی ارسال شده مینویسد.
موقع خواندن از FIFO، از اندیس read_index میخوانیم و سپس آن را یک واحد افزایش میدهیم و سپس مقدار read_index را بررسی میکنیم، اگر بزرگتر از طول آرایه (USB_FIFO_SIZE) باشد در آن مقدار صفر را قرار میدهیم.

برای ارسال داده از طریق USB تابع USB_Write را استفاده میکنیم.

توابع موردنیاز را پیادهسازی کردیم. حال باید در تابع callback مربوط به دریافت، دادههای دریافت شده را در FIFO بنویسیم. فایل usbd_cdc_if.c باز کرده و هدر فایل usb_serial.h را به آن اضافه میکنیم تا به تابع USB_write_fifo دسترسی داشته باشیم.

در تابع callback مربوط به دریافت داده، از تابع USB_write_fifo استفاده میکنیم و Buf(دادههای دریافت شده) و Len (تعداد دادهی دریافت شده) را به این تابع ارسال میکنیم تا دادههای دریافت شده را به FIFO اضافه کند.
هدر فایل usb_serial.h که خودمان نوشتیم را به فایل main.c هم اضافه میکنیم. حال میتوانیم با استفاده از FIFO که پیادهسازی کردیم، دادههای دریافت شده را پردازش کنیم.

میخواهیم برنامهای بنویسیم که میکروکنترلر با دریافت مقدار 55 هگز، متن Hello World را ارسال کند و با دریافت مقادیر دیگر، خود مقدار دریافت شده را ارسال کند. یک متغییر (یک بایتی) به نام cmd تعریف میکنیم. در داخل حلقهی while هر بار یک بایت (یک مقدار) از FIFO خوانده و در متغییر cmd قرار میدهیم. برای اینکار آدرس متغییر cmd را به USB_Read ارسال کرده و طول داده را 1 ارسال میکنیم.
درصورتیکه در FIFO دادهای وجود داشته باشد، مقدار خوانده شده و در متغیر موردنظر قرار میگیرد و تابع مقدار 1 را بر میگرداند. در صورتی که دادهای در FIFO وجود نداشته باشد تابع USB_Read مقدار صفر بر میگرداند. برای همین USB_Read(&cmd, 1) را در شرط if قرار میدهیم تا اگر خروجی تابع غیر صفر باشد برنامه وارد if شود. برنامه زمانی وارد if میشود که مقداری از FIFO خوانده شده باشد.
در داخل if یک if دیگر نوشته و مقدار cmd را بررسی میکنیم، اگر برابر با 55 هگز باشد از طریق USB متن مورد نظر را ارسال میکنیم و در غیر این صورت مقدار دریافت شده را ارسال میکنیم.

برنامه را کامپایل کرده و میکروکنترلر را پروگرام میکنیم.
نرمافزار QCom را باز میکنیم. Com Port را باز کرده و توالی اعداد هگز 5512FF55AB را ارسال میکنیم. توجه داشته باشید که حتماً باید تیک HEX String را بزنید (در نرمافزار QCom) تا متن نوشته شده را بهصورت هگز در نظر گرفته و ارسال کند. با بررسی خروجی (اطلاعات ارسال شده از سمت میکروکنترلر) میتوان مشاهده کرد زمانی که میکروکنترلر مقدار 55 هگز را دریافت میکند، متن Hello World را ارسال میکند و بهازای بقیهی مقادیر دریافتی، همراه با یک متن، مقدار دریافتی را ارسال میکند.

میخواهیم برنامهای بنویسیم که میکروکنترلر با دریافت مقدار 01 هگز، دو عدد بعدی که دریافت میکند را با همدیگر جمع کرده و نتیجه را ارسال کند. و به ازای دریافت مقدار AA هگز، مقدار بعدی که دریافت میکند را یک واحد به آن اضافه کرده و نتیجه را ارسال کند. برای پیاده سازی از ساختار switch استفاده میکنیم.
وقتی که 01 ارسال شده باشد، دو بایت دیگر از FIFO میخوانیم. حاصل جمع دو مقدار را بدست آورده و نتیجه را ارسال میکنیم.

وقتی که AA ارسال شده باشد، یک بایت دیگر از FIFO میخوانیم و به آن یک واحد اضافه کرده و نتیجه را ارسال میکنیم.

این بار به میکروکنترلر توالی هگز 01030455aa06 را ارسال میکنیم. میکروکنترلر با دریافت 01 دو مقدار بعدی که 03 و 04 هستند را با هم جمع کرده و ارسال میکند. چون مقدار 07 (نتیجه حاصل جمع) قابل نمایش نمیباشد، نرم افزار به جای آن مربع نشان داده است. در ادامه مقدار 55 ارسال شده است برای همین میکروکنترلر هم متن Hello world را ارسال کرده است. در آخر با دریافت aa به مقدار بعدی که 06 میباشد یک واحد اضافه کرده و نتیجه را ارسال میکند (چون خروجی قابل چاپ کردن نیست به جای آن هم مربع نشان داده است).

تیک Show In Hex را میزنیم تا دادههای ارسال شده از سمت میکروکنترلر را بهصورت هگز مشاهده کنیم.

مثال دیگر:

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