打印
[MCU]

ABOV_MCU_96F8208S_AD功能及优化心得

[复制链接]
2141|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
rankey|  楼主 | 2018-9-20 10:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
各位兄弟: 大家好!

    鄙人自学ABOV_MCU.最近在弄AD功能,写了一个测试代码.主要是实现12位AD转换,温度值在9摄氏度,开启LED闪烁。其他指示灯熄灭。这个简单的功能。

     这个测试程序,已调试OK 。硬件上功能实现OK。代码里,主要在AD值消抖处理,防止闪烁和待机的来回频繁切换,用了自己的想法,也实现。这点比较欣慰,
      请21IC的大仙们再次指点,斧正~~
   附上代码:
-------------main-------------------
     void main(void)
{
         cli();                  // disable INT. during peripheral setting
         clock_init();           // initialize operation clock
          Wait_uSec(60);  // 60ms System Stabilize Delay
         port_init();            // initialize ports
         Timer_Start();    //定时器初始化及开启       
         sei();                  // enable INT.
          M=0;
          Heat=0;
         com=0x00;
         LED2=0x00;  //运行指示灯
        LED1=0x01;
         NOP;
         NOP;
          NOP;
            
        while(1)
               
        {
                  time_proess ( );    //时间调度处理函数
                  Process_AD();       //AD数据处理函数
            if(temp_now_val<=186&&temp_now_val>=184)   //温度等于9℃,就开启闪烁
                         {
                                   T1_AD_9degree++;
                                     if(T1_AD_9degree==20)
                                                 {
                                                   T1_AD_9degree=10;     //消抖变量T1_AD_9degree,返回初始值10,等待一下一次消抖
                                                         M_T1_startflag=1;    //开启闪烁定时器。定时中断服务实现闪烁
                                                  }
                               
                         }       

      else if(temp_now_val>=190||temp_now_val<=180)  //温度不是9℃,且离9℃有0.5℃温差,则返回待机状态
                        {                                              //避免了温度值在9℃临近时,闪烁与待机来回频繁切换
                                 T1_AD_9degree--;          //消抖
                                 if(T1_AD_9degree==0)
                                {         
                                    T1_AD_9degree=10;
                                       M_T1_startflag=0;      //闪烁的控制变量置0,使得定时中断服务函数里,不再执行闪烁
                                    M=0;                        //马达运行指示灯熄灭
                                    Heat=0;                   //加热指示灯熄灭
                                    com=0x00;             //这是运行指示灯,待机指示的公共地,必须置0
                                    LED2=0x00;         //运行指示灯熄灭
                                    LED1=0x01;      //待机指示灯点亮
                                    NOP;
                
                                     }
                       
                        }       
             else                                    //AD值临近9℃的AD值,处在抖动状态,则消抖值不动作,防止双闪与待机来回频繁切换。
                     {
                        nop;
                       }                       
                }               
}
-------------主要的几个函数体定义部分---------------
//ADC
//input : AN
//output: 12bit ADC value
int Get_ADdata(void)           // 获取AN9通道的12bit数据
{
        uint TempData = 0;              //定义一个12bit的AD值存储变量
        ADCCRL &= 0xf0;                //清通道选择位
        nop;
        nop;
        nop;
        nop;
        ADCCRH = 0x05;                // clock=fx/2,ALIGN为1:AD转换后数据排列为LSB模式 ,ADCRDH[3:0], ADCDRL[7:0])
        ADCCRL = 0x99;               //A/D使能,并选择转换通道 (选择AN9)
//        ADCCRL |= An;               
        nop;
        nop;
        nop;
        nop;
        ADCCRL |= ADST;                //开启ADC 转换
        nop;
        nop;
        nop;
        nop;
                                 //等待转换完成
        while(!(ADCCRL&0x10));  //为真,转换AD完成--此处一定要用按位&运算符,用逻辑&&会出现AD通道错乱现象
       TempData = (((int)ADCDRH)<<8|(int)ADCDRL);       // TempData的高8位获取ADCDRH的低4位数据,再加ADCDRL的8位数据,这样TempData获取完整的12位数据
        nop;
        nop;
        nop;
        ADCCRL &= ~ADST;               //STOP ADC
        nop;
        nop;
        nop;
        return TempData;                //TempData 的值返回给了ADdata()函数
}

---------------AD数据的处理---------------
void Process_AD(void)    //对采集的7个AD数据,进行冒泡,去头,去尾处理;再赋值给当前温度值

{
          if( T1_AD_start==1)    //T1_AD_start是定时中断服务函数操作的,用于定时时间到,确认开启AD转换
          {
               uchar i,j,temp,count;
               for(count=0;count<10;count++)
            {
                Temp_ad_val[count]= Get_ADdata( );     //获取10个AD值,依次赋值给数组     
              }
//========================10个数据的冒泡处理======================================  
                count=10;
            for(i=0;i<count-1;i++)
               {
           for(j=0;j<(count-1-i);j++)
                 {
                   if (Temp_ad_val[j]>=Temp_ad_val[j+1])
                     {
                        temp=Temp_ad_val[j];
                        Temp_ad_val[j]=Temp_ad_val[j+1];
                        Temp_ad_val[j+1]=temp;
                      }
                  }
             }
//========================对小于0℃和大于99℃的数据,进行处理======================================
      if(Temp_ad_val[3]<=0x76)   
            {
               temp_now_val=0x76;   //小于0℃的,都归为0℃

            }        
           if(Temp_ad_val[3]>=0x951)
            {
               temp_now_val=0x951;    //大于99℃的,都归为99℃

            }  
         
//========================掐头,去尾,进行处理======================================
//                      Temp_ad_val[0]=0;
//                      Temp_ad_val[6]=0;

//========================对剩余的8个AD值,取平均值======================================                                               
                temp_now_val=0;
                for(i=1;i<9;i++)
                       {
                               temp_now_val+= Temp_ad_val[i];
                          }

                      temp_now_val=temp_now_val>>3;        //除以8,用右移3位操作来实现
                                       
                       }       
             T1_AD_start=0;   //AD数据处理完毕,开始标志量清零,等待下一次的开启               
}



-------------------------时间调度函数-----------
void  time_proess (void)  //时间调度处理函数
{
        /*****-----------AD转换的定时部分----------******/
        if(T1_10ms==1)   //定时到125Us,AD转换周期需要40uS
                {
                           T1_AD_320ms++;
                           if(T1_AD_320ms==200)  //定时时间到25ms,开启一次AD转换
                                 {
                                          T1_AD_start=1;  
                                          T1_AD_320ms=0;  //25ms定时器清零
                                 }
                       
                 }

}


-----------------------变量定义部分-----------------------
#define   LED1  P30             //待机指示灯
#define   LED2  P31             //运行指示灯
#define   com   P16             //模拟GND
#define   M     P37             //气泵引脚
#define   Heat  P36             //加热引脚
#define   NTC   P12             //NTC的分压输入引脚 电压模拟量


uchar     M_T1_startflag=0;            //温度到9℃,气泵打开后启动定时器1
uchar     T1_10ms=0;                  //10ms定时,累计次数值
uchar     T1_50mS=0;                  //50ms定时,累计次数值  
uchar     T1_1S=0;                    //1S定时,累计次数值
uchar     T1_1min=0;                  //1min定时,累计次数值
uchar     T1_1hour=0;                 //1hour定时,累计次数值
#define   T1_5s_count  5              //5秒的定时器中断次数

uchar T1_AD_320ms = 0;      //每隔25ms.开始一次AD转换
uchar T1_AD_start = 0;       //到25ms,AD转换开始,标志量

int T1_AD_9degree =10;      //稳定到9℃,消抖变量
uchar  T1_M_fliter =0;        //马达对应的灯,闪灭的频率变量
uchar  T1_M_50mS =0;  


#define   AN9          0x09          //A/D转换通道9                                     ADST
#define   ADST         0x40                 //控制A/D转换开始,1 转换开始触发信号   0x40->( 0  1  0  0  0 0 0 0)

// code  uint   Temp_table[ ]={
//118,125,131,138,145,152,160,168,176,185,                    //  0℃---9℃  12位A/D转换结果
//193,203,212,222,233,243,254,266,278,290,                    //  10℃---19℃  12位A/D转换结果
//303,316,329,343,358,372,388,403,420,436,                    //  20℃---29℃  12位A/D转换结果
//453,471,489,507,526,546,566,586,607,628,                    //  30℃---39℃  12位A/D转换结果
//650,672,695,718,742,766,790,815,841,867,                    //  40℃---49℃  12位A/D转换结果
//893,919,946,974,1001,1030,1058,1087,1116,1145,              //  50℃---59℃  12位A/D转换结果
//1175,1205,1235,1266,1296,1327,1358,1389,1421,1452,          // 60℃---69℃  12位A/D转换结果
//1484,1516,1548,1580,1612,1644,1676,1708,1740,1772,          // 70℃---79℃  12位A/D转换结果
//1804,1836,1868,1900,1931,1963,1994,2026,2057,2088,          //  80℃---89℃  12位A/D转换结果
//2118,2149,2179,2209,2239,2269,2298,2327,2356,2385           //  90℃---99℃


