用keil5写数码管显示实验,包含smg.c,smg.h,main.c代码,要求依次显示0-7数字
时间: 2025-04-07 11:00:38 浏览: 125
<think>好的,用户想要在Keil5中实现数码管依次显示0到7的数字,需要编写smg.c、smg.h和main.c这三个文件。我得先理清楚整个程序的结构和各个文件的功能。
首先,数码管显示通常涉及到段选和位选的控制。段选决定显示哪个数字,位选决定哪个数码管亮起。用户要求依次显示0-7,可能需要使用8个数码管,每个显示一个数字,或者一个数码管动态显示不同数字。这里应该是指动态扫描,让多个数码管逐个显示不同的数字,利用视觉暂留效果看起来像是同时显示。
接下来,硬件连接部分需要确认。假设使用的是共阴极数码管,那么段选码对应的0-7的数字需要正确设置。例如,数字0的段码可能是0x3F,1是0x06,依此类推。需要提供正确的段码表,可能需要根据实际硬件调整,这里假设用户使用的是常见的配置。
然后考虑代码结构。smg.h头文件应该包含函数声明和必要的宏定义,比如段选和位选的端口定义。smg.c则包含具体的函数实现,比如数码管初始化、显示函数等。main.c里则是主循环,控制显示的顺序和延时。
动态扫描的实现需要定时器中断或者延时函数来切换显示的数码管。这里用户可能没有提到使用定时器,所以先用延时函数实现。但要注意,延时过长会导致闪烁,过短可能导致显示不稳定。通常动态扫描的频率在50Hz以上,每个数码管显示1-2ms,但用延时函数可能难以精确控制,这里为了简单,使用较短的延时。
接下来,编写smg.h。需要定义数码管的段选和位选端口,假设P0接段选,P2接位选。声明初始化函数和显示函数。
smg.c里,初始化函数可能设置端口模式,显示函数则根据输入的数字和位置,设置段选和位选。动态扫描需要在主循环中不断刷新各个数码管的位置,依次显示0-7。但用户要求依次显示0-7,可能是指每个数码管显示一个数字,从左到右依次显示0到7,或者单个数码管循环显示0-7。需要明确。
如果硬件是8位数码管,每个对应一个数字,那么位选依次选中每个数码管,段选设置对应的数字。例如,第一位显示0,第二位显示1,直到第八位显示7,然后循环。但用户可能希望8个数码管同时显示0-7,每个显示不同的数字,然后整体循环。或者是一个数码管循环显示0-7,每个数字显示一段时间。需要进一步确认。
可能用户的意思是一个数码管依次显示0到7,每个数字显示一段时间,然后循环。或者多个数码管依次点亮显示对应的数字。假设是8位数码管,每个显示对应的数字,即第一位0,第二位1,直到第八位7,然后重复。这种情况下,显示函数需要接收一个数组,包含8个数字,然后动态扫描显示。
但用户问题描述是“依次显示0-7数字”,可能更简单的情况是,使用一个数码管,依次显示0到7,每个数字显示一段时间,比如1秒,然后下一个。或者使用多个数码管,每个显示不同的数字,依次点亮。需要进一步分析。
考虑到通常的实验板可能有多个数码管,通过位选控制哪个亮,所以可能需要动态扫描。例如,让8个数码管分别显示0-7,通过快速切换位选,实现同时显示。但用户要求“依次显示”,可能是指每个数字依次显示,比如先显示0,然后1,直到7,循环。这种情况下,可能只使用一个数码管,逐个显示数字。
但常见的实验通常是多个数码管动态显示不同内容,比如显示8位不同的数字。所以可能用户需要的是让8个数码管分别显示0到7,每个位置显示对应的数字,并且持续循环。或者,让所有数码管同时显示同一个数字,依次从0变化到7。
需要明确用户的需求。可能用户的需求是让数码管依次显示0到7,每个数字显示一段时间,比如1秒,然后下一个。这种情况下,只需要控制段选,显示不同的数字,而位选固定,因为可能只使用一个数码管。或者如果多个数码管,位选依次切换,同时段选变化,但这样可能每个数码管显示不同的数字。
可能用户的问题存在歧义,需要假设。假设用户使用的是多位一体的数码管,希望每个数码管依次显示0-7,即第一个显示0,第二个显示1,直到第八个显示7,然后循环。这种情况下,需要动态扫描,每个时刻只点亮一个数码管,显示对应的数字,然后快速切换,形成视觉上的持续显示。
或者,用户希望的是单个数码管依次显示0到7,每个数字显示一段时间。这种情况下,位选固定,段选变化。例如,使用一个数码管,每隔一秒切换数字。
需要根据常见实验情况判断。通常,动态扫描多个数码管是常见的实验内容,所以假设用户希望8个数码管分别显示0-7,通过动态扫描实现。因此,代码需要包含段码表,位选控制,以及循环刷新显示。
现在,开始编写代码结构:
smg.h中声明函数,比如void SMG_Init(void); 和 void SMG_Display(unsigned char pos, unsigned char num); 可能还需要一个显示多个数字的函数,或者主循环中循环调用显示函数。
但动态扫描通常是在中断中处理,但用户可能没有使用中断,所以主循环中需要不断刷新每个数码管的显示。每个数码管显示一定时间,比如1ms,然后切换到下一个,这样循环起来。
但为了简化,主函数中可能用一个循环,依次显示每个数字在每个位置,但这样可能需要更复杂的控制。或者,用户希望的是让数码管从左到右依次显示0到7,每个数码管显示对应的数字,并且保持常亮。但数码管通常需要动态扫描,所以即使希望常亮,也需要持续刷新。
可能更简单的做法是,让8个数码管同时显示0-7,每个位置显示对应的数字,通过动态扫描实现。因此,段选数据根据位置决定,比如pos0显示0,pos1显示1,直到pos7显示7。
因此,主函数中会有一个数组,保存要显示的数字,如0-7,然后循环调用显示函数,传入位置和数字。
但显示函数可能需要一次显示所有数码管,通过动态扫描。因此,可能需要一个函数,比如SMG_Display_Numbers(unsigned char *numbers),其中numbers是包含8个数字的数组,然后在函数内部循环显示每个数码管,每个显示一段时间。
但考虑到代码结构,可能需要将动态扫描放在主循环中,每次显示一个数码管,然后延时,再下一个。但这样会有闪烁,除非延时非常短。
或者,使用一个定时器中断来定期刷新数码管,这样主循环只需要更新要显示的数据,而定时器负责刷新显示。但用户可能没有提到使用定时器,所以可能需要用延时函数来实现动态扫描。
综合考虑,可能代码结构如下:
- smg.h中包含段码和位码的定义,以及函数声明。
- smg.c中包含段码表,初始化函数,以及显示单个数字的函数。
- main.c中主循环依次设置每个数码管显示对应的数字,并循环扫描。
但需要明确,每个数码管显示不同的数字,并且动态扫描。因此,主循环中需要不断遍历每个数码管,设置对应的段码和位码,然后短暂延时,实现扫描。
例如,在main.c中,定义一个数组smg_num[8] = {0,1,2,3,4,5,6,7}; 然后循环中,for(i=0;i<8;i++) { SMG_Display(i, smg_num[i]); delay_ms(1); } 这样每个数码管显示1ms,循环起来形成视觉暂留。
但这样可能需要调整延时时间,确保扫描频率足够高,比如整体8个数码管扫描周期在20ms以内,这样频率50Hz,不会有闪烁。
因此,代码的大致结构应该是:
在smg.h中:
- 定义段选和位选的端口(假设P0和P2)
- 声明SMG_Init和SMG_Display函数
在smg.c中:
- 段码表数组,对应0-7的段码
- 位码表数组,对应每个数码管的位选信号(共阴极的话,位选是低电平有效?或者高电平?需要根据硬件确定)
- SMG_Init函数设置端口为推挽输出(假设STC单片机)
- SMG_Display函数接收位置和数字,设置段选和位选
在main.c中:
- 包含smg.h
- 主函数初始化后,循环显示每个数码管的数字
但需要注意,动态扫描需要不断刷新,所以主循环必须持续执行显示过程,而不是只执行一次。
例如,main.c中的循环是while(1) { for(i=0到7) { 显示第i个数码管为i,延时1ms } }
这样,每个数码管显示1ms,全部显示完需要8ms,周期为8ms,频率约125Hz,足够快,不会有闪烁。
现在,具体代码:
smg.h:
#ifndef _SMG_H_
#define _SMG_H_
#include <REGX52.H>
#define SMG_SEG_PORT P0 // 段选接P0口
#define SMG_DIG_PORT P2 // 位选接P2口
void SMG_Init(void);
void SMG_Display(unsigned char pos, unsigned char num);
#endif
smg.c:
#include "smg.h"
// 共阴极数码管段码表(0-9)
unsigned char code SMG_Num[] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
// 位选码表,假设8位数码管,P2.0-P2.7控制位选,低电平有效
unsigned char code SMG_Digit[] = {
0xFE, // 第0位: 1111 1110
0xFD, // 第1位: 1111 1101
0xFB, // 第2位: 1111 1011
0xF7, // 第3位: 1111 0111
0xEF, // 第4位: 1110 1111
0xDF, // 第5位: 1101 1111
0xBF, // 第6位: 1011 1111
0x7F // 第7位: 0111 1111
};
void SMG_Init(void)
{
P0 = 0x00; // 初始化段选端口
P2 = 0xFF; // 初始化位选端口(所有数码管关闭)
}
void SMG_Display(unsigned char pos, unsigned char num)
{
if(pos >= 8) return; // 防止越界
if(num > 9) return; // 只显示0-9
SMG_SEG_PORT = SMG_Num[num]; // 设置段选
SMG_DIG_PORT = SMG_Digit[pos]; // 设置位选
}
这里可能存在一个问题:段选和位选是否需要先关闭位选再切换,以避免残影。通常的做法是,在切换位选时,先关闭所有位选,设置段选,再打开新的位选。因此,SMG_Display函数可能需要先关闭所有数码管,再设置段选,再打开对应的位选。
修改SMG_Display函数:
void SMG_Display(unsigned char pos, unsigned char num)
{
if(pos >= 8) return;
if(num > 9) return;
SMG_DIG_PORT = 0xFF; // 关闭所有位选
SMG_SEG_PORT = SMG_Num[num];
SMG_DIG_PORT = SMG_Digit[pos];
}
这样可以避免切换时的残影。
然后,在main.c中:
#include "smg.h"
#include <intrins.h>
void Delayms(unsigned int ms) // 粗略延时函数
{
unsigned int i, j;
for(i=ms; i>0; i--)
for(j=110; j>0; j--);
}
void main()
{
unsigned char i;
SMG_Init();
while(1)
{
for(i=0; i<8; i++)
{
SMG_Display(i, i); // 第i位数码管显示数字i
Delayms(1); // 延时1ms
}
}
}
这里,每个数码管显示1ms,然后循环,这样所有数码管每隔8ms刷新一次,频率约125Hz,足够快,不会有闪烁。
需要注意,段码表和位码表是否正确。例如,如果数码管是共阳极,段码需要取反。同样,位选的有效电平也要根据硬件设计确定。如果位选是高电平有效,那么位码表应该是0x01, 0x02等。假设用户使用的是共阴极数码管,位选低电平有效,段选高电平有效。
另外,延时函数可能不够精确,但作为示例可以接受。实际项目中建议使用定时器中断。
最后,需要提醒用户根据实际硬件调整段码和位码,特别是如果使用的单片机型号不同,端口可能需要更改。例如,如果是P1口控制段选,需要修改smg.h中的宏定义。
综上,代码结构大致如此,可以实现8位数码管依次显示0-7的数字,通过动态扫描实现稳定显示。</think>以下为数码管显示0-7的完整实现代码,采用动态扫描方式实现稳定显示:
$$smg.h$$
```c
#ifndef _SMG_H_
#define _SMG_H_
#include <REGX52.H>
#define SEG_PORT P0 // 段选信号控制端口
#define DIG_PORT P2 // 位选信号控制端口
// 函数声明
void SMG_Init(void);
void SMG_Display(unsigned char pos, unsigned char num);
#endif
```
$$smg.c$$
```c
#include "smg.h"
// 共阴极数码管段码表(0-9)
unsigned char code segCode[] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
// 位选控制表(低电平有效)
unsigned char code digCode[] = {
0xFE, 0xFD, 0xFB, 0xF7,
0xEF, 0xDF, 0xBF, 0x7F
};
void SMG_Init(void)
{
DIG_PORT = 0xFF; // 初始化关闭所有数码管
SEG_PORT = 0x00; // 清空段选信号
}
void SMG_Display(unsigned char pos, unsigned char num)
{
if(pos > 7) return; // 位选范围0-7
if(num > 9) return; // 数字范围0-9
DIG_PORT = 0xFF; // 关闭显示(消影)
SEG_PORT = segCode[num];
DIG_PORT = digCode[pos];
}
```
$$main.c$$
```c
#include "smg.h"
#include <INTRINS.H>
void Delay1ms(void) // 晶振11.0592MHz
{
unsigned char i, j;
_nop_();
i = 2;
j = 199;
do {
while (--j);
} while (--i);
}
void main()
{
unsigned char i;
SMG_Init();
while(1)
{
// 依次点亮8位数码管
for(i=0; i<8; i++)
{
SMG_Display(i, i); // 第i位显示数字i
Delay1ms(); // 保持显示1ms
Delay1ms();
}
}
}
```
**代码说明:**
1. **硬件连接:**
- 段选信号连接P0端口
- 位选信号连接P2端口
- 数码管类型:共阴极
2. **工作原理:**
- 动态扫描方式:每次点亮1位数码管,8ms完成一轮刷新(频率≈125Hz)
- `segCode`数组存储0-9的七段码值
- `digCode`数组存储位选控制码
3. **使用注意事项:**
- 需根据实际数码管类型(共阴/共阳)修改段码表
- 若开发板端口不同,需修改`smg.h`中的宏定义
- 延时时间可调整(建议单次显示1-2ms)
**实验现象:**
8位数码管将稳定显示0-7数字,每个数字固定在对应的数码管位上,无明显闪烁。若需要实现数字轮换效果,可修改main函数中的显示逻辑。
阅读全文
相关推荐















