先上文件:https://pan.baidu.com/s/1pB9HZkxn0LEM-tDX2qDNtA 提取码: 4nra
最近单片机课程要做课设,于是本人决定设计一款用STM32F103C8T6驱动的点阵屏,目前方案还在完善,先发一版方案(附简单驱动代码及仿真)
1. 点阵屏
16X16点阵屏需要由四个8X8点阵屏组成,我用的是共阴极,原理如下:
COL与ROW分别控制点阵屏的列与行,可以看出,COL置1、ROW置0可以点亮,例如将第一列置1,第一行置0,则左边第一个LED亮。
如果用IO直接控制点阵屏,4个点阵屏需要占用64个引脚,而且驱动电流也不够。因此本文用74HC595移位寄存器控制列,用74HC138解码器控制行,最终只需占用8个IO,关于这两个芯片的原理,相信大多数同学都知道,后面我也会出文章讲解。
2. 74HC595
接线图如下:
74HC595 | |
SHCP | PA0 |
STCP | PA1 |
DS | PA2 |
使用两个74HC595级联,每次向U2(第一个)传入16个数据,因为一个74HC595只能寄存8个数据,多余的8个会通过Q7`发送给U3(第二个)。
如下图所示,DS(PA2)为传入的数据,每次捕捉到SHCP(PA0)的上升沿便会向寄存器写入一个数据,当读到STCP(PA1)上升沿,则输出数据。
void W74HC595_WriteByte(u16 Byte)
{
u8 i;
for(i=0;i<16;i++)
{
if(Byte & 0x8000>>i) GPIO_SetBits(GPIOA, GPIO_Pin_2);//移位读传入的Byte,1则亮
else GPIO_ResetBits(GPIOA, GPIO_Pin_2);
GPIO_SetBits(GPIOA, GPIO_Pin_0); //SHCP上升沿将数据写入寄存器
GPIO_ResetBits(GPIOA, GPIO_Pin_0);
}
GPIO_SetBits(GPIOA, GPIO_Pin_1); //STCP上升沿将数据从寄存器输出
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
}
3. 74HC138
接线图:
74HC138 | |
A0 | PA4 |
A1 | PA5 |
A2 | PA6 |
E1(第一个)/E3(第二个) | PA7 |
E2 | PA8 |
74HC138读真值表,当E1、E2、E3分别为0、0、1时,解码器工作,否则解码器不工作。
PA8接E2,可以看出当PA8为1时两个解码器都不工作,用于将数据写入后打开再关闭解码器,有效取消残影。
PA7接第一个解码器(U4)的E1,接第二个(U5)的E3,当E1=0,第一个解码器工作,当E3=1,第二个解码器工作。
PA4、PA5、PA6用于输入,电路及代码如下:
void W74HC138_WriteByte(u8 h)
{
u8 a,b,c;
switch(h)//笨方法,将16种都列举出来
{
case 0: a=1; b=1; c=1; break;
case 1: a=0; b=1; c=1; break;
case 2: a=1; b=0; c=1; break;
case 3: a=0; b=0; c=1; break;
case 4: a=1; b=1; c=0; break;
case 5: a=0; b=1; c=0; break;
case 6: a=1; b=0; c=0; break;
case 7: a=0; b=0; c=0; break;
case 8: a=1; b=1; c=1; break;
case 9: a=0; b=1; c=1; break;
case 10: a=1; b=0; c=1; break;
case 11: a=0; b=0; c=1; break;
case 12: a=1; b=1; c=0; break;
case 13: a=0; b=1; c=0; break;
case 14: a=1; b=0; c=0; break;
case 15: a=0; b=0; c=0; break;
}
if(h<=7) //H0-H7
{
GPIO_ResetBits(GPIOA, GPIO_Pin_7);//使能E3
GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)(a));
GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)(b));
GPIO_WriteBit(GPIOA, GPIO_Pin_6, (BitAction)(c));//分别写入数据
GPIO_ResetBits(GPIOA, GPIO_Pin_8);//使能E2,也就是打开138
GPIO_SetBits(GPIOA, GPIO_Pin_8);//关闭138
}
else if(h>=8 && h<=15) //H8-H15
{
GPIO_SetBits(GPIOA, GPIO_Pin_7);//使能E1
GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)(a));
GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)(b));
GPIO_WriteBit(GPIOA, GPIO_Pin_6, (BitAction)(c));//分别写入数据
GPIO_ResetBits(GPIOA, GPIO_Pin_8);//使能E2,也就是打开138
GPIO_SetBits(GPIOA, GPIO_Pin_8);//关闭138
}
else
{
GPIO_SetBits(GPIOA, GPIO_Pin_8);//关闭138
}
}
4. 控制代码
本代码由74HC138控制行、74HC595控制列
void Show(u8 h, u16 Byte)//h为行,Byte为该行显示LED的16进制
{
W74HC595_WriteByte(Byte);
W74HC138_WriteByte(h);
}
代码实现了第h行亮的灯为Byte,举个例子:
Show(1, 0x1081);
0x1081 = 0001 0000 1000 0001
因此该代码实现了第1行,第4、9、16个灯亮。
在主函数中只需While遍历16行即可实现图像的显示。
5. 取字模
使用PCtoLCD2002取字模,软件也在最上面的链接中一起给出。
首先左上角新建图像,大小为16X16。
在模式中,配置如下:
然后在画布上整自己需要的图案再生成字模,例如我随便生成了一个,复制下来是这样:
{0x80,0x43,0x80,0x42,0x80,0x42,0xC0,0xC2,0x40,0xC4,0x40,0xC4,0x41,0xC4,0x61,0x24},
{0x22,0x28,0x22,0x28,0x26,0x28,0x34,0x38,0x18,0x30,0x18,0x10,0x18,0x00,0x00,0x00}
将标红的大括号删除即是我们可以使用的字模,程序如下:
u8 showwhat[32] =
{0x80,0x43,0x80,0x42,0x80,0x42,0xC0,0xC2,0x40,0xC4,0x40,0xC4,0x41,0xC4,0x61,0x24,
0x22,0x28,0x22,0x28,0x26,0x28,0x34,0x38,0x18,0x30,0x18,0x10,0x18,0x00,0x00,0x00};
int main(void)
{
u8 i;
Led_Init();
while(1)
{
i++;
if(i >= 16) i=0;
Show(i, showwhat[i*2]<<8|showwhat[i*2+1]);//显示行列
}
}
这样即可实现简单图像的显示,由于仿真频率的问题,显示为一行行显示,实物则不会这样,后续我还会跟进实物,有问题欢迎指出!