C51玩8x8LED点阵:PointGame

发布者:勾剑寒最新更新时间:2020-03-25 来源: eefocus关键字:C51  8x8LED点阵  PointGame 手机看文章 扫描二维码
随时随地手机看文章

**

前言

**

我借同学的光驱把光盘中的文件拷出来后,开始尝试玩一玩单片机。

目前做的比较难的是8X8Led点阵的使用,元件感觉有点多啊。


我用的是普中科技HC6800-ES V2.0的开发板,很多人说什么普中垃圾,我觉得还是他们自己C语言和数电等知识还没弄懂之类的吧。还有老师的教程到8X8LED点阵这里,很多人说有问题,我甚至见过一篇博客写这个教程但是在结果后写:没有显示… dots…

也是,视频里说了有个地方需要短接的,至于是哪里,请往下看!


像以往一样,做个预想,这篇结束时,可以尽量在LED点阵上显示文字等。


**

8X8LED阵列

**

在这里插入图片描述

我用的单片机中的LED阵列是左边这种。

行,是D7~D0,而列是P07 ~ P00。

如果想点亮哪盏灯,需要找到那盏灯对应的行和列。行输出1,而对应的列输出0就行了。原理是相当简单。


比如说我想点亮左上角第一个LED,行输出为 0x80 (D7~D0 = 1000 0000),列输出为 0x7f (P07 ~P00 = 0111 1111) 。


**

74HC595

**

在这里插入图片描述

74HC595是中间那片。


74HC595是硅结构的CMOS器件。兼容低电压TTL电路,遵循JEDEC标准。具有8位移位寄存器和一个存储寄存器,三太输出功能。

而两个寄存器有不同的时钟,但都是根据上升沿触发。


74HC595原理和使用

在这里插入图片描述

单片机芯片通过P35P34P36三个IO口来控制D0~D7的输出。

当然如果不用74HC595而直接让LED点阵连接单片机也可以,但这里不谈那个。


值得注意的一点是,OE这个口为低电平有效。如果其有效,那么输出就有效。这个有JOE这个开关来控制。单片机短接片一般没被操作时,短接片是OE短接VCC,为了让OE有效,应该让其短接GND。

在这里插入图片描述

在这里插入图片描述

同一种芯片的引脚的名字可能不同,但是引脚是一样的。


当我想要使用这块芯片实现,串行输入并行输出的时候,


电源口就不说了,输入口(SER)准备好输入数字(8个)的第一个。两个时钟信号(SRCLK、RCLK)初始化为0。(非SRCLR)复位口为1(不复位)。JOE段子接GND,让OE为低电平(输出有效)。


移位寄存器时钟信号(SRCLK)出现上升沿,串行输入口输入一个数字

第二步运行8次,8次后,需要输入的8位数字就都放在了对应的位置上

存储寄存器时钟信号(RCLK)出现上升沿,8个并行输出口同时输出。

点亮阵列左上角的LED灯

sbit类型是取端口(一位),将其命名为一个变量。


还需要注意的是,每次编程直接使用SER、data、RCLK是不行的,容易出现重定义。每次自己还是取另类一点的变量名。

#include

#include

typedef unsigned int u16;

typedef unsigned char u8;



sbit My_SRCLK = P3^6;//移位寄存器时钟信号

sbit My_RCLK = P3^5;//存储寄存器时钟信号

sbit My_SER = P3^4;//串行输入口


void Hc595_SendByte(u8 My_data){

u8 a;

My_SRCLK = 0;

My_RCLK=0;

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

My_SER = My_data>>7; //每次只输入一位

My_data<<=1;

My_SRCLK = 1;//出现上升沿     串行输入一位

_nop_();//延迟一毫秒(一个指令周期

_nop_();//延迟一毫秒(一个指令周期)

My_SRCLK = 0;

}

My_RCLK=1;//出现上升沿    并行输出8位

_nop_();

_nop_();

My_RCLK = 0;

}


void main(){

Hc595_SendByte(0x80);//行输入 1000 0000

P0 = 0x7f;//列输入 0111 1111

while(1){}

}


显示结果:

在这里插入图片描述

如果JOE与GND没短接的话会出问题。

在这里插入图片描述

去掉JOE处的短接片后,如果用手指触碰接口的针多次,LED阵列的那盏灯会灭(如果按复位按钮,等也会灭)。解决方法是按USB口旁边的开关重启就行了。


显示数字零

普中HC6800-ES V2.0开发板资料常用辅助开发软件文字取模软件

里有一个取字模软件,可以选择特定的阵列,然后处理后得到自己的位选和段选分别的十六进制。


