菜鸟学PIC单片机(三)

发布者:beta12最新更新时间:2017-12-07 来源: eefocus关键字:菜鸟  PIC单片机 手机看文章 扫描二维码
随时随地手机看文章

菜鸟学PIC 单片机 (三)LCD时钟的总结,并由中断暂禁的后果说开去

 上回说到刚接触PIC没20天的菜鸟碧水长天准备"野心勃勃"写一段LCD显示精确时钟的但遭到无情狙击的故事,幸好得到这里行家的点拨,方能理清一点头绪,于是,今天就接着上回的故事,总结一些通用的注意事项,并对LCD显示精确时钟进行功能实现上的分析.

  

一、先总结一些细节的问题,再分析功能实现上的缺陷:


1. 关于中断现场的保护和恢复的问题
  由于movf指令可以影响STATUS,而W又要在现场保护过程中起中转寄存器的作用,因此,应先保护W,再保护STATUS,最后是保存其他现场变

量。保存的时候应注意,如果W的备份寄存器w_temp若不是位于快速存取区70H~7FH,假如w_temp定位为0x20,那么还需保证bank1,bank2,

bank3中的0xA0,0x120,0x1A0出的单元没有被派做他用。如果fsr_temp,pclath_temp等也不是定义在快速存取区的话,那么,需注意在备份FSR

,PCLATH之前,要确保当前操作在bank0处(当然,在其他bank也可,但必须注意在恢复现场的时候,也要保证在相同的bank中对备份积存器进

行操作,为了方便起见,建议控制在bank0处进行保存和恢复操作)。
   至于,备份寄存器若定位与快取区中,那么对bank没有要求,但对次序的要求仍然存在的。
  
  这是经过改进后的恢复和保存现场代码:
ORG     0x000                  ; processor reset vector
    nop                      ; ICD need
     goto    main              ; go to beginning of program

    ORG     0x004             ; interrupt vector LOCation
    movwf   w_temp            ; 先保存W
    movfw    STATUS            ; 再保存STATUS到W中
    clrf     STATUS          ; 注意该指令,确保对status_temp,pclath_temp的操作在bank0中
                      ; (如果备份寄存器定义在快取区中,可无取消此条clrf及恢复现场那条clrf指令)
    movwf    status_temp       ; 保存上上条指令备份在W中的STATUS
    movfw    PCLATH          ; 备份PCLATH
    movwf    pclath_temp
    movfw    FSR          ; 备份FSR
    movwf    fsr_temp      
    ; 可添加其他欲保护的变量

;******************** 中断服务代码
    btfss    INTCON,T0IE      ; 判断是否为T0中断
    goto    other_int
    btfss    INTCON,T0IF      ; it 's the time of T0 int
    goto    other_int
    bcf    INTCON,T0IF      ; 是T0中断,清除中断标志
    movlw    0x10          ; 微秒的高位字节加上定时时间 256x16分频=4096=0x1000的高位(0x10)
    addwf    us+1
    goto    end_int          
other_int              ; 可添加其他中断服务代码
    nop              ; other isr code CAN be added
;**********************************
end_int                  ; 恢复现场
    clrf    STATUS          ; 确保恢复现场的操作在bank0中(如果备份寄存器定义在快取区中,可无取消此条指令)
    ; 可添加恢复其他变量
    movfw    fsr_temp      ; 恢复FSR
    movwf    FSR
    movfw    pclath_temp      ; 恢复PCLATH(FSR和PCLATH的恢复无先后之分)
    movwf    PCLATH
    movfw   status_temp       ; 先恢复STATUS
    movwf    STATUS            ; 
    swapf   w_temp,f
    swapf   w_temp,w          ; 最后恢复W,采用swapf是因为其不会影响STATUS
    retfie                    ; 中断返回

;*********


2.(保留区域,待添加)

--------------------------------------------

二、分析功能实现上的缺陷,并由中断响应及子程序暂禁中断所引起的问题说开去

  先将昨天贴的源程序的main部分的代码拿出来分析:
  主程序要实现的功能是显示时钟:   
                  HH MM SS
                  00:00:00
  定时中断每次产生4096us的增量,在中断服务中,将此时间增量累加在(us+1:us)两个相邻的字节中,由_clock子程序
对(us+1:us)进行及时判断,超出50ms即取走一个50ms的增量,并保留余量在(us+1:us)中以保证长时间定时精确.

主程序流程:

main
    nop
    call    _init         ; 调用初始化子程序,清缓冲区,实现液晶显示器和TMR0的初始化操作.
    call    _disp1        ; 调用显示字符"    HH MM SS    "的子程序
