当前位置:   article > 正文

STC89C52---定时器,中断_89c52使用外部中断1配合led灯实验,当外部中断1启用时led灯的亮度发生改变,比如一

89c52使用外部中断1配合led灯实验,当外部中断1启用时led灯的亮度发生改变,比如一

目录

一:定时器

1:简历

2:定时器/计数器0/1和相关寄存器

A:介绍

B: 相关寄存器

C:基本原理

3:定时器/计数器控制寄存器TCON

4:定时器/计数器工作模式寄存器TMOD

 (1)门控制

(2):使用STC-iSP软件生成配置

(3):使用STC-iSP软件定时器

(4)时间的计算

二:中断

1:简历

B:中断寄存器

2:中断流程

 3:中断系统

4:中断函数

5:配置中断流程 

6:中断源

 三:配置定时器和中断

B:2,10,16进制转化

四:案例

1:定时器点亮LED灯

2:定时器时钟


一:定时器

1:简历

51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成 定时器

作用: (1)用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作

            (2)替代长时间的Delay,提高CPU的运行效率和处理速度 

                (…)

定时器个数:3个(T0、T1、T2),T0和T1与传统的51单片机兼容,T2是此型号单片机增加的资源 注意:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0和T1的操作方式是所有51单片机所共有的

2:定时器/计数器0/1和相关寄存器

A:介绍

STC89C52系列单片机的定时器0和定时器1,与传统8051的定时器完全兼容,当在定时器1做波特率发生器时,定时器0可以当两个8位定时器用。


STC89C52系列单片机内部设置的两个16位定时器/计数器TO和T1都具有计数方式和定时方式两种工作方式。对每个定时器/计数器(TO和T1),在特殊功能寄存器TMOD中都有一控制位-C/T来选择TO或T1为定时器还是计数器。定时器/计数器的核心部件是一个加法(也有减法)的计数器,其本质是对脉冲进行计数。只是计数脉冲来源不同: 如果计数脉冲来自系统时钟,则为定时方式,此时定时器/计数器每12个时钟或者每6个时钟得到一个计数脉冲,计数值加1:如果计数脉冲来自单片机外部引脚(TO为P3.4,T1为P3.5),则为计数方式,每来一个脉冲加1.

当定时器/计数器工作在定时模式时,可在烧录用户程序时在STC-ISP编程器中设置(如下图所示)是系统时钟一12还是系统时钟一6后让TO和T1进行计数。当定时器/计数器工作在计数模式时,对外部脉冲计数不分频。

定时器/计数器:0有4种工作模式: 模式0(13位定时器/计数器),模式1(16位定时器/计数器模式这个模式是最常使用的模式), 模式2(8位自动重装模式),模式3(两个8位定时器/计数器)。定时器/计数器1除模式3外,其他工作模式与定时器/计数器0相同,T1在模式3时无效,停止计数。

B: 相关寄存器

C:基本原理

3:定时器/计数器控制寄存器TCON

TCON: 定时器/计数器中断控制寄存器(可位寻址)  可位寻址-----可以单独给每一位赋值

TCON为8位寄存器,控制中断源的开启,可以位寻址。高4位控制定时器0/1,低4位控制外部中断。

①TR0:定时器0控制位。     TR1:定时器1控制位。

②TF0:定时器0溢出位,置1时申请中断    TF1:定时器1溢出位,置1时申请中断

  1.  TCON一般赋值以下的这两个位
  2.     TF0 = 0;        //清除TF0标志
  3.     TR0 = 1;        //启动定时器0

4:定时器/计数器工作模式寄存器TMOD


   不可位寻址----只能整体给8位赋值

  • GATE:门控制;GATE=0,仅有运行控制位TRx来控制定时/计数器的开启;GATE=1,由TRx和外部中断脉冲计数。(用于计算外部中断负跳变的次数)
  • C/T:计数器模式和定时器模式选择;C/T=0,选择定时器模式;C/T=1,选择计数器模式

 (1)门控制

A:GATE=0仅有运行控制位TRx来控制定时/计数器的开启;      当启动控制为1时关闭(通路),   0打开(断路)

B:GATE=1    置1时受外部中断引脚和TCON控制器控制

 配置TMOD打开定时器0   (下面这中写法只在开启一个定时器时有用, 开启动多个会覆盖)

  1. //TMOD打开定时器0
  2. TMOD=0x01 //0000 0001 GATE=0 C/T=0,选择定时器模式 01->16位定时器