这里准备一个:链接:https://pan.baidu.com/s/1yKKo6xzj9cvhLAgz6MTz4Q

提取码:s297

复制这段内容后打开百度网盘手机App,操作更方便哦


打开软件后,新建8X8的图像,模拟动画,放大格点,用鼠标在白色窗口中点上自己想要的,取模方式,C51

在这里插入图片描述

如果选择的是纵向(行选),那么列选是通用的


0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe


如果选择的是横向(列选),那么行选是通用的


0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01


更改纵向还是横向在参数设置-》其他选项里

在这里插入图片描述

1.为了显示正确,必须先选通用的,再选另外一边

2.一般另外一边在显示和延迟后需要消隐


#include

#include

typedef unsigned int u16;

typedef unsigned char u8;



sbit My_SRCLK = P3^6;

sbit My_RCLK = P3^5;

sbit My_SER = P3^4;



 

u8 led_wei[]={

0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe

};


u8 led_duan[]={

0x00,0x00,0x3e,0x41,0x41,0x41,0x3e,0x00

};


//延迟

void delay(u16 i){

while(i--){}

}

void Hc595_SendByte(u8 My_data){

u8 a;

My_SRCLK = 0;

My_RCLK=0;

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

My_SER = My_data>>7;

My_data<<=1;

My_SRCLK = 1;

_nop_();

_nop_();

My_SRCLK = 0;

}

My_RCLK=1;

_nop_();

_nop_();

My_RCLK = 0;

}


void main(){

u8 a=0;

while(1){

P0=0x7f;

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

P0=led_wei[a];

Hc595_SendByte(led_duan[a]);

delay(100);

Hc595_SendByte(0x00);//消隐

}


}

}


显示结果:

在这里插入图片描述

同样如果不短接JOE和GND,还是会出错(输出无效)。但是不碰JOE端子,显示还是正常的。


有这么个有趣的结果,如果不短接JOE和GND,用手指按着JOE端子VCC和JOE上。

在这里插入图片描述

手指接触VCC和JOE时,输出无效,一部分灯就没亮(不是灭了)。

当手指没有接触时,又恢复正常(一部分)。

然后陷入长久的循环中。


**


Point_Game

**


64个灯中,我打算选一个灯做Point Bird,这个Bird只会上升和下降。会有障碍从右边生成并移向左边,如果Bird撞到障碍或掉了下来,那么就判断为输。


一共3个模块,


keyproc : 独立按键的控制

show:列选和行选

logic:游戏初始化,倒计时,移动,显示等

keyproc.h


#ifndef _KEY_PROC_H_

#define _KEY_PROC_H_   



#include"reg52.h"

#include"intrins.h"



typedef unsigned char u8;

typedef unsigned int u16;



sbit k1 = P3^1;//RXD

//sbit k2 = P3^0;//TXD



static int key = 0;

void delay(u16 i);

u8 Key_Process();

void Key_Zero();


#endif


keyproc.c


#include"keyproc.h"




void delay(u16 i){

while(i--){}

}



void Key_Zero(){

key = 0;

}


u8 Key_Process(){

if(k1==0){

delay(1000);

if(k1==0)key=~key;

delay(1000);

}

return key;

}


跨文件不要直接使用和传递全局变量,鉴于C语言的特性你也传递不了。跨文件只能用函数传递和返回变量 。(其实是可以的)

传递跨文件变量看我另一篇文章:C51:解决ERROR L104: MULTIPLE PUBLIC DEFINITIONS


show.h


#ifndef _SHOW_H_

#define _SHOW_H_  


#include"keyproc.h"


sbit g_SRCLK = P3^6;//移位寄存器时钟

sbit g_RCLK = P3^5;//存储寄存器时钟

sbit g_SER = P3^4;//串行输入




void ChooseRows(u8 iData);

void ChooseCols(u8 iData);


#endif


show.c


#include"show.h"



/*

LED阵列

P07 P06 P05 P04 P03 P02 P01 P00

D7 

D6

D5

D4 

D3 

D2 

D1 

D0

       

*/

void ChooseRows(u8 iData){

u8 a ;

g_RCLK = 0;

g_SRCLK = 0;

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

g_SER = iData >> 7;

iData<<=1;


g_SRCLK = 1;

_nop_();

_nop_();

g_SRCLK = 0;

}

g_RCLK = 1;

_nop_();

_nop_();

g_RCLK = 0;

}

void ChooseCols(u8 iData){


P0 = iData;

}


logic.h


#ifndef _LOGIC_H_

#define _LOGIC_H_


#include"show.h"

#include"stdlib.h"

#include"keyproc.h"



