普中科技51单片机部分源代码(入门)
一:准备工作
软/硬件准备
事先声明该单片机的芯片是STC89C52RC/LE52RC(对应keil中的AT89C52)。使用的软件是keil uVision5与AiCube-ISP-v6.96T
一个常见问题的解答
这一部分是关于单片机本身的。一些学习者可能已经在使用普中科技的单片机进行相关的学习了,在这个过程也许会发现这样一个现象:
当编写好一个使用8*8LED点阵或1*8LED模块的程序时,运行是正常的,但是这时如果又编写了一个使用1*8LED模块或8*8LED点阵的程序时会发现在xtc中点击下载/编程后,进度一直卡在“正在检测目标单片机”或者直接显示“连接超时,请检查单片机”,或者连接成功后单片机没有展现出预期的效果,出现这个的原因可能是(以下回答来自AI):





总而言之,在涉及到关于8*8LED点阵与1*8LED模块的问题时,可以尝试更换另一种连接方式来解决,如果不起效果再另寻其他原因。
二:部分代码
实验1:点亮一个LED
效果如下:

程序如下:
#include "reg52.h"
/*
作用:包含头文件
解释:reg52.h是51单片机的寄存器定义头文件。它告诉编译器:
单片机有哪些特殊功能寄存器(如P0、P1、P2、P3)
这些寄存器的地址是什么
可以定义位操作(如sbit)
类比:就像C语言中的#include <stdio.h>,包含了printf、scanf等函数的声明
*/
sbit LED = P2^0;
/*
作用:定义位变量
分解:
sbit:special bit,特殊位声明,用于定义单片机的某个具体引脚
LED:你给这个引脚起的别名,方便编程
P2^0:表示P2口的第0位(最低位)
P2是51单片机的4个8位并行I/O口之一(P0、P1、P2、P3)
^0表示第0位,^1表示第1位,...,^7表示第7位
硬件对应:在开发板上,P2.0引脚通常连接着一个LED灯
注意:51单片机的I/O口是准双向口,既能输入也能输出
*/
void main()
{
while(1)
{
LED = 0;//阳极通常接到高电平(这是固定的),所以要想控制LED的亮灭,所以只能通过
//控制LED阴极的状态来实现亮灭,亮为0,灭为1
}
}
/*
作用:主函数,程序入口
解释:和标准C语言一样,main()是程序开始执行的地方
51单片机特点:main()函数永远不会返回,所以通常是void类型
while(1)创建一个死循环,程序在这里不断重复执行
单片机程序必须有无限循环,否则程序执行完main()就结束了
括号{}内是循环体
*/
实验2:点亮一排LED
效果如下:

程序如下:
#include "reg52.h"
void main()
{
while(1)
{
P2 = 0x00;
/*
P2是什么?
P2是51单片机的第3个8位并行I/O口
它有8个引脚:P2.0, P2.1, P2.2, P2.3, P2.4, P2.5, P2.6, P2.7
每个引脚可以独立控制,输出0(低电平)或1(高电平)
2. 0x00是什么?
0x前缀:表示这是十六进制数
00:十六进制数00
*/
}
}
实验3:1*8LED流水灯
简单实现
程序如下:
#include "reg52.h"
#include <intrins.h> // 包含_crol_循环左移函数
typedef unsigned int u16;
typedef unsigned char u8;
void delay(u16 t)
{
while(t--);
}
void main()
{
u8 led = 0xFE; // 1111 1110,只有P2.0=0(低电平点亮第一个LED)
while(1)
{
P2 = led; // 输出到P2口
delay(50000); // 延时
led = _crol_(led, 1); // 循环左移1位
// 当移回初始状态时,重置(可选)
if(led == 0x7F) // 0111 1111,只有P2.7=0
{
delay(50000);
}
}
}
依次点亮再依次熄灭
结构如下:

