历史上的今天
返回首页

历史上的今天

今天是:2025年05月16日(星期五)

正在发生

2020年05月16日 | 51单片机实验(一)定时/计数器及其中断

2020-05-16 来源:eefocus

我们这学期开了单片机的课,不知道为什么我们要用汇编语言写程序,感觉汇编程序真的挺难写的,所以把实验记录下来把。


如果没有学过汇编的小伙伴建议先去熟悉一下简单的汇编指令,之前简单的实验我就不记录了,我们从定时计数器实验开始吧。


首先来回顾一下和中断,定时有关的知识

51单片机中断级别


中断源

image.png?imageView2/2/w/550

中断允许寄存器IE

image.png?imageView2/2/w/550

EA---全局中允许位。

EA=1,打开全局中断控制,在此条件下,由各个中断控制位确定相应中断的打开或关闭。

EA=0,关闭全部中断。

-------,无效位。

ET2---定时器/计数器2中断允许位。 EA总中断开关,置1为开;

ET2=1,打开T2中断。 EX0为外部中断0(INT0)开关,……

ET2=0,关闭T2中断。 ET0为定时器/计数器0(T0)开关,…… 

ES---串行口中断允许位。 EX1为外部中断1(INT1)开关,……

ES=1,打开串行口中断。 ET1为定时器/计数器1(T1)开关,……

ES=0,关闭串行口中断。 ES为串行口(TX/RX)中断开关,……

ET1---定时器/计数器1中断允许位。 ET2为定时器/计数器2(T2)开关,……

ET1=1,打开T1中断。

ET1=0,关闭T1中断。

EX1---外部中断1中断允许位。

EX1=1,打开外部中断1中断。

EX1=0,关闭外部中断1中断。

ET0---定时器/计数器0中断允许位。

ET0=1,打开T0中断。

ET0=0,关闭T0中断。

EX0---外部中断0中断允许位。

EX0=1,打开外部中断0中断。

EX0=0,关闭外部中断0中断。


中断优先级寄存器IP

image.png?imageView2/2/w/550

-------,无效位。

PS---串行口中断优先级控制位。

PS=1,串行口中断定义为高优先级中断。

PS=0,串行口中断定义为低优先级中断。

PT1---定时器/计数器1中断优先级控制位。

PT1=1,定时器/计数器1中断定义为高优先级中断。

PT1=0,定时器/计数器1中断定义为低优先级中断。

PX1---外部中断1中断优先级控制位。

PX1=1,外部中断1中断定义为高优先级中断。

PX1=0,外部中断1中断定义为低优先级中断。

PT0---定时器/计数器0中断优先级控制位。

PT0=1,定时器/计数器0中断定义为高优先级中断。

PT0=0,定时器/计数器0中断定义为低优先级中断。

PX0---外部中断0中断优先级控制位。

PX0=1,外部中断0中断定义为高优先级中断。

PX0=0,外部中断0中断定义为低优先级中断。


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

image.png?imageView2/2/w/550

|-----------------定时器1------------------------|--------------------定时器0----------------------|

GATE---门控制位。

GATE=0,定时器/计数器启动与停止仅受TCON寄存器中TRX(X=0,1)来控制。

GATE=1,定时器计数器启动与停止由TCON寄存器中TRX(X=0,1)和外部中断引脚(INT0或INT1)上的电平状态来共同控制。

C/T---定时器和计数器模式选择位。

C/T=1,为计数器模式;C/T=0,为定时器模式。


M1M0---工作模式选择位。

image.png?imageView2/2/w/550

定时器/控制器控制寄存器TCON

image.png?imageView2/2/w/550

TF1---定时器1溢出标志位。

当定时器1记满溢出时,由硬件使TF1置1,并且申请中断。进入中断服务程序后,由硬件自动清0。需要注意的是,如果使用定时器中断,那么该位完全不用人为去操作,但是如果使用软件查询方式的话,当查询到该位置1后,就需要用软件清0。

