复位电路;
晶振:
晶振:工作输出正弦波,电容帮助起振
位选&段选
实质上是利用视觉暂留的原理,快速的切换哪一位数码管点亮,因为段选都是公用的,同时点亮,只会输出同样的数字。
锁存器 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口的状态可能是不确定的,所以在代码中明确设置高电平是为了确保锁存器能够正确工作,具体原因如下:
- 确保初始化状态:虽然I/O口可能在上电时默认为高电平,但这并不能保证所有情况下都是如此。明确设置可以确保锁存器的工作状态是已知的和正确的。
- 防止错误操作:如果不明确设置高电平,锁存器可能会在上电时处于未知状态,从而导致数据传输错误或其他不期望的行为。
- 逻辑控制需要:在许多设计中,逻辑电路需要通过明确的信号控制才能工作。即使默认状态是高电平,编写代码时也应该明确设置以确保逻辑的一致性和可靠性
锁存器
锁存器(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 秒 (second, s) = 1000 毫秒 (millisecond, ms)
- 1 毫秒 (ms) = 1000 微秒 (microsecond, μs)
所以,综合来看:
- 1 秒 (s) = 1000 毫秒 (ms) = 1,000,000 微秒 (μs)
定时/计数器的控制
主要操作TR0