//Point  Bird的位置

static u8 bird_y = 4;


//通用的列选

static u8  xdata led_cols[ ]={

0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe

};


//特殊字符

static u8  xdata led_numbers_rows[6 ][8 ]={

0x00,0x00,0x3e,0x41,0x41,0x41,0x3e,0x00,  //0

0x00,0x00,0x22,0x42,0xFE,0x02,0x02,0x00, //1

0x00,0x21,0x43,0x45,0x49,0x31,0x00,0x00,  //2

0x00,0x00,0x42,0x81,0x89,0x89,0x76,0x00,  //3

0x04,0x02,0x01,0x02,0x04,0x08,0x10,0x20, //¡Ì

0x81,0x42,0x24,0x18,0x18,0x24,0x42,0x81 //¡Á


};


//障碍

static u8 xdata led_walls_rows[ ] = {

0xF0,0xE1,0x07,0x1C,0x33,0x70,0x84,0xCC

};


//显示数组

static u8 xdata leds_no_bird[8]={0};

static u8 xdata leds[8]={0};



void Init_Game();

void Move();

void Display();

void Lose();



#endif


logic.c


#include"logic.h"


void Init_Game(){


u8 a,b,c;


//初始化显示数组

for(a=0;a<8;++a)

leds[a]=0;

//初始化Point Bird的位置

bird_y = 4;

//按k1启动游戏

while(1)

if(Key_Process())

break;

Key_Zero();

//倒计时 √ 3 2 1 0

for(a=0;a<5;a++){

for(b=0;b<100;b++)//ÏÔʾÎȶ¨

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

ChooseCols(led_cols[c]);

ChooseRows(led_numbers_rows[4 - a][c]);

delay(100);

ChooseRows(0x00);

}

}

}



void Move(){

static u8 c = 0;

u8 a,temp;

u8 n = rand()%8;

//Point Bird的移动

u8 value = Key_Process();

Key_Zero();

if(value){

if(bird_y ++ >= 7)bird_y = 7;

}

else bird_y--;

//障碍移动

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

leds_no_bird[a]=leds_no_bird[a+1];

}

leds_no_bird[7] = 0x00;

//每隔3个生成一条障碍,并放入数组

if(c++ ==4 ){

leds_no_bird[7] |= led_walls_rows[n];

c=0;

}

///复制

for(a=0;a<8;++a)

leds[a]=leds_no_bird[a];

//最后处理Point Bird

temp = leds[1];

temp |= (1< //如果或后的值域原值一样,说明撞墙

if(temp==leds[1]){

while(1)

Lose();//×

}

else leds[1]  = temp;

}


void Display(){


u8 a,b;

for(b=0;b<100;b++) //使显示稳定

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

ChooseCols(led_cols[a]);

ChooseRows(leds[a]);

delay(100);

ChooseRows(0x00);

}


}


void Lose(){


u8 a,b;

for(b=0;b<100;b++)//使显示稳定

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

ChooseCols(led_cols[a]);

ChooseRows(led_numbers_rows[5][a]);

delay(100);

ChooseRows(0x00);

}

}


main.c


#include"logic.h"


void main(){


Init_Game();

while(1){

Move();

Display();

}

}


显示效果:

在这里插入图片描述

在这里插入图片描述


关键字:C51  8x8LED点阵  PointGame 引用地址:C51玩8x8LED点阵:PointGame

上一篇:单片机实验——8X8LED点阵显示技术(二)
下一篇:基于51单片机个8位数码管的简单拨号键盘

推荐阅读最新更新时间:2024-11-13 22:02