TR1---定时器1运行控制位。

由软件清0关闭定时器1。当GATE=1,且INIT为高电平时,TR1置1启动定时器1;当GATE=0时,TR1置1启动定时器1。

TF0---定时器0溢出标志,其功能及其操作方法同TF1。

TR0---定时器0运行控制位,其功能及操作方法同TR1。

IE1---外部中断1请求标志。

当IT1=0时,位电平触发方式,每个机器周期的S5P2采样INT1引脚,若NIT1脚为定电平,则置1,否则IE1清0。

当IT1=1时,INT1为跳变沿触发方式,当第一个及其机器周期采样到INIT1为低电平时,则IE1置1。IE1=1,表示外部中断1正向CPU中断申请。当CPU响应中断,转向中断服务程序时,该位由硬件清0。

IT1外部中断1触发方式选择位。

IT1=0,为电平触发方式,引脚INT1上低电平有效。

IT1=1,为跳变沿触发方式,引脚INT1上的电平从高到低的负跳变有效。

IE0---外部中断0请求标志,其功能及操作方法同IE1。

IT0---外部中断0触发方式选择位,其功能及操作方法同IT1。


PS:上面的内容是从别的论坛上复制的,贴在这复习也方面,如果侵权请联系我删除。


实验1 定时器/计数器及中断程序设计

这个实验比较简单,实验的基本连线如下

本次实验的内容是使用程序查询方式来判断定时器有没有溢出,从而控制LED的频闪。


我们使用的51单片机的频率是12MHz,时钟周期就是1/12M s,一个指令周期是12个时钟周期,也就是1us


我们要实验周期为200ms的闪烁,就需要每隔20*5ms就将p0.0为取反一次。


选用工作方式为0,也就是13位的定时器


这就需要计时器的初值=2^13-5ms/1us = 3192 = 0c78H


然后每当计数20次之后就将p0.0取反一次。


下面我们来看代码


ORG 0000H

ljmp Start

 

ORG 0100H

Start:

mov TMOD,#00H   ;计数模式为0,13位计数模式

mov TH0,#0CH ;6C78H 定时器0的高8位

mov TL0,#78H    ;定时器0的低8位

mov R7,#20      ;设置循环20次

setb TR0        ;开定时器/计数器0的中断

首先是start 标记的初始化程序,设置TMOD寄存器,最低两位设置为00,然后将0C78H送入TH0 和 TH1,20送入R7,开中断。


Loop: jbc TF0,T0SVR   ;如果TF0位1就跳转,TF0是定时器0的溢出标志位

sjmp Loop

 

T0SVR: mov TH0,#0CH ;0C78H

mov TL0,#78H

djnz R7,Next

mov R7,#20

cpl P0.0        ;取反p0.0位

Next:sjmp Loop

END

接着就是判断TF0(定时器0的溢出标志位)为1就跳转到TOSVR标记的程序段,重新设置TH0和TL0的值,重新开始计时,如果已经重复过20次了,就继续运行下去,将R7重新赋值为20,并且取反p0.0,否则跳转到Loop语句标号出,继续计时。


完整代码如下


;1:定时/计数器实验,方式0,查询方式编程

;系统时钟12MHz,T0每5ms溢出一次

;20次后取反P0.0

;执行后,与P0.0连接的LED亮0.1s灭0.1s,即以5Hz的频率闪烁

ORG 0000H

ljmp Start

 

ORG 0100H

Start:

mov TMOD,#00H   ;计数模式为0,13位计数模式

mov TH0,#0CH ;6C78H 定时器0的高8位

mov TL0,#78H    ;定时器0的低8位

mov R7,#20      ;设置循环20次

setb TR0        ;开定时器/计数器0的中断

    ;计数,溢出了之后就跳转

Loop: jbc TF0,T0SVR   ;如果TF0位1就跳转,TF0是定时器0的溢出标志位

sjmp Loop

 

T0SVR: mov TH0,#0CH ;0C78H

mov TL0,#78H

