51定时中断系统控制LED点阵屏显示逐帧动画

news/2024/11/22 20:53:22/

写在前面

最近回头看之前写的文章感到一种很浓的公式感,我确实是提前写好了模板每次都套用,整篇看下来感觉就像是在交老师布置的实验报告,看起来很成熟但实际上背离了自己的初衷,接下来我会尽可能的复现自己在做的时候的尝试和思考过程

一、简单介绍

  1. 类似于笔记地总结LED点阵屏使用需要用到的模块知识
  2. 静态显示图形
  3. 逐帧显示,这里只做了3帧,“I ❤ U”,帧率可调

二、原理和知识总结 

1、LED点阵屏

 LED点阵屏的结构和数码管非常类似,需要对其逐行或者逐列扫描,一次扫描显示一行/列的亮灭,当扫描间隔极短时人眼看来就像是同时显示

 

 通过原理图显示LED点阵屏的列接在了单片机的P0 I/O口,而行接在了D0~D7,就是接下来要提的

2、74HC595

 功能简单的说就是串转并输出,595内部有一个8位缓冲区移位寄存器,先接收串行输入数据一位后将其移位,然后再接收下一位,8位接收完了就将8位数据并行一次输出

 OE非:也许是open enable?低电平芯片输出有效

SER: 串行输入

SRCLK: SERCLK 的缩写,上升沿时移位寄存器的数据移位

RCLK : 上升沿时移位寄存器的数据进入数据存储寄存器(也就是送到了输出端)并直到下一个上升沿来之前保持不变

下面是图解,较好理解

2、Sfr和Sbit声明

sfr(special function register):特殊功能寄存器声明

 例:sfr P0 = 0x80   //声明P0口寄存器,物理地址为0x80

普中的板子开发板原理图里可以看到P0就是连接LED点阵的列端口,即通过这个命令把单片机地址为0x80的寄存器资源分配给了外设LED点阵屏,当我们要使用其他寄存器的时候也可以自己声明寄存器,分配给需要的外设,在常用的头文件<REGX52.H>中可以找到相关声明

 这个物理地址可以在官方手册里找到

可位寻址/不可位寻址:在单片机系统中,操作任意寄存器或者某一位的数据时,必须给出其物理地址,又因为一个寄存器里有8位,所以位的数量是寄存器数量的8倍,单片机无法对所有位进行编码,故每8个寄存器中,只有一个是可以位寻址的。对不可位寻址的寄存器,若要只操作其中一位而不影响其它位时,可用“&=”、“|=”、“^=”的方法进行位操作,

 sbitspecial bit):特殊位声明

可用于声明某寄存器某一位

例:sbit P0_1 = 0x81;    或    sbit P0_1 = P0^1       //声明P0寄存器的第一位

2.2、实际应用

51单片机内部寄存器都是已经声明过了的,但实际应用却需要对着电路原理图才知道P0、P1、P2以及其中的具体位等等这些是分配给了哪些外设(因为P0之类名字本身没有特殊意义)

举个例子,如果在某个项目里,P0分给了矩阵按键,整个代码中P0将会多次出现,而移植到其他项目里是,就需要看原来项目的原理图查看P0的分配,当然了可以采用注释,但注释也最多写一行,而代码如果复杂了前面的注释后面可能会忘记,综合考虑可以自己对寄存器进行声明

比如本次要用到的SER,SERLCK,RLCK,找到对应寄存器地址重新声明,注意声明名称不能重复

首先看到开发板这三个分别对应P3_4、P3_6、P3_5,在头文件里已经声明过了寄存器地址,我们没必要更改头文件,就直接重新声明就可以

//自定义寄存器名称,方便使用
sbit SERCLK = P3 ^ 6;   //上升沿移位 
sbit RCK = P3 ^ 5;   //RCLK,上升沿锁存,并行输出
sbit SER = P3 ^ 4;	 //串行输入位

关于sbit还有一个问题是,sbit声明的部分是编译器预处理的部分,必须放在函数外部

三、程序设计和实现步骤

3.1、尝试显示静态图像

3.1.1 74HC595写函数

功能:将要写入的一个字节串行输入到74HC595中,就可以选择点亮点阵屏的哪些行

实现原理:输出寄存器的高位在下,因此将写入的字节数据从高位到低位串行输入和向下移位,依次和0x80(1000 0000)、0x40...取&运算就可以实现串行输入,采用for循环和移位运算符简化

		SER = Byte & (0x80>>i);    //从高位到低位依次赋给串行输入位SERCLK = 1;				   //每输入一位给一个上升沿使其移位SERCLK = 0;				   //一位移位后立刻将SERCLK复位