loop   
    call    _clock        ; 调用时间更新子程序,更新定时中断产生的时间累加值
    call    _convert      ; 调用时钟的小时,分,秒的BCD码转换子程序,并换成字符对应的ASCII码
    call    _disp2        ; 调用转换后的小时:分:秒字符的显示子程序
    goto    loop      ; 执行主循环

分析如下:
   由于_clcok和_convert码制字符转换子程序与时间显示_disp2子程序是前后的顺序关系的,在时间显示时,前两个子程序是不工作的,由于

LCM的慢显特性,使得该子程序执行时间较长,这样,即使中断定时时间已经累计到应改变显示结果的条件,但此刻_disp2若仍在显示上一时间

,使得_clcok不能及时更新时间,并且_convert不能转换代码,那么显示结果仍然没有变化。当loop循环执行一次完毕之后,_clock和_convert才开始更新.
   但是这里可能会有个疑问:既然如此,计算_disp2的执行时间大概为500ms,当_disp2子程序执行完毕之后,那么也开始循环执行_clock和

_convert,然后LCM再显示,此刻应该显示的是更新的时间了吧,总时间也大概为1s多一点,为何执行结果大概等到1分钟左右,秒区数字才加1呢?   
   问题提得很好。

   思考原因可能为 :由于_clock不能及时更新时间,及不能及时取走(us+1:us)中大于50ms时的50ms量,但中断服务代码中始终严格执行下面两

条指令:
    movlw    0x10          ; 256x16分频=4096=0x1000的高位(0x10)
    addwf    us+1          ; 微秒的高位字节加上定时时间 
多次累加后(15次累加令us+1单元的内容为从00H到F0H)令us+1单元溢出,丢失定时的时间增量,若当_clock更新时,(us+1:us)发生溢出使得其

值小于50ms(代数值50000),因此也不能使得变量ms50的值增加,那么秒钟变量sec也不会变化,转换后时间显示仍然保持不变.
  注意: 当_clock更新时间时,(us+1:us)若满足大于50 000的条件,则ms50变量加一,在main主程序中_clock循环更新时,若捕捉到20次

(us+1:us)单元大于50000(50ms)时,sec的值才能加1。而这个在多次更新过程中捕捉该条件的周期,就是秒区显示加1的周期,我认为这个周

期是固定的,也许是30秒,也许是1分钟,也许更长,只要程序长度和结构没有发生变化。后来在程序中,我增加延时子程序的时间,结果秒区数字加1的间隔时间也跟着延长了。

   到了这里,知道了问题所在,那么在基于原程序的框架下,我对几种解决方案都尝试了一下:

方案1:
     [既然症结是在_clock不能真实捕捉到每一次中断时间累加增量(us+1:us)值大于50ms(50000)的条件,那么,将_clock内嵌中断中去,中

断每一次改变us+1的值然后马上进行时间更新,这样,使得_clock能真实捕捉每一次(us+1:us)值大于50ms(50000)的条件,也能真实更新系统时

间。]

  方案1分析:这样确实可以保证每一次都可以捕捉us时间增量,不考虑运行的结果问题,该方案有几个缺点:

  1) 中断服务代码由于调用了_clock子程序,显得异常臃肿;
  2) 每次中断(4096us)都调用_clock,判断其是否到50ms(值为50000),增加了程序的开销,效率较低;
  3) 由于LCM慢显示特性的原因,可能使得结果仍然不能令人满意:

  关于3) 我描述一下一下:虽然此刻,秒区的数字能基本上每秒钟跳变一次了,但是调试过程中出现了一个问题: 秒区数字跳变有时会忽略下

一个值,而跳到下下一个值去,比如,当前显示12,然后马上显示14。

  那么问题出在什么地方呢? 试想,若_convert在进行格式转换时,发生中断,且更改了sec变量,那么,_convert会按新的值进行转换,这

样,本来这次要转换并送显示的旧值被新值给覆盖了,所以,_disp2在显示的时候,也就根据_convert的转换结果,忠实地显示了一个新值,将

本来应该显示的值给忽略了。

  既然如此,有什么办法来解决呢?两个方法:

  (a)  _convert在对时间变量进行格式转换时,暂时禁止TMR0中断,转换后再开启TMR0中断;
  (b)  将_conver也归并到中断代码中去,规定次序,使得_clock更新时间后,_convert再进行转换,这样,格式转换区的变量不用担心被

_clock修改;
   
   **那么方法(a)会存在什么问题呢?试想:当_convert在转换时,TMR0定时时间到,TMR0向内核提交中断,但由于TMR0中断请求被禁止,即使