djnz R7,Next

mov R7,#20

cpl P0.0        ;取反p0.0位

Next:sjmp Loop

END

这个实验是不是很简单呢?不着急,我们马上进入下一个实验


实验2 使用T1方式完成上述实验

使用中断来控制闪烁频率,实验电路图连线如下

k3接在p2.7  k2 接在p2.6 k1接在p2.5,当开关断开的时候p2口都是高电平,当开关闭合的时候p2口就变成低电平


先来看一下初始化程序


XTH EQU 30H ;存放定时器常数高8位

XTL EQU 31H   ;存放定时器常数低8位

 

ORG 0000H

ljmp Start

 

ORG 001BH ;用的是定时器1,自然是1B

ljmp T1SVR

 

ORG 0100H

Start: mov SP,#5FH ;堆栈区设在未用RAM的高端

mov TMOD,#00010000B ;T/C1,模式1

mov TH1,#0FFH ;FFF0啊,好像是负16,28800赫兹啊,

mov TL1,#0F0H ;对了,这行和上行可以有,也可以没有

clr TR1 ;关闭定时器

mov IE,#10001000B ;设置EA和ET1,好像在ISIS中EA这要接高电平

因为有中断,所以要初始化sp堆栈指针,用来进行中断返回,使用t/c1 T1模式,16位定时器,关闭定时器TR1,开中断。


接着是扫描程序,查询三个按钮的开关情况


ScanKey:

mov A,P2

cpl A ;按下时为0,我们要当1处理,自然要翻转一下

anl A,#11100000B ;只要最高3位,其它位屏蔽

swap A ;这一行和下一行共同作用,将3位按键移到最低3位,然后散转

rr A  ;这一行和下一行可以同时去掉,不影响执行,但是程序上是有意义滴

mov DPTR,#TABKey

jmp @A+DPTR

在软件上模拟的时候,p2口一直是高电平,只有当按键按下去的时候才会变成低电平,然后取反,然后将高三位析取出来,交换到低位最后右移得到散装程序入口地址。


下面是散转程序


TABKey: ajmp NoKey ;跳转表KEY1P、2P、3P分别为按下指定3键后的处理代码,用于产生不同的频率

ajmp Key1P

ajmp Key2P

ajmp NoKey ;这样的是组合键,如果指定另一种频率,则1和2按下时可以起作用

ajmp Key3P

ajmp NoKey

ajmp NoKey

ajmp NoKey

sjmp ScanKey

NoKey: clr TR1 ;所有键都抬起来时执行,停止闪烁!

sjmp ScanKey

 

Key1P: mov XTH,#0FEH ;FE0D= (-500)二进制补码,1KHZ的频率闪烁所需要,这里存的数都是补码

mov XTL,#0DH

setb TR1        ;开定时器1

sjmp ScanKey

 

Key2P: mov XTH,#0FFH ;FF07= (-250)二进制补码,以2KHZ的频率闪烁

mov XTL,#07H

setb TR1

sjmp ScanKey

 

Key3P: mov XTH,#0FFH

mov XTL,#84H ;FF84= (-125)二进制补码,以4KHZ的频率闪烁

setb TR1

sjmp ScanKey

关于散转程序入口地址,我们可以看成k3k2k1组成的3位二进制数(按下的时候为1,没有按下的时候为0),然后就可以计算他们相对于TABKey的偏移地址了。


如果没有按下按钮的话,就关闭TR1中断,停止闪烁,跳回到扫描程序


如果按下了按钮的话,就进入相应的散转程序,设置TH1和TL1的值,我们使用XTH和XTL作为中间变量给TH1和TL1赋值,一开始赋值了30H和31H,也就是说计时器溢出了之后才会重新给TH1和TL1赋值,然后将p2.1位取反。


这里面还涉及到二进制补码的计算,简单说一下负数补码的算法:符号位不变,数值为取反之后加一。比如-500=FE0DH,计算机内存的都是补码


