打印
[STM32F4]

MBI5052P4显示屏驱动

[复制链接]
2212|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主




  在万能的淘宝上买了一个P4室内全彩单元板,64x32,可以用来挂在客厅里用来显示时间,温湿度。

  买的时候非常担心,问了好几家,想知道用的是什么扫描方案,用什么器件可以驱动起来,不过老板都拒绝回答,最终寂寞难耐之下,找了一家约了。
  拿到屏后,庆幸芯片没有打磨,抱着屏直接找资料,居然是JXI5020,搭配D7528作为行选,这比几年前普遍用74HC595高大上多了。
  用万用表测了线,控制也很简单。
U13_R---1         2---U13_G
U13_B---3         4---GND  
U14_R---5         6---U14_G  
U14_B---7         8---GND  
A   ---9        10---B  
C  ---11        12---EN_L/EN_H
DCLK---13        14---LE
GCLK---15        16---GND
  现在问题来了,这个芯片适合FPGA驱动,因为需要用FPGA的高速IO才有机会实现它的SPWM,实现真彩的显示。
  不过多年不用FPGA的我,表示爱不起,不过可以先用STM32F103显示7彩再说。
  显示屏分上下两屏,上下两屏各有两片D7528,控制着16行。4片JXI5020级联,够成16*4共64个像素。
  以下是实现扫描的代码:
