第三讲 数码管显示的原理、数码管的静态显示

复位电路;

晶振:

晶振:工作输出正弦波,电容帮助起振

位选&段选

实质上是利用视觉暂留的原理,快速的切换哪一位数码管点亮,因为段选都是公用的,同时点亮,只会输出同样的数字。

锁存器 74HC573

高电平 数据直通

低电平 数据锁存

打开位选锁存器 选择位 拉低 打开段选 选择数数字 拉低

一个端口用两个锁存器 控制16个IO口

#include <reg52.h>

sbit DUAL = P2^6;  // 锁存器控制信号
sbit WEI = P2^5;   // 数码管选择信号
typedef unsigned char uint;

// 数码管段码表
uint code table[] = {
    0x3F,  // 数字0
    0x06,  // 数字1
    0x5B,  // 数字2
    0x4F,  // 数字3
    0x66,  // 数字4
    0x6D,  // 数字5
    0x7D,  // 数字6
    0x07,  // 数字7
    0x7F,  // 数字8
    0x6F   // 数字9
};

void delay(uint time);

void main()
{
    uint i;

    // 初始化I/O口状态,只需要设置一次
    WEI = 1;        // 使能数码管
    P0 = 0xEF;      // 点亮数码管
    WEI = 0;        // 锁存数码管
    
    while(1) {
        for(i = 0; i < 10; i++) {
            // 传输数据并锁存
            DUAL = 1;       // 使能锁存器
            P0 = table[i];  // 显示数字
            DUAL = 0;       // 锁存数据
            
            delay(500);     // 延迟,便于观察每个数字
        }
    }
}

// 延迟函数
void delay(uint time)
{
    uint i, j;
    for(i = 0; i < time; i++)
        for(j = 0; j < 125; j++); // 延迟循环
}

为什么使用`code`关键字?

在C51编程中,`code`关键字的使用有助于将数据存储在程序存储器(通常是闪存)中,而不是在数据存储器(RAM)中。这对于资源有限的单片机特别有用,因为程序存储器的容量通常远大于数据存储器。了解和使用`code`关键字可以有效优化存储器的使用,提高系统的稳定性和性能。

1. **节省RAM**:51单片机的RAM资源有限,通常只有256字节。将静态数据(如常量、查找表等)放在程序存储器中可以节省宝贵的RAM资源。
2. **程序存储器较大**:51单片机的程序存储器(例如4KB、8KB甚至更大)远大于RAM。将数据存储在程序存储器中可以充分利用这些资源。
3. **数据不可变**:对于不需要改变的数据,如查找表、常量字符串等,将其存储在程序存储器中可以保证数据的稳定性和不可变性。

### `code`关键字的使用

使用`code`关键字可以将数据声明为常量存储在程序存储器中。以下是几个示例:


   使用`code`关键字将数组`table[]`存储在程序存储器中。这些数据在程序执行过程中不会被修改,因此适合存储在程序存储器中。

2. **访问`code`数据**:
   在主循环中,使用`table[i]`来获取存储在程序存储器中的数据。编译器会自动处理程序存储器中的数据读取,无需额外的操作。

### 总结

使用`code`关键字将常量数据存储在程序存储器中,可以有效节省RAM资源,提高系统的稳定性和性能。这在资源有限的单片机系统中尤为重要。通过合理使用`code`关键字,可以优化存储器使用,提高程序的可维护性和可靠性。

为什么要给锁存器的开关上高电平

在51单片机上,I/O口的上电默认状态并不是固定的,具体情况取决于硬件设计和电路连接。一般情况下,I/O口上电后的状态是不确定的,可能是高电平,也可能是低电平。因此,为了确保电路行为的确定性,通常会在初始化时明确设置I/O口的状态。