开多个定时器下面这个写法

  1. //TMOD是不可位寻址,必须8位同时赋值 TMOD=0000 0001
  2. TMOD &= 0xF0; //设置定时器模式 TMOD=TMOD & 1111 0000 TMOD的低四位清零,高四位保持不变;
  3. TMOD |= 0x01; //设置定时器模式 TMOD=TMOD | 0000 0001 TMOD的最低位置1,高四位保持不变;
  4. /*
  5. TMOD的低四位清零,高四位保持不变;
  6. TMOD=1010 0011
  7. 1010 0011 & 1111 0000(0xF0)= 1010 0000
  8. */
  9. /*
  10. TMOD的最低位置1,高四位保持不变;
  11. TMOD=1010 0000
  12. 1010 0000 | 0000 0001(0x01)= 1010 0001
  13. */

(2):使用STC-iSP软件生成配置

  1. void Timer0Init(void) //1毫秒@12.000MHz
  2. {
  3. //TMOD配置
  4. TMOD &= 0xF0; //设置定时器模式
  5. TMOD |= 0x01; //设置定时器模式
  6. //设置定时器(计算)初值(TH0,TL0)因为打开的是0计时器
  7. TL0 = 0x18; //设置定时初值 定时器0的高低位
  8. TH0 = 0xFC; //设置定时初值 定时器0的高8位
  9. //TCON配置
  10. TF0 = 0; //清除TF0标志
  11. TR0 = 1; //定时器0开始计时
  12. }

定时器配置大致完成

(3):使用STC-iSP软件定时器

  1. //改造下给传传递延长时间
  2. #include <REGX52.H>
  3. void Delay(unsigned int xms) //
  4. {
  5. unsigned char i, j;
  6. while(xms)
  7. {
  8. i = 2;
  9. j = 239;
  10. do
  11. {
  12. while (--j);
  13. } while (--i);
  14. xms--;
  15. }
  16. }

(4)时间的计算

我们使用的是16位定时器, 并且没有自动装载, 所以在写中断函数的时需要手动写装载

 

        在16位全部变为1111 1111 1111 1111  (16进制)也就是65536每隔1us加1 (10进制)启动中断

        如果我们不设置初值它会从0开始加到了65536(10进制)每隔1us加1;   也就是65.536ms启动中断

        一般情况的使用我们会设置初值(TH0,TL0)它从初值开始加,加到65536启动中断(每隔1us加1),我们使用的是16位,并且没有自动装载的,所以需要手动在中断函数把TH0,TL0在写一遍

TH0:定时器0的高8位           TH1:定时器1的高8位

TL0:定时器0的低8位            TL01:定时器1的低8位

我们想每隔1ms让程序中断,进入中断函数,只需要将初值设置为64536既可以

  1. //16进制
  2. TH0=(65536-1000)/256 //定时器0的高8位
  3. TLO=(65536-1000)%256 //定时器0的低8位

解释

  1. //10进制
  2. 125/100=1
  3. 125%10=25

具体的应用在下面的实例代码的1:定时器点亮LED灯

二:中断

1:简历

中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的

当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。     实现这种功能的部件称为中断系统,请示CPU中断的请求源称为中断源。微型机的中断系统一般允许多个中断源,当几个中断源同时向CPU请求中断,要求为它服务的时候,这就存在CPU优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。CPU总是先响应优先级别最高的中断请求。


当CPU正在处理一个中断源请求的时候(执行相应的中断服务程序) ,发生了另外一个优先级比它还高的中断源请求。如果CPU能够暂停对原来中断源的服务程序,转而去处理优先级更高的中断请求源,处理完以后,再回到原低级中断服务程序,这样的过程称为中断嵌套。这样的中断系统称为多级中断系统,没有中断嵌套功能的中断系统称为单级中断系统。

B:中断寄存器

2:中断流程

 3:中断系统

 A:打开中断时必须打开全局中断 (EA=1)

B:打开对应的中断允许位

C:中断开的少,可以不用管中断优先级这个

4:中断函数

中断源个数:8个(外部中断0、定时器0中断、外部中断1、定时器1中断、串口中断、定时器2中断、外部中断2、外部中断3) 中断优先级个数:4个