程序如下:
main.c
#include "led.h"
void main()
{
while(1)
{
led_server();
}
}
CONFIG.h
#ifndef __CONFIG_H__
#define __CONFIG_H__
#include <reg52.h>
typedef unsigned int u16;
#endif
delay.c
#include <delay.h>
void delay_ms(u16 time)
{
u16 i,j;
for (i = 0; i < time; i++) //软件延时,大约1000ms,即1秒
for (j = 0; j < 110; j++);
}
DELAY.h
#ifndef _DELAY_H_
#define _DELAY_H_
#include "config.h"
//函数申明
void delay_ms(u16 time);
#endif
led.h
#ifndef _DELAY_H_
#define _DELAY_H_
#include "config.h"
//函数申明
void delay_ms(u16 time);
#endif
led.c
#include "led.h"
#define TIME 100
void led_server()
{
char i;
for(i = 0;i < 8;i++)
{
//将数字1左移i位
LED_PIN &= ~(1 << i);// 低电平点亮
delay_ms(TIME);
}
for(i= 7;i >= 0;i--)
{
LED_PIN |= (1 << i); // 高电平关闭
delay_ms(TIME); //延时1s
}
}
实验4:8*8LED点阵显示
显示单个字母
以8*8LED点阵显示字母“O”为例
效果如下:

