//实例13:用P0口显示逻辑"与"运算结果
#include //包含单片机寄存器的头文件
void main(void)
{
P0=(4>0)&&(9>0xab);//将逻辑运算结果送P0口
while(1)
; //设置无限循环,防止程序“跑飞”
}
请问大侠们最后的无限循环是如何防止程序跑飞的?
瑞萨公司推出的R8C/1B单片机采用改进的Flash存储器工艺,大大缩短了编程/擦除挂起的时间,使其能够更加及时地响应中断或进行其他操作。
Flash编程/擦除挂起功能
所谓挂起功能,是指当Flash模块正在执行编程或擦除操作时,CPU改写模式可以暂停当前的Flash操作,将编程或擦除挂起的功能。在编程/擦除挂起的过程中,用户ROM区的内容可通过程序来读取。
瑞萨R8C/Tiny单片机在R8C/18以后的产品中(如R8C/1B),较之以前的产品(如R8C/15),Flash存储器在编程/擦除挂起功能上有了很大改进,其具体功能的比较请参见表1,编程/擦除挂起操作时序请参见图1。
由表1可以看出,R8C/1B单片机所采用的Flash模块工艺在以下方面拥有明显的优势。
挂起时间延迟最长为97μs+6个CPU时钟周期,最长的挂起重新启动时间延迟为3μs+4个CPU时钟周期;R8C/15单片机Flash模块只能在擦除时挂起,但改进Flash工艺的R8C/1B单片机在编程时也可以实现挂起功能;擦除时可以编程。
图1为编程/擦除挂起的简单示意图,在编程/擦除开始之后,如果发生了某个中断请求,在等待一段挂起延迟之后,CPU转向中断子程序的处理。中断处理子程序执行之后,Flash存储器继续执行编程或擦除过程,直至操作结束。
Flash编程/擦除挂起功能的实现
● EW0模式与EW1模式
CPU改写模式是通过固化在单片机程序存储器中的软件命令对Flash存储器进行编程的形式,适合对单片机进行在应用中编程(IAP)的场合,即能够在不使用Flash编程器,且将单片机安装在电路板的状态下实现对Flash的改写。
CPU改写模式分为擦除/编程0模式(EW0模式)和擦除/编程1模式(EW1模式)。
这两种模式的根本区别在于改写控制程序的执行区域不同。如图2所示,EW0模式中,改写控制程序在Flash存储器以外的区域执行,因此在这种模式下可以改写所有的用户ROM区。EW1模式中,改写控制程序依然存放在用户ROM区的某一个块中,并在此区域执行,因此在这种模式下,除了存有改写控制程序的块以外,其他的用户ROM区都可以被改写。
在执行擦除/编程的过程中,在EW0模式下CPU处于正常运行的状态,而在EW1模式下CPU处于保持状态。
● Flash编程/擦除挂起的设定
相关的寄存器
与Flash编程/擦除挂起相关的寄存器是闪存控制寄存器4(FMR4),FMR4有6个位均与编程/擦除挂起功能相关,请参见表2。
EW0模式的擦除挂起设定
对于EW0模式转移到擦除挂起时,首先需要将FMR40位置“1”(允许挂起)、FMR41位置“1”(请求擦除挂起),然后延迟一段时间(97μs+CPU时钟周期×6),在确认FMR46位为“1”(允许读)后才能对用户ROM区进行存取。如果将FMR41位置“0”(重新启动擦除),就重新开始自动擦除。设定过程如图3所示。注意,在EW0模式,请将所使用中断的中断向量表和中断程序存储在RAM区中。
EW1模式的擦除挂起设定
对于EW1模式,首先需要将擦除挂起功能设定为有效,即将FMR40位置“1”(允许挂起),并预先将需要响应的可屏蔽中断设定为中断允许状态。这样在执行块擦除命令后,如果该中断产生,经过一段时间延迟后(电气特性推荐值为:97μs+CPU时钟周期×6),就能执行擦除挂起,并接受中断请求。如果发生中断请求,FMR41位就自动变为“1”,执行擦除挂起。在结束中断处理后,如果自动擦除还没有结束(FMR00位为“0”),就必须将FMR41位置“0”,重新开始自动擦除。设定过程如图4所示。
在EW1模式下执行擦除指令进行Flash擦除时(典型值为200ms/1K字节块),CPU虽处于HOLD状态,但可以接受中断响应,实现分时擦除。利用这个工作原理,下面给出一个R8C/1B单片机的应用实例,利用Timer(定时器)中断和Flash擦除挂起功能实现对擦除时间的估算。
使用TimerX定时1ms,Flash擦除过程中每1ms挂起一次,进入中断处理程序并调整计时变量g_Timers。在擦除结束后,g_Timers所存储的就是擦除时间的估算值。
例程如下。
#include "sfr_r81b.h"
unsigned int g_Timers;//总擦除时间计数变量
#pragma interrupt timerX_ISR
void timerX_ISR(){
g_Timers++;
}
/* 检查Data Flash状态寄存器 */
unsigned char checkStatusRegister(){
return fmr07|fmr06;
}
/* 清除DataFlash状态寄存器 */
void clearStatusRegister(){
*((unsigned char *)0x2400) = 0x50;//执行清除状态寄存器软件命令
}
/* 块擦除 */
unsigned char eraseBlock(unsigned int adr){
unsigned char result="1";
asm("FCLR I");//关中断
fmr01 = 0;
fmr01 = 1;//进入CPU改写模式
fmr11 = 0;
fmr11 = 1;//设置为EW1模式&nb
sp;
fmr40 = 0;
fmr40 = 1;//允许中断擦除挂起
asm("FSET I");//开中断
g_Timers = 0;//计数值清零
prex=0x32-1;tx=0x32-1;//定时值1ms
txs=1;//定时器X开始计数
*((unsigned char *)adr) = 0x20;//执行块擦除软件命令
*((unsigned char *)adr) = 0xD0;
while(fmr00 != 1){//判断擦除是否结束
fmr41 = 0;//中断返回后继续擦除
}
txs=0;//定时器X停止计数
fmr01 = 0;//退出CPU改写模式
if(!checkStatusRegister()){//查看状态寄存器
result = 0;//擦除成功
}
else //擦除失败
clearStatusRegister();//清除状态寄存器
return result;
}
/* 对MCU进行初始化 */
void initMCU(){
unsigned char i="0";
asm("FCLR I");//关中断
//将CPU时钟切换为主时钟20MHz
prcr = 1;//解除对cm0,cm1,ocd寄存器的写保护
cm13 = 1;//接通 Xin-Xout
cm15 = 1;//Xin-Xout驱动能力:高
cm05 = 0;//Xin-Xout启动
cm16 = 0;//无分频模式
cm17 = 0;
cm06 = 0;//使CM16,CM17有效
while(1){//等待主时钟振荡稳定
if(!ocd3){
if(i>=10) break;
else ++i;
}
}
ocd2 = 0;//选择主时钟
prcr = 0;//设定对cm0,cm1,ocd寄存器的写保护
//设置定时器
txmr=0x00;//定时器X设为定时器模式
tcss=0x11;//选择计数源为f8
txic=0x07;//定时器X中断优先级为7
asm("FSET I");//开中断
}
/* 主函数 */
void main(void)
{
unsigned char flag;
initMCU();//对MCU进行初始化
flag = eraseBlock(0x2400);//擦除大小为1kB的块A,块首地址为2400H
while (1);
}