_convert转换完毕之后,允许TMR0中断,那么TMR0的中断请求会不会被丢弃呢? 显然,根据PIC的中断系统,当TMR0定时时间到后,首先将

T0IF置1,并由T0IF向内核提出中断请求,如果该中断请求被禁止,那么只要其中断标志T0IF仍然保持为1,当该中断响应解禁之后,内核根据

T0IF立即响应其中断。
   因此,方法(a)中"TMR0的中断请求可能会被遗弃的担心"是多余的.

   并且,由于_convert的执行时间少于一个中断周期,所以它对中断的暂禁操作不会出现在一个暂禁中断的过程中,中断标志T0IF的多次被置一

的现象,所以不会发生中断响应被冲掉的不良后果。同样,_clock子程序在没有加载到中断服务代码中去时,其对TMR0的暂禁影响与_convert分

析的结果相同.

   那么,既然如此,我认为这样的话,由于_disp2的执行时间也不会超过1秒,因此,不会出现当秒跳变时,_convert来不及转换而丢弃上一次待

转换的字符。所以,结果应该是正常.
   于是按照这种方法修改程序,结果发现秒区每次都跳变,最小增量为2,最多为为3(跳变周期大约1.2秒)。于是将延迟子程序的外循环值由

64H-〉40H(大概右25ms变成16ms),结果仍然如此,秒区每次都跳变,只是跳变节奏比未修改延时子程序前变快很多(跳变周期大约0.6s),但最

小跳变增量1,最多为2。

    [正在分析其根源,也请有兴趣的兄弟一起思考一下.....]


   那么那试试方法(b).我按方法(b)修改了程序,结果发现,仍然出现秒区数字跳变的情况。

    究其原因,跟3)类似:当_disp2运行的时候,准备从显示缓冲区取字符来显示,如果发生中断,_clock,_convert更改了显示缓冲区的内容

,使得本来即将待显示的内容被替换成下一次显示的内容。所以,该方法依然存在,而且,由于_disp执行时间大于一次中断的255us,如果在

_disp执行过程暂禁TMR0中断将会丢弃中断请求(即:TMR0的中断请求被自己下一次中断请求覆盖,上一次中断请求被忽略,显示时间将变慢)。



----------------------------------------------------------------

方案2:

   [中断服务仍然只改变us+1的值,但是格式转换及显示功能内嵌到_clock子程序中去,主程序执行_clock循环。]
  
   下午我按这种方式更改了程序,在软件模拟时发现程序跑飞。原因是:内嵌了这些功能之后,代码由400行变成500多行,在_disp1查表显示

字符时,_table已经超过PCL的256字ROM空间,而查表时未注意PCLATH内容,以致跑飞。解决此问题后,下载到ICD中运行,发现结果倒是正常

了,但是感觉时间好像有一点点慢。
   呵呵,细心的站友想必已经看出来了,由于加了显示功能的_clock子程序中依然是暂时禁止TMR0中断的,虽然该时间显示功能只是在时间跳

变时刷新LCD屏幕,但是正是由于在时间跳变时执行时间刷新的周期过长(大于4096us),TMR0 的多次中断请求最后只被响应一次,即T0IF多次

被置1后,却只能在_clock子程序末对TMR0解禁时得到一次中断响应,未被响应的累积时间被丢弃了,没有加到(us+1:us)中去,引起时钟显示变

慢了.


方案3:

由于前两个方案均存在不近人意的问题,难道在用TMR0做秒表时,且当"定时中断的周期小于LCD慢显器件的驱动刷新周期的情况下",就没有一个

完美的解决方案么?
  留在这里和有兴趣的站友一起思考...


关键字:菜鸟  PIC单片机 引用地址:菜鸟学PIC单片机(三)

上一篇:菜鸟学PIC单片机(一)
下一篇:PIC16F877单片机内部EEPROM读写实例

推荐阅读最新更新时间:2024-03-16 15:48