锁存器的开关(通常是使能信号或控制信号)需要明确设置高电平才能通过数据。当你上电后,I/O口的状态可能是不确定的,所以在代码中明确设置高电平是为了确保锁存器能够正确工作,具体原因如下:

  1. 确保初始化状态:虽然I/O口可能在上电时默认为高电平,但这并不能保证所有情况下都是如此。明确设置可以确保锁存器的工作状态是已知的和正确的。
  2. 防止错误操作:如果不明确设置高电平,锁存器可能会在上电时处于未知状态,从而导致数据传输错误或其他不期望的行为。
  3. 逻辑控制需要:在许多设计中,逻辑电路需要通过明确的信号控制才能工作。即使默认状态是高电平,编写代码时也应该明确设置以确保逻辑的一致性和可靠性

锁存器

锁存器(Latch)是一种用于数据暂时存储的数字电路元件,可以在某一时刻“锁住”输入数据,并在需要时提供输出。锁存器常用于保持数据稳定,尤其是在数据线的驱动能力较弱时。通常与并行端口结合使用,以稳定并行数据传输中的数据。

### 锁存器的工作原理

1. **数据输入(D)**:这是输入数据的端口。
2. **控制输入(Enable/Control/Clock)**:决定是否将输入数据传送到输出端的控制信号。当控制信号处于激活状态时,输入数据会传输到输出端并保持不变,直到下一个控制信号到来。
3. **数据输出(Q)**:这是输出数据的端口,输出的数据会保持当前状态,直到锁存器接收到下一个控制信号并更新数据。

### 锁存器的类型

1. **D锁存器(Data Latch)**:最常见的锁存器类型,使用D输入和控制信号。
2. **SR锁存器(Set-Reset Latch)**:使用两个输入信号,分别用于设置和重置输出状态。

### 51单片机中锁存器的应用

在51单片机中,锁存器经常用于扩展并行I/O端口,通过外部锁存器芯片,如74HC573或74LS373,可以扩展51单片机的I/O端口数量。

- **D**:数据输入
- **E(Enable)**:控制输入,当E=1时,数据D传输到输出Q。
- **Q**:数据输出

### 锁存器在单片机中的应用示例

假设我们要用锁存器扩展51单片机的I/O端口,下面是一个示例电路图:


     74HC573
   +-----------+
D0  | 1      20 | VCC
D1  | 2      19 | OE  -> Connected to 51 MCU control pin
D2  | 3      18 | LE  -> Connected to 51 MCU control pin
D3  | 4      17 | Q7
D4  | 5      16 | Q6
D5  | 6      15 | Q5
D6  | 7      14 | Q4
D7  | 8      13 | Q3
GND | 9      12 | Q2
Q0  | 10     11 | Q1
   +-----------+

在这个电路中:
- 74HC573的D0-D7连接到51单片机的某一个I/O端口。
- OE和LE分别连接到51单片机的控制引脚,用于控制数据的锁存和输出。
- Q0-Q7作为扩展的I/O端口,可以连接到其他外设或电路。

通过使用锁存器,51单片机可以有效地扩展其并行端口,实现更多的I/O操作。
 

#define与typedef的比较

在C语言中,`#define`预处理指令用于定义宏。宏可以是常量、表达式或代码片段的替代名称。然而,宏的替换是直接文本替换,可能会引发一些不可预见的错误。相比之下,使用`typedef`更为安全和推荐,因为它遵循C语言的类型系统,提供更强的类型检查。

#### 可读性和调试
- `typedef`更易于调试和阅读,尤其在复杂类型时。编译器会提供更准确的错误信息。
- `#define`只是简单的文本替换,可能导致意外的错误,且调试信息不够直观。

#### 类型检查
- `typedef`遵循C语言的类型系统,提供更严格的类型检查。
- `#define`则没有类型检查,容易导致类型相关的错误。

#### 作用范围
- `typedef`定义的类型名称遵循C语言的作用域规则。
- `#define`定义的宏在整个预处理范围内有效,可能会不小心覆盖其他地方的定义。

### 示例对比

//使用#define定义宏:
#define uint unsigned int

uint a = 10;


//使用typedef定义类型:


typedef unsigned int uint;

uint a = 10;

### 复杂类型的应用

对于复杂类型,如结构体或指针类型,使用`typedef`更加清晰和安全:


// 使用#define
#define PINT int*

PINT a, b;  // 实际上 a 是 int*,但是 b 是 int 类型

// 使用typedef
typedef int* PINT;

PINT a, b;  // a 和 b 都是 int* 类型

综上所述,虽然`#define`可以用于定义类型的别名,但在大多数情况下,使用`typedef`更为推荐,特别是在涉及复杂类型和需要严格类型检查的场合。

中断

什么是中断

2.中断结构
 


3.中断相应的条件

计数器&定时器


在理解单片机或微控制器的时序特性时,机器周期、时钟周期和晶振周期是三个重要的概念。下面分别介绍这些概念及其关系。

### 晶振周期(Oscillator Period)

晶振周期是由外部晶体振荡器(晶振)产生的时钟信号的周期。晶振的频率通常在MHz范围内。举例来说,如果一个晶振的频率为12 MHz,那么它的周期是:

\[ \text{晶振周期} = \frac{1}{\text{晶振频率}} = \frac{1}{12\, \text{MHz}} = \frac{1}{12,000,000} \, \text{秒} \approx 83.3 \, \text{纳秒} \]

### 时钟周期(Clock Cycle)

时钟周期是指单片机内部时钟信号的周期。对于80C52单片机,时钟周期通常是晶振周期的1/12,这意味着时钟信号的频率是晶振频率的1/12。以12 MHz的晶振为例:

\[ \text{时钟周期} = 12 \times \text{晶振周期} = 12 \times 83.3 \, \text{纳秒} = 1 \, \text{微秒} \]

### 机器周期(Machine Cycle)

机器周期是单片机完成一个基本操作所需的时间,这通常是多个时钟周期的总和。对于80C52单片机,一个机器周期是12个时钟周期。因此:

\[ \text{机器周期} = 12 \times \text{时钟周期} = 12 \times 1 \, \text{微秒} = 12 \, \text{微秒} \]

### 关系总结

- **晶振周期**:晶振的一个周期,是由外部晶振频率决定的。
- **时钟周期**:通常是晶振周期的1/12,是单片机内部时钟信号的周期。
- **机器周期**:通常是12个时钟周期,是单片机完成一个基本操作所需的时间。

### 实例

假设使用一个12 MHz的晶振:

1. **晶振周期**:
   - 晶振频率 = 12 MHz
   - 晶振周期 = 1 / 12,000,000 秒 ≈ 83.3 纳秒

2. **时钟周期**:
   - 时钟周期 = 12 × 晶振周期 = 12 × 83.3 纳秒 = 1 微秒

3. **机器周期**:
   - 机器周期 = 12 × 时钟周期 = 12 × 1 微秒 = 12 微秒

### 应用

理解这些时间单位的关系在编写延迟程序、设置定时器和调试硬件时非常重要。例如:

- **延迟函数**:为了创建一个精确的延迟,可以基于机器周期进行计数。
- **定时器设置**:配置定时器以产生特定的时间间隔,通常基于机器周期进行计算。
- **串行通信**:设置波特率时,需要理解时钟周期和机器周期,以确保正确的通信速率。

### 总结

晶振周期:外部晶振的一个周期,由晶振频率决定。
时钟周期:单片机内部时钟的一个周期,通常是晶振周期的1/12。
-机器周期:单片机完成一个基本操作所需的时间,通常是12个时钟周期。

这些概念及其关系是理解和使用单片机时序特性的基础,尤其是在进行时间敏感的操作和优化系统性能时。

分频的概念

分频是指将一个输入时钟信号的频率降低到原来频率的一个分数,例如,将原来的频率除以2、4、8等。分频的应用广泛存在于数字电路中,用于产生不同频率的时钟信号以适应不同的需求。例如,单片机的时钟源通常需要经过分频以得到合适的工作频率。

