摘要:
本项目以AT89C52为基础,使用74HC138和74HC595控制8*8LED点阵显示拟定的内容,可以进行和静态显示和动态显示,并能够控制显示的方向,同时使用lcd1602作为辅助功能,显示相关的内容
一.主体思路
使用MATRIX-8*8LED点阵,由74HC138控制列(行),74HC595显示数据,从而将指定的数据输入点阵显示
静态显示,每次输出前8个数据的后8个数据,逐帧显示
动态显示,每次输出前8个数据的后7个数据+第9个数据,以此类推,达到动画的效果
二.主要内容
1.主要功能
(一)静态显示姓名首字母以及姓名
(二)动态显示姓名首字母以及姓名
(三)LCD1602显示模式,不同模式代表不同功能
2.硬件电路设计
2.1 元件选取
如上图所示,选取AT89C52开发板,74HC138、74HC595模块,MATRIX-8*8绿色点阵屏,LM016L(LCD1602)、按钮BUTTON以及电阻RES和排阻RESPACK-8以及复位所需元器件
2.2 单片机IO口选取
如上图所示,使用了P1的0~3,5~7IO口,使用了P2全部IO口,使用了P3的0~5IO口以及复位所需IO口
2.3 硬件部分作用
(一)74HC595模块
该模块的作用是将数组内提前拟定好的数据进行输出。
SH_CP是控制数据左移位,高电平有效
ST_CP是数据输出,高电平有效
MR和OE分别是移位寄存器清零和输出使能,均为低电平有效
DS是串口输入,一次输入一位
Q0~Q7为并行输出(此处不考虑第9输出引脚)
使用过程:
1.先全部置低电平,即DS=0,SH_CP=0,ST_CP=0
2.DS置高电平,输入1,若为低电平则输入0
3.SH_CP置高电平,产生一个上升电平>2us
4.SH_CP置低电平
以上4步重复8次,即完成一个字节的传输
5.ST_CP置高电平,产生一个上升电平>2us
6.ST_CP置低电平
(二)74HC138模块
该模块的作用是选取行(列),使数据在该行(列)中输出。
A、B、C是输入端,分别代表二进制中的最低位,中间位和最高位
E1、E2、E3是使能控制端,E2,E3低电平有效,E1高电平有效
Y0~Y7是输出端,对应输入端(0~7)
(三)LED点阵模块
该模块的作用是显示输出的数据,显示名称首字母以及名称,动画等
初始点阵的上半部分引脚设为B0~B7,从B0开始从左往右,分别代表1~8列,下半引脚设为A0~A7,从A7开始从左到右分别代表1~8行,此时所有引脚均为高电平有效
将该点阵进行X翻转后,上半引脚从B7开始从左到右分别代表1~8行,下半引脚从A0开始分别代表1~8列,此时B0~7引脚低电平有效,A0~7引脚高电平有效
为了让点阵能更好的显示,对翻转后的点阵进行两次X镜像,逆转90°,再Y镜像,完成操作
(四)LCD1602模块
该模块的作用是显示模式,方便使用者查看功能
(五)按键模块
该模块的作用是切换模式,使LED点阵显示不同的内容
(六)复位模块
该模块的作用是使系统复位,从而切换其他模式
3.软件设计
先进行模块化编程
如上图所示,将整体程序分为主函数main,延时函数delay,按键模块key,显示模块led,模式模块lcd,控制模块74HC
(一)74HC模块
首先使用sbit定义相关引脚,如上图所示
定义col函数,对列进行选取,在上述点阵中从左到右分别代表1~8列,
使用switch函数,对传入的形参进行判断,若形参为1,则代表第一列,使L1,L2,L3均为0,即均为低电平,从而控制74HC138进行列的选择,如下图所示
其余7列类同
定义display显示函数,在选取好的列上显示数组中的数据
先使L4和L6置于低电平,然后将8位数据一位一位传入,传入过程要将L4置为高电平再恢复为低电平
传入一字节的数据后,将L6置为高电平,开启并行输出,一次输出该数据,将其显示到对应的列上
(二)LCD1602模块
首先使用sbit定义相关引脚,如上图所示
定义数据输出口P2
#define out P2
编写写入命令函数writecom,写入数据函数writedat,LCD初始化函数initial
以及字符串显示函数lcd_string
(三)led模块
首先使用取字摸软件将想要显示的数据转化为十六进制编码,如上图所示
在动态显示过程中,需要定义计数变量cnt以及count
使用for循环每次选取指定的8位数据,先选取列col(i+1),再使该列显示相关的数据display(tab[i+cnt]),然后使count加1,delay延时并且清屏,判断count是否大于指定数字,如果大于使cnt加1,在下次循环中显示后7位+第9位数据,如果数据已经显示到最后8位,使cnt=0,重新循环
使动画改变方向,只需要改变cnt(例共40个元素,将cnt初始化为32),使点阵一开始显示最后8位数据,在count越界后使cnt减1,当cnt<0时,重新初始化为32
(四)key模块
通过控制按钮改变点阵中所显示的内容
首先使用sbit定义相关引脚,如上图所示
不断扫描是否有按键按下,若有按键按下,则该引脚变为低电平,对其进行消除抖动,并判断是否松开,若松开,进行二次消除抖动,并传回相关按键的值
(五)delay模块
编写能够延时1ms的函数
(六)main模块
首先对初始化LCD1602,然后显示相关的字符串
在循环中不断扫描key的按键值,不同的按键值代表点阵显示不同的模式,每个模式点阵都会显示不同的内容,LCD1602会显示是模式几
4.源程序代码
(一)main模块
#include <reg52.h>
#include "74HC.h"
#include "delay.h"
#include "key.h"
#include "led.h"
#include "lcd1602.h"
#define uchar unsigned char
#define uint unsigned int
uchar KeyNum;
void main(){
initlcd();
lcd_string(0x85,"PROJECT2");
lcd_string(0xC0,"WELCOME");
while(1){
KeyNum=key();
if(KeyNum==1){
while(1){
lcd_string(0xC8,"mode A");
fun();
}
}
else if(KeyNum==2){
while(1){
lcd_string(0xC8,"mode B");
fun2();
}
}
else if(KeyNum==3){
while(1){
lcd_string(0xC8,"mode C");
fun3();
}
}
else if(KeyNum==4){
while(1){
lcd_string(0xC8,"mode D");
fun4();
}
}
}
}
(二)delay模块
#define uchar unsigned char
#define uint unsigned int
void delay(uint x){
uchar i,j;
while(x--){
i=2;
j=239;
do{
while(--j);
}while(--i);
}
}
(三)key模块
#include <reg52.h>
#include "delay.h"
#define uchar unsigned char
#define uint unsigned int
sbit K0=P1^0;
sbit K1=P1^1;
sbit K2=P1^2;
sbit K3=P1^3;
uchar key(){
uchar KeyNumber=0;
if(K0==0){delay(20);while(K0==0);delay(20);KeyNumber=1;}
if(K1==0){delay(20);while(K1==0);delay(20);KeyNumber=2;}
if(K2==0){delay(20);while(K2==0);delay(20);KeyNumber=3;}
if(K3==0){delay(20);while(K3==0);delay(20);KeyNumber=4;}
return KeyNumber;
}
(四)LED模块
#include <reg52.h>
#include "74HC.h"
#include "delay.h"
#define uchar unsigned char
#define uint unsigned int
uchar cnt1,cnt2;
uchar tabA[]={
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xFF,0x01,0x01,0x01,0x01,0x01,0x01,0x00,
0x00,0x80,0x40,0x20,0x1F,0x20,0x40,0x80,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
uchar tabC[]={
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x54,0x6E,0xFB,0x6C,0x54,0x40,0x01,0x0F,
0xE2,0xBE,0xEB,0x0D,0x55,0xF9,0x95,0x05,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
void fun(uchar a){
uchar i;
uchar cnt,count;
while(1){
for(i=0;i<8;i++){
col(i+1);
display(tabA[i+cnt]);
count++;
delay(4);
display(0); //清屏
if(count>22){
count=0;
cnt++;
if(cnt>32){
cnt=0;
}
}
}
}
}
void fun2(uchar a){
uchar i;
uchar cnt,count;
while(1){
for(i=0;i<8;i++){
col(i+1);
display(tabC[i+cnt]);
count++;
delay(4);
display(0); //清屏
if(count>22){
count=0;
cnt++;
if(cnt>32){
cnt=0;
}
}
}
}
}
void fun3(uchar a){
uchar i;
uchar cnt=32,count;
while(1){
for(i=0;i<8;i++){
col(i+1);
display(tabA[i+cnt]);
count++;
delay(4);
display(0); //清屏
if(count>22){
count=0;
cnt--;
if(cnt<0){
cnt=32;
}
}
}
}
}
void fun4(uchar a){
uchar i;
uchar cnt=32,count;
while(1){
for(i=0;i<8;i++){
col(i+1);
display(tabC[i+cnt]);
count++;
delay(4);
display(0); //清屏
if(count>22){
count=0;
cnt--;
if(cnt<0){
cnt=32;
}
}
}
}
}
(五)LCD模块
#include <reg52.h>
#include <intrins.h>
#include "delay.h"
#define uchar unsigned char
#define uint unsigned int
#define out P2
sbit RS=P3^3;
sbit RW=P3^4;
sbit E=P3^5;
//有重复功能函数,选取部分函数即可
void writedat(unsigned char dat){
RS=1;
RW=0;
E=0;
P2=dat;
delay(5);
E=1;
E=0;
}
void writecom(unsigned char com){
RS=0;
RW=0;
E=0;
P2=com;
delay(5);
E=1;
E=0;
}
void initlcd(){
writecom(0x38);
writecom(0x0c);
writecom(0x06);
writecom(0x01);
}
void check_busy(){
uchar dt;
do{
dt=0xff;
E=0;
RS=0;
RW=1;
E=1;
dt=out;
}while(dt&0x80);
E=0;
}
void write_data(uchar dat){
check_busy();
E=0;
RS=1;
RW=0;
out=dat;
E=1;
_nop_();
E=0;
delay(1);
}
void write_command(uchar com){
check_busy();
E=0;
RS=0;
RW=0;
out=com;
E=1;
_nop_();
E=0;
delay(1);
}
void lcd_initial(){
write_command(0x38);
write_command(0x0C);
write_command(0x05);
write_command(0x01);
}
void lcd_string(uchar ad,uchar *s){
write_command(ad);
while(*s>0){
write_data(*s++);
delay(100);
}
}
void LCD_WriteData(unsigned char dat){
RS=1;
RW=0;
out=dat;
E=1;
delay(5);
E=0;
delay(5);
}
void LCD_WriteCommand(unsigned char com){
RS=0;
RW=0;
out=com;
E=1;
delay(5);
E=0;
delay(5);
}
void LCD_SetCursor(unsigned char Line,unsigned char Column){
LCD_WriteCommand(Line==1?0x80+(Column-1):0x80+(Column-1+0x40));
}
void LCD_ShowString(uchar Line,uchar Column,char *String){
uchar i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
(六)74HC模块
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit L1=P3^0;
sbit L2=P3^1;
sbit L3=P3^2;
sbit L5=P1^5;
sbit L4=P1^6;
sbit L6=P1^7;
void wrong(uint i){
if(i)
P0=0xFF;
}
//注意col函数取的是列
void col(uchar i){
switch(i){
case 1:{
L1=1;
L2=1;
L3=1;
}break;
case 2:{
L1=0;
L2=1;
L3=1;
}break;
case 3:{
L1=1;
L2=0;
L3=1;
}break;
case 4:{
L1=0;
L2=0;
L3=1;
}break;
case 5:{
L1=1;
L2=1;
L3=0;
}break;
case 6:{
L1=0;
L2=1;
L3=0;
}break;
case 7:{
L1=1;
L2=0;
L3=0;
}break;
case 8:{
L1=0;
L2=0;
L3=0;
}break;
default:wrong(1);break;
}
}
void display(uchar a){
uint i;
L4=L6=0;
for(i=0;i<8;i++){
L5=a>>7;
a<<=1;
L4=1;
_nop_();
_nop_();
L4=0;
}
L6=1;
_nop_();
_nop_();
L6=0;
}
至此,我们已经基本完成了整个项目,.h文件自然不必多说,相信各位读者的能力。
相信大家对点阵的使用更加熟练,也更多的了解到了AT89C52单片机,欢迎各位一起讨论和交流。