void dispaly_process(void) //共7us
{
        unsigned char i, j;
        unsigned char k;
        unsigned char rdata1[64];
       
        unsigned int wdata1;
        unsigned int wdata2;
        for (j = 0; j < 64; j++)
        {
                        JXI5020_PORT ->BRR  = UR14_SDO | UG14_SDO | UB14_SDO | UR13_SDO | UG13_SDO | UB13_SDO;
                        JXI5020_PORT ->BSRR = JXI5020_SCK;
                        JXI5020_PORT -> BRR = JXI5020_SCK;
        }       
        JXI5020_PORT -> BSRR = JXI5020_LE;                               
        JXI5020_PORT -> BRR  = JXI5020_LE;       
        //JXI5020_PORT -> BSRR = JXI5020_OE;
        if(led_dis_cnt < 8) D7258_PORT -> BSRR = D7258_EN;
        else D7258_PORT -> BRR = D7258_EN;
        switch(led_dis_cnt)
        {
                case 7:
                case 15:
                        //D7258_PORT -> BRR = D7258_A | D7258_B | D7258_C;
                        D7258_PORT -> BSRR = (D7258_A | D7258_B | D7258_C)<<16;
                break;
                case 6:
                case 14:
                        D7258_PORT -> BSRR = D7258_A | ((D7258_B | D7258_C)<<16);
                        //D7258_PORT -> BRR = D7258_B | D7258_C;
                break;       
                case 5:
                case 13:       
                        //D7258_PORT -> BRR = D7258_A | D7258_C;
                        D7258_PORT -> BSRR = D7258_B | ((D7258_A | D7258_C)<<16);
                break;
                case 4:
                case 12:       
                        D7258_PORT -> BSRR = D7258_A | D7258_B |((D7258_C)<<16);;
                        //D7258_PORT -> BRR = D7258_C;
                break;               
                case 3:
                case 11:
                        //D7258_PORT -> BRR = D7258_A | D7258_B;
                        D7258_PORT -> BSRR = D7258_C | ((D7258_A | D7258_B)<<16);
                break;       
                case 2:
                case 10:       
                        D7258_PORT -> BSRR = D7258_A | D7258_C | (D7258_B<<16);
                        //D7258_PORT -> BRR = D7258_B;
                break;       
                case 1:
                case 9:
                        //D7258_PORT -> BRR = D7258_A;
                        D7258_PORT -> BSRR = D7258_B | D7258_C | (D7258_A<<16);
                break;       
                case 0:
                case 8:       
                        D7258_PORT -> BSRR = D7258_A | D7258_B | D7258_C;
                break;                       
        }

          for (j = 64; j > 0; j--)
        {
                if(leddisbuf[64*led_dis_cnt + j - 1] & 0x01)JXI5020_PORT ->BSRR = UR14_SDO;
                else JXI5020_PORT ->BRR = UR14_SDO;
                if(leddisbuf[64*led_dis_cnt + j - 1] & 0x02)JXI5020_PORT ->BSRR = UG14_SDO;
                else JXI5020_PORT ->BRR = UG14_SDO;       
                if(leddisbuf[64*led_dis_cnt + j - 1] & 0x04)JXI5020_PORT ->BSRR = UB14_SDO;
                else JXI5020_PORT ->BRR = UB14_SDO;                               
                //xia
                if(leddisbuf[64*(16+led_dis_cnt) + j - 1] & 0x01)JXI5020_PORT ->BSRR = UR13_SDO;
                else JXI5020_PORT ->BRR = UR13_SDO;
                if(leddisbuf[64*(16+led_dis_cnt) + j - 1] & 0x02)JXI5020_PORT ->BSRR = UG13_SDO;
                else JXI5020_PORT ->BRR = UG13_SDO;       
                if(leddisbuf[64*(16+led_dis_cnt) + j - 1] & 0x04)JXI5020_PORT ->BSRR = UB13_SDO;
                else JXI5020_PORT ->BRR = UB13_SDO;       
                JXI5020_PORT ->BSRR = JXI5020_SCK;
                JXI5020_PORT -> BRR = JXI5020_SCK;
        }

        JXI5020_PORT -> BSRR = JXI5020_LE;                               
        JXI5020_PORT -> BRR  = JXI5020_LE;       
        //JXI5020_PORT -> BRR  = JXI5020_OE;       
        led_dis_cnt++;
        if (led_dis_cnt == 16)
        {
                led_dis_cnt = 0;
        }
}

  代码中使用了leddisbuf[64*32]作为显存,代码实现了这一部分显存从上到下,从左到右的扫描,要更新显示内容,直接把数据填充到这个显存里就好了。
  但是我并不满足于这样的显示,继续找资料,发现MBI5052居然脚序完全一致。
  
  关键是MBI5052提供了SRAM,自己就可以显示真彩色,只要刷数据和提供垂直同步信号就好,相信用单片机就可以搞定。
  于是我果断在淘宝上买了50片,花了一百。
  同时也加购了两个P4的显示屏。
  拿到芯片的第一件事就是把P4上原来的JXI5020取下来,再把新买的MBI5052焊上去,这个对于我来说还是基本没有难度的。
  还有就是芯片也从STM32F103升级到了STM32F407,这个的IO速度要快许多。
  不过令人头疼的是MBI5052的资料太难懂了,而且也没有对应的参考设计。

  这个图里基本上说明了对MBI的操作,只是不够详细,比如倍频时怎么操作,帧与帧之间怎么操作。
  以下是扫描的代码:
{
        unsigned int sck_cnt;
        unsigned short i,j,k,m;
        unsigned short state_reg=(1<<GCLK_FROM_DCLK)|(15<<LINE_16_NUMS)|(0<<PWM_GCLKS16BIT)|(0<<GCLK_DOUBLE)|0x2b;
        unsigned short red1;
        unsigned short green1;
        unsigned short blue1;
        unsigned short red2;
        unsigned short green2;
        unsigned short blue2;
        unsigned int mask;
        unsigned int bufaddA,bufaddB;

//1写入状态寄存器
//a写状态寄存器之前的前置设定指定
        JXI5020_PORT -> BSRRL = JXI5020_LE;//LE置为高电平        
        for(sck_cnt = 14;sck_cnt > 0;sck_cnt --)
        {
                JXI5020_PORT ->BSRRL = JXI5020_SCK;
                delay(2);
                JXI5020_PORT -> BSRRH = JXI5020_SCK;
                delay(1);       
        }
        JXI5020_PORT -> BSRRH = JXI5020_LE;//LE置为低电平                
//b写状态寄存器
        for(j = 0;j < 4;j++)//每个通道由4片MBI5052级联,每个通道锁存一次数据
        {
                for(sck_cnt = 0;sck_cnt < 16;sck_cnt ++)
                {
                        mask = 0x8000 >> sck_cnt;
                        if(j == 3)
                                if(sck_cnt == 12)JXI5020_PORT -> BSRRL = JXI5020_LE;//LE置为高电平        
                        if(state_reg & mask)JXI5020_PORT -> BSRRL  = UR14_SDO | UG14_SDO | UB14_SDO | UR13_SDO | UG13_SDO | UB13_SDO;
                        else JXI5020_PORT ->BSRRH  = UR14_SDO | UG14_SDO | UB14_SDO | UR13_SDO | UG13_SDO | UB13_SDO;               
                        delay(1);
                        JXI5020_PORT -> BSRRL = JXI5020_SCK;
                        delay(1);
                        JXI5020_PORT -> BSRRH = JXI5020_SCK;       
                        //delay(1);
                }
        }
        JXI5020_PORT -> BSRRH = JXI5020_LE;//LE置为低电平        
//2写入16*2*16的数据
        for(m = 0;m < 16;m++)//共有16行
        {
                for(i = 0;i < 16;i++)//每个MBI5052有16个通道,
                //for(i = 0;i < 1;i++)
                {       
                        for(j = 0;j < 4;j++)//每个通道由4片MBI5052级联,每个通道锁存一次数据
                        //for(j = 0;j < 1;j++)
                        {
#if 0
                                bufaddA = 0x000000ff;
                                bufaddB = 0x0000ff00;;//8位原始数据对应到16位PWM数据
#else                               
                                bufaddA = leddisbuf[((m+1)*64-1) - j*16 - i];
                                bufaddB = leddisbuf[((m+1)*64-1) - j*16 - i + 64*16];//8位原始数据对应到16位PWM数据
#endif
#if 0                               
                                if((m == 1) && (i == 0) && (j == 0))//m == 4 //用于测试数据显示的位置
                                {       
                                        red1 =   (bufaddA & 0xff0000) >> 8;//2 * (leddisbuf[i*64 + j] & 0xff0000>>16)上半屏数据
                                        green1 = (bufaddA & 0x00ff00) >> 0;//2 * (leddisbuf[i*64 + j] & 0x00ff00>>8)上半屏数据
                                        blue1 =  (bufaddA & 0x0000ff) << 8;//上半屏数据
                                        red2 =   (bufaddB & 0xff0000) >> 8;//上半屏数据
                                        green2 = (bufaddB & 0x00ff00) >> 0;//上半屏数据
                                        blue2 =  (bufaddB & 0x0000ff) << 8;//上半屏数据       
                                }
                                else
                                {       
                                        red1 =   0x0000;
                                        green1 = 0x0000;
                                        blue1 =  0x0000;//(leddisbuf[bufaddA] & 0x0000ff) << 1;//上半屏数据
                                        red2 =   0x0000;//(leddisbuf[bufaddB] & 0xff0000) >> 15;//上半屏数据
                                        green2 = 0x0000;//(leddisbuf[bufaddB] & 0x00ff00) >> 7;//上半屏数据
                                        blue2 =  0x0000;//(leddisbuf[bufaddB] & 0x0000ff) << 1;//上半屏数据
                                }
#else
                                        red1 =   (bufaddA & 0xff0000) >> 8;//2 * (leddisbuf[i*64 + j] & 0xff0000>>16)上半屏数据
                                        green1 = (bufaddA & 0x00ff00) >> 0;//2 * (leddisbuf[i*64 + j] & 0x00ff00>>8)上半屏数据
                                        blue1 =  (bufaddA & 0x0000ff) << 8;//上半屏数据
                                        red2 =   (bufaddB & 0xff0000) >> 8;//上半屏数据
                                        green2 = (bufaddB & 0x00ff00) >> 0;//上半屏数据
                                        blue2 =  (bufaddB & 0x0000ff) << 8;//上半屏数据       
#endif                               
                               
                                //if(m == 0)red1 = 255;
                                for(k = 0;k < 16;k++)
                                {
                                        mask = 0x8000 >> k;
                                        if(j == 3)
                                                if(k == 15)JXI5020_PORT -> BSRRL = JXI5020_LE;//最后一个位LE置为高电平
#if 1
                                        if(red1 & mask)JXI5020_PORT -> BSRRL = UR14_SDO;
                                        else JXI5020_PORT -> BSRRH = UR14_SDO;
                                        if(green1 & mask)JXI5020_PORT -> BSRRL = UG14_SDO;
                                        else JXI5020_PORT -> BSRRH = UG14_SDO;
                                        if(blue1 & mask)JXI5020_PORT -> BSRRL = UB14_SDO;
                                        else JXI5020_PORT -> BSRRH = UB14_SDO;       
                                        if(red2 & mask)JXI5020_PORT -> BSRRL = UR13_SDO;
                                        else JXI5020_PORT -> BSRRH = UR13_SDO;
                                        if(green2 & mask)JXI5020_PORT -> BSRRL = UG13_SDO;
                                        else JXI5020_PORT -> BSRRH = UG13_SDO;
                                        if(blue2 & mask)JXI5020_PORT -> BSRRL = UB13_SDO;
                                        else JXI5020_PORT -> BSRRH = UB13_SDO;       
                                        delay(1);
                                        JXI5020_PORT -> BSRRL = JXI5020_SCK;
#else
                                        JXI5020_PORT -> BSRRL = UR14_SDO | UG14_SDO;                                       
#endif                                       
                                        delay(1);
                                        //delayins++;
                                        JXI5020_PORT -> BSRRH = JXI5020_SCK;                               
                                }               
                        }
                        JXI5020_PORT -> BSRRH = JXI5020_LE;//LE置为低电平                
                }
        }
//3发送至少50个GCLK 最后3个CLK拉高LE,发送VSYNC
        for(sck_cnt = 0;sck_cnt < 60;sck_cnt ++)
        {
                if(sck_cnt == 60 - 3)JXI5020_PORT -> BSRRL = JXI5020_LE;//LE置为高电平        
                //if(state_reg & mask)JXI5020_PORT ->BSRRL  = UR14_SDO | UG14_SDO | UB14_SDO | UR13_SDO | UG13_SDO | UB13_SDO;
                JXI5020_PORT ->BSRRH  = UR14_SDO | UG14_SDO | UB14_SDO | UR13_SDO | UG13_SDO | UB13_SDO;               
                delay(1);
                JXI5020_PORT ->BSRRL = JXI5020_SCK;
                delay(1);
                if(sck_cnt < 59)JXI5020_PORT -> BSRRH = JXI5020_SCK;//最后一个不要拉低
        }
        JXI5020_PORT -> BSRRH = JXI5020_LE;//LE置为低电平        
        delay(2);//LE下降沿与GCLK上升沿满足要求
//4消隐
        for(sck_cnt = 0;sck_cnt < 512;sck_cnt ++)
        {
                JXI5020_PORT ->BSRRH  = UR14_SDO | UG14_SDO | UB14_SDO | UR13_SDO | UG13_SDO | UB13_SDO;               
                JXI5020_PORT ->BSRRL = JXI5020_SCK;
                delay(1);
                //JXI5020_PORT -> BSRRH = JXI5020_SCK;
        }
        JXI5020_PORT -> BSRRH = JXI5020_SCK;//SCK置为低电平        
//5开始显示       
        for(i = 0;i < 16; i++)
        {
                //设置行电平
                if(i < 8) D7258_PORT -> BSRRL = D7258_EN;
                else D7258_PORT -> BSRRH = D7258_EN;
                switch(i)
                {
                        case 7:
                        case 15:
                                D7258_PORT_BSRR = (D7258_A | D7258_B | D7258_C)<<16;
                                //D7258_PORT -> BSRRH = D7258_A | D7258_B | D7258_C;
                                //D7258_PORT -> BSRRL = 0;
                        break;
                        case 6:
                        case 14:
                                D7258_PORT_BSRR = D7258_A | ((D7258_B | D7258_C)<<16);
                                //D7258_PORT -> BSRRH = D7258_B | D7258_C;
                                //D7258_PORT -> BSRRL = D7258_A;
                        break;       
                        case 5:
                        case 13:
                                D7258_PORT_BSRR = D7258_B | ((D7258_A | D7258_C)<<16);               
                                //D7258_PORT -> BSRRH = D7258_A | D7258_C;
                                //D7258_PORT -> BSRRL = D7258_B;
                        break;
                        case 4:
                        case 12:
                                D7258_PORT_BSRR = D7258_A | D7258_B |((D7258_C)<<16);               
                                //D7258_PORT -> BSRRH = D7258_C;
                                //D7258_PORT -> BSRRL = D7258_A | D7258_B;                       
                        break;               
                        case 3:
                        case 11:
                                D7258_PORT_BSRR = D7258_C | ((D7258_A | D7258_B)<<16);
                                //D7258_PORT -> BSRRH = D7258_A | D7258_B;
                                //D7258_PORT -> BSRRL = D7258_C;
                        break;       
                        case 2:
                        case 10:
                                D7258_PORT_BSRR = D7258_A | D7258_C | (D7258_B<<16);       
                                //D7258_PORT -> BSRRH = D7258_B;
                                //D7258_PORT -> BSRRL = D7258_A | D7258_C;
                        break;       
                        case 1:
                        case 9:
                                D7258_PORT_BSRR = D7258_B | D7258_C | (D7258_A<<16);
                                //D7258_PORT -> BSRRH = D7258_A;
                                //D7258_PORT -> BSRRL = D7258_B | D7258_C;
                        break;       
                        case 0:
                        case 8:       
                                D7258_PORT_BSRR = D7258_A | D7258_B | D7258_C;
                                //D7258_PORT -> BSRRH = 0;
                                //D7258_PORT -> BSRRL = D7258_A | D7258_B | D7258_C;
                        break;                       
                }               
                for(sck_cnt = 0;sck_cnt < 1025;sck_cnt ++)//发送1024个脉冲,第1024个脉冲时停止 占时应约为1000/60/16=1.25ms
                {               
                        JXI5020_PORT ->BSRRL = JXI5020_SCK;
                        delay(2);
                        if(sck_cnt < 1025-1)JXI5020_PORT -> BSRRH = JXI5020_SCK;
                        delay(1);
                }       
                for(sck_cnt = 0;sck_cnt < 5;sck_cnt ++)//等待50个脉冲的消隐时间
                {       
                        JXI5020_PORT ->BSRRH  = UR14_SDO | UG14_SDO | UB14_SDO | UR13_SDO | UG13_SDO | UB13_SDO;               
                        JXI5020_PORT ->BSRRL = JXI5020_SCK;
                        delay(1);
                        //JXI5020_PORT -> BSRRH = JXI5020_SCK;
                }
                JXI5020_PORT -> BSRRH = JXI5020_SCK;
        }
//0复位
#if 1       
        JXI5020_PORT -> BSRRL = JXI5020_LE;//LE置为高电平        
        for(sck_cnt = 10;sck_cnt > 0;sck_cnt --)
        {
                JXI5020_PORT ->BSRRL = JXI5020_SCK;
                delay(1);
                JXI5020_PORT -> BSRRH = JXI5020_SCK;
                delay(0);       
        }
        JXI5020_PORT -> BSRRH = JXI5020_LE;//LE置为低电平
        //for(sck_cnt = 10;sck_cnt > 0;sck_cnt --)
        //{
        //        JXI5020_PORT -> BSRRH = JXI5020_SCK;
        //}       
#endif       

}
  加上RTC就可以实现时间和日期的显示了。
