2008-01-21 17:26:00 mybirdsky 阅读数 2024
  • 51单片机也能玩TFT彩屏-第2季第3部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第3个课程,主要讲解TFT液晶显示器的原理和编程显示线条、文字、图片等。本课程的学习目标是对较复杂的TFTLCD的编程有所掌握,为以后更进一步学习显示打好更好基础。

    2686 人正在学习 去看看 朱有鹏
2007-12-25 12:34:26

字体变小 字体变大
用51单片机控制led显示汉字,电路中行方向由p0口和p2口完成扫描,由于p0口没有上拉电阻,因此接一个4.7k*8的排阻上拉。 如没有排阻,也可用8个普通的4.7k 1/8w电阻。为提供负载能力,接16个2n5551的NPN三极管驱动。
列方向则由4—16译码器74LS154完成扫描,它由89C51的P1.0---P1.3控制。同样,驱动部分则是16个2N5401的三极管完成的。
电路的供电为一片LM7805三端稳压器,耗电电流为100ma左右。

采用一块12*20cm的万能电路板,应当选用质量好些的发光管,(否则有坏点现象, 更换起来较麻烦)首先将256个发光管插入电路板,注意插入方向,同时使高度一致,行方向直接焊接起来, 列方向则搭桥架空焊接,完成后用万用表测试一下如有不亮的更换掉。

然后找一个电脑硬盘的数据线, 截取所需的长度,分别将行,列线引出至电路的相关管脚即可。原理图为了简洁,故只画出了示意图,行列方向只画出了2个三极管,屏幕只画出4个发光管, 实际上发光管为256只,三极管行列方向各16只,一共32只。焊接过程认真仔细一天时间即可完成全部制作。将程序编译后烧写入89c51, 插入40pin Ic座,即可看到屏幕轮流显示:“倚天一出宝刀屠龙”。

当然,你可将程序的汉字代码部分更换为您所需要的代码即可显示你所需要的汉字。

程序清单:

ORG 00H

LOOP: MOV A,#0FFH ;开机初始化,清除画面

MOV P0,A ;清除P0口

ANL P2,#00 ;清除P2口

MOV R2,#200

D100MS: MOV R3,#250 ;延时100毫秒

DJNZ R3,$

DJNZ R2,D100MS

MOV 20H,#00H ;取码指针的初值

l100: MOV R1,#100 ;每个字的停留时间

L16: MOV R6,#16 ;每个字16个码

MOV R4,#00H ;扫描指针清零

MOV R0,20H ;取码指针存入R0

L3: MOV A,R4 ;扫描指针存入A

MOV P1,A ;扫描输出

INC R4 ;扫描指针加1,扫描下一个

MOV A,R0 ; 取码指针存入A

MOV DPTR,#TABLE ;取数据表的上半部分的代码

MOVC A,@A+DPTR

MOV P0,A ; 输出到P0

INC R0 ;取码指针加1,取下一个码。

MOV A,R0

MOV DPTR,#TABLE ;取数据表下半部份的代码

MOVC A,@A+DPTR

MOV P2,A ;输出到P2口

INC R0

MOV R3,#02 ;扫描1毫秒

DELAY2: MOV R5,#248 ;

DJNZ R5,$

DJNZ R3,DELAY2

MOV A,#00H ;清除屏幕

MOV P0,A

ANL P2,#00H

DJNZ R6,L3 ;一个字16个码是否完成?

DJNZ R1,L16 ;每个字的停留时间是否到了?

MOV 20H,R0 ;取码指针存入20H

CJNE R0,#0FFH,L100 ;8个字256个码是否完成?

JMP LOOP ;反复循环

TABLE :

;汉字“倚”的代码

db 01H,00H,02H,00H,04H,00H,1FH,0FFH

db 0E2H,00H,22H,00H,22H,0FCH,26H,88H

db 2AH,88H,0F2H,88H,2AH,0FAH,26H,01H

