IAR FOR NEC 定时器间隔不能小于86.4us的分析-------IAR代码优化问题
一.近日在用0537D调试定时器H0的定时间隔功能,间隔时间设为16.25us,在定时器中断处理函数中将P10口的状态反转,实现在P10口输出方波,方波脉宽为16.25us。通过示波器观察P10口波形,发现波形脉宽并不是需要的16.25us,而是86.4us(大概),而且不管将CMP00的值该为多少都是86.4us的脉宽
http://cache.amobbs.com/bbs_upload782111/files_40/ourdev_648595NOATCK.JPG
示波器波形 (原文件名:11.JPG)
只有把定时时间设置大于86.4us才能正常输出,比如设置为100us,示波器能观察到100us脉宽的波形。
IAR程序如下:
#include "io78f0537_64.h"
#include "intrinsics.h"
#pragma location = "OPTBYTE"
__root const unsigned char option_bytes[]={0x7F,0x01,0x00,0x00,0x03}; /*设置选项字节*/
#define PM00 PM0_bit.no0
#define PM01 PM0_bit.no1
#define PM10 PM1_bit.no0
#define IRTXD P1_bit.no0
/*时钟初始化*/
void Clock_inital(void)
{
OSCSEL=0;
MSTOP=1;
RSTOP=0;
MCM=0;
XTSTART=0;
PCC = 0;
LSRSTOP=1;
EXCLK=1;
EXCLKS=0;
OSCSELS=1;
WDTE = 0XAC;
}
/*定时器H0初始化*/
void TMH0_ini(void)
{
TMHMD0 = 0x00;/* 8M*/
CMP00 = 130;/* 13016.25us 38-40k*/
TMMKH0 = 0;/*开中断*/
}
void main(void)
{
__disable_interrupt();
Clock_inital();
PM10 = 0;/*-----P10口输出*/
TMH0_ini();
TMHE0 = 1;/*------开始定时器H0*/
IMS = 0xcc;
IXS = 0x00;
__enable_interrupt();
while(1)
{
WDTE = 0XAC;
}
}
/*-------定时器H0中断处理函数*/
#pragma vector = INTTMH0_vect
__interrupt void MD_INTTMH0(void)
{
TMIFH0 = 0;
IRTXD = ~IRTXD;
WDTE = 0XAC;
}
但是把上面的程序移到PM+里面,定时为16.25us,在示波器里也能正常观察到16.25us脉宽的波形。
http://cache.amobbs.com/bbs_upload782111/files_40/ourdev_648600FXLJ2U.JPG
(原文件名:22.JPG)
PM+程序如下:
#pragma sfr
#pragma DI
#pragma EI
#pragma NOP
#pragma HALT
#pragma STOP
#define IRTXD P1.0
#pragma interrupt INTTMH0 MD_INTTMH0
void Clock_inital(void)
{
OSCSEL=0;
MSTOP=1;
RSTOP=0;
MCM=0;
XTSTART=0;
PCC = 0;
LSRSTOP=1;
EXCLK=1;
EXCLKS=0;
OSCSELS=1;
WDTE = 0XAC;
}
void TMH0_ini(void)
{
TMHMD0 = 0x00;/* 8M*/
CMP00 = 130;/* 13016.25us*/
TMMKH0 = 0;
}
main()
{
DI();
Clock_inital();
PM1.0 = 0;
IMS = 0xcc;
IXS = 0x00;
TMH0_ini();
TMHE0 = 1;
EI();
while(1)
{
WDTE = 0XAC;
}
}
__interrupt void MD_INTTMH0(void)
{
TMIFH0 = 0;
IRTXD = ~IRTXD;
WDTE = 0XAC;
}
Option.asm 文件
OPT CSEG AT 0080H
OPTION: DB 7FH ; Enables watchdog timer operation (illegal access detection operation),
; Window open period of watchdog timer: 50%,
; Overflow time of watchdog timer: 210/fRL,
; Internal low-speed oscillator can be stopped by software.
DB 01H ; 2.7 V POC mode
DB 00H ; Reserved area
DB 00H ; Reserved area
DB 03H ; On-chip debug operation enabled
END
分析:既然程序都是一样的,配置字节也是一样,但是输出波形却不一样,那么应该就是IAR的设置问题。通过查阅资料和咨询高手,推断是IAR效率的问题,既然是效率的问题,那么就有可能跟IAR编译优化有关。打开项目的IAR的优化设置选项如图1:
http://cache.amobbs.com/bbs_upload782111/files_40/ourdev_648602L3B8ZE.JPG
图1 (原文件名:图1.JPG)
项目默认的优化(optimizations)Level项选择的是Low,将low该为Medium,图2
http://cache.amobbs.com/bbs_upload782111/files_40/ourdev_648604H6RZB2.JPG
图2 (原文件名:图2.JPG)
重新编译后运行
在示波器里观察到想要的波形,脉宽16.25us
http://cache.amobbs.com/bbs_upload782111/files_40/ourdev_648605C2QBV2.JPG
(原文件名:22.JPG)
将优化选择为high也能得到正确结果。但是选择为None和low是一样的。
通过上面的实验初步得出结论:IAR优化选项会影响定时器执行效率。但是具体的影响在什么地方却不知道!!!!????./emotion/em003.gif
将上面的结论用到项目里定时器模拟38K红外发送程序里面又出现了新问题:
程序如下:
#include "io78f0537_64.h"
#include "intrinsics.h"
#include "nec78f0xb.h"
#define U1200CR5092 /* UART0 = 1200CR50=92*/
#define U1200CR51208 /* UART0 = 1200CR51=208*/
#define U2400CR5046 /* UART0 = 2400CR50=46*/
#define U2400CR5185 /* UART0 = 2400CR51=104*/
#pragma location = "OPTBYTE"
__root const unsigned char option_bytes[]={0x60,0x01,0x00,0x00,0x03}; //--------设置选项字节
unsigned char count = 0;
unsigned char IRSNEDFLAG;
unsigned char IRREVOKSET;
unsigned char IRHEAD1SET;
unsigned char IRLENTHSET;
typedef structM2A_uart_data
{
unsigned charHead1;
unsigned charLenth;
unsigned charHead2;
unsigned charAfn;
unsigned charData_u;
} _M2A_uart_data;
_M2A_uart_data IRDATA;
void nopn(void)
{
unsigned int i;
for(i=0;i<40000;i++)
{
}
}
//时钟初始化
void Clock_inital(void)
{
EXCLK=1;
OSCSEL=0;
XTSTART=0;
EXCLKS=0;
OSCSELS=1;
PCC = 0;
LSRSTOP=1;
RSTOP=0;
XSEL=0;
MCM0=0;
MSTOP=1;
WDTE = 0XAC;
}
//串口0初始化
void UART0_inital(void)
{
/* |------|------|------|------|------|------|------|------|*
|7 |6 |5 |4 |3 | 2|1 |0 |
BRGC0 |------|------|------|------|------|------|------|------|
|TPS01 |TPS00 | 0|MDL04 |MDL03 |MDL02 |MDL01 |MDL00 |
|------|------|------|------|------|------|------|------|*/
BRGC0 = 0x09;/* fxclk0=TM50k=9*/
/* |------|------|------|------|------|------|------|------|*
|7 |6 |5 |4 |3 | 2|1 |0 |
ASIM0 |------|------|------|------|------|------|------|------|
|POWER0|TXE0|RXE0|PS01|PS00| CL0|SL0 |1 |
|------|------|------|------|------|------|------|------|*/
ASIM0 = 0x05;
POWER0 = 1;
TXE0 = 0;
RXE0 = 1;
PM10 = 0;
IRTXD = 1;
PM11 = 1;
PU11 = 0;
IRRXD = 1;
SRMK0=0;
STMK0=1;
WDTE = 0XAC;
}
//定时器50初始化为UART0的时钟
void TM50_ini(void)
{
P17 = 0;
PM17 = 0;
/* |------|------|------|------|------|------|------|------|*
|7 |6 |5 |4 |3 | 2|1 |0 |
TCL50 |------|------|------|------|------|------|------|------|
| 0|0 |0 | 0| 0|TCL502|TCL501|TCL500|
|------|------|------|------|------|------|------|------|*/
TCL50 = 0x04;/*f=8M/2^2=2M */
CR50 = U2400CR50;/* (1/2M) * 80 = 40usUART0=2400 CR50=46UART0=1200 CR50=92*/
/* |------|------|------|------|------|------|------|------|*
|7 |6 |5 |4 |3 | 2|1 |0 |
TMC50 |------|------|------|------|------|------|------|------|
|TCE50 |TMC506|0 |0 | LVS50|LVR50 |TMC501|TOE50 |
|------|------|------|------|------|------|------|------|*/
TMC50 = 0x8A;
TMMK50 = 1;
WDTE = 0XAC;
}
//定时器51初始化为红外波特率控制定时器
void TM51_ini(void)
{
TCL51 = 0x05;/*f= 8M/64 = 0.25M*/
CR51 = U2400CR51; /* (1/0.25M) *208 = 833us 1s/1200=833us,1/2400 = 416us CR51 = 104 */
TMC51 = 0x0A;
TMMK51 = 0;
TMPR51 = 0;
}
//定时器H0初始化为38K载波输出
void TMH0_ini(void)
{
TMHMD0 = 0x00;/* 8M*/
CMP00 = 130;/* 130 38-40k*/
TMMKH0 = 0;
TMPRH0 = 1;
}
//红外数据模拟发送函数
void Irsend(unsigned char sdata)
{
unsigned char senddata,i;
senddata = sdata;
IRSNEDFLAG = 0;
/*IRTXD = ~IRTXD;*/
TCE51 = 1;
TMHE0 = 1;
do{}while( 0 == IRSNEDFLAG);
for(i=0;i<8;i++)
{
if(senddata-(senddata/2)*2)
{
IRSNEDFLAG = 0;
IRTXD = 0;
TCE51 = 1;
do{}while( 0 == IRSNEDFLAG);
}
else
{
IRSNEDFLAG = 0;
IRTXD = ~IRTXD;
TMHE0 = 1;
TCE51 = 1;
do{}while( 0 == IRSNEDFLAG);
}
senddata = senddata >> 1;
}
IRSNEDFLAG = 0;
IRTXD = 0;
TCE51 = 1;
do{}while( 0 == IRSNEDFLAG);
IRSNEDFLAG = 0;
}
void main(void)
{
DI();
Clock_inital();
UART0_inital();
IMS = 0xcc;
IXS = 0x00;
TM50_ini();
TM51_ini();
TMH0_ini();
EI();
Irsend(0X12);
nopn();
Irsend(0X34);
nopn();
Irsend(0X56);
nopn();
Irsend(0X78);
nopn();
Irsend(0X9A);
nopn();
Irsend(0XBC);
nopn();
while(1)
{
Irsend(0X78);
/*moni_uart(0x68);*/
/*TXS0 = 0X56;*/
/*nopn();*/
}
}
//-----定时器51中断处理,间隔时间为波特率时间
#pragma vector = INTTM51_vect
__interrupt void MD_INTTM51(void)
{
TMIF51 = 0;
TMHE0 = 0;
TCE51 = 0;
IRSNEDFLAG = 1;
WDTE = 0XAC;
}
//----定时器H0中断处理函数,间隔时间为(1/38k)/2
#pragma vector = INTTMH0_vect
__interrupt void MD_INTTMH0(void)
{
TMIFH0 = 0;
IRTXD = ~IRTXD;
WDTE = 0XAC;
}
#pragma vector = INTSR0_vect
__interrupt void JS_INTSR0(void)
{
unsigned char rdata0;
unsigned char cwzt;
cwzt = ASIS0;
if(0x00 != cwzt)
{
return;
}
rdata0 = RXB0;
SRIF6 = 0;
IRDATA.Data_u = rdata0;
count ++;/*overtime control*/
if(count >= 200)
{
count = 0;
}
}
当把工程的优化设置为图3所示的medium时
http://cache.amobbs.com/bbs_upload782111/files_40/ourdev_648606RSSSU0.JPG
图3 (原文件名:图3.JPG)
用示波器观察P10口却没有观察到波形,查看汇编程序
http://cache.amobbs.com/bbs_upload782111/files_40/ourdev_648607NUVM0C.JPG
图4 (原文件名:图4.JPG)
发现优化后的程序在do()while()语句处成了死循环,所以后面的程序都执行不了。
怎么办,让这个函数不优化,查看#pragma optimize的用法:
http://cache.amobbs.com/bbs_upload782111/files_40/ourdev_648608MJRV3E.JPG
(原文件名:tt7.JPG)
描述:使用pragma optimize 指令可以减小优化等级或者关掉一些优化选项,这个指令只影响紧跟在其后的函数。这个指令的参数只能为比项目优化等级低的参数,比如项目优化选择为low,那么就不能用#pragma optimize = medium来定义函数,如果定义了会被编译器忽略。
所以我在Irsend函数前面加上
#pragma optimize = none
让这个函数不优化:
//红外数据模拟发送函数
//#pragma optimize = none
void Irsend(unsigned char sdata)
然后编译运行,在P10口观察到了发送的调制好的红外信号。
二
关于避免程序优化后不能执行还有其他方法:
1. volatile 的使用
比如有事用for循环写延时函数
for(i=0i<100;i++);
上面的语句可以用来延时,但是如果选择(high)高优化,那么上面的语句就会被优化掉
http://cache.amobbs.com/bbs_upload782111/files_40/ourdev_648609IY9DOK.JPG
(原文件名:图6.JPG)
整个delay函数被优化成了一条RET语句。
当使用volatile 定义后
http://cache.amobbs.com/bbs_upload782111/files_40/ourdev_648610JCPU1R.JPG
(原文件名:图7.JPG)
Delay函数并没有被优化。
关于其他避免程序被优化掉的方法希望大家能够给点意见!!!./emotion/em003.gif LZ真仔细,赞~~~ {:smile:}
LZ真仔细,赞~~~ 学习了,谢谢分享
页:
[1]