Clemens Valens
/
LED_panel
32x64 3-color message board http://elektorembedded.blogspot.com/
Embed:
(wiki syntax)
Show/hide line numbers
main.cpp
00001 #include "mbed.h" 00002 #include "font.h" 00003 #include "arial_8pt.h" 00004 #include "ini.h" 00005 #include <ctype.h> 00006 00007 00008 #define ROWS 16 /* Two rows are drawn "in parallel". */ 00009 #define COLUMNS 64 00010 00011 typedef enum 00012 { 00013 kOrange = 0, 00014 kGreen = 1, 00015 kRed = 2, 00016 kBlack = 3 00017 } 00018 color_t; 00019 00020 typedef struct 00021 { 00022 unsigned char pixel[COLUMNS]; // Contains data for 2 rows! 00023 } 00024 row_t; 00025 00026 typedef struct 00027 { 00028 int rows; 00029 int columns; 00030 row_t row[ROWS]; 00031 } 00032 matrix_t; 00033 00034 matrix_t Panel; 00035 00036 DigitalOut led1(LED1); 00037 DigitalOut led2(LED2); 00038 DigitalOut led3(LED3); 00039 DigitalOut led4(LED4); 00040 00041 DigitalOut Enable(p5); // enable 00042 DigitalOut Clock(p15); // clock per bit 00043 DigitalOut Latch(p14); // latch per line 00044 DigitalOut R1(p6); // Red upper half 00045 DigitalOut R2(p7); // Red lower half 00046 DigitalOut G1(p12); // Green upper half 00047 DigitalOut G2(p13); // Green lower half 00048 BusOut Row(p8,p9,p10,p11); 00049 00050 DigitalIn Switch(p20); // Day selection switch. 00051 00052 #define PANEL_ON Enable = 0 00053 #define PANEL_OFF Enable = 1 00054 #define CLOCK_DATA Clock=0; Clock=1 00055 #define LATCH_DATA Latch=0; Latch=1 00056 00057 Serial PC(USBTX,USBRX); // USB serial port. 00058 LocalFileSystem local("local"); // File system. 00059 const char *ini_file = "/local/pages.ini"; 00060 00061 #define MAX_LINES (4) 00062 #define MAX_LINE_LENGTH (128) /* Use very long lines for easy scrolling, we have plenty of memory. */ 00063 #define MAX_PAGES (7) 00064 #define SCROLL_GAP (24) /* in pixels */ 00065 00066 00067 typedef struct 00068 { 00069 char str[MAX_LINE_LENGTH]; 00070 color_t color; 00071 int x; 00072 int y; 00073 int scroll; // <0=left, 0=no scroll, >0=right 00074 int strlen_pixels; // String length in pixels. 00075 } 00076 line_t; 00077 00078 typedef struct 00079 { 00080 line_t line[MAX_LINES]; 00081 int hide; 00082 } 00083 page_entry_t; 00084 00085 page_entry_t pages[MAX_PAGES]; 00086 00087 00088 struct 00089 { 00090 float scroll_speed; 00091 float brightness; 00092 } 00093 app_data; 00094 00095 00096 void led_sweep(); 00097 void panel_load(unsigned char *p_pixel, int nr_of_pixels); 00098 void panel_refresh_row(int nr, row_t *p_pixel_data, int nr_of_pixels); 00099 void panel_refresh(matrix_t *p_panel); 00100 void panel_init(matrix_t& panel, int rows, int columns); 00101 void panel_fill_row(row_t *p_row, unsigned char value, int count); 00102 void panel_fill_matrix(matrix_t& panel, unsigned char value); 00103 void put_pixel(matrix_t& panel, unsigned int x, unsigned int y, color_t color); 00104 int put_char_xy(matrix_t& panel, char ch, unsigned int x, unsigned int y, const FONT_INFO *p_font, color_t color); 00105 int put_string_xy(matrix_t& panel, char *p_str, unsigned int x, unsigned int y, const FONT_INFO *p_font, color_t color); 00106 int measure_string(char *p_str, const FONT_INFO *p_font); 00107 void clear_display(void); 00108 int is_valid_char(char ch); 00109 color_t str_to_color(const char *p_str); 00110 int ini_file_handler(void* user, const char* section, const char* name, const char* value); 00111 void page_pre_init(void); 00112 void page_post_init(const FONT_INFO *p_font); 00113 int page_next(int page); 00114 int page_show(matrix_t& panel, int p); 00115 00116 00117 void led_sweep() 00118 { 00119 led1 = 0; 00120 led2 = 0; 00121 led3 = 0; 00122 led4 = 0; 00123 led1 = 1; 00124 wait(0.05); 00125 led1 = 0; 00126 led2 = 1; 00127 wait(0.05); 00128 led2 = 0; 00129 led3 = 1; 00130 wait(0.05); 00131 led3 = 0; 00132 led4 = 1; 00133 wait(0.05); 00134 led4 = 0; 00135 } 00136 00137 00138 // Clock the data into the display. 00139 // This is where the bit-banging happens. 00140 void panel_load(unsigned char *p_pixel, int nr_of_pixels) 00141 { 00142 int i; 00143 for (i=0; i<nr_of_pixels; i++) 00144 { 00145 unsigned char pixel = p_pixel[i]; 00146 R1 = pixel & 0x01; 00147 pixel >>= 1; 00148 G1 = pixel & 0x01; 00149 pixel >>= 1; 00150 R2 = pixel & 0x01; 00151 pixel >>= 1; 00152 G2 = pixel & 0x01; 00153 CLOCK_DATA; 00154 } 00155 LATCH_DATA; 00156 } 00157 00158 00159 void panel_refresh_row(int nr, row_t *p_pixel_data, int nr_of_pixels) 00160 { 00161 Row = nr; 00162 panel_load(p_pixel_data->pixel,nr_of_pixels); 00163 PANEL_ON; 00164 wait(app_data.brightness); 00165 PANEL_OFF; 00166 } 00167 00168 00169 void panel_refresh(matrix_t *p_panel) 00170 { 00171 int i; 00172 for (i=0; i<p_panel->rows; i++) 00173 { 00174 panel_refresh_row(i,&p_panel->row[i],p_panel->columns); 00175 } 00176 } 00177 00178 00179 void panel_init(matrix_t& panel, int rows, int columns) 00180 { 00181 CLOCK_DATA; // Init the clock line 00182 LATCH_DATA; // Reset the shift registers 00183 panel.rows = rows; 00184 panel.columns = columns; 00185 panel_fill_matrix(panel,kBlack); // Clear display. 00186 } 00187 00188 00189 void panel_fill_row(row_t *p_row, unsigned char value, int count) 00190 { 00191 int i; 00192 for (i=0; i<count; i++) 00193 { 00194 p_row->pixel[i] = value; 00195 } 00196 } 00197 00198 00199 void panel_fill_matrix(matrix_t& panel, unsigned char value) 00200 { 00201 int i; 00202 for (i=0; i<panel.rows; i++) 00203 { 00204 // Two rows are stored in one row... 00205 panel_fill_row(&panel.row[i],(value<<2)+value,panel.columns); 00206 } 00207 } 00208 00209 00210 void put_pixel(matrix_t& panel, unsigned int x, unsigned int y, color_t color) 00211 { 00212 unsigned char mask; 00213 unsigned char c; 00214 00215 if (x<panel.columns && y<2*panel.rows) 00216 { 00217 mask = 0x03; 00218 c = color; 00219 if (y>=panel.rows) 00220 { 00221 // Remember: two rows are stored in one. 00222 y -= panel.rows; 00223 c <<= 2; 00224 mask <<= 2; 00225 } 00226 c |= ~mask; // Do not overwrite the other pixel. 00227 panel.row[y].pixel[x] |= mask; // Clear pixel (pixels are active low!). 00228 panel.row[y].pixel[x] &= c; // Add in the zeroes. 00229 } 00230 } 00231 00232 00233 int put_char_xy(matrix_t& panel, char ch, unsigned int x, unsigned int y, const FONT_INFO *p_font, color_t color) 00234 { 00235 int i, h, w; 00236 if (p_font!=NULL) 00237 { 00238 i = ch - p_font->start_char; 00239 int width = p_font->p_character_descriptor[i].width; 00240 int second_byte = 0; 00241 if (width>8) 00242 { 00243 // Some wide characters are coded in two bytes. 00244 second_byte = width - 8; 00245 width = 8; 00246 } 00247 int offset = p_font->p_character_descriptor[i].offset; 00248 const uint8_t *p_char = p_font->p_character_bitmaps + offset; 00249 uint8_t mask; 00250 for (h=0; h<p_font->height; h++) 00251 { 00252 // Plot pixels for first byte. 00253 mask = 0x80; 00254 for (w=0; w<width; w++) 00255 { 00256 if ((*p_char&mask)!=0) put_pixel(panel,x+w,y+h,color); 00257 mask >>= 1; 00258 } 00259 if (second_byte>0) 00260 { 00261 // Handle 2nd byte of extra wide characters. 00262 p_char += 1; 00263 mask = 0x80; 00264 for (w=0; w<second_byte; w++) 00265 { 00266 if ((*p_char&mask)!=0) put_pixel(panel,x+w+8,y+h,color); 00267 mask >>= 1; 00268 } 00269 } 00270 p_char += 1; 00271 } 00272 return p_font->p_character_descriptor[i].width; 00273 } 00274 return 0; 00275 } 00276 00277 00278 int put_string_xy(matrix_t& panel, char *p_str, unsigned int x, unsigned int y, const FONT_INFO *p_font, color_t color) 00279 { 00280 int _x = 0; 00281 while (*p_str!=0) 00282 { 00283 _x += put_char_xy(panel,*p_str,x+_x,y,p_font,color); 00284 _x += 1; 00285 p_str += 1; 00286 } 00287 return _x>0? _x-1 : 0; 00288 } 00289 00290 00291 // Return the length of a string in pixels when printed using the provided font. 00292 int measure_string(char *p_str, const FONT_INFO *p_font) 00293 { 00294 int i; 00295 int strlen_pixels = 0; 00296 if (p_font!=NULL) 00297 { 00298 while (*p_str!=0) 00299 { 00300 i = *p_str - p_font->start_char; 00301 strlen_pixels += p_font->p_character_descriptor[i].width; 00302 strlen_pixels += 1; 00303 p_str += 1; 00304 } 00305 } 00306 return strlen_pixels; 00307 } 00308 00309 00310 void clear_display(void) 00311 { 00312 panel_fill_matrix(Panel,kBlack); 00313 } 00314 00315 00316 int is_valid_char(char ch) 00317 { 00318 return (ch>=' ' && ch<='~'); 00319 } 00320 00321 #define IS_SECTION(a) if (strcmp(p_section,(a))==0) 00322 #define IS_NAME(a) if (strcmp(p_name,(a))==0) 00323 #define IS_VALUE(a) if (strcmp(p_value,(a))==0) 00324 00325 color_t str_to_color(const char *p_str) 00326 { 00327 color_t color = kGreen; 00328 if (strcmp(p_str,"green")==0) color = kGreen; 00329 else if (strcmp(p_str,"orange")==0) color = kOrange; 00330 else if (strcmp(p_str,"red")==0) color = kRed; 00331 else if (strcmp(p_str,"black")==0) color = kBlack; 00332 return color; 00333 } 00334 00335 00336 int ini_file_handler(void *p_user, const char *p_section, const char *p_name, const char *p_value) 00337 { 00338 // Called from ini.c 00339 00340 int p = 0; 00341 00342 IS_SECTION("global") 00343 { 00344 IS_NAME("brightness") app_data.brightness = atof(p_value)/10000.0; 00345 else IS_NAME("speed") app_data.scroll_speed = atof(p_value)/1000.0; 00346 } 00347 else IS_SECTION("page1") p = 0; 00348 else IS_SECTION("page2") p = 1; 00349 else IS_SECTION("page3") p = 2; 00350 else IS_SECTION("page4") p = 3; 00351 else IS_SECTION("page5") p = 4; 00352 else IS_SECTION("page6") p = 5; 00353 else IS_SECTION("page7") p = 6; 00354 00355 IS_NAME("hide") pages[p].hide = atoi(p_value); 00356 else IS_NAME("text1") strcpy(pages[p].line[0].str,p_value); 00357 else IS_NAME("text2") strcpy(pages[p].line[1].str,p_value); 00358 else IS_NAME("text3") strcpy(pages[p].line[2].str,p_value); 00359 else IS_NAME("text4") strcpy(pages[p].line[3].str,p_value); 00360 else IS_NAME("color1") pages[p].line[0].color = str_to_color(p_value); 00361 else IS_NAME("color2") pages[p].line[1].color = str_to_color(p_value); 00362 else IS_NAME("color3") pages[p].line[2].color = str_to_color(p_value); 00363 else IS_NAME("color4") pages[p].line[3].color = str_to_color(p_value); 00364 else IS_NAME("x1") pages[p].line[0].x = atoi(p_value); 00365 else IS_NAME("x2") pages[p].line[1].x = atoi(p_value); 00366 else IS_NAME("x3") pages[p].line[2].x = atoi(p_value); 00367 else IS_NAME("x4") pages[p].line[3].x = atoi(p_value); 00368 else IS_NAME("y1") pages[p].line[0].y = atoi(p_value); 00369 else IS_NAME("y2") pages[p].line[1].y = atoi(p_value); 00370 else IS_NAME("y3") pages[p].line[2].y = atoi(p_value); 00371 else IS_NAME("y4") pages[p].line[3].y = atoi(p_value); 00372 else IS_NAME("scroll1") pages[p].line[0].scroll = atoi(p_value); 00373 else IS_NAME("scroll2") pages[p].line[1].scroll = atoi(p_value); 00374 else IS_NAME("scroll3") pages[p].line[2].scroll = atoi(p_value); 00375 else IS_NAME("scroll4") pages[p].line[3].scroll = atoi(p_value); 00376 00377 // Return 0 on error. 00378 return 1; 00379 } 00380 00381 00382 void page_pre_init(void) 00383 { 00384 int i, j; 00385 int y; 00386 // Set zero default values. 00387 memset(&pages,0,sizeof(pages)); 00388 for (j=0; j<MAX_PAGES; j++) 00389 { 00390 y = 0; 00391 for (i=0; i<MAX_LINES; i++) 00392 { 00393 // Set non-zero default values. 00394 pages[j].line[i].color = kBlack; 00395 pages[j].line[i].y = y; 00396 y += 8; 00397 } 00398 } 00399 } 00400 00401 00402 void page_post_init(const FONT_INFO *p_font) 00403 { 00404 int i, j; 00405 for (j=0; j<MAX_PAGES; j++) 00406 { 00407 for (i=0; i<MAX_LINES; i++) 00408 { 00409 // We need to know the length in pixels of each string. 00410 pages[j].line[i].strlen_pixels = measure_string(pages[j].line[i].str,p_font); 00411 } 00412 } 00413 } 00414 00415 00416 int page_next(int page) 00417 { 00418 page += 1; 00419 if (page<0) page = MAX_PAGES - 1; 00420 else if (page>=MAX_PAGES) page = 0; 00421 return page; 00422 } 00423 00424 00425 int page_show(matrix_t& panel, int p) 00426 { 00427 int i; 00428 clear_display(); 00429 // Show page if not hidden. 00430 if (pages[p].hide==0) 00431 { 00432 for (i=0; i<MAX_LINES; i++) 00433 { 00434 int x = pages[p].line[i].x; 00435 // Print the string. 00436 put_string_xy(panel,pages[p].line[i].str,x,pages[p].line[i].y,&arial_8pt_font_info,pages[p].line[i].color); 00437 // Handle scrolling. 00438 if (pages[p].line[i].scroll!=0) 00439 { 00440 // Simply print the string a second time, display clipping will prevent 00441 // artifacts when a string is partly printed off-screen. 00442 if (pages[p].line[i].scroll<0) 00443 { 00444 // Scroll to the left. 00445 x += (pages[p].line[i].strlen_pixels + SCROLL_GAP); 00446 // Reset the starting point when the string is completely off screen. 00447 if (pages[p].line[i].x+pages[p].line[i].strlen_pixels<0) pages[p].line[i].x = x; 00448 } 00449 else if (pages[p].line[i].scroll>0) 00450 { 00451 // Scroll to the right. 00452 x -= (pages[p].line[i].strlen_pixels + SCROLL_GAP); 00453 // Reset the starting point when the string is completely off screen. 00454 if (pages[p].line[i].x>=COLUMNS) pages[p].line[i].x = x; 00455 } 00456 put_string_xy(panel,pages[p].line[i].str,x,pages[p].line[i].y,&arial_8pt_font_info,pages[p].line[i].color); 00457 00458 // Update x position. 00459 pages[p].line[i].x += pages[p].line[i].scroll; 00460 } 00461 } 00462 } 00463 else p = page_next(p); // Page is hidden, move on to the next page. 00464 00465 return p; 00466 } 00467 00468 00469 int main() 00470 { 00471 int page = 0; 00472 int debounce = 0; 00473 const FONT_INFO *p_font = &arial_8pt_font_info; 00474 00475 PC.printf("\nmbed LED panel experiments\n"); 00476 led_sweep(); 00477 00478 led1 = 0; 00479 led2 = 0; 00480 led3 = 0; 00481 led4 = 0; 00482 00483 // Set some default values. 00484 app_data.brightness = 0.0005; 00485 app_data.scroll_speed = 0.001; 00486 00487 // Setup display. 00488 PANEL_OFF; 00489 panel_init(Panel,ROWS,COLUMNS); 00490 00491 // Read page data. 00492 page_pre_init(); 00493 int error = false; 00494 error = ini_parse(ini_file,ini_file_handler,0); 00495 page_post_init(p_font); 00496 00497 //sprintf(pages[0].line[0].str,"%0.3f",app_data.scroll_speed); 00498 00499 while (1) 00500 { 00501 if (error==true) 00502 { 00503 put_string_xy(Panel,"file not found",0,0,p_font,kRed); 00504 } 00505 else 00506 { 00507 page = page_show(Panel,page); 00508 } 00509 00510 // Handle next-page switch. 00511 if (Switch==1) 00512 { 00513 if (debounce<10) debounce += 1; 00514 else if (debounce==10) 00515 { 00516 debounce += 1; 00517 page = page_next(page); 00518 clear_display(); 00519 } 00520 } 00521 else debounce = 0; 00522 00523 /*if (PC.readable()) 00524 { 00525 int ch; 00526 ch = PC.getc(); 00527 PC.putc(ch); 00528 if (ch=='B') color = kBlack; 00529 else if (ch=='R') color = kRed; 00530 else if (ch=='O') color = kOrange; 00531 else if (ch=='G') color = kGreen; 00532 else if (ch=='x') x -= 1; 00533 else if (ch=='X') x += 1; 00534 else if (ch=='y') y -= 1; 00535 else if (ch=='Y') y += 1; 00536 PC.printf("\tx=%d, y=%d, color=%d\n",x,y,color); 00537 clear_display(); 00538 }*/ 00539 00540 panel_refresh(&Panel); // Call regularly! 00541 wait(app_data.scroll_speed); // Slow down, but not too much. 00542 } 00543 }
Generated on Thu Jul 14 2022 01:11:21 by 1.7.2