51系列
AT89C52基础模块
- AT89C51只有两个定时器,一个串口,两个外部中断
周期
- 时钟周期又称振荡周期,由晶振决定 = 1/fsc
- 状态周期 = 2*时钟周期
- 机器周期 = 6状态周期 = 12时钟周期
- 指令周期:执行指令所需的所有时间,不同的指令所需的时间不同。
- 执行指令需要一个机器周期(12MHz => 1us)
- 双周期指令:执行指令需要两个机器周期(12MHz => 2us)
- 四周期指令:执行指令需要四个机器周期(12MHz => 4us)
引脚
- P0(AD0-7)为8位漏级开路双向I/O口(需要外部上拉电阻)
- P1、P2(A8-15):标准I/O【P1.0/T2,P1.1/T2EX】
- P3特殊功能I/O,也可作为普通I/O
- P3.0/RXD
- P3.1/TXD
- P3.2/INT0*
- P3.3/INT1*
- P3.4/T0
- P3.5/T1
- P3.6/WR*
- P3.7/RD*
- RST:复位引脚
- ALE / PROG  ̄ \overline{\text{PROG}} PROG:访问外部数据存储器/程序存储器
- PSEN  ̄ \overline{\text{PSEN}} PSEN:允许程序存储器
- EA/VPP:允许外部访问
存储器结构
RAM:0-1F
- 工作寄存器组:4组*8个Ri
RAM:20-2F
- 位寻址区
RAM:30-7F
- 通用RAM
RAM:80-FF
TR0SFR(红色可位搜索) | 符号 | 字节(物理)地址 | 位名称 | |||||||
---|---|---|---|---|---|---|---|---|---|---|
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | |||
P0 | P0 | 80H | P0.7 | P0.6 | P0.5 | P0.4 | P0.3 | P0.2 | P0.1 | P0.0 |
堆栈指针 | SP | 81H | ||||||||
数据指针DPTR | DPH | 82H | ||||||||
DPL | 83H | |||||||||
保留3字节 | 84H-86H | |||||||||
电源和波特率 | PCON | 87H | SMOD | GF1 | GF0 | PD | IDL | |||
定时器控制寄存器 | TCON | 88H | TF1 | TR1 | TF0 | IE1 | IT1 | IE0 | IT0 | |
定时器计数器方式控制 | TMOD | 89H | GATE1 | C/T*1 | M1_1 | M1_0 | GATE0 | C/T*0 | M0_1 | M0_0 |
定时器计数器0L | TL0 | 8AH | ||||||||
定时器计数器1L | TL1 | 8BH | ||||||||
定时器计数器0H | TH0 | 8CH | ||||||||
定时器计数器1H | TH1 | 8DH | ||||||||
保留2Byte | 8EH-8FH | |||||||||
P1 | P1 | 90H | P1.7 | P1.6 | P1.5 | P1.4 | P1.3 | P1.2 | P1.1 | P1.0 |
保留7Byte | 91H-97H | |||||||||
串行控制 | SCON | 98H | SM0 | SM1 | SM2 | REN | TB8 | RB8 | TI | RI |
串行缓冲区 | SBUF | 99H | ||||||||
P2 | P2 | A0H | P2.7 | P2.6 | P2.5 | P2.4 | P2.3 | P2.2 | P2.1 | P2.0 |
中断允许 | IE | A8H | EA | ET2 (reg52.h //8052 only) | ES | ET1 | EX1 | ET0 | EX0 | |
P3 | P3 | B0H | P3.7 | P3.6 | P3.5 | P3.4 | P3.3 | P3.2 | P3.1 | P3.0 |
中断优先 | IP | B8H | PT2 (reg52.h) | PS | PT1 | PX1 | PT0 | PX0 | ||
定时器/计数器2 | T2CON | C8H | TF2 | EXF2 | RCLK | TCLK | EXEN2 | TR2 | C/T*2 | CP/RL2 |
定时器/计数器2模式 | T2MOD | C9H | T2OE | DCEN | ||||||
捕获 | RCPA2L | CAH | ||||||||
RCPA2H | CBH | |||||||||
定时器/计数器2高低位 | TL2 | CCH | ||||||||
TH2 | CDH | |||||||||
程序状态字 | PSW | D0H | CY | AC | F0 | RS1 | RS0 | OV | PF | |
累加器 | ACC | E0H | ||||||||
寄存器B | B | F0H |
定时器
- 计数周期为:机器周期
定时器/计数器0、1
- 寄存器
定时器计数器控制寄存器 | TCON | 88H | TF1 | TR1 | TF0 | TR0 | IE1 | IT1 | IE0 | IT0 |
---|---|---|---|---|---|---|---|---|---|---|
定时器计数器方式控制 | TMOD | 89H | GATE1 | C/T*1 | M1_1 | M1_0 | GATE0 | C/T*0 | M0_1 | M0_0 |
中断允许 | IE | A8H | EA | ES | ET1 | EX1 | ET0 | EX0 | ||
定时器计数器0L | TL0 | 8AH | ||||||||
定时器计数器1L | TL1 | 8BH | ||||||||
定时器计数器0H | TH0 | 8CH | ||||||||
定时器计数器1H | TH1 | 8DH |
M1M0 | 工作方式 | 功能 | 备注 |
---|---|---|---|
00 | 0 | 13位(不可重装) | 高5位加低8位 |
01 | 1 | 16位不可重装 | \ |
10 | 2 | 8位自动重装 | TH值==>>TL值 |
11 | 3 | 两个8位计数器(只适用于T0) |
- IE 【EA = 1】
- ET对应置为才能启用中断功能
定时器T2
- 中断软件清零
- 寄存器
定时器/计数器2 | T2CON | C8H | TF2 | EXF2 | RCLK | TCLK | EXEN2 | TR2 | C/T*2 | CP/RL2 |
---|---|---|---|---|---|---|---|---|---|---|
定时器/计数器2模式 | T2MOD | C9H | T2OE | DCEN | ||||||
定时器/计数器2高低位 | TL2 | CCH | ||||||||
TH2 | CDH | |||||||||
捕获 | RCPA2L | CAH | ||||||||
RCPA2H | CBH |
T2CON
- 有两个信号源:①内部时钟溢出TF2。②外部T2EX负跳沿。
- 定时器2有三个工作方式
- 捕获方式
- 自动重装(向上/下计数)
- 波特率发生器
RCLK | TCLK | CP/R2 | EXEN2 | 工作方式 |
---|---|---|---|---|
1 | 1 | x | x | 波特率发生器 |
0 | 0 | 1 | 1 | 外部T2EX*捕获 |
0 | 0 | 1 | 0 | \ |
0 | 0 | 0 | 1 | 外部T2EX*重装 |
0 | 0 | 0 | 0 | 溢出自动重装 |
- T2CON
- TF2:T2溢出标志,硬件置位,软件清零
- EXF2:定时器2外部标志。当EXEN2=1,且当T2EX引脚上出现负跳变而出现捕获或重装载时,EXF2置位,申请中断.此时如果允许定时器2中断,CPU响应中断,执行定时器2中断服务程序,EXF2必须由软件清除。当定时器2工作在向上或向下计数工作方式时(DCEN=1) , ExF2不能激活中断。
- 串行通信()设置
- RCLK:接收时钟允许。1:用T2溢出脉冲作为串行口的接收时钟。0:用Tl的溢出脉冲作为接收时钟。
- TCLK:发送时钟允许。同上。
- EXEN2:T2外部允许标志。
- 1:T2 捕获或重装载
- 0:T2EX端的外部信号无效。
- TR2:定时器2启动、暂停
- C/T*:定时器2计数方式。C模式:下跳沿触发
- CP/RL2:捕获/重装载选择。【与EXEN2关联】
- l:T2EN双端出现负跳变脉冲时发生捕获操作。
- 0:若定时器2溢出或EXEN2=l条件下,T2EN双端出现负跳变脉冲,都会出现自动重装载操作。当RCLK=1或TCLK=1时,该位无效,在定时器2溢出时强制其自动重装载。
定时器/计数器2模式 | T2MOD | C9H | T2OE | DCEN |
---|
- T2OE:T2输出允许位,当T2OE=1的时候,允许时钟输出到P1.0。(仅对80C54/80C58有效)
- DCEN:向下计数允许位。DCEN=1是允许T2向下计数,否则向上计数。
重装模式
- 用RCAPH、L值装入T2H、L
捕获模式
- 当EXEN2=0时,只当作一个16bit定时器/计数器。
- 当EXEN2=1,出现T2EN时下跳,将T2H、L装入RCAPH、L
波特率模式
- 用RCAPH、L重装
- 波 特 率 = 振 荡 频 率 32 × [ 65536 − ( R C P A 2 H , R C P A 2 L ) B ] 波特率=\frac{振荡频率}{32×[65536-(RCPA2H,RCPA2L)_B]} 波特率=32×[65536−(RCPA2H,RCPA2L)B]振荡频率
调用方法
定时器0、1
#include <reg52.h>
char timer0 = ; //T0计数值
char timer0_1 = ; //模式3下另一个计数器
void init_T0();
int main(){
Intr_init();
Timer0_init();
while(1)
{
/* idle process */
};
return 0;
}
/* 中断初始化 */
void Intr_init()
{
ET0 = 1; //开T0中断
ET1 = 1; //开T1中断
EA = 1;
}
/* 定时器初始化 */
void Timer0_init()
{
//初始化定时器0初值
/*******模式0*********/
TH0 = (8192 - timer0)/255;
TL0 = (8192 - timer0)%255;
/*
*******模式1*********
TH0 = (65536 - timer0)/255;
TL0 = (65536 - timer0)%255;
*******模式2*********
TH0 = 256 - timer0;
TL0 = 256 - timer0;
*******模式3*********
TH0 = 256 - timer0;
TL0 = 256 - timer0_1;
*/
//定时器模式选择
//参考寄存器表
TMOD = 0x00; //模式0:13位
/*
TMOD = 0x01; //模式1:16位
TMOD = 0x02; //模式2:8位自动重装
TMOD = 0x03; //两个8位
TMOD = TMOD | 0x04; //计数器模式
TMOD = TMOD | 0x08; //门控使能
*/
TR0 = 1;
//TR1 = 1;
}
/* T0中断服务程序 */
void intr_T0() interrupt 1
{
/* do something */
}
定时器2
#include <reg52.h>
char timer2 = ; //T0计数值
void init_T2();
int main(){
Intr_init();
Timer2_init();
while(1)
{
/* idle process */
};
return 0;
}
/* 中断初始化 */
void Intr_init()
{
/* 波特率模式下不需中断 */
//ET2 = 1; //开T2中断
//修改中断优先级
PT2 = 1;
EA = 1;
}
/* 定时器初始化 */
void Timer2_init()
{
//初始化定时器2初值
/*******波特率模式*********/
TH0 = (65536 - timer2)/255;
TL0 = (65536 - timer2)%255;
RCAP2L = (65536 - timer2)/255;
RCAP2H = (65536 - timer2)%255;
/* *******捕获模式********* TH0 = 0x00; TL0 = 0x00; *******重装模式********* TH0 = 65536 - timer2; TL0 = 65536 - timer2; RCAP2L = 65536 - timer2; RCAP2H = 65536 - timer2; */
//定时器2模式选择
//参考寄存器表
RCLK = 1; //波特率发生器模式
TCLK = 1;
/* EXEN2 = 1; //使能外部引脚 CP_RL2 = 1; //捕获模式 C_T2 = 1; //使用计数器 */
TR2 = 1;
}
/* T0中断服务程序 */
void intr_T2() interrupt 5
{
TF2 = 0; //软件清零
//EXF2 = 0;
/* do something */
}
中断
- 中断向量表
中断号 | 中断地址 | 中断功能 |
---|---|---|
0 | 03H | EX0 |
1 | 0BH | T0 |
2 | 13H | EX1 |
3 | 1BH | T1 |
4 | 23H | ES |
5 | 2BH | ET2 |
- 优先级
IP^ | 中断功能 |
---|---|
0 | EX0 |
1 | T0 |
2 | EX1 |
3 | T1 |
4 | ES |
5 | ET2 |
串行控制 | SCON | 98H | SM0 | SM1 | SM2 | REN | TB8 | RB8 | TI | RI |
---|---|---|---|---|---|---|---|---|---|---|
串行缓冲区 | SBUF | 99H |
SM0-2
- SM2:多机通信控制位
- SM0、SM1:串口工作模式
SM0 | SM1 | 说明 | 波特率 |
---|---|---|---|
0 | 0 | 同步移位寄存器 | Fosc/12 |
0 | 1 | 10bit帧、8bitdata | 定时器T1/T2 |
1 | 0 | 11bit帧、8bit、1bit多机 | Fosc/32或Fosc/64 |
1 | 1 | 11bit帧、8bit、1bit多机 | T1/T2 |
- REN:接收使能
- T、RB8:11bit帧作为第九位
- TI、RI:发送接收中断标志,硬件置位,软件清零
实现方法
非中断方法
#include <reg52.h>
void Intr_init();
void UartInit();
void send_data(unsigned char x);
unsigned char recieve_data();
unsigned char buf = 0;
int main(){
Intr_init();
UartInit();
send_data(buf);
buf = recieve_data();
while(1);
return 0;
}
void Intr_init()
{
EA = 1;
ES = 0;
}
void send_data(unsigned char x)
{
SBUF = x;
while(TI == 0);
TI = 0;
}
unsigned char recieve_data(){
unsigned char x;
while(RI == 0);
x = SBUF;
RI = 0;
return x;
}
void UartInit() //9600bps@12.000MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xD9; //设置定时初始值
TH1 = 0xD9; //设置定时重载值
ET1 = 0; //禁止定时器%d中断
TR1 = 1; //定时器1开始计时
}
中断方法
#include <reg52.h>
void Intr_init();
void UartInit();
char busy = 0;
unsigned char buf = 0;
int main(){
Intr_init();
UartInit();
while(1)
{
if(busy == 0)
{
SBUF = 0x25;
busy = 1;
}
};
return 0;
}
void Intr_init()
{
EA = 1;
ES = 1;
ET1 = 0;
}
void UartInit() //9600bps@12.000MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xD9; //设置定时初始值
TH1 = 0xD9; //设置定时重载值
ET1 = 0; //禁止定时器%d中断
TR1 = 1; //定时器1开始计时
}
void Uart_Intr() interrupt 4
{
if(RI)
{
RI = 0;
/* do something */
}
else if(TI)
{
TI = 0;
busy = 0;
/* do something */
}
}
重定向printf
#include <reg52.h>
#include <stdio.h>
void Intr_init();
void UartInit();
char send_busy = 0;
char write_busy = 0;
unsigned char buf = 0;
/* 重定向 */
//UART1 发送串口数据
void UART1_SendData(char dat)
{
ES=0; //关串口中断
SBUF=dat;
while(TI!=1); //等待发送成功
TI=0; //清除发送中断标志
ES=1; //开串口中断
}
//重写putchar函数
char putchar(char c)
{
UART1_SendData(c);
return c;
}
int main(){
Intr_init();
UartInit();
while(1)
{
printf("字符串");
};
return 0;
}
void Intr_init()
{
EA = 1;
ES = 0;
ET1 = 0;
}
void UartInit() //9600bps@12.000MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //设置定时器模式
TMOD |= 0x20; //设置定时器模式
TL1 = 0xD9; //设置定时初始值
TH1 = 0xD9; //设置定时重载值
ET1 = 0; //禁止定时器%d中断
TR1 = 1; //定时器1开始计时
}
其他功能寄存器
PCON
电源和波特率 | PCON | 87H | SMOD | GF1 | GF0 | PD | IDL |
---|
- PD:掉电工作位
- IDL:空闲工作位
- GF:系统保留通用标志
PSW
- CY:进位标志
- AC:辅助进位标志
- F0、F1:用户定义
- RS1、0:工作寄存器
- OV:溢出标志
- P:奇偶标志:1–>奇
STC15F100系列
- 在AT89C52基础增加
- 【看门狗】
- 【IAP】
- 【可编程时钟输出】
- 【P3 I/O控制寄存器】
- 在AT89C52基础减去
- 【定时器2(包括捕获功能)】
- 修改定时器工作模式0为
特殊寄存器映射
SFR | 符号 | 字节(物理)地址 | 位名称 | |||||||
---|---|---|---|---|---|---|---|---|---|---|
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | |||
电源控制寄存器 | PCON | 87H | - | - | LVDF | - | GF1 | GF0 | PD | IDL |
辅助寄存器0 | AUXR | 8EH | T0*12 | T1*12 | - | - | - | - | - | - |
INT_CLKO | INT_CLKO | 8FH | - | EX4 | EX3 | EX2 | - | - | T1CLKO | T0CLKO |
CLK_DIV | CLK_DIV | 97H | - | - | - | - | - | CLKS2 | CLKS1 | CLKS0 |
P3M1 | P3M1 | B1H | ||||||||
P3M0 | P3M0 | B2H | ||||||||
IRC_CLKO | IRC_CLKO | BBH | - | - | - | - | - | - | IRCS1 | IRCS0 |
WDT_CONR | WDT_CONR | C1H | ||||||||
ISP/IAP Flash数据寄存器 | IAP_DATA | C2H | ||||||||
ISP/IAP Flash地址高8bit | IAP_ADDRH | C3H | ||||||||
ISP/IAP Flash地址低8bit | IAP_ADDRL | C4H | ||||||||
ISP/IAP命令寄存器 | IAP_CMD | C5H | - | - | - | - | - | - | MS1 | MS0 |
ISP/IAP命令触发器 | IAP_TRIG | C6H | ||||||||
ISP/IAP控制寄存器 | IAP_CONTR | C7H | IAPEN | SWBS | SWRST | CMD_FAIL | - | WT2 | WT1 | WT0 |
可编程时钟
系统时钟分频
CLK_DIV | CLK_DIV | 97H | - | - | - | - | - | CLKS2 | CLKS1 | CLKS0 |
---|
- 系统R/C震荡时钟分频如下表格
CLKS2 | CLKS1 | CLKS0 | 分频系数 |
---|---|---|---|
0 | 0 | 0 | /1 |
0 | 0 | 1 | /2 |
0 | 1 | 0 | /4 |
0 | 1 | 1 | /8 |
1 | 0 | 0 | /16 |
1 | 0 | 1 | /32 |
1 | 1 | 0 | /64 |
1 | 1 | 1 | /128 |
可编程时钟输出
- 有三路可编程时钟输出
- IRC_CLKO/P3.4
- CLK_OUT0/P3.5
- CLK_OUT1/P3.4
- 寄存器
辅助寄存器0 | AUXR | 8EH | T0*12 | T1*12 | - | - | - | - | - | - |
---|---|---|---|---|---|---|---|---|---|---|
INT_CLKO | INT_CLKO | 8FH | - | EX4 | EX3 | EX2 | - | - | T1CLKO | T0CLKO |
IRC_CLKO | IRC_CLKO | BBH | - | - | - | - | - | - | IRCS1 | IRCS0 |
- AUXR
- T*12:定时器速度是传统51的12倍**【计数时钟为系统(晶振)时钟】**
- INT_CLKO
- T1CLKO:管脚P3.5允许时钟输出【定时器1】
- T0CLKO:管脚P3.4允许时钟输出【定时器0】
- 输出时钟频率= T溢出率 / 2
- IRC_CLKO
- IRCS:输出IRC时钟(见下表)
IRCS1 | IRCS0 | 输出频率 |
---|---|---|
0 | 0 | 无时钟输出 |
0 | 1 | 内部时钟输出不分频 |
1 | 0 | 2分频 |
1 | 1 | 4分频 |
P3口输出模式
- P3M0、1:设定P3.5-3.0
P3M1[5:0] | P3M0[5:0] | I/O模式 |
---|---|---|
0 | 0 | 标准双向I/O |
0 | 1 | 推挽 |
1 | 0 | 高阻 |
1 | 1 | 开漏(外加上拉电阻) |
IAP
- 1KB/2KB数据EEPROM
- 每个扇区512(0.5K)字节数据
ISP/IAP Flash数据寄存器 | IAP_DATA | C2H | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
ISP/IAP Flash地址高8bit | IAP_ADDRH | C3H | ||||||||
ISP/IAP Flash地址低8bit | IAP_ADDRL | C4H | ||||||||
ISP/IAP命令寄存器 | IAP_CMD | C5H | - | - | - | - | - | - | MS1 | MS0 |
ISP/IAP命令触发器 | IAP_TRIG | C6H | ||||||||
ISP/IAP控制寄存器 | IAP_CONTR | C7H | IAPEN | SWBS | SWRST | CMD_FAIL | - | WT2 | WT1 | WT0 |
IAP_CMD
- 命令见下表
MS1 | MS0 | 命令内容 |
---|---|---|
0 | 0 | 待机、无操作 |
0 | 1 | 对数据Flash区读字节 |
1 | 0 | 对数据Flash区进行字节编程 |
1 | 1 | 对数据Flash扇区进行擦除 |
IAP_TRIG
- ,触发命令
IAP_CONTR
ISP/IAP控制寄存器 | IAP_CONTR | C7H | IAPEN | SWBS | SWRST | CMD_FAIL | - | WT2 | WT1 | WT0 |
---|
- IAPEN:IAP读写擦使能
- SWBS:0:软件选择从用户应用程序启动;1:从系统ISP监控程序区启动
- SWRST:1:软件复位
- CMD_FAIL:触发命令失败标志位,软件清零
- WT2-0:设置等待时间(见下表)
WT2 | WT1 | WT0 | Read | Program | Sector Erase | 推荐系统时钟 |
---|---|---|---|---|---|---|
0 | 0 | 0 | 2个时钟 | 55个时钟 | 21012个时钟 | <=1MHz |
0 | 0 | 1 | 2个时钟 | 110个时钟 | 42024个时钟 | <=2MHz |
0 | 1 | 0 | 2个时钟 | 165个时钟 | 63036个时钟 | <=3MHz |
0 | 1 | 1 | 2个时钟 | 330个时钟 | 126072个时钟 | <=6MHz |
1 | 0 | 0 | 2个时钟 | 660个时钟 | 252114个时钟 | <=12MHz |
1 | 0 | 1 | 2个时钟 | 1100个时钟 | 420240个时钟 | <=20MHz |
1 | 1 | 0 | 2个时钟 | 1320个时钟 | 504288个时钟 | <=24MHz |
1 | 1 | 1 | 2个时钟 | 1760个时钟 | 672384个时钟 | <=30MHz |
调用方法
- 参考STCF100系列指南
#include <reg51.h> #include <intrins.h> typedef unsigned char Byte; typedef unsigned int Word; /* 声明ISP功能寄存器地址 */ sfr IAP_DATA = 0xC2; sfr IAP_ADDRH = 0xC3; sfr IAP_ADDRL = 0xC4; sfr IAP_CMD = 0xC5; sfr IAP_TRIG = 0xC6; sfr IAP_CONTR = 0xC7; /* 定义命令 */ #define CMD_IDLE 0 //Stand-By #define CMD_READ 1