完整代码

/*** @brief 74HC595写入的一个字节* @param  Byte 要写入的字节* @retval 无*/
void _74HC595_WriteByte(unsigned char Byte)
{unsigned char i;for(i=0; i<8; i++){SER = Byte & (0x80>>i);    //从高位到低位依次赋给串行输入位SERCLK = 1;				   //每输入一位给一个上升沿使其移位SERCLK = 0;				   //一位移位后立刻将SERCLK复位}RCK = 1;		//八位串行输入完毕使其并行输出RCK = 0;		//输出完立刻复位
}

3.1.2、 按列显示LED点阵屏函数

实现原理:

  1. 调用74HC595写函数选择要点亮的行,如0x42(0100 0010 )就是选择2和7行
  2. 选中列为位选信号取低电平,参数Column传递第几列
  3. 位选信号清0,如果不清零,就无法显示其他列,清0后在while里可以同时调用多次显示不同列

完整代码

/*** @brief LED显示一列数据* @param  Column 要显示的那一列(从左到右为0~7列)* @param  Data 要显示列的数据,高位在上低位在下,1亮,0灭* @retval 无*/
void MatrixLED(unsigned char Column, Data)
{_74HC595_WriteByte(Data);		//选中给高电平点阵屏的行MatrixLED_Port = ~(0x80 >> Column);         //选中列,即可确定具体该列LED的亮灭Delay(1);                //保证亮度MatrixLED_Port = 0xFF;     //位选信号清零,用于再循环中可以同时显示多列
}

3.1.3、主函数设计 

 尝试显示静态图像,只需要在主函数的while里调用MatrixLED()随便敲几个

当然首先得对SERLCK,RLCK初始化,因为单片机一上电就给高电平

	SERCLK = 0;		//由于一上电SERCLK、RCK都被置高电平,因此需手动赋初值0RCK = 0;
void main()
{SERCLK = 0;        //由于一上电SERCLK、RCK都被置高电平,因此需手动赋初值0RCK = 0;while(1){MatrixLED(0,a);MatrixLED(1,b);MatrixLED(2,c);MatrixLED(3,d);MatrixLED(4,e);MatrixLED(5,f);MatrixLED(6,g);MatrixLED(7,h);}
}

 这图怎么才能弄成正的啊...

3.2、逐帧图像显示

做到这就想要让点阵屏一帧一帧的显示图像

1、最开始想法简单粗暴,直接把三帧,,也就是24次调用MatrixLED()写在while里,显示一帧delay一秒,然后清空再写下一帧,为此还写了个“初始化函数”,为了方便

void LED_ShowInit()
{MatrixLED(0,0x00);MatrixLED(1,0x00);MatrixLED(2,0x00);MatrixLED(3,0x00);MatrixLED(4,0x00);MatrixLED(5,0x00);MatrixLED(6,0x00);MatrixLED(7,0x00);
}

这个主函数极其丑陋,并不打算拿出来丢人

直接上问题,这样写的结果是每一帧刚亮就立刻灭了,因为MatrixLED()中有个位选清零,但是不加清0无法显示多列,直接写在while循环里不能解决问题

2、想到了定时和中断控制,调用之前写过的1ms定时初始化函数,每1ms转到中断函数,调用显示一帧动画,这样亮灭的时间间隔就是1ms(当时是这么以为的)

定义列位选变量,可以用数组,感觉差不多,用于后续更改显示下一帧,

	a = 0x00; b = 0x42; c = 0x42; d = 0x7E; e = 0x42; //第一帧列位选变量,用于后续更改显示下一帧f = 0x42; g = 0x00; h = 0x00;                      

定义计数变量,每一次进入中断函数变量+1,加到1000,改变位选变量显示第二帧,加到2000显示第三帧,按照这时的想法,计数一次就是1ms,加到1000的时候一帧显示1s...

定时初始化函数

void Timer0Init()
{TMOD = TMOD & 0XF0;    //低四位置零,高四位不变TMOD = TMOD | 0X01;    //最低位置1,高四位不变TR0 = 1;TF0 = 0;TL0 = 0x18;		//设置定时初值TH0 = 0xFC;		//设置定时初值ET0 = 1;EA = 1;PT0 = 0;
}

中断函数代码

void Timer0_Routine()   interrupt 1
{	static unsigned int T0Count;T0Count++;TL0 = 0xFF;		//设置定时初值TH0 = 0xF7;		//设置定时初值MatrixLED(0,a); //显示一帧图像MatrixLED(1,b);MatrixLED(2,c);MatrixLED(3,d);MatrixLED(4,e);MatrixLED(5,f);MatrixLED(6,g);MatrixLED(7,h);if(T0Count == 1000)   //帧间隔{LED_ShowInit();   //LED全灭a = 0x30; b = 0x48; c = 0x44; d = 0x22; e = 0x44; //修改为第二帧位选f = 0x48; g = 0x30; h = 0x00;}if(T0Count == 2000) {LED_ShowInit();a = 0x00; b = 0x7E; c = 0x01; d = 0x01; e = 0x01;  //第三帧f = 0x7E; g = 0x00; h = 0x00;}
}

运行结果仍然有问题

  • 闪烁频率低,肉眼可见,用手机录视频的时候更明显,实在上不了台面
  • 帧与帧之间间隔时间远远不止1s

重新检查代码发现问题出在MatrixLED()函数中的Delay(1),Delay是自己编写的延时函数,单位是1ms,而代码里在中断函数里调用8次,那么一次中断就会延时8ms,不考虑程序其他执行时间,亮灭间隔也有8ms,离得近是可以看出来闪烁的(晚上尤其明显)

一共进入1000次中断显示下一帧,那么一帧的显示时间就是8000ms,8秒钟还是很长的

3、定时溢出时间由1ms改成1us,结果闪的还是明显甚至可以看见列从上到下的“滚动”

4、 尝试删除MatrixLED()中的Delay,观察到的结果

 闪烁频率效果不错,但是亮度很低,拍出来看着还行实际真的很暗

5、还是降低延时时间,重写一个以10us为单位的延时函数,测试出同时兼顾亮度和闪烁频率的延时时间

void Delay10us(unsigned int x10us)		//@11.0592MHz
{unsigned char i;while(x10us){i = 2;while (--i);x10us--;}
}

延时为400us时效果不错,稳定亮度也够

使用定时中断函数显示LED点阵屏的多帧图像

是的,一开始就是奔着浪漫~

代码实现

#include <REGX52.H>
#include"Delay.h"//自定义寄存器名称,方便使用
sbit SERCLK = P3 ^ 6;   //上升沿移位 
sbit RCK = P3 ^ 5;   //RCLK,上升沿锁存,并行输出
sbit SER = P3 ^ 4;	 //串行输入位
#define MatrixLED_Port  P0/*** @brief 74HC595写入的一个字节* @param  Byte 要写入的字节* @retval 无*/
void _74HC595_WriteByte(unsigned char Byte)
{unsigned char i;for(i=0; i<8; i++){SER = Byte & (0x80>>i);    //从高位到低位依次赋给串行输入位SERCLK = 1;				   //每输入一位给一个上升沿使其移位SERCLK = 0;				   //一位移位后立刻将SERCLK复位}RCK = 1;		//八位串行输入完毕使其并行输出RCK = 0;		//输出完立刻复位
}/*** @brief LED显示一列数据* @param  Column 要显示的那一列(从左到右为0~7列)* @param  Data 要显示列的数据,高位在上低位在下,1亮,0灭* @retval 无*/
void MatrixLED(unsigned char Column, Data)
{_74HC595_WriteByte(Data);		//选中给高电平点阵屏的行MatrixLED_Port = ~(0x80 >> Column);         //选中列,即可确定具体该列LED的亮灭Delay10us(40);MatrixLED_Port = 0xFF;     //位选信号清零,用于再循环中可以同时显示多列
}void LED_ShowInit()
{MatrixLED(0,0x00);MatrixLED(1,0x00);MatrixLED(2,0x00);MatrixLED(3,0x00);MatrixLED(4,0x00);MatrixLED(5,0x00);MatrixLED(6,0x00);MatrixLED(7,0x00);
}unsigned char a,b,c,d,e,f,g,h;void main()
{SERCLK = 0;		//由于一上电SERCLK、RCK都被置高电平,因此需手动赋初值0RCK = 0;Timer0Init();a = 0x00; b = 0x42; c = 0x42; d = 0x7E; e = 0x42;    //第一帧列位选变量,用于后续更改显示下一帧f = 0x42; g = 0x00; h = 0x00;while(1){}
}void Timer0_Routine()   interrupt 1
{	static unsigned int T0Count;T0Count++;TL0 = 0xFF;		//设置定时初值TH0 = 0xF7;		//设置定时初值MatrixLED(0,a); //显示一帧图像MatrixLED(1,b);MatrixLED(2,c);MatrixLED(3,d);MatrixLED(4,e);MatrixLED(5,f);MatrixLED(6,g);MatrixLED(7,h);if(T0Count == 100)   //帧间隔{LED_ShowInit();   //LED全灭a = 0x30; b = 0x48; c = 0x44; d = 0x22; e = 0x44; //修改为第二帧位选f = 0x48; g = 0x30; h = 0x00;}if(T0Count == 200) {LED_ShowInit();a = 0x00; b = 0x7E; c = 0x01; d = 0x01; e = 0x01;  //第三帧f = 0x7E; g = 0x00; h = 0x00;}
}

上面的定时初始化中的 修改,溢出时间间隔为1us

	TL0 = 0xFF;		//设置定时初值TH0 = 0xFF;		//设置定时初值

Delay10us函数在上面贴了没有修改,记得包含进去~ 

下一篇考虑数组移位方式实现帧变换


http://www.ppmy.cn/news/444368.html

相关文章

51单片机入门 - 驱动 8x8 LED 点阵屏

硬件型号、软件版本、以及烧录流程 操作系统&#xff1a;Windows 10 x84-64单片机&#xff1a;STC89C52RC编译器&#xff1a;SDCC烧录软件&#xff1a;stcgal 1.6开发板&#xff1a;普中51单片机开发板A2套件&#xff08;2022&#xff09; 在 VS Code 中新建项目到烧录的过程…

一文教你玩LED点阵屏32*64/64*64----基于STM32

以32*64点阵屏为例&#xff0c;详解LED点阵屏驱动全过程 首先要了解LED点阵屏幕的显示原理。 一般LED点阵屏在某一时间段内只能点亮某一行或者某一列&#xff0c;因为人的眼睛只有24帧速度&#xff0c;只要屏幕速度超过这个值&#xff0c;我们看到的是一个连续完整的画面。一般…

led点阵屏静态图

话不多说&#xff0c;上代码&#xff0c;前提是你已经知道各行代码的意思。跟着老师的代码走最好&#xff0c;每一行都一样&#xff0c;要不然会有意想不到的错误&#xff0c;小白阶段就不要自己创新代码了。X﹏X #include <REGX52.H> sbit RCKP3^5; //RCLK sbit SCKP3^6…

【Arduino实验11 LED点阵屏显示】

目录 一、实验目的 二、实验设备与环境 三、实验重点 四、实验难点 五、实验内容 5.1实验任务 5.2实验原理 5.3实验内容 5.4实验结果 5.5思考题 一、实验目的 1熟悉8*8点阵屏的原理与功能&#xff1b; 2 掌握数组变量的使用&#xff1b; 3 连接点阵屏显示电路&#x…

MCU-51:LED点阵屏

目录 一、点阵屏介绍1.1 简介1.2 分类 二、点阵屏原理2.1 点阵屏显示原理2.2 74HC595芯片介绍 三、代码演示3.1 静态笑脸3.2 动态Hello! 注意&#xff1a;一定要看 之前我们介绍了控制LED灯亮灭的操作&#xff0c;今天我们要介绍一下控制LED点阵屏亮灭的操作&#xff0c;8*8的L…

6. LED 点阵屏

点阵屏介绍 LED点阵屏由若干个独立的LED组成&#xff0c;LED以矩阵的形式排列&#xff0c;以灯珠亮灭来显示文字、图片、视频等。LED点阵屏广泛应用于各种公共场合&#xff0c;如汽车报站器、广告屏以及公告牌等 LED点阵屏分类 按颜色&#xff1a;单色、双色、全彩 按像素&…

[入门教程]详细讲解STM32控制LED点阵屏(HUB75接口)

本文适合初级入门的同学&#xff0c;大佬请绕道。讲解怎么用stm32驱动成品LED点阵屏显示一副七色无灰度的图片&#xff0c;有灰度的图片可以入门后继续研究。 使用软硬件&#xff1a; 软件&#xff1a;Keil5&#xff0c;程序在后面会给出 硬件&#xff1a;STM32F103最小系统、…

51单片机——LED点阵屏

51单片机——LED点阵屏 LED点阵屏LED点阵屏原理74HC595串转并芯片源代码例程一&#xff1a;静态笑脸效果展示 例程二&#xff1a;笑脸->平脸->哭脸效果展示 LED点阵屏 c51的LED点阵屏其实就是一个8*8像素的屏幕&#xff0c;一共有64个发光二极管。如下图 LED点阵屏原理…