中断号:                    中断函数名可以改但是不建议

注意:中断的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的中断资源,例如中断源个数不同、中断优先级个数不同等等

5:配置中断流程 

大置流程TMOD-->TCON-->计数器初值-->中断配置

6:中断源

 三:配置定时器和中断

  1. void Timer0Init(void) //1毫秒@12.000MHz
  2. {
  3. //定时器配置 (可以使用STC生成)
  4. TMOD &= 0xF0; //设置定时器模式
  5. TMOD |= 0x01; //设置定时器模式
  6. TL0 = 0x18; //设置定时初值
  7. TH0 = 0xFC; //设置定时初值
  8. TF0 = 0; //清除TF0标志
  9. TR0 = 1; //定时器0开始计时
  10. //中断配置
  11. ET=1; //打开中断允许位
  12. EA=1; //使能总开关
  13. }

B:2,10,16进制转化

四:案例

1:定时器点亮LED灯

mian.c

  1. #include <REGX52.H>
  2. #include "time.h"
  3. void main(){
  4. Init_time();
  5. while (1){
  6. }
  7. }

time.c

  1. #include <REGX52.H>
  2. //一般来说&是清零;|是置1
  3. unsigned int count=0;
  4. sbit LED_D1= P2^0;
  5. void Init_time() //1微秒@12.000MHz
  6. {
  7. TMOD &= 0xF0; //设置定时器模式
  8. TMOD |= 0x01; //设置定时器模式
  9. TL0 = 0x18; //设置定时初值
  10. TH0 = 0xFC; //设置定时初值
  11. TF0 = 0; //清除TF0标志
  12. TR0 = 1; //定时器0开始计时
  13. //中断配置
  14. ET0=1; //打开中断允许位
  15. EA=1; //使能总开关
  16. LED_D1=1;
  17. }
  18. void Timer0_Routine() interrupt 1
  19. {
  20. //每隔1微秒启动中断函数
  21. count++;
  22. /*因为它是16位,没有自动装载\
  23. 每次进去中断函数都会从0开始计数.计数到65536在中断
  24. 所以加上 TL0 = 0x18;TH0 = 0xFC;让它从64536计数
  25. 这个就是手动装载
  26. */
  27. TL0 = 0x18; //设置定时初值
  28. TH0 = 0xFC; //设置定时初值
  29. if (count==1000)
  30. {
  31. count=0;
  32. LED_D1=~ LED_D1;
  33. }
  34. }
  35. //每隔1微秒启动中断,然后自动打开中断函数

time.h

  1. #ifndef __TIME_H__
  2. #define __TIME_H__
  3. void Init_time();
  4. void Timer0_Routine();
  5. #endif

2:定时器时钟

main.c

  1. #include <REGX52.H>
  2. #include "LCD1602.h"
  3. #include "Delay.h"
  4. #include "Timer.h"
  5. unsigned char Sec,Min,Hour;
  6. void main()
  7. {
  8. //初始化lcd和定时器
  9. LCD_Init();
  10. Timer0Init();
  11. LCD_ShowString(1,1,"Clock:"); //上电显示静态字符串
  12. LCD_ShowString(2,1," : :");
  13. while(1)
  14. {
  15. LCD_ShowNum(2,1,Hour,2); //显示时分秒
  16. LCD_ShowNum(2,4,Min,2);
  17. LCD_ShowNum(2,7,Sec,2);
  18. }
  19. }
  20. void Timer0_Routine() interrupt 1
  21. {
  22. static unsigned int T0Count;
  23. TL0 = 0x18; //设置定时初值
  24. TH0 = 0xFC; //设置定时初值
  25. T0Count++;
  26. if(T0Count>=1000) //定时器分频,1s
  27. {
  28. T0Count=0;
  29. Sec++; //1秒到,Sec自增
  30. if(Sec>=60)
  31. {
  32. Sec=0; //60秒到,Sec清0,Min自增
  33. Min++;
  34. if(Min>=60)
  35. {
  36. Min=0; //60分钟到,Min清0,Hour自增
  37. Hour++;
  38. if(Hour>=24)
  39. {
  40. Hour=0; //24小时到,Hour清0
  41. }
  42. }
  43. }
  44. }
  45. }

