51单片机笔记[1]-基础实验
实验目的
- 掌握使用KEIL,Proteus软件
- 掌握程序下载方法
实验内容
点亮发光二极管
按下K1按键(P2.0),点亮发光二极管(P1.0)LED1
按下K2按键(P2.1),LED1~LED8(P1口)双向流水灯
P1.0口连接的发光二极管,编写子程序,实现闪烁5次后,常亮
矩阵键盘按键显示
按下矩阵键盘(4*4),通过数码管静态显示按键键码值0-F
数码管显示
P2口连接的7段共阳极数码管,编写子程序实现循环显示1-F
P1口连接的7段共阳极数码管,编写子程序实现循环显示9-1
实验原理
io口的4种模式
- 推挽输出
- 高阻输入(上拉输入)
- 开漏输出
- 准双向I/O
51单片机操作io口
sbit:定义特殊功能寄存器的位变量.
P4^0:P4组io的第一个管脚
4x4键盘读取
常见的按键扫描方式有:
- io口直接与按键一一对应,适用于io口较多的情况
- 矩阵式,通过行扫描和列扫描最终确定按键,但是这样会造成键位冲突
- 使用逻辑芯片扩展,如74HC595D并入串出芯片
- 电阻采样扩展,设置不同的按键电阻,按下键时单片机AD采样到不同的电压
矩阵键盘的按键扫描方式
对于矩阵键盘,我们只能逐行扫描,然后读取列的状态信号。如果R3行输出低电平,那么黄色按键如果有按下动作的话,那读取C2列信号也应该为低电平,而该行上其他没有按下动作的按键的列信号则为高电平。因此,我们可以得到矩阵键盘的基本扫描步骤:
- R1输出低电平,R2、R3、R4输出高电平,逐个读取C1、C2、C3、C4判断列信号,如果都为高电平则R1行上没有按键按下。
- R2输出低电平,R1、R3、R4输出高电平,逐个读取C1、C2、C3、C4判断列信号。
- R3输出低电平,R1、R2、R4输出高电平,发现C2列信号为低电平,那么可以判断得R3行的C2列的按键有按下动作。
- R4输出低电平,R1、R3、R4输出高电平,逐个读取C1、C2、C3、C4判断列信号。
如此循环往复,扫描的按键的我们知道有按键按下动作,那么又怎么知道是哪一个按键按下呢?这时,我们最好定义一个键值全局变量,给矩阵行列上的每一个的按键编一个唯一的号码。当扫描的某一行某一列的按键动作后,把对应的编号复制给键值变量,这样我们判断这个键值,就知道是哪个按键有触发动作了。
注意事项:R行引脚全部设置为开漏,C列引脚全部设为上拉输入
还有一种扫描方法称为线反转法.
[https://blog.csdn.net/shmily_cml0603/article/details/7079554]
[https://blog.csdn.net/weixin_39799646/article/details/112065230]
实验过程
仿真图
LED流水灯 | 矩阵键盘按键 |
---|---|
![]() |
![]() |
流程图
画的可能不太标准,还请见谅
发光二极管 | 双向流水灯 | LED闪烁 | 数码管显示 | 矩阵键盘扫描 |
---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
程序
1.c
#include <reg52.h>
#include <stdio.h>
sbit LED0=P1^0;
sbit BUTTON1=P2^0;
sbit BUTTON2=P2^1;
void delay()//延时函数
{
unsigned char a,b;
for(a=0;a<200;a++)
for(b=0;b<200;b++);;
}
void key()
{
if(BUTTON1==0)
{
delay();
if(BUTTON1==0)
{
LED0=~LED0;
}
while(!BUTTON1);
}
}
void main(void){
while(1){
LED0=1;
key();
}
}
2.c
//流水灯
#include <reg52.h>
#include <stdio.h>
#include <intrins.h>//循环移位
#define LED(NUM) LED##i
sbit BUTTON=P2^1;
//灯
sbit LED1=P1^0;
sbit LED2=P1^1;
sbit LED3=P1^2;
sbit LED4=P1^3;
sbit LED5=P1^4;
sbit LED6=P1^5;
sbit LED7=P1^6;
sbit LED8=P1^7;
unsigned char LED[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
//延时函数
void delay(){
int a,b;
for(a=0;a<200;a++) for(b=0;b<200;b++);;
}
int main(void){
while(1){
BUTTON=1;
if(BUTTON==0){
int i;
for(i=1;i<8;i++){
//LED(NUM)=1;
P1=LED[i];
delay();
}
for (i=8;i>0;i--){
P1=LED[i];
delay();
}
}
}
}
3.c:面向百度编程😏
#include <stdio.h>
#include <reg52.h>
//矩阵键盘按键显示
//TODO:按键消抖
//段码表
unsigned char distab[16] = {
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
};//0-F
//显示0字符:P1=distab[0]
//显示函数
void show_char(int input){
//while(1){
P0=0xFF;
P0=~distab[input];
//}
}
//延时函数
delay(){
int i,j;
for(i=0;i<200;i++){
for(j=0;j<200;j++);
}
}
//回调函数
_delay(int function){
int i,j;
}
//按键检测
unsigned char keyscan()
{ unsigned char tempkey;
int num;
P1=0xfe;
tempkey=P1;
tempkey=tempkey&0xf0;
while(tempkey!=0xf0)
{
tempkey=P1;
tempkey=tempkey&0xf0;
while(tempkey!=0xf0)
{
tempkey=P1;
switch(tempkey)
{
case 0xee:num=10;show_char(10); //A
break;
case 0xde:num=3;show_char(3);
break;
case 0xbe:num=2;show_char(2);
break;
case 0x7e:num=1;show_char(1);
break;
}
while(tempkey!=0xf0)
{
tempkey=P1;
tempkey=tempkey&0xf0;
}
}
}
P1=0xfd;
tempkey=P1;
tempkey=tempkey&0xf0;
while(tempkey!=0xf0)
{
tempkey=P1;
tempkey=tempkey&0xf0;
while(tempkey!=0xf0)
{
tempkey=P1;
switch(tempkey)
{
case 0xed:num=11;show_char(11);//B
break;
case 0xdd:num=6;show_char(6);
break;
case 0xbd:num=5;show_char(5);
break;
case 0x7d:num=4;show_char(4);
break;
}
while(tempkey!=0xf0)
{
tempkey=P1;
tempkey=tempkey&0xf0;
}
}
}
P1=0xfb;
tempkey=P1;
tempkey=tempkey&0xf0;
while(tempkey!=0xf0)
{
tempkey=P1;
tempkey=tempkey&0xf0;
while(tempkey!=0xf0)
{
tempkey=P1;
switch(tempkey)
{
case 0xeb:num=12;show_char(12); //C
break;
case 0xdb:num=9;show_char(9);
break;
case 0xbb:num=8;show_char(8);
break;
case 0x7b:num=7;show_char(7);
break;
}
while(tempkey!=0xf0)
{
tempkey=P1;
tempkey=tempkey&0xf0;
}
}
}
P1=0xf7;
tempkey=P1;
tempkey=tempkey&0xf0;
while(tempkey!=0xf0)
{
tempkey=P1;
tempkey=tempkey&0xf0;
while(tempkey!=0xf0)
{
tempkey=P1;
switch(tempkey)
{
case 0xe7:num=13;show_char(13);
break;
case 0xd7:num=14;show_char(14);
break;
case 0xb7:num=0;show_char(0);
break;
case 0x77:num=14;show_char(15);
break;
}
while(tempkey!=0xf0)
{
tempkey=P1;
tempkey=tempkey&0xf0;
}
}
}
}
//开机加载效果
void onload(){
int i;
for(i=0;i<16;i++){
P1=0x0;
show_char(i);
delay();
}
//清屏
P0=0xff;
}
//主函数
int main(void){
onload();
while(1){
keyscan();
//key();
}
}
备注
最终实现可能与实验内容有一点点出入(管脚不同或功能增减)
真机调试
平台:“普中-3”51开发板
备注:开发板与仿真管脚排列及配置有所不同
开发板原理图
开发板实物图
代码
编译及烧录
USB转TTL模块短接好(即 P31T 与 URXD 连接,P30R 与 UTXD 连接)
单片机:STC89C52RC
注意:使用STC-ISP下载时,需要先上电电脑识别到串口,打开hex文件点击下载后重新开启电源(冷启动)
然后按一下reset键
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库