RTC_GetTime(RTC_Format_BIN,&RTC_TimeStruct);
RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct);
LED_P8x16Char(0,0,RTC_TimeStruct.RTC_Hours/10 + '0',crcolortmp,bkcolortmp);
LED_P8x16Char(0 +1*8,0,RTC_TimeStruct.RTC_Hours%10 + '0',crcolortmp,bkcolortmp);
LED_P8x16Str(0 +2*8,0,":",crcolortmp,bkcolortmp);
LED_P8x16Char(0 +3*8,0,RTC_TimeStruct.RTC_Minutes/10 + '0',crcolortmp,bkcolortmp);
LED_P8x16Char(0 +4*8,0,RTC_TimeStruct.RTC_Minutes%10 + '0',crcolortmp,bkcolortmp);
LED_P8x16Str(0 +5*8,0,":",crcolortmp,bkcolortmp);
LED_P8x16Char(0 +6*8,0,RTC_TimeStruct.RTC_Seconds/10 + '0',crcolortmp,bkcolortmp);
LED_P8x16Char(0 +7*8,0,RTC_TimeStruct.RTC_Seconds%10 + '0',crcolortmp,bkcolortmp);

LED_P8x16Char(0 +3*8,16,RTC_DateStruct.RTC_Month/10 + '0',crcolortmp,bkcolortmp);
LED_P8x16Char(0 +4*8,16,RTC_DateStruct.RTC_Month%10 + '0',crcolortmp,bkcolortmp);
LED_P8x16Str(0 +5*8,16,"-",crcolortmp,bkcolortmp);
LED_P8x16Char(0 +6*8,16,RTC_DateStruct.RTC_Date/10 + '0',crcolortmp,bkcolortmp);
LED_P8x16Char(0 +7*8,16,RTC_DateStruct.RTC_Date%10 + '0',crcolortmp,bkcolortmp);