Timer.c

  1. #include <REGX52.H>
  2. /**
  3. * @brief 定时器0初始化,1毫秒@12.000MHz
  4. * @param 无
  5. * @retval 无
  6. */
  7. void Timer0Init(void)
  8. {
  9. TMOD &= 0xF0; //设置定时器模式
  10. TMOD |= 0x01; //设置定时器模式
  11. TL0 = 0x18; //设置定时初值
  12. TH0 = 0xFC; //设置定时初值
  13. TF0 = 0; //清除TF0标志
  14. TR0 = 1; //定时器0开始计时
  15. ET0=1;
  16. EA=1;
  17. PT0=0;
  18. }
  19. /*定时器中断函数模板
  20. void Timer0_Routine() interrupt 1
  21. {
  22. static unsigned int T0Count;
  23. TL0 = 0x18; //设置定时初值
  24. TH0 = 0xFC; //设置定时初值
  25. T0Count++;
  26. if(T0Count>=1000)
  27. {
  28. T0Count=0;
  29. }
  30. }
  31. */

Timer.h

  1. #idndef __TIMER_H__
  2. #define __TIMER_H__
  3. void Timer0Init(void);
  4. #endif

Delay.c

  1. void Delay(unsigned int xms)
  2. {
  3. unsigned char i, j, k;
  4. while (xms--)
  5. {
  6. i = 6;
  7. j = 157;
  8. k = 59;
  9. do
  10. {
  11. do
  12. {
  13. while (--k);
  14. } while (--j);
  15. } while (--i);
  16. }
  17. }

Delay.h

  1. #ifndef __DELAY_H__
  2. #define __DELAY_H__
  3. void Delay(unsigned int xms);
  4. #ednif