PIC单片机精通_异步串口通讯实例与细节
1.前言 PIC16F876a异步串口通信的定义以及寄存器控制,这里不再多谈,前面已经进行过详细的分析。这里注意集中在几个关键点上。 串口中断服务程序应该注意什么? 利用串口助手进行调试应该注意什么? 串口助手接收不到数据的几种可能因素? 2.实例分析 PIC单片机与上位机握手程序如下: /********************************************************/ /*Author: Chunxu Shen; All Rights Reserved! /*Tsinghua University 2016-11-19 /*Serial Test Low Spee
[单片机]
PIC单片机-PICC介绍
目录: 一、如何从汇编转向PICC 二、浅谈PICC 的位操作 三、PICC 之延时函数和循环体优化 五、在PICC 中使用常数指针 六、PICC 关于unsigned 和 signed 的几个关键问题 七、用PICC 写高效的位移操作 八、C 程序优化 九、关于PIC的C语言中嵌入汇编语言 十、PICC中实现C语言与汇编语言混合编程 ---------------------------------------------------------------------------------------------------------------- 一、如何从汇编转向PICC
[单片机]
PIC单片机实现RS232串口异步通讯的设计
编写程序实现以下功能。在计算机上使用串口大师向开发板发每次发送1个字符。开发板每接收到一个数据,则交换该数据的高低4位,再发送回计算机。 端口初始化时使能发送与接收,使用扫描方式接收数据,接收到数据后立即交换高低四位并发送,交换高低四位方式如下: 完整程序: * 标 题: 异步串口通讯 * 功能描述: 在计算机上使用串口大师向开发板发每次发送1个字符。 * 开发板每接收到一个数据,则交换该数据的高低4位,再发送回计算机。 #include #define uint8 unsigned char #define uint16 unsigned int __CONFIG(FOSC_HS &WDTE_OFF &BOREN_OFF
[单片机]
<font color='red'>PIC单片机</font>实现RS232串口异步通讯的设计
PIC单片机驱动LCD12864液晶显示闪动字体程序
/********************************************************************** *** 功能:12864LCD显示 显示闪动字体,各位同学可以自己修改。 *** 实验内容:0x81 0x90 0x88 0x98 分别是LCD四行的行首地址,我们操作LCD现实的字符就是分别放在这里面的 *** 开发板连接方法: 接上有字库LCD12864 注意调节对比度,LCD12864工作电流较大,请用外接电源供电。 *************************************************************************************
[单片机]
基于PICFxx单片机控制的正弦波逆变电源
   0 引言   逆变电源是一种采用电力电子技术进行电能变换的装置。随着电力电子技术的发展,逆变电源的应用越来越广泛,但应用系统对逆变电源的输出电压波形特性也随之提出了越来越高的要求,因为电源的输出波形质量直接关系到整个系统的安全和可靠性指标。   随着数字信号处理技术的发展,以SPWM控制方式设计的逆变电源越来越受到青睐。本文介绍的SPWM逆变电源就是采用PIC单片机来实现SPWM控制和正弦波方式输出,而且电路简单,性能安全可靠,灵活性强,同时可以降低谐波,提高效率。    1 SPWM逆变器结构   逆变电源的拓扑结构有多种形式,图l所示是SPWM逆变电源的基本结构,它主要由变压器中心抽头推挽式升压电路、逆变电路、滤
[电源管理]
PIC单片机抗静电处理解决方案
PIC单片机有计算功能和记忆内存像CPU并由软件控制运行。然而,处理能力—般,存储器容量也很有限,这取决于PIC的类型。但是它们的最高操作频率大约都在20MHz左右,存储器容量用做写程序的大约1K—4K字节。 1:MCLR上拉10k、串联一个1k电阻,0.1uf电容到地。 2:MCLR上拉1k、串联一个200电阻,0.1uf电容到地。 3:MCLR上拉1k、0.1uf电容到地。 4:MCLR上拉4.7k、串联一个1k电阻,0.1uf电容到地。 5:禁止MCLR,MCLR脚下拉一个1k电阻到地,电阻并一0.1uf电容。
[单片机]
<font color='red'>PIC单片机</font>抗静电处理解决方案
PIC单片机 设定配置字信息
;******************************************************************* ; SAMPLE.ASM ; 8x8 Software Multiplier for 16Cxxx Family ;******************************************************************* ; ; The 16 bit result is stored in 2 bytes ; ; Before calling the subroutine mpy , the multiplier shoul
[单片机]
基于PIC单片机的RS-232转CAN通信适配卡设计
  CAN总线-控制器局部网(CAN)国际标准(ISO11898)。CAN总线与一般的通信总线相比,它的数据通信具有突出的可靠性、实时性和灵活性。   其特点可概括如下:CAN为多主方式工作。在报文标识符上,各节点分成不同的优先级。采用非破坏总线仲裁技术。只需通过对报文的标识符滤波即可实现点对点、一点对多点方式传送接收数据。直接通信距离最远可达零10km(速率5kbps以下);通信速率最高可达到1Mbps(此时通讯距离最长为40m)。CAN上的节点数主要取决于总线驱动电路,目前可达110个。报文采用短帧结构,传输时间短,受到干扰的概率低。每帧信息都有CRC校验及其他检错措施,具有极好的检错效果。通信介质可为双绞线、同轴电缆或光纤
[单片机]
基于<font color='red'>PIC单片机</font>的RS-232转CAN通信适配卡设计
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved