分享

天宇32*32 RGB点阵故事 下

 暗香浮动在黄昏 2019-06-17

    我又回来了,很久没来eepw论坛了在去年写过的一篇帖子:STM32f103实战之驱动32*32 RGB点阵 中介绍了下RGB 点阵屏显示的方法。但是在上一篇帖子中明明标题是RGB点阵,可是为嘛没看到有RGB显示的方法,因为方法在本文中经行补充。

    此次项目我是参考了n多资料后,用了不到2个月时间重写程序,包括底层驱动,上层画图库,显示ASCII字符,显示中文字符等函数。

    RGB点阵屏接口是标准08接口:

接口连线(部分定义,详细见工程matrix_config.h中定义)

  1. #define MTX_PORT      

  2. #define MTX_PORTc GPIOC  

  3. #define MTX_RCCPB   RCC_APB2Periph_GPIOB  

  4. #define MTX_PR0     GPIO_Pin_0   //GPIOC  

  5. #define MTX_PG0     GPIO_Pin_11  //GPIOB  

  6. #define MTX_PB0     GPIO_Pin_1   //GPIOC  

  7. #define MTX_PR1     GPIO_Pin_2   //GPIOC  

  8. #define MTX_PG1     GPIO_Pin_12  //GPIOB  

  9. #define MTX_PB1     GPIO_Pin_3   //GPIOC  

  10. #define MTX_PA      GPIO_Pin_4   //GPIOC  

  11. #define MTX_PB      GPIO_Pin_6   //GPIOC  

  12. #define MTX_PC      GPIO_Pin_5   //GPIOC  

  13. #define MTX_PSTB    GPIO_Pin_13  //GPIOB  

  14. #define MTX_POE     GPIO_Pin_7   //GPIOC  

  15. #define MTX_PCLK    GPIO_Pin_10  //GPIOB  

屏幕我是采用2块 16*32 RGB点阵,采用级联方式连接。

扫描方式是8/1 扫描,就是说R0 G0 B0 对应的是上面0-7 的数据   R1 G1 B1 对应下面0-7 的数据,单块屏幕分辨率32*16 ,级联2块构成32*32 RGB 点阵屏。

       点阵要显示灰度,有两种方式,第一采用硬PWM芯片驱动,如TLC5941 芯片,可以硬件产生pwm 感兴趣的去看手册,我在此不解释,另一种是比较常用的是采用恒流芯片,类似74hc138 不同的是驱动全彩屏用的是恒流芯片驱动。而一般单色双色屏采用的是74hc138+595 由于全彩屏亮度高,耗电量也高,并且刷新速度快,导致行驱动多采用MOS管驱动,这就是屏幕驱动的区别。而驱动芯片也采用高速FPGA 或 CPLD 的驱动方式。RGB点阵灰度显示:每个点点亮不同时间会显示不同亮度,玩过PWM 的童鞋应该明白吧,50% 的占空比就是显示 一遍的亮度。

定义一个不同占空比数组

  1. int waits[] = {10,20,40,80,160,320,640,1280};  

  1. //显示不同占空比,就能显示不同灰度,你以为就这一个函数就够了吗?  NO NO NO 这只是整屏一个灰度显示函数,  

  1. /** 

  2.  * latches / shows a line and waits for n amount of time. 

  3.  */  

  4. void showLine(int amount) {  

  5.     int c = 0;  

  6.   STROBE;  

  7.   DISP_ON;  

  8.   for (c=0; c<amount; c++) //asm("nop");  

  9.   DISP_OFF;  

  10. }  