程序如下:
/**************************************************************************************
* 8*8LED点阵———显示数字实验 *
实现现象:下载程序后点阵上显示数字0
注意事项:一定要将J24短接片短接到GND端。
***************************************************************************************/
#include "reg51.h" //此文件中定义了单片机的一些特殊功能寄存器
#include<intrins.h>
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
sbit SRCLK=P3^6;
sbit RCLK=P3^5;
sbit SER=P3^4;
//SER是数据,SRCLK是"进一位"信号,RCLK是"确定输出"信号
u8 ledduan[]={0x00,0x00,0x3e,0x41,0x41,0x41,0x3e,0x00};
u8 ledwei[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
/*******************************************************************************
* 函 数 名 : delay
* 函数功能 : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
while(i--);
}
/*******************************************************************************
* 函数名 : Hc595SendByte(u8 dat)
* 函数功能 : 向74HC595发送一个字节的数据
* 输入 : 无
* 输出 : 无
*******************************************************************************/
void Hc595SendByte(u8 dat)
{
u8 a;
SRCLK=0;
RCLK=0;
for(a=0;a<8;a++)
{
SER=dat>>7;
dat<<=1;
SRCLK=1;
_nop_();
_nop_();
SRCLK=0;
}
RCLK=1;
_nop_();
_nop_();
RCLK=0;
}
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
u8 i;
while(1)
{
P0=0x7f;
for(i=0;i<8;i++)
{
P0=ledwei[i]; //位选
Hc595SendByte(ledduan[i]); //发送段选数据
delay(100); //延时
Hc595SendByte(0x00); //消隐
}
}
}
回形流水灯
灯会在最外层依次点亮,像流水灯那样
程序如下:
#include "reg51.h"
#include <intrins.h>
typedef unsigned int u16;
typedef unsigned char u8;
sbit SRCLK = P3^6;
sbit RCLK = P3^5;
sbit SER = P3^4;
u8 code row_mask[] = {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F};
u8 code col_mask[] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
// 简化路径:直接计算位置
u8 get_next_pos(u8 *row, u8 *col)
{
static u8 direction = 0; // 0:右, 1:下, 2:左, 3:上
static u8 r = 0, c = 0;
switch(direction)
{
case 0: // 向右移动
c++;
if(c == 7) direction = 1; // 到最右,改为向下
break;
case 1: // 向下移动
r++;
if(r == 7) direction = 2; // 到最下,改为向左
break;
case 2: // 向左移动
c--;
if(c == 0) direction = 3; // 到最左,改为向上
break;
case 3: // 向上移动
r--;
if(r == 0) direction = 0; // 到最上,改为向右
break;
}
*row = r;
*col = c;
return 1;
}
void delay(u16 t) { while(t--); }
void Hc595SendByte(u8 dat)
{
u8 i;
for(i = 0; i < 8; i++)
{
SER = (dat >> 7) & 1;
dat <<= 1;
SRCLK = 0; _nop_(); SRCLK = 1;
}
RCLK = 0; _nop_(); RCLK = 1; _nop_(); RCLK = 0;
}
void main()
{
u8 i, row, col;
// 从左上角开始
row = 0; col = 0;
while(1)
{
// 动态扫描显示当前点
for(i = 0; i < 8; i++)
{
P0 = row_mask[i]; // 选择行
if(i == row) // 目标行
Hc595SendByte(col_mask[col]); // 点亮目标列
else
Hc595SendByte(0x00); // 其他行灭
delay(5);
Hc595SendByte(0x00); // 消隐
}
// 延时控制流动速度
delay(1000);
// 获取下一个位置
get_next_pos(&row, &col);
// 如果回到起点,稍微延时
if(row == 0 && col == 0)
delay(1000);
}
}
实验5:8*8LED点阵显示英文字母A到Z
效果一:依次闪烁26个英文字母
一个英文字母显示一段时间后切换到下一个英文字母,从A循环到Z之后回到A继续循环
程序如下:
// 完整修正版 - 字母方向一致
#include "reg51.h"
#include <intrins.h>
typedef unsigned int u16;
typedef unsigned char u8;
sbit SRCLK = P3^6;
sbit RCLK = P3^5;
sbit SER = P3^4;
// 修正后的字模库 - 所有字母方向一致
// 注意:这里有两种可能的字模,根据你的点阵实际效果选择一种
u8 code AlphabetFont[26][8] = {
// 版本A:适用于行从上到下扫描的点阵
{0x00,0x18,0x24,0x42,0x7E,0x42,0x42,0x42}, // A
{0x00,0x7C,0x42,0x42,0x7C,0x42,0x42,0x7C}, // B
{0x00,0x3C,0x42,0x40,0x40,0x40,0x42,0x3C}, // C
{0x00,0x7C,0x42,0x42,0x42,0x42,0x42,0x7C}, // D
{0x00,0x7E,0x40,0x40,0x7C,0x40,0x40,0x7E}, // E
{0x00,0x7E,0x40,0x40,0x7C,0x40,0x40,0x40}, // F
{0x00,0x3C,0x42,0x40,0x4E,0x42,0x42,0x3C}, // G
{0x00,0x42,0x42,0x42,0x7E,0x42,0x42,0x42}, // H
{0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x7C}, // I
{0x00,0x1F,0x04,0x04,0x04,0x44,0x44,0x38}, // J
{0x00,0x42,0x44,0x48,0x70,0x48,0x44,0x42}, // K
{0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x7E}, // L
{0x00,0x42,0x66,0x5A,0x42,0x42,0x42,0x42}, // M
{0x00,0x42,0x62,0x52,0x4A,0x46,0x42,0x42}, // N
{0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x3C}, // O
{0x00,0x7C,0x42,0x42,0x7C,0x40,0x40,0x40}, // P
{0x00,0x3C,0x42,0x42,0x42,0x4A,0x44,0x3A}, // Q
{0x00,0x7C,0x42,0x42,0x7C,0x48,0x44,0x42}, // R
{0x00,0x3C,0x42,0x40,0x3C,0x02,0x42,0x3C}, // S
{0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10}, // T
{0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x3C}, // U
{0x00,0x42,0x42,0x42,0x42,0x24,0x24,0x18}, // V
{0x00,0x42,0x42,0x42,0x42,0x5A,0x66,0x42}, // W
{0x00,0x42,0x42,0x24,0x18,0x18,0x24,0x42}, // X
{0x00,0x44,0x44,0x28,0x10,0x10,0x10,0x10}, // Y
{0x00,0x7E,0x02,0x04,0x08,0x10,0x20,0x7E} // Z
};
// 测试版本B:行顺序反转的字模(如果上面版本方向不对)
u8 code AlphabetFont2[26][8] = {
{0x42,0x42,0x42,0x7E,0x42,0x24,0x18,0x00}, // A(反转)
{0x7C,0x42,0x42,0x7C,0x42,0x42,0x7C,0x00}, // B(反转)
{0x3C,0x42,0x40,0x40,0x40,0x42,0x3C,0x00}, // C(反转)
{0x7C,0x42,0x42,0x42,0x42,0x42,0x7C,0x00}, // D(反转)
// ... 其他字母类似反转
};
// 关键:尝试不同的行扫描顺序
// 版本1:从上到下扫描(默认)
u8 code RowScan1[] = {0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE};
// 版本2:从下到上扫描
u8 code RowScan2[] = {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F};
// 版本3:任意顺序扫描
u8 code RowScan3[] = {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F};
// 当前使用的扫描表
#define RowScan RowScan2 // 先试版本2,如果不行换版本1
void delay(u16 i)
{
while(i--);
}
void Hc595SendByte(u8 dat)
{
u8 i;
SRCLK = 0;
RCLK = 0;
for(i = 0; i < 8; i++)
{
SER = (dat & 0x80) >> 7;
dat <<= 1;
SRCLK = 1;
_nop_();
_nop_();
SRCLK = 0;
}
RCLK = 1;
_nop_();
_nop_();
RCLK = 0;
}
void main()
{
u8 letter = 0;
u16 i, scan_count;
u8 direction_test = 0; // 方向测试标志
while(1)
{
// 显示当前字母
for(scan_count = 0; scan_count < 50; scan_count++) // 显示约0.25秒
{
// 扫描显示整个字母
for(i = 0; i < 8; i++)
{
P0 = RowScan[i];
Hc595SendByte(AlphabetFont[letter][i]);
delay(50);
Hc595SendByte(0x00);
}
}
// 切换到下一个字母
letter++;
if(letter >= 26)
{
letter = 0;
// 每轮结束后可以测试不同方向
direction_test ^= 1; // 切换方向测试
}
}
}
效果二:动态,流水式的显示英文字母
具体效果是显示的字母不会立即消失,而是一段一段移动,一个字母接着一个字母的显示,就像是大街上的那种LED广告屏,字不会突然消失,而是从一边移动到另一边
// 修正完整版 - 实现平滑流水式显示A-Z字母
#include "reg51.h"
#include <intrins.h>
typedef unsigned int u16;
typedef unsigned char u8;
sbit SRCLK = P3^6;
sbit RCLK = P3^5;
sbit SER = P3^4;
// 字母字模库(8x8)
u8 code AlphabetFont[26][8] = {
{0x00,0x18,0x24,0x42,0x7E,0x42,0x42,0x42}, // A
{0x00,0x7C,0x42,0x42,0x7C,0x42,0x42,0x7C}, // B
{0x00,0x3C,0x42,0x40,0x40,0x40,0x42,0x3C}, // C
{0x00,0x7C,0x42,0x42,0x42,0x42,0x42,0x7C}, // D
{0x00,0x7E,0x40,0x40,0x7C,0x40,0x40,0x7E}, // E
{0x00,0x7E,0x40,0x40,0x7C,0x40,0x40,0x40}, // F
{0x00,0x3C,0x42,0x40,0x4E,0x42,0x42,0x3C}, // G
{0x00,0x42,0x42,0x42,0x7E,0x42,0x42,0x42}, // H
{0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x7C}, // I
{0x00,0x1F,0x04,0x04,0x04,0x44,0x44,0x38}, // J
{0x00,0x42,0x44,0x48,0x70,0x48,0x44,0x42}, // K
{0x00,0x40,0x40,0x40,0x40,0x40,0x40,0x7E}, // L
{0x00,0x42,0x66,0x5A,0x42,0x42,0x42,0x42}, // M
{0x00,0x42,0x62,0x52,0x4A,0x46,0x42,0x42}, // N
{0x00,0x3C,0x42,0x42,0x42,0x42,0x42,0x3C}, // O
{0x00,0x7C,0x42,0x42,0x7C,0x40,0x40,0x40}, // P
{0x00,0x3C,0x42,0x42,0x42,0x4A,0x44,0x3A}, // Q
{0x00,0x7C,0x42,0x42,0x7C,0x48,0x44,0x42}, // R
{0x00,0x3C,0x42,0x40,0x3C,0x02,0x42,0x3C}, // S
{0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10}, // T
{0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x3C}, // U
{0x00,0x42,0x42,0x42,0x42,0x24,0x24,0x18}, // V
{0x00,0x42,0x42,0x42,0x42,0x5A,0x66,0x42}, // W
{0x00,0x42,0x42,0x24,0x18,0x18,0x24,0x42}, // X
{0x00,0x44,0x44,0x28,0x10,0x10,0x10,0x10}, // Y
{0x00,0x7E,0x02,0x04,0x08,0x10,0x20,0x7E} // Z
};
// 行扫描
u8 code RowScan[] = {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F};
// 显示缓冲区(16列,容纳2个字母)
u8 display_buffer[16];
// 全局变量
u8 current_letter = 0;
u8 column_index = 0;
u8 buffer_offset = 0;
// 延时函数
void delay(u16 i)
{
while(i--);
}
// 74HC595发送一个字节
void Hc595SendByte(u8 dat)
{
u8 i;
SRCLK = 0;
RCLK = 0;
for(i = 0; i < 8; i++)
{
SER = (dat & 0x80) >> 7;
dat <<= 1;
SRCLK = 1;
_nop_();
_nop_();
SRCLK = 0;
}
RCLK = 1;
_nop_();
_nop_();
RCLK = 0;
}
// 初始化显示缓冲区
void init_buffer(void)
{
u8 i;
// 清空缓冲区
for(i = 0; i < 16; i++)
{
display_buffer[i] = 0x00;
}
// 初始化变量
current_letter = 0;
column_index = 0;
buffer_offset = 0;
}
// 更新缓冲区(每次左移一列,添加新的一列)
void update_buffer(void)
{
u8 i;
// 整体左移一列
for(i = 0; i < 15; i++)
{
display_buffer[i] = display_buffer[i + 1];
}
// 获取当前字母的当前列
display_buffer[15] = AlphabetFont[current_letter][column_index];
// 更新列索引
column_index++;
// 如果当前字母的8列都已显示,切换到下一个字母
if(column_index >= 8)
{
column_index = 0;
current_letter++;
if(current_letter >= 26)
{
current_letter = 0; // 从A重新开始
}
}
}
// 显示当前缓冲区
void display_buffer_content(void)
{
u8 i, j;
static u8 scan_count = 0;
// 显示多帧以保持稳定性
for(j = 0; j < 5; j++)
{
// 逐行扫描
for(i = 0; i < 8; i++)
{
P0 = RowScan[i];
Hc595SendByte(display_buffer[i + buffer_offset]);
delay(2);
Hc595SendByte(0x00);
}
}
}
// 主函数
void main(void)
{
// 初始化
init_buffer();
while(1)
{
// 显示当前内容
display_buffer_content();
// 每次显示后更新缓冲区(左移效果)
update_buffer();
// 控制滚动速度
delay(3000);
}
}
上述两种方式速度可以自行调节
补充说明
这一部分是关于8*8LED点阵的简单演示,要想理解代码为什么这样编写,就必须深入了解该点阵的工作原理。但本人能力有限,实在是无法清晰地,清楚地将原理解释清楚,所以在此推荐B站UP“爱上半导体”的视频,具体的视频链接如下:
LED点阵广告屏发光的原理,_哔哩哔哩_bilibili
https://www.bilibili.com/video/BV1xZ4y1Z7RP/?spm_id_from=333.337.search-card.all.click 还有一点就是注意,在实际操作时一定要注意引脚的连接是否正确,正确的引脚连接方式才会展现出正确的展示效果
一种连接方式:
另一种连接方式:

