各位兄弟: 大家好!
鄙人自学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
}
|