真正显示PWM函数:
  1. void display_PWM(void) {  

  2.     u8 s;  

  3.     u8 plane;  

  4.     u8 Display_Cache[64][3];  

  5.     u8 Display_Cache1[64][3];  

  6.     #if(MATRIX_WIDTH == 32)  

  7.         for(plane = 0; plane < scan; plane ++) //ÐÐɨÃè  

  8.         {  

  9.                 setRow(s);  

  10.                     Send_RGB_Module(plane,0);  

  11.                 showLine(waits[1]);  

  12.         }  

  13.     #else  

  14.         //GPIO6_LOW;  

  15.         for(plane = 0; plane < scan; plane ++) //ÐÐɨÃè É¨Ãè8ÐР 

  16.         {  

  17.                 u8 num,a;  

  18.               for(a=0;a<32;a++){  

  19.                   Display_Cache[a][0]=Display_PWM[plane*32+a][0];  

  20.                   Display_Cache[a][1]=Display_PWM[plane*32+a][1];  

  21.                   Display_Cache[a][2]=Display_PWM[plane*32+a][2];}  

  22.               for(a=0;a<32;a++){  

  23.                   Display_Cache[a+32][0]=Display_PWM[plane*32+a+512][0];  

  24.                   Display_Cache[a+32][1]=Display_PWM[plane*32+a+512][1];  

  25.                   Display_Cache[a+32][2]=Display_PWM[plane*32+a+512][2];}  

  26.               for(a=0;a<32;a++){  

  27.                   Display_Cache1[a][0]=Display_PWM[plane*32+a+256][0];  

  28.                   Display_Cache1[a][1]=Display_PWM[plane*32+a+256][1];  

  29.                   Display_Cache1[a][2]=Display_PWM[plane*32+a+256][2];}  

  30.               for(a=0;a<32;a++){  

  31.                   Display_Cache1[a+32][0]=Display_PWM[plane*32+a+768][0];  

  32.                   Display_Cache1[a+32][1]=Display_PWM[plane*32+a+768][1];  

  33.                   Display_Cache1[a+32][2]=Display_PWM[plane*32+a+768][2];}  

  34.               setRow(plane);  // ÐÐÑ¡Ôñ  

  35.               for(num=8;num>0;num--) //ÿһÐÐɨÃè8´Î  

  36.               {  

  37.                         for(s = 0; s <2 /*= (MATRIX_WIDTH/32)*/; s ++) //ɨ2Ä£¿é 32*2 ¸öµã  

  38.                         {  

  39.                                 for(a=0;a<MATRIX_MODULE;a++) //Ñ­»·´Ó0 ~ 32  

  40.                                 {  

  41.                                         if((Display_Cache[s*32+a][0] & 0x80) == 0x80)  

  42.                                             MTX_PORTc->BSRR = MTX_PR0;  

  43.                                         else  

  44.                                             MTX_PORTc->BRR  = MTX_PR0;                                         

  45.                                         if((Display_Cache[s*32+a][1] & 0x80) == 0x80)  

  46.                                             MTX_PORT->BSRR = MTX_PG0;  

  47.                                         else  

  48.                                             MTX_PORT->BRR  = MTX_PG0;  

  49.                                         if((Display_Cache[s*32+a][2] & 0x80) == 0x80)  

  50.                                             MTX_PORTc->BSRR = MTX_PB0;  

  51.                                         else  

  52.                                             MTX_PORTc->BRR  = MTX_PB0;  

  53.                                         if((Display_Cache1[s*32+a][0] & 0x80) == 0x80)  

  54.                                             MTX_PORTc->BSRR = MTX_PR1;  

  55.                                         else  

  56.                                             MTX_PORTc->BRR  = MTX_PR1;   

  57.                                         if((Display_Cache1[s*32+a][1] & 0x80) == 0x80)  

  58.                                             MTX_PORT->BSRR = MTX_PG1;  

  59.                                         else  

  60.                                             MTX_PORT->BRR  = MTX_PG1;  

  61.                                         if((Display_Cache1[s*32+a][2] & 0x80) == 0x80)  

  62.                                             MTX_PORTc->BSRR = MTX_PB1;  

  63.                                         else  

  64.                                             MTX_PORTc->BRR  = MTX_PB1;  

  65.                                         CLK_TOGGLE  

  66.                                 }  

  67.                         }  

  68.                         for(a=0;a<64;a++)  

  69.                         {  

  70.                             Display_Cache[a][0] = Display_Cache[a][0] <<1;  

  71.                             Display_Cache[a][1] = Display_Cache[a][1] <<1;  

  72.                             Display_Cache[a][2] = Display_Cache[a][2] <<1;  

  73.                             Display_Cache1[a][0] = Display_Cache1[a][0] <<1;  

  74.                             Display_Cache1[a][1] = Display_Cache1[a][1] <<1;  

  75.                             Display_Cache1[a][2] = Display_Cache1[a][2] <<1;  

  76.                         }  

  77.                         showLine(waits[num]);  //8(5): 2.12 0.38  

  78.                 }  

  79.         }  

  80.         //GPIO6_HIGH;  

  81.     #endif  

  82. }  