db 63H,0FEH,26H,00H,02H,00H,00H,00H

;以下分别输入天,一,出, 宝,刀,屠,龙,的代码,略。

end

2019-04-21 17:31:30 weixin_44212493 阅读数 775
  • 51单片机也能玩TFT彩屏-第2季第3部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第3个课程,主要讲解TFT液晶显示器的原理和编程显示线条、文字、图片等。本课程的学习目标是对较复杂的TFTLCD的编程有所掌握,为以后更进一步学习显示打好更好基础。

    2686 人正在学习 去看看 朱有鹏

51单片机 16X192点阵程序动态显示任意汉字

在这里插入图片描述
在这里插入图片描述
程序参考源代码如下:

#include<AT89X52.H>
sbit ST=P3^5;
sbit E1=P3^4;
sbit MR=P3^7;
char cashe[12];
char code wd[12][16]={

{0xFF,0xC0,0xFE,0xFE,0xFE,0xFE,0x80,0xFE,0xFD,0xFD,0xFB,0xF7,0xEF,0xDF,0x3F,0xFF},
{0xFF,0x03,0xFF,0xFF,0xFF,0xFF,0x01,0x7F,0x7F,0x7F,0x7F,0x7F,0x7D,0x7D,0x81,0xFF},/“无”,0/
/* (16 X 16 , 宋体 )*/

{0xDF,0xDF,0xDF,0xCF,0x57,0x58,0x5F,0xDF,0xDE,0xDE,0xDE,0xDD,0xDD,0xDB,0xDB,0xD7},
{0x7F,0x6F,0x73,0x77,0x7F,0x01,0x5F,0x5F,0xDF,0xDF,0xDF,0xDF,0xDD,0xDD,0xE1,0xFF},/“忧”,1/
/* (16 X 16 , 宋体 )*/

{0xFE,0xFE,0xFE,0xC0,0xDE,0xDE,0xC0,0xDE,0xDE,0xDE,0xC0,0xDE,0xFE,0xFE,0xFF,0xFF},
{0xFF,0xFF,0xFF,0x07,0xF7,0xF7,0x07,0xF7,0xF7,0xF7,0x07,0xF7,0xFD,0xFD,0x01,0xFF},/“电”,2/
/* (16 X 16 , 宋体 )*/

{0xFF,0xC0,0xFF,0xFF,0xFF,0xFE,0xFE,0xFE,0x00,0xFE,0xFE,0xFE,0xFE,0xFE,0xFA,0xFD},
{0xFF,0x0F,0xDF,0xBF,0x7F,0xFF,0xFF,0xFB,0x01,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},/“子”,3/
/* (16 X 16 , 宋体 )*/

{0xFF,0x83,0xBB,0xAB,0xAA,0xAA,0xA9,0xAB,0xAB,0xAA,0xEE,0xD7,0xDB,0xBB,0x7F,0xFF},
{0x7F,0x3F,0x7F,0x01,0xFD,0xFD,0xBD,0xBD,0x5D,0xED,0x05,0xED,0xFD,0xFD,0xEB,0xF7},/“购”,4/
/* (16 X 16 , 宋体 )*/

{0xEF,0xEF,0xAF,0xAE,0x82,0xAD,0x6B,0xEB,0xE6,0xCD,0x2B,0xEF,0xEE,0xED,0xEB,0xFF},
{0x7F,0x7F,0x7F,0x03,0xAB,0xAB,0x6B,0x6B,0xDB,0xDB,0xBB,0x7B,0xFB,0xFB,0xD7,0xEF},/“物”,5/
/* (16 X 16 , 宋体 )*/

};

void del(int i)//============================//延时程序
{while(i–);}

aline() ////=======================发送一行的显示程序
{
char i=0;
TI=0;
for(i=0;i<12;i++)
{SBUF=cashe[i];while(~TI);TI=0;} //将缓存中的信息转存入595的存储器中,到此不显示
}

