بریم توی CubeIDE 🙂 تا برای سختافزاری که جلسه قبل زدیم کتابخونه بنویسیم 🙂
توی این آموزش فرض بر ان است که شما به زبان C و STM32 تا حدودی مسلط هستید و خیلی از قسمتهای مربوط به جزئیات اینها از توضیحات در این آموزش خارج است.
اول یک در CubeIDE پروژه ایجاد میکنیم و توی محیط چندتا پینی که لازمه برای ال سی دی تعریف بشن رو خروجی تعریف میکنیم و براشون لیبل میزاریم:
- پین ال سی دی به اسم SCL رو به اسم N1202_scl دیفاین میکنم
- پین ال سی دی به اسم mosi رو به اسم N1202_sda دیفاین میکنم
- پین ال سی دی به اسم CS رو به اسم N1202_CS دیفاین میکنم
- پین ال سی دی به اسمRESET رو به اسم N1202_res دیفاین میکنم
منطبق بر تصویر بالا در CubeIDE، البته من توی این تصویر چیزایی دیگهای هم منطبق بر برد خودم تعریف کردم که شما نیازی به اونها ندارید حالا کلاک میکرو رو روی کریستال خارجی قرار میدم و فرکانس رو روی PLL میزارم روی 9 تا به 72 مگ کلاک روی کور اصلی برسیم.
و توی تنظیمات پینها چون سرعت 0 و 1 شدن پینها برای ال سی دی بسیار حائز اهمیت هست و با سرعت ال سی دی ما رابطه مستقیم داره روی تنظیمات GPIO در کیوب ماکزیمم سرعت رو روی high قرار میدم و برنامه رو جنریت میکنم.
خب بعد از ساختن کدهای پروژه به فایل Main.h توی CubeIDE میریم و میبینیم که کامپایلر پینهای ما رو به این صورت دیفاین کرده
1 2 3 4 5 6 7 8 | #define N1202_res_Pin GPIO_PIN_11 #define N1202_res_GPIO_Port GPIOA #define N1202_CS_Pin GPIO_PIN_12 #define N1202_CS_GPIO_Port GPIOA #define N1202_sda_Pin GPIO_PIN_4 #define N1202_sda_GPIO_Port GPIOB #define N1202_scl_Pin GPIO_PIN_5 #define N1202_scl_GPIO_Port GPIOB |
حالا برای نوشتن کتابخونه چند تا فایل به پروژه اضافه میکنیم که من اونها رو اینجوری اسم میگذارم:
1 2 3 4 | N1202.h N1202.c و اگه دوست داشتید fonts.h |
خب برای مقدمات کار ما اول از همه به یک فونت هم نیاز داریم من برای این کار سالیان دور یک فونت از اینترنت گرفتم که دقیقا یادم نیست کجا بوده ولی از این فونت انگلیسی توی همه کارام استفاده کرده ام فونت انگلیسی 5*8 پیکسلی هست که جدول فونتمون اینه:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | char FontLookup[97][5]={ {0x00, 0x00, 0x00, 0x00, 0x00},// (space) {0x00, 0x00, 0x5F, 0x00, 0x00},// ! {0x00, 0x07, 0x00, 0x07, 0x00},// " {0x14, 0x7F, 0x14, 0x7F, 0x14},// # {0x24, 0x2A, 0x7F, 0x2A, 0x12},// $ {0x23, 0x13, 0x08, 0x64, 0x62},// % {0x36, 0x49, 0x55, 0x22, 0x50},// & {0x00, 0x05, 0x03, 0x00, 0x00},// ' {0x00, 0x1C, 0x22, 0x41, 0x00},// ( {0x00, 0x41, 0x22, 0x1C, 0x00},// ) {0x08, 0x2A, 0x1C, 0x2A, 0x08},// * {0x08, 0x08, 0x3E, 0x08, 0x08},// + {0x00, 0x50, 0x30, 0x00, 0x00},// , {0x08, 0x08, 0x08, 0x08, 0x08},// - {0x00, 0x30, 0x30, 0x00, 0x00},// . {0x20, 0x10, 0x08, 0x04, 0x02},// / {0x3E, 0x51, 0x49, 0x45, 0x3E},// 0 {0x00, 0x42, 0x7F, 0x40, 0x00},// 1 {0x42, 0x61, 0x51, 0x49, 0x46},// 2 {0x21, 0x41, 0x45, 0x4B, 0x31},// 3 {0x18, 0x14, 0x12, 0x7F, 0x10},// 4 {0x27, 0x45, 0x45, 0x45, 0x39},// 5 {0x3C, 0x4A, 0x49, 0x49, 0x30},// 6 {0x01, 0x71, 0x09, 0x05, 0x03},// 7 {0x36, 0x49, 0x49, 0x49, 0x36},// 8 {0x06, 0x49, 0x49, 0x29, 0x1E},// 9 {0x00, 0x36, 0x36, 0x00, 0x00},// : {0x00, 0x56, 0x36, 0x00, 0x00},// ; {0x00, 0x08, 0x14, 0x22, 0x41},// < {0x14, 0x14, 0x14, 0x14, 0x14},// = {0x41, 0x22, 0x14, 0x08, 0x00},// > {0x02, 0x01, 0x51, 0x09, 0x06},// ? {0x32, 0x49, 0x79, 0x41, 0x3E},// @ {0x7E, 0x11, 0x11, 0x11, 0x7E},// A {0x7F, 0x49, 0x49, 0x49, 0x36},// B {0x3E, 0x41, 0x41, 0x41, 0x22},// C {0x7F, 0x41, 0x41, 0x22, 0x1C},// D {0x7F, 0x49, 0x49, 0x49, 0x41},// E {0x7F, 0x09, 0x09, 0x01, 0x01},// F {0x3E, 0x41, 0x41, 0x51, 0x32},// G {0x7F, 0x08, 0x08, 0x08, 0x7F},// H {0x00, 0x41, 0x7F, 0x41, 0x00},// I {0x20, 0x40, 0x41, 0x3F, 0x01},// J {0x7F, 0x08, 0x14, 0x22, 0x41},// K {0x7F, 0x40, 0x40, 0x40, 0x40},// L {0x7F, 0x02, 0x04, 0x02, 0x7F},// M {0x7F, 0x04, 0x08, 0x10, 0x7F},// N {0x3E, 0x41, 0x41, 0x41, 0x3E},// O {0x7F, 0x09, 0x09, 0x09, 0x06},// P {0x3E, 0x41, 0x51, 0x21, 0x5E},// Q {0x7F, 0x09, 0x19, 0x29, 0x46},// R {0x46, 0x49, 0x49, 0x49, 0x31},// S {0x01, 0x01, 0x7F, 0x01, 0x01},// T {0x3F, 0x40, 0x40, 0x40, 0x3F},// U {0x1F, 0x20, 0x40, 0x20, 0x1F},// V {0x7F, 0x20, 0x18, 0x20, 0x7F},// W {0x63, 0x14, 0x08, 0x14, 0x63},// X {0x03, 0x04, 0x78, 0x04, 0x03},// Y {0x61, 0x51, 0x49, 0x45, 0x43},// Z {0x00, 0x00, 0x7F, 0x41, 0x41},// [ {0x02, 0x04, 0x08, 0x10, 0x20},// "\" {0x41, 0x41, 0x7F, 0x00, 0x00},// ] {0x04, 0x02, 0x01, 0x02, 0x04},// ^ {0x40, 0x40, 0x40, 0x40, 0x40},// _ {0x00, 0x01, 0x02, 0x04, 0x00},// ` {0x20, 0x54, 0x54, 0x54, 0x78},// a {0x7F, 0x48, 0x44, 0x44, 0x38},// b {0x38, 0x44, 0x44, 0x44, 0x20},// c {0x38, 0x44, 0x44, 0x48, 0x7F},// d {0x38, 0x54, 0x54, 0x54, 0x18},// e {0x08, 0x7E, 0x09, 0x01, 0x02},// f {0x08, 0x14, 0x54, 0x54, 0x3C},// g {0x7F, 0x08, 0x04, 0x04, 0x78},// h {0x00, 0x44, 0x7D, 0x40, 0x00},// i {0x20, 0x40, 0x44, 0x3D, 0x00},// j {0x00, 0x7F, 0x10, 0x28, 0x44},// k {0x00, 0x41, 0x7F, 0x40, 0x00},// l {0x7C, 0x04, 0x18, 0x04, 0x78},// m {0x7C, 0x08, 0x04, 0x04, 0x78},// n {0x38, 0x44, 0x44, 0x44, 0x38},// o {0x7C, 0x14, 0x14, 0x14, 0x08},// p {0x08, 0x14, 0x14, 0x18, 0x7C},// q {0x7C, 0x08, 0x04, 0x04, 0x08},// r {0x48, 0x54, 0x54, 0x54, 0x20},// s {0x04, 0x3F, 0x44, 0x40, 0x20},// t {0x3C, 0x40, 0x40, 0x20, 0x7C},// u {0x1C, 0x20, 0x40, 0x20, 0x1C},// v {0x3C, 0x40, 0x30, 0x40, 0x3C},// w {0x44, 0x28, 0x10, 0x28, 0x44},// x {0x0C, 0x50, 0x50, 0x50, 0x3C},// y {0x44, 0x64, 0x54, 0x4C, 0x44},// z {0x00, 0x08, 0x36, 0x41, 0x00},// { {0x00, 0x00, 0x7F, 0x00, 0x00},// | {0x00, 0x41, 0x36, 0x08, 0x00},// } {0x08, 0x1C, 0x2A, 0x08, 0x08}, // <- {0x08, 0x08, 0x2A, 0x1C, 0x08},// -> }; |
خب همه اینا رو اوکی کردیم میریم سراغ قسمت شیرین و اصلی برنامه
ابتدا اینکلودهای برنامه رو تنظیم میکنیم برای این کار میریم توی فایل main.c در CubeIDE و فایل کتابخونه رو اینکلود میکنیم.
1 | #include "N1202.h" |
بعد میریم به فایل N1202.h و فایل مربوط به سورس کتابخونه رو دیفاین میکنیم.
1 | #include "N1202.c" |
و در نهایت میریم به فایل N1202.c و فایلهای زیر رو اینکلود میکنیم.
1 2 3 | #include "stm32f1xx_hal.h" #include"N1202.h" #include <math.h> |
و حالا برای اینکه در خیلی از موارد از سایز ال سی دی توابعی که مینویسم بیرون نزنن طول و عرض پیکسلی ال سی دی رو هم اینجوری دیفاین میکنیم.
1 2 | #define lcd_x_pix 96 #define lcd_y_pix 68 |
چون کنترل ما روی ال سی دی به صورت بایت بایت هست در صورتی که نیازه ما بتونیم یک بیت از اون بایت رو کنترل کنیم (مثلا روشن شدن و خاموش شدن 1 پیکسل)
چند تا دیفاین هم برای کنترل کردن وضعیت بیتها در یک بایت تعریف میکنیم به این شکل:
1 2 3 | #define cbi(port, bit) (port) &= ~(1 << (bit)) #define sbi(port, bit) (port) |= (1 << (bit)) #define inv_bit(port,bit) (port) ^=(1 << (bit)) |
توضیحات این دیفاینها اینجوریه که sbi میاد مقدار bit رو از بایت port برابر با یک قرار میده.
توضیحات این دیفاینها اینجوریه که cbi میاد مقدار bit رو از بایت port برابر با صفر قرار میده.
توضیحات این دیفاینها اینجوریه که inv_bit میاد مقدار bit رو از بایت port مخالف وضعیت قبلی خود همون بیت قرار میده (در روایتی از خودم هست که بیت رو تاگل میکنه یا XOR میکنه) خود ^ که در دیفاین تعریف شده XOR هست در زبان C.
و اینکه مجدد توضیح بدم تمام این توابع میتونن خیلی سادهتر نوشته بشن و کتابخونه رو بهینهتر کنن ولی من این توضیحات رو در اینجا نمیگذارم بر هر حال یوزر هم باید برای بدست آوردن اون چیزی که نیاز داره یک زحمتی بکشه و این مبحث فقط آموزش نوشتن کتابخونه یک ال سی دی هست منطبق بر خط خط دیتاشیت.
خب حالا توی دیتاشیت نوشته شما میتونید دیتاها رو از رم ال سی دی بخونید ولی ما اون پینی که قرار باشه دیتا رو ازش بخونیم رو سخت افزار ال سی دی مون نداریم یعنی بیرون نیومده پس ما نمیتونیم بخونیم 🙂 برای اینکه اینجا دستمون بستس باید یک رم مجازی با همون حجم رم ال سی دی توی میکرو تعریف کنیم و یک نسخه دوم از اطلاعات رم ال سی دی رو توی میکرو نگه داریم برای این کار هم چون به متغیری که بیتی باشه دسترسی نداریم متغیر بایتی برای در نظر میگیرم و بیت اولش و استفاده میکنیم (خود این مبحث برای ران شدن روی میکروکنترلرهای با رم کم نیاز به بهینهسازی داره)
خب من این آرایه رو اینجوری تعریف میکنم:
1 | uint8_t N1202_cache[lcd_x_pix][lcd_y_pix]; |
توی طول برنامه اول دیتا رو بعد از پردازش وارد این آرایه میکنم و بعد از این آرایه منتقل میکنم به رم ال سی دی.
یکی دیگه از توابعی که من مینویسم (باز این مبحث هم نیاز به بهینهسازی داره) اینه که دو تا بایت در ورودی بگیره یکی به اسم دیتا و یکی هم سلکت بعد بیت سلکت شده از دیتا رو تو خروجی به ما بده پس این تابع رو هم اینجوری مینویسم:
1 2 3 4 | uint8_t bi_to_by (uint8_t byte,uint8_t select){ if(byte>>select & 0x01)return 1; else return 0; } |
حالا چون این مطلب باید به صورتی باشه که قشر زیادی بتونن ازش استفاده کنن من تابع ارسال دیتا رو به دو شکل مینویسم که توی یکی از حالتها برای اینکه سرعت بیشتری رو بگیرم در CubeIDE از توابع hal استفاده نکردم و خود ریجیسترهای مربوطه رو توی تابع خودم نوشتم و این تنها بهینهسازیای هست که توی کل کتابخونه بروز میدم 😐
و ما الان تمام پیشنیازهای ال سی دی رو توی کدمون تعریف کردیم برای اینکه دستهبندی این مطالب درست باشد جلسه بعد میریم سراغ ارسال دیتا به رم ال سی دی و اینشیال اولیه ال سی دی و یکم بازی با کامندهای ال سی دی که توی دیتاشیت گفته شده 🙂
و اینکه انشالله تا 3 جلسه دیگه شما هم ال سی دی رو راه انداختید هم روش نوشتید هم توابع دایره کشیدن و رسم مستطیل و … براش نوشتید البته این توابع یکبار نیاز به نوشتن دارن بقیش میشه همینارو یکم دستکاری کرد و جاهای دیگه استفاده کرد 🙂
به امید داشتن ایرانی آبادتر و آرزوی موفقیت برای شما.
لینک پروژه در گیت هاب، شامل سورس کد و PCB