1.数码管实验
1.1动态数码管显示
动态数码管显示就是应用了人眼的视觉停留,通过来回不停的点亮数码管来实现
- 这里可以看到P0口控制着数码管显示什么数字
//对共阴数码管0~F显示进行定义
unsigned char EIG_LED_POOL[16] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};
- P2^2;P2^3;P2^4口通过138译码器来控制哪个数码管显示
- 所以就需要不断地切换不同数码管进行显示
#include "reg52.h"
//对数码管进行宏定义
#define EIG_LED P0
//对数码管位选信号进行定义
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
//对共阴数码管0~F显示进行定义
unsigned char EIG_LED_POOL[16] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};
//设置延时函数
void delay(unsigned int tem)
{
while(tem--);
}
//设置数码管显示函数
void EIG_LED_DISPLAY()
{
unsigned char i = 0;
for(i=0;i<8;i++)
{
//这里就可以拿到数码管位选信号
switch(i)
{
case 0: LSC = 1; LSB = 1; LSA = 1; break;
case 1: LSC = 1; LSB = 1; LSA = 0; break;
case 2: LSC = 1; LSB = 0; LSA = 1; break;
case 3: LSC = 1; LSB = 0; LSA = 0; break;
case 4: LSC = 0; LSB = 1; LSA = 1; break;
case 5: LSC = 0; LSB = 1; LSA = 0; break;
case 6: LSC = 0; LSB = 0; LSA = 1; break;
case 7: LSC = 0; LSB = 0; LSA = 0; break;
}
EIG_LED = EIG_LED_POOL[i];//这里定义了数码管显示相应数字
delay(50000);//产生显示
EIG_LED = 0x00;//0x00数码管不显示,就是对数码管进行消零
}
}
void main()
{
while(1)
{
EIG_LED_DISPLAY();
}
}
实验现象:
数码管从左至右显示0~7
2.独立按键实验
按键需要进行消抖,常用的是软件方式消抖:
当检测到按键按下后,延迟几毫秒,再次进行检测
这里可以看到当按键按下后,IO口变成低电平
#include "reg52.h"
//对按键进行定义
sbit key1 = P3^1;
sbit key2 = P3^0;
sbit key3 = P3^2;
sbit key4 = P3^3;
//对led1进行定义
sbit led1 = P2^0;
//设置延时函数
void delay(unsigned int tem)
{
while(tem--);
}
//设置按键扫描
unsigned char KEY_SCAN()
{
static unsigned char time = 1;//这里使用static修饰time,让time存放在函数中,不会重新初始化
if(time==1&&key1==0)//这里添加time的检测,就是为了防止程序多次循环
{
delay(1000);
time = 0;
if(key1 == 0)
{
return 1;
}
}
else if(key1 == 1)
{
time = 1;
}
return 0;
}
void main()
{
unsigned char kkk = 0;
while(1)
{
kkk = KEY_SCAN();
if(kkk == 1)
{
led1 = !led1;//通过不断地反转led1,就可以实现led1灯通过按键实现亮灭
}
}
}
实验现象:
当按下按键k1,D1灯亮,再按,灭,如此循环
3.矩阵按键实验
行列扫描法检测时,先送一列为低电平,其余几列全为高电平(此时我们确 定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电 平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列 的,用同样方法轮流送各列一次低电平,再轮流检测一次各行是否变为低电平, 这样即可检测完所有的按键,当有键被按下时便可判断出按下的键是哪一个键。 当然我们也可以将行线置低电平,扫描列是否有低电平。从而达到整个键盘的检测。
//实现的实验现象
//按键s1-s16按下,数码管显示0~F
//在按键按下抬起后,数码管才显示数据
#include "reg52.h"
//对矩阵按键进行宏定义
#define KEY_MATRIX P1
//对数码管进行宏定义
#define LED_EIG P0
//定义延时函数
void delay(unsigned int tem)
{
while(tem--);
}
//对数码管0~F进行定义
unsigned char LED_EIG_POOL[16] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};
//使用行列式扫描方法
unsigned char KEY_MATRIX_RANK_SCAN()
{
static unsigned char key_value = 0;
KEY_MATRIX = 0xf7;//第一列赋值0,其余全为1
if(KEY_MATRIX != 0xf7)//当按键按下后,if语句成立,开始执行
{
delay(100);//消抖
switch(KEY_MATRIX)
{
case 0x77: key_value=1; break;
case 0xb7: key_value=5; break;
case 0xd7: key_value=9; break;
case 0xe7: key_value=13; break;
}
}
while(KEY_MATRIX != 0xf7);//在按键抬起之前,语句一直成立,实现按键抬起再显示
KEY_MATRIX = 0xfb;//第二列赋值0,其余全为1
if(KEY_MATRIX != 0xfb)//当按键按下后,if语句成立,开始执行
{
delay(100);//消抖
switch(KEY_MATRIX)
{
case 0x7b: key_value=2; break;
case 0xbb: key_value=6; break;
case 0xdb: key_value=10; break;
case 0xeb: key_value=14; break;
}
}
while(KEY_MATRIX != 0xfb);//在按键抬起之前,语句一直成立,实现按键抬起再显示
KEY_MATRIX = 0xfd;//第三列赋值0,其余全为1
if(KEY_MATRIX != 0xfd)//当按键按下后,if语句成立,开始执行
{
delay(100);//消抖
switch(KEY_MATRIX)
{
case 0x7d: key_value=3; break;
case 0xbd: key_value=7; break;
case 0xdd: key_value=11; break;
case 0xed: key_value=15; break;
}
}
while(KEY_MATRIX != 0xfd);//在按键抬起之前,语句一直成立,实现按键抬起再显示
KEY_MATRIX = 0xfe;//第四列赋值0,其余全为1
if(KEY_MATRIX != 0xfe)//当按键按下后,if语句成立,开始执行
{
delay(100);//消抖
switch(KEY_MATRIX)
{
case 0x7e: key_value=4; break;
case 0xbe: key_value=8; break;
case 0xde: key_value=12; break;
case 0xee: key_value=16; break;
}
}
while(KEY_MATRIX != 0xfe);//在按键抬起之前,语句一直成立,实现按键抬起再显示
return key_value;
}
void main()
{
unsigned char key = 0;
while(1)
{
key = KEY_MATRIX_RANK_SCAN();
if(key != 0)
{
LED_EIG = LED_EIG_POOL[key-1];
}
}
}
4.IO扩展-74HS595/LED点阵
4.1滚动显示
通过 74HC595 模块控制 LED 点阵以一行循环滚动显示。
注意这里跳线帽要接GND和OE
一个字节的数据要输入HC595中,需要一个比特一个比特的传输,先将数据存放到SER(即P34)中,再SRCLK接收到上升沿信号后将数据存放到移位寄存器中,这样进行8次后,再RCLK接收到上升沿信号将数据从移位寄存器存放到存储寄存器中进行显示。
#include "reg52.h"
//对P0端口进行宏定义
#define LED_COL P0
//对C595进行定义
sbit SER = P3^4;
sbit rCLK = P3^5;
sbit SRCLK = P3^6;
//建设一个LED点阵显示池
unsigned char LED_MATRIX_POOL[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
//设置延时函数
void delay(unsigned int tem)
{
while(tem--);
}
//向74HC595写入一个字节数据,并将数据移到存储寄存器中进行显示
void HC595_WRITE_DATA(unsigned char dat)
{
unsigned char i = 0;
for(i=0;i<8;i++)//循环8次将数据写入移位寄存器中
{
SER = dat>>7;//将拿到的dat数据向左移7位,最高位就变成了最低位,这样就可以将这位数据送入移位寄存器中
dat<<=1;//之后再将dat数据向左移1位,这样dat数据的次高位就变成了最高位,在下一次循环中就可将这个最高位的数据存放到移位寄存器中
SRCLK = 0;
delay(1);
SRCLK = 1;
delay(1);//SRCLK是通过接收上升沿信号将数据存放到移位寄存器中
}
rCLK = 0;
delay(1);
rCLK = 1;//移位寄存器接收到一个字节数据后,RCLK通过接收上升沿数据将移位寄存器中的数据存放到存储寄存器中
}
void main()
{
LED_COL = 0x00;//设置P0端口全为低
while(1)
{
unsigned char i = 0;
for(i=0;i<8;i++)
{
HC595_WRITE_DATA(LED_MATRIX_POOL[i]);
delay(10000);
HC595_WRITE_DATA(0x00);
}
}
}
4.2显示左上角一个点
- 点亮左上角的一个点,就需要对行列分别进行电平设置
- 让点亮的那个点,行为高,列为低
- 所以对应的行为0x80,列为0x7f
#include "reg52.h"
//对LED点阵列进行宏定义
#define LED_COL P0
//对LED点整行进行定义
sbit SER = P3^4;
sbit rCLK = P3^5;
sbit SRCLK = P3^6;
//定义延时函数
void delay(unsigned int tem)
{
while(tem--);
}
//HC595接收一个字节数据,并将数据存放到存储寄存器中
void HC595_WRITE_DATA(unsigned char dat)
{
unsigned char i = 0;
for(i=0;i<8;i++)
{
SER = dat>>7;
dat <<= 1;
SRCLK = 0;
delay(1);
SRCLK = 1;
delay(1);
}
rCLK = 0;
delay(1);
rCLK = 1;
}
void main()
{
while(1)
{
LED_COL = 0x7f;
HC595_WRITE_DATA(0x80);
}
}
4.3显示数字/显示图形
需要使用动态扫描,和数码管一样,通过设置极短的延时来达到
这里必须要设置消隐,不然就会出现显示不正确
扫描出的是列;
行是通过控制高低电平,当扫描到第一行,对应的将第一列设置为低电平,就可以让第一行第一列显示
#include "reg52.h"
//对LED点阵列进行宏定义
#define LED_COL P0
//对LED点阵行进行定义
sbit SER = P3^4;
sbit rCLK = P3^5;
sbit SRCLK = P3^6;
//设置延时函数
void delay(unsigned int tem)
{
while(tem--);
}
//扫描的行
unsigned char row[8] = {0x00,0x7C,0x82,0x82,0x82,0x7C,0x00,0x00};//显示0
unsigned char row2[8] = {0x38,0x7C,0x7E,0x3F,0x3F,0x7E,0x7C,0x38};//显示心型
//列,依次从左向右进行显示
unsigned char col[8] = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
//HC595写入一个字节的数据,并将数据存储到存储寄存器中
void HC595_WRITE_DATA(unsigned char dat)
{
unsigned char i = 0;
for(i=0;i<8;i++)
{
SER = dat>>7;
dat <<= 1;
SRCLK = 0;
delay(1);
SRCLK = 1;
delay(1);
}
rCLK = 0;
delay(1);
rCLK = 1;
}
void main()
{
while(1)
{
unsigned char i = 0;
for(i=0;i<8;i++)
{
LED_COL = col[i];
HC595_WRITE_DATA(row2[i]);
delay(100);
HC595_WRITE_DATA(0x00);//这里的消隐要加
}
}
}
5.直流电机
实验现象:电机转动3s左右,停止3s左右,以此循环
#include "reg52.h"
//定义直流电机
sbit DC_MOTO = P1^0;
//定义延时函数
//1 微秒(us)=0.001 毫秒(ms)
void delay_ms(unsigned int ms)
{
unsigned int i,j;
for(i=ms;i>0;i--)
for(j=100;j>0;j--);
}
void main()
{
while(1)
{
DC_MOTO = 1;
delay_ms(3000);
DC_MOTO = 0;
delay_ms(3000);
}
}