برنامج تحريك (تمرير) النصوص scrolling text باستخدام 8×8 LED Matrix و Arduino :
الدائرة الكهربية :


بعد ذلك دعونا نلقي نظرة على مثال لتمرير نص ولنرى ما هو مختلف. فيما يلى الكود ووصفه.
كود:
/*
8x8 LED Matrix MAX7219 Scrolling Text Example
Based on the following library:
GitHub | riyas-org/max7219 https://github.com/riyas-org/max7219
*/
#include <MaxMatrix.h>
#include <avr/pgmspace.h>
PROGMEM const unsigned char CH[] = {
3, 8, B00000000, B00000000, B00000000, B00000000, B00000000, // space
1, 8, B01011111, B00000000, B00000000, B00000000, B00000000, // !
3, 8, B00000011, B00000000, B00000011, B00000000, B00000000, // "
5, 8, B00010100, B00111110, B00010100, B00111110, B00010100, // #
4, 8, B00100100, B01101010, B00101011, B00010010, B00000000, // $
5, 8, B01100011, B00010011, B00001000, B01100100, B01100011, // %
5, 8, B00110110, B01001001, B01010110, B00100000, B01010000, // &
1, 8, B00000011, B00000000, B00000000, B00000000, B00000000, // '
3, 8, B00011100, B00100010, B01000001, B00000000, B00000000, // (
3, 8, B01000001, B00100010, B00011100, B00000000, B00000000, // )
5, 8, B00101000, B00011000, B00001110, B00011000, B00101000, // *
5, 8, B00001000, B00001000, B00111110, B00001000, B00001000, // +
2, 8, B10110000, B01110000, B00000000, B00000000, B00000000, // ,
4, 8, B00001000, B00001000, B00001000, B00001000, B00000000, // -
2, 8, B01100000, B01100000, B00000000, B00000000, B00000000, // .
4, 8, B01100000, B00011000, B00000110, B00000001, B00000000, // /
4, 8, B00111110, B01000001, B01000001, B00111110, B00000000, // 0
3, 8, B01000010, B01111111, B01000000, B00000000, B00000000, // 1
4, 8, B01100010, B01010001, B01001001, B01000110, B00000000, // 2
4, 8, B00100010, B01000001, B01001001, B00110110, B00000000, // 3
4, 8, B00011000, B00010100, B00010010, B01111111, B00000000, // 4
4, 8, B00100111, B01000101, B01000101, B00111001, B00000000, // 5
4, 8, B00111110, B01001001, B01001001, B00110000, B00000000, // 6
4, 8, B01100001, B00010001, B00001001, B00000111, B00000000, // 7
4, 8, B00110110, B01001001, B01001001, B00110110, B00000000, // 8
4, 8, B00000110, B01001001, B01001001, B00111110, B00000000, // 9
2, 8, B01010000, B00000000, B00000000, B00000000, B00000000, // :
2, 8, B10000000, B01010000, B00000000, B00000000, B00000000, // ;
3, 8, B00010000, B00101000, B01000100, B00000000, B00000000, // <
3, 8, B00010100, B00010100, B00010100, B00000000, B00000000, // =
3, 8, B01000100, B00101000, B00010000, B00000000, B00000000, // >
4, 8, B00000010, B01011001, B00001001, B00000110, B00000000, // ?
5, 8, B00111110, B01001001, B01010101, B01011101, B00001110, // *
4, 8, B01111110, B00010001, B00010001, B01111110, B00000000, // A
4, 8, B01111111, B01001001, B01001001, B00110110, B00000000, // B
4, 8, B00111110, B01000001, B01000001, B00100010, B00000000, // C
4, 8, B01111111, B01000001, B01000001, B00111110, B00000000, // D
4, 8, B01111111, B01001001, B01001001, B01000001, B00000000, // E
4, 8, B01111111, B00001001, B00001001, B00000001, B00000000, // F
4, 8, B00111110, B01000001, B01001001, B01111010, B00000000, // G
4, 8, B01111111, B00001000, B00001000, B01111111, B00000000, // H
3, 8, B01000001, B01111111, B01000001, B00000000, B00000000, // I
4, 8, B00110000, B01000000, B01000001, B00111111, B00000000, // J
4, 8, B01111111, B00001000, B00010100, B01100011, B00000000, // K
4, 8, B01111111, B01000000, B01000000, B01000000, B00000000, // L
5, 8, B01111111, B00000010, B00001100, B00000010, B01111111, // M
5, 8, B01111111, B00000100, B00001000, B00010000, B01111111, // N
4, 8, B00111110, B01000001, B01000001, B00111110, B00000000, // O
4, 8, B01111111, B00001001, B00001001, B00000110, B00000000, // P
4, 8, B00111110, B01000001, B01000001, B10111110, B00000000, // Q
4, 8, B01111111, B00001001, B00001001, B01110110, B00000000, // R
4, 8, B01000110, B01001001, B01001001, B00110010, B00000000, // S
5, 8, B00000001, B00000001, B01111111, B00000001, B00000001, // T
4, 8, B00111111, B01000000, B01000000, B00111111, B00000000, // U
5, 8, B00001111, B00110000, B01000000, B00110000, B00001111, // V
5, 8, B00111111, B01000000, B00111000, B01000000, B00111111, // W
5, 8, B01100011, B00010100, B00001000, B00010100, B01100011, // X
5, 8, B00000111, B00001000, B01110000, B00001000, B00000111, // Y
4, 8, B01100001, B01010001, B01001001, B01000111, B00000000, // Z
2, 8, B01111111, B01000001, B00000000, B00000000, B00000000, // [
4, 8, B00000001, B00000110, B00011000, B01100000, B00000000, // \ backslash
2, 8, B01000001, B01111111, B00000000, B00000000, B00000000, // ]
3, 8, B00000010, B00000001, B00000010, B00000000, B00000000, // hat
4, 8, B01000000, B01000000, B01000000, B01000000, B00000000, // _
2, 8, B00000001, B00000010, B00000000, B00000000, B00000000, // `
4, 8, B00100000, B01010100, B01010100, B01111000, B00000000, // a
4, 8, B01111111, B01000100, B01000100, B00111000, B00000000, // b
4, 8, B00111000, B01000100, B01000100, B00101000, B00000000, // c
4, 8, B00111000, B01000100, B01000100, B01111111, B00000000, // d
4, 8, B00111000, B01010100, B01010100, B00011000, B00000000, // e
3, 8, B00000100, B01111110, B00000101, B00000000, B00000000, // f
4, 8, B10011000, B10100100, B10100100, B01111000, B00000000, // g
4, 8, B01111111, B00000100, B00000100, B01111000, B00000000, // h
3, 8, B01000100, B01111101, B01000000, B00000000, B00000000, // i
4, 8, B01000000, B10000000, B10000100, B01111101, B00000000, // j
4, 8, B01111111, B00010000, B00101000, B01000100, B00000000, // k
3, 8, B01000001, B01111111, B01000000, B00000000, B00000000, // l
5, 8, B01111100, B00000100, B01111100, B00000100, B01111000, // m
4, 8, B01111100, B00000100, B00000100, B01111000, B00000000, // n
4, 8, B00111000, B01000100, B01000100, B00111000, B00000000, // o
4, 8, B11111100, B00100100, B00100100, B00011000, B00000000, // p
4, 8, B00011000, B00100100, B00100100, B11111100, B00000000, // q
4, 8, B01111100, B00001000, B00000100, B00000100, B00000000, // r
4, 8, B01001000, B01010100, B01010100, B00100100, B00000000, // s
3, 8, B00000100, B00111111, B01000100, B00000000, B00000000, // t
4, 8, B00111100, B01000000, B01000000, B01111100, B00000000, // u
5, 8, B00011100, B00100000, B01000000, B00100000, B00011100, // v
5, 8, B00111100, B01000000, B00111100, B01000000, B00111100, // w
5, 8, B01000100, B00101000, B00010000, B00101000, B01000100, // x
4, 8, B10011100, B10100000, B10100000, B01111100, B00000000, // y
3, 8, B01100100, B01010100, B01001100, B00000000, B00000000, // z
3, 8, B00001000, B00110110, B01000001, B00000000, B00000000, // {
1, 8, B01111111, B00000000, B00000000, B00000000, B00000000, // |
3, 8, B01000001, B00110110, B00001000, B00000000, B00000000, // }
4, 8, B00001000, B00000100, B00001000, B00000100, B00000000, // ~
};
int DIN = 7; // DIN pin of MAX7219 module
int CLK = 6; // CLK pin of MAX7219 module
int CS = 5; // CS pin of MAX7219 module
int maxInUse = 2;
MaxMatrix m(DIN, CS, CLK, maxInUse);
byte buffer[10];
char text[]= "LED Matrix , MAX7219 & Arduino "; // Scrolling text
void setup() {
m.init(); // module initialize
m.setIntensity(15); // dot matix intensity 0-15
}
void loop() {
printStringWithShift(text, 100); // (text, scrolling speed)
}
// Display the extracted characters with scrolling
void printCharWithShift(char c, int shift_speed) {
if (c < 32) return;
c -= 32;
memcpy_P(buffer, CH + 7 * c, 7);
m.writeSprite(32, 0, buffer);
m.setColumn(32 + buffer[0], 0);
for (int i = 0; i < buffer[0] + 1; i++)
{
delay(shift_speed);
m.shiftLeft(false, false);
}
}
// Extract the characters from the text string
void printStringWithShift(char* s, int shift_speed) {
while (*s != 0) {
printCharWithShift(*s, shift_speed);
s++;
}
}
الوصف :
• يتعين علينا هنا تضمين مكتبة إضافية وهى avr/pgmspace والتى تحتوى على PROGMEM وهو "معدّل متغير" variable modifier ويستخدم لتخزين البيانات في ذاكرة الفلاش بدلاً من SRAM. عندما يكون لدينا قاعدة بيانات كبيرة من المتغيرات الثابتة ، كما هو الحال في هذه الحالة التي تعرف الأحرف letters , characters ، فمن الأفضل تخزينها في ذاكرة الفلاش لأنها أكبر بكثير ، 32 كيلو بايت ، مقارنة بذاكرة SRAM ، 2 كيلو بايت .
كود:
#include <avr/pgmspace.h>
PROGMEM const unsigned char CH[] = {
3, 8, B00000000, B00000000, B00000000, B00000000, B00000000, // space
………………..
……………......
الكلمة المفتاحية PROGMEM هى معدل متغير ، ويجب أن تستخدم فقط مع أنواع البيانات المعرفة فى الملف pgmspace.h ، وهى تخبر المترجم " بوضع هذه المعلومات فى ذاكرة البرنامج الفلاش " بدلا من وضعها فى ذاكرة RAM ، حيث مكانها العادى .
استخدام PROGMEM هو أيضًا إجراء من خطوتين . بعد وضع البيانات في ذاكرة الفلاش ، يتطلب الأمر طرقًا خاصة (دوال ) ، محددة أيضًا في المكتبة pgmspace.h ، لقراءة البيانات من ذاكرة البرنامج مرة أخرى إلى الذاكرة RAM ، حتى نتمكن من القيام بشيء مفيد بها.
• بجانب مصفوفة الأحرف ، يتم تحدد (تعريف) نص التمرير :
كود:
char text[]= " LED Matrix , MAX7219 & Arduino "; // Scrolling text
• وفي قسم الحلقة loop ، الدالة المعرفة بمعرفة المستخدم printStringWithShift ، تقوم بطباعة نص التمرير على مصفوفة الليدات مع تعريف سرعة التمرير بالمللي ثانية بالوسيط الثانى .
كود:
void loop() {
printStringWithShift(text, 100); // (text, scrolling speed)
}
// Extract the characters from the text string
void printStringWithShift(char* s, int shift_speed) {
while (*s != 0) {
printCharWithShift(*s, shift_speed);
s++;
}
}
• أول شيء تقوم به هذه الدالة هو أنها تستخرج الأحرف من السلسلة النصية ، ثم تعرض هذه الأحرف المتحركة على مصفوفة الليدات بمساعدة دالة طباعة حرف مع الإزاحة printCharWithShift .
كود:
// Display the extracted characters with scrolling
void printCharWithShift(char c, int shift_speed) {
if (c < 32) return;
c -= 32; // Character index
memcpy_P(buffer, CH + 7 * c, 7); // Get a copy of character bytes , store in buffer
m.writeSprite(32, 0, buffer); // Display char in buffer at x=32 , y=0
m.setColumn(32 + buffer[0], 0);// Update column 32 + buffer[0] with 0
for (int i = 0; i < buffer[0] + 1; i++)
{
delay(shift_speed);
m.shiftLeft(false, false);//Shift char
}
}
أساسيات الكود بسيطة للغاية. يتم تعريف المعلومات من أجل MAX7219 لعرض حرف.
لكل حرف يتم استخدام 7 بايت. في الوقت الحالي ، لا يهم ما يعنيه. يشير PROGMEM إلى أن البيانات يتم تخزينها في ذاكرة البرنامج بحيث لا تتخلص (تهلك) من ذاكرة الوصول العشوائي RAM.

يمكنك إلقاء نظرة على الموقع http://www.asciitable.com/ ومحاولة إستنتاج علاقة في تسلسل الأحرف.
• الأحرف 32 الأولى (0..31, 0x00..0x1F) من كود أسكى غير قابلة للطباعة. تقوم الدالة printCharWithShift() بالتحقق من ذلك if ولا تفعل أي شيء (تتم العودة return على الفور) في حالة اكتشاف أحد هذه الأحرف. عدا ذلك else ، يتم ُطرح 32 من قيمة الحرف (على سبيل المثال ، يمثل الحرف L بالقيمة 76 ويتم طرح 32 منه (النتيجة 44). الآن عد إلى المصفوفة CH وابدأ في العد ؛ "الصف الأول" هو 0 ، عد إلى 44. ماذا تجد؟
كود:
if (c < 32) return;
c -= 32;
• تقوم الدالة الآن بإنشاء نسخة (باستخدام memcpy_P) من البايتات السبعة التي تعثر عليها في مصفوفة البايت الصغيرة المسماة المخزن المؤقت buffer ؛ الدالة memcpy_P هى إصدار خاص من الدالة memcpy تقوم بالنسخ من ذاكرة البرنامج PROGMEM بدلاً من ذاكرة (RAM) العادية .
كود:
memcpy_P(buffer, CH + 7 * c, 7); // Get a copy of character bytes , store in buffer
الوسيط الأول هو "الهدف" dest وهو المكان الذى يتم النسخ إليه فى ذاكرة RAM ، وهو هنا المصفوفة buffer ، والوسيط الثانى هو "المصدر" src وهو المكان الذى يتم النسخ منه فى ذاكرة البرنامج ، وهو هنا CH + 7 * c ، والوسيط الثالث هو "حجم" size النسخ ، وهو هنا 7 بايت .
• باستخدام الدالة writeSprite() ، تتم كتابة البيانات إلى MAX7219.
تقوم الدالة printStringWithShift() بالمرور ، بعمل تكرار loop ، عبر النص الذي مررته كوسيط (مؤشر إلى مصفوفة الأحرف ، *s ) ولكل حرف في النص تستدعي الدالة printCharWithShift() . عن طريق زيادة المؤشر pointer ، فإنه سيتم تمرير الحرف التالي.
كما تعلم ، فإن السلاسل النصية (C-strings) تنتهى بالحرف nul '\ 0' ( قيمة كود أسكى بصفر “0” ). ستتوقف الدالة عن استدعاء الدالة printCharWithShift() بمجرد اكتشاف أن المؤشر s يشير إلى الحرف nul .
|