main()
{
int m=0,n=0;
TI=0;
SM0=0;
SM1=0;
E1=0;
while(1)
for(m=0;m<16;m++) //共有16行 循环16次显示这16行 串行的595送出行的数据
{ //由74hc154选中要显示的行

for(n=0;n<12;n++)         //这个for循环用来向缓存数组中装载要显示的内容
	{cashe[11-n]=wd[n][m];}  //将第m个字的第n行信息装载  ,因为595串接 数据第一个进去的会在最后一个595中,最后进去的会在第一个595中
aline();     //将缓存中的一行信息载入595缓存中
ST=0;ST=1; //595产生上升沿 输出595锁存的数据
P2=m;  //选中要显示的行输出数据
  
del(100);//延时一段时间,以造成视觉暂存效应

  }

}

2014-04-10 15:14:57 huang20083200056 阅读数 4387
  • 51单片机也能玩TFT彩屏-第2季第3部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第3个课程,主要讲解TFT液晶显示器的原理和编程显示线条、文字、图片等。本课程的学习目标是对较复杂的TFTLCD的编程有所掌握,为以后更进一步学习显示打好更好基础。

    2686 人正在学习 去看看 朱有鹏

51单片机开发系列四

LED点阵扫描显示

象棋小子    1048272975

LED点阵屏发光亮度强,指示效果好,可以制作运动的发光图文,更容易吸引人的注意力,信息量大,随时更新,有着非常好的广告和告示效果。笔者此处就LED点阵屏动态扫描显示作一个简单的介绍。

1. LED点阵屏显示原理概述

图1-1为一种8x8的LED点阵单色行共阳模块的内部等效电路图,对于红光LED其工作正向电压约为1.8v,其持续工作的正向电流一般10ma左右,峰值电流可以更大。如下图,当某一行线为高电平而某一列线为低时,其行列交叉的点就被点亮,当某一行线为低电平时,无论列线如何,对应的这一行的点全部为暗。LED点阵屏显示就是通过一定的频率进行逐行扫描,数据端不断输入数据显示,只要扫描频率足够高,由于人眼的视觉残留效应,就可以看到完整的文字或图案信息。通常有4、8、16线扫描方式,扫描行数越少,点阵的显示亮度越好,但相应硬件数据寄存器需求也越多。


图1-1 点阵内部原理图

2. 硬件设计

微控制器的IO口均不能流过过大的电流,LED点亮时有约10ms的电流,因此LED点阵引脚不要直接接单片机IO口,应先经过一个缓冲器74HC573。单片机IO口只需很小的电流控制74HC573即可间接的控制LED点阵某一行(或某一列),而74HC573输出也能负载约10ms的电流。设置LED每点驱动电流为ID =15ma,这个电流点亮度好,并且有一定的裕度,即使电源输出电压偏高也不会烧毁LED,限流电阻值

R = (VCC- VCE – VOL – VLED) / ID

VCC为5v供电,VCE为三极管C、E间饱和电压,估为0.2v, VOL为74hc573输出低电平时电压,不同灌电流,此值不一样,估为0.2v,具体查看规格书,VLED为红光驱动电压,估为1.7v,根据上式可算出限流电阻为R = 200R。

LED点阵屏需接收逐个扫描信号,扫描到相应列(或行),对应的列(或行)数据有效,即显示这一列(或行)的信息。一般产生扫描信号是需要采用专门的译码器,如三线八线译码器74HC138,这样可硬件保证任意时刻只有一列(或一行)正在扫描,并且可减少微控制器的IO口占用。市面上的51开发板对于LED点阵屏的设计基本都没有采用译码器,直接用单片机IO产生扫描信号,为兼容软件,笔者此处也不加译码器,软件保证IO口产生相应的扫描信号。

