<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های Arman Barkhordar</title>
        <link>https://virgool.io/feed/@itsarman</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-06-17 08:06:27</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/489329/avatar/5X8wx0.jpeg?height=120&amp;width=120</url>
            <title>Arman Barkhordar</title>
            <link>https://virgool.io/@itsarman</link>
        </image>

                    <item>
                <title>سریال USART در AVR</title>
                <link>https://virgool.io/@itsarman/%D8%B3%D8%B1%DB%8C%D8%A7%D9%84-usart-%D8%AF%D8%B1-avr-jgyt8snzbxoj</link>
                <description>در تمام میکروکنترلرها مثل AVR و PIC و یا میکروهای سطح بالا نظیر ARM، همواره برای تبادل اطلاعات میان میکروکنترلرها و یا برقراری ارتباط با بردهای الکترونیکی مثل سنسورهایی که با سریال اطلاعات را رد و بدل می‌کنند، پورت‌ها یا رابط‌هایی مثل USART وجود دارد که این امر را میسر می‌سازد.  USART  نوعی از یک ارتباط سریال است و وقتی اسمی از ارتباط سریال برده می‌شود، تنها USART مد نظر نیست. چون به غیر از USART ارتباطات سریال دیگری مثل SPI و I2C هم وجود دارد.رابط سریال USARTارتباط سریال به نوعی از ارتباط گفته می‌شود که بیت به بیت اطلاعات به صورت سری از یک رشته سیم منتقل می‌شود تمام  این بیت‌ها بصورت پشت سرهم و با فاصله زمانی مشخص است.همانطور که گفتیم USART نوعی ارتباط سریال است که اول حروف Universal Synchronous Asynchronous Receiver Transmitter بوده و به معنای فرستنده گیرنده سنکرون و آسنکرون جهانی است. در میکروکنترلرهای AVR سه پایه برای سریال USART تعبیه شده که این سه پایه مطابق شکل زیر عبارت‌اند از: TXD ،RXD و XCK.TXD: پایه Transmit یا ارسال داده است و باید به پایه RXD دستگاه مقابل متصل شود. RXD: پایه Receive یا دریافت داده است و باید به پایه TXD دستگاه مقابل متصل شود. XCK: این پایه مربوط به زمانی است که ارتباط سریال ما سنکرون یا همزمان باشد. در این صورت این پایه به پایه XCK میکروکنترلری که میخواهیم با آن ارتباط برقرار کنیم متصل می‌شود.· پایه XCK جز استاندارد (RS232) استاندارد جهانی ارتباط سریال UART نبوده و تنها درمیکروکنترلر AVRوجود دارد.· منظور از “دستگاه مقابل” یک میکروکنترلر، کامپیوتر، سنسور و یا هرچیزی است که دارای ارتباط USART می‌باشد.شرح عملکرد  USARTبرای تبادل ارتباط میان دستگاه‌ها باید RXD ها به TXD ها متصل شوند.  با توجه به شکل زیر پایه TXD مربوط به Device 1 به پایه RXD مربوط به Device 2 متصل است. باید گفت که در شکل زیر فقط می‌توان اطلاعات را از Device 1 به Device 2 انتقال داد و برای اینکه ارتباط دو طرفه شود باید TXD دستگاه 2 را به RXD دستگاه 1 متصل کنیم. اما برای شرح عملکرد سریال، فعلا ما ارتباط را بصورت یک طرفه در نظر می‌گیریم.اگر Device 1 بخواهد اطلاعاتی را به Device 2 بفرستد، این اطلاعات در قالب frame ارسال می‌شود که ساختار آن بصورت زیر است.هر فریم از 4 قسمت اصلی تشکیل شده است:1. بیت Start (St) که همواره 0 منطقی است و در اول شروع فریم می‌آید.2. بیت‌های داده که حامل داده اصلی هستند و بین 5 تا 9 بیت می‌توانند باشند. اینکه تعداد بیت‌های داده چقدر باشد، توسط ما مشخص می‌شود.3. بیت Parity (P) که به آن بیت توازن هم گفته می‌شود. این بیت می‌تواند وجود داشته باشد یا اینکه اصلا مورد استفاده قرار نگیرد.4. بیت Stop (Sp) که همیشه 1 منطقی است و حداقل 1 بیت و حداکثر 2 بیت می‌تواند باشد که این مورد هم توسط ما مشخص می‌شود. بیت Sp بر خلاف بیت St در آخر هر فریم می‌آید.· بیت Start، بیت Parity (درصورت فعال سازی) و بیت Stop بصورت اتوماتیک و سخت افزاری به داده‌ چسبانده می‌شوند و ما تنها باید داده‌هایی را که میخواهیم بفرستیم مشخص کنیم.· در حالت عادی (IDLE) اگر اطلاعاتی رد و بدل نشود، وضعیت خط انتقال در حالت 1 منطقی قرار دارد. به همین خاطر است که بیت استارت بصورت همیشه 0 ظاهر می‌شود تا آغاز یک فریم را مشخص کند.· سرعت انتقال داده یکی از فاکتورهای اصلی ارتباط USART است و به آن نرخ ارسال گویند و واحد آن بیت بر ثانیه (bps) می‌باشد. مثلا نرخ ارسال 9600 یعنی تعداد 9600 بیت می‌تواند در 1 ثانیه ارسال شود.بیت توازندلیل وجود این بیت، تشخیص خطا در فریم است. بیت توازن دو نوع است:1. توازن زوج (Even Parity) که تعداد 1 موجود در داده و بیت توازن باید زوج شوند.2. توازن فرد (Odd Parity) که تعداد 1 موجود در داده و بیت توازن باید فرد شوند.مقدار بیت توازن بستگی به داده‌ای که میخواهیم منتقل کنیم دارد. فرض کنید نوع توازن را زوج انتخاب کرده‌ایم و داده‌ای که می‌خواهیم ارسال شود 8 بیتی بوده و بصورت 11001001 باشد. با توجه به این داده، تعداد 1 ها 4 می‌باشد. پس چون 4 عددی زوج است، بیت توازن 0 منطقی می‌شود.مزیت بودن بیت توازنتوازن زوج و داده ارسالی 01101110  را در نظر بگیرید. چون تعداد 1 برابر 6 می‌شود و زوج است، در طرف گیرنده هم باید همین تعداد 1 شناسایی شود. اگر در طول مسیر یکی از بیت‌های ارسالی تغییر وضعیت دهد، تعداد 1 ها فرد شده و گیرنده از این طریق متوجه رخ دادن خطا در داده می‌شود. خطای مربوط به بیت توازن با PE نشان داده می‌شود.· نوع توازن بیت Parity، در هر دو طرف فرستنده و گیرنده، باید هر دو فرد و یا هر دو زوج باشد.رجیسترهای USART در AVRبرای دسترسی به ارتباط سریال USART در تمامی میکروکنترلرهای AVR رجیسترهایی تعبیه شده‌اند که تمامی موارد فوق را پیاده‌سازی می‌کنند. مواردی مثل توازن فرد یا زوج، تعداد بیت‌های داده و نرخ ارسال همگی از طریق این رجیسترها تنظیم می‌شوند. 7 رجیستر برای ارتباط USART وجود دارد که عبارت اند از : UCSRB ،UCSRA ،UBRRH ،UBRRL و UCSRC و 2 رجیستر با اسم یکسان UDR.رجیسترهای UBRRL و UBRRH برای تنظیم نرخ ارسال داده و رجیسترهای UCSRA تا UCSRC وظیفه کنترل و تنظیم نوع عملکرد رابط سریال را بر عهده دارند. همچنین دو رجیستر که نام هر دوی آنها UDR است، یکی برای ارسال داده و دیگری برای دریافت داده خواهد بود.رجیسترهای UBRRL و (Usart Baud Rate Register) UBRRHاین دو رجیستر برای تنظیم نرخ ارسال هستند که مقدار کم ارزش آن UBRRL و مقدار با ارزش آن UBRRH است.مقدار UBRR از 12 بیت تشکیل شده که 8 بیت کم ارزش آن در UBRRL و 4 بیت با ارزش آن در UBRRH قرار دارد. نرخ ارسال با توجه به یکی از سه فرمول زیر محاسبه می‌شود.فرمول اولدر اول توضیحات این مطلب گفتیم که USART در دو مد سنکرون و آسنکرون می‌تواند عمل کند. اگر USART در مد آسنکرون باشد و بیت U2X در رجیستر UCSRA برابر 0 باشد، از فرمول زیر برای تنظیم Baud Rate استفاده می‌کنیم.Fosc فرکانس کاری میکروکنترلر، UBRR مقدار رجسترهای UBRR که 12 بیت هستند و BAUD که میزان نرخ ارسال یا همان Baud Rate است. اعداد 1 و 16 هم که ثابت هستند.فرمول دوماگر USART در مد آسنکرون باشد و بیت U2X در رجیستر UCSRA برابر 1 شود، سرعت انتقال داده 2 برابر خواهد شد. در این حالت باید از فرمول زیر استفاده کرد.تنها تفاوت این فرمول نصف شدن عدد ثابت 16 و تبدیل به 8 است. چون سرعت 2 برابر شده است.فرمول سوماگر مد کاری بصورت سنکرون انتخاب شود، بیت U2X تاثیری در نرخ ارسال ندارد و باید از رابطه زیر برای تنظیم Baud Rate استفاده کرد.این فرمول هم مشابه فرمول‌های ذکر شده است و تنها عدد ثابت 2 در مخرج قرار می‌گیرد.رجیسترهای (Usart Data Register) UDRوقتی صحبت از ارسال و یا دریافت اطلاعات می‌شود، باید به این دو رجیستر توجه کرد. این دو رجیستر کاملا همنام هستند و یکی از آنها برای دریافت اطلاعات(Read) و دیگری برای ارسال اطلاعات(Write) است.نکته: اگر تعداد بیت‌های داده را 8 بیت انتخاب کنیم که اکثرا مواقع هم همینگونه است، اطلاعات دریافتی در قالب یک بایت رد و بدل می‌شوند.اگر یک بایت دریافت شود (یک بایت از طریق پایه RXD وارد شود)، با خواندن UDR، در اصل مقدار رجیستری که برای دریافت داده است، خوانده می‌شود. به عبارتی دیگر تمایز بین این دو رجیستر را کامپایلر (CodeVision) انجام می‌دهد.unsigned char A;A = UDR;اگر بخواهیم یک بایت را ارسال کنیم، باید بر روی UDR بنویسیم. بلافاصله پس از مقدار دادن به UDR، ارسال اطلاعات از پایه TXD میکروکنترلر آغاز می‌شود.UDR = 0xAA;به عنوان مثال، یک بایت با مقدار “10101010” (0xAA) بر روی UDR نوشتیم که ارسال این بایت بصورت سخت‌افزاری انجام می‌شود.رجیستر (Usart Control Status Register A) UCSRAرجیسترهای UCSR جهت کنترل و تعیین وضعیت رابط سریال عمل می‌کنند. اما رجیستر UCSRA بیشتر وضعیت‌ها و اخطارهای جاری رابط سریال را نشان می‌دهد.بیت RXCاگر یک بایت دریافت شود، این بیت 1 می‌شود. در غیر این صورت 0 است.بیت TXCپس از اتمام ارسال یک بایت این بیت 1 می‌شود. در غیر این حالت 0 است.بیت (Usart Data Register Empty) UDREپس از اتمام ارسال یک بایت، مدت زمانی طول می‌کشد تا رجیستر UDR ارسالی خالی شود. پس از خالی شدن UDR، این بیت 1 شده و می‌توان بایت بعدی را برای ارسال روی آن نوشت. نکته: اگر این بیت 1 نشده باشد و بایت بعدی بلافاصله روی UDR نوشته شود، خطای سخت افزاری رخ می‌دهد.بیت ( Frame Error) FEاین بیت در گیرنده کاربرد دارد و زمانی 1 می‌شود که در فریم دریافتی خطاهایی مثل یکسان نبودن نرخ انتقال یا عدم تشخیص بیت‌های Start و Stop رخ دهد. مثلا اگر نرخ ارسال فرستنده 9600bps و در گیرنده 38400bps تنظیم شده باشد، این بیت مداوم در گیرنده 1 شده و 1 باقی می‌ماند. از این طریق می‌توان وقوع خطا را متوجه شد.بیت (Data Over Run) DORاگر در گیرنده یک بایت دریافت شود و برنامه‌نویس این بایت را نخواند و سپس یک بایت دیگر دریافت شود، در این صورت مقدار بایت قبلی از بین خواهد رفت و این بیت 1 می‌شود.بیت (Parity Error) PEاگر مشکل بیت توازن رخ دهد که بیت 1 می‌شود.بیت U2Xاگر این بیت 1 شود، نرخ ارسال داده 2 برابر خواهد شد.بیت (Multi Processor Communication Mode) MPCMاگر این بیت را 1 کنیم، ارتباط سریال وارد مد چند پردازنده‌ای می‌شود.رجیستر (Usart Control Status Register B) UCSRBاین رجیستر بصورت شکل زیر است و جهت کنترل سخت افزاری رابط سریال به کار می‌رود.بیت RXC Interrupt Enable) RXCIE)اگر این بیت 1 شود، وقفه دریافت USART فعال شده و در صورت گرفتن یک بایت، وقفه رخ می‌دهد. شماره Vector این وقفه عدد 12 است.بیت TXC Interrupt Enable) TXCIE)اگر این بیت را 1 کنیم، در صورت کامل شدن ارسال یک بایت، وقفه رخ می‌دهد. شماره Vector این وقفه عدد 14 است.بیت Usart Data Register Empty Interrupt Enable) UDRIE)در صورت 1 کردن این بیت، اگر پس از ارسال بایت، رجیستر UDR نوشتنی خالی شده و آماده دریافت بایت بعدی شود، وقفه رخ می‌دهد. شماره Vector این وقفه عدد 13 است.نکته: برای رخ دادن وقفه به غیر از فعال کردن هر کدام از این سه بیت، باید بیت وقفه عمومی هم 1 شود.بیت RX Enable) RXEN)برای حالت گیرندگی باید این بیت را 1 کرد. در غیر این صورت نمی‌توانیم داده دریافت کنیم.بیت TX Enable) TXEN)برای حالت فرستندگی این بیت باید 1 شود. در غیر این صورت نمی‌توان ارسال داده انجام داد.بیت Usart Character Size 2) UCSZ2)بیت‌های UCSZ از 3 بیت تشکیل شده که بیت سوم آن یعنی UCSZ2 در این رجیستر قرار دارد و دو UCSZ0 و UCSZ1 در رجیستر UCSRC واقع شده‌اند. گفتیم که طول داده دریافتی و ارسالی می‌تواند 5، 6، 7، 8 و یا 9 بیت باشد. این مقدار توسط این 3 بیت مطابق شکل زیر تنظیم می‌شود.به عنوان مثال اگر بخواهیم طول داده‌های ارسالی یا دریافتی 8 بیت باشد، وضعیت این 3 بیت باید “011” مقداردهی شود.بیت RX Bit 8) RXB8)در جدول بالا  اگر طول داده بصورت 9 بیتی تنظیم شود، این بیت نهمین بیت دریافتی است و باید قبل از رجیستر UDR خوانده شود. به عنوان یادآوری باید گفت که بیت‌های 0 تا 7 در رجیستر UDR فقط خواندنی قرار دارند.بیت TX Bit 8) TXB8)اگر طول داده را 9 بیت تنظیم کنیم، این بیت نهمین بیت ارسالی است و باید قبل از نوشتن بر روی UDR نوشتنی، مقداردهی شود. باز هم یادآور می‌شویم که بیت‌های 0 تا 7 در رجیستر UDR نوشتنی قرار دارند.رجیستر Usart Control Status Register C) UCSRC)این رجیستر هم قسمت‌های دیگر رابط سریال را کنترل می‌کند.بیت Usart Register Select) URSEL)اگر به رجیستر UBRRH دقت کرده باشید، آخرین بیت این رجیستر دقیقا بیت URSEL است. چون رجیستر UCSRC و UBRRH در حافظه از آدرس مشترکی استفاده می‌کنند، این بیت تمایز بین این دو رجیستر را انجام می‌دهد. به عبارتی دیگر اگر بخواهیم بر روی رجیستر UCSRC مقداری بنویسیم باید این بیت را بصورت 1 شده اعمال کنیم و از طرفی اگر بخواهیم مقداری را بر روی UBRRH بنویسیم باید این بیت را 0 شده در نظر بگیریم.بیت Usart Mode Select) UMSEL)رابط USART در دو مد سنکرون و آسنکرون کار می‌کند.· اگر UMSEL برابر 0 شود، مد آسنکرون انتخاب می‌شود.· اگر UMSEL برابر 1 شود، مد سنکرون فعال خواهد شد.در اکثر موارد مد آسنکرون استفاده می‌شود. اما اگر مد سنکرون انتخاب شود، کافی است در هر دو میکرو، پایه‌های XCK به یکدیگر وصل شوند. در این صورت پایه XCK یکی از میکروها بصورت خروجی و پایه XCK میکرو دیگر، باید بصورت ورودی تعریف شود.بیت‌های UPM0 و Usart Parity Mode) UPM1)در مورد بیت Parity صحبت کردیم. بیت توازن یا غیر فعال است و یا فعال بوده و در حالت زوج یا فرد قرار دارد.· اگر این دو بیت “00” شوند، بیت توازن غیرفعال بوده و در Frame ارسالی یا دریافتی وجود ندارد.· حالت “01” غیر مجاز است.· حالت “10” بیت توازن فعال شده و بصورت توازن زوج عمل می‌کند.· حالت “11” بیت توازن فعال شده و بصورت توازن فرد عمل می‌کند.بیت Usart Stop Bit Select) USBS)تعداد بیت‌های Stop را معلوم می‌کند.· اگر 0 باشد، یک بیت Stop در آخر فریم می‌آید.· اگر 1 باشد، دو بیت Stop استفاده می‌شود.بیت‌های UCSZ0 و Usart Character Size) UCSZ1)این بیت‌ها در توضیحات رجیستر UCSRB شرح داده شدند.بیت Usart Clock Polarity) UCPOL)این بیت زمانی کاربرد دارد که رابط USART در مد سنکرون عمل کند.مثال 1برنامه‌ای بنویسید که بصورت مداوم هر 1 ثانیه حرف A را بر روی خروجی چاپ کند. بیت Parity غیرفعال، تعداد بیت‌های Stop یک و طول داده 8 بیت است. همچنین نرخ ارسال هم 9600bps می‌باشد.تذکر: در تمام مثال‌ها فرکانس کاری میکروکنترلر بصورت 8MHz داخلی تنظیم شده است و مد عملکرد هم آسنکرون می‌باشد.#include &lt;mega16.h&gt;#include &lt;delay.h&gt;void main(void){UBRRH = 0;UBRRL = 51;UCSRA = 0x00;UCSRB = 0x08;UCSRC = 0x86;while(1){//UDR = 65;UDR = &#039;A&#039;;delay_ms(1000);}}تنظیم UBRRH و UBRRLاولین کار مشخص کردن نرخ ارسال یا Baud Rate است. چون در مد آسنکرون هستیم و بیت U2X واقع در رجیستر UCSRA صفر است، باید از فرمول اول استفاده کنیم.با گذاشتن 8000000 بجای Fosc و 9600 بجای BAUD، مقدار UBRR برابر 51 می‌شود. پس UBRRH برابر 0 و UBRRL برابر 51 خواهد شد.تنظیم UCSRAگفتیم که این رجیستر بیشتر وضعیت رابط را نشان می‌دهد. اما دو بیت مهم آن یعنی MPCM و U2X باید 0 شوند. نوشتن 0 یا 1 بر روی U2X روی Baud Rate تاثیر می‌گذارد و اگر در این مثال آن را 1 کنیم، مقدار Baud Rate دو برابر خواهد شد.تنظیم UCSRBاز هیچ وقفه‌ای استفاده نمی‌کنیم. پس سه بیت TXCIE ،RXCIE و UDRIE باید 0 شوند. تنها می‌خواهیم ارسال داده انجام دهیم. پس بیت RXEN برابر 0 و بیت TXEN برابر 1 می‌شود. چون طول داده 8 بیتی است، وضعیت بیت‌های UCSZ باید “011” شود. در نتیجه بیت UCSZ2 باید 0 شود. در آخر هم به دلیل 8 بیتی بودن طول داده، نیازی به دو بیت RXB8 و TXB8 نیست. بنابراین مقدار این رجیستر 0x08 خواهد شد.تنظیم UCSRCگفتیم که برای نوشتن روی UCSRC باید بیت URSEL را هنگام مقداردهی 1 کنیم. چون عملکرد در مد آسنکرون است، بیت UMSEL باید 0 شود. بیت توازن نداریم پس UPM0 و UPM1 هر دو باید 0 باشند. تعداد بیت Stop هم 1 بیت است. در نتیجه USBS باید 0 باشد. اما چون وضعیت بیت‌های UCSZ برابر “011” شد، هر دو بیت UCSZ0 و UCSZ1 باید 1 شوند. در آخر هم UCPOL که در مثال‌های بعدی در مورد آن توضیح می‌دهیم، باید 0 مقداردهی گردد. با این تفاسیر مقدار رجیستر UCSRC برابر 0x86 می‌شود.بدنه whileچون قرار است بصورت مداوم اطلاعات ارسال شود، دستورات را داخل (1)while می‌نویسیم. برای ارسال یک بایت، کافی است به رجیستر UDR مقدار دهیم. حرف A در داخل برنامه بصورت ‘A’ تفسیر می‌شود و این مقدار را به UDR می‌دهیم که بلافاصله پس از مقدارگیری ارسال اطلاعات آغاز شده و CPU به دستور delay می‌رسد و این چرخه ادامه دارد.تذکر: به عنوان کامنت عبارت UDR = 65 را نوشته‌ایم. تمام حروف انگلیسی، اعداد و علامت‌ها در جدولی به نام جدول اسکی ذکر شده‌اند که هر حرف یا علامت از یک بایت منحصر به فرد برای نمایش استفاده می‌کند. این مقدار برای حرف A برابر 65 است.برنامه مثال 1 را طوری ارتقا دهید که بجای حرف A عبارت Hello را چاپ کند. تمام تنظیمات یکسان است.#include &lt;mega16.h&gt;#include &lt;delay.h&gt;unsigned char Array[] = {&#039;H&#039;, &#039;e&#039;, &#039;l&#039;, &#039;l&#039;, &#039;o&#039;};unsigned char i;void main(void){UBRRH = 0;UBRRL = 51;UCSRA = 0x00;UCSRB = 0x08;UCSRC = 0x86;while(1){for(i=0;i&lt;5;i++){UDR = Array[i];while((UCSRA&amp;0x20)==0x00);}delay_ms(1000);}}تعریف آرایهچون عبارت Hello از 5 حرف تشکیل شده است، بنابراین یک آرایه با طول 5 بایت تعریف می‌کنیم که هر حرف یک بایت را اشغال کرده است.حلقه Forدر حلقه For مقدار i با هر بار اجرا یک واحد زیاد می‌شود. مقدار اولیه متغیر i برابر 0 است و تا عدد 5 ادامه پیدا می‌کند. اما مقدار رجیستر UDR از عناصر آرایه و به ترتیب از حرف H تا حرف آخر ادامه می‌یابد.پس از اینکه به UDR مقدار داده شد، باید منتظر بمانیم تا داده ارسال شده و رجیستر UDR خالی و آماده ارسال بایت بعدی شود. اینکار با دستور (while((UCSRA&amp;0x20)==0x00 انجام می‌شود. به عبارتی بیت UDRE واقع در رجیستر UCSRA وقتی رجیستر UDR خالی شود 1 خواهد شد. پس اگر مقدار UCSRA را با 0x20 بصورت منظقی &amp; کنیم و حاصل را با 0x00 مقایسه کنیم، در حالت عادی شرط صحیح بوده و CPU در دستور while صبر می‌کند. اما به محض 1 شدن بیت UDRE، شرط نادرست شده و CPU از while خارج می‌شود. بنابراین حلقه به انتها رسیده و از اول حلقه، رجیستر UDR مقدار بعدی را گرفته و این روال ادامه خواهد یافت.</description>
                <category>Arman Barkhordar</category>
                <author>Arman Barkhordar</author>
                <pubDate>Wed, 22 Dec 2021 21:08:46 +0330</pubDate>
            </item>
                    <item>
                <title>معماری MVVM در WPF</title>
                <link>https://virgool.io/CodeLovers/%D9%85%D8%B9%D9%85%D8%A7%D8%B1%DB%8C-mvvm-%D8%AF%D8%B1-wpf-f1y5zuof3m9w</link>
                <description>معماری MVVM یا ( Model-View-View Model ) یک الگوی معماری است که در مهندسی نرم افزار و تکنولوژی های برنامه نویسی شرکت مایکروسافت استفاده می شود و به عنوان الگوی طراحی مدل، توسط مارتین فاولر معرفی شده است.معماری MVVM به صورت هدفمند و برای توسعه پلتفرم UI ها حرفه ای که از برنامه نویسی رویداد محور پشتیبانی می کنند به وجود آمده است از جمله برنامه هایی که از برنامه نویسی رویداد محور استفاده می کنند می توان به: WPF, Silver Light و ZK Framework اشاره کرد.معماری MVVM امکانات بی نظیری را برای جدا سازی لایه Graphic User Interface و لایه Business Logic و یا کد های منطقی پشت مدل در اختیار شما قرار می دهد همچنین به عنوان یک Data Model انعطاف پذیر از View Model شناخته می شود.دلایل استفاده از MVVM:همکاری با دیگر برنامه نویسانبا جدا کردن قسمت UI برنامه از کد مربوطه، این امکان فراهم می شود تا متخصصین هر قسمت بتوانند در زمان یکسان بر روی پروژه کار کنند، یعنی زمانی که طراحان مشغول کار با UI هستند، توسعه دهندگان هم مشغول توسعه کد برنامه هستند بدون آنکه نیاز باشد هر دو با هم بر روی فایل های یکسان کار کنند.سهولت در تست برنامهمعماری MVVM رابطه بین منطق برنامه و UI را از بین می برد و باعث می شود تا توانایی تست برنامه بالاتر برود.با استفاده از MVVM هر قسمت از کد ریز تر می شود و اگر درست اجرا بشود، وابستگی های داخلی و خارجی داخل قسمت های جدایی از کد که شامل منطق برنامه است (قسمت های مورد نیاز برای تست)،  قرار می گیرند.آسان تر کردن نگهداری پروژهبا داشتن یک جدا کننده بین قسمت های مختلف برنامه یک ساختار و یکنواختی به کد های برنامه می دهد و باعث می شود تا پیدا کردن مکان های مختلف آسان شود.ارتباط بین اجزای MVVMسه قسمت اصلی MVVM در WPF:ویو - Viewاین بخش شمال تمامی عناصر UI پروژه میشود به عبارت دیگری تمام آن چیزی که کاربر از برنامه مشاهده میکند دراین بخش قرار می گیرد، در زبان  View، XAMLمی تواند به صورت Window, User Controls  و یا Resource Dictionaries  باشد.ویو مدل - View Modelاین قسمت شامل Object  هایی هست که داده ها و تابع ها را برای هریک از View  ها فراهم می کنند. در کل یک رابطه یک به یک بین کلاس های View  و View Model وجود دارد. کلاس های View Model داده ها را برای View  ارسال می کند و Command  ها را برای مدیریت UI  فراهم می کند. برخلاف روش های دیگر، View Model نباید اطلاعاتی در مورد View مربوط به خودش داشته باشد. این قسمت یک اصل کیلیدی روش MVVM  است.درواقع View Model  رابطه بین View  و Model است.مدل - Modelبه طور کلی Model  دسترسی به داده ها (Data) و سرویس هایی که برنامه نیاز دارد را فراهم میکند. زمانی که View Model  درحال کنار هم قرار دادن اطالاعات Model  هست، Class  های موجود در Model  کار اصلی برنامه را انجام می دهند. اگر شما در حال استفاده از Dependency injection باشید، Class  های موجود در Model به صورت پارامتر های سازنده interface  به View model  شما ارسال می شوند.از آنجایی که تعامل بین View model  و Model  به برنامه شما بستگی دارد، برای ادامه این مقاله فقط روی رابطه بین Model  و View Model  تمرکز می کنیم.اتصال - Bindingتوانایی Bind  کردن، استفاده از MVVM  را فراهم میکند. Bind  ها در View  تعریف می شوند و  Properties  های داخل View  را به  Properties  های View Model  متصل می کند.برای مثال:C#public class ViewModel 
{
  public string FirstName { get; set; }
}XAML&lt;TextBlock Text=&amp;quot{Binding Path=FirstName}&amp;quot VerticalAlignment=&amp;quotCenter&amp;quot HorizontalAlignment=&amp;quotCenter&amp;quot/&gt;کد بالا متعلق به قسمت شروعی از الگوی MVVM است، Binding مقدار موجود در Text Block، آن را  برابر با Property FirstName  موجود در کلاس View Model  قرار می دهد. اگر این کد اجرا بشود مقدار Text Block  خالی خواهد بود چونکه هیچ چیزی برای متصل کردن کلاس View Model  به Window  وجود ندارد، در WPF  می تواند با استفاده از Data Context  این ارتباط را ایجاد کرد.مقدار Data Context  را می توان در کلاس سازنده Window  تنظیم کرد، اگر هیچ Data Context  ای به عنصری از UI  متصل نباشد، Data Context  را از کلاس پدر خود به ارث می برد. بنابرین، تنظیم کردن Data Context  در داخل Window ، آن را برای تمامی عناصر داخل آن تنظیم می کند.public MainWindow()
{
var viewModel = new ViewModel();
viewModel.FirstName = &amp;quotArman&amp;quot
DataContext = viewModel;
InitializeComponent();
}حال با اجرا کردن برنامه، Text Block  مقدار “Arman” را نشان خواهد داد.دقت کنید که بر اساس روش MVVM تنها کدی که باید داخل MainWindow.cs  و یا دیگر View ها وارد شود DataContext است، در این جا ما برای ساده کردن مقاله این کد را در اینجا وارد کردیم، روش اصلی بعد از معرفی Command ها بیان شده است!یکی از بهترین نکات در مورد Bind  ها این است که UI را با داده های داخل View Model  هماهنگ می کند. برای مثال اگر بخواهیم  مقدار Text block قبلی را عوض کنیم:public MainWindow()
{
var viewModel = new ViewModel();
viewModel.FirstName = &amp;quotArman&amp;quot
DataContext = viewModel;
InitializeComponent();
viewModel.FirstName = &amp;quotMehdi&amp;quot
}اگر برنامه را اجرا کنیم Text Block  همچنان مقدار “Arman” را نمایش خواهد داد، با این وجود که مقدار Property FirstName  تقییر کرده اما هیچ اطلاع رسانی به Binding  برای تغییر دادن مقدارش وجود ندارد. این مشکل را می تواند با پیاده سازی (INPC (INotifyPropertyChanged برطرف کرد. این Interface یک Event مخصوص دارد که به Binding  اطلاع می دهد که property  خاصی تغییر کرده و هر bind ای که از آن استفاده می کند باید مقدارش را به روزرسانی کند.از INPC می توان به شکل زیر استفاده کرد:public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string FirstName { get; set; }
public void d(string propertyName) =&gt; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}public MainWindow()
{
var viewModel = new ViewModel();
viewModel.FirstName = &amp;quotArman&amp;quot
DataContext = viewModel;
InitializeComponent();
viewModel.FirstName = &amp;quotMehdi&amp;quot
viewModel.d(nameof(ViewModel.FirstName));
}حال Text Block مقدار “Mehdi” را نشان خواهد داد.با این حال، استفاده از این ایونت برای هر بار که مقدار Porperty  تغییر می کند می تواند بسیار خسته کننده شود. اما از آنجا که استفاده از MVVM  بسیار فرا گیر شده است، FrameWork  های زیادی هم برای فراهم کردن یک کلاس پایه برای کلاس View model  ساخته شده اند.دستورها - Commandsاستفاده از Bind  ها یک راه عالی برای انتقال داده ها از View Model  به View به شمار می رود، اما ما همچنان نیاز داریم که به View Model  اجازه بدهیم تا بتواند به UI پاسخ بدهد. اکثر User Control  ها که یک مقدار پیش فرض UI دارند (مانند یک دکمه) توسط Command ها مدیریت می شوند. تمامی User Control هایی که ICommandSource را پیاده سازی می کنند، از یک Command property پشتیبانی می کنند، که زمانی که عمل پیش فرض یک کنترل رخ می دهد، فراخوانی می شود. تعداد بسیار زیادی از کنترل ها این Interface را پیاده سازی می کنند، مانند: دکمه ها، منو ها و چک باکس ها.دستور ها Object هایی هستند که ICommand را اجرا می کنند و یا به بیانی دیگر، Command  ها پیام هایی هستند که از View به View Model فرستاده می شوند. زمانی که Event پیش فرض کنترلی (مانند کلیک کردن دکمه) رخ می دهد، Method داخل Commnad فراخوانی می شود. بنابراین Command ها هم می توانند وقتی قابل فراخوانی شدن باشند، نشان داده شوند. این موضوع به کنترل اجاره می دهد تا خودش را بر اساس فعال شدن یا نشدن Command، فعال یا غیرفعال بکند. مثال برای دستور ها:همانطور که در بالا دیده شد، ما میتوانیم مقدار FistName را  هنگامی که روی دکمه ای کلیک شد، تغییر دهیم.در ابتدا باید یک Command به View Model اضافه کنیم:public class ViewModel : ViewModelBase
{
 public ICommand ChangeNameCommand { get; }
     ...
}سپس، یک دکمه به Main Window اضافه می کنیم و با استفاده از Binding مقدار Command موجود در این صفحه را به Command داخل View Model متصل می کنیم:XAML&lt;Button Content = &amp;quotChange Name&amp;quot Command=&amp;quot{Binding Path=ChangeNameCommand}&amp;quot /&gt;حالا فقط نیاز داریم که یک Command Object جدید به ChangeNameCommand property موجود در View Model اختصاص دهیم. متاسفانه، WPF شامل یک ICommand پیش فرض مناسب برای استفاده در View Model نیست، با این وجود پیاده سازی Interface بسیار سادست:public class DelegateCommand : ICommand
{
 private readonly Action&lt;object&gt; _executeAction;
public DelegateCommand(Action&lt;object&gt; executeAction)
{
_executeAction = executeAction;
}
public void Execute(object parameter) =&gt; _executeAction(parameter);
 public bool CanExecute(object parameter) =&gt; true;
public event EventHandler CanExecuteChanged;
}برای مثال، در این پیاده سازی ساده، زمانی که Command اجرا می شود، تابع DelegateCommand فرا خوانده میشود. حالا می توانیم کد View Model را ادامه بدهیم:public class ViewModel : ViewModelBase
{
 ...
private readonly DelegateCommand _changeNameCommand;
public ICommand ChangeNameCommand =&gt; _changeNameCommand;
public ViewModel()
 {
_changeNameCommand = new DelegateCommand(Name);
}
private void Name(object commandParameter)
{
FirstName = &amp;quotPouria&amp;quot
 }
}حال اگر برنامه را اجرا کنیم و بر روی دکمه کلیک کنیم، مقدار Text Block تغییر خواهد کرد.حالا  پخش CanExecute از ICommand را اجرا می کنیم:public class DelegateCommand : ICommand
{
private readonly Action&lt;object&gt; _executeAction;
private readonly Func&lt;object, bool&gt; _canExecuteAction;
public DelegateCommand(Action&lt;object&gt; executeAction, Func&lt;object, bool&gt; canExecuteAction)
{
 _executeAction = executeAction;
 _canExecuteAction = canExecuteAction;
 }
public void Execute(object parameter) =&gt; _executeAction(parameter);
public bool CanExecute(object parameter) =&gt; _canExecuteAction?.Invoke(parameter) ?? true;
public event EventHandler CanExecuteChanged;
  public void InvokeCanExecuteChanged() =&gt; CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}همانند تابع Execute، این Command هم یک CanExecute delegate دریافت می کند. بر همین اساس، CanExecuteChanged event هم با یک متد Public اجرا می شود بنابراین ما میتوانیم هر زمان که CanExecute delegate تغییر کند آن را فرا بخوانیم.اگرچه معماری MVVM نیاز به یادگیری بیشتر برای فهم آن نیاز دارد، اما زمانی که به مفاهیم پایه آن مسلط شوید، می تواند ساخت برنامه با WPF را بسیار راحت تر بکند. علاوه بر این موضوع، با جدا کردن قسمت های مختلف برنامه، در نهایت به یک برنامه با قابلیت نگه داری بالاتر دست پیدا می کنید که انجام اعملیات Unit test را بسیار ساده تر میکند.Sources:- Microsoft.com- Intellitect.com- Blogsnook.com- Special thanks to Stackoverflow &amp; Github communityروش پژوهش و ارائه مطالب - دکتر یعقوبیآرمان برخوردار - دانشگاه صدرا</description>
                <category>Arman Barkhordar</category>
                <author>Arman Barkhordar</author>
                <pubDate>Thu, 24 Dec 2020 19:08:31 +0330</pubDate>
            </item>
            </channel>
</rss>