用mega8单片机的单路ADC(PC2)测电池电压,为什么读出的AD值始终为0?
大家帮忙看看,不知道为什么读出的AD值始终是0???一、ADC初始化函数:
void ADC_Init(void)
{
ADCSR = 0x00; //disable adc
ACSR= 0x80;//模拟比较器禁用
ADMUX = 0xc2;//片内2.56V,右对齐,ADC2单端输入
ADCSRA= 0xcf;//ADC使能,开始转换,单次转换,中断使能,128分频。
}
二、中断函数
#pragma interrupt_handler adc_isr:iv_ADC
void adc_isr(void)
{
//conversion complete, read value (int) using...
ADC_Flag=1;
ADC_Value=(unsigned int)ADCL; //Read 8 low bits first (important)
ADC_Value|=(unsigned int)ADCH<< 8; //read 2 high bits and shift into top byte
ADC_Value= ADC_Value/1024*256;
}
三、主函数
void main(void)
{
volatile INT32U AD_Sum=0;
unsigned int i,j;
ADC_Init();
while(1)
{
if(ADC_Flag)//转换完成
{
ADC_Flag=0;//清除转换完成标志
AD_Read=ADC_Value;
AD_Count++;
if(AD_Count==50)//数据满
{
AD_Count=0;
choise(AD_Read, AD_Counter);//排序
for(i=10;i<40;i++)//取中间30个
{
AD_Sum=AD_Sum+AD_Read;
}
AD_Sum=AD_Sum/30;
if((AD_Sum*11)<=1000)//电压值小于10V
{
PWMB_Stop();
PORTD=0x00;
delay_nms(3000);
PORTC&=~BIT(Power_Lock); //关机
while(1);
}
AD_Sum=0;
}
ADCSRA|=0xC0;//开始新的转换
}
}
} //----------------------------------------------------------------------------------------------------
// ADC采样函数
//----------------------------------------------------------------------------------------------------
unsigned int get_ad(void)
{
unsigned int adc_result;
ADCSRA |= 1<<ADSC; //置位ADSC位,启动一次AD转换
while(!(ADCSRA & (1 << ADIF))); //等待
adc_result = ADC; //保存ADC采样值
return adc_result;
}
//----------------------------------------------------------------------------------------------------
// ADC滤波函数
// 连续采样202次,去掉最大值,最小值,再除以N-2
//----------------------------------------------------------------------------------------------------
unsigned intadc_filter(void)
{
unsigned int i,j,k,l;
unsigned int temp;
unsigned int value_buf;
unsigned long sum=0;
unsigned int adc_result=0;
for (i=0;i<N;i++) //一次采集N个数据,放入value_buf[ ] 数组中
{
value_buf = get_ad();
delay_us(5);
delay_us(5);
delay_us(5);
delay_us(5);
}
for (j=0;j<N-1;j++) //采样值由小到大排列,排序采样冒泡法
{
for (k=0;k<N-j;k++)
{
if ( value_buf>value_buf )
{
temp = value_buf;
value_buf = value_buf;
value_buf = temp;
}
}
}
for (l=1;l<N-1;l++) //只把value_buf[ ] 数组中的1-(N-1)相加,抛弃最左,最右数据(即最大,最小值)
{
sum += value_buf;
}
adc_result=sum/(N-2);
return (adc_result);
}
下面是主程序中采用AN0的使用:
//---------------------------------------------------------------------------------------------------- 充电电流
ADMUX = 0x00; //选择AREF, 结果右对齐,选择ADC通道0
adc_result = adc_filter();
v0_h = (adc_result >> 8) & 0xFF; //ADC高位
v0_l = adc_result & 0xFF; //ADC低位
//---------------------------------------------------------------------------------------------------- 放电电流 上面是一个完成项目的程序,可以参考参考 谢谢【2楼】 rqiang :我就是不理解为什么我的不可以?ADC转换中断完成后,置位ADC_Flag标志,同时将AD结果读入一变量ADC_Value;主函数判断标志ADC_Flag,如果置位,则读取ADC_Value的值放入数组内,同时清零ADC_Flag标志、启动下一次转换。数组满后,做滤波处理。
可能是初始化有问题,可实在看不出那里有问题?郁闷 直接ADC_Value=ADC试试 你测的是什么电池的电压.有没有做过12V蓄电池电压测试 ADC初始化程序应该对的,下面是ICCAVR自动生成的AN0的初始化程序
//ADC initialize
// Conversion time: 416uS
void adc_init(void)
{
ADCSR = 0x00; //disable adc
ADMUX = 0x00; //select adc input 0
ACSR= 0x80;
ADCSR = 0xCF;
} 一般有两种方法:中断法和查询法。既然你使用中断服务程序,主程序就不该查询中断标志位。可以参考清华大学出版社马潮 詹卫前 耿德根编著的《atmega8原理及应用手册》P284页程序 回复【7楼】gaojian413
-----------------------------------------------------------------------
我是在中断函数里置位了一标志,主函数查询的。而且我测试过,中断里直接判断ADC_Value的值就是0!!! 回复【5楼】fengwan
-----------------------------------------------------------------------
没有我测试的电压可以是外接的,或者12V镍氢电池。 ADC_Value= ADC_Value/1024*256;
如果不要这句呢?
或者改为ADC_Value= ADC_Value/4;
是不是先除以1024之后就已经是零了 楼主
原理图也发上来.看看. 回复【10楼】zht9961020
-----------------------------------------------------------------------
汗。。。疏忽了,不出意外的话就是这个问题了,我现在去调试一下。谢谢。 好了,再次感谢zht9961020的提醒,疏忽了。浪费了我几乎一天的时间,怎么也找不出毛病。 为表感谢。我将全部代码贴出.
main.c
#include <Init.h>
unsigned int AD_Read,AD_Count=0;
enum
{
SET = 0x0a,
OK = 0x09,
POWER = 0x03,
};
INT8U Key,PWM_Flag=1,Run_State,ADC_Flag=0;
//volatile ADC_T Adc={0,0};
volatileINT32UADC_Value;
OCR_T Ocr1;
OCR_T OCR_Set(INT8U flag);
void ADC_Init(void)
{
ADCSR = 0x00; //disable adc
ACSR= 0x80;//模拟比较器禁用
ADMUX = 0xc2;//片内2.56V,右对齐,ADC2单端输入
ADCSRA= 0xcf;//ADC使能,开始转换,单次转换,中断使能,128分频。
}
void Init(void)
{
DDRC=0x00;
PORTC=0x00;
DDRB=0x00;
PORTB=0x00;
DDRD=0xff;//灯全部亮
PORTD=0x00;
DDRC&=~(BIT(Key_Set)|BIT(Key_Ok)|BIT(Power_Key)); //输入
DDRC|= BIT(Power_Lock)|BIT(PWM_A); //输出
PORTC|=BIT(Key_Set)|BIT(Key_Ok)|BIT(Power_Key);//开上拉
PORTC|= BIT(Power_Lock); //电平锁定
PORTC&=~BIT(PWM_A); //电平锁定
delay_nms(1000);
PORTD=0xff;
DDRB|=BIT(Motor_A)|BIT(Motor_B)|BIT(PWM_B);
PORTB&=~(BIT(Motor_A)|BIT(Motor_B)|BIT(PWM_B));
ADC_Init();
SEI();
delay_nms(1000); //LED灯长亮
PORTD=0xff;
while(!(PINC&0x08)); //等待开机按键释放
}
#pragma interrupt_handler adc_isr:iv_ADC
void adc_isr(void)
{
//conversion complete, read value (int) using...
ADC_Flag=1;
ADC_Value=(unsigned int)ADCL; //Read 8 low bits first (important)
ADC_Value|=(unsigned int)ADCH<< 8; //read 2 high bits and shift into top byte
ADC_Value= ADC_Value*256/1024;
}
void main(void)
{
volatile INT32U AD_Sum=0;
unsigned int i,j;
Init();
while(1)
{
if(ADC_Flag)//转换完成
{
ADC_Flag=0;//清除转换完成标志
AD_Read=ADC_Value;
AD_Count++;
if(AD_Count==50)//数据满
{
AD_Count=0;
choise(AD_Read, AD_Counter);//排序
for(i=10;i<40;i++)//取中间30个
{
AD_Sum=AD_Sum+AD_Read;
}
AD_Sum=AD_Sum/30;
if((AD_Sum*11)<=1000)//电压值小于10V
{
PWMB_Stop();
PORTD=0x00;
delay_nms(3000);
PORTC&=~BIT(Power_Lock); //关机
while(1);
}
AD_Sum=0;
}
ADCSRA|=0xC0;//开始新的转换
}
Key=Key_Scan();
if(Key==SET)//按下设定键
{
if(Run_State==0x01)
{
PWMB_Stop();
Run_State=0x02;
}
else
{
PWM_Flag++;
if(PWM_Flag==9) {PWM_Flag=1;}
Ocr1=OCR_Set(PWM_Flag);
}
}
if(Key==OK)//按下确定键
{
if(Run_State!=0x01)
{
Run_State=0x01;
PWMB_Start(Ocr1);
}
}
if(Key==POWER)
{
PORTD=0x00;
delay_nms(500);
PORTD=0xff;
delay_nms(500);
PORTD=0x00;
delay_nms(500);
PORTC&=~BIT(Power_Lock); //关机
while(1);//防止乱按键
}
LED_Train(PWM_Flag-1);
}
}
OCR_T OCR_Set(INT8U flag)
{
static OCR_T Ocr_Temp;
switch (flag)
{
case 1: // 1/1
{
Ocr_Temp.b=TOP/1;
Ocr_Temp.a=Ocr_Temp.b*1;
}break;
case 2: // 1/2
{
Ocr_Temp.b=TOP/2;
Ocr_Temp.a=Ocr_Temp.b*2;
}break;
case 3: // 1/4
{
Ocr_Temp.b=TOP/4;
Ocr_Temp.a=Ocr_Temp.b*4;
}break;
case 4: // 1/8
{
Ocr_Temp.b=TOP/8;
Ocr_Temp.a=Ocr_Temp.b*8;
}break;
case 5: // 1/10
{
Ocr_Temp.b=TOP/10;
Ocr_Temp.a=Ocr_Temp.b*10;
}break;
case 6: // 1/20
{
Ocr_Temp.b=TOP/20;
Ocr_Temp.a=Ocr_Temp.b*20;
}break;
case 7: // 1/40
{
Ocr_Temp.b=TOP/40;
Ocr_Temp.a=Ocr_Temp.b*40;
}break;
case 8: // 1/50
{
Ocr_Temp.b=TOP/50;
Ocr_Temp.a=Ocr_Temp.b*50;
}break;
default :break;
}
return Ocr_Temp;
} Init.c //为方便好多函数都在main.c内编写了
#define INIT_C
#include <Init.h>
void port_init(void)
{
PORTB = 0x00;
DDRB= 0xff;
PORTC = 0x00; //m103 output only
DDRC= 0x00;
PORTD = 0x00;
DDRD= 0xff;
}
void Key_Init(void)
{
KEY_PORT =0xff;
KEY_DDR=0xf0;
}
//TIMER1 initialize - prescale:64
// WGM: 15) PWM fast, TOP=OCRnA0x30d3
// desired value: 10Hz
// actual value: 10.000Hz (0.0%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1=0;
OCR1A=12499;
OCR1B=6000;
//TCCR1A = 0x23;
//TCCR1B = 0x1b; //start Timer
}
void PWMB_Start(OCR_T Ocr)
{
TCCR1B = 0x00; //stop
TCNT1=0;
OCR1A=Ocr.a;
OCR1B=Ocr.b;
TCCR1A = 0x23;
TCCR1B = 0x1b; //start Timer
}
void PWMB_Stop(void)
{
TCCR1A = 0x00;
TCCR1B = 0x00; //start Timer
}
void PWMA_Start(void)
{
DDRC |=BIT(PWM_A);
PORTC&=~BIT(PWM_A);
}
void PWMA_Stop(void)
{
DDRC |=BIT(PWM_A);
PORTC|=BIT(PWM_A);
}
void MotorA_Start(void)
{
DDRB |=BIT(Motor_A);
PORTB&=~BIT(Motor_A);
}
void MotorA_Stop(void)
{
DDRB |=BIT(Motor_A);
PORTB|=BIT(Motor_A);
}
void MotorB_Start(void)
{
DDRB |=BIT(Motor_B);
PORTB&=~BIT(Motor_B);
}
void MotorB_Stop(void)
{
DDRB |=BIT(Motor_B);
PORTB|=BIT(Motor_B);
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
timer1_init();
//ADC_Init();
MCUCR = 0x00;
GICR= 0x00;
TIMSK = 0x00; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}
uchar KEY_Pressed(void)
{
uchar key;
//Key_Init();
key=KEY_PIN&0x0b;
if(key==0x0b)
return 0;
else
return 1;
}
INT8U Key_Scan(void)
{
//void *ptr=&flag;
uchar oldkey,newkey;
if((KEY_Pressed())==1)//有按键
{
oldkey=KEY_PIN&0x0b;
}
else {return 0;}
delay_nms(50);
newkey=KEY_PIN&0x0b;
if(oldkey==newkey) //确认按键
{
while((PINC&0x0B)!=0x0B);//等待按键释放
return newkey;
}
else {return 0;}
}
void LED_Train(INT8U flag)
{
DDRD=0xff;//输出
PORTD=~BIT(flag);
}
void delay_1us(void) //1us延时函数
{
asm("nop");
}
void delay_nus(unsigned int n) //N us延时函数
{
unsigned int i=0;
for (i=0;i<n;i++)
delay_1us();
}
void delay_1ms(void) //1ms延时函数
{
unsigned int i;
for (i=0;i<(unsigned int)(XTAL*143-2);i++);
}
void delay_nms(unsigned int n) //N ms延时函数
{
unsigned int i=0;
for (i=0;i<n;i++)
{
delay_1ms();
}
}
void delay(long int x)
{
uchar j;
while((x--)!=0)
{
for(j=0;j<125;j++)
{
;
}
}
}
void choise(unsignedint *a,unsigned int n) //从小到大排序
{
unsigned int i,j,k,temp;
for(i=0;i<n-1;i++)
{
k=i; //*给记号赋值
for(j=i+1;j<n;j++)
if(a>a) k=j; //*是k总是指向最小元素
if(i!=k)//*当k!=i是才交换,否则a 即为最小
{
temp=a;
a=a;
a=temp;
}
}
} Init.h
#ifndef INIT_H
#define INIT_H
#include <iom8v.h>
#include <macros.h>
//-------------------------------------宏定义---------------------------------------
#define XTAL 8
#define TOP 0x30d3 //12499
#define uchar unsigned char
#define uint unsigned int
#define cchar const unsigned char
typedef unsigned char INT8U;
typedef signed char INT8S;
typedef unsigned int INT16U;
typedef signed int INT16S;
typedef unsigned long INT32U;
typedef signed long INT32S;
typedef float FP32;
typedef double FP64;
typedef enum{false = 0, true = 1}BOOLEAN;
typedef enum
{
Key_Set=0x01,
Key_Start=0x02,
Key_Power=0x08,
}Key_T;
typedef struct
{
volatile INT16U a;
volatile INT16U b;
} OCR_T;
typedef struct
{
volatile INT8U ADC_Flag;
volatile INT16U ADC_Value;
} ADC_T;
#define KEY_PORT PORTC
#define KEY_DDR DDRC
#define KEY_PIN PINC
#define LED_PORT PORTD
#define LED_DDR DDRD
#define LED_PIN PIND
#define AD_Counter50
#define Power_LockPC4//电平锁定
#define Power_Key PC3//开关机检测
#define Power_ADC PC2//电池电压检测
#define Key_Ok PC1//确定
#define Key_Set PC0//设置
#define PWM_B PB2//配气
#define PWM_A PC5//气路切换
#define Motor_A PB1
#define Motor_B PB0
//------------------------------------函数声明区------------------------------------------
void port_init(void);
void init_devices(void);
void PWMB_Start(OCR_T Ocr);
void PWMB_Stop(void);
uchar KEY_Pressed(void);
INT8U Key_Scan(void);
void LED_Train(INT8U flag);
void delay_1us(void); //1us延时函数
void delay_nus(unsigned int n); //N us延时函数
void delay_1ms(void); //1ms延时函数
void delay_nms(unsigned int n); //N ms延时函数
void ADC_Init(void);
void choise(unsignedint *a,unsigned int n) ;
#else
#endif 是正在做的一个小项目,基本完成。代码有点乱,还没有整理。简单修改一下,OCR1B口就可输出任意精确占空比的PWM波形。比较简单O(∩_∩)O~ MARK 留个记号 呵呵没有液晶显示,调起来不方便。反复测试if((AD_Sum*11)<=1187)这句,最后测量的电压为11.88V,实测12.34V,分压电阻用的是102和103的,实际102:(102+103)并不是正好11.结果还可以接受。
算了,不测了。给AD_Sum*11乘个系数k=12.34/11.88。应该好了。O(∩_∩)O~ 经测试,AD测量电压值在12.30到12.40V之间。OK了。 呵呵呵,刚要说,以前也犯过~~ 留个爪子 mark 最近正好在ADC,看了这贴受益匪浅,留个记号 哇~~~刚好要弄ADC,参考了~~ mark 做个记号 ADC_Value= ADC_Value*256/1024;
这条语句还用这样写吗?写成下面的语句不就结了!
ADC_Value >>= 2;
页:
[1]