不同的连接方式会产生不同的连接效果,注意甄别
实验6:动态数码管
点亮全部动态数码管显示0-7
效果如下:


程序如下:
#include <reg51.h>
typedef unsigned char u8;
typedef unsigned int u16;
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
u8 code smguang[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay(u16 i)
{
while(i--);
}
void display()
{
u16 num;
for(num = 0;num<8;num++)
{
switch(num)
{
case (0):
LSA = 1;LSB = 1;LSC = 1;break;
case (1):
LSA = 0;LSB = 1;LSC = 1;break;
case (2):
LSA = 1;LSB = 0;LSC = 1;break;
case (3):
LSA = 0;LSB = 0;LSC = 1;break;
case (4):
LSA = 1;LSB = 1;LSC = 0;break;
case (5):
LSA = 0;LSB = 1;LSC = 0;break;
case (6):
LSA = 1;LSB = 0;LSC = 0;break;
case(7):
LSA = 0;LSB = 0;LSC = 0;break;
}
P0 = smguang[num];
delay(100);
P0 = 0xFF;
}
}
void main()
{
while(1)
{
display();
P2 = 0x00;
}
}
点亮前五个数码管显示“HELLO”
效果展示:

程序如下:
#include "reg52.h"
typedef unsigned int u16;
typedef unsigned char u8;
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;
u8 code smgduan[17]={0x76,0x79,0x38,0x38,0x3f,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay(u16 i)
{
while(i--);
}
void DigDisplay()
{
u8 i;
for(i=0;i<5;i++)
{
switch(i)
{
case(0):
LSA=1;LSB=1;LSC=1; break;
case(1):
LSA=0;LSB=1;LSC=1; break;
case(2):
LSA=1;LSB=0;LSC=1; break;
case(3):
LSA=0;LSB=0;LSC=1; break;
case(4):
LSA=1;LSB=1;LSC=0; break;
case(5):
LSA=0;LSB=1;LSC=0; break;
case(6):
LSA=1;LSB=0;LSC=0; break;
case(7):
LSA=0;LSB=0;LSC=0; break;
}
P0=smgduan[i];
delay(100);
P0=0x00;
}
}
void main()
{
while(1)
{
DigDisplay();
}
}
实验7:蜂鸣器
简单的持续发声程序:
#include <reg52.h>
sbit beep = P2^5;
// 简单延时函数
void delay_us(unsigned int us)
{
while(us--);
}
void main()
{
while(1)
{
beep = ~beep; // 翻转电平
delay_us(500); // 延时约500us,产生约1kHz频率
//人耳可以听到的声音频率是有范围的,这里的delay就是起到调节频率的作用
}
}
实验8:步进电机驱动
步进电机模块位于P10-P13,共四个引脚可以控制其驱动,但是正常情况下只选择其中的一个进行使用,使用将步进电机的一个引脚连接到与上述提到的四个引脚的旁边的“5V”引脚上。另一个引脚接到四个引脚的其中一个上(这里以P13为例)
程序如下:
#include <reg52.h>
sbit power = P1^3;
typedef unsigned int u16;
void delay(u16 i)
{
while(i--);
}
void main()
{
while(1)
{
power = 0;
delay(100000);
power = 1;
delay(100000);
}
}
实验9:矩阵键盘控制动态数码管
启动后,动态数码管的第一个会显示数字0,按下矩阵按键后会对应显示:S1---0 S2---1 S3---2 S4---3 S5---4 S6---5 S7---6 S8---7 S9---8 S10---9 S11---A S12---b S13---C S14---d S15---E S---F
当然不是只能第一个动态数码管亮,可以通过位选来选择哪个亮(八个中的任意一个)
程序如下:
/*************************************************************************************
*
实验现象:下载程序后数码管显示0,按下矩阵按键上的按键显示对应的数字
注意事项:
**************************************************************************************
*/
#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
#define GPIO_DIG P0 //数码管P0.0-P0.7
#define GPIO_KEY P1 //矩阵按键8个IO管脚为P1.0-P1.7
u8 KeyValue; //用来存放读取到的键值
//数码管显示值,需要翻转
u8 code smgduan[17]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//显示0~F的值
/*******************************************************************************
* 函 数 名 : delay
* 函数功能 : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
while(i--);
}
/*******************************************************************************
* 函 数 名 : KeyDown
* 函数功能 : 检测有按键按下并读取键值
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void KeyDown(void)
{
char a=0;
GPIO_KEY=0x0f;
if(GPIO_KEY!=0x0f)//读取按键是否按下
{
delay(1000);//延时10ms进行消抖
if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
{
//测试列
GPIO_KEY=0X0F;
switch(GPIO_KEY)
{
case(0X07): KeyValue=0;break;
case(0X0b): KeyValue=1;break;
case(0X0d): KeyValue=2;break;
case(0X0e): KeyValue=3;break;
}
//测试行
GPIO_KEY=0XF0;
switch(GPIO_KEY)
{
case(0X70): KeyValue=KeyValue;break;
case(0Xb0): KeyValue=KeyValue+4;break;
case(0Xd0): KeyValue=KeyValue+8;break;
case(0Xe0): KeyValue=KeyValue+12;break;
}
}
}
while((a<50)&&(GPIO_KEY!=0xf0)) //检测按键松手检测
{
delay(100);
a++;
}
}
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
while(1)
{
KeyDown(); //按键判断函数
GPIO_DIG=~smgduan[KeyValue]; //
}
}
三:补充说明
在使用keil时,应该注意keil官方软件没有汉化,所以使用不会显示中文。但是有的使用者会发现:如果给代码进行注释时,中文注释会直接变为一串“?????”(如下),这个是可以调节的

解决方法是:
点击edit后点击Configuration(如图)


图中蓝色框那里选择Chinese

之后的效果(注释可以正常显示):

软件提供
可能会有人需要相关的软件:
keil:https://www.keil.com/
https://www.keil.com/
stc:https://www.stcmicro.com/cn/rjxz.html
https://www.stcmicro.com/cn/rjxz.html
上述的都是官方软件,其中stc的无需注册,可以直接下载。但是keil需要注册,如果有人嫌注册麻烦的话,可以私信我,以提供相关的软件安装包以及部分代码;再补充一个关于LED代码查询的程序。
四:总结
感谢您阅读本文!希望这篇关于单片机入门使用的分享,能为您提供一些启发和帮助。
如果您有任何想法、经验或建议,都非常欢迎在评论区与我交流讨论,或者与我私信交流。文中如有疏漏或错误之处,也恳请各位读者朋友不吝指正,共同完善内容。
本文是在AI(元宝)的协助下完成,后续还会不断更新、调整和补充更多相关内容,努力为大家提供更有价值的技术分享。
再次感谢您的支持,期待与您一起进步!
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)