外部中断
可能是定时器T1/T0方式0(16位可自动重装初值)或者定时器T2(只有16位可自动重装初值)
T1/T0与T2除了控制寄存器的配置有些不一样,其余定时初值等都是一样的.
//---------------定时器2初始化函数-----&中断方法------//
void T2_Init(void) //50毫秒@12Hz
{
AUXR &= 0xFB; //定时器时钟12T模式
T2L = 0xB0; //设置定时初值
T2H = 0x3C; //设置定时初值
EA = 1; //开总中断
IE2 |= 0X04; //开定时器2中断允许控制位
AUXR |= 0x10; //定时器2开始计时
}
●12分频:
t = ( 2 n − a ) ∗ 12 f s y s t=\frac{(2^n-a)*12}{f_{sys}} t=fsys(2n−a)∗12
●不分频:
t = ( 2 n − a ) ∗ 1 f s y s t=\frac{(2^n-a)*1}{f_{sys}} t=fsys(2n−a)∗1
时间t的单位位秒; (举例为50ms)
定时器应该只会考16位的,所以n=16;
系统时钟 f s y s f_{sys} fsys应该是12MHz,即 12 × 1 0 6 12×10^6 12×106Hz
若采用12分频,可算得计数初值十进制数a=15536,换算成二进制数位 a = ( 11110010110000 ) 2 a=(11 1100 1011 0000)_2 a=(11110010110000)2
课本P31
系统时钟 f s y s f_{sys} fsys =主时钟 f o s c f_{osc} fosc / N
N为分频系数,可以通过时钟分频寄存器CLK_DIV进行改变,默认为1.
例
#include
#define uchar unsigned char
#define uint unsigned int
uchar i=0;
uchar j;
void GPIO(void); //IO口初始化函数
void T2_Init(void); //定时器2初始化函数50毫秒@12Hz
void main(void)
{
GPIO(); //IO口初始化
T2_Init();//定时器2初始化
while(1); //用原地踏步模拟主程序
}
void GPIO(void) //IO口初始化函数
{
P0M1=0;
P0M0=0;
P1M1=0;
P1M0=0;
P2M1=0;
P2M0=0;
P3M1=0;
P3M0=0;
}
//---------------定时器2初始化函数-----&中断方法------//
void T2_Init(void) //50毫秒@12Hz
{
AUXR &= 0xFB; //定时器时钟12T模式
T2L = 0xB0; //设置定时初值
T2H = 0x3C; //设置定时初值
EA = 1; //开总中断
IE2 |= 0X04; //开定时器2中断允许控制位
AUXR |= 0x10; //定时器2开始计时
}
//------定时器二中断服务函数0----------//
void T2_ISR(void) interrupt 12
{
i++;
j=i/20;
if(j==0||j==1)
{
P46=0;
}
if(j==2)
{
P46=1;
}
if(j==3) i=0;
}
运行结果:
(波形图占空比,周期符合要求,但不是水平的原因可能是IO口内部RC充放电)
●方法二:
方法二改变了系统时钟 f s y s f_{sys} fsys ,来获得较长的时间.定时初值的计算方法与上边所说一样,只是需要提前将系统时钟 f s y s f_{sys} fsys按照公式算出.可以得到定时初值a= ( 3036 ) 10 (3036)_{10} (3036)10
#define x 3036 //定时1秒的初值
老师在程序中直接将3036用#define
宏定义为x
,(不加前缀声明数字类型时,默认为10进制数,编辑器在运行时统一将数字转化为二进制)
T2L = x; //设置定时初值 T2H = x>>8; //设置定时初值
T2L和T2H都是8位状态寄存器,只有8位,只能存8个数.上边第一句将x
赋值给T2L
,运行时编辑器自动将x
转化为二进制数1011 1101 1100,T2L寄存器只能保存二进制数的低八位.
x
右移8位,高位用0补齐,x>>8
的结果位0000 1011
,再将右移的结果赋值给T2H.
这种通过宏定义来赋值,是为了后续该程序容易改,考试没太有必要用,直接对T2L和T2H赋十六进制值就行.
#define uchar unsigned char
#define uint unsigned int
#define x 3036 //定时1秒的初值
uchar i=0;
void GPIO(void); //IO口初始化函数
void T2_Init(void); //定时器2初始化函数50毫秒@12Hz
void main(void)
{
GPIO(); //IO口初始化
T2_Init();//定时器2初始化
while(1); //用原地踏步模拟主程序
}
void GPIO(void) //IO口初始化函数
{
P0M1=0;
P0M0=0;
P1M1=0;
P1M0=0;
P2M1=0;
P2M0=0;
P3M1=0;
P3M0=0;
}
//---------------定时器2初始化函数-----&中断方法------//
void T2_Init(void) //50毫秒@12Hz
{
CLK_DIV=0x04; //系统时钟为主时钟的16分频
AUXR &= 0xFB; //定时器时钟12T模式
T2L = x; //设置定时初值
T2H = x>>8; //设置定时初值
EA = 1; //开总中断
IE2 |= 0X04; //开定时器2中断允许控制位
AUXR |= 0x10; //定时器2开始计时
}
void T2_ISR(void) interrupt 12
{
i++;
if(i==1||i==2)
{
P46=0;
}
if(i==3)
{
P46=1;
i=0;
}
}
运行结果:
多次改变时钟分频寄存器CLK_DIV的值,运行结果并未产生肉眼可见的变化.不知道是代码问题还又是仿真的BUG.
●方法一,二对比
方法一是先定时一个比较小的时间,之后定时器溢出,触发中断,进入定时器中断服务函数,循环变量i再中断函数里累加.判断循环变量i是否达到预定值,多次执行中断服务函数,产生误差时间.如果定时器定时时间比较小,需要较多次数地执行中断服务函数,误差时间就会肉眼可见.
所以在使用方法一时定时器定时时间应该尽可能的大,以减小误差.
方法二,多配置一个寄存器,增加犯错概率.
可提前将常用定时时间准备好
#include
#define uchar unsigned char
#define uint unsigned int
void GPIO(void); //IO口初始化函数
void T1_Init(void); //定时器1初始化函数10毫秒@12MHz
void main(void)
{
GPIO(); //IO口初始化
T1_Init();//定时器1初始化
}
void GPIO(void) //IO口初始化函数
{
P0M1=0;
P0M0=0;
P1M1=0;
P1M0=0;
P2M1=0;
P2M0=0;
P3M1=0;
P3M0=0;
}
//---------------定时器1初始化函数-----&中断方法------//
void T1_Init(void) //10毫秒@12MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xF0; //设置定时初值
TH1 = 0xB8; //设置定时初值
TF1 = 0; //清除TF1标志
EA = 1; //开总中断
ET1 = 1; //开定时器1中断允许控制位
TR1 = 1; //定时器1开始计时
}
void T1_ISR(void) interrupt 3
{
}
1、在系统编程(In System Programming,ISP)
在应用编程(In Application Programming,IAP)P14
2、STC单片机命名规则P15
●工作电压:F、L、W
●程序空间大小(程序储存器)
1、任何一个中央处理单元CPU都包含有控制器和运算器两大基本模块
2、通过程序计数器(Program Counter,PC)从程序存储器中源源不断地取出所要执行的代码。因此,程序计数器PC是CPU中最基本的控制部分。PC的特点就是总是指向下一条所要执行的指令的地址空间。P22
3、程序计数器的宽度为16位。也就是说,地址深度为216,地址的范围为0~65535,即64K。因此,程序存储器的深度最大为64K。
4、数据指针(Dual Data Pointer,DPTR)是一个16位的专用寄存器。
由DPL(低8位)和DPH(高8位)组成,其地址为82H(DPL,低字节)和83H(DPH,高字节)。DPTR是8051中唯一可以直接进行16位操作的寄存器。此外,也可以按照字节分别对DPH和DPL进行操作。P25
5、在STC单片机中,用于控制指向存储空间位置的是一个堆栈指针(Stack Pointer,SP)它实际上就是一个8位的专用寄存器。该寄存器的内容就是栈顶的地址,也就是用于表示当前栈顶在内部RAM块中的位置。其作用主要用于保存现场。先进后出,后进先出P25
6、指针类寄存器3个,SP;DPTR;PC
7、运算器:8位算术逻辑单元ALU(核心);累加器ACC;B寄存器;程序状态字PSW P21
8、指令通道???
9、
10、程序存储器16位的PC指向下一条要执行的指令。
CPU只能通过使用MOVC指令,从程序空间读取数据。
当单片机复位后,程序计数器(PC)的内容为0x0000。
因此,从程序存储器地址为0x0000的地方开始执行程序。另外,中断服务程序的入口地址(也称为中断向量)也放在程序存储单元。
11、STC系列单片机内部提供了大容量的数据Flash存储器,用于实现电可擦除的**只读存储器(EEPROM)**功能。
数据Flash存储器和程序Flash存储器空间是分开的。
12、