打印
[技术问答]

调试程序中对延时时间变长感到疑惑,遂寻找其问题原因...

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


  • 问题补充 : 2019/09/18 15:35

    延时函数跟STC单片机时用的差不多:

    void delay_ms(unsigned int ms)

    {

       unsigned int i;

             do{

                  i = 24000000 / 13000;

                              while(--i)          //14T per loop

                                    {

                                            ;

                                    }

         }while(--ms);

    }

    正常时同STC一样延时时间很准,出现问题时该延时时间整整变为正常值的7倍。比较符合12T单片机和1T单片机的延时函数时间之比,刚好为整数的。新唐的ML51系列是新推出的单片机吧,感觉还是有些莫名其妙的问题,希望新唐赶紧解决。

  • 问题补充 : 2019/09/18 15:45

    引起问题的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;        
    }

  • 问题补充 : 2019/09/18 17:51

    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中断则不会出现上述问题。





满意回答
2019/09/19 14:55

可能是SFRS  page切换的问题。主循环中刚刚切换到page1,立马被中断打断了,中断里切换到page0后没有恢复到page1,就导主循环后的执行的语句就不对了。所以在中断有对SFR操作的内容,都需要在中断里备份SFRS的状态才行。




使用特权

评论回复
沙发
twjiang| | 2021-4-17 06:28 | 只看该作者
如果对 ADC 采样实时性没那么高的话,可改用 关 ADC 中断,使用 poll 方式对 ADC采样

使用特权

评论回复
板凳
piteqiu| | 2021-4-17 12:03 | 只看该作者
我认为这种比较的精准的延时,还是用定时器好,感觉是那个计算的问题导致的。

使用特权

评论回复
地板
jasontu| | 2021-4-20 08:15 | 只看该作者
不懂你的意图,你迈了adc中断,不清adc flag,还是会迈adc 中断,迈而影响後面的代码。
执行时间当然会有问题。

使用特权

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

本版积分规则

1881

主题

6433

帖子

8

粉丝