最后就是定时器溢出中断程序


T1SVR: mov TH1,XTH

mov TL1,XTL

cpl P2.1 ;翻转P2.1,每两次一个周期

reti

END

这就是我们刚刚说的包括给TH1和TL1赋值和将p2.1取反的操作


完整程序如下


;2:定时/计数器实验,T1方式1

;系统时钟12MHz,P2.1连接LED,P2.5~P2.7分别连接K1~K3

;用户按下K1~K3,LED以不同频率(1KHz、2KHz、4KHz)闪烁,即定时时间分别为0.5ms,0.25ms,0.125ms

;宏定义常量

XTH EQU 30H ;存放定时器常数高8位

XTL EQU 31H   ;存放定时器常数低8位

 

ORG 0000H

ljmp Start

 

ORG 001BH ;用的是定时器1,自然是1B

ljmp T1SVR

 

ORG 0100H

Start: mov SP,#5FH ;堆栈区设在未用RAM的高端

mov TMOD,#00010000B ;T/C1,模式1

mov TH1,#0FFH ;FFF0啊,好像是负16,28800赫兹啊,

mov TL1,#0F0H ;对了,这行和上行可以有,也可以没有

clr TR1 ;关闭定时器

mov IE,#10001000B ;设置EA和ET1,好像在ISIS中EA这要接高电平

 

ScanKey:

mov A,P2

cpl A ;按下时为0,我们要当1处理,自然要翻转一下

anl A,#11100000B ;只要最高3位,其它位屏蔽

swap A ;这一行和下一行共同作用,将3位按键移到最低3位,然后散转

rr A  ;这一行和下一行可以同时去掉,不影响执行,但是程序上是有意义滴

mov DPTR,#TABKey

jmp @A+DPTR

 

TABKey: ajmp NoKey ;跳转表KEY1P、2P、3P分别为按下指定3键后的处理代码,用于产生不同的频率

ajmp Key1P

ajmp Key2P

ajmp NoKey ;这样的是组合键,如果指定另一种频率,则1和2按下时可以起作用

ajmp Key3P

ajmp NoKey

ajmp NoKey

ajmp NoKey

sjmp ScanKey

NoKey: clr TR1 ;所有键都抬起来时执行,停止闪烁!

sjmp ScanKey

 

Key1P: mov XTH,#0FEH ;FE0D= (-500)二进制补码,1KHZ的频率闪烁所需要,这里存的数都是补码

mov XTL,#0DH

setb TR1        ;开定时器1

sjmp ScanKey

 

Key2P: mov XTH,#0FFH ;FF07= (-250)二进制补码,以2KHZ的频率闪烁

mov XTL,#07H

setb TR1

sjmp ScanKey

 

Key3P: mov XTH,#0FFH

mov XTL,#84H ;FF84= (-125)二进制补码,以4KHZ的频率闪烁

setb TR1

sjmp ScanKey

 

T1SVR: mov TH1,XTH

mov TL1,XTL

cpl P2.1 ;翻转P2.1,每两次一个周期

reti

END

那么到这里,实验2就结束啦


实验3 中断的嵌套

实验3就是在实验2的基础上加上了中断的嵌套,所以我们需要先设置中断优先寄存器IP的初始值,电路图如下

我们开看一下初始化程序


XTH EQU 30H ;存放定时器常数高8位

XTL EQU 31H   ;存放定时器常数低8位

ORG 0000H

ljmp Start

ORG 0003H

ljmp Ex0SVR

ORG 0013H

ljmp Ex1SVR

ORG 001BH

ljmp T1SVR

ORG 0100H

Start: mov SP,#5FH ;堆栈区设在未用RAM的高端

mov TMOD,#00010000B

mov TH1,#0FFH

mov TL1,#0F0H

clr TR1         ;关TR1中断

mov IE,#10001101B

mov IP,#00001000B;设置不同的优先级,观察执行效果

mov P2,#0FFH

mov P3,#0FFH

