搜索
bottom↓
回复: 4

IAR FOR NEC 定时器间隔不能小于86.4us的分析-------IAR代码优化问题

[复制链接]

出0入0汤圆

发表于 2011-6-14 17:03:46 | 显示全部楼层 |阅读模式
一.
近日在用0537D调试定时器H0的定时间隔功能,间隔时间设为16.25us,在定时器中断处理函数中将P10口的状态反转,实现在P10口输出方波,方波脉宽为16.25us。通过示波器观察P10口波形,发现波形脉宽并不是需要的16.25us,而是86.4us(大概),而且不管将CMP00的值该为多少都是86.4us的脉宽

示波器波形 (原文件名: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;/* 130  16.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脉宽的波形。

(原文件名: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;/* 130  16.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:

图1 (原文件名:图1.JPG)

项目默认的优化(optimizations)Level项选择的是Low,将low该为Medium,图2

图2 (原文件名:图2.JPG)

重新编译后运行
在示波器里观察到想要的波形,脉宽16.25us

(原文件名:22.JPG)
将优化选择为high也能得到正确结果。但是选择为None和low是一样的。
通过上面的实验初步得出结论:IAR优化选项会影响定时器执行效率。但是具体的影响在什么地方却不知道!!!!????

将上面的结论用到项目里定时器模拟38K红外发送程序里面又出现了新问题:
程序如下:
#include "io78f0537_64.h"
#include "intrinsics.h"
#include "nec78f0xb.h"

#define U1200CR50  92   /* UART0 = 1200  CR50=92*/
#define U1200CR51  208   /* UART0 = 1200  CR51=208*/

#define U2400CR50  46    /* UART0 = 2400  CR50=46*/
#define U2400CR51  85   /* UART0 = 2400  CR51=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 struct  M2A_uart_data
{
    unsigned char  Head1;
    unsigned char  Lenth;
    unsigned char  Head2;
    unsigned char  Afn;
    unsigned char  Data_u[250];
} _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=TM50  k=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 = 40us  UART0=2400 CR50=46  UART0=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[count] = rdata0;
    count ++;/*overtime control*/
    if(count >= 200)
    {
            count = 0;
    }
   
}
当把工程的优化设置为图3所示的medium时

图3 (原文件名:图3.JPG)

用示波器观察P10口却没有观察到波形,查看汇编程序

图4 (原文件名:图4.JPG)
发现优化后的程序在do()while()语句处成了死循环,所以后面的程序都执行不了。
怎么办,让这个函数不优化,查看#pragma optimize的用法:

(原文件名: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)高优化,那么上面的语句就会被优化掉

(原文件名:图6.JPG)
整个delay函数被优化成了一条RET语句。
当使用volatile 定义后

(原文件名:图7.JPG)
Delay函数并没有被优化。

关于其他避免程序被优化掉的方法希望大家能够给点意见!!!

出0入0汤圆

发表于 2011-6-15 14:34:20 | 显示全部楼层
LZ真仔细,赞~~~

出0入0汤圆

发表于 2013-6-17 21:43:21 | 显示全部楼层

LZ真仔细,赞~~~

出0入0汤圆

发表于 2015-7-22 22:34:01 来自手机 | 显示全部楼层
学习了,谢谢分享
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-29 10:38

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表