当某一列(或一行)LED点均点亮时,电流约15max8=90ma流过这一列(或一行)公共端,微控制器IO口无法直接驱动这个电流,需加三极管驱动,由于51单片机低电平灌电流较大,因此适合采用PNP三极管作为驱动。三极管基极电流设为2ma即可让三极管饱和,最大驱动电流远大于90ma。基极偏置电阻阻值

Rb =(VCC - VEB – VOL) / IB

VCC为5v供电,VEB为三极管E、B间的导通电压0.7v,VOL为单片机IO口输出低电平时电压,可根据规格书估为0.2v,故Rb = 2k即可。


图2-1 8X8共阴LED点阵原理图

3. 驱动实现

LED点阵数据口接P0口,扫描选择线接P2口的0~7位。对于动态扫描,都是有一个扫描频率的,LED屏扫描频率下限为50HZ,低于一定的扫描频率,显示会闪烁。频率过高,则亮度较差且占用cpu资源。一般整个屏扫描一遍时间为约10ms较合适(即扫描频率100HZ),我们采用的是8线扫描方式,每一行点亮时间为1.5ms,扫描一遍为12ms。为保证这个刷新频率,通常是通过定时器来周期性进行点阵屏刷新。

显示屏显示往往会涉及到画点、画线、画图等复杂的运算,改变屏幕的信息,只需处理显存中的数据,因此对于显示屏,是需要开辟出一块内存空间作为显存使用的。8X8点阵每个点可用1 bit表示,一行1字节,显存8字节即可。由于点阵屏像素点太少,没有必要实现画线、画图等复杂操作,笔者此处仅对点阵屏画点、文字上下左右移动进行代码实现。

点阵屏动态显示功能模块文件Matrix.c内容如下:

#include"reg52.h"

#include"Matrix.h"

 

// 每个LED点需1位保存,8X8点阵需8字节显存

static unsigned char FrameBuffer[8];

 

// 外部模块通过该函数获得显存内存位置进行处理

unsigned char *MatrixGetBuffer()

{

    return FrameBuffer;

}

 

// 点阵刷新,保证以一定周期调用刷新

void MatrixScan()

{

    static unsigned char Select =0; // 记录扫描的选择线

    // 列数据输出到点阵数据端口

    MatrixOutputData(FrameBuffer[Select]);

    // 扫描信号输出到点阵扫描选择端口

    MatrixOutputSelect(Select);

    Select++; // 进入到下一行扫描

    if (Select >= 8) {

        Select= 0; // 所有行已扫描,回到第一行再次开始扫描

    }

}

 

// LED点阵屏打点函数,对(x, y)位置进行亮,灭,状态取反

voidMatrixSetPoint(unsigned char x, unsigned char y, unsigned char Operation)

{

    if (x>7 || y>7) { // 位置保证在点阵屏区域内

        return;

    }

    switch (Operation) {

    case SET: // (x, y)位置置位,灯灭

        FrameBuffer[x] |= 1<< y;

        break;

    case CLEAR: // (x, y)位置清零,灯亮

        FrameBuffer[x] &= ~(1<< y);

        break;

    case NEGATE: // (x, y)位置取反,灯状态改变

        FrameBuffer[x] ^= 1<< y;

        break;

    default:

        break;

    }

}

 

// LED点阵屏清屏,显存对应1的位置,灯灭,0相应的灯才点亮

voidMatrixClearScreen()

{

    unsigned char i;

    for (i=0; i<8; i++) {

        FrameBuffer[i] = 0xff;

    }

}

 

// 点阵平移,上下左右四个方向平移1,平移空缺位置用数据Filling填充

void MatrixMove(unsignedchar Direction, unsigned char Filling)