12分频的理解

12分频表示将输入时钟信号的频率降低到原来的1/12。例如,如果输入时钟信号的频率是12 MHz,那么经过12分频后的输出信号频率就是1 MHz。

晶振频率

80C52单片机通常使用的晶振频率范围为1 MHz到12 MHz,不过在一些应用中,使用更高的晶振频率(如16 MHz或24 MHz)也是可能的。常见的标准晶振频率包括6 MHz、11.0592 MHz、12 MHz等。

时钟周期和机器周期

在80C52单片机中,时钟周期(Clock Cycle)是晶振周期的1/12。机器周期(Machine Cycle)是12个时钟周期。因此,如果晶振频率为12 MHz,则时钟周期为1微秒,机器周期为12微秒。

假设晶振频率为12 MHz:

  • 时钟周期(Clock Cycle) = 1 / 12 MHz = 1 / 12,000,000 秒 ≈ 83.3 纳秒
  • 机器周期(Machine Cycle) = 12 × 时钟周期 = 12 × 83.3 纳秒 ≈ 1 微秒

如果晶振频率为11.0592 MHz:

  • 时钟周期 = 1 / 11.0592 MHz ≈ 90.42 纳秒
  • 机器周期 = 12 × 90.42 纳秒 ≈ 1.085 微秒

1M = 1,000,000: 在大多数情况下,"M"表示百万

  1. 1 秒 (second, s) = 1000 毫秒 (millisecond, ms)
  2. 1 毫秒 (ms) = 1000 微秒 (microsecond, μs)

所以,综合来看:

  • 1 秒 (s) = 1000 毫秒 (ms) = 1,000,000 微秒 (μs)

定时/计数器的控制

主要操作TR0

应用举例

  • 10
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是静态单个数码管显示的实验步骤: 材料: - Arduino开发板 - 数码管 - 220欧姆电阻 - 杜邦线若干 步骤: 1. 将材料准备齐全。 2. 将数码管的针脚与Arduino开发板的数字引脚相连,具体连接方式见下图: ``` 数码管正极 -> 数字引脚12 数码管负极 -> 数字引脚11 第一位数码管 a -> 数字引脚2 第一位数码管 b -> 数字引脚3 第一位数码管 c -> 数字引脚4 第一位数码管 d -> 数字引脚5 第一位数码管 e -> 数字引脚6 第一位数码管 f -> 数字引脚7 第一位数码管 g -> 数字引脚8 ``` 注意:连接时需要将数码管的220欧姆电阻连接在正极和数字引脚12之间。 3. 在Arduino开发板的IDE中编写代码: ```c void setup() { // 设置数码管的引脚为输出模式 pinMode(2, OUTPUT); // a pinMode(3, OUTPUT); // b pinMode(4, OUTPUT); // c pinMode(5, OUTPUT); // d pinMode(6, OUTPUT); // e pinMode(7, OUTPUT); // f pinMode(8, OUTPUT); // g pinMode(11, OUTPUT); // 数码管负极 pinMode(12, OUTPUT); // 数码管正极 } void loop() { // 显示数字1 digitalWrite(2, HIGH); // a digitalWrite(3, LOW); // b digitalWrite(4, LOW); // c digitalWrite(5, LOW); // d digitalWrite(6, LOW); // e digitalWrite(7, LOW); // f digitalWrite(8, LOW); // g digitalWrite(11, LOW); // 数码管负极 digitalWrite(12, HIGH); // 数码管正极 // 等待一段时间 delay(1000); } ``` 上述代码中,setup函数用于设置数码管引脚的模式,loop函数用于循环执行显示数字1的操作,并通过delay函数控制显示时间。 4. 将编写好的代码上传到Arduino开发板中。 5. 数码管显示数字1,每隔1秒钟更新一次。 注意:实验时要注意电路连接的正确性,避免短路或其他损坏。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值