در دو بخش قبل، یک LCD را به کمک واحد SPI را راهاندازی کردیم و تصویر و فونت روی آن نمایش دادیم. در این بخش قصد داریم یک انیمیشن روی LCD Nokia نمایش دهیم.
در ابتدا باید یک عکس متحرک پیدا کنیم و آن را به فریمهای جداگانه تقسیم کنیم. یا اینکه فریمهای انیمیشن خودمان را بسازیم. برای راحتی کار ما راه اول را میرویم و از یک عکس متحرک آماده استفاده میکنیم. بعد از تقسیم فایل Gif به فریمهای جداگانه، باید ابعاد عکسها را به اندازه LCD Nokia 5110 یعنی 84×48 پیکسل تغییر دهیم. همچنین چون این نمایشگر تنها قابلیت تصاویر سیاه و سفید را دارد و برای هر پیکسل نیز یک بیت تعریف میشود، باید فرمت عکسها را به Monochorme Bitmap یا همان Bitmap (bmp) تغییر دهیم. در آخر نیز هر عکس را به آرایه 504 بایتی تبدیل میکنیم.
خلاصه مراحلی که باید طی کنیم:
- یک انیمیشن (ترجیحا یک فایل گیف ساده)
- تقسیم به عکس یا فریمهای جداگانه
- تغییر ابعاد و فرمت عکسها
- تبدیل هر عکس به آرایه
بعد از این مراحل، آرایههای مذکور را به صورت یک ماتریکس در یک هدر فایل ذخیره کردیم تا بتوانیم در پروژه از آن استفاده کنیم.
برای شروع پروژه مانند بخش قبلی پروژه را در Cube MX میسازیم و دقیقا مانند همان بخش، واحدهای مختلف را تنظیم میکنیم. با این تفاوت که برای واحد SPI، DMA را نیز در حالت Circular تنظیم میکنیم. مجددا مانند قبل درایورها را روی LL تنظیم میکنیم و بعد از ایجاد پروژه وارد محیط Keil میشویم.
نوشتن کد برای اجرای انیمیشن بر روی LCD Nokia
همانطور که اشاره شد، باید هدرفایلی که درست کردیم را به پروژه اضافه کنیم (چگونگی انجام این کار در بخش قبلی گفته شد). ماتریکسی که درست کردهایم، باید چیزی شبیه به تصویر زیر باشد:
حالا باید به سراغ فایل main.c برویم و کد پروژه را بنویسیم. در ابتدای کد، هدرفایلهای مورد نیاز از جمله هدرفایل انیمیشنی که درست کردیم را به کد اضافه میکنیم؛
1 2 3 4 | #include "stdio.h" #include "LCD.h" #include "string.h" #include "animation.h" |
سپس مانند پروژه DMA به USART، یک بافر حافظه با اندازه مشخص (تعداد پیکسلهای LCD Nokia ) تعریف میکنیم؛
1 2 | #define VBSize 504 uint8_t VBuffer[VBSize]; |
همچنین کدی که برای تنظیم و راهاندازی DMA در آن پروژه تعریف کرده بودیم را به صورت یک تابع، و این بار برای انتقال اطلاعات به SPI مینویسیم؛
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /* function to configure DMA */ void Transfer_frame(void) { LCD_goto_xy(0,0); //go to positon (0,0) on LCD LL_GPIO_ResetOutputPin(LCD_GPIO, CE_pin); //put CE to Low state LL_GPIO_SetOutputPin(LCD_GPIO, DC_pin); //LCD Data Mode LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_3, //Channel3 in DMA1 is used for SPI1 (uint32_t) VBuffer, //Address of the first element of the memory buffer LL_SPI_DMA_GetRegAddr(SPI1), //Addrees of the SPI register to transter data LL_DMA_DIRECTION_MEMORY_TO_PERIPH); //Direction of the data transmission LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_3, (uint32_t) VBSize); //Size of the transfer LL_DMA_EnableChannel(DMA1, //Enable DMA1 LL_DMA_CHANNEL_3); LL_SPI_EnableDMAReq_TX(SPI1); //Enable DMA Request for SPI1 (Start the data transfer) } |
حالا باید واحد SPI و همچین LCD و DMA را راهاندازی کنیم و سپس بافری که ساختیم را مقداردهی کنیم؛
1 2 3 4 5 6 7 8 9 10 11 | LL_SPI_Enable(SPI1); //Enable SPI1 LL_mDelay(10); LCD_init(); //Initialize the LCD LCD_cls(); //Clear the LCD LL_mDelay(100); Transfer_frame(); //Call the DMA configuration function memset(VBuffer,0,VBSize); //Clear the memory buffer |
اکنون همه چیز برای نمایش انیمیشن ما آماده است. در حلقه while(1) کد زیر را مینویسیم:
1 2 3 4 5 6 | /* Scroll the animation frames with 200ms Delay between them */ for(int i=0;i<26;i++) { memcpy(VBuffer, animation_buffer[i], VBSize); LL_mDelay(140); } |
تعداد تکرارهای حلقه for به اندازه تعداد فریمهای انیمیشنی است که در نظر گرفتهایم. اگر همه مراحل را به درستی انجام داده باشیم نمایش انیمیشن را روی LCD Nokia میبینیم.
خطاهای احتمالی :
- عدم نمایش صحیح فریمها به دلیل اشتباه در ایجاد آریهها(به صورت عمودی یا افقی) و حالت نمایش آنها(عمودی یا افقی)
- استفاده از وقفه؛ توصیه میشود در این پروژه از وقفه استفاده نکنید.
- استفاده از توابع تغییر موقعیت یا پاک کردن LCD Nokia بعد از راه اندازی DMA. این عمل موجب خطا در نمایش صحیح فریمها میشود.
در سه بخش اخیر با نمایش اطلاعات مختلف روی LCD آشنا شدیم، در بخش بعدی در مورد نحوه راهاندازی تایمر در حالت PWM صحبت خواهیم کرد.