打印
[技术问答]

ML51TC0AE,运行一段自己编的ADC函数后,单片机变成12T运行模式了。延时时间长到7倍

[复制链接]
1411|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xtp1230|  楼主 | 2019-9-18 15:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    调试程序中对延时时间变长感到疑惑,遂寻找其问题原因所在,最后发现问题是在运行了一个自己编的ADC函数后出现的。我把该函数定义放在官方BSP文件中的ADC.C中,并在adc.h中也有声明。并非系统时钟变慢,我特意添加了一段函数测试异常过程中CLKO输出仍为24MHz。又特意编了个while(1)函数测试IO口输出方波频率,改变while(1)函数中内容,正常和异常时IO口输出频率之比不尽相同,有异常是IO口方波频率是正常时的5倍的,有比率是5.5倍的,正符合12T单片机和1T单片机(当然也不是所有指令都是1T)同频处理指令速度之比。请问这个是新唐ML51系列单片机的BUG吗?

使用特权

评论回复
沙发
xtp1230|  楼主 | 2019-9-18 15:41 | 只看该作者
本帖最后由 xtp1230 于 2019-9-18 15:44 编辑

引起问题的ADC函数如下:
float Get_ADCResult(unsigned char channel)                //channel = 0~7,VBG
{
  unsigned int ADC_Result;
        unsigned char ozc;
        u8 n;
        u16        adc_value_all = 0;
        float        adc_avg;

        ADC_Open(ADC_SINGLE,channel);

        for ( ozc=0; ozc<3; ozc++ )                //读取并丢弃前3次ADC结果,以获取准确值
        {
                clr_ADCCON0_ADCF;                   //清零ADC转换完成标志位
                set_ADCCON0_ADCS;                   //开始转换
                while(!(ADCCON0&SET_BIT7));           //等待转换结束
        }

        ADCRH = 0; ADCRL = 0;                      //调试用,验证是否真的进行了ADC转换
        clr_ADCCON0_ADCF;
        set_ADCCON0_ADCS;

        for(n=0;n<1;n++)                //对所测ADC通道电压进行10次采样,计算平均值
        {
                set_PCON_IDLE;                          //为提高ADC准确度,ADC时单片机进入IDLE待机状态
                while(!(ADCCON0&SET_BIT7));
                ADC_Result = (ADCRH<<4) + ADCRL;
                adc_value_all += ADC_Result;        //对进行AD转换,并对转换值进行累加
                ADC_Result = 0;
        }
        adc_avg = adc_value_all/1.0+0.0001; //加上0.0001是为了排除5171/10.0被计算成为517.0999的情况
        return        adc_avg;        
}

使用特权

评论回复
板凳
xtp1230|  楼主 | 2019-9-18 17:50 | 只看该作者
ML51_BSP_Keil_C51文件中的示例文件(StdDriver目录下的)ADC_Simple,将其代码改为如下,便可出现上述问题。
/*---------------------------------------------------------------------------------------------------------*/
/*                                                                                                         */
/* Copyright(c) 2019 Nuvoton Technology Corp. All rights reserved.                                         */
/*                                                                                                         */
/*---------------------------------------------------------------------------------------------------------*/

//***********************************************************************************************************
//  Website: http://www.nuvoton.com
//  E-Mail : MicroC-8bit@nuvoton.com
//***********************************************************************************************************

//***********************************************************************************************************
//  File Function: ML51 series ADC software trigger on shot demo code
//***********************************************************************************************************
#include "ML51.h"


#define en_MPW_CTR()  P56_PUSHPULL_MODE, SFRS = 0x00,        P5 |= SET_BIT6        //P56脚推挽输出高电平
#define dis_MPW_CTR() P56_PUSHPULL_MODE, SFRS = 0x00,        P5 &= CLR_BIT6        //P56脚推挽输出低电平


void ADC_ISR (void) interrupt 11
{
        ;
//   clr_ADCCON0_ADCF;                //clear ADC interrupt flag
}


void main ()
{
  unsigned int ADCRESULT;

          MFP_P16_UART0_TXD;                //设置P16为串口0输出
          P16_PUSHPULL_MODE;
    UART_Open(24000000,UART0_Timer3,115200);   // Open UART0 use timer1 as baudrate generate and baud rate = 115200
    ENABLE_UART0_PRINTF;
  
                ENABLE_ADC_INTERRUPT;
                ENABLE_GLOBAL_INTERRUPT;

                ADC_Open(ADC_SINGLE,1);                 //Enable ADC_CH4
    ADC_ConvertTime(3,7);
   
                clr_ADCCON0_ADCF;
    set_ADCCON0_ADCS;                       // Software trig adc start
    while((ADCCON0|CLR_BIT7)==CLR_BIT7);    // wait ADCF = 1;
    ADCRESULT = (ADCRH<<4)+ADCRL;
    printf("\n ADC result = 0x%X  ", ADCRESULT);
           Timer0_Delay(24000000,100,1000);
                                            
        while(1)
        {
                en_MPW_CTR();
                dis_MPW_CTR();
        }
               
}

