实验一:控制动态数码管从左至右显示0—7:
学习视频:11.5-动态数码管实验--软件编程_哔哩哔哩_bilibili
#include "reg51.h"
#include "intrins.h"
typedef unsigned int u16;
typedef unsigned char u8;
#define SMG_A_DP_PORT P0 // 宏定义 SMG_A_DP_PORT 代表 P0
sbit LSA = P2^2; // 译码器 位控制器 详情见解析1.2
sbit LSB = P2^3; // 译码器 位控制器
sbit LSC = P2^4; // 译码器 位控制器
u8 gsmg_code[17] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71};
// 用smg_code数组来存储数值和字母,第一排:0,1,2,3,4,5,6,7,8,9, 第二排:A,b,C,d,E,F, 详情见解析1.1
void delay10us(u16 ten_us) // 延时程序
{
while(ten_us--);
}
void smg_display()
{
u8 i = 0;
for(i=0;i<8;i++) // 在for循环中 依次设置位控制来选择显示的数码管
{
switch(i)
{
case 0: LSC = 1;LSB = 1;LSA = 1; break; //当i=0时P2.4 P2.3 P2.2为111对应LED8
case 1: LSC = 1;LSB = 1;LSA = 0; break; //当i=1时P2.4 P2.3 P2.2为110对应LED7
case 2: LSC = 1;LSB = 0;LSA = 1; break; //当i=2时P2.4 P2.3 P2.2为101对应LED6
case 3: LSC = 1;LSB = 0;LSA = 0; break; //当i=3时P2.4 P2.3 P2.2为100对应LED5
case 4: LSC = 0;LSB = 1;LSA = 1; break; //当i=4时P2.4 P2.3 P2.2为011对应LED4
case 5: LSC = 0;LSB = 1;LSA = 0; break; //当i=5时P2.4 P2.3 P2.2为010对应LED3
case 6: LSC = 0;LSB = 0;LSA = 1; break; //当i=6时P2.4 P2.3 P2.2为001对应LED2
case 7: LSC = 0;LSB = 0;LSA = 0; break; //当i=7时P2.4 P2.3 P2.2为000对应LED1
}
SMG_A_DP_PORT = gsmg_code[i]; // 对应LED后,显示数字0-7 正好与i对应,所以直接用i在数组中的位置,i=0对应gsmg_code[0]也为0
delay10us(100); // 延时1000us = 1ms 肉眼观察不到是依次显示
SMG_A_DP_PORT = 0x00; // 消除上一个同一位置的显示光影
}
}
void main()
{
while(1)
{
smg_display();
}
}
解析1.1:
需要了解数码管的构造:51单片机数码管是共阴极,顾名思义,共阴极数码管有个共同的阴极,即 有共同一端是接地的,如图所示。因此,当数码管引脚为高电平(为1)的时候,就会被点亮。
如图所示:当需要在数码管显示——数字 4 ,需要将B、C、F、G赋1值,于是要将P0赋值为二进制0110 0110 ,即16进制P0=0x66。
由上可得,一个数码管需要8位数据线来显形,那多个数码管就需要很多数据线或者I/O口来操作,显然很笨,于是需要引入控制线来控制哪个数码管被当前操作。
解析1.2:
74HC138译码器,通过P2.4、P2.3、P2.2来控制这8个LED灯的选择。
P2.4、P2.3、P2.2 有3个二进制位:
000 = Y0 ---> LED1
001 = Y1 ---> LED2
010 = Y2 ---> LED3
011 = Y3 ---> LED4
100 = Y4 ---> LED5
101 = Y5 ---> LED6
110 = Y6 ---> LED7
111 = Y7 ---> LED8
实验二:控制动态数码管从左至右显示 自己输入的数:
学习视频:07.多位数码管扫描显示_哔哩哔哩_bilibili
#include "reg51.h"
#include "intrins.h"
typedef unsigned int u16;
typedef unsigned char u8;
#define SMG_A_DP_PORT P0 // 宏定义 SMG代表数码管
u8 gsmg_code[17] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71};
u8 date_code[8] = {7,0,8,0,4,2,0,2}; // 自己输入,笔者这里输入的是日期:20240807 从低到高
void delay10us(u16 ten_us) // 延时程序
{
while(ten_us--);
}
void main()
{
u8 i=0;
while(1)
{
for(i=0;i<8;i++)
{
P2 = i<<2; // 直接P2赋值 i是几就点亮第几位LED 笔者也不知道原因
SMG_A_DP_PORT=gsmg_code[date_code[i]]; // 对P0赋值
delay10us(50); // 延时短一点,人眼看到时连续的
}
}
}
实验三:控制动态数码管显示 自己输入的一个三位数:
学习视频:07.多位数码管扫描显示_哔哩哔哩_bilibili
#include "reg51.h"
#include "intrins.h"
typedef unsigned int u16;
typedef unsigned char u8;
#define SMG_A_DP_PORT P0 // 宏定义P0
u8 gsmg_code[17] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71,0x00};
// 数组gsmg_code保存数字 0-9,A-F,外加一个0x00(空)
u8 date_code[8] = {0,0,0,16,16,16,16,16}; // 构建一个数组来保存要输入的三位数, gsmg_code[16] = 0x00;表示LED高位都是不显示
u16 shuzi_code = 456; // 输入一个三位数字,因为456 > 255(1+2+4+8+16+32+64+128) 所以要用u16来定义类型
void delay10us(u16 ten_us) // 延时程序
{
while(ten_us--);
}
void main()
{
u8 i=0;
while(1)
{
for(i=0;i<8;i++) // for循环来选择要显示的LED位
{
date_code[0]=shuzi_code%10; // 取出三位数的个位放到LED最低位
date_code[1]=shuzi_code/10%10; // 取出三位数的十位放到LED最二位
date_code[2]=shuzi_code/100; // 取出三位数的百位放到LED最三位
P2 = i<<2; // i是几,LED的显示位就是几
SMG_A_DP_PORT = gsmg_code[date_code[i]]; // LED显示数
delay10us(50); // 延时到眼睛看不到依次循环显示残影
SMG_A_DP_PORT = 0x00; // 把LED每一位都为空,消除每一次循环上一次显示的残影
}
}
}
实验四:控制动态数码管显示 时间 并正常走动:
#include "reg51.h"
#include "intrins.h"
typedef unsigned int u16;
typedef unsigned char u8;
#define SMG_A_DP_PORT P0 // 宏定义数码管
u8 gsmg_code[18] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,
0x77,0x7c,0x39,0x5e,0x79,0x71,0x00,0x40}; // 多添加了横杠-:0x40
u8 date_code[8] = {16,16,17,16,16,17,16,16}; // 初始化晶体管
u16 hour=12, min=59, sec=22; // 设置时间变量初值
u8 count = 0;
void delay10us(u16 ten_us) // 延时程序
{
while(ten_us--);
}
jisuan() // 将时间变量计算到date_code数组中,最后输入到P0
{
date_code[0] = sec%10; // 最低两位显示 秒
date_code[1] = sec/10;
date_code[3] = min%10; // 中间两位显示 分
date_code[4] = min/10;
date_code[6] = hour%10; // 最高两位显示 时
date_code[7] = hour/10;
}
void main()
{
u8 i=0;
while(1)
{
for(i=0;i<8;i++) // 循环 位控制LED的显示位
{
P2 = i<<2; // i为几,LED第几位显示
SMG_A_DP_PORT = gsmg_code[date_code[i]]; // LED显示数值
delay10us(100);
SMG_A_DP_PORT = 0x00; // LED消除上次显示的光影
}
count++; // count记录执行了多少次for循环
if(count==100) // for每循环执行一次 要8*1.25ms=10ms 当count为100时,用时100*10ms=1s (我猜的理论上是这样)
{
count=0;
sec++;
if(sec==60) // 用时1s后sec+1,加到60 min+1,以此类推
{
sec=0;
min++;
if(min==60)
{
min=0;
hour++;
if(hour==24)
{
hour=0;
}
}
}
jisuan(); // sec、min、hour计算完成后保存到date_code数组,最后在while下次循环中写到数码管中
}
}
}
以上内容,学习参考所用。如有侵权,Call我必删。