{

    unsigned char i;

    switch (Direction) { // 判断平衡的方向

    case MOVE_UP: // 向上平移1,每列数据第7位移到第6位,如此类推

        for (i=0; i<8; i++) {

            FrameBuffer[i] =(FrameBuffer[i]>>1) | ((Filling<<(7-i))&0x80);

        }

        break;

    case MOVE_DOWN: // 向下平移1,每列数据第0位移到第1位,如此类推

        for (i=0; i<8; i++) {

            FrameBuffer[i]= (FrameBuffer[i]<<1) | ((Filling>>i)&0x01);

        }

        break;

    case MOVE_LEFT: // 向左平移1,右一列的数据移到当前列中,如此类推

        for (i=0; i<7; i++) {

            FrameBuffer[i] = FrameBuffer[i+1];

        }

        FrameBuffer[i] = Filling;

        break;

    case MOVE_RIGHT: // 向右平移1,左一列的数据移到当前列中,如此类推

        for (i=7; i>=1; i--) {

            FrameBuffer[i] = FrameBuffer[i-1];

        }

        FrameBuffer[i] = Filling;

        break;

    default:

        break;

    }

}

 

我们在点阵屏模块头文件Matrix.h中实现模块的宏定义及接口访问宏实现,使之方便移植及修改接口配置。模块头文件同时也引出模块的接口函数,如MatrixScan()为点阵屏刷新函数,需周期性调用刷新点阵屏显示。点阵屏动态显示功能模块文件Matrix.h内容如下:

#ifndef__Matrix_H__

#define__Matrix_H__

 

#ifdef__cplusplus

extern"C" {

#endif

 

#define SET         0x1 //置1操作

#define CLEAR           0x2 // 清0操作

#define NEGATE      0x3 //取反操作

 

#defineMOVE_UP     0x1 // 向上平移1

#defineMOVE_DOWN   0x2 // 向下平移1

#defineMOVE_LEFT   0x3 // 向左平移1

#defineMOVE_RIGHT 0x4 // 向右平移1

 

// 列数据输出到P0口

#defineMatrixOutputData(Dat) {P0 = (Dat);}

// P2口输出对应列的扫描选择线,低有效

#defineMatrixOutputSelect(Select) {P2 = ~(1<<(Select));}

 

 

voidMatrixClearScreen(void);

voidMatrixMove(unsigned char Direction, unsigned char Filling);

unsigned char*MatrixGetBuffer(void);

voidMatrixScan(void);

voidMatrixSetPoint(unsigned char x, unsigned char y, unsigned char Operation);

 

#ifdef__cplusplus

}

#endif

 

#endif/*__Matrix_H__*/

 

外部应用通过引入点阵屏的模块头文件Matrix.h来实现调用点阵屏驱动函数,简单测试调用(心形在点阵屏内随机平移)实现如下:

#include"reg52.h"

#include"Matrix.h"

 

// 心形坐标数据

static unsigned charcode HeartShape[][2] = {

{3, 3}, {4, 2}, {5,3}, {5, 4}, {4, 5},

{3, 6}, {2, 5}, {1,4}, {1, 3}, {2, 2},

};

 

// 以定时器时间为计时标准,记录时间间隔

static volatileunsigned int SystemTick = 0;

 

// 定时器1.5ms中断处理进行数码管刷新

void T0_Interrupt()interrupt 1

{

    TH0 = (65536-1500) / 256;

    TL0 = (65536-1500) % 256;

    SystemTick++; // 记录时间间隔

    MatrixScan(); // 刷新数码管

}

 

void T0_Init()

{

    TMOD = 0x01; // 定时器0工作方式1

    // 1.5ms计时中断(12M)

    TH0 = (65536-1500) / 256;

    TL0 = (65536-1500) % 256;

    ET0 = 1; // 定时器T0中断允许

    EA = 1; // 总中断允许

}

 

 

void main()