secold = RTC_TimeStruct.RTC_Seconds;               
OSTimeDly(50, OS_OPT_TIME_DLY, &err);

  我把扫描的任务放在低优先级的任务里,循环执行,这样就可以在高优先级的任务里执行一些周期性特别长的任务,比如更新显存,读取时间、温湿度等。
  不过不要问我为什么不用FPGA,因为我觉得可以用单片机就解决的问题还是用单片机比较简单方便,包括硬件系统和软件系统。
  以上的程序还不完善,比如时序的优化,去掉一些无用的delay。
  还有就是原始数据是24bit的,每个基色为8bit,但是MBI5052是16bit的PWM,可以通过更加专业的颜色校正算法把8bit原始数据对应到这16bit的PWM值上,提升显示效果。

  接下来要做的就是用PTC CREO设计一个壳子,3D打印出来,把主板装进去,挂起来了,全部弄好后再上图。


沙发
mmuuss586| | 2017-4-8 17:56 | 只看该作者

不错;

使用特权

评论回复
板凳
yiy| | 2017-4-8 21:10 | 只看该作者
给力,是淘宝66元的那个吗

使用特权

评论回复
地板
shaniadolphin|  楼主 | 2017-4-10 09:43 | 只看该作者
yiy 发表于 2017-4-8 21:10
给力,是淘宝66元的那个吗