设置sp堆栈指针(有中断的程序不要忘了设置sp的初始值),设置T/C1的T1模式(16位定时器),关TR1中断


设置IE中 EA =1 (总的中断允许控制位)  ES=1(串行口中断允许控制位)  ET1 = 1(定时器1) ET0 = 1(定时器0)


设置IP中的 PT1 = 1,即定时器1的优先级高


这里顺便附上中断入口地址的地址


外部中断0:入口:0003H


定时器0: 入口:000BH


外中断1: 入口:0013H


定时器1: 入口:001BH


串口中断:入口:0023H


下面是中断程序和扫描程序


ScanKey:mov A,P2

jb ACC.7,ScanKey

Key2P: mov XTH,#0FEH

mov XTL,#0CH

setb TR1

sjmp ScanKey

Ex0SVR: mov XTH,#0FFH

mov XTL,#06H

setb TR1

reti

Ex1SVR: mov XTH,#0FFH

mov XTL,#83H

setb TR1

reti

 

T1SVR: mov TH1,XTH

mov TL1,XTL

cpl P2.1        ;p2.1口取反

reti

END

从电路图可以看出来,K3是控制ACC.7;K2是中断0,K1是中断1


也就是一开始小灯是不闪的,按下任意一个按钮后,就开中断了,就会不停闪,通过按不同的按钮就可以改变定时器TH1和TL1的值从而控制灯闪烁的频率,还是挺简单的嘛


下面是最后一个实验的完整代码


XTH EQU 30H ;存放定时器常数高8位

XTL EQU 31H   ;存放定时器常数低8位

ORG 0000H

ljmp Start

ORG 0003H

ljmp Ex0SVR

ORG 0013H

ljmp Ex1SVR

ORG 001BH

ljmp T1SVR

ORG 0100H

Start: mov SP,#5FH ;堆栈区设在未用RAM的高端

mov TMOD,#00010000B

mov TH1,#0FFH

mov TL1,#0F0H

clr TR1         ;关TR1中断

mov IE,#10001101B

mov IP,#00001000B;设置不同的优先级,观察执行效果

mov P2,#0FFH

mov P3,#0FFH

ScanKey:mov A,P2

jb ACC.7,ScanKey

Key2P: mov XTH,#0FEH

mov XTL,#0DH        ;1KHZ

setb TR1

sjmp ScanKey

Ex0SVR: mov XTH,#0FFH

mov XTL,#07H        ;2KHZ

setb TR1

reti

Ex1SVR: mov XTH,#0FFH

mov XTL,#84H        ;4KHZ

setb TR1

reti

 

T1SVR: mov TH1,XTH

mov TL1,XTL

cpl P2.1        ;p2.1口取反

reti

END


那么,这次实验就做完啦

推荐阅读

史海拾趣

德欣(COV)公司的发展小趣事

面对电子行业的快速发展和市场竞争的加剧,德欣公司始终将技术创新作为发展的核心动力。公司不断加大研发投入,引进先进的生产设备和技术人才,加强与高校和科研机构的合作。通过不断的技术创新和产品升级,德欣公司在保持传统产品优势的同时,也成功拓展了新的业务领域,实现了产业升级和可持续发展。

BULGIN公司的发展小趣事

随着技术的不断进步和市场的扩大,BULGIN公司在20世纪60年代成为了当时世界上最大的、产品线最为齐全的电子零件制造商之一。公司保持着快速的创新与发展,BULGIN品牌开始覆盖多国市场,为全球各地的客户提供优质的产品和服务。

CLARE公司的发展小趣事

CLARE公司的创业之路始于对电子行业深厚的技术积累和敏锐的市场洞察力。公司的创始人凭借其深厚的专业知识和经验,准确把握了行业的发展趋势,成功开发了一系列具有竞争力的电子产品。这些产品在市场上获得了良好的反响,为CLARE公司奠定了坚实的技术和市场基础。

Gamma Microelectronics ( APM )公司的发展小趣事