上面函数我稍微说下: 每次刷新一屏数据。 一屏幕又被刷新8次,但是这8次刷新中,占空比不同,占空比依次递减。最终调用此函数,就刷一屏数据。下面上面函数放进定时器里,就不用管了。 但是要定义一个 3byte * 1024 的空间 这是显示缓存,要显示的数据就存在此数组中。好在stm32 ram 有20k,32*32 点阵 都要占3Kb RAM, 看来刷RGB 真是很占系统资源的。

下面底层函数搞定,剩下就是移植上层函数。参考2 Adafruit 已经开源了一个画图基础库,直接偷过来移植,移植很容易他的库是C++ 只要把变量定义稍稍修改,就能用。函数中包括画点 画线 画矩形 填充矩形 画三角形 填充三角形 画圆 填充圆 等  具体用法:

  1. void drawPixel(s8,s8,u32);  

  2. void drawLine(s8,s8,s8,s8,u32);  

  3. void drawFastVLine(s8, s8, s8, u32);  

  4. void drawFastHLine(s8, s8, s8, u32);  

  5. void drawRect(s8, s8, s8, s8, u32);  

  6. void fillRect(s8 x, s8 y ,s8 w, s8 h, u32 Color);  

  7. void fillScreen(u32 Color);  

  8. void drawCircle(s8 x0, s8 y0, s8 r, u32 Color);  

  9. void drawCircleHelper(s8 x0, s8 y0, s8 r, s8 cornername,    u32 Color);  

  10. void fillCircleHelper(s8 x0, s8 y0, s8 r, s8 cornername,    s8 delta, u32 Color);  

  11. void fillCircle(s8 x0, s8 y0, s8 r, u32 color);  

  12. void drawTriangle(s8 x0, s8 y0, s8 x1, s8 y1,   s8 x2, s8 y2, u32 Color);  

  13. void fillTriangle(s8 x0, s8 y0, s8 x1, s8 y1, s8 x2, s8 y2, u32 Color);  

  14. void drawRoundRect(s8 x0, s8 y0, s8 w, s8 h,    s8 radius, u32 Color);  

  15. void fillRoundRect(s8 x0, s8 y0, s8 w, s8 h,    s8 radius, u32 Color);  

  16. void ClearBuff(u16 num1, u16 num2);  

  17. void fillScreen(u32 Color);  

画一个点:

  1. drawPixel(0, 0, Color888(255, 255, 255));  

填充一个矩形:

  1. fillRect(0, 0, 32, 32, Color888(0, 255, 0));  

画一个矩形:

  1. drawRect(0, 0, 32, 32, Color888(255, 255, 0));  

画线:

  1. // draw an 'X' in red  

  2. drawLine(0, 0, 31, 15, Color888(255, 0, 0));  

  3. drawLine(31, 0, 0, 15, Color888(255, 0, 0));  

显示ASCII 字符: (目前支持4种字体)

  1. setFont(font5x7);  

  2. drawString(2,0,COLOR_GREEN,"Select");  

  3. drawString(6,7,0x0000fffa,"Mode");  

  4. setFont(font3x5);  

  5. drawString(3,14,0x0000fffa,"< use >");  

还支持滚动显示字符:
  1. setScrollSpeed(25);  

  2. setScrollFont(font3x5);  

  3. setScrollColor(COLOR_BLUE);  

  4. scrollText("Hello World!!!", 1);  

还能显示中文,点阵屏内有一块 w25Q16 spi flash 。 内部前700Kb 存放 中文字库,支持显示 GBK 字符集 所以要显示中文很容易了:
  1. draw_hanzi( 0, 0,0x00ffffff,"天");  

  2. draw_hanzi(16, 0,0x00ffffff,"宇");  

移动显示字符

参考资料:

    1. 底层函数参考:Github  STM32RGBMatrixDriver

    2. 上层画图库   :adafruit/RGB-matrix-Panel

    3. 参考资料3    :  The Light Appliance Page

    4.灰度显示资料 :LED点阵屏显示原理

    5.Adafruit 函数 :Library

    6.汉字字符显示参考: (1)gbk字符集编码 (2)GBK内码查询

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多