🚀write in front🚀
🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
💬本系列哔哩哔哩江科大51单片机的视频为主以及自己的总结梳理📚
前言:
本文是根据哔哩哔哩网站上"江协科技51单片机"视频的学习笔记,在这里会记录下江协科技51单片机开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了江协科技51单片机教学视频和链接中的内容。
引用:
51单片机入门教程-2020版 程序全程纯手打 从零开始入门_哔哩哔哩_bilibili
c51语言变量语句意思,C51中循环语句-CSDN博客
LED点阵引用:
江科大51单片机学习笔记之LED点阵屏_江科大led点阵屏-CSDN博客
51单片机关键字code,idata:
keil中C51关键字code用法_c51 code-CSDN博客
【51】单片机中的data、idata、xdata、code等关键字的作用-CSDN博客
模拟电梯控制:
【51单片机练习3------智能电梯控制系统1】_智能电梯系统-CSDN博客
基于51单片机的四层电梯控制系统_51单片机电梯控制系统设计-CSDN博客
51单片机学习------1天学完普中基本实验例程,走马观花式学习,大家切勿效仿。_普中单片机实验-CSDN博客
参考:
51单片机常用功能及相关内容_单片机_浪客小子-GitCode 开源社区
正文:
0. 🌿概述
在淘宝上购买了江协科技51单片机开发板套件(普中科技STC51单片机A2型号),就上在上一篇博文里说的自己计划学习下江协科技51单片机开发教程,通过STC51单片机这种MCU这种贴近于裸机的开发来增加对于系统硬件层面知识的了解和掌握。
1. 🚀51单片机控制LED点阵屏(8*8)
LED点阵屏(8*8)的点阵规格,可以分为单色屏,双色屏,三色屏(红绿蓝三色可以组成全彩色)
8*8 LED点阵显示屏的显示原理和8段LED数码段的驱动原理相似,LED点阵显示屏也需要按行或者按列的方式依次扫描显示每一行/列,控制行/列显示的内容。
8*8 LED显示点阵和数码管一样,有共阴极和共阳极两种接法,因为点阵矩阵可以按行或整案列查看所以单色LED 显示矩阵的共阴极和共阳极接线方法没有什么差异。但是对于双色的8*8 LED显示矩阵共阴极和共阳极的接线方法就有差异了。
2. 🚀51单片机开发板LED点阵屏电路原理图
我本次实验使用的普中科技51单片机开发板LED点阵屏电路原理图如下
经过测试开发板的实际接线如下,D0~D7接在 8*8 LED点阵的行,P00~P07接在LED点阵的列。
😎如果直接使用单片机的IO口来驱动 8*8 LED点阵则需要16个IO口,为了节约单片机IO口资源使用 74HC595移位寄存器来减少单片机IO口资源使用。
😎74HC595使用 3 个输入IO口,看控制8个IO口的输出。
3. 🚀 74HC595的使用
74HC595的工作原理
🚀 74HC595 是串行输入并行输出移位寄存器,可用3根线输入串行数据,8根线输出并行数据,多片级联后,可输出16位,24位,32位等,常用于IO口扩展。
串行输入,并行输出。
🌵左边是移位寄存器🌵右边是暂存寄存器
🛍️单片机IO口上电默认是高电平,所以需要初始化为低电平。
🛍️单片机IO口电路示意通中引脚符号上的"上划横线"表示低电平有效。
|-----------------------|-------|
| 引脚 | 说明 |
| RCLK (Register Clock) | 寄存器时钟 |
| SRCLK (Serial Clock) | 串行时钟 |
| SRCLR (Serial Clear) | 串行清零 |
| SER | 串行数据 |
| | |
🛍️单片机IO口输出是若上拉,其特性是输出低电平可以通过较大电流,输入高电平通过电流较弱。单片机IO口输出高电平驱动LED能力较弱,所以输出高电平驱动LED灯可以通过一个 74HC245缓冲器或者三极管来缓冲一下,增强IO口高电平信号的驱动能力。
即使是使用了74HC595来增大引脚的驱动能力驱动能力,输出点亮LED的亮度还是不均匀。
🛍️74HC595是恒压输出的,观察点阵屏的输出效果可以发现当74HC595一次点亮多个(例如8个)LDE灯时,LED灯的亮度要比一次点亮2个LED灯的亮度要弱。点阵显示屏显示动态数据的时候亮度不均匀。
🛍️原因是 74HC595是恒压输出的,解决方法可以是使用恒流输出的缓冲器,让每一个输出引脚的输出电流恒定当要驱动多个引脚时会自动增大总的输入电流。
74HC595 移位寄存器的串行输入引脚的移位寄存器的时序裸机操作:
🛍️ SER 为输入信号,当SRCLK时钟上升沿时SER的信号的一位数据(高电平为1,低电平为0)被保存到移位寄存器的最低位,同时移位寄存器里原有的数据位被往下平移一位。每次 SRCLK时钟上升沿时进行一次SER输入信号数据的锁存和移位,以此类推,SRCLK 出现8次时钟上升沿,SER输入的8为数据被保存到移位寄存器里。📚️
🛍️RCLK 寄存器时钟上升沿,移位寄存器里的8位数据被并行的输出到锁存寄存器里,当RCK寄存器为低电平时移位寄存器里的值对输出寄存器里的值不产生影响。📚️
🛍️74HC595移位寄存器可以多片级联,74HC595移位寄存器的 QH' 输出引脚可以连接到下一片74HC595一位寄存器的 SER 输入引脚,实现74HC595的多片级联,可以实现16位或32为IO口的扩展📚️
4. 🚀 Keil5 特殊功能寄存器 sfr 和 sbit 关键字
📚️ sfr (special function register):特殊功能寄存器
📚️ sbit(special bit):特殊位声明
📚️ 可位寻址/不可位寻址:在单片机系统中,操作任意寄存器或者寄存器某一位的数据时,必须给出其物理地址,又因为一个寄存器有8位,所谓位的数量是寄存器的8倍。单片机无法对所有的位进行编码,故每8个寄存器,只有一个是可以位寻址的。
5. 🚀 LED点阵屏显示笑脸
使用Excel 手动计算"笑脸"段码
第0列:0011 1100 = 0x3C
第1列:0100 0010 = 0x42
第2列:1001 1001 = 0x99
第3列:1000 0101 = 0x85
第4列:1000 0101 = 0x85
第5列:1001 1001 = 0x99
第6列:0100 0010 = 0x42
第7列:0011 1100 = 0x3c
编写源码,每次选中一列,在每一列上输出段码显示笑脸。
cpp
#include <REGX52.H>
#include <INTRINS.H>
#include "delay.h"
//sfr
//special function register
//special bit
sbit SER = P3^4; //SER
sbit RCK = P3^5; //RCLK
sbit SRCLK = P3^6; //SRCLK
void _74HC595_WriterByte(unsigned char Byte)
{
SER = Byte & 0x80; //非0即1
SRCLK = 1;
SRCLK = 0;
SER = Byte & 0x40; //非0即1
SRCLK = 1;
SRCLK = 0;
SER = Byte & 0x20; //非0即1
SRCLK = 1;
SRCLK = 0;
SER = Byte & 0x10; //非0即1
SRCLK = 1;
SRCLK = 0;
SER = Byte & 0x08; //非0即1
SRCLK = 1;
SRCLK = 0;
SER = Byte & 0x04; //非0即1
SRCLK = 1;
SRCLK = 0;
SER = Byte & 0x02; //非0即1
SRCLK = 1;
SRCLK = 0;
SER = Byte & 0x01; //非0即1
SRCLK = 1;
SRCLK = 0;
//移位寄存器并行输出到锁存寄存器
RCK = 1;
RCK = 0;
}
void _74HC595_Init()
{
//单片机启动默认IO口为高电平,需要初始化RCLK, SRCLK为低电平
SRCLK = 0;
RCK = 0;
}
//最左边列为低0列,最右边列为第7列
void _74HC595_ShowColumn(unsigned char Column, unsigned char Data)
{
_74HC595_WriterByte(Data);
P0 = ~(0x80 >> Column);
//同数码管一样,LED点阵也需要消影
Delay(1); //延时1ms给数据显示时间,延时时间太短的话LED亮度不够
P0 = 0xFF; //清除位选
}
void main()
{
unsigned char i = 0;
P0 = 0xFF;
_74HC595_Init();
_74HC595_WriterByte(0xFF);
while(1)
{
// P0 = ~(1 << i);
// Delay(200);
//
// i++;
// if(i >= 8)
// i = 0;
_74HC595_ShowColumn(0, 0x3C);
_74HC595_ShowColumn(1, 0x42);
_74HC595_ShowColumn(2, 0x99);
_74HC595_ShowColumn(3, 0x85);
_74HC595_ShowColumn(4, 0x85);
_74HC595_ShowColumn(5, 0x99);
_74HC595_ShowColumn(6, 0x42);
_74HC595_ShowColumn(7, 0x3C);
}
}
下载到单片机开发板,实际显示效果如下图所示:
6. 🚀 LED点阵屏显示动画-取模软件
附带资料里的取模软件,"新建图像",选择高度为8宽度为32
默认格点太小了,选择"模拟动画","放大格点",放大格点显示的大小方便操作,
放大格点之后效果
在取模软件里"参数设置","其它选型",就是我们取模的方式配置:
📗LED点阵屏显示有纵向扫描,也有横向扫描,我们这里使用的是纵向扫描每次扫描一列。
📗高位在上还是低位在上
鼠标狂点,在点阵里点击显示"Hello !" 字符。
提取子模,点击"取模方式","C51"格式
复制拷贝生成的子模,拷贝到我们的Keil5 源码编辑器里。
7 🚀 LED点阵屏显示动画-源码编写
流动文字显示的原理
流动字幕的显示原理:
📝第一次显示0到7列,然后偏移1列第二次显示1到8列,再偏移1列,第三次显示2-9列,这样每次偏移1列进行显示。
main.c 文件
cpp
#include <REGX52.H>
#include <INTRINS.H>
#include "delay.h"
#include "MatrixLED.h"
//默认放在RAM里面的
//code关键字,把数组放到Flash里面
unsigned char code Animation [] = {
/*-- 调入了一幅图像:这是您新建的图像 --*/
/*-- 宽度x高度=32x8 --*/
0x00,0x00,0x7D,0x00,0x00,0x00,0x00,0x00,
0xFF,0x08,0x08,0x08,0xFF,0x00,0x3E,0x49,
0x49,0x49,0x39,0x00,0xFF,0x01,0x02,0x00,
0xFF,0x01,0x03,0x00,0x3E,0x41,0x41,0x3E,
0x00,0x00,0x7D,0x00,0x00,0x00,0x00,0x00,
};
void main()
{
unsigned char i = 0;
unsigned char offset = 0;
unsigned char count = 0;
P0 = 0xFF;
MatrixLED_Init();
Animation[0] = 0x00;
while(1)
{
for(i=0; i< 8; i++){
MatrixLED_ShowColumn(i, Animation[i + offset]);
}
count++;
if(count >= 20)
{
count = 0;
offset++;
if(offset > (40 - 8))
offset = 0;
}
}
}
MatrixLED.c 文件
cpp
#include <REGX52.H>
#include <INTRINS.H>
#include "delay.h"
#incldue "MatrixLED.h"
//sfr
//special function register
//special bit
sbit SER = P3^4; //SER
sbit RCK = P3^5; //RCLK
sbit SRCLK = P3^6; //SRCLK
#define MATRIX_LED_PORT P0
/**
* @brief 74HC595写入一个字节
* @param Byte 要写入的字节
* @retval 无
*/
void MatrixLED_WriterByte(unsigned char Byte)
{
SER = Byte & 0x80; //非0即1
SRCLK = 1;
SRCLK = 0;
SER = Byte & 0x40; //非0即1
SRCLK = 1;
SRCLK = 0;
SER = Byte & 0x20; //非0即1
SRCLK = 1;
SRCLK = 0;
SER = Byte & 0x10; //非0即1
SRCLK = 1;
SRCLK = 0;
SER = Byte & 0x08; //非0即1
SRCLK = 1;
SRCLK = 0;
SER = Byte & 0x04; //非0即1
SRCLK = 1;
SRCLK = 0;
SER = Byte & 0x02; //非0即1
SRCLK = 1;
SRCLK = 0;
SER = Byte & 0x01; //非0即1
SRCLK = 1;
SRCLK = 0;
//移位寄存器并行输出到锁存寄存器
RCK = 1;
RCK = 0;
}
/**
* @brief 点阵屏初始化
* @param 无
* @retval 无
*/
void MatrixLED_Init()
{
//单片机启动默认IO口为高电平,需要初始化RCLK, SRCLK为低电平
SRCLK = 0;
RCK = 0;
}
/**
* @brief LED点阵屏显示一列数据
* @param Column 要显示的列,范围0~7,0在最左边
* @param Data 选择列显示的数据,高位在上,1为亮,0为灭
* @retval 无
*/
void MatrixLED_ShowColumn(unsigned char Column, unsigned char Data)
{
MatrixLED_WriterByte(Data);
MATRIX_LED_PORT = ~(0x80 >> Column);
//同数码管一样,LED点阵也需要消影
Delay(1); //延时1ms给数据显示时间,延时时间太短的话LED亮度不够
MATRIX_LED_PORT = 0xFF; //清除位选
}
MatrixLED.h 文件
cpp
#ifndef __MATRIXLED_H__
#define __MATRIXLED_H__
void MatrixLED_WriterByte(unsigned char Byte);
void MatrixLED_Init();
void MatrixLED_ShowColumn(unsigned char Column, unsigned char Data);
#endif
显示效果
8. 关键字'code'将数组放到单片机内部Flash中
🍎关键字'code'将数组放到单片机内部Flash中。
当没有关键字code的时候,默认 unsigned char Animation [] 数组执行时会被放到 SRAM 中,因为STC89C52系列单片机的Flash一般是 4KB或者8KB,SRAM的大小是512字节。当需要显示的点阵屏数组内容是固定不点的时候,可以使用 'code' 关键字将数组的内容放到单片机的Flash中存储,而不用加载到DRAM中,节省宝贵的DRAM资源。
🍎当使用了关键字'code'之后,在程序代码中就不能修改数组中内容的值了,否则在编译的时候编译器就报报错提示程序尝试修改'unmodified location。'