سلام وقتتون بخیر : با یکی دیگه از سری مطالب میکروکنترلر stm32 در خدمت شما هستم؛ بریم سر سراغ ادامه ی کتابخونه؛ اول دوتا فایل برای کتابخونه میسازیم یکی h. و یکی هم c. ؛ دوم باید یکسری تابع بنویسیم برای اجرای تنظیملت یکیش اینه که پایه های LCD رو تعریف کنیم ( راه اندازی نمایشگر nokia 5110 با stm32 جلسه 2 )؛ مطلب جلسه قبل : راه اندازی نمایشگر nokia 5110 با stm32 جلسه 1
راه اندازی نمایشگر nokia 5110 با stm32 جلسه 2
برای راحتی کار، استراکچر براش میسازیم که پورت ها و پینها داخلش ذخیره بشن اینجوری :
1 2 3 4 |
typedef struct { GPIO_TypeDef* port; uint16_t pin; } N5110_pin_TypeDef; |
حالا ازش استفاده میکنیم و استراکچر دوم که تعریف پروت ها هست رو مینویسیم :
1 2 3 4 5 6 7 8 9 |
typedef struct { N5110_pin_TypeDef RST; N5110_pin_TypeDef CS; N5110_pin_TypeDef DC; N5110_pin_TypeDef DIN; N5110_pin_TypeDef SCK; N5110_Delay_Fn delay_function; N5110_Bitmap_TypeDef* bmp; } N5110_TypeDef; |
پس توی استراکچر دوم ما برای پایه مثلا ریست هم پورت رو داریم و هم پین رو …. پایه های میکرو که RST ,CS ,DC ,DIN ,SCK باشه رو اینجا تعریف کردیم ولیکن اون دوتا پارامتر پایانی بمونه بعدا توضیح میدم راحبشون؛ حالا باید پایه ها رو کانفیگ کنیم و خروجی تعریف کنیم و با چنتا تابع بتونیم پین به پینشو کنترل کنیم؛ برای کنترل پین پین LCD این دیفاین ها رو مینویسیم :
1 2 3 4 5 6 7 8 9 10 |
#define N5110_CS_LOW lcd->CS.port->BRR = lcd->CS.pin #define N5110_CS_HIGH lcd->CS.port->BSRR = lcd->CS.pin #define N5110_DC_LOW lcd->DC.port->BRR = lcd->DC.pin #define N5110_DC_HIGH lcd->DC.port->BSRR = lcd->DC.pin #define N5110_DIN_LOW lcd->DIN.port->BRR = lcd->DIN.pin #define N5110_DIN_HIGH lcd->DIN.port->BSRR = lcd->DIN.pin #define N5110_RST_LOW lcd->RST.port->BRR = lcd->RST.pin #define N5110_RST_HIGH lcd->RST.port->BSRR = lcd->RST.pin #define N5110_SCK_LOW lcd->SCK.port->BRR = lcd->SCK.pin #define N5110_SCK_HIGH lcd->SCK.port->BSRR = lcd->SCK.pin |
الان اینجوری شد که هر جا بخوایم مثلا پایه CS ال سی دی رو 0 کنیم کافیه بنویسیم :
1 |
N5110_CS_LOW |
و هر کجا بخوایم پایه CS رو 1 کنیم اینو مینویسیم :
1 |
N5110_CS_HIGH |
این روند برای تمام پایه های ال سی دی هست و از اینجا به بعد تو کتابخونه پایه ها رو با این کنترل میکنیم؛ این دیفاین ها رو توی فایل h. مینویسیم و استراکچر هایی که بالا تعریف شد هم توی فایل h. مینویسیم؛ حالا لازمه چندتا لایبرری از STM32 هم وارد کنیم داخل فایل h. ؛ اینجوری مینویسم :
1 2 3 |
#include "stm32f10x.h" #include "stm32f10x_rcc.h" #include "stm32f10x_gpio.h" |
خب چند دیفاین دیگه هم لازم داریم برای ال سی دی مثلا طول و عرض LCD رو دیفاین میکنیم :
1 2 |
#define lcd_x_pix 84 #define lcd_y_pix 48 |
یک تابع هم مینویسیم برای اتصال کلاک به پورت هایی که LCD بهشون وصل شده؛ این موضوع بر میگرده به آموزش STM32 که توی یکی از جلسه ها توضیح دادم چی به چیه؛ به این صورت عمل میکنیم که توی تابع مقدار پورت LCD رو میگیریم و با تابع :
1 |
RCC_APB2PeriphClockCmd |
کلاک میکرو رو به اون پورت اتصال میدیم؛ این تابع یک ورودی پوینتر داره؛ تابع رو اینجوری منویسم :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void _N5110_Clock(GPIO_TypeDef* port){ if (port == GPIOA) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); else if(port == GPIOB) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); else if(port == GPIOC) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); else if(port == GPIOD) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); else if(port == GPIOE) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); else if(port == GPIOF) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE); else if(port == GPIOG) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE); } |
میاد بررسی میکنه که ورودی با کدوم شرط برابر هست بعد همون شرط رو اجرا میکنه که توی زیر مجموعه اون شرط کلاک رو به همون پورت شرط متصل کردیم؛ چندتا پورت هم بالا تر گذاشتیم برای میکرو های بزرگتر؛ خب دیگه همه زمینه سازی ها شد که یک تابع بنویسیم که ال سی دی رو پیکر بندی یا ایشنال کنه (یعنی کلاک پورت ها رو وصل کنه و پورت هارو خروجی کنه و کلا تنظیملتی که ال سی دی برای شروع کار لازم داره رو بهش بده)؛ من اسم تابع ایشنال LCD رو میزارم :
1 |
void N5110_Init(N5110_TypeDef* lcd) |
خب توی این تابع چی مینویسیم؟ این بر میگرده به اموزش های STM32 که میایم پایه ها رو خروجی میکنیم و کلاک پایه ها رو وصل میکنیم (البته برای شروع اینه بعدا تغیرش میدیم )؛ خب :
1) استراکچر GPIO ها رو اول تابع لود میکنیم :
1 |
GPIO_InitTypeDef GPIO_InitStructure; |
2) با تابعی که برای اتصال کلاک به پورت ها نوشته بودیم کلاک رو به تک تک پورت های ال سی دی وصل میکنیم (یعنی اگه کل پایه های ال سی دی به یک پورت وصل هست فقط کلاک همون پورت رو وصل میکنیم ولی اگه هر کدم از پایه ها به صورت پراکنده روی یک پورت بود باید کلاک رو به تمام پورت ها وصل کنیم )
1 2 3 4 5 |
_N5110_Clock(lcd->CS.port); _N5110_Clock(lcd->DC.port); _N5110_Clock(lcd->DIN.port); _N5110_Clock(lcd->RST.port); _N5110_Clock(lcd->SCK.port); |
پس ما اینجوری مینویسم.
3) حالا باید پایه ها رو خروجی کنیم برای اینکار باید مقدار استراکچر GPIO رو تغیر بدیم و داخل استراکچر بریزیم ( توضیح بیشتر در آموزش STM32 )
خب برای خروی کردن پورت ها اینجوری مینویسیم :
1 2 3 4 5 6 7 8 9 10 11 12 |
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = lcd->CS.pin; GPIO_Init(lcd->CS.port , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = lcd->DC.pin; GPIO_Init(lcd->DC.port , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = lcd->DIN.pin; GPIO_Init(lcd->DIN.port , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = lcd->RST.pin; GPIO_Init(lcd->RST.port , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = lcd->SCK.pin; GPIO_Init(lcd->SCK.port , &GPIO_InitStructure); |
اول که مد خروجی رو با
1 |
GPIO_InitStructure.GPIO_Mode |
تعیین میکنیم که روی
1 |
GPIO_Mode_Out_PP |
تنظیم شده حالا میایم سرعت GPIO رو با
1 |
GPIO_InitStructure.GPIO_Speed |
تنظیم میکنیم که این رو هم روی 50 مگاهرتز تنظیم میکنیم
1 |
GPIO_Speed_50MHz |
خب حالا برای تک تک پین های ال سی دی خروجی تعریف میکنیم با مشخصاتی که بالا دادیم
1 2 3 4 5 6 7 8 9 10 |
GPIO_InitStructure.GPIO_Pin = lcd->CS.pin; GPIO_Init(lcd->CS.port , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = lcd->DC.pin; GPIO_Init(lcd->DC.port , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = lcd->DIN.pin; GPIO_Init(lcd->DIN.port , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = lcd->RST.pin; GPIO_Init(lcd->RST.port , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = lcd->SCK.pin; GPIO_Init(lcd->SCK.port , &GPIO_InitStructure); |
حالا میریم سراغ یکی پارامتر های بالا که توی استراکچر بود یعنی :
1 |
N5110_Delay_Fn delay_function; |
ببنید ما توی کتابخونه لازم داریم تابع دیلا داشته باشیم برای اینکه دیلا توی برنامه وقتی که کتابخونه رو به برنامه اضافه کردید دوتا نشه و دقیق تر بودن دیلای ها و کم شدن حجم برنامه میایم تابعی رو در قالب استراکچر از کابر میگیریم که به عنوان تابع دیلای از اون توی برنامش نوشته شده؛ خب توضیحات کافیه حالا لازمه LCD رو ریست کنیم تا اگه از قبل چیزی داخلش بوده بپره؛ این وسط سایر پایه ها رو هم در وضعیت 1 قرار میدیم؛ پس پایه Res رو برای ریست LCD 0 میکنیم و با استفاده از تابعی که توی استراکچر از کابر گرفته بودیم یکم تاخیر ایجاد میکنیم و ال سی دی رو ریست در میاریم :
1 2 3 4 5 6 7 |
N5110_RST_LOW; N5110_DC_HIGH; N5110_DIN_HIGH; N5110_SCK_HIGH; N5110_CS_HIGH; lcd->delay_function(10); N5110_RST_HIGH; |
به همین سادگی طبق توضیحات گذشته میدونیم الگوریتم کار این LCD چجوریه ولی حالا میخوایم بهش دیتا بدیم؛ برای دیتا دادن به ال سی دی ما 3 تا پایه داریم
نکته : دیتا دادن به LCD دو نمونه هست، یکیش کامند یکی هم دیتا برای نمایش.
CS : که برای مشخص کردن کامند بودن یا دیتا بودن دیتایی که الان وارد ال سی دی شده استفاده میشه
SDA : پایه دیتا برایI2C
SCL : پایه کلاک برای I2C
حالا باید یک تابع بنویسیم که بیاد دیتایی که بهش میدیم رو بفرسته رو ال سی دی من اسمشو اینجوری میزارم :
1 |
void N5110_WriteByte(N5110_TypeDef* lcd, uint8_t dat, uint8_t mode){ |
یک پونتر و یک دیتا و یک مد برای دیتاهای ورودی تابع در نظر میگیریم
- پوینتر وقتی کاربرد داره که بخوایم چند ال سی دی به یک میکرو بزنیم
- دیتا هم 8 بیت دیتاییکه میفرسته
- مد هم مشخص کننده نوع دیتا هست که دیتا هست یا کامند
خب چجوری بفهمیمی که چجوری دیتا بفرستیم؟ اینجاشو با دقت بخونید؛ دیتاشیت صفحه 12 گفته که :
1) برای دیتا دادن به ال سی دی اول پایه CS رو 0 کنید ( CS مخفف chip select هستش و با 0 کردن این پایه کنترلر ال سی دی اماده دریافت دیتا از کابر میشه )
2) تعیین کنید که این دیتایی ارسال میکنید دیتا هست یا کامند (اگر دیتا بود خب میاد روی ال سی دی نمایش داده میشه ولیکن اگر کامند بود به عنوان دستوری برای کنترلر شناخته میشه (اگر پایه DC مقدار high یا 1 داشته باشد دیتای ورودی به عنوان دیتایی برای نمایش یه کنترلر فرستاده میشود و اگر مقدار low یا 0 داشته باشد به عنوان کامند یا دستوری به کنترلر ال سی دی ) پس ما دوتا دیفاین به اول کتابخونه برای این موضوع اضافه میکنیم :
1 2 |
#define N5110_COMMAND 0 #define N5110_DATA 1 |
خب حالا یک شرط میزاریم که اگه MOD دیتای ورودی به تابع 1 بود پایه DC رو high کن و اگر دیتای ورودی کامند یا 0 بود DC هم low بشه؛ پس مینویسیم :
1 |
if (mode == N5110_DATA) N5110_DC_HIGH; else N5110_DC_LOW; |
نکته : بعد از اتمام 8 بیت دیتای ارسالی باید این پایه رو 0 کنیم.
حالا چون دیتا ها 8 بیتی ارسال میشه به ال سی دی پس یک فور لازم داریم تا دونه دونه بیت ها رو ارسال کنه؛ پس یک متغیر برای FOR تعریف میکنیم 8 بیتی هم باشه من اسمشو میزارم i :
1 |
uint8_t i; |
حالا باید یک for بنویسیم که 8 بار تکرار بشه :
1 2 |
for (i = 0; i < 8; i++) { } |
توی این فور اول برا یک شرط داریم که یک بیت از دیتای ورودی رو انتخاب میکنه و مقدارشو روی SDA میریزه :
1 |
if(dat & 0x80) N5110_DIN_HIGH; else N5110_DIN_LOW; |
حالا برای تکرار دوم باید بره سراغ بیت بعدی دیتا پس یکی شیفت میدیم دیتا رو :
1 |
dat = dat << 1; |
خب حالا ما یک بیت از دیتا رو به ال سی دی فرستادیم ولی کلاک رو که SCL باشه برای این بیت به LCD ارسال نکردیم؛ پس SCL رو 0 و 1 میکنیم تا کلاک هم برای این بیت ارسال بشه :
1 2 |
N5110_SCK_LOW; N5110_SCK_HIGH; |
خب با تکرار 8 بار برای این FOR 8 بیت دیتا و 8 کلاک به ال سی دی ارسال میشه؛ پس کل for میشه این :
1 2 3 4 5 6 |
for (i = 0; i < 8; i++) { if(dat & 0x80) N5110_DIN_HIGH; else N5110_DIN_LOW; dat = dat << 1; N5110_SCK_LOW; N5110_SCK_HIGH; } |
خب موقع خروج از تابع هم CS رو 1 میکنیم که چیپ ال سی دی از سلکت در بیاد :
1 |
N5110_CS_HIGH; |
پس کل تابع اراسال دیتا به ال سی دی میشه :
1 2 3 4 5 6 7 8 9 10 11 12 |
void N5110_WriteByte(N5110_TypeDef* lcd, uint8_t dat, uint8_t mode){ uint8_t i; N5110_CS_LOW; if (mode == N5110_DATA) N5110_DC_HIGH; else N5110_DC_LOW; for (i = 0; i < 8; i++) { if(dat & 0x80) N5110_DIN_HIGH; else N5110_DIN_LOW; dat = dat << 1; N5110_SCK_LOW; N5110_SCK_HIGH; } N5110_CS_HIGH; } |
خب دیگه قسمت سخت کار همین بود از اینجا به بعد سادس همش کار با همین تابعی هست که نوشیم؛ به امید داشتن ایرانی اباد تر لایق دونستید برای من هم دعا کنید
هزینه این اموزش ها هم نشر اون هست پس تا میتونید به دیگران برای یادگیری کمک کنید
موفق باشید
مهمان
سلام خیلی خوب بود همه را فهمیدم الا قسمت delay-fonction(10 یعنی قسمت dilay اگه امکانش هست یه قسمت کد کوچیک بزارین تا متوجه شم
نویسنده این مطلب
میتونید از سمپل هایی که تو اینترنت موجود هست با تایمر systic استفاده گنید
مهمان
سلام. ممنونم. آموزش هاتون عالین. فقط یه سوال اشتم. به کدوم پایه های میکرو وصل کنم؟
نویسنده این مطلب
هر پینی رو میتونید متصل کنید قابل تنظیم هست تو برنامه
مهمان
سلام
تا همین جاش هم خیلی مفید بود
خیلی ممنون
مهمان
نویسنده این مطلب
استقبالی از مطالب نمیشه ؟ ادامه بدم ؟
مهمان
خیلی توقع نداشته باشید که به سرعت مطلبتون خونده بشه؛ مطلب شما از اون دسته مطلبایی هست که تصادفی توی جستجوی یک نفر پیدا میشه و به قول معروف دلش رو شاد میکنه و اینا
مهمان
چرا؟
خیلی خوبه
مهمان
سلام ، بله ادامه بدید،

ما الکترونیکی نیستیم ولی الکترونیکی ها رو دوست داریم
نمیدونم چرا نظر دادن اینقدر سخته
ولی یه پیشنهاد
یه دکمه تشکری چیزی بزارید برای کسی که می خونه خیلی راحت تره نسبت به نظر دادن،البته این نظر من بود حالا خوبه یا که بد بود
مهمان
سلام.
خیلی ممنون بابت مطلب.
خیلی هم استقبال میشه. ادامه بدید. طریقه استفاده رو نگفتی مهندس؟
نویسنده این مطلب
با تمام شدن نوشتن کتابخونه میشه ازش استفاده کرد
البته من این کتابخونه رو توی ی طرح هایی بزرگتر میخواستم استفاده کنم برای همون نوشتم
مهمان
نقل قول از مهدی دمرچیلو:
خب بسم الله – بیا یاد بده.
باشه سورس کدش رو میزارم.
مهمان
من ال سی دی نوکیا ۱۲۰۰ رو راه اندازی کردم که هم کم مصرف تر از ۵۱۱۰ هستش هم پیکسل های بیشتری داره.با stm32
مدیر سایت
خب بسم الله – بیا یاد بده.