,如果禁止ADC中断则不会出现上述问题。

使用特权

评论回复
地板
tianxj01| | 2019-9-18 18:09 | 只看该作者
xtp1230 发表于 2019-9-18 17:50
ML51_BSP_Keil_C51文件中的示例文件(StdDriver目录下的)ADC_Simple,将其代码改为如下,便可出现上述问题 ...

如果你的源代码就是这样的,那么很明显,你把ADC 中断标志清除语句屏蔽掉了,ADC中断就会占有大量的时间。
不管ADC中断是不是有别的事情要干,一旦打开ADC中断,则必须清除中断标志。

使用特权

评论回复
5
dongnanxibei| | 2019-9-18 20:40 | 只看该作者
我觉得没问题,是楼主代码没有考虑全面。

使用特权

评论回复
6
dongnanxibei| | 2019-9-18 20:40 | 只看该作者
你使用了ADC,又想做其他的,肯定会影响到了,但是你时钟还是那个时钟,所以输出没问题,是你理解错了

使用特权

评论回复
7
zhuotuzi| | 2019-9-18 22:10 | 只看该作者
CLKO输出仍为24MHz,说明没问题啊。

使用特权

评论回复
8
zhuotuzi| | 2019-9-18 22:11 | 只看该作者
你IO方波是用什么代码输出的

使用特权

评论回复
9
zhuotuzi| | 2019-9-18 22:11 | 只看该作者
如果你程序里面翻转的,那要考虑到其他代码是否占用了这个时间。

使用特权

评论回复
10
xtp1230|  楼主 | 2019-9-19 14:38 | 只看该作者
本帖最后由 xtp1230 于 2019-9-19 14:53 编辑

    我是看到手册中提到:Place the device in Idle mode during a conversion.所以在我的ADC函数中有开始ADC后就将单片机转入Idle模式的语句,ADC结束后产生的ADC中断自然唤醒单片机恢复正常模式。
    现在问题得以解决,原因还是以前未处理好ADC中断标志的清零。下面这段程序中运行后方波输出频率633kHz,并且开启ADC中断及中断服务程序。
#include "ML51.h"

#define en_MPW_CTR()  P56_PUSHPULL_MODE, SFRS = 0x00,        P5 |= SET_BIT6        //P56脚推挽输出高电平
#define dis_MPW_CTR() P56_PUSHPULL_MODE, SFRS = 0x00,        P5 &= CLR_BIT6        //P56脚推挽输出低电平

void ADC_ISR (void) interrupt 11
{
}                        

void main ()
{
  unsigned int ADCRESULT;

  MFP_P16_UART0_TXD;                //设置P16为串口0输出
  P16_PUSHPULL_MODE;
  UART_Open(24000000,UART0_Timer3,115200);   
  ENABLE_UART0_PRINTF;

        ENABLE_ADC_INTERRUPT;
        ENABLE_GLOBAL_INTERRUPT;

        ADC_Open(ADC_SINGLE,1);                 //Enable ADC_CH1
        ADC_ConvertTime(3,7);
  
        clr_ADCCON0_ADCF;
        set_ADCCON0_ADCS;                                  // Software trig adc start
        set_PCON_IDLE;
        while((ADCCON0|CLR_BIT7)==CLR_BIT7);    // wait ADCF = 1;
        clr_ADCCON0_ADCF;                                   //clear ADC interrupt flag
        ADCRESULT = (ADCRH<<4)+ADCRL;
                                            
         while(1)
        {
                en_MPW_CTR();
                dis_MPW_CTR();
        }
}

    根据这个例程中的代码的实验,我修改了工作中的程序代码,先前的问题得以解决,单片机运行速度不再像是“12T单片机“了。不过以前不正常时,PWM,串口速率都不受影响,只是处理指令的速度慢了。另外实验中我发现,单片机Idle状态由ADC中断唤醒后不能立即操作特殊功能寄存器,至少是部分特殊功能寄存器不能操作,应该是唤醒后紧跟着执行的是普通语句,定义变量的语句也可以,_nop()_语句不行。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

5

主题

43

帖子

0

粉丝