{

    unsigned char *pBuffer;

    unsigned char State = 0;

    unsigned char Point;

    unsigned char Direction;

    unsigned char DataAnd;

    unsigned char i;

    // 定时器初始化

    T0_Init();

    // 获得点阵显存,以作数据处理

    pBuffer = MatrixGetBuffer();

    // 点阵屏清屏

    MatrixClearScreen();

    // 开启定时器进行计时以及点阵扫描

    TR0 = 1;

 

    Point = 0;

    while(1) {

       switch (State) {

       case 0:    //状态0为逐点打出心形

           if (SystemTick > 334) { // 500ms打心形的一个点

              SystemTick = 0;

           MatrixSetPoint(HeartShape[Point][0],HeartShape[Point][1], CLEAR);

              Point++;

              if (Point >sizeof(HeartShape)/sizeof(HeartShape[0])) {

                  State = 1; // 心形打完,进入状态1,是否到边界判断

                  Direction = TL0& 0x3; // 随机得出心形的移动方向

              }                

           }

           break;

 

       case 1:    // 状态1为心形是否移动到点阵屏边界的判断

           switch (Direction) { // 移动方向判断是否到相应方向的边界

           case 0:    // 左边界判断

              // 第一列的点有一个亮,则认为图形到了左边界

              if (pBuffer[0] !=0xff) {

                  Direction = TL0& 0x3; // 重新选择移动方向

              } else {

                  State = 2; // 未到左边界,进入状态2进行左平移

              }

              break;

           case 1:    // 右边界判断

              // 第八列的点有一个亮,则认为图形到了右边界

              if (pBuffer[7] !=0xff) {

                  Direction = TL0& 0x3; // 重新选择移动方向

              } else {

                  State = 2; // 未到右边界,进入状态2进行右平移

              }

              break;

           case 2:    // 上边界判断

              // 所有列的第一行点有一个亮,则认为图形到了上边界

              DataAnd = 0xff;

              for (i=0; i<8; i++) {

                  DataAnd &= pBuffer[i];

              }

              if (DataAnd & 0x1) {

                  State = 2; // 未到上边界,进入状态2进行上平移                           

              } else {

                  Direction = TL0& 0x3; // 重新选择移动方向

              }

              break;

           case 3:    // 下边界判断

              // 所有列的第八行点有一个亮,则认为图形到了下边界

              DataAnd = 0xff;

              for (i=0; i<8; i++) {

                  DataAnd &= pBuffer[i];

              }

              if (DataAnd & 0x80) {

                  State = 2; // 未到下边界,进入状态2进行下平移                           

              } else {

                  Direction = TL0& 0x3; // 重新选择移动方向

              }

              break;

           default:

              break;

           }

           break;

 

       case 2:    // 状态2为对点阵屏平移

           if (SystemTick < 667){  // 1s平移1次

              continue;

           }

           SystemTick = 0;

           switch (Direction) {

           case 0:    // 左平移,平移后的空缺位置灭

              MatrixMove(MOVE_LEFT, 0xff);

              break;

           case 1: // 右平移,平移后的空缺位置灭

              MatrixMove(MOVE_RIGHT,0xff);

              break;

           case 2:    // 上平移,平移后的空缺位置灭

              MatrixMove(MOVE_UP, 0xff);

              break;

           case 3:    // 下平移,平移后的空缺位置灭

              MatrixMove(MOVE_DOWN, 0xff);

              break;

           default:

              break;

           }

           State = 1; // 平移后再进入状态1进行边界检测

           break;

 

       default:

           break;

       }  

    }

}

附录:

此章节的Keil工程,包含源码,Preteus仿真,包含仿真电路,可直接查看效果,Matrix.rar。

http://pan.baidu.com/s/1dDchpYh

 

 

2018-06-01 18:15:55 nanfeibuyi 阅读数 3298
  • 51单片机也能玩TFT彩屏-第2季第3部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第3个课程,主要讲解TFT液晶显示器的原理和编程显示线条、文字、图片等。本课程的学习目标是对较复杂的TFTLCD的编程有所掌握,为以后更进一步学习显示打好更好基础。

    2686 人正在学习 去看看 朱有鹏

单片机 LED点阵

一、简述

     使用8×8LED点阵显示汉字。向上滚动"中华"两个汉字。

     文件打包:链接: https://pan.baidu.com/s/1oHSAIY6qVA7qFFWUvMvJEA 密码: snyg