为了进一步满足市场需求,G24i在英国威尔士卡迪夫建成了世界上第一条25MW的大规模生产基于钛衬底的DSSC基地。这一基地的建成标志着G24i在DSSC领域实现了从研发到生产的全链条覆盖。大规模生产不仅降低了产品的制造成本,也提高了生产效率和质量稳定性。G24i通过不断优化生产流程和提升管理水平,确保了产品的市场竞争力。

CIF公司的发展小趣事

A公司是一家专注于电子元器件生产的CIF公司。在成立初期,A公司凭借其创新的研发能力和高效的生产流程,迅速在市场中脱颖而出。通过与全球多家知名电子产品制造商建立稳定的CIF贸易关系,A公司不断扩大生产规模,优化产品质量,逐渐发展成为行业内的领军企业。

FTCAP Fischer & Tausche Capacitor Group公司的发展小趣事

C公司是一家专注于电子产品贸易的CIF公司。为了降低成本、提高效率,C公司积极整合全球供应链资源,与多家优质的电子产品生产商建立了长期合作关系。通过优化采购、生产和物流等环节,C公司成功降低了运营成本,提高了市场竞争力。

问答坊 | AI 解惑

使用RealView MDK进行SW调试和实时跟踪

STM32有两个调试端口,即JTAG和SW。Keil 的ULINK2 USB-JATG接口适配器支持这两种调试接口。 本文描述了如何配置和使用SW接口来获取各种调试信息。 一、目标调试阶段的配置 1. 调试器的选择 选择μVision->Debug ->Options for Target –>D ...…

查看全部问答>

基于89S52的等精度频率计的设计

本人前一段时间制作的等精度频率计,给大家分享下…

查看全部问答>

小弟不才,再来求救~~~关于步进电机的线序

Datasheet上面给出了序列是 :输入信号        输出信号    PA PB    |     B /B  A /A ----------- |---------------    L  H  & ...…

查看全部问答>

【诚聘】Digital IC Verification Engineer

美资公司 LSI 上海研发中心高薪诚聘存储通讯领域人才,薪水待遇优厚,部分人员有出国培训机会。(部门内部推荐,成功机会更高)有意者请将中英文简历发送至:asic_tapeout@hotmail.com Digital IC Verification EngineerDESCRIPTION OF DUTIES IN ...…

查看全部问答>

请问一下,如何将数组定义在代码区?

就像51里那样,定义在code区 这样可以减少ram的消耗 请问如何实现呢?…

查看全部问答>

【求助】定时器A的输入信号

我想用捕获模式.书上有这样一句: 定时器A的输入信号,由CCIx1和CCIx0选择,输入信号可以来自外部引脚也可以来自内部信号. 但是看电路,不是都在P1口输入的吗,怎样能做到用内部信号? 是用一个IO口输出信号再连到P1口的1.1 或 1.2或 1.3 吗 ?…

查看全部问答>

【求助】

斑竹和高手们: 救命啊!我的(flash emulation tools)JTAG程序下载的头坏了,不知道怎么修理。现在急用请大家帮帮忙!!!!!!!!…

查看全部问答>

常用二阶IIR滤波系数的计算方法

  IIR滤波器是无限冲击响应滤波器, 其优点:       1. 采用模拟原型滤波的标准设计,容易理解。       2. 可以用低阶设计实现,并且可以高速运行       ...…

查看全部问答>

linux驱动模型简析(转帖)

作者:李强,华清远见嵌入式学院讲师。 本人注:详细请参见《深入理解LINUX内核》第十三章。 kobjec是linux在2.6中新引进的统一的设备管理模型,他的主要目的就是对linux的2.6系统所有的设备进行统一的管理,在以前的内核中并没有独立的数据结构 ...…

查看全部问答>

MSP430上实现的DES加密标准

附件中是TI网站上提供的数据加密标准DES在MSP430上的实现,可以在MSP430上实现DES啦。密钥长度:DES为64位,3DES为192位。…

查看全部问答>