LCD1602.c

  1. #include <REGX52.H>
  2. //引脚配置:
  3. sbit LCD_RS=P2^6;
  4. sbit LCD_RW=P2^5;
  5. sbit LCD_EN=P2^7;
  6. #define LCD_DataPort P0
  7. //函数定义:
  8. /**
  9. * @brief LCD1602延时函数,12MHz调用可延时1ms
  10. * @param 无
  11. * @retval 无
  12. */
  13. void LCD_Delay()
  14. {
  15. unsigned char i, j;
  16. i = 2;
  17. j = 239;
  18. do
  19. {
  20. while (--j);
  21. } while (--i);
  22. }
  23. /**
  24. * @brief LCD1602写命令
  25. * @param Command 要写入的命令
  26. * @retval 无
  27. */
  28. void LCD_WriteCommand(unsigned char Command)
  29. {
  30. LCD_RS=0;
  31. LCD_RW=0;
  32. LCD_DataPort=Command;
  33. LCD_EN=1;
  34. LCD_Delay();
  35. LCD_EN=0;
  36. LCD_Delay();
  37. }
  38. /**
  39. * @brief LCD1602写数据
  40. * @param Data 要写入的数据
  41. * @retval 无
  42. */
  43. void LCD_WriteData(unsigned char Data)
  44. {
  45. LCD_RS=1;
  46. LCD_RW=0;
  47. LCD_DataPort=Data;
  48. LCD_EN=1;
  49. LCD_Delay();
  50. LCD_EN=0;
  51. LCD_Delay();
  52. }
  53. /**
  54. * @brief LCD1602设置光标位置
  55. * @param Line 行位置,范围:1~2
  56. * @param Column 列位置,范围:1~16
  57. * @retval 无
  58. */
  59. void LCD_SetCursor(unsigned char Line,unsigned char Column)
  60. {
  61. if(Line==1)
  62. {
  63. LCD_WriteCommand(0x80|(Column-1));
  64. }
  65. else if(Line==2)
  66. {
  67. LCD_WriteCommand(0x80|(Column-1+0x40));
  68. }
  69. }
  70. /**
  71. * @brief LCD1602初始化函数
  72. * @param 无
  73. * @retval 无
  74. */
  75. void LCD_Init()
  76. {
  77. LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
  78. LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
  79. LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
  80. LCD_WriteCommand(0x01);//光标复位,清屏
  81. }
  82. /**
  83. * @brief 在LCD1602指定位置上显示一个字符
  84. * @param Line 行位置,范围:1~2
  85. * @param Column 列位置,范围:1~16
  86. * @param Char 要显示的字符
  87. * @retval 无
  88. */
  89. void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
  90. {
  91. LCD_SetCursor(Line,Column);
  92. LCD_WriteData(Char);
  93. }
  94. /**
  95. * @brief 在LCD1602指定位置开始显示所给字符串
  96. * @param Line 起始行位置,范围:1~2
  97. * @param Column 起始列位置,范围:1~16
  98. * @param String 要显示的字符串
  99. * @retval 无
  100. */
  101. void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
  102. {
  103. unsigned char i;
  104. LCD_SetCursor(Line,Column);
  105. for(i=0;String[i]!='\0';i++)
  106. {
  107. LCD_WriteData(String[i]);
  108. }
  109. }
  110. /**
  111. * @brief 返回值=X的Y次方
  112. */
  113. int LCD_Pow(int X,int Y)
  114. {
  115. unsigned char i;
  116. int Result=1;
  117. for(i=0;i<Y;i++)
  118. {
  119. Result*=X;
  120. }
  121. return Result;
  122. }
  123. /**
  124. * @brief 在LCD1602指定位置开始显示所给数字
  125. * @param Line 起始行位置,范围:1~2
  126. * @param Column 起始列位置,范围:1~16
  127. * @param Number 要显示的数字,范围:0~65535
  128. * @param Length 要显示数字的长度,范围:1~5
  129. * @retval 无
  130. */
  131. void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
  132. {
  133. unsigned char i;
  134. LCD_SetCursor(Line,Column);
  135. for(i=Length;i>0;i--)
  136. {
  137. LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
  138. }
  139. }
  140. /**
  141. * @brief 在LCD1602指定位置开始以有符号十进制显示所给数字
  142. * @param Line 起始行位置,范围:1~2
  143. * @param Column 起始列位置,范围:1~16
  144. * @param Number 要显示的数字,范围:-32768~32767
  145. * @param Length 要显示数字的长度,范围:1~5
  146. * @retval 无
  147. */
  148. void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
  149. {
  150. unsigned char i;
  151. unsigned int Number1;
  152. LCD_SetCursor(Line,Column);
  153. if(Number>=0)
  154. {
  155. LCD_WriteData('+');
  156. Number1=Number;
  157. }
  158. else
  159. {
  160. LCD_WriteData('-');
  161. Number1=-Number;
  162. }
  163. for(i=Length;i>0;i--)
  164. {
  165. LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
  166. }
  167. }
  168. /**
  169. * @brief 在LCD1602指定位置开始以十六进制显示所给数字
  170. * @param Line 起始行位置,范围:1~2
  171. * @param Column 起始列位置,范围:1~16
  172. * @param Number 要显示的数字,范围:0~0xFFFF
  173. * @param Length 要显示数字的长度,范围:1~4
  174. * @retval 无
  175. */
  176. void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
  177. {
  178. unsigned char i,SingleNumber;
  179. LCD_SetCursor(Line,Column);
  180. for(i=Length;i>0;i--)
  181. {
  182. SingleNumber=Number/LCD_Pow(16,i-1)%16;
  183. if(SingleNumber<10)
  184. {
  185. LCD_WriteData(SingleNumber+'0');
  186. }
  187. else
  188. {
  189. LCD_WriteData(SingleNumber-10+'A');
  190. }
  191. }
  192. }
  193. /**
  194. * @brief 在LCD1602指定位置开始以二进制显示所给数字
  195. * @param Line 起始行位置,范围:1~2
  196. * @param Column 起始列位置,范围:1~16
  197. * @param Number 要显示的数字,范围:0~1111 1111 1111 1111
  198. * @param Length 要显示数字的长度,范围:1~16
  199. * @retval 无
  200. */
  201. void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
  202. {
  203. unsigned char i;
  204. LCD_SetCursor(Line,Column);
  205. for(i=Length;i>0;i--)
  206. {
  207. LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
  208. }
  209. }

LCD1602.h

  1. #ifndef __LCD1602_H__
  2. #define __LCD1602_H__
  3. //用户调用函数:
  4. void LCD_Init();
  5. void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
  6. void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
  7. void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
  8. void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
  9. void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
  10. void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
  11. #endif

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/531284
推荐阅读
相关标签
  

闽ICP备14008679号