PS/2键盘接口C51驱动
/************************** 文件所用资源 1.外部中断0 2.端口:P3.3、P3.4 **************************/ sbit PS2_DAT=P3^7; //数据 uchar code unshifted = //shift键没按下译码表 { 0x0e,'`', 0x15,'q', 0x16,'1', 0x1a,'z', 0x1b,'s', 0x1c,'a', 0x1d,'w', 0x1e,'2', 0x21,'c
[单片机]
C51中~XBYTE 简介
C51的P0,P2口做外部扩展时使用,其中XBYTE ,P2口对应于地址高位,P0口对应于地址低位。一般P2口用于控制信号,P0口作为数据通道。 XBYTE定义的是外部地址,这样才能和接到你的IO口上的器件通信 在一般的读写外部RAM的程序中,经常看到这样的句子: XBYTE =data 写数据 data=XBYTE 读数据1 外部总线由3组总线组成,数据 地址 控制,我们常常一般就叫他外部总线,既然是有3组不同的信号,那么他们是怎么协调工作的呢?一般情况CPU有特殊的外部数据访问指令如你这里讲51的MOVX指令(在C语言中他会编译成这个指令)在执行这个指令的时候3组线是协调工作 mov dptr,#1000h
[单片机]
如何采用C51单片机读写CAT24C32
#include #include//我的自定义LCD1602头文件 /*--------------------------------------------------------------- 24C32可存储4K(1024*4)个字节(8bit),因此寻址地址最大为0x0FFF,24C32为从机。 ----------------------------------------------------------------*/ #defineWriteDeviceAddress0x0A2//定义器件在I2C总线中的写地址(注意:根据自定义从机地址接口改变) #defineReadDviceAdd
[单片机]
如何采用<font color='red'>C51</font>单片机读写CAT24C32
c51单片机浮点数及其汇编程序设计
在 单片机 应用系统的数据处理过程中,经常会遇到小数的运算问题,如求解BCD的增量算式、线性化处理等。因此,需要用二进制数来表示小数。表示小数的方法一般有两种,定点数和浮点数。定点数结构简单,与整数的运算过程相同,运算速度快。但随着所表示数的范围的扩大,其位数成倍增加,给运算和存储带来不便,而且也不能保证相对精度不变。浮点数的结构相对复杂,但它能够以固定的字节长度保持相对精度不变,用较少的字节表示很大的数的范围,便于存储和运算,在处理的数据范围较大和要求精度较高时,采用浮点数。 浮点数的概念 常用的科学计数法来表示一个十进制数如 l234.75=1.23475E3=1.23475 103 在数据很大或很小时,采用科学计数避免了
[单片机]
单片机C语言C51的数据类型
C51的数据类型分为基本数据类型和组合数据类型,情况与标准C中的数据类型基本相同,但其中char型与short型相同,float型与double型相同,另外,C51中还有专门针对于51单片机的特殊功能寄存器型和位类型。 一.字符型char 有signed char和unsigned char之分,默认为signed char。它们的长度均为一个字节,用于存放一个单字节的数据。 对于signed char,它用于定义带符号字节数据,其字节的最高位为符号位,“0”表示正数,“1”表示负数,补码表示,所能表示的数值范围是-128~+127; 对于unsigned char,它用于定义无符号字节数据或字符,可以存放一个字节
[单片机]
单片机C语言<font color='red'>C51</font>的数据类型
C51单片机的外部中断设计1s定时器
51单片机给我们提供了2个计时器中断,分别是计时器0和计时器1,他们对应的优先级分别是1和3,开启计时器并允许其中断后,计时器会从给定的初始值开始,每个指令周期加1,直到加到65535,再加一时计时器溢出,计时器此时会进入中断,并执行中断服务函数。 虽然书上讲的很清楚了,但实际使用还是有些许差别,我自己是这样理解的 65536-50000的由来 假设我使用的单片机的晶振为12MHZ,其机器周期是1us,即每1us产生一次计数 如果设计一个1s的定时器,理论上是需要1*10^6个机器周期,但定时器T0只能对机器周期能进行最大65536次计数,很明显已经超过了,并不能直接采用T0的默认值 转下思维模式,取个65535之内的整数值,
[单片机]
用<font color='red'>C51</font>单片机的外部中断设计1s定时器
C51/C52单片机的中断(EXTI)介绍(一)
一、什么是中断 打断:打断当前做的事情,去执行中断函数里的程序,执行完过后回来接着执行原来未执行完的程序。如下图所示: 二、中断源及中断号 注意:写中断服务函数时,中断源与中断号要一一对应,否则不能进入中断服务函数,比如: void Timer0IRQ(void) interrupt 1 //1就是中断号,默认工作组0 格式如下: void 函数名(void) interrupt 中断号 using 工作组 { 中断服务函数内容; } 三、中断相关寄存器介绍 1、中断允许控制寄存器IE 2、扩展中断控制寄存器XICON(STC89C52RC) 四、中断优先级
[单片机]
<font color='red'>C51</font>/C52单片机的中断(EXTI)介绍(一)
独立按键c语言代码,C51独立按键的识别示例程序
每按一次独立键盘的S2键,与P1口相连的一个发光二极管往下移动一位。 #include sbit BY1=P3^4; //定义按键的输入端S2键 unsigned char count; //按键计数,每按一下,count加1 unsigned char temp; unsigned char a,b; void delay10ms(void) //延时程序 {undefined unsigned char i,j; for(i=20;i 0;i--) for(j=248;j 0;j--); } key() //按键判断程序 {undefined if(BY1==0) //判断是否按下键盘,当单片机上电时所有IO口为//高电平,S
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved