第二周核心笔记整理
(一)LED 与 IO 口控制
1. 点灯原理
-
电路逻辑:
-
接法:VCC — LED — 单片机 IO 口。
-
控制:
-
给 0 (低电平) —有压差 — 亮(灌电流)。
-
给 1 (高电平) — 无压差 — 灭。
-
-
-
编程方式:
-
整体赋值:操作寄存器(如 P1)。
-
P1 = 0xAA;// 二进制10101010,实现间隔点亮。 -
注意:二进制最低位对应 P1.0(最右边)。
-
-
位寻址:单独操作某一个引脚。
P1 = 0;。
-
2. 流水灯实现方案
-
方式1(暴力法):挨个赋值
0,中间加Delay()。 -
方式2(移位法):使用 C 语言移位运算符
<<或>>,配合逻辑运算。 -
方式3(库函数法 - 推荐):
-
头文件:
#include <intrins.h> -
函数:
_crol_(变量, 位数)(循环左移) /_cror_(循环右移)。 -
优势:移出的位会补回到另一头,不会丢失。
-
(二)按键检测 (Key)
1. 基础逻辑
-
电平状态:
-
0:代表按下(导通接地)。
-
1:代表松开(上拉电阻拉高)。
-
2. 按键分类
-
独立按键:
-
一端接 IO 口,另一端直接接地 (GND)。
-
程序直接读 IO 口电平即可。
-
-
矩阵按键:
-
结构:行线 + 列线交叉。
-
扫描原理:“先选行,后查列”。
-
选行:将某一行置 0,其余行置 1(激活该行)。
-
查列:读取列引脚。如果某列读到 0,则说明该“行-列”交叉点的键被按下。
-
循环:快速轮流激活每一行,利用视觉暂留实现全键盘检测。
-
-
3. 【重点模型】按键消抖与边缘检测
不要只判断“当前是0”,要判断“刚才没按,现在按了”。
// 核心公式:检测下降沿(按下的瞬间)
Key_Down = Key_Val & (Key_Val ^ Key_Old);
Key_Up = ~Key_Val & (Key_Val ^ Key_Old);
Key_Old = Key_Val; // 必须更新历史状态
(三)数码管与定时器中断
1. 数码管显示原理
-
结构:
-
段选 (Segment):控制显示什么字(a, b, c, d, e, f, g, dp)。
-
位选 (Common):控制哪个位置的数码管亮。
-
-
极性(共阴极为例):
-
段码:给 1 亮(高电平驱动)。
-
位码:给 0 选中(低电平接地选通)。
-
2. 74HC573 锁存器(P0口复用核心)
-
总体思路:“谁接听,谁处理”。P0 口是公共数据线,锁存器是开关。
-
控制引脚:
-
P2.6 (段选锁存):控制显示的内容。
-
P2.7 (位选锁存):控制显示的位置。
-
-
操作口诀:先 1 后 0。
-
Latch(锁存器) = 1;// 打开门,让 P0 的数据进去。 -
P0 = Data;// 送数据。 -
Latch = 0;// 关上门,锁住数据(此时 P0 变了也不影响里面)。
-
3. 定时器中断 (Timer0)
这就像一个“看不见的闹钟”,后台自动运行,不占用 Delay 时间。
-
配置三部曲(初始化):
-
设置模式:
TMOD(通常用模式1: 16位定时器)。 -
装初值:
TL0,TH0(决定定时的长短)。 -
开开关:
-
ET0 = 1;(允许定时器0说话)(打开闹钟)。 -
EA = 1;(允许总中断说话)(开始计时)。
-
-
-
【重点模型】定时器标准代码模板
(假设 12MHz 晶振,1ms 中断)
// 1. 初始化函数
void Timer0_Init()
{
TMOD &= 0xF0; // 清零低四位
TMOD |= 0x01; // 设置为模式1
TL0 = 0x18; // 设置初值低8位 (65536-1000)
TH0 = 0xFC; // 设置初值高8位
TF0 = 0; // 清除溢出标志
TR0 = 1; // 开始计时
ET0 = 1; // 打开闹钟
EA = 1; // 开始计时
}
// 2. 中断服务函数 (每1ms自动执行一次)
void Timer0_Routine() interrupt 1
{
// 每次进来先重装初值!(重要)
TL0 = 0x18;
TH0 = 0xFC;
}
void main(){
Timer0_Init();
while(1)
{
}
}
中断配置方法
1.在生成的定时器初始化函数内增加中断打开命令 ET0=1;EA=1;
2.书写中断服务函数(Timer0Server)
3.在服务函数内初始化计数值
4.在主程序内添加定时器0初始化函数
应用
unsigned char Seg_Pos;
unsigned char Seg_Buf[]={10,10,10,10,10,10};
unsigned char Time=500;
unsigned char Key_Val,Key_Down,Key_Up,Key_Old;
bit System_Flag=1;//流转状态标识位 0-停止 1-启动
//定时器初始化函数
void Timer0_Init(void) //1毫秒@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1; //打开闹钟
EA=1; //开始计时
}
//定时器0中断服务函数
void Timer0Server() interrupt 1
{
TL0 = 0x18; //设置定时初始值
TH0 = 0xFC; //设置定时初始值
if(++Seg_Pos == 6) Seg_Pos = 0;
Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);
}
void main()
{
Timer0_Init();
while(1)
{
Key_Read();
Key_Val=Key_Read();//读取键码值
Key_Down=Key_Val&(Key_Val^Key_Old);//检测下降沿
Key_Up=~Key_Val&(Key_Val^Key_Old);//检测上升沿
Key_Old=Key_Val;//扫描辅助变量
switch(Key_Down)
{
case 1:
System_Flag=1;
break;
case 2:
System_Flag=0;
break;
case 3:
Time +=100;
break;
case 4:
Time -=100;
break;
}
Seg_Buf[0]=Time/100%10;
Seg_Buf[1]=Time/10%10;
Seg_Buf[2]=Time/1%10;
}
}