不知道说的是不是同一款,如果有兴趣我可以单独发给你,包括工程。
我前天才又买了一块屏,上回买的MBI5052还有一些,刚好还够一个屏,打算用来做平时活动时打羽毛球的计分板。

使用特权

评论回复
5
yiy| | 2017-4-10 10:57 | 只看该作者
shaniadolphin 发表于 2017-4-10 09:43
不知道说的是不是同一款,如果有兴趣我可以单独发给你,包括工程。
我前天才又买了一块屏,上回买的MBI50 ...

不错不错,好想法。站内消息发给我,我去看看。

使用特权

评论回复
6
gwfufu| | 2017-6-20 17:32 | 只看该作者
显示屏常规封装的脚位都是一样的,
现在都GW6808在做节能屏了,

使用特权

评论回复
7
jerry79688| | 2019-9-1 18:45 | 只看该作者
你好,有看到你的这篇关于MBI5052P4显示屏驱动的**,我试了一下,不成功,想向你请教一下,不知道是否能给点意见,非常感谢!

使用特权

评论回复
8
hu459846936| | 2020-1-1 21:40 | 只看该作者
多年过去了,不知道大佬还能不能看到这条回复,首先,感谢大佬。是您的这篇帖子,让我找到了突破方向。我在研究MBI5153,但是数据手册并不完整。看了您的这篇帖子之后,明白了这个MBI5052应该是后续芯片的早期版本。后来的数据手册都阉割掉了写入数据的时序。让人摸不着头脑。看了5052的数据手册,稍微明白了一点,如大佬能能看到回复,而且有幸您的工程文件还在的话,能否给我发一份,感激不尽。wojiushihuxq@126.com

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

15

帖子

4

粉丝