int  Temp_ad_val[10]={0};    //对采集10次的数据,进行冒泡排序的数组,去掉第1个,最后1个,再取算数平均值

int  temp_now_val=0;   //当前的温度值



------------------定时中断服务函数----------------------

void INT_Timer0() interrupt 13
{
          WDTCR= 0x20;        // Clear WDT Counter
          IIFLAG&=0x00;    //清定时器0的中断标志,使得为T0为没有溢出中断、没有T0中断产生。
          T0CR=0x0C;  //关闭timer0
           T1_10ms++;
              if(T1_10ms==80)             //定时时间到10ms
                                {
                                          T1_10ms=0;
                                          T1_50mS++;
                                          if(T1_50mS==5)   //定时时间到50ms
                                                {
                                                        T1_50mS=0;
                                                        T1_1S++;
                                                         if(T1_1S==20)  //定时时间到1S
                                                         {
                                                                  T1_1S=0;
                                                                  T1_1min++;
                                                                   if(T1_1min==60)     //定时时间到1小时
                                                                         {
                                                                                 T1_1min=0;
                                                                                 T1_1hour++;
                                                                                  if(T1_1hour==24)  //定时时间到24小时,即1天
                                                                                        {
                                                                                                 T1_1hour=0;
                                                                                        }
                                                                                  
                                                                         }
                                                               
                                                         }
                                                          
                                                         
                                                }
                                          
                                        }

               
                    T0DR = 0x7C;    // period count,再次装入计数值
                    T0CR=0x8C;       // 开Timer0;
            

}

       


void INT_Timer1() interrupt 14
{
             WDTCR= 0x20;        // Clear WDT Counter
             T1CRL = 0x60;           // timer setting Low   0x60->0110 0000-->011->Fx/8;  清定时器1的中断标志
             T1CRH = 0x00;           // timer setting High  关定时器T1
          
       
        /*-----------LED灯闪灭的定时部分----------*/
                 if(M_T1_startflag==1)
                        {          
//                                  T1_AD_320ms=0;  //AD转换的定时时间清零
                                   T1_M_50mS++;
                                  if(T1_M_50mS==25) //定时到500ms
                                        {          
                                          T1_M_50mS=0;
                                         //        M_T1_startflag=0;      //
                                          M=~M;         //M取反后,再赋值给自己,实现M指示灯的闪灭效果.
                                         com=0x00;
                                         LED2=0;
                                         LED1=0;
                                        }
                                       
                        }       
       
           T1ADRH = 0x9C;          // period count High   
           T1ADRL = 0x3F;          // period count Low
           T1CRH |= 0x80;          // 开定时器 counter1

}





相关帖子

沙发
gaoyang9992006| | 2018-9-20 20:08 | 只看该作者
你这AD值的消抖,这么搞麻烦啊。因为是12位的,你可以取4位或者10位啊。这样就等价消除抖动了。
如果用int16 存储这个AD,你可以这么操作
int16 ad_val;
ad_val=(ad_val>>2)<<2;
这样,先把采集到的12位数据右移出去2位最低位,然后左移回来,这样就清理掉了最低的两位。
如果你保留8位精度,就把这两个2换成4

使用特权

评论回复
板凳
rankey|  楼主 | 2018-9-21 08:10 | 只看该作者
gaoyang9992006 发表于 2018-9-20 20:08
你这AD值的消抖,这么搞麻烦啊。因为是12位的,你可以取4位或者10位啊。这样就等价消除抖动了。
如果用int1 ...

很感谢你的建议!很好,让我知道了以后用8位AD采样值,可以先用12位AD值,再按你的办法处理一下。

使用特权

评论回复
地板
hwpga| | 2018-9-21 13:28 | 只看该作者
ad采样不应该用for,应该用定时器或时间片采样,如1MS采样一次,10次分10MS轮询采样完10次冒泡排序后也没必要中间8个累加求平均
如果采样的AD值为{402,410,408,407,412,418,415,420,407,408}
排序后{402,407,407,408,408,410,412,415,418,420}
直接取中间的如果adcDat=adc_com[4]+adc_com[5]; adcDat>>=1;

使用特权

评论回复
5
rankey|  楼主 | 2018-9-25 08:35 | 只看该作者
有道理,AD采样比较费时,集中一次性采样10次,再处理数据,是很费时。分散开采集,再处理数据,这样可以提高CPU使用效率。

使用特权

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

本版积分规则

21

主题

181

帖子

4

粉丝