最近搞了个全彩点阵,有点伤心,,,打样的PCB质量伤不起啊,各种问题,都不太想接着做了。不知有木有感兴趣的哥们啊,共享下我的东西吧。。。
先上图:
焊好了各种芯片。。。
焊好点阵块,点阵好贵的啊。。。
用手摸一摸信号线,看到了希望啊。。。
显示ASCII,后来加入了SPI FLASH ,搞了GBK字符集,支持所有中文显示了
这个大家认识吧。。嘿嘿。。手机拍摄的效果没有人眼看上去的好,况且隔得近,这么大个点得隔几米远看起来才细腻啊。。。
这个是阿狸,嘿嘿。。。看起来不是很像大家也是知道的,32*16的分辨率啊!
原理图见附件,代码在下面:
行驱动,采用的是74HC138:
这个大家都会的,译码器。。。
void LED_SelectLine(u8 line)
{
switch(line)
{
case 0:HC138C_LOW();HC138B_LOW();HC138A_LOW(); HC138S1_HIGH();HC138S2_LOW();break;
case 1:HC138C_LOW();HC138B_LOW();HC138A_HIGH(); HC138S1_HIGH();HC138S2_LOW();break;
case 2:HC138C_LOW();HC138B_HIGH();HC138A_LOW(); HC138S1_HIGH();HC138S2_LOW();break;
case 3:HC138C_LOW();HC138B_HIGH();HC138A_HIGH(); HC138S1_HIGH();HC138S2_LOW();break;
case 4:HC138C_HIGH();HC138B_LOW();HC138A_LOW(); HC138S1_HIGH();HC138S2_LOW();break;
case 5:HC138C_HIGH();HC138B_LOW();HC138A_HIGH(); HC138S1_HIGH();HC138S2_LOW();break;
case 6:HC138C_HIGH();HC138B_HIGH();HC138A_LOW(); HC138S1_HIGH();HC138S2_LOW();break;
case 7:HC138C_HIGH();HC138B_HIGH();HC138A_HIGH(); HC138S1_HIGH();HC138S2_LOW();break;
case 8:HC138C_LOW();HC138B_LOW();HC138A_LOW(); HC138S1_LOW();HC138S2_HIGH();break;
case 9:HC138C_LOW();HC138B_LOW();HC138A_HIGH(); HC138S1_LOW();HC138S2_HIGH();break;
case 10:HC138C_LOW();HC138B_HIGH();HC138A_LOW(); HC138S1_LOW();HC138S2_HIGH();break;
case 11:HC138C_LOW();HC138B_HIGH();HC138A_HIGH(); HC138S1_LOW();HC138S2_HIGH();break;
case 12:HC138C_HIGH();HC138B_LOW();HC138A_LOW(); HC138S1_LOW();HC138S2_HIGH();break;
case 13:HC138C_HIGH();HC138B_LOW();HC138A_HIGH(); HC138S1_LOW();HC138S2_HIGH();break;
case 14:HC138C_HIGH();HC138B_HIGH();HC138A_LOW(); HC138S1_LOW();HC138S2_HIGH();break;
case 15:HC138C_HIGH();HC138B_HIGH();HC138A_HIGH();HC138S1_LOW();HC138S2_HIGH();break;
default:HC138S1_HIGH();HC138S2_HIGH();break;
}
}
列驱动采用的是德州仪器的一款IC:TLC5941,这种全彩屏一般都是用的FPGA做吧,在这我搞STM32试了下,面积不能太大。全彩驱动起来特别要速度,一个点由红绿蓝3个led组成,得控制每个led的亮度,数据量比较大呀。。。搞个小屏玩玩还是可以的。。。
void TLC_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA| RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO |
RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOE, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1 ,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
// XLAT MODE BLANK
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
}
void TLC5941_Init(void)
{
GSCLK_Init(); // Enable GSCLK
TLC_GPIO_Init(); // GPIO Init
}
u16 TLC_SendData(u16 dat)
{
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
SPI1->DR = dat;
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
return (SPI1->DR);
}
void TLC_Set(u16 *p)
{
u8 i;
/* Turn off all outputs */
BLANK_HIGH();
/* XLAT Pin set low */
XLAT_LOW();
/* NOTE : XLAT pin must be low when the MODE pin gose high-to-low or
low-to-high to change back and forth between GS_MODE and DC_MODE */
/* Enter DC_MODE */
MODE_HIGH();
/* Send dot correction data 6*16 = 96 bits */
for(i=0;i<6;i++)
{
TLC_SendData(*p);
p++;
}
/* XLAT Pin set high */
XLAT_HIGH();
/* XLAT Pin set low */
XLAT_LOW();
/* Turn on all outputs */
BLANK_LOW();
}
void TLC_Display(u16 *p)
{
u8 i;
/* Turn off all outputs */
BLANK_HIGH();
/* XLAT Pin set low */
XLAT_LOW();
/* Enter GS_MODE */
MODE_LOW();
/* Send GS data 12*16 = 192 bits */
for(i=0;i<12;i++)
{
TLC_SendData(*p);
p++;
}
/* XLAT Pin set high */
XLAT_HIGH();
/* XLAT Pin set low */
XLAT_LOW();
/* Turn on all outputs */
BLANK_LOW();
}
驱动是老老实实对着手册敲的啊,有问题望指正哈。
此外,这款IC还需要一个PWM参考时钟,在芯片速度极限内,速度越快, {MOD}彩饱和度越高,看起来越鲜艳,当然,速度一块干扰问题又来了,这里用了STM32的定时器输出方波,STM32方波速度一开快了就变三角波了,呵呵
void GSCLK_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_TIM4,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_Init(GPIOD, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = 2;//Auto-Reload Register (ARR)
TIM_TimeBaseStructure.TIM_Prescaler = (u16)(SystemCoreClock / 24000000) - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_Pulse = 2;//Capture Compare Register(CCR)
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM4, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM4, ENABLE);
TIM_Cmd(TIM4, ENABLE);
}
就这么多了,希望对大家有用,有兴趣的哥们也搞个玩玩啊。。
---------------------------------
你好,做成32行的话可能有一点点压力,如果是扫32行的话亮度就会降低,甚至可能闪屏,做成16行扫的,得增加芯片,同时单片机也要一次发送两行的数据,全彩点阵的数据量比较大。
这个东西我也研究过一下,小面积用单片机,用类似于TLC5941这样的芯片驱动,应该是不成问题的,这个原理和74HC595是一样的。如果想玩大的,这种方案是行不通的。首先TLC4951
这个芯片很贵,面积大了成本会很高,而且这个芯片也不太好买。市场上的全彩屏用的都不是这样的方案,都是专门的横流IC驱动的,像台湾聚积的。这些驱动IC原理和74HC595也类似,
595是恒压,这个是横流,一个是16通道,一个是8通道。用这些芯片做,成本可以降低很多,这些芯片一般价格低于1元。
可能你会有一个疑问,74HC595我们平时用的时候输出都是 1 和 0 两种状态,那怎么让74HC595产生半亮类似于PWM效果呢?用专业的话讲就是怎么产生灰度。
在这里可以充分的利用74HC595的OE使能脚,用PWM控制OE即可。例如我要让接在595的Q0脚LED亮度为1/16,Q1的亮度为2/16,Q2为3/16 ...... 那么从Q0 ~ Q2接的LED亮度依次增强。
此时可以将OE的PWM分为4种,分别为1/16,2/16,4/16,8/16。那么Q0可由第一种PWM表现出来,Q1可由第二种PWM表现出来,Q3可由第一种和第二种PWM叠加表现出来,依次类推....
所以一帧数据我们需要发送四次,同时每次的OE占空比都不同,这样一帧下来后,给人的感觉就是每个led的亮度都不一样。用此种方法控制RGB三原 {MOD},就可以实现全彩了。这只是基本原理,
你可以在此基础上拓展出更加高效的算法出来。
这样也会带来一个问题,平时发送一次的数据,要分四次发送,这样要求处理器性能更强。如果是用STM32驱动,小面积应该是没有问题的。
74HC595是恒压的,而且是8通道,可能你想用专门做全彩点阵的驱动IC来做,横流16通道,可以带来更均匀的亮度以及更简单的布线。我了解的几款台湾聚积的芯片,和595还是有一些区别的,
这类芯片含有一些LED专门用的命令信号,而这些命令的发送与获得,是靠时钟的脉冲数和一根专用线实现的,也就是说SPI在发送一个字节的第几位时,你得在另外一根信号线上给一个上升/下降沿。这样也给我们带来一个麻烦事,就是STM32的硬件SPI口不能配置成这种芯片这样的时序,那么软件模拟的话速度要大打折扣了。
所以要有一个“定制”的这样的逻辑帮你刷屏就一切都好办了,这应该也就是为什么那些全彩点阵控制卡全部是FPGA做的原因了吧。
说了这么多,总结一下吧。哥们如果你有兴趣玩这个,可以尝试用CPLD,FPGA这样的器件去驱动。
用LED专门的驱动芯片,搞一片SDRAM作为点阵屏的缓存,用CPLD/FPGA源源不断的产生这样的“刷屏”逻辑,把SDRAM的数据往屏上搬,那么就可以保证不闪屏和高亮度。
同时你可以用CPLD/FPGA搞一个兼容STM32的FSMC的接口,那么就和你玩LCD是一样的了,速度也很快了。甚至FPGA搞一个SPI口,你用51单片机驱动这个屏都会很爽了。
--------------------------------
!!!太感谢了!!发了这么多!!!!!感谢!!!
我目前的想法是
单片机是stm32,因为是刚学的,正好做个东西巩固一下,也算边做东西边前进。
列驱动是TLC5941。
行驱动是74HC138+APM4953。
点阵是8*32的全彩点阵(买了4个8*8的),
准备弄成16行的,STM32倍频到72M,这样应该频率够了(纯感觉,自己也不太清楚)
基本的就是这些。
现在主要有两个问题:
1、TLC5941和APM4953我查都是输出电流型的,那我应该买共阳极的点阵屏还是共阴极的点阵屏啊?
2、我想配个小的锂电池,不插电的时候也能撑一段时间,这个一般弄个多大容量的啊
一周热门 更多>