اطلاعیه

Collapse
No announcement yet.

کار با پورت USB میکرو های سری AT90USB

Collapse
X
 
  • فیلتر
  • زمان
  • Show
Clear All
new posts

    #16
    پاسخ : کار با پورت USB میکرو های سری AT90USB

    وسط حرفاتون بگم
    لینک زیر رو از برادر عزیز Osamu Tamura گرفتم. مرجع کامل تمام کلاسهای کاری USB هستش :
    http://www.usb.org/developers/devclass_docs

    برای آشنایی با پروتکلهای ارتباطی فایل Class definitions for Communication Devices رو دانلود کنید.
    برای اینکه کلاس CDC رو بشناسید به 6.3.12 از فایل PSTN120.pdf مراجعه کنید.
    بت در بغل و به سجده پیشانی ما کافر زده خنده بر مسلمانی ما
    اسلام به ذات خود ندارد عیبی هر عیب که هست در این مسلمانی ماست

    دیدگاه


      #17
      پاسخ : کار با پورت USB میکرو های سری AT90USB

      خوب من دیدم آقا مجتبی مانیتور نداره گفتم. شروع کنم. در جبهه های غربی به یک باگ برخورد کردم که کار رو سخت کرده و فعلا پروژه آنالیز AVR276 متوقف شده :angry:

      استفاده از AVR272_USB_CDC_Virtual_Com_Port
      ابتدا فایل PDF و فایل های ضمیمه این application رو از لینک های زیر دانلود کنید :
      http://www.atmel.com/dyn/products/product_docs.asp?category_id=163&family_id=607 &subfamily_id=760&part_id=4096
      http://www.atmel.com/dyn/resources/prod_documents/AVR272_USB_CDC_Virtual_Com_Port.zip
      http://www.atmel.com/dyn/resources/prod_documents/doc7619.pdf
      پس از دانلود فایل های ضمیمه را extract کنید و میبینید که سه تا فایل هست که هر کدوم برای یک سری میکروکنترلرهای AT90USB هستش. ما با فایل STK526-series2-cdc-2_0_3-doc کار داریم که از AT90USB82 و AT90USB162 پشتیبانی میکنه.
      پس از extract این فایل پوشه های زیر رو میبینید :
      demo که باهاش خیلی کار داریم چون کدها تو این پوشه هستن
      doc که مربوط به توضیحات این کتابخونه هستش
      lib_board که هدر فایل های بردهای استاندارد رو داره
      lib_mcu کتابخونه های لایه های پایین برای سخت افزار میکروکنترلر
      modules که کتابخونه های لایه های بالا رو داره هم برای usb و هم برای schulder که زمانبندی اجرای قسمت های مختلف برنامه رو انجام میده و یه جوری همون main loop هستش.
      تو پوشه demo/gcc فایل مربوط به avrstudio رو میتونید اجرا کنید. به بخش configuration برید و مطابق زیر عمل کنید :




      نکته اول اینکه این کتابخونه تا این لحظه یک عدد باگ داشته :

      اول اینکه تو lib_mcu/power/power_drv.h باید چند تا پرانتز رو مثل زیر پاک کنید :


      کد:
      #ifdef __GNUC__
        #define Clear_prescaler()            (clock_prescale_set(0))
      #else
        #define Clear_prescaler()            (Set_cpu_prescaler(0))
      #endif
      
      //! Set_prescaler.
      //!
      //! This function configure the internal CPU core clock prescaler value
      //!
      //!
      //! @param x: prescaler new value
      //!
      //! @return none.
      //!
      #ifdef __GNUC__
        #define Set_cpu_prescaler(x)            (clock_prescale_set(x))
      #else
        extern void Set_cpu_prescaler(U8 x);
      #endif



      رو به صورت زیر تغییر بدید :



      کد:
      #ifdef __GNUC__
        #define Clear_prescaler()            clock_prescale_set(0)
      #else
        #define Clear_prescaler()            Set_cpu_prescaler(0)
      #endif
      
      //! Set_prescaler.
      //!
      //! This function configure the internal CPU core clock prescaler value
      //!
      //!
      //! @param x: prescaler new value
      //!
      //! @return none.
      //!
      #ifdef __GNUC__
        #define Set_cpu_prescaler(x)            clock_prescale_set(x)
      #else
        extern void Set_cpu_prescaler(U8 x);
      #endif


      بعد از اون فایل wdt.c رو از مسیر lib_mcu/wdt به پروژه اضافه کنید .


      برنامه رو کامپایل کنید. اگه مشکلی پیش اومد اون رو برطرف کنید.
      پورت USB رو به کامپیوتر وصل کنید و درایورش رو یه تک فایل inf هستش از تو پوشه demo نصب کنید. به Device Manager برید و باید یک پورت سریال مجازی اونجا ببینید. اگه نبود مشکل رو برطرف کنید.


      حالا همه چی آمادست بریم سر اصل مطلب. اتمل تو این کتابخونه به شما این امکان رو داده که به صورت یه سریال پورت با پورت USB ارتباط برقرار کنید. حالا ببینیم یه سریال پورت چی داره. خوب چند تا سیگنال داریم که به صورت flag تو برنامه قابل دسترسی هستند :



      کد:
      Signal Name	Direction	Access in code
      DTR	PC -> Device	line_status.DTR
      RTS	PC -> Device	line_status.RTS
      DCD	Device -> PC	serial_state. bDCD
      DSR	Device -> PC	serial_state. bDSR
      Ring	Device -> PC	serial_state. bRing
      CTS	Device -> PC	serial_state.bBreak


      در ضمن هر کدام از سیگنالهای Dev->PC پس از اینکه فلگش رو تغییر دادید باید تابع cdc_update_serial_state(); رو صدا بزنید تا تغییرات به کامپیوتر ارسال بشه. البته این تابع هوشمنده و اگه تغییراتی انجام نشده باشه بیخود چیزی رو ارسال نمیکنه پس مرتبا این تابع رو صدا بزنید خودش میفهمه که تغییراتی هست یا نه.

      خوب علاوه براین سیگنالها دو تا تابع داریم که کار خط TX و RX رو میکنن. در واقع اصل این دو تابع هستند


      کد:
      	PC -> Device	char uart_usb_getchar(void);
      	Device -> PC	int uart_usb_putchar(int);


      همین طور کاملا از اسمشون پیداست میتونید با اونها داده های ارسال شده از کامپیوتر را دریافت کنید یا به کامپیوتر دادههایی رو بفرستید.
      فقط برای دریافت کردن اول باید مطمئن بشید که داده ای وجود داره این کار رو با تابع uart_usb_test_hit() انجام میدیم و متغیر rx_counter هم تعداد بایت های باقی مونده رو به ما میده. کد زیر یک مثاله که با دریافت کاراکتر ‘a’ پورت D رو 1 میکنه و با دریافت کاراکتر ‘b’ پورت D رو 0 میکنه :



      کد:
      if (uart_usb_test_hit())  // Something received from the USB ?
      {
      	while (rx_counter)
      	{
      		ch = uart_usb_getchar();	// Echo and
      		if( ch == 'a’ )
      			PORTD = 1;
      		Else if(ch ==’b’)
      			PORTD = 0;
      	}
      }


      کمی دقیقتر باید توضیح بدم.
      شما باید کدهای مربوط به تبادل داده با PC رو داخل یکی از دو محل زیر بنویسید.
      1 . داخل تابع void cdc_task(void) در فایل cdc_task.c .
      اگه به این تابع نگاه کنید می بینید که بچه های اتمل هم همین کار رو کردن و اون تو کدهاشون رو نوشتن. میتونید تمام اون کد ها پاک کنید و فقط این چند خط رو به عنوان بیس کار باقی بزارید :



      کد:
      void cdc_task(void)
      {
      	char ch = 0;
      	if(Is_device_enumerated()) //Enumeration processs OK and COM port openned ?
      	{
      		if (uart_usb_test_hit())  // Something received from the USB ?
      		{
      			while (rx_counter)
      			{
      				ch = uart_usb_getchar();	// Echo upercase
      				if( ch >= 'a' && ch <= 'z' )
      					ch -= 'a' - 'A';
      				
      				uart_usb_putchar(ch);  // loop back USB to USART
      			}
      		}
      		cdc_update_serial_state();
      	}
      }


      خوب با توضیحاتی که دادم دیگه میتونید از مثال اتمل به خوبی سر در بیارید. میمونه فایل های printf و scanf که با دستور زیر تو همون فایل cdc_task.c به دو تابع uart_usb_putchar و uart_usb_getchar پیوند خورده :



      کد:
      #ifdef __GNUC__
        fdevopen((int (*)(char, FILE*))(uart_usb_putchar),(int (*)(FILE*))uart_usb_getchar); //for printf redirection 
      #endif



      امیدوارم مفید بوده باشه. به زودی یه پروژه مثال با C# و این سیستم میزاریم که دمای هوا و وضعیت 4 کلید رو روی صفحه مانیتور ببینید و همچنین 2 رله رو توسط فرمان از طریق کامپیوتر قطع و وصل کنید.
      بت در بغل و به سجده پیشانی ما کافر زده خنده بر مسلمانی ما
      اسلام به ذات خود ندارد عیبی هر عیب که هست در این مسلمانی ماست

      دیدگاه


        #18
        پاسخ : کار با پورت USB میکرو های سری AT90USB

        USB Descriptors :
        در طول مراحل سرشماری میزبان چندتا از توصیفگرهای دستگاه رو از اون درخواست میکنه تا بتونه اون رو به درستی شناسایی و درایور درست رو برای راه اندازیش لود بکنه . به طور کلی هر دستگاه USB باید توصیفگرهای نشان داده شده در شکل زیر رو دارا باشه تا توسط میزبان قابل شناسایی باشه و اون رو شناسایی کنه


        مشکلترین قسمت کار نوشتن برنامه برای ارتباط با پورت USB اینه که بتونه تعیین کنه توصیفگرهای دستگاه باید چی باشند هر دستگاه USB برای اتصال به میزبان نیاز به فرایندی داره که سرشماری (enumeration) نامیده میشه .که البته AT90USBxxx software library تمام مراحل انجام سرشماری رو برای هر دو مد device و reduced host فراهم میکنه و به این ترتیب طی مراحل سرشماری توصیفگرهای دستگاه به میزبان ارسال میشه طوری که هر توصیفگر معادل یک آدرس منحصر به فرد هست .

        توصیفگرهای دستگاه (Device Descriptor) :

        هر دستگاه USB تنها میتونه یک توصیفگر دستگاه باشه ، این توصیفگر اطلاعاتی در رابطه با ورژن USB ، ماکزیمم اندازه هر بسته اطلاعات اندپوینت صفر ، VID ، PID ، ورژن دستگاه ، تعداد پیکره بندی های ممکن که دستگاه اون ها رو شامل میشه و چند توصیفگر دیگر در جدول زیر فرمت این توصیفگر نشان داده شده است :


        توصیفگر پیکره بندی (Configuration Descriptor) :
        هر دستگاه usb میتواند بیشتر از یک توصیفگر پیکره بندی داشته باشد البته اکثر دستگاه های usb تنها دارای یک توصیفگر پیکره بندی میباشند . این توصیفگر همونطور که از اسمش پیداس برای مواردی چون مد تغذیه دستگاه ، اینکه دستگاه خود بایاس باشه یعنی از تغذیه روی باس USB استفاده نمی کنه و یا اینکه از تغذیه باس استفاده میکنه ، اگر دستگاه خود بایاس هست حداکثر توانی که میتونه از باس دریافت کنه (ماکزیمم جریان دریافتی از باس ) چقدر هست ، تعدا واسط های موجود ، اندازه کل بایت های داده بازگشتی از دستگاه که شامل مجموع بایت های توصیفگرهای پیکره بندی ، واسط و اندپوینت می باشد و چند مورد دیگر که در جدول زیر به اختصار توضیح داده شده اند :



        توصیفگر واسط (Interface Descriptor ) :
        هر دستگاه میتواند بیش از یک واسط داشته باشد اطلاعات اصلی که توسط این توصیفگر منتقل می شود تعداد اندپوینت های دستگاه به غیر از اندپوینت صفر و همچنین اینکه usb تو چه کلاس و زیر کلاسی داره کار میکنه و موارد دیگه که در جدول زیر به اختصار توضیح داده شده اند :



        توصیفگر اندپوینت (Endpoint Descriptor) :
        این توصیفگر برای توصیف پارامترهای اندپوینت دستگاه استفاده میشه مانند : جهت اندپوینت اینکه ورودی هست یا خروجی ، آدرس اندپوینت ، نوع ارسال داده اینکه ارسال کنترلی ، توده ای ، وقفه ای و یا اینکه همزمان هست .حداکثر اندازه بسته ای که اندپوینت در یک ترنزکشن پشتیبانس میکنه ، فاصله زمانی مابین انتقال داده ها در مد ارسال وقفه ای و موارد دیگر که به اختصار در جدول زیر توضیح داده شده اند :




        توجه : در USB داده ها با ساختار مشخصی انتقال میابند بطوری که داده ها در بسته ها و زمان های مشخص انتقال پیدا می کنند که به هر بسته اطلاعاتی یک ترنزکشن گفته میشود.


        پایان قسمت دوم (AVR276)

        دیدگاه


          #19
          پاسخ : کار با پورت USB میکرو های سری AT90USB

          سلام
          در راستا انجام مراحل گفته شده در "پاسخ # 16"
          پیغام زیر در پنجره Message ظاهر میشه :
          gcc plug-in: no avr toolchain installation found. the avr gcc plug-in can still be used if you set up your own build tools.
          ازکجا باید متوجه کامپایل شدن صحیح avrstudio بشیم ؟

          دیدگاه


            #20
            پاسخ : کار با پورت USB میکرو های سری AT90USB

            نوشته اصلی توسط hamid67fathi
            سلام
            در راستا انجام مراحل گفته شده در "پاسخ # 16"
            پیغام زیر در پنجره Message ظاهر میشه :
            gcc plug-in: no avr toolchain installation found. the avr gcc plug-in can still be used if you set up your own build tools.
            ازکجا باید متوجه کامپایل شدن صحیح avrstudio بشیم ؟
            این اررور میگه که avrstudio کامل نصب نشده و toolchain ش رو پیدا نمیکنه. کدوم ورژن رو استفاده می کنید؟ ورژن 5 ؟ فایل 600 مگی رو دانلود کردی؟
            بت در بغل و به سجده پیشانی ما کافر زده خنده بر مسلمانی ما
            اسلام به ذات خود ندارد عیبی هر عیب که هست در این مسلمانی ماست

            دیدگاه


              #21
              پاسخ : کار با پورت USB میکرو های سری AT90USB

              نوشته اصلی توسط mostafahk
              این اررور میگه که avrstudio کامل نصب نشده و toolchain ش رو پیدا نمیکنه. کدوم ورژن رو استفاده می کنید؟ ورژن 5 ؟ فایل 600 مگی رو دانلود کردی؟
              سلام
              حجمش 124 MB هست و از لینک خود Atmel دانلود کردم.
              http://www.atmel.com/dyn/resources/prod_documents/avrstudio4setup.exe

              دیدگاه


                #22
                پاسخ : کار با پورت USB میکرو های سری AT90USB

                نوشته اصلی توسط hamid67fathi
                سلام
                حجمش 124 MB هست و از لینک خود Atmel دانلود کردم.
                http://www.atmel.com/dyn/resources/prod_documents/avrstudio4setup.exe
                نه این ناقصه. 600 مگابایتیه رو دانلود کن.
                http://www.atmel.com/forms/software_...l-5.0.1223.exe
                بت در بغل و به سجده پیشانی ما کافر زده خنده بر مسلمانی ما
                اسلام به ذات خود ندارد عیبی هر عیب که هست در این مسلمانی ماست

                دیدگاه


                  #23
                  پاسخ : کار با پورت USB میکرو های سری AT90USB

                  آقا من راستش دیگه با این مثال اتمل حال نکردم رفتم سراغ همون LUFA ، خوب این چند تا مزیت داره اولا اینکه تو برای کار تو کلاس ها مختلف مثال داره دومم اینکه خود آقا DEAN CAMERA هی و حاضر اند و هر سوالی داشتیم از خودشون میتونیم بپرسیم .


                  پس از این جا به بعد این تاپیک متمرکز میشه به "کار با LUFA "؛
                  کار با LUFA
                  قسمت اول
                  اجرای VirtualSerial

                  با یه مثال که برای کار با کلاس CDC هست شروع میکنم :
                  اما کسایی که میخوان استفاده کنند:
                  1. اول آخرین ورژن LUFA رو از سایت آقای Dean Camera
                  http://www.fourwalledcubicle.com/LUFA.php
                  2. برای کار با LUFA یا از WINAVR یا AVRSTUDIO استفاده میکنیم .
                  3. برای شروع از مثال VirtualSerial استفاده میکنیم این مثال تو مسیر زیر واقع شده :
                  \LUFA-120219\Demos\Device\ClassDriver\VirtualSerial
                  4.بعد makefile اش رو بازمیکنید و اگه میکروتون با پیشفرض فرق داشت اسم میکرو رو عوض میکنید ، اینجا :

                  # MCU name
                  MCU = at90usb162

                  5. برنامه برای at90usb1287 نوشته شده و پیکره بندی سخت افزارش هم با توجه به پایه های این میکرو در بورد USBKEY انجام شده از این جهت اگه میکرو رو عوض کنید احتمال داره که پایه هایی که تو پیکره بندی سخت افزار ازشون استفاده شده تو میکرو جدید موجود نباشند که موقع کامپایل دقیقا با کلیک بر روی ارور مربوطه میتونید به اون جا که اون پایه تعریف شده مراجعه کنید و اون رو تغییر بدید مثلا من با at90usb162 کار میکنم بعد از کامپایل به من میگه که میکرو شما porte نداره و بعد من هم امدم فایل Joystick.h که تو مسیر : LUFA-120219\LUFA\Drivers\Board\AVR8\USBKEY قرار گرفته رو به صورت زیر اصلاح کردم تا بتونم مثال خودش رو اجرا کنم ؛

                  کد:
                  /* Private Interface - For use in library only: */
                  	#if !defined(__DOXYGEN__)
                  		/* Macros: */
                  			#define JOY_BMASK         ((1 << 2) | (1 << 3) | (1 << 4))
                  			#define JOY_EMASK         ((1 << 1) | (1 << 0))
                  
                  			#define JOY_PORTE_MASK_SHIFT   0
                  	#endif
                  
                  	/* Public Interface - May be used in end-application: */
                  		/* Macros: */
                  			/** Mask for the joystick being pushed in the left direction. */
                  			#define JOY_LEFT         (1 << 0)
                  
                  			/** Mask for the joystick being pushed in the right direction. */
                  			#define JOY_RIGHT        ((1 << 1) >> JOY_PORTE_MASK_SHIFT)
                  
                  			/** Mask for the joystick being pushed in the upward direction. */
                  			#define JOY_UP          (1 << 2)
                  
                  			/** Mask for the joystick being pushed in the downward direction. */
                  			#define JOY_DOWN         ((1 << 3) >> JOY_PORTE_MASK_SHIFT)
                  
                  			/** Mask for the joystick being pushed inward. */
                  			#define JOY_PRESS         (1 << 4)
                  
                  		/* Inline Functions: */
                  		#if !defined(__DOXYGEN__)
                  			static inline void Joystick_Init(void)
                  			{
                  				DDRB &= ~JOY_BMASK;
                  				DDRB &= ~JOY_EMASK;
                  
                  				PORTB |= JOY_BMASK;
                  				PORTB |= JOY_EMASK;
                  			}
                  
                  			static inline void Joystick_Disable(void)
                  			{
                  				DDRB &= ~JOY_BMASK;
                  				DDRB &= ~JOY_EMASK;
                  
                  				PORTB &= ~JOY_BMASK;
                  				PORTB &= ~JOY_EMASK;
                  			}
                  
                  			static inline uint8_t Joystick_GetStatus(void) ATTR_WARN_UNUSED_RESULT;
                  			static inline uint8_t Joystick_GetStatus(void)
                  			{
                  				return (((uint8_t)~PINB & JOY_BMASK) | (((uint8_t)~PINB & JOY_EMASK) >> JOY_PORTE_MASK_SHIFT));
                  			}
                  		#endif

                  6. بعد پروزه رو کامپایل میکنید .
                  7. من برای پروگرام کردن از flip استفاده میکنم ،اگه شما هم میخوایید با flip کار کنید و اگه فلیپ رو ندارید اون رو دانلود و نصبش کنید و درایورش رو هم نصب کنید . برای نحوه کار با flip به اینجا مراجعه کنید : http://www.eca.ir/forum2/index.php?topic=55398.0
                  8. حالا میکرو رو با فیلیپ پروگرام میکنیم بعد روی start کلیک میکنیم بعداز چند لحظه میکرو به عنوان یه device توسط pc با عنوان "lufa cdc demo" شناسایی میشه .
                  9. حالا باید درایور device جدید رو نصب کنیم برای اینکار درایور که تو مسیر : \LUFA-120219\Demos\Device\ClassDriver\VirtualSerial رو انتخاب و نصب میکنید.
                  10. به این ترتیب device جدید با عنوان "Communications Port" شناخته میشه .

                  11. حالا برای تست یه نرم افزار برای ارتبط با پورت سریال تهیه کنید بعد تنظیمات اون رو متناسب با تنظیمات device مون انجام بدید بعد هم کانکت بشید ،اگه فایل Joystick.h رو طوری که من گفتم پیکره بندی کرده باشید
                  با صفر شدن به ترتیب پایه های : PB0 , PB1 , PB2 ,PB3 , PB4 تو محیط ترمینال به ترتیب موارد زیر به نمایش در میان :

                  Joystick Left

                  Joystick Right

                  Joystick Up

                  Joystick Down

                  Joystick Pressed


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

                  پایان قسمت اول کار با LUFA

                  دیدگاه


                    #24
                    پاسخ : کار با پورت USB میکرو های سری AT90USB

                    2.بررسی مثال VirtualSerial (بخش اول)
                    خوب بیایید فایل سورس برنامه رو ببینیم توش چه خبره ،

                    خوب اولش که امده VirtualSerial.h رو اینکلود کرده ، پس بریم ببینیم تو این چه خبره ،
                    تو فایل هدر VirtualSerial.h اول امده فایل های هدر معمول مورد نیاز که تو دایرکتوری اصلی نرم افزار هستند رو اینکلود کرده ، به ترتیب زیر :

                    کد:
                    #include <avr/io.h>
                    		#include <avr/wdt.h>
                    		#include <avr/power.h>
                    		#include <avr/interrupt.h>
                    		#include <string.h>
                    		#include <stdio.h>

                    بعد فایل هدر Descriptors.h رو اینکلود کرده تو این فایل همونطور که قبلا تو چند پست پیش گفته شد تنظیمات مربوط به توصیفگرها انجام شده ، پسر خوبیه کاری به کارش نداریم :mrgreen:
                    که به صورت زیر اینکلود شده :

                    کد:
                    ##include "Descriptors.h"


                    بعد از این هدر مربوط به ورژن lufa هست که در اون اطلاعات مربوط به ورژن ، روز ،ماه و سال انتشار قرار گرفته و به صورت زیر اینکلود شده :

                    کد:
                    #include <LUFA/Version.h>

                    بعد از این فایل های هدر مربوط به پیکره بندی سخت افزار مورد استفاده قرا گرفته که به قرار زیر هستند :

                    کد:
                    	#include <LUFA/Drivers/Board/LEDs.h>
                    		#include <LUFA/Drivers/Board/Joystick.h>

                    تو فایل هدر اول اطلاعات مربوط به پیکره بندی led ها قرار گرفته و تو فایل دوم اطلاعات مربوط بهJoystick که یه صفحه کلید 5 کلیدی هست .
                    تو فایل اول رو که نگاه کنید میبیند که میاد با توجه به سخت افزار انتخاب شده تو میک فایل سخت افزار مورد استفاده رو تشخیص میده و بعد میره به فایل هدر مربوط به پیکره بندی led های اون سخت افزار و پیکره بندی اون رو برای اعمال دستور ات برنامه به پورت ها جهت خاموش و روشن کردن led ها در نظر میگره ،خوب تو اینجا به صورت پیشفرض چون تو میک فایل سخت افزار مورد نظر USBKEY انتخاب شده ،تو این قسمت از میک فایل :

                    کد:
                    # Target board (see library "Board Types" documentation, NONE for projects not requiring
                    # LUFA board drivers). If USER is selected, put custom board drivers in a directory called
                    # "Board" inside the application directory.
                    BOARD = USBKEY

                    تنظیمات بورد توسعه USBKEY اعمال میشه . البته میتونیم فایل هدر سخت افزار خودمون رو درست کنیم و اون رو وارد فایل هدر کنیم و تو میک فایل اون رو انتخاب کنیم ، اما من اینجا از همین استفاده میکنم و تنظیمات خودم رو تو همون اعمال میکنم مثلا پورت هایی که led ها از شماره یک تا سه به اون متصل هستند رو پورت d و پین های صفر تا سه انتخاب کردم ، به صورت زیر :
                    تنظیمات اعمال شده در فایل هدر به آدرس : LUFA-120219\LUFA\Drivers\Board\AVR8\USBKEY

                    کد:
                    /* Public Interface - May be used in end-application: */
                    		/* Macros: */
                    			/** LED mask for the first LED on the board. */
                    			#define LEDS_LED1    (1 << 0)
                    
                    			/** LED mask for the second LED on the board. */
                    			#define LEDS_LED2    (1 << 1)
                    
                    			/** LED mask for the third LED on the board. */
                    			#define LEDS_LED3    (1 << 2)
                    
                    			/** LED mask for the fourth LED on the board. */
                    			#define LEDS_LED4    (1 << 3)
                    
                    			/** LED mask for all the LEDs on the board. */
                    			#define LEDS_ALL_LEDS  (LEDS_LED1 | LEDS_LED2 | LEDS_LED3 | LEDS_LED4)
                    
                    			/** LED mask for none of the board LEDs. */
                    			#define LEDS_NO_LEDS   0
                    			
                    			,
                    			
                    			static inline void LEDs_Init(void)
                    			{
                    				DDRD |= LEDS_ALL_LEDS;
                    				PORTD &= ~LEDS_ALL_LEDS;
                    			}
                    
                    			static inline void LEDs_Disable(void)
                    			{
                    				DDRD &= ~LEDS_ALL_LEDS;
                    				PORTD &= ~LEDS_ALL_LEDS;
                    			}
                    
                    			static inline void LEDs_TurnOnLEDs(const uint8_t LEDMask)
                    			{
                    				PORTD |= LEDMask;
                    			}
                    
                    			static inline void LEDs_TurnOffLEDs(const uint8_t LEDMask)
                    			{
                    				PORTD &= ~LEDMask;
                    			}
                    
                    			static inline void LEDs_SetAllLEDs(const uint8_t LEDMask)
                    			{
                    				PORTD = ((PORTD & ~LEDS_ALL_LEDS) | LEDMask);
                    			}
                    
                    			static inline void LEDs_ChangeLEDs(const uint8_t LEDMask,
                    			                  const uint8_t ActiveMask)
                    			{
                    				PORTD = ((PORTD & ~LEDMask) | ActiveMask);
                    			}
                    
                    			static inline void LEDs_ToggleLEDs(const uint8_t LEDMask)
                    			{
                    				PORTD ^= LEDMask;
                    			}
                    
                    			static inline uint8_t LEDs_GetLEDs(void) ATTR_WARN_UNUSED_RESULT;
                    			static inline uint8_t LEDs_GetLEDs(void)
                    			{
                    				return (PORTD & LEDS_ALL_LEDS);
                    			}

                    و به همین ترتیب تنظیمات مربوط به Joystick در فایل هدر Joystick.h قرار گرفته ، که من تنظیمات خودم رو به صورت زیر تو فایل هدر مربوط به بورد توسعهusbkey رو به صورت زیر اعمال کردم :
                    LUFA-120219\LUFA\Drivers\Board\AVR8\USBKEY

                    کد:
                    /* Private Interface - For use in library only: */
                    	#if !defined(__DOXYGEN__)
                    		/* Macros: */
                    			#define JOY_BMASK         ((1 << 2) | (1 << 3) | (1 << 4))
                    			#define JOY_EMASK         ((1 << 1) | (1 << 0))
                    
                    			#define JOY_PORTE_MASK_SHIFT   0
                    	#endif
                    
                    	/* Public Interface - May be used in end-application: */
                    		/* Macros: */
                    			/** Mask for the joystick being pushed in the left direction. */
                    			#define JOY_LEFT         (1 << 0)
                    
                    			/** Mask for the joystick being pushed in the right direction. */
                    			#define JOY_RIGHT        ((1 << 1) >> JOY_PORTE_MASK_SHIFT)
                    
                    			/** Mask for the joystick being pushed in the upward direction. */
                    			#define JOY_UP          (1 << 2)
                    
                    			/** Mask for the joystick being pushed in the downward direction. */
                    			#define JOY_DOWN         ((1 << 3) >> JOY_PORTE_MASK_SHIFT)
                    
                    			/** Mask for the joystick being pushed inward. */
                    			#define JOY_PRESS         (1 << 4)
                    
                    		/* Inline Functions: */
                    		#if !defined(__DOXYGEN__)
                    			static inline void Joystick_Init(void)
                    			{
                    				DDRB &= ~JOY_BMASK;
                    				DDRB &= ~JOY_EMASK;
                    
                    				PORTB |= JOY_BMASK;
                    				PORTB |= JOY_EMASK;
                    			}
                    
                    			static inline void Joystick_Disable(void)
                    			{
                    				DDRB &= ~JOY_BMASK;
                    				DDRB &= ~JOY_EMASK;
                    
                    				PORTB &= ~JOY_BMASK;
                    				PORTB &= ~JOY_EMASK;
                    			}
                    
                    			static inline uint8_t Joystick_GetStatus(void) ATTR_WARN_UNUSED_RESULT;
                    			static inline uint8_t Joystick_GetStatus(void)
                    			{
                    				return (((uint8_t)~PINB & JOY_BMASK) | (((uint8_t)~PINB & JOY_EMASK) >> JOY_PORTE_MASK_SHIFT));
                    			}
                    		#endif


                    بعد از این فایل هدر USB.h به ترتیب زیر اینکلود شده :

                    کد:
                    #include <LUFA/Drivers/USB/USB.h>

                    تو این فایل هدر ، هدر تمامی کتابخانه های مورد نیاز برای کار با پورت usb تو تمامی کلاس ها اینکلود شده و دیگه نیازی نیست که برای مثلا یک کار خاص فایل های هدر مورد نیاز رو به صورت جداگانه اینکلود کنیم ، به این ترتیب در صورت استفاده از پورت usb باید در ابتدای برنامه اینکلود بشه .
                    بعد از اینها 4 تا ماکرو داریم به قرار زیر:

                    کد:
                    /* Macros: */
                    		/** LED mask for the library LED driver, to indicate that the USB interface is not ready. */
                    		#define LEDMASK_USB_NOTREADY   LEDS_LED1
                    
                    		/** LED mask for the library LED driver, to indicate that the USB interface is enumerating. */
                    		#define LEDMASK_USB_ENUMERATING (LEDS_LED2 | LEDS_LED3)
                    
                    		/** LED mask for the library LED driver, to indicate that the USB interface is ready. */
                    		#define LEDMASK_USB_READY    (LEDS_LED2 | LEDS_LED4)
                    
                    		/** LED mask for the library LED driver, to indicate that an error has occurred in the USB interface. */
                    		#define LEDMASK_USB_ERROR    (LEDS_LED1 | LEDS_LED3)

                    ماکرو اول میاد led شماره یک رو روشن میکنه ، خوب روشن شدن این ماکرو تو برنامه تو جایی استفاده شده که با روشن کردن led شماره یک به ما اطلاع میده که پورت usb قابل استفاده نیست و ارتباط برقرار نشده .

                    تو ماکرو دوم led های 2 و 3 روشن میشن ، خوب روشن شدن این دو led با هم به این معنی هست که دستگاه ما در حال انجام مرحله سرشماری هست و هنوز ارتباط برقرار نشده .
                    ماکرو سوم led های 2 و 4 رو روشن میکنه و روشن شدن این دو با هم به معنی اتمام سرشماری و برقراری ارتباط موفق با پورت کام هست و میشه با pc از طریق یه اینترفیس با میکرو ارتباط برقرار کرد .
                    ماکروی چهارم led 1 و 3 روشن میکنه روشن شدن این دو led با هم یعنی اینکه مراحل سرشماری تمام شده اما موقع برقرای ارتباط با مشکل مواجه شده و عیب رو باید در این مرحله جستجو کرد.

                    خوب بعد از این ماکرو ها پروتوتایپ توابعی که البته 4 تای آخر رخداد هستند که تو برنامه استفاده شدند نوشته شده اند که به قرار زیر هستند :

                    کد:
                    /* Function Prototypes: */
                    		void SetupHardware(void);
                    		void CheckJoystickMovement(void);
                    
                    		void EVENT_USB_Device_Connect(void);
                    		void EVENT_USB_Device_Disconnect(void);
                    		void EVENT_USB_Device_ConfigurationChanged(void);
                    		void EVENT_USB_Device_ControlRequest(void);

                    خوب اول اینکه تمام توابع و رخدادها بدون ورودی و خروجی هستند .

                    تابع اول ،SetupHardware :
                    با فراخونی این تابع تنظیمات سخت افزاری میکرو و بورد انجام میشه .

                    تابع دوم ،CheckJoystickMovement :
                    تو این تابع همونطور که ازاسمش پیداس ، چک میشه که آیا کلیدی از جوی استیک فشار داده شده یا خیر ، بررسی بیشتر بمونه برای بعد از برگشت به فایل سورس اصلی و رسیدن به این تابع .

                    خوب قبل از اینکه رخداد ها رو بررسی کنیم ،هر کدام از این رخداد ها یا به اصطلاح USB Events مربوط به یک از اتفاقات جاری در پورت usb هستند مثل متصل شدن ، قطع شدن ، سرشماری و... .

                    رخداد اول ، EVENT_USB_Device_Connect :
                    این رخداد موقع اتصال میکرو به پورت usb فراخونی میشه و هرچی داخل اون باشه اجرا میشه
                    توجه کنید که این رخداد time-critical هست و نباید اجرای اون بیشتر از 2 ثانیه طول بکشه ، در غیر اینصورت مراحل سرشماری بدرستی انجام نمیشه.

                    رخداد دوم ، EVENT_USB_Device_Disconnect :
                    این رخداد زمانی رخ میده که میکرو در مد USB Device هست و مراحل سرشماری طی شده و میکرو با پورت usb ارتباط برقرار کرده ، اگه میکرو از پورت usb جدا بشه این رخداد رخ میده و هرچی داخلش باشه اجرا میشه ، یعنی اگه حین کار یدفعه کابل پورت USB قطع شد میتونیم با یک کردن یه فلگ یه آلارمی رو فعال کنیم که آقا اتصال پورت USB قطع شده.

                    رخداد سوم، EVENT_USB_Device_ConfigurationChanged :
                    این رخداد زمانی رخ میده که شماره پیکره بندی تغییر کنه ، با وقوع این تغییر این رخداد به وقوع می پیونده و باید در روال اون کلاسی که میخواهیم میکرو در اون کار کنه رو انتخاب کنیم و توسط تابع CDC_Device_ConfigureEndpoints پیکره بندی مورد نظر رو بروی اندپوینت ها انجام بدیم که اگر درست اجرا بشه خروجی این تابع "TRUE" و در غیر این صورت "FALSE" خواهد بود .
                    توجه کنید که این رخداد time-critical هست و نباید اجرای اون بیشتر از 1 ثانیه طول بکشه ، در غیر اینصورت مراحل سرشماری بدرستی انجام نمیشه.

                    رخداد چهارم ، EVENT_USB_Device_ControlRequest :
                    این رخداد زمانی که میزبان یه درخواست رو برای اندپوینت کنترلی دستگاه USB ارسال میکنه رخ میده . تو این رخداد باید درخواست ارسالی با استفاده از تابع CDC_Device_ProcessControlRequest بررسی بشه ، ورودی این تابع کلاسی هست که توش کار میکنیم .
                    توجه کنید که این رخداد time-critical هست و نباید اجرای اون بیشتر از 50ms طول بکشه ، در غیر اینصورت مراحل سرشماری بدرستی انجام نمیشه.

                    پایان قسمت دوم



                    دیدگاه


                      #25
                      پاسخ : کار با پورت USB میکرو های سری AT90USB

                      3.بررسی مثال VirtualSerial (بخش دوم )

                      خوب حالا برمیگردیم داخل فایل سورس اصلی برنامه یعنی ، VirtualSerial.c :

                      در ادامه فایل چیزی که میبینیم یه داده داریم که به صورت Structure که اون هم به صورت لانه ای تعریف شده ( چقدر خفنه !) که به قرار زیر هست :

                      کد:
                      typedef struct
                      			{
                      				struct
                      				{
                      					uint8_t ControlInterfaceNumber; /**< Interface number of the CDC control interface within the device. */
                      
                      					uint8_t DataINEndpointNumber; /**< Endpoint number of the CDC interface's IN data endpoint. */
                      					uint16_t DataINEndpointSize; /**< Size in bytes of the CDC interface's IN data endpoint. */
                      					bool   DataINEndpointDoubleBank; /**< Indicates if the CDC interface's IN data endpoint should use double banking. */
                      
                      					uint8_t DataOUTEndpointNumber; /**< Endpoint number of the CDC interface's OUT data endpoint. */
                      					uint16_t DataOUTEndpointSize; /**< Size in bytes of the CDC interface's OUT data endpoint. */
                      					bool   DataOUTEndpointDoubleBank; /**< Indicates if the CDC interface's OUT data endpoint should use double banking. */
                      
                      					uint8_t NotificationEndpointNumber; /**< Endpoint number of the CDC interface's IN notification endpoint, if used. */
                      					uint16_t NotificationEndpointSize; /**< Size in bytes of the CDC interface's IN notification endpoint, if used. */
                      					bool   NotificationEndpointDoubleBank; /**< Indicates if the CDC interface's notification endpoint should use double banking. */
                      				} Config; /**< Config data for the USB class interface within the device. All elements in this section
                      				      *  <b>must</b> be set or the interface will fail to enumerate and operate correctly.
                      				      */
                      				struct
                      				{
                      					struct
                      					{
                      						uint16_t HostToDevice; /**< Control line states from the host to device, as a set of \c CDC_CONTROL_LINE_OUT_*
                      											  *  masks. This value is updated each time \ref CDC_Device_USBTask() is called.
                      											  */
                      						uint16_t DeviceToHost; /**< Control line states from the device to host, as a set of \c CDC_CONTROL_LINE_IN_*
                      											  *  masks - to notify the host of changes to these values, call the
                      											  *  \ref CDC_Device_SendControlLineStateChange() function.
                      											  */
                      					} ControlLineStates; /**< Current states of the virtual serial port's control lines between the device and host. */
                      
                      					CDC_LineEncoding_t LineEncoding; /** Line encoding used in the virtual serial port, for the device's information.
                      					                 * This is generally only used if the virtual serial port data is to be
                      					                 * reconstructed on a physical UART.
                      					                 */
                      				} State; /**< State data for the USB class interface within the device. All elements in this section
                      				     *  are reset to their defaults when the interface is enumerated.
                      				     */
                      			} USB_ClassInfo_CDC_Device_t;


                      خوب اول ،
                      مختصری در مورد Structure

                      خوب ببینید ما تو زبان سی انواع داده داریم مثل char, int , float ,unsigned char,unsigned iint,long in و ... که همونطور که میدونید میتونیم با استفاده از پیشوندها ترکیبات جدید بسازیم اما اینها همگی به یک نوع داده خاص دلالت میکنند ، یعنی ما نمیتونیم تو یه داده از نوع int هم کاراکتر بریزیم هم عدد !

                      خوب فرض کنید که سازمان ثبت احوال میخواد اطلاعات هر نفر رو اعم از نام ، نام خانوادگی ، نام پدر ، تاریخ تولد ، محل صدور، شماره شناسنامه، کد ملی و ... رو تو یه متغیر ذخیره کنه .
                      خوب اگه بخواد این ها رو ذخیره کنه باید برای اون هایی که به صورت کارکتر هستند بیاد یه آرایه دو بعدی که بعد اولش تعداد کاراکتر های مورد نیاز برای هر نفر و آرایه دومش تعداد آدم ها هستند رو از نوع char تعریف کنه و برای اون هایی که از نوع عدد هستند باید برای یه ارایه دوبعدی تعریف کنه که تو بعد اول تعداد درایه مورد نیاز برای اون اطلاعات خاص و تو بعد دوم تعداد آدم ها رو از نوع مثلا int تعریف کنه .

                      خوب حالا این به خودش میگه چی میشد من یه متغیر داشتم که به اندازه آدم ها آرایه داشت و تو همون متغیر اطلاعات رو وارد میکردم . خوب این آقا چیزی که میخواد اینه که یه نوع داده باشه ، 120 بایتی ، که تو مثلا 100 بایت اولش بشه کارکتر گذاشت تو 20 بایت بعدش عدد بعد هم به صورت آرایه تک بعدی باشه و بعدش هم به اندازه تمام آدم ها باشه .

                      خوب همونطور که میدونید ما همچین چیزی تو زبان سی نداریم ، پس باید این "نوع داده جدید رو ایجاد کنیم " این کار با استفاده از دستور struct به فرم کلی زیر انجام میشه :


                      کد:
                      struct "اسم نوع داده جدید"{
                      
                      لیست عناصر داده ;
                      };


                      مثلا فرض کنید میخواییم همین نوع داده ای که سازمان ثبت احوال لازم داره رو ایجاد کنیم ،مینویسیم :

                      کد:
                      struct personal{
                      
                      char first_name[20];
                      char last_name[20];
                      char father_name[20];
                      int date_of_birth;
                       
                      };


                      خوب این از نوع داده جدید .

                      اما ما که صرفا نمیخواییم فقط یه نوع داده تعریف کنیم ،مگه نه !؟

                      چیزی که سازمان ثبت احوال میخواست "یه متغیر با یه نوع داده جدید" بود.

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

                      فرم کلی تعریف متغیر مثل تعریف متغیر های معمولی هست که به قرار زیر هست :

                      struct "اسم متغیر" "اسم نوع داده جدید"


                      یا مثلا همون موقع که نوع رو ایجاد میکنیم ، پشت بندش متغیر ها مون رو هم تعریف میکنیم ، تو این حالت در صورت عدم نیاز به این نوع داده جدید برای تعریف متغیر هایی از این جنس داده در مکان های دیگه میتونیم از اسم نوع داده جدید فاکتور بگیریم و حذفش کنیم ، به صورت زیر :

                      کد:
                      struct {
                      
                      لیست عناصر داده ;
                      } "اسم متغیر"


                      خوب حالا میتونیم یه متغیر با اون نوع داده ای که سازمان ثبت احوال میخواست ایجاد کنیم ، اسم متغیر رو هم person میزاریم و از نوع personal(که قبلا این توع داده رو تعریفش کردیم) رو به صورت یه متغیر مثلا 1000 درایه ای که قراره تو هر داریه مشخصات یه نفر قرار بگیره ، به صورت زیر تعریف میکنیم :

                      struct personal person[1000];


                      یا :


                      struct {

                      char first_name[20];
                      char last_name[20];
                      char father's_name[20];
                      int date_of_birth;

                      }person[1000];


                      خوب حالا برای دسترسی به هر کدوم از عناصر متغیر جدید مون که به صورت ساختمان داده هست باید از "." استفاده کنیم .

                      مثلا فرض کنید که میخواییم اطلاعات شخص شماره 20 رو برای سازمان ثبت احوال ثبت کنیم ، داریم :


                      person[20].first_name="ali";
                      person[20].last_name="taghipour";
                      person[20].father_name="hasan";
                      person[20].date_of_birth=1370;



                      خوب حالا فرض کنید که سازمان احوال بخواد اطلاعات رو برحسب آدرس که شامل استان ، شهر ، خیابان ،کوچه و پلاک محل زندگی افراد sort کنه و همینطور تاریخ تولید افراد ، روز ، ماه و سالش هم مشخص باشه .

                      خوب به نظرتون باید اینجا چه کار کرد !؟

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

                      خوب پس برای این مورد آخر یعنی اعمال آدرس و تاریخ تولد بر حسب روز ماه و سال کاری که به نظر من میرسه ، میشه از این تکنیک تعریف ساختمان ها به صورت لانه ای استفاده کرد به ترتیب زیر :

                      1. بیاییم اول ساختمان داده آدرس که شامل عناصر : استان ، شهر خیابان ، کوچه و پلاک هست به صورت زیر تعریف کنیم :

                      کد:
                      struct address {
                      char town[20];
                      char city[20];
                      char street[20];
                      char alley[20];
                      int no;
                       
                       };


                      2. بیاییم ساختمان داده تاریخ رو با عناصر روز ، ماه و سال به صورت زیر تعریف کنیم :

                      کد:
                       struct date{
                       
                       int day;
                       int month;
                       int year;
                       
                       };


                      3. حالا بیاییم ساختمان داده اصلی که متغیر مشخصات افراد از اون نوع تعیین میشه به صورت زیر بنویسیم :

                      کد:
                      struct {
                      
                      char first_name[20];
                      char last_name[20];
                      char father_name[20];
                      struct address addr;
                      struct date birth; 
                      }person[1000];


                      حالا بجای اینکه بیاییم جدا جدا ساختمان داده رو تعریف کنیم و بعد بیاییم از اون ساختمان دادهذ برای تعریف یه متغیر جدید داخل یه ساختمان داده دیگه استفاده کنیم اون ساختمان داده و متغیر از اون جنس رو هم داخل همون ساختمان داده اصلی تعریف میکنیم مثلا برای مثال قبل داریم :

                      کد:
                      struct {
                      
                      	char first_name[20];
                      	char last_name[20];
                      	char father_name[20];
                      
                      		struct {
                      			char town[20];
                      			char city[20];
                      			char street[20];
                      			char alley[20];
                      			int no;
                      			}addr;
                      		
                      		struct{ 
                      			int day;
                      			int month;
                      			int year;
                      			}birth; 
                       
                      }person[1000];

                      خوب حالا بیایید مثلا مشخصات همون نفر 20 ام رو دوباره وارد کنیم :

                      کد:
                      person[20].first_name="ali";
                      person[20].last_name="taghipour";
                      person[20].father_name="hasan";
                      person[20].birth.day=31;
                      person[20].birth.month=6;
                      person[20].birth.year=1370;
                      person[20].addr.town="Tehran";
                      person[20].addr.city="Eslamshahr";
                      person[20].addr.street="Emam khomyni";
                      person[20].addr.alley="Shahid kazemi";
                      person[20].addr.no=51;




                      خوب تا همین جا از مبحث Structure برای کار ما تو اینجا کافیه .


                      دوستان ببخشید دیگه کم آوردم ادامه باشه برای پست بعدی!انشالله.

                      پایان قسمت سوم









                      دیدگاه


                        #26
                        پاسخ : آموزش کار با پورت USB میکرو های سری AT90USB

                        4.بررسی مثال VirtualSerial (بخش سوم)

                        خوب تو بخش قبل با structur تا حدودی که نیاز داریم آشنا شدیم فقط موند یه typdef ،


                        در مورد typdef باید گفت زمانی که مثلا ما میخواهیم یه اسم با مصما به یه نوع داده اختصاص بدیم تا بعد از اون دیگه برای تعریف یه متغیر از اون داده دیگه مجبور به استفاده از ترکیبات طولانی و غریب استفاده نکینم مخصوصا زمانی که این نوع داده ما از جنس ساختمان داده باشه که باید اونوقت از struct هم اولش نوشته بشه برای پرهیز از این کار میاییم از typdef در ابتدای تعریف استفاده میکنیم و درانتها بعد از آکولاد بسته اسم جدیدمون رو که میخواهیم متغیر های از این جنس داده جدید رو با اون تعریف کنیم ، مینویسیم و در انتهای اون یه t میزاریم که هر کی اینو دید بدونه که این اسم یه نوع داده هست .

                        خوب حالا بریم سوقت نوع داده جدید لانه ای lufa که در ابتدا پست گزاشتم ،
                        همونطور که میبینید در ابتدا از typdef استفاده کرده و در انتها هم امده اسم داده رو گزاشته :
                        USB_ClassInfo_CDC_Device_t
                        خوب همونطور که اسمش مشخصه ، این نوع داده مربوط میشه به مشخصات دستگاه usb تو کلاس cdc حالا به چه درد میخوره ؟
                        تو تمامی کلاس ها برای انجام هر کاری یکسری تابع نوشته شده مثل پیکره بندی اندپوینت ، دریافت یا ارسال داده و ...
                        این توابع برای اجرا نیاز به اطلاعات دستگاه usb تو اون کلاس کاری معین دارند این اطلاعات از طریق یه متغیر که نوع اش از همین نوع ساختمان داده جدید هست به این توابع پاس میشه .

                        حالا عناصرش چیه ؟
                        کلا دو تا عنصر داره که هر جفتشون هم از یه نوع ساختمان داده جدید هستند به ترتیب زیر :
                        1. Config:
                        این متغیر برای پیکره بندی داده در ارتباط دستگاه usb تو کلاس cdc استفاده میشه و باید قبل از اجرای مراحل سرشماری تمام عناصرش مقدار دهی بشن تا سرشماری به درستی انجام بشه .

                        عناصر Config:
                        1. ControlInterfaceNumber :
                        یه متغیر 8 بیتی هست ، که مشخص کننده شماره واسط هست که مقدار ابتداییش صفر هست . با هرتوصیفگر واسط افزایش مییابد.
                        2.DataINEndpointNumber:
                        شماره اندپوینت ورودی (device-to-host ) رو مشخص میکنه .
                        3.DataINEndpointSize:
                        یه متغیر 16 بیتی هست و تعداد بایت اندپوینت ورودی رو تعیین میکنه و میتونه از 8 تا 256 با پله های 8 تایی مقدار دهی بشه .البته تو میکرو at90usb162 تا 64 بایت میتونه باشه.
                        4. DataINEndpointDoubleBank :
                        یه فلگ هست که اگر یک بشه به این معنی هست که اندیونت ورودی به صورت DoubleBank استفاده میشه و اگر صفر باشه به این معنی هست که اندپوینت ورودی به صورت One bank
                        5. DataOUTEndpointNumber :
                        یک متغیر هشت بیتی هست که مشخص کننده شماره اندپوینت خروجی هست .(تو at90usb162 کلا 5 تا اندپوینت داریم که اندپوینت صفر اندپوینت کنترلی هست و 4 تا ی دیگه یعنی 1 و 2 و 3 و 4 قابل برنامه ریزی در دو جهت ورودی و خروجی هستند)
                        6.DataOUTEndpointSize:
                        یه متغیر 16 بیتی هست و تعداد بایت اندپوینت خروجی رو تعیین میکنه و میتونه از 8 تا 256 با پله های 8 تایی مقدار دهی بشه .البته تو میکرو at90usb162 تا 64 بایت میتونه باشه.
                        7.DataOUTEndpointDoubleBank :
                        یه فلگ هست که اگر یک بشه به این معنی هست که اندیونت خروجی به صورت DoubleBank استفاده میشه و اگر صفر باشه به این معنی هست که اندپوینت خروجی به صورت One bank
                        8.NotificationEndpointNumber:
                        هیچی در موردش نفهمیدم.
                        9.NotificationEndpointSize:
                        هیچی در موردش نفهمیدم.
                        10. NotificationEndpointDoubleBank :
                        هیچی در موردش نفهمیدم.

                        عنصر دوم ، State هم یک متغیر از نوع یه ساختمان داده جدید هست که عناصرش به قرار زیر هستند :
                        اما یه توضیح کلی درمورد State ، این عنصر کاری که میکنه اینکه وضعیت داده ها رو اینکه ورودی هستند یا خروجی رو داخل دستگاه usb تعیین میکنه و بعد از انجام مراحل سرشماری مقایر تمام عناصرش ریست شده و به حالت دیفالتشون برمیگردند .

                        1. ControlLineStates :
                        وضعیت فعلی خط کنترل پورت مجازی سریال رو بین دستگاه و میزبان تعیین میکنه.
                        این متغیر هم خودش از نوع یه داده ساختمانی هست دارای عناصر زیر هست که در هدر CDCClassCommon قرار گرفتند :
                        1- HostToDevice :
                        یک متغیر 16 بیتی هست . که وضعیت خط کنترل رو از میزبان به دستگاه تعییین میکنه.
                        2- DeviceToHost :
                        یک متغیر 16 بیتی هست . که وضعیت خط کنترل رو از دستگاه به میزبان تعییین میکنه.

                        2. LineEncoding
                        اسن هم یه متغیر از نوع ساختمان داده CDC_LineEncoding_t هست که اطلاعات مربوط به ارتباط با پورت سریال رو در خودش نگهداری میکنه . عناصرش به قرار زیر هستند :
                        1-BaudRateBPS :
                        یک متغیر 32 بیتی هست و تعیین کننده نرخ ارسال اطلاعات بر حسب بیت در ثانیه هست .
                        2- CharFormat:
                        یک متغیر 8 بیتی هست و تعیین کننده فرمت ارسال داده به پورت سریال هست که مقادیر زیر رو میتونه بگیره :


                        CDC_LINEENCODING_OneStopBit ;//Each frame contains one stop bit.
                        CDC_LINEENCODING_OneAndAHalfStopBits ;//Each frame contains one and a half stop bits.
                        CDC_LINEENCODING_TwoStopBits ;//Each frame contains two stop bits.



                        3- ParityType :
                        یک متغیر 8 بیتی هست و تعیین کننده فرم بیت پرتی هست که میتونه یکی از مقادیر زیر باشه :

                        CDC_PARITY_None ;//No parity bit mode on each frame.
                        CDC_PARITY_Odd ;//Odd parity bit mode on each frame.
                        CDC_PARITY_Even ;//Even parity bit mode on each frame.
                        CDC_PARITY_Mark ;//Mark parity bit mode on each frame.
                        CDC_PARITY_Space ;//Space parity bit mode on each frame.

                        4- DataBits :
                        یک متغیر 8 بیتی هست و تعیین کننده تعداد بیت داده در هر کارکتر هست .

                        خوب اینهم از عناصر حالا بریم داخل برنامه دوباره ببینیم چطوری این عناصر رو مقدار دهی کرده :

                        کد:
                        USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface =
                        	{
                        		.Config =
                        			{
                        				.ControlInterfaceNumber     = 0,
                        
                        				.DataINEndpointNumber      = CDC_TX_EPNUM,
                        				.DataINEndpointSize       = CDC_TXRX_EPSIZE,
                        				.DataINEndpointDoubleBank    = false,
                        
                        				.DataOUTEndpointNumber     = CDC_RX_EPNUM,
                        				.DataOUTEndpointSize      = CDC_TXRX_EPSIZE,
                        				.DataOUTEndpointDoubleBank   = false,
                        
                        				.NotificationEndpointNumber   = CDC_NOTIFICATION_EPNUM,
                        				.NotificationEndpointSize    = CDC_NOTIFICATION_EPSIZE,
                        				.NotificationEndpointDoubleBank = false,
                        			},
                        	};

                        خوب همونطور که میبینید فقط قسمت CONFIG مقداردهی شده و قسمت STAT همون مقدار دیفالت خودش رو خواهد داشت .
                        قبل از بررسی مقادیر ، یه هدر دیگه هست به نام Descriptors که تو هر پروژه ای باید وجود داشته باشه ، یه نگاهی بهش بندازیم :
                        تو اینجا 5 تا ماکرو داریم به قرار زیر :

                        کد:
                        /* Macros: */
                        		/** Endpoint number of the CDC device-to-host notification IN endpoint. */
                        		#define CDC_NOTIFICATION_EPNUM     2
                        
                        		/** Endpoint number of the CDC device-to-host data IN endpoint. */
                        		#define CDC_TX_EPNUM          3
                        
                        		/** Endpoint number of the CDC host-to-device data OUT endpoint. */
                        		#define CDC_RX_EPNUM          4
                        
                        		/** Size in bytes of the CDC device-to-host notification IN endpoint. */
                        		#define CDC_NOTIFICATION_EPSIZE    8
                        
                        		/** Size in bytes of the CDC data IN and OUT endpoints. */
                        		#define CDC_TXRX_EPSIZE        16

                        خوب این ماکرو ها رو داشته باشید ، برگردیم به ادامه داستان ،
                        خوب چیزی که میشه از اون مقادیر استخراج کرد :

                        1. شماره واسط 0 در نظر گرفته شده.
                        2. شماره اندپوینت ورودی برابر با ماکروی CDC_TX_EPNUM قرار گرفته ، با توجه با اون چیزی که بالا داشتیم مبین اندپوینت شماره 3 هست .
                        3. سایز اندپوینت ورودی برابر با ماکرو CDC_TXRX_EPSIZEقرار گرفته ، با توجه به اون ماکرو های بالا یعنی سایز اندپوینت وردی برابر با 8 بایت .
                        4. نوع بانک اندپوینت برابر با FALSE قرار گرفته یعنی اندپوینت ورودی به صورت ONE BANK هست

                        5. شماره اندپوینت خروجی برابر با ماکروی CDC_RX_EPNUM قرار گرفته ، با توجه با اون چیزی که بالا داشتیم مبین اندپوینت شماره 4 هست
                        6. سایز اندپوینت خروجی برابر با ماکرو CDC_TXRX_EPSIZEقرار گرفته ، با توجه به اون ماکرو های بالا یعنی سایز اندپوینت وردی برابر با 8 بایت .
                        7. نوع بانک اندپوینت خروجی برابر با FALSE قرار گرفته یعنی اندپوینت خروجی به صورت ONE BANK هست

                        خوب حالا بریم ادامه برنامه رو ببنیم چه خبره ،

                        در ادامه یه متغیر به نام USBSerialStream از نوع ساختمان داده FILE به صورت استاتیک تعریف شده .
                        خوب این نوع داده جدید در داخل فایل هدر stdio.h تعریف شده و برای زمانی استفاده میشه که مثلا میخواهیم اطلاعاتمونرو روی یه حافظه جانبی مثل SD MMC یا هرچیز دیگه ای بنویسیم و یا بخونیم و ذخیره کنیم .
                        اما تو اینجا دیگه نیازی به باز کردن بستن و این جور کار ها نیست در واقع این کار به یه فرم دیگه با استفاده از توابع خود LUFA انجام میشه فقط برای اینکه بتونیم از توابع خوندن و نوشتن که در هدر stdio.h آمده استفاده کنیم نیاز به همچین چیزی داریم و البته قبل از اون باید ساختار این فایل هدر رو برای کلا س CDC تعریف کنیم که این کار به واسطه تابع

                        CDC_Device_CreateStream(USB_ClassInfo_CDC_Device_t * const CDCInterfaceInfo,
                        FILE* const Stream)

                        انجام میشه و بعد از اون میتونیم از این فایل برای استفاده در توابع هدر stdio.h استفاده کنیم .
                        توجه کنید که ادلیل انجام اینکار اینکه ساختار ارسال و دریافت داده دیگه مثل ارتباط UART معمول نیست که مثلا 10 بیت تو یه قالب خاص فرستاده بشه لذا چون اینجا داده ها به صورت بسته داده ارسال میشن و یه ساختار کاملا متفاوتی در تمام قسمت های ایتن بسته دارند بناراین ملزم به استفاده از یه ساختمان داده جدید مثل فایل هستیم و بعد با استفاده از توابع هدر stdio.h که برای نوشتن و خوندن از فایل ها در نظر گرفته شدند میتونیم برای ارسال و دریافت استفاده کنیم.

                        خوب در ادامه برنامه وارد تابع اصلی ، MAIN میشیم .
                        تو اینجا اول تابع SetupHardware() اجرا میشه و تو اون تنظیمات سخت افزاری میکرو در ابتدا به صورت زیر انجام میشه :

                        /* Disable watchdog if enabled by bootloader/fuses */
                        MCUSR &= ~(1 << WDRF);
                        wdt_disable();

                        /* Disable clock division */
                        clock_prescale_set(clock_div_1);

                        اول واچ داگ که احتمالا در صورت استفاده از بوت لودر برای پروگرام کردن فعال شده غیر فعال میشه و بعد چون ضریب غفرکانس اوسیلاتور میکرو روی یک تنظیم میشه چون داریم از اوسیلاتور 8 مگا هرتز استفاده میکنیم و بواسطه PLL اون میخواهیم به فرکانس کار USB یعنی 48 مگا هرتز برسیم باید ضریب یک باشه
                        و در ادامه هم تنظیمات سخت افزار بورد مورد انجام میشه :

                        /* Hardware Initialization */
                        Joystick_Init();
                        LEDs_Init();

                        و بعد از اون هم تنظیمات پریفیال usb میکرو با اجرای تابع زیر انجام میشه.

                        USB_Init();

                        خوب بعد از اجرای تابع SetupHardware تابع زیر اجرا میشه و ساختار اصلی فایل برای استفاده از توابع هدر stdio.h فراهم میشه :

                        /* Create a regular character stream for the interface so that it can be used with the stdio.h functions */
                        CDC_Device_CreateStream(&VirtualSerial_CDC_Int erface, &USBSerialStream);

                        بعد از اجرای تابع فوق تابع LEDs_SetAllLEDs اجرا میشه ، این تابع با توجه به اینکه ورودیش چی باشه میاد led های مورد نظر که به عنوان ورودی به تابع پاس میشن رو روشن و بقیه رو خاموش میکنه که تو این جا ماکروی
                        LEDMASK_USB_NOTREADY
                        به عنوان ورودی به تابع پاس میشه و اون هم led شماره یک رو روشن و بقیه رو خاموش میکنه که این به معنی قطع بودن فعلی دستگاه از میزبان هست .
                        بعد از اجرای تابع فوق ماکروی
                        sei();
                        اجرا میشه و وقفه سراسری رو فعال میکنه .

                        خوب فرض کنید که میکرو رو پروگرام کردیم و تغذیه رو هم وصل کردیم اما هنوز کابل usb وصل نشده خوب بعد از اجرای تابع USB_Init(); و اینیشیال شدن پریفیال usb و فعال شدن وقفه سراسری رخداد مربوط به قطع ارتباط دستگاه با میزبان به وقوع می پیونده و روتین اون یعنی روتین زیر در سورس برنامه اجرا میشه :

                        کد:
                        /** Event handler for the library USB Disconnection event. */
                        void EVENT_USB_Device_Disconnect(void)
                        {
                        	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
                        }

                        خوب همونطور که قبلا گفته شد با و همونطور که خودتون ملاحظه میکنید با توجه به ماکروی به کار رفته در تابع LEDs_SetAllLEDs با اجرای این روتین led شماره یک روشن میشهو بقیه led ها هم خاموش میشن.
                        حالا میاییم کابل رو متصل میکنیم بعد از وصل شدن کابل رخداد مربوط به اتصال دستگاه به میزبان بهوقوع می پیونده و روتین زیر اجرا میشه :

                        کد:
                        /** Event handler for the library USB Connection event. */
                        void EVENT_USB_Device_Connect(void)
                        {
                        	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
                        }

                        خوب با اجرای این روتین هم با توجه به ماکروی بکار رفته در آرگومان تابع led های 2 و 3 روشن و بقیه led ها خاموش میشن که بیان گر اجرای مراحل سرشماری هست.
                        و آغاز مرحله سرشماری رو اعلام میکنه که بعد از اجرای درست و بدون مشکل تابع
                        USB_USBTask();
                        سرشماری تموم میشه .
                        حالا بعد از اجرای مرحله سرشماری اگر سرشماری انجام بشه چون منجر به ایجاد یکسری تغیرات در پیکره بندی های usb میشه رخداد تغییر پیکره بندی رخ میده و روتین زیر اجرا میشه :

                        کد:
                        /** Event handler for the library USB Configuration Changed event. */
                        void EVENT_USB_Device_ConfigurationChanged(void)
                        {
                        	bool ConfigSuccess = true;
                        
                        	ConfigSuccess &= CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface);
                        
                        	LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
                        }

                        خوب تو این روتین با اجرای تابع CDC_Device_ConfigureEndpoints که ورودی اش از نوع اشاره گر به ساختمان داده از نوع USB_ClassInfo_CDC_Device_t و پاس شدن اطلاعات مربوط به پیکره بندی اندپوینت های ورودی و خروجی به واسطه این اشاره گر که اینجا اشاره میکنه به آدرس متغیرVirtualSerial_CDC_Interface که از نوع داده ساختمان USB_ClassInfo_CDC_Device_t هست انجام میشه ، حالا اگر پیکره بندی به درستی انجام بشه خروجی این تابع true و اگر پیکره بندی به هر دلیلی مثلا مقدار دهی اشتباه به عناصر متغیر ورودی تابع پیکره بندی ، به درستی اجرا نشه خروجی این تابع false میشه بعد خروجی ین تابع در داخل فلگ
                        ConfigSuccess
                        ریخته میشه و در خط بعد چک میشه که آیا مقدارش true هست یا false اگر مقدار صحیح باشه ماکروی LEDMASK_USB_READY به عنوان ورودی تابع
                        LEDs_SetAllLEDsمعرفی میشه و در این صورت led های 2 و 4 روشن میشن و این به معنی برقرای ارتباط کامل بین دستگاه و میزبان هست .
                        اما برای دریافت و ارسال داده یه تابع دیگه همیشه باید همراه تابع
                        USB_USBTask();
                        اجرا بشه یعنی تابع :
                        CDC_Device_USBTask(&VirtualSerial_CDC_Interfac e);

                        توجه : پس هر کجا که خواستیم از طریق پورت usb ارتباط بین میزبان و ستگاه برقرار بشه باید تضمین کنیم که این دو تابع پشت سر هم حتما تو اون روتین خاص اجرا خواهند شد!
                        تو روال اصلی برنامه قبل از این دو تابع یه تابع دیگه هست یعنی ، تابع
                        CDC_Device_ReceiveByte(&VirtualSerial_CDC_Inte rface);
                        خوب اونطور که من فهمیدم این تابع تعداد بایت های دریافت شده از طرف دستگاه که میزبان براش میفرسته رو برمیگردونه و اگه داده ای از pc ارسال بشه منتظر میمونه تا خونده بشه و به خاطر همین سرعت اجرای روتین رو کلی کاهش میده ، راستش هنوز دقیقا نفهمیدم که چرا استفاده شده و تاثیرش رو اجرای قسمت های دیگه چیه به خاطر همین با دو تا فوروارد اسلش کامنتش کردم تا سرعت اجرای روتین افزایش پیدا کنه تا موقع دریافت داده از pc به دستگاه با تاخیر مواجه نشم و اطلاعات ورودی در لحظه تو روتین مورد نظر مورد پردازش قرار بگیره و مجبور به وارد کردن چند باره یه داده یا کاراکتر برای اطمینان از صحت ارسال اون نشم ، به شما هم پیشنهاد میکنم این کار رو بکنید .
                        خوب یه رخداد دیگه هم هست که قبلا توضیح دادم در موردش و اون هم رخداد EVENT_USB_Device_ControlRequest
                        هست :
                        ین رخداد زمانی که میزبان یه درخواست رو برای اندپوینت کنترلی دستگاه USB ارسال میکنه رخ میده . تو این رخداد باید درخواست ارسالی با استفاده از تابع CDC_Device_ProcessControlRequest بررسی بشه ، ورودی این تابع کلاسی هست که توش کار میکنیم .

                        خوب این از بررسی کلیت کاری که تو سورس اصلی انجام میشه و روتین هایی که باید باشند تا همه چیز درست اجرا بشه ، بررسی توابع برای ارسال و دریافت داده بمونه برای پست بعدی!انشالله.

                        پایان قسمت چهارم

                        دیدگاه


                          #27
                          پاسخ : آموزش کار با پورت USB میکرو های سری AT90USB

                          سلام اخوی
                          داداش داری میری جلو همینطوری. من خیلی سرم شلوغ شده وگرنه تنهات نمیزاشتم :angry:
                          1. من هنوز با lufa کار نکردم به نظر شما از اتمل بهتره؟
                          2. یه تجربه هم کردم گفتم بگم دور همیم. رگولاتور داخلی این آی سی ها خوب کار نمیکنه و اگه دستگاه چند ساعت به کامپیوتر وصل باشه هنگ میکنه و باید کابلش رو بکشی و دوباره بزنی. اگه از رگولاتور خارجی استفاده کنید این مشکل حل میشه. میتونید از یک مقاومت و زنر 3.3 ولت هم استفاده کنید که ارزونتر بشه.
                          بت در بغل و به سجده پیشانی ما کافر زده خنده بر مسلمانی ما
                          اسلام به ذات خود ندارد عیبی هر عیب که هست در این مسلمانی ماست

                          دیدگاه


                            #28
                            پاسخ : آموزش کار با پورت USB میکرو های سری AT90USB

                            5.بررسی مثال VirtualSerial (بخش چهارم)

                            خوب تو این بخش میخواهیم توابع ارسال و دریافت داده رو بررسی کنیم .
                            اول توابع خود LUFA،
                            تو کتابخونه های LUFA برای هر کلاسی یک کتابخونه ارائه شده که میشه برای ارسال و دریافت داده از اون ها استفاده کرد خوب اینجا ما داریم تو کلاس CDC کار میکنبم کتابخونه مربوطه برای این کار CDCClassDevice.h هست توابع اش به قرار زیر هستند :

                            کد:
                            bool CDC_Device_ConfigureEndpoints(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) 
                            
                            void CDC_Device_ProcessControlRequest(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
                            
                            void CDC_Device_USBTask(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
                            
                            void EVENT_CDC_Device_LineEncodingChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo)
                            
                            void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) 
                            
                            void EVENT_CDC_Device_BreakSent(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
                            			                const uint8_t Duration) 
                            uint8_t CDC_Device_SendData(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
                            			              const char* const Buffer,
                            			              const uint16_t Length) 
                            
                            uint8_t CDC_Device_SendString(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
                            			               const char* const String) 
                            
                            uint8_t CDC_Device_SendByte(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
                            			              const uint8_t Data) 
                            
                            uint16_t CDC_Device_BytesReceived(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) 
                            
                            int16_t CDC_Device_ReceiveByte(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) 
                            
                            uint8_t CDC_Device_Flush(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) 
                            
                            void CDC_Device_SendControlLineStateChange(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) 
                            
                            void CDC_Device_CreateStream(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
                            			               FILE* const Stream) 
                            
                            void CDC_Device_CreateBlockingStream(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo,
                            			                   FILE* const Stream)

                            خوب چندتاش رو که مربوط به پیکره بندی و این جور چیزا میشد رو تو اثنای مطالب چند پست قبلی گفتم، یکسریاش رو که اصلا نفهمیدم چین، اما اون هایی که برای دریافت و ارسال هستند رو با هم بررسی میکنیم :

                            توابع ارسال داده :
                            1. CDC_Device_SendByte:
                            این تابع دو ورودی داره و یک خروجی ،
                            ورودی اول : ورودی اولش باید اشاره گر به متغیری از نوع ساختمان داده USB_ClassInfo_CDC_Device_t باشه خوب اگه یادتون باشه اول برنامه یه متغیر از این نوع تعریف و مقدار دهی کردیم از همون به عنوان ورودی استفاده میکنیم و چون ورودی تابع اشاره گر هست قبل از متغیر از علامت & استفاده میکنیم .
                            ورودی دوم : ورودی دومش یک کارکتر هست که میخواهیم برای PC ارسال کنیم ، توجه کنید که این تابع کد اسکی معادل کارکتر ها رو برای PC ارسال میکنه بنابراین درصورت استفاده از اعداد اونچیزی که اونور تو PCدیده میشه اون عدد نیست بلکه کاراکتر معادل اون کد اسکی هست .
                            این تابع یه خروجی داره که از اون برای تشخیص وضعیت اندپوینت بعد از ارسال استفاده میشه و میشه با دونستن اینکه خروجی چیه در ادامه یه تصمیم جدید گرفت و اون رو اجرا کرد ، اما نکته ای که وجود داره خروجی این تابع از نوعuint8_t هست که باید با عناصر یه نوع داده شمارشی برای فهمیدن وضعیت اندپوینت ها بعداز ارسال مقایسه بشه ، اسم نوع داده شمارشی که اینجا استفاده شده Endpoint_WaitUntilReady_ErrorCodes_t هست.
                            خوب بیایید یه نگاهی به تعریف این داده شمارشی بندازیم :

                            کد:
                            enum Endpoint_WaitUntilReady_ErrorCodes_t { 
                             ENDPOINT_READYWAIT_NoError = 0, 
                             ENDPOINT_READYWAIT_EndpointStalled = 1, 
                             ENDPOINT_READYWAIT_DeviceDisconnected = 2, 
                             ENDPOINT_READYWAIT_BusSuspended = 3, 
                             ENDPOINT_READYWAIT_Timeout = 4, 
                             ENDPOINT_READYWAIT_NoError = 0, 
                             ENDPOINT_READYWAIT_EndpointStalled = 1, 
                             ENDPOINT_READYWAIT_DeviceDisconnected = 2, 
                             ENDPOINT_READYWAIT_BusSuspended = 3, 
                             ENDPOINT_READYWAIT_Timeout = 4, 
                             ENDPOINT_READYWAIT_NoError = 0, 
                             ENDPOINT_READYWAIT_EndpointStalled = 1, 
                             ENDPOINT_READYWAIT_DeviceDisconnected = 2, 
                             ENDPOINT_READYWAIT_BusSuspended = 3, 
                             ENDPOINT_READYWAIT_Timeout = 4 
                            }


                            خوب قبل از ادامه ماجرا ،
                            مختصری در رابطه با enum

                            خوب اول اینکه این هم مثل struct برای تعریف یه نوع داده جدید استفاده میشه ، اما چه نوع داده ای اصلا برای چی ؟

                            خوب حتما پیش امده که تو یه برنامه که نوشتید برای اجرای یکسری روتین مجبور به چک کردن مقدار یه متغیر بودید که اگر مثلا اون متغیر برابر با مثلا 5 بود فلان کار انجام بشه اگر برابر با 8 بود فلان کار انجام بشه و قص علی هذا ، نمونه بارز این اتفاق میدونید کجاست ؟ زمانی یه که ما داریم از دستور switch استفاده میکنیم .
                            خوب قطعا منظور ما از این اعداد که حالا مثلا تو ساختار switch جلوی case ها مینویسیم برقراری یه شرط هست که در عالم اعداد برابر با یک مقدار و در عالم معنا برابر با یک لفظ هست (بحث فلسفی شد) حالا ما اگر بتونیم بجای اون اعداد که جلوی case مینوشتیم از یه لفظ استفاده کنیم خیلی خوب میشد نه ؟
                            خوب برای این کار شاید این به نظرتون بیاد که مثلا اول برنامه بیاییم این اعداد رو دیفاین کنیم ، درسته اما آیا راه حل بهتری وجود نداره ؟ تازه یه چیز دیگه ، فرض کنید که ما یه تابع داریم که دوست داریم خروجی اون تابع به جای اعداد یه لفظ باشه ، به عنوان مثال تابعی که برای خوندن یه کیپد نوشته شده رو در نظر بگیرید مسلما خروجی این تابع در وهله اول وقتی داریم مینویسیمش حتما یه عدد خواهد بود که هر عدد بیانگر یه کدوم از دکمه های صفحه کلید هست حالا اگه ما میتونستیم یه کاری کنیم که اون تابع بجای اینکه خروجی اش یه عدد بی معنی باشه دقیقا همون لفظی باشه که روی صفحه کلید ما نوشته شده میشد ،فکرش رو بکنید چقدر تو خوانا تر شدن برنامه به ما کمک میکرد!خوب آیا باز هم میتونیم از دیفاین برای حل همچین مشکلی استفاده کنیم ؟

                            خوب تو زبان c به برنامه نویس این امکان داده شده که بتونه برای مجموعه هایی از اعداد که هر کدومشون تو عالم معنا متناظر با یه لفظ خاص هستند ، بیاد یه متغیر از یه نوع داده جدید استفاده کنه که عناصرش همون اعداد باشن اما اینبار به جای عدد از یه لفظ استفاده بشه و هر وقت که خواست مثلا از فلان عدد استفاده کنه بیاد جای اون ، اون لفظ مورد نظر رو بزاره (خوب نگفتم میدونم) .
                            توجه دلیل اینکه به این نوع داده میگن شمارشی اینه که تمام الفاظ نوشته شده برابر با یک عدد هستند که در مورد نحوه این مقدار دهی در ادامه توضیح میدم .
                            خوب حالا بریم سراغ تعاریف اصلی ، ما برای تعریف یه همچین نوع داده ای که بهش میگیم نوع داده شمارشی از کلمه کلیدی enum درابتدای ساختمان داده جدید مون استفاده میکنیم
                            نحوه تعریف یه ساختمان داده شمارشی به فرم کلی زیر هست :

                            enum "اسم نوع داده شمارشی"{

                            عنصر اول ,
                            عنصر دوم,
                            عنصر سوم ,
                            .
                            .
                            .
                            };

                            توجه کنید که عناصر بوسیله کاما از هم جدا میشن.
                            خوب این از تعریف نوع داده اما ما که صرفا نمیخواییم یه نوع داده جدید درست کنیم ، ما نیاز به یه متغیر داریم با یه فرم ساختمان داده جدید اون هم از نوع داده شمارشی ، خوب برای تعریف متغیر هامون به دوصورت میشه عمل کرد :
                            1. اول نوع داده شمارشی مون رو تعریف کنیم بعد بیایم به صورت زیر متغیر هامون رو هم تعریف کنیم :

                            enum "اسم نوع داده شمارشی" "اسم متغیر"

                            2. تو این روش میتونیم پشت بند اینکه نوع داده شمارشی رو تعریف کردیم بعد از آکولاد آخر اسم متغیر هامون رو وارد کنیم و اگر نخواهییم متغیری از این نوع داده در جای دیگه ای از برنامه تعریف کنیم میتونیم اسمش رو هم حذف کنیم .به صورت زیر :

                            enum "اسم نوع داده شمارشی"{

                            عنصر اول ,
                            عنصر دوم,
                            عنصر سوم ,
                            .
                            .
                            .
                            }"اسم متغیر";

                            خوب فقط یه موضوعی در مورد مقدار عناصر شمارشی بگم ، خوب اگه ما به هیچ کدوم از عناصر مقدار دهی نکیم از اول ، اولین عنصر مقدار صفر ، دومین عنصر مقدار یک وnامین عنصر هم مقدار n-1 رو میگیرن.اما اگر ما بیاییم به عناصر مثلا یدفعه عنصر 5 رو حالا بهر دلیلی که داریم مثلا مقدار 10 رو بدیم ، مقدار عناصر قبل از 5 از صفر تا 4 مقداردهی عادیشون صوت میگره اما ازخود عنصر 5 به بعد و از 10 تا هر چقدر که نیاز باشه مقدار دهی میشن .

                            حالا برگردیم به lufa ما اینجا یه تابع داریم که خروجیش از نوع uint8_t هست پس باید اول یه متغیر از این نوع رو اول برنامه تعریف کنیم مثلا :

                            uint8_t send_out;

                            حالا هر کجا خواستیم وضعیت خروجی این تابع رو چک کنیم از ساختار if به شکل زیر استفاده میکنیم :

                            f(send_out==ENDPOINT_READYWAIT_NoError )
                            CDC_Device_SendByte (&VirtualSerial_CDC_Interface,"ENDPOINT_R EADYWAIT_NoError"

                            خوب این از تابع اول برای ارسال داده .

                            2. دومین تابع ،CDC_Device_SendString :
                            این تابع برای ارسال رشته های کارکتری استفاده میشه ،دو تا ورودی داره و یک خروجی .
                            ورودی اول که مثل تابع قبل هست .
                            ورودی دوم هم رشته کاراکتری هست که میخواهیم برای pc ارسال کنیم مثلا همین موردی که تو کد بالا هست میتونید نحوه استفاده از این تابع رو ببینید .
                            خروجی این تابع از نوع uint8_t و باید با عناصر داده شمارشی Endpoint_Stream_RW_ErrorCodes_t مقلیسه بشه ، عناصر این داده شمارشی به قرار زیر هستند :

                            کد:
                            Enum for the possible error return codes of the Endpoint_*_Stream_* functions. 
                            Enumerator: 
                            
                            
                            ENDPOINT_RWSTREAM_NoError 
                            
                             
                            Command completed successfully, no error. 
                            
                            
                            
                            ENDPOINT_RWSTREAM_EndpointStalled 
                            
                             
                            The endpoint was stalled during the stream transfer by the host or device. 
                            
                            
                            
                            ENDPOINT_RWSTREAM_DeviceDisconnected 
                            
                             
                            Device was disconnected from the host during the transfer. 
                            
                            
                            
                            ENDPOINT_RWSTREAM_BusSuspended 
                            
                             
                            The USB bus has been suspended by the host and no USB endpoint traffic can occur until the bus has resumed. 
                            
                            
                            
                            ENDPOINT_RWSTREAM_Timeout 
                            
                             
                            The host failed to accept or send the next packet within the software timeout period set by the USB_STREAM_TIMEOUT_MS macro. 
                            
                            
                            
                            ENDPOINT_RWSTREAM_IncompleteTransfer 
                            
                             
                            Indicates that the endpoint bank became full or empty before the complete contents of the current stream could be transferred. The endpoint stream function should be called again to process the next chunk of data in the transfer.


                            3.تابع سوم ، CDC_Device_SendData:
                            این تابع برای ارسال یک بافر داده مثل رشته کاراکتر با طول مشخص استفاده میشه .
                            این تابع سه تا ورودی داره و یک خروجی
                            ورودی اول ، مثل دو تابع قبلی هست، ورودی دوم بافر داده هست که باید از نوع char باشه و ورودی سوم هم طول داده ای هست که میخواهیم به pc ارسال بشه .مثلا فرض کنید میخواییم دو تا کارکتر اول رشته "mojtaba"رو ارسال کنیم برای این منظور مینویسیم :

                            CDC_Device_SendData (&VirtualSerial_CDC_Interface,"mojtaba&qu ot;,2 );

                            این تابع یک خروجی هم داره که از نوع uint8_t هست و باید با عناصر داده شمارشی که در موردشون تو تابع دوم توضیح داده شد مقایسه بشن.

                            توابع دریافت داده :
                            کلا یک تابع برای دریافت داده داریم :
                            1.CDC_Device_ReceiveByte :
                            این تابع برای دریافت داده ها به صورت کارکتر استفاده میشه یک ورودی داره و یک خروجی ،
                            ورودی این تابع مثل ورودی اول توابع ارسال هست .
                            خروجی این تابع هم در واقع همون کاراکتری هست که از طرف pcبرای دستگاه ارسال میشه .
                            البته اگر داده ای از طرف pc برای دستگاه ارسال نشه خروجی این تابع یک مقدار منفی خواهد بود
                            به عنوان مثال فرض کنید که میخواهیم کارکتری رو از pcدریافت و دوباره اون رو برای pc ارسال کنیم تا تو هایپر ترمینال به نمایش دربیاد میتونید از روتین زیر برای این کار استفاده کنید :

                            کد:
                            	   for (;;)
                                {
                                    while (CDC_Device_BytesReceived(&VirtualSerial_CDC_Interface))
                                     CDC_Device_SendByte(&VirtualSerial_CDC_Interface,
                            				
                            				CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface));
                            
                                    CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
                                    USB_USBTask();
                                }


                            خوب فقط یه مطلبی رو بگم ، تمامی این توابع که برای دریافت و ارسال داده استفاده میشن ، زمانی میتونن استفاده بشن که تمام مراحل سرشماری انجام شده باشه و دستگاه آماده دریافت و ارسال داده باشه این موضوع رو میشه به کمک عناصر داده شمارشی USB_Device_States_t و مشخصا برای این کاری که ما میخواییم بکنیم یعنی چک کردن آماده بودن دستگاه، از عنصر DEVICE_STATE_Configured برای چک کردن این مسئله استفاده میکنیم ، خوب همیشه وضعیت دستگاه تو متغیری به اسم USB_DeviceState ذخیره میشه و میشه با مقایسه اون با عناصر داده شماری فوق الذکر از موقعیت فعلی دستگاه مطلع شد ، مثلا برای موردی که اینجا ذکر شد میتونیم روتین قبل رو به صورت زیر باز نویسی کنیم :


                            کد:
                            for (;;){
                            		
                            		if(USB_DeviceState==DEVICE_STATE_Configured){
                            		
                                    while (CDC_Device_BytesReceived(&VirtualSerial_CDC_Interface))
                                     CDC_Device_SendByte(&VirtualSerial_CDC_Interface,
                            				
                            				 CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface));
                            				 
                            													}
                            
                                    CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
                                    USB_USBTask();
                                }


                            دوستان توابع هدر stdio بمونه برای پست بعدی !انشالله.

                            پایان قسمت پنجم .


                            سلام اخوی
                            داداش داری میری جلو همینطوری. من خیلی سرم شلوغ شده وگرنه تنهات نمیزاشتم
                            hello بر برادر مصطفی .
                            من هنوز با lufa کار نکردم به نظر شما از اتمل بهتره؟
                            آقا شک نکن .صد در صد ، هیچی جای lufa رو نمیگیره شما الان یه سرچ بکن ببین چقدر مطلب میاد بالا در موردش ، مسله بعدی اینه که این آقا camera الان جزو مهندسای اتمل هست و از این بابت میشه گفت که اتمل پشت lufa هست در ضمن این lufa برای کار تو بیشتر کلاس ها چه دیوایس چه هاست کتابخونه داره و تمامی میکرو های avr اعم از mega ، xmega, avr32 رو ساپورت میکنه کما اینکه من تو چند جا دیدم که برای راه اندازی پورت usb تو میکرو های arm شرکت nxp هم از این کتابخونه استفاده کرده بودند .

                            2. یه تجربه هم کردم گفتم بگم دور همیم. رگولاتور داخلی این آی سی ها خوب کار نمیکنه و اگه دستگاه چند ساعت به کامپیوتر وصل باشه هنگ میکنه و باید کابلش رو بکشی و دوباره بزنی. اگه از رگولاتور خارجی استفاده کنید این مشکل حل میشه. میتونید از یک مقاومت و زنر 3.3 ولت هم استفاده کنید که ارزونتر بشه.
                            ممنون از تذکرتون.
                            راستش من هنوز به همچین مشکلی برخورد نکردم اما اگه از دوستان کسی خواست چنین کاری بکنه باید تو تنظیمات میکرو این مورد رو لحاظ کنید، برای این منظور باید تو میک فایل که در حالت عادی به صورت زیر هست :

                            کد:
                            # LUFA library compile-time options and predefined tokens
                            LUFA_OPTS = -D USB_DEVICE_ONLY
                            LUFA_OPTS += -D FIXED_CONTROL_ENDPOINT_SIZE=8
                            LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1
                            LUFA_OPTS += -D USE_FLASH_DESCRIPTORS
                            LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)"


                            باید با استفاده از ماکروی USB_OPT_REG_DISABLED به جای ماکروی USB_OPT_REG_ENABLED رگولاتور داخلی رو غیر فعال کنید و پیکره بندی رو به صورتی که در دیتا شیت گفته برای 3.3 ولت انجام بدید.


                            دیدگاه


                              #29
                              پاسخ : آموزش کار با پورت USB میکرو های سری AT90USB

                              6. چت بین USART و USB

                              با سلام


                              دوستان تو این قسمت برای جذاب تر شدن بحث یه مثال می خوام بزارم ، تو این مثال همونطور که از عنوانش مشخصه بین پورت USB و UART میکرو ارتباط برقرار میکنیم و از طریق دو تا هایپر ترمینال ، یکی برای پورت USB و یکی برای UART ، از USB به UART و از UART به USB چت میکنیم .

                              خوب این برنامه رو تو غایل main.c دموی VirtualSerial کپی ،پیست کنید و اون رو کامپایل کنید و بعد میکرو تون رو باهاش پروگرام کنید .
                              برنامه :

                              کد:
                              /*
                                     LUFA Library
                                 Copyright (C) Dean Camera, 2012.
                              
                               dean [at] fourwalledcubicle [dot] com
                                    www.lufa-lib.org
                              */
                              
                              /*
                               Copyright 2012 Dean Camera (dean [at] fourwalledcubicle [dot] com)
                              
                               Permission to use, copy, modify, distribute, and sell this
                               software and its documentation for any purpose is hereby granted
                               without fee, provided that the above copyright notice appear in
                               all copies and that both that the copyright notice and this
                               permission notice and warranty disclaimer appear in supporting
                               documentation, and that the name of the author not be used in
                               advertising or publicity pertaining to distribution of the
                               software without specific, written prior permission.
                              
                               The author disclaim all warranties with regard to this
                               software, including all implied warranties of merchantability
                               and fitness. In no event shall the author be liable for any
                               special, indirect or consequential damages or any damages
                               whatsoever resulting from loss of use, data or profits, whether
                               in an action of contract, negligence or other tortious action,
                               arising out of or in connection with the use or performance of
                               this software.
                              */
                              
                              /** \file
                               *
                               * Main source file for the VirtualSerial demo. This file contains the main tasks of
                               * the demo and is responsible for the initial application hardware configuration.
                               */
                              
                              #include "VirtualSerial.h"
                              
                              //**FUNCTION PROTOTYPE:
                              void serial_to_usb(void);
                              void usb_to_serial(void);
                              void Serial_SendString_mojtaba(const char* StringPtr);
                              
                              
                              /** LUFA CDC Class driver interface configuration and state information. This structure is
                               * passed to all CDC Class driver functions, so that multiple instances of the same class
                               * within a device can be differentiated from one another.
                               */
                              USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface =
                              	{
                              		.Config =
                              			{
                              				.ControlInterfaceNumber     = 0,
                              
                              				.DataINEndpointNumber      = CDC_TX_EPNUM,
                              				.DataINEndpointSize       = CDC_TXRX_EPSIZE,
                              				.DataINEndpointDoubleBank    = false,
                              
                              				.DataOUTEndpointNumber     = CDC_RX_EPNUM,
                              				.DataOUTEndpointSize      = CDC_TXRX_EPSIZE,
                              				.DataOUTEndpointDoubleBank   = false,
                              
                              				.NotificationEndpointNumber   = CDC_NOTIFICATION_EPNUM,
                              				.NotificationEndpointSize    = CDC_NOTIFICATION_EPSIZE,
                              				.NotificationEndpointDoubleBank = false,
                              			},
                              	};
                              
                              /** Standard file stream for the CDC interface when set up, so that the virtual CDC COM port can be
                               * used like any regular character stream in the C APIs
                               */
                              static FILE USBSerialStream;
                              
                              
                              /** Main program entry point. This routine contains the overall program flow, including initial
                               * setup of all components and the main program loop.
                               */
                              int main(void)
                              {	
                              	
                              
                              
                              			
                              	SetupHardware();
                              
                              	/* Create a regular character stream for the interface so that it can be used with the stdio.h functions */
                              	CDC_Device_CreateStream(&VirtualSerial_CDC_Interface, &USBSerialStream);
                              
                              	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
                              	sei();
                              	
                              	for (;;)
                              	{
                              		
                              		
                              	
                              		CheckJoystickMovement();
                              		
                              		serial_to_usb();
                              		usb_to_serial();
                              		
                              		
                              		/* Must throw away unused bytes from the host, or it will lock up while waiting for the device */
                              		//CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface);
                              
                              		CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
                              		USB_USBTask();
                              		
                              	}
                              }
                              
                              /** Configures the board hardware and chip peripherals for the demo's functionality. */
                              void SetupHardware(void)
                              {
                              	/* Disable watchdog if enabled by bootloader/fuses */
                              	MCUSR &= ~(1 << WDRF);
                              	wdt_disable();
                              
                              	/* Disable clock division */
                              	clock_prescale_set(clock_div_1);
                              
                              	/* Hardware Initialization */
                              	Joystick_Init();
                              	LEDs_Init();
                              	USB_Init();
                              	Serial_Init(9600UL, false);
                              
                              //USB_Init(USB_CurrentMode,USB_OPT_REG_DISABLED);
                              }
                              
                              /** Checks for changes in the position of the board joystick, sending strings to the host upon each change. */
                              void CheckJoystickMovement(void)
                              {
                              	uint8_t   JoyStatus_LCL = Joystick_GetStatus();
                              	int16_t   temp;
                              	char*    ReportString = NULL;
                              	static bool ActionSent  = false;
                              
                              	if (JoyStatus_LCL & JOY_UP)
                              	 ReportString = "Joystick Up\r\n";
                              	else if (JoyStatus_LCL & JOY_DOWN)
                              	 ReportString = "Joystick Down\r\n";
                              	else if (JoyStatus_LCL & JOY_LEFT)
                              	 ReportString = "Joystick Left\r\n";
                              	else if (JoyStatus_LCL & JOY_RIGHT)
                              	 ReportString = "Joystick Right\r\n";
                              	else if (JoyStatus_LCL & JOY_PRESS)
                              	 ReportString = "Joystick Pressed\r\n";
                              	else
                              	 ActionSent = false;
                              
                              	if ((ReportString != NULL) && (ActionSent == false))
                              	{
                              		ActionSent = true;
                              
                              		/* Write the string to the virtual COM port via the created character stream */
                              		fputs(ReportString, &USBSerialStream);
                              	
                              		
                              	
                              		/* Alternatively, without the stream: */
                              		// CDC_Device_SendString(&VirtualSerial_CDC_Interface, ReportString);
                              	}
                              }
                              
                              /** Event handler for the library USB Connection event. */
                              void EVENT_USB_Device_Connect(void)
                              {
                              	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
                              }
                              
                              /** Event handler for the library USB Disconnection event. */
                              void EVENT_USB_Device_Disconnect(void)
                              {
                              	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
                              	DDRB=_BV(7);
                              	PORTB^=_BV(7);
                              }
                              
                              /** Event handler for the library USB Configuration Changed event. */
                              void EVENT_USB_Device_ConfigurationChanged(void)
                              {
                              	bool ConfigSuccess = true;
                              
                              	ConfigSuccess &= CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface);
                              
                              	LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
                              }
                              
                              /** Event handler for the library USB Control Request reception event. */
                              void EVENT_USB_Device_ControlRequest(void)
                              {
                              	CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface);
                              }
                              
                              
                              //serial_to_usab
                              void serial_to_usb(void){
                              uint8_t DataByte;
                              static int i=0;
                              
                              	DataByte = Serial_ReceiveByte ();
                               
                              		
                              	if((DataByte!=255)&&(DataByte!=10)&&(DataByte!=13))Serial_SendByte(DataByte),putc(DataByte,&USBSerialStream);
                              	if((DataByte==10)||(DataByte==13))Serial_SendString_mojtaba("\n\r"),fputs("\n\r", &USBSerialStream);
                              
                              						}//serial_to_usab
                              	 
                              //usb_to_serial
                              void usb_to_serial(void){
                              uint8_t DataByte;
                              
                              	DataByte = getc(&USBSerialStream);
                              	
                              	if((DataByte!=255)&&(DataByte!=10)&&(DataByte!=13))Serial_SendByte(DataByte),putc(DataByte,&USBSerialStream);
                              	if((DataByte==10)||(DataByte==13))Serial_SendString_mojtaba("\n\r"),fputs("\n\r", &USBSerialStream);
                              
                              						}//usb_to_serial
                              
                              
                              	//Serial_SendString_mojtaba 
                              	void Serial_SendString_mojtaba(const char* StringPtr){
                              		uint8_t CurrByte;
                              
                              			while ((CurrByte = *StringPtr) != 0x00)
                              				{
                              					Serial_SendByte(CurrByte);
                              					StringPtr++;
                              				}
                              	
                              	}//Serial_SendString_mojtaba

                              بعد از ران شدن میکرو و شناسایی اون توسط ویندوز دوتا هایپر ترمینال باز کنید یکی برای پورت کام 1 که مربوط به usart میشه و یکی هم برای پورت usb ، بعد روی دکمه برقراری ارتباط کلیک کنید تا اینترفیس هامون پورت ها رو باز کنند .

                              حالا هر چی تو محیط هایپر ترمینال uart بنویسید همزمان توی هایپر ترمینال usb هم به نمایش در میاد و بالعکس .

                              مثلا :


                              سخت افزار مورد نیاز هم به غیر از میکرو و مدار راه اندازش ، یه آی سی MAX232 و چهار تا خازن بالای 1 میکرو (الکترولیتی)50 ولت که دیگه همه باهاش آشنایی دارند و کانکتور D9 به تعداد لازم .

                              راستی تو این پروژه از کتابخونه Serial.h استفاده شده که باید به صورت زیر هدرش تو فایل هدر VirtualSerial.h اینکلود بشه :

                              کد:
                              #include <LUFA/Drivers/Peripheral/Serial.h>



                              پایان قسمت ششم

                              دیدگاه


                                #30
                                پاسخ : آموزش کار با پورت USB میکرو های سری AT90USB

                                7. پروگرامر MKII

                                خوب من گفتم برای اینکه یکم دوستان بیشتر ترغیب بشن ، روی پروژه MKII مجموعه LUFA کار کنیم و یه پروگرامر MKII با همین AT90USB162 بسازیم و کلی حالشو ببریم !


                                خوب دوستان پیرو تاپیک "ساخت پروگرامر MKII " و توضیحات موجود در اونجا و آشنایی قبلی با LUFA ، تصمیم گرفتم که ساخت پروگرامر MKII رو تو این پست با استفاده از میکرو AT90USB162 توضیح بدم .
                                توجه : توضیحات این تاپیک فقط در مورد پروگرام کردن میکرو های 5 ولتی و سری مگا و تاینی و AT90S هست .

                                خوب بترتیب کارهایی که باید بکنیم :

                                سخت افزار :

                                1. یه بورد برای میکروی AT90USB162 بزنید که توش کانکتور USB و یه کانکتور IDC برای رابط ISP باشه ، همینطور یه پوش باتون برای ریست و یه پوش باتون برای HWB (برای اجرای بوت لودر) میتونید از شماتیک هدر بورد TATLY AVR استفاده کنید (اگه درخواستی مبنی بر طراحی PCB داشتیم ، یه PCB هم خودم براش طراحی میکنم).

                                نرم افزار :

                                1. خوب فلیپ رو که دیگه دارید ؟! اگه ندارید دانلود کنید ، بوت لودر DFU رو هم دانلود کنید ، بعد با یه پروگرامر دیگه AT90USB162 رو باهاش پروگرام کنید .

                                2. حالا بریم سراغ پروژه MKII ، این پروژه تو مسیر : LUFA-120219\Projects\AVRISP-MKII

                                قرار داره ، فایل سورس AVRISP-MKII و میک فایل رو باز کنید ،

                                خوب در حالت دیفالت ، این برنامه برای بورد USBTINYMKII نوشته شده اما چون ما اطلاعی از شماتیک این بورد نداریم پس از یه بورد دیگه که شماتیکش (اتصالاتش) میدونیم چیه استفاده میکنم ، خوب من از بورد USBKEY بشکلی که تو چند پست قبل گفتم برای میکرو خودم (AT90USB162) اصلاحش کردم استفاده میکنم و چون دارم از یه کریستال 8 مگ خارجی استفاده میکنم ، فرکانس اوسیلاتور رو هم 8 مگ میزارم ؛ برای این منظور توی میک فایل تغییرات زیر رو اعمال میکنم :


                                کد:
                                #BOARD = USBTINYMKII
                                BOARD = USBKEY
                                
                                #F_CPU = 16000000
                                F_CPU = 8000000


                                3. حالا برنامه رو کامپایل میکنید.

                                4. بعد از طریق FLIP یا اگه دوست نداشتید با FLIP کار نکنید از طریق همون رابط ISP فایل هگز رو تو میکرو پروگرام میکنید.

                                5. حالا اگه با FLIP پروگرام کردید ، بعد از اتمام پروگرام ، روی دکمه استارت کلیک کنید تا برنامه از آدرس بردار ریست اجرا بشه . اگر هم از طریق ISP پروگرام کردید ، کابل USB رو به PC متصل کنید .

                                6. برای برقراری ارتباط با پروگرامر MKII نیاز به درایور داریم ، برای این منظور کافی AVRStudio رو نصب کنید ، به این ترتیب به محض اتصال کابل usb یا کلیک بر روی دکمه استارت ، pc بعد از چند لحظه با این پیغام که در زیر میبینید به شما میگه که پروگرامر MKII رو شناخته و درایورشو نصب کرده و آماده استفاده است .

                                PIC1


                                PIC2


                                PIC3


                                7. حالا AVRStudio رو باز کنید (من با ورژن 4.19 کار میکنم (ورژن 5 اش باگ داره احتمال داره که با مشکلای عجیب غریب مواجه بشید ، اگه ورژن کامل 6 امد رو اون هم توضیح میدم))

                                حالا به شکل زیر به پروگرامر متصل بشید :

                                PIC4


                                PIC5


                                بعد از کلیک بر روی کانکت پنجره مربوط به پروگرامر باز میشه به این شکل :
                                PIC6


                                از اینجا به بعد هم که دیگه واضحه.

                                برای اطمینان بیشتر از عملکرد این پروگرامر ، من برنامه زیر رو که برای مگا هشت نوشته بودم ، (یه مولد موج مربعی با فرکانس 1 هرتز هست ) رو از این طریق پروگرام کردم و همه چیز ok بود و بدون مشکل هم کار میکنه ، این برنامه اش ( البته با کامپایلر IAR ) :


                                کد:
                                #include <ioavr.h>
                                #include <intrinsics.h>
                                __C_task void main( void )
                                {
                                 DDRC=(1<<DDC5);
                                 TCCR1B=(1<<CS11);  
                                 TIMSK=(1<<TOIE1);
                                __enable_interrupt();  
                                  while(1);
                                  }
                                 #pragma vector= TIMER1_OVF_vect 
                                __interrupt void TIMER1_OVF(void)
                                   {
                                    /*FOR BASE TIME : 5000us*/
                                   static unsigned char i=0;
                                   TCNT1=0xec78;
                                   if(++i==100)PORTC^=(1<<5),i=0;
                                     }


                                اینم از یه پروگرامر فوق العاده و ازون قیمت ، 5 هزار تومن پول میکرو ش هست کانکتور ها و بقیه مخلفاتش هم روی هم میشه هزار تومن ، یه بورد یه رو هم که براش خودتون طراحی کنید و بزنید ، میگیریم 4 هزار تومن، یعنی با 10 هزار تومن صاحب یه پروگرامر MKII میشید! (البته فقط برای میکروهای 5 ولتی و میکروهایی که با ISP پروگرام میشین) .


                                پایان قسمت هفتم

                                دیدگاه

                                لطفا صبر کنید...
                                X