二、效果


三、工程文件结构

1、Keil工程


2、仿真电路图


四、代码

88led.c文件

#include<reg51.h>
#define uint unsigned int
#define uchar unsigned char
uchar code led[]={0xEF,0xEF,0x83,0xAB,0xAB,0x83,0xEF,0xEF,0xD5,0x93,0x55,0xC0,0x00,0xEF,0xEF,0xEF};//汉字“中华” 点阵码
uchar code  led_w[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//对应1~8行,赋给P2口,控制在哪一行显示
/********************************************************************/
//函数名:delay_1ms(uint x)
//功能:利用定时器0精确定时1ms; 自加 time_t的值为后面时间调整函数服务
//调用函数:
//输入参数:x,1ms计数
//输出参数:
//说明:延时的时间为1ms乘以x 
/********************************************************************/
void delay_1ms(uint x)
{
	TMOD=0X01;//开定时器0,工作方式为1
	TR0=1;//启动定时器0;
	while(x--)
	{
		TH0=0Xfc;//定时1ms初值的高8位装入TH0
		TL0=0X18;//定时1ms初值的低8位装入TL0
		while(!TF0);//等待,直到TF0为1
		TF0=0;	   //重置溢出位标志
	}		
	TR0=0;//停止定时器0;
}
/**********************************************************/
//函数名:ledplay()
//功能:led点阵显示程序
//调用函数:
//输入参数:
//输出参数:
//说明:
/**********************************************************/
void ledplay()
{
	uchar i,y,j;
	y=0; //稳定显示电平,平滑滚动,每8行数据显示10次
	j=0;//数据偏移,每次偏移1位
	while(1)//实现汉字向上滚动效果
	{
		for(i=0;i<8;i++)//显示8行数据
		{
			P0=0xFF;//消除上次电平的影响		
			P2=led_w[i];//控制显示行
			P0=led[i+j];//行电平数据
			delay_1ms(3);//延时3ms
		}
		y++;
		if(y>9)
		{
			P0=0xFF;//消除上次电平的影响
			delay_1ms(1);//延时,确保消除上次电平的影响
			y=0;
			j++;
			if(j>8)	//"中华"二字一共16行电平数据(0~15),i+j要<15
				j=0;
		}
	}

}
/**********************************************************/
//主程序
/**********************************************************/
void main()
{
	ledplay();//调用显示程序;
}

五、总结


2014-06-25 10:34:05 XinYaping 阅读数 4320
  • 51单片机也能玩TFT彩屏-第2季第3部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第3个课程,主要讲解TFT液晶显示器的原理和编程显示线条、文字、图片等。本课程的学习目标是对较复杂的TFTLCD的编程有所掌握,为以后更进一步学习显示打好更好基础。

    2686 人正在学习 去看看 朱有鹏

很简陋的一段小程序,演示如何显示点阵字库。有时间的时候再详细解释。

#include <stdio.h>
#include <stdlib.h>

struct HzkInfoStruct
{
	int HzkSelect;
	int HzkSquare;
	char * fileName;
	FILE * file;
	int martixBytesCount;
	unsigned char *pMatrix;
};

typedef struct HzkInfoStruct HzkInfo;

void SelectHZK(HzkInfo * pHzkInfo);
void LoadHzkInfo(HzkInfo * pHzkInfo);
void CleanupHzkInfo(HzkInfo hzkInfo);
void GetQuWh(unsigned char *chineaseWord, int * qu, int * wh);
void FillMartix(HzkInfo * pHzkInfo, const int qu, const int wh);
void PrintMartix(HzkInfo hzkInfo);

int _tmain(int argc, _TCHAR* argv[])
{
	unsigned char chinease[3] = "京";
	HzkInfo hzkInfo;
	int qu;
	int wh;

	SelectHZK(&hzkInfo);

	if(hzkInfo.file == NULL || hzkInfo.pMatrix == NULL)
	{
		printf("HZK loading failed. Will exit now.\n");
		goto EXIT;
	}

	GetQuWh(chinease, &qu, &wh);
	FillMartix(&hzkInfo, qu, wh);
	PrintMartix(hzkInfo);

	EXIT:
	CleanupHzkInfo(hzkInfo);
	return 0;
}

void GetQuWh(unsigned char *chineaseWord, int * qu, int * wh)
{
	*qu = chineaseWord[0] - 0xa0;
	*wh = chineaseWord[1] - 0xa0;
}

void FillMartix(HzkInfo * pHzkInfo, const int qu, const int wh)
{
	fseek(pHzkInfo->file, (94 * (qu - 1) + (wh - 1)) * pHzkInfo->martixBytesCount, SEEK_SET);
	fread(pHzkInfo->pMatrix, pHzkInfo->martixBytesCount, 1, pHzkInfo->file);
}

void PrintMartix(HzkInfo hzkInfo)
{
	int i, j, k;
	int i_steps = hzkInfo.HzkSquare / 8;
	unsigned char * pMatrix = hzkInfo.pMatrix;

	printf("\n");

	for (j = 0; j < hzkInfo.HzkSquare; j++)
	{
		for (i = 0; i < i_steps; i++)
		{
			for (k = 0; k < 8; k++)
			{
				if (pMatrix[i] & (0x80 >> k))
				{
					printf("%c ", '*');
				}
				else
				{
					printf("  ");
				}
			}
		}

		pMatrix += i_steps;
		printf("\n");
	}

	printf("\n");
}

void SelectHZK(HzkInfo * pHzkInfo)
{

SELECT:

	printf("Please select [0: Exit; 1: HZK16; 2: HZK32;] : ");
	scanf_s("%d", &(pHzkInfo->HzkSelect));

	if(pHzkInfo->HzkSelect == 0)
	{
		exit(0);
	}

	if(pHzkInfo->HzkSelect < 1 || pHzkInfo->HzkSelect > 2)
	{
		goto SELECT;
	}

	switch(pHzkInfo->HzkSelect)
	{
	case 1:
		pHzkInfo->fileName = "Hzk16";
		pHzkInfo->HzkSquare = 16;
		break;
	case 2:
		pHzkInfo->fileName = "HZK32";
		pHzkInfo->HzkSquare = 32;
		break;
	}
	
	LoadHzkInfo(pHzkInfo);
}

void CleanupHzkInfo(HzkInfo hzkInfo)
{
	if(hzkInfo.pMatrix != NULL)
	{
		fclose(hzkInfo.file);

		free(hzkInfo.pMatrix);
		hzkInfo.pMatrix = NULL;
	}
}

void LoadHzkInfo(HzkInfo * pHzkInfo)
{
	printf("Loading %s ... ", pHzkInfo->fileName);
	if ((fopen_s(&(pHzkInfo->file), pHzkInfo->fileName, "rb")) != 0)
	{
		printf("Failed.\n");
		pHzkInfo->file = NULL;
		pHzkInfo->martixBytesCount = 0;
		pHzkInfo->pMatrix = NULL;
	}
	else
	{
		pHzkInfo->martixBytesCount = pHzkInfo->HzkSquare * pHzkInfo->HzkSquare / 8;
		pHzkInfo->pMatrix = (unsigned char *)malloc(pHzkInfo->martixBytesCount);

		if(pHzkInfo->pMatrix == NULL)
		{
			printf("Malloc failed.\n");
			fclose(pHzkInfo->file);
			pHzkInfo->file = NULL;
			pHzkInfo->martixBytesCount = 0;
			pHzkInfo->pMatrix = NULL;

			return;
		}

		printf("Done.\n");
	}
}

演示效果:


使用16*16 的字库:



使用32*32 的字库:


点阵字体的旋转

阅读数 206

没有更多推荐了,返回首页