#定时器中断原理#
(这个都是数模电模的知识,看不懂的宝子不用担心哒,但是原理还要知道一点哦^_^)
①定时器
由16位计数器组成,每加一次时间固定(1微秒)
②晶振原理
晶振具有压电效应,即在晶片俩极外加电压后晶体会产生变形,反过来,如果外力使晶片变形,则两极上就会产生电压
③晶振分类:
1.有源晶振:震荡器,有四个引脚,不需要CPU的内部振荡器,信号稳定,质量较好,连接方式简单,产生信号为方波信号(特例位正弦波信号)示波器测信号与GND之间,供电便能产生一个时钟信号,误差最小为0.1PPM
2.无源晶振:晶体,一般为2引脚的无极性器件,一般需要借助与负载电容形成的时钟电路才能产生震荡信号,产生正弦波信号,用示波器测一个引脚与地之间的波形,需要特殊的引脚搭配(XTAL1与XTAL2指的是8051系单片机上常见的用于接“晶振”的俩个引脚,从原理来说,这俩个引脚与MCU内部的反相器相连接,反相器与外部的晶振组成一个构成一个皮尔斯振荡器,误差最小为5PPM
下面为晶振原理图👇

晶振+俩个电容→形成12MHZ正弦波→(整形)方波12MHZ→(12分频)1MHZ(周期1微秒)
方波每一个脉冲为1微秒,提供时钟
④单片机中断逻辑
12MHZ晶振整形成12MHZ方波再分频成1MHZ的脉冲信号,周期为1微秒,一个脉冲信号使加法计数器加一,加到65535后,再加一就会溢出,产生中断标志位为1,触发定时器中断,进入中断服务函数,硬件将中断服务函数标志位归0,加法计数器开始加一(中断函数不能执行太久,不然又会进入中断,系统死机),中断服务函数执行完,返回主函数
(补充)51单片机为八位单片机(寄存器八位)
计数器为16位(高八位THO与低八位TLO整合)寄存器加一直到填满16位,十进制为65535,再加一,寄存器会清零,在16位外会产生1(进位信号→计数器中断的标志位,计数器计数完毕,进入中断函数,执行完毕后再执行主函数)
下面为示意图👇
16位计数器,从0开始计数到产生一个标志位,需要(65535(满)+1(溢出))微秒
⑤初始化
初始化 装初值①THO=(65536-你所需要的值)/256
②TLO=(65536-你所需要的值)%256
中断函数{
重装初值
①THO=(65536-你所需要的值)/256
②TLO=(65536-你所需要的值)%256
}
⑥手动计算

⑦知识点:
1.15系列51单片机由单个定时/计数器,T0,T1,T2,为16位加法计数器,由低8位TL0(TL1,TL2)和高8位TH0(TH1,TH2)俩个寄存器组成,最大计数值位65535个计数脉冲




重中之重!!!
编写中断服务函数
11. 程序设计
12. 实现多个延时函数
1.定时器初始化:(12MHZ 1ms 16位自动重装)
2.中断服务函数:
count++;//count1++//count2++
If(count==200)//200ms计时
count =0;
If(count1==500) count 1=0;
If(count2==1000) count2=0;

15.函数编写示范
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
//定义
sbit LSA=P2^5;
sbit LSB=P2^6;
sbit LSC=P2^7;
sbit S5=P3^2;
uchar state;
//hc573定义
void hc573(uint channel)
{
switch(channel)
{
case 4:LSA=0;LSB=0;LSC=1;break;
case 5:LSA=1;LSB=0;LSC=1;break;
case 6:LSA=0;LSB=1;LSC=1;break;
case 7:LSA=1;LSB=1;LSC=1;break;
}
}
//延时函数
void delay_ms(uchar xms) //@12.000MHz
{
for( ;xms>0;xms--)
{
unsigned char data i, j;
i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}
}
//初始化
void init()
{
hc573(4);
P0=0XFF;
hc573(5);
P0=0X00;
EA=1;
EX0=1;//外部中断0
IT0=1;//外部中断0下降沿触发
//外部中断函数的初始化
}
//led控制函数
void led()
{
hc573(4);
if(state==1)
{
P0=0XFE;
}
else if(state==2)
{
P0=0XFF;
delay_ms(500);
P0=0XFE;
delay_ms(500);
}
else
{
P0=0XFF;
}
//控制L1灯的开关于闭合,用state计数
//state=0,灯灭
//state=1,灯亮
//state=3→state=0,灯灭
//(循环)
}
//外部中断函数
void External() interrupt 0
{
hc573(4);
if(S5==0)
{
delay_ms(10);//延时消抖
if(S5==0)//开关闭合
{
state = 1+state;//用于循环计数
if(state==3)
{
state=0;
}
while(S5==0);//S5一直是闭合状态
delay_ms(10);//延时消抖
while(S5==0);//按键S5若是闭合,一直维持该状态
}
}//消抖
}
//主函数
void main()
{
init();
while(1)
{
led();
}
}
16.定时器解决之前led点亮问题
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
//整体思路:
//跟随模式让L1亮起→LE为1→Y4C为1→Y4为0→P25 P26 P27 为001→倒着看为100(二进制)
//位定位
sbit LSA =P2^5;
sbit LSB =P2^6;
sbit LSC =P2^7;
sfr AUXR =0x8e;//
uchar count;//进入中断函数的次数
uchar state_led;//led1()的状态码
uchar position;//led2()led的移位
uchar direction;//led2()led的移动方向(向左移或者向右移)
//hc573初定义
void hc573(uint channel)
{
switch(channel)
{
case 4:LSA=0;LSB=0;LSC=1;break;
case 5:LSA=1;LSB=0;LSC=1;break;
case 6:LSA=0;LSB=1;LSC=1;break;
case 7:LSA=1;LSB=1;LSC=1;break;
}
}
//蜂鸣器初始化
void init_system()
{
hc573(5);
P0=0X00;
//LED初始化是熄灭状态
hc573(4);//Y4为0状态→跟随模式
P0=0Xff;//等势,灯全灭
}
////延时函数+时间单位
//void delay_ms(uint xms)//标参数,执行5次就是5ms
//{
// //@12.000MHz
// for ( ;xms>0;xms--)
// {
// unsigned char data i, j;
// i = 12;
// j = 169;
// do
// {
// while (--j);
// } while (--i);//执行1ms
// }
//}
//定时器初始化50ms
void initial_timer0()
{
AUXR &=0x7f;//定时器12t模式
TMOD &=0xf0;//设置定时器模式
TL0 =0xb0;
TH0 =0x3c;//定时初值
TF0=0;//清楚tf0标志
EA=1;//总开关闭合
ET0=1;//定时器0
TR0=1;//定时器0开始计时标志
}
//定时器中断服务函数
void timer0() interrupt 1
{
count ++;//记录次数
if(count==10)//进行10次为500ms
{
count =0;//count归零
state_led=1-state_led;//led1的状态变化
//下面的函数跟之前做的for函数类似
if(direction==0)//向右移(从左到右依次点亮)
{
position++;
if(direction==8)//灯全部点亮状态,若是从俩边到中间点亮,需要改为4
{
direction=1;//方向改变,向左移(从右到左依次熄灭)
}
}
else
{
position--;//从右到左依次熄灭
if(position==0)//全部熄灭状态
{
direction=0;//改变方向
}
}
}
}
//灯函数集
void led1()//led每隔500ms闪烁一次
{
hc573(4);
if(state_led==0)
{
P0=0XFF;
}
else
{
P0=0X00;
}
}
void led2()//led从左到右依次点亮,在从右到左依次熄灭
{
hc573(4);
P0=0XFF<<position;//实现条件,position每隔500ms加1(从左到右依次点亮)
//再position每隔500ms依次减一(从右到左依次熄灭)
}
void led3()//led每次只亮一个,从左到右点亮,再从右到左点亮,时间间隔500ms
{
hc573(4);
P0=~(0X01>>position);
}
void led4()//每次只亮俩个,从左到右依次点亮,再从右到左点亮
{
hc573(4);
P0=~(0X03<<position);
}
void led5()//俩边到中间点亮,在从中间到俩边熄灭
{
hc573(4);
P0=~((0XFF<<position)&(0XFF>>position));
}
void led6()//每次只亮俩个,从俩边到中间靠拢,在从中间道理啊Bain扩散,时间间隔500ms
{
hc573(4);
P0=~((0X80>>position)&(0x01<<position));
}
//void led()
//{
// uint i=0;
// for(i=0;i<9;i++)
// {
// P0 = 0xff << i;
// delay_ms(500);
// }
//从俩边到中间点亮,再从中间到俩边熄灭
/*for(i=0;i<4;i++)
{
P0=(0xff<<i) & (0xff>>i);
delay_ms(500);
}
for(i=5;i<9;i++)
{
P0=(0xff>>i) | (0xff<<i);
delay_ms(500);
}
*/
//分别从左到右,从右到左依次点亮
/*for(i=0;i<9;i++)
{
P0=0xff<<i;
delay_ms(500);
}
for (i=8;i>0;i--)
{
P0=0xff<<i;
delay_ms(500);
}*/
/* P0=0X00;//L1=L2=L3=L4=L5=L6=L7=L8=0;
delay_ms(500);
P0=0XFF;//L1=L2=L3=L4=L5=L6=L7=L8=1;
*/
// delay_ms(500);//亮灭持续
//}
//主函数
void main()//main函数只执行一遍 ,时间太短,看不出效果→加时长while循环
{
init_system();
initial_timer0();
//LSA=0; LSB=0;LSC=1;//跟随模式
//L1=0;//灯亮
//俩边等势,灯灭
// L2=L3=L4=L5=L6=L7=L8=1;
while(1)
{
led1();
led2();
led3();
led4();
led5();
led6();
}
}
#添加一嘴,之前的LED模块的代码将所有情况代码重新编写了蓝桥杯51单片机设计-CSDN博客#



9261

被折叠的 条评论
为什么被折叠?



