در بخش قبلی یک LCD Nokia را به کمک واحد SPI را راهاندازی کردیم و یک تصویر را روی آن نمایش دادیم. در این بخش قصد داریم یک فونت برای نوشتن در LCD تعریف کنیم و پیامهای موردنظرمان را روی LCD نمایش دهیم.
با ما همراه باشید.
قبل از هر چیز، نیاز به یک فونت داریم که ما برای نمونه یک فونت 5×8 در نظر گرفتیم که هدر فایل آن با جستوجوی عبارت font 5×8.h قابلدسترسی است. چگونگی استفاده از این هدر فایل در ادامه کار شرح داده میشود.
ابتدا مانند قبل روند ساخت پروژه را طی میکنیم. تنظیم کلاک، دیباگ، واحد SPI و همچنین پایههای خروجی را مانند بخش قبل تنظیم میکنیم و کد پروژه را ایجاد میکنیم تا وارد محیط Keil شویم.
نوشتن کد پروژه
در ابتدا باید هدر فایلی که در ابتدا گفتیم را به پروژه اضافه کنیم، بدین منظور، هدرفایل را در مسیری که پروژه را ایجاد کردهایم و در پوشه Core و سپس Inc کپی میکنیم. اکنون در محیط Keil، از نوارابزار یا از منوی Project و سپس Manage، Project Items را انتخاب میکنیم. از پنجره باز شده از طریق کلید Add files… به مسیر پروژه میرویم و هدرفایل کپی شده را انتخاب میکنیم تا به پروژه اضافه شود و در آخر OK را میزنیم. حالا باید در ابتدای فایل main.c نیز هدرفایل را اضافه کنیم. بدین منظور از دستور زیر استفاده میکنیم:
#include "font.h"
اکنون نیاز به تعریف تأخیرهای موردنیاز داریم. توجه کنید برای اینکه دستورات تغییر موقعیت نوشتن و فرستادن کاراکترها بهدرستی توسط LCD اجرا شوند، باید از تأخیر استفاده کنیم. سه تأخیر بهصورت زیر تعریف میکنیم:
#define X_NOP() {__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();} #define Y_NOP() X_NOP();X_NOP();X_NOP();X_NOP();X_NOP();X_NOP();X_NOP();X_NOP();X_NOP();X_NOP(); #define Z_NOP() Y_NOP();Y_NOP();Y_NOP();Y_NOP();Y_NOP();Y_NOP();Y_NOP();Y_NOP();Y_NOP();Y_NOP();
مانند بخش قبلی، تابع send_SPI که از قبل نوشتیم را در این پروژه نیز تعریف میکنیم:
void send_SPI(uint8_t data) { while(!LL_SPI_IsActiveFlag_TXE(SPI1)); LL_SPI_TransmitData8(SPI1, data); while(!LL_SPI_IsActiveFlag_RXNE(SPI1)) {} }
به وسیله این تابع، دو تابع برای فرستادن اطلاعات دستوری و نمایشی مینویسیم؛
/// send command to the LCD void LCD_SendCmd(uint8_t cmd) { LL_GPIO_ResetOutputPin(LCD_GPIO, CE_pin); //put CE to Low state LL_GPIO_ResetOutputPin(LCD_GPIO, DC_pin); //LCD Command Mode send_SPI(cmd); //X address Z_NOP();Z_NOP();Z_NOP();Z_NOP();Z_NOP();Z_NOP();Z_NOP();Z_NOP(); LL_GPIO_SetOutputPin(LCD_GPIO, DC_pin); //LCD exit from Command Mode LL_GPIO_SetOutputPin(LCD_GPIO, CE_pin); //put CE to High state } /// send data to the LCD void LCD_SendData(uint8_t data) { LL_GPIO_ResetOutputPin(LCD_GPIO, CE_pin); //put CE to Low state send_SPI(data); X_NOP();X_NOP();X_NOP();X_NOP();Z_NOP(); LL_GPIO_SetOutputPin(LCD_GPIO, CE_pin); //put CE to High state }
توجه کنید که در این دو تابع، پایه فعالسازی چیپ را در شروع و پایان دستورات، فعال و غیرفعال کردهایم. همچنین بعد از فرستادن دستور و دادههای نمایشی تأخیر قرار دادهایم. در پروژه ما تأخیر مناسب برای فرستادن دستور حدود 90 میکروثانیه و برای فرستادن دادهها حدود 10 میکروثانیه بود که بهوسیله تأخیرهای تعریفشده در ابتدای پروژه، این دو تأخیر موردنیاز را ایجاد کردهایم (کلاک این پروژه 72 مگاهرتز تنظیم شده است).
برای استفاده از LCD مانند پروژه قبل نیاز به یک فعالسازی اولیه داریم که این بار میخواهیم بهوسیله یک تابع این عمل را انجام دهیم؛
/// LCD initialization void LCD_init(void) { LL_GPIO_SetOutputPin(LCD_GPIO, CE_pin); //LCD Enable LL_GPIO_SetOutputPin(LCD_GPIO, DC_pin); //LCD Data Mode ////configure LCD : LL_GPIO_ResetOutputPin(LCD_GPIO, Reset_pin); LL_mDelay(10); LL_GPIO_SetOutputPin(LCD_GPIO, Reset_pin); LL_mDelay(10); /// LCD_SendCmd(0x21); //Function set(extended instruction set) LCD_SendCmd(0x90); //VOP LCD_SendCmd(0x07); //temperature coefficient LCD_SendCmd(0x13); //Voltage bias /// LCD_SendCmd(0x20); //Function set(basic instruction set) LCD_SendCmd(0x0C); //Display Configuration LCD_SendCmd(0x40); //Y address LCD_SendCmd(0x80); //X address }
برای کنترل نوشتن، دو تابع تغییر موقعیت و پاک کردن صفحهنمایش را تعریف میکنیم:
/// x&y position void LCD_goto_xy(int x, int y) { uint8_t xh = 0x80 | (x & 0x7F); uint8_t yh = 0x40 | (y & 0x07); LCD_SendCmd(xh); LCD_SendCmd(yh); } /// clear screen void LCD_cls(void) { LCD_goto_xy(0,0); for(int i=0;i<=(48*84/8);i++) { LCD_SendData(0x00); } }
اکنون باید بهوسیله تعریف یک تابع، از کاراکترهایی که در هدرفایل تعریف شده، برای نوشتن استفاده کنیم. بهعبارتدیگر، میخواهیم تابعی بنویسیم که یک کاراکتر را دریافت کند، این کاراکتر را در بافر فونت تعریف شده پیدا کند و آن را روی LCD نمایش دهد. تابع مذکور را به صورت زیر مینویسیم:
/// send single character to the LCD void LCD_send_char (char ch) { ch = ch - ' '; int index = ch * 5; for(int i=0;i<5;i++) { LCD_SendData(font5x8[index++]); } LCD_SendData(0x00); }
اکنون با استفاده از تابع LCD_send_char میتوانیم تابع دیگری بنویسیم که بتواند یک رشته را روی LCD نمایش دهد:
/// send string to the LCD void LCD_puts (char *ch) { while(*ch) { LCD_send_char(*ch++); } }
حالا همه کدهای مورد نیاز را نوشتهایم. میتوانیم به وسیله کدهای نوشته شده اطلاعات دلخواهمان را روی LCD بنویسیم.
مانند قبل، واحد SPI را فعال میکنیم (قبل از حلقه while(1)) :
LL_SPI_Enable(SPI1);
دستورات زیر را در ادامه مینویسیم:
LL_mDelay(10); LCD_init(); LCD_cls(); LCD_goto_xy(25,3); LCD_puts("Salam");
اگر تمامی مراحل به درستی انجام شده باشند، در موقعیت تعیین شده روی LCD Nokia، اطلاعات نمایش داده میشود.
نکته: باید توجه کرد که آرایه نوشته شده برای فونت، با طرز نمایش اطلاعات روی LCD، از نظر افقی یا عمودی بودن انطباق داشته باشد.
ریدایرکت کردن Printf برای نمایش اطلاعات روی LDC Nokia
میتوانیم مانند آموزش قسمت ریدایرکت کردن Printf توسط واحد USART، در این پروژه نیز تابع Printf را برای نمایش اطلاعات روی LCD Nokia ریدایرکت کنیم. بدین منظور ابتدا باید تنظیمات Run-Time Environment که در آموزش مذکور گفته شد را به همان شکل انجام دهیم. سپس تابع stdout_putchar را به صورت زیر تعریف میکنیم:
int stdout_putchar (int ch) { LCD_send_char(ch); return (ch); }
اکنون میتوانیم از دستور printf برای نمایش اطلاعات روی LCD Nokia استفاده کنیم.
در دو بخش گذشته در مورد نحوه راهاندازی LCD Nokia و نمایش عکس و اطلاعات نوشتاری روی آن صحبت کردیم. در بخش بعدی با چگونگی نمایش یک انیمیشن روی LCD آشنا خواهیم شد.
منبع:سیسوگ