搜索
bottom↓
回复: 36

马老师请进,关于avr连续自动转换的问题

[复制链接]

出0入0汤圆

发表于 2011-11-5 10:38:55 | 显示全部楼层 |阅读模式
最进买了您的书,学习AD转换,写了一个连续自由转换的实验程序(cvavr),主程序首先初始化AD(设置为连续自由转换),进入主循环什么也不做,编译后用avr sdudio软件模拟仿真,发现第一次能正常启动ad转换,但之后无法自动启动第二次转换,且adsc标志位一直为0,按理说第一次启动后adsc应该一直为1啊,百思不得其解,程序在2楼。请您明示。谢谢。

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

 楼主| 发表于 2011-11-5 10:42:10 | 显示全部楼层
//#define ENABLE_BIT_DEFINITIONS
#include <mega16.h>
#include <delay.h>

#asm
.equ __lcd_port=0x15;
#endasm
#include <lcd.h>
unsigned char dis_buff[5]={0,0,0,0,0};
//bit time_2ms_ok;
unsigned char  *str;

//#include <intrinsics.h>
#define FIRST_ADC_INDEX 0                   //第一个通道标示
#define LAST_ADC_INDEX 1                   //第二个通道标示
//#define Num_result 11                       //每一个AD通道的采样次数为11次
#define ADC_VREF_TYPE 0x40
//float adc_date[LAST_ADC_INDEX-FIRST_ADC_INDEX+1];     //存放每一路AD通道的转换结果的数组
//float ADresults[Num_result];              //4个AD通道转换结果暂存数组
//unsigned char AD_Final=0;              //单通道AD转换11次采样后标志
unsigned int input_index=0;
#define ADC0 1
#define ADC1 2
//#define ADC2 3
//#define ADC3 4
//unsigned char times=0;
unsigned int temp1,temp2;
//float voltage;
//float current;


/*float ADFilte(void)                    //AD去极值数字滤波,结果处理
{
   float Filte_result=0;
   unsigned int i,j;
   float temp;
   unsigned int count;
   for(j=0;j<Num_result-1;j++)
   {
      for(i=0;i<Num_result-j;i++)
      {
         if(ADresults>ADresults[i+1])
         {
            temp=ADresults;
            ADresults=ADresults[i+1];
            ADresults[i+1]=temp;
          }
       }
   }
   for(count=1;count<(Num_result-1);count++)
   {
     Filte_result+=ADresults[count];
   }
   return Filte_result/(Num_result-2);
}
*/

/*float V_I(float vol)
{
  current=4+((vol-80)/(400-80))*16;
  return current;
}
*/

// ADC电压值送显示缓冲区函数
void adc_to_disbuffer(unsigned int adc)
{
char i,j;
for (i=0;i<=3;i++)
{
    j=3-i;
    dis_buff[j]=(adc % 10)+48;
    adc /= 10;
}
lcd_gotoxy(input_index*6,0);
lcd_puts(str);
}

//#pragma vector=ADC_vect
//__interrupt void AD_process(void)

// ADC 转换完成中断服务
interrupt [ADC_INT] void AD_process(void)
{
  //unsigned char times=0;
  //unsigned int temp1,temp2;

   unsigned int adc_v;

   temp1=ADCL;
   temp2=ADCH;
   temp2=(temp2<<8)+temp1;

// ADresults[times]=temp2;               //将结果移到数组ADresults[]
//times++;
   ADCSRA |=(1 << ADIF);                                        // Acknowledge the ADC Interrupt Flag

   adc_v=(unsigned long)temp2*5000/1024; //换算成电压值
   adc_to_disbuffer(adc_v);              //转换成ASCII码,送显示缓冲区

//   if (++input_index>(LAST_ADC_INDEX-FIRST_ADC_INDEX))    //判断两通道是否转换完毕
//       input_index=0;
//   ADMUX=(FIRST_ADC_INDEX|ADC_VREF_TYPE)+input_index;     //切换到下一通道准备继续转换
  // AD_Final=1;

/* if(times==Num_result)
  {
     voltage=ADFilte();
     adc_date[input_index]=V_I(voltage);
     times=0;
     if (++input_index>(LAST_ADC_INDEX-FIRST_ADC_INDEX))
       input_index=0;
     ADMUX=(FIRST_ADC_INDEX|ADC_VREF_TYPE)+input_index;
     AD_Final=1;
  }
*/
}


void main(void)
{
// WDTCR=(1<<WDCE)|(1<<WDE);
// WDTCR = 0x00;
  DDRA&=~(1<<ADC0)|(1<<ADC1)|(1<<ADC2)|(1<<ADC3);              // 初始化I/O端口
  PORTA=0x00;

  ADMUX=0x40;                         //ADC参考电源选择AVCC,AREF外部并接电容,ADC0单端输入
  ADCSRA=0xAD;                        //ADC允许,自动触发转换,ADC转换中断允许位,32分频,ADCclk=(4MHz/32)=125kHz
  SFIOR=0;                           //连续自由转换


  //asm("sei");

  //  lcd_init(16);
// lcd_clear();
  ADCSRA|=(1<<ADSC); //开启ADC

  str =dis_buff;
// #asm("sei") // 开放全局中断

  while(1)
  {
  #asm("nop");
  }
}
程序原来是想实现2通道转换,结果发现有问题,好多语句注释掉了,注释之后的程序是一个通道连续自由转换的实验程序,中断被禁止,只想观察连续自由转换是否正常进行。

出0入0汤圆

 楼主| 发表于 2011-11-5 10:57:54 | 显示全部楼层
是不是因为第一次转换完成后,adif中断标志自动置1,同时启动第2次转换,然后必须软件清零adif中断标志(好像是写1清零吧),以便第二次转换完成置位。而程序中并没有在转换完成后清adif中断标志?
但是如果果真是这个原因,在我把全局中断打开后,第一次转换完成进入中断,硬件会自动清零adif中断标志的,但是仿真的时候,打开中断的话还是无法启动第2次转换,郁闷。

出0入0汤圆

 楼主| 发表于 2011-11-5 12:26:16 | 显示全部楼层
想了一上午,终于找到问题了,我在中断服务函数里应该再次开启ad转换,在中断服务函数里加了一句话:ADCSRA|=(1<<ADSC); //开启ADC,就好了。以下是个人见解:
第一次转换结束并进入中断后,ADIF马上清零,从第一次转换结束到ADIF中断硬件清零的间隔极短,以至于ADIF的上升沿无法触发下一次转换,此时adsc标志位为0,并一直保持,所以第2次ad转换未启动。
不知道是不是这样,请指教

出0入0汤圆

发表于 2011-11-5 12:29:29 | 显示全部楼层
回复【3楼】microhard567  
-----------------------------------------------------------------------

这么做不是自动的。。
看看 ADATE 吧

出0入0汤圆

发表于 2011-11-5 12:38:52 | 显示全部楼层
avr sdudio软件模拟仿真能做什么?它不是一片AVR在真正运行工作!

avr sdudio软件模拟仿真,主要是模拟用户代码的执行,而AVR硬件本身实现的功能,绝大部分它是不能模拟的。

比如在avr sdudio软件模拟仿真情况下,你初始化定时器,让它1秒钟中断一次,这个代码的初始化部分可以模拟,模拟器把定时器相关的寄存器赋值。

但是,定时器开始计数、以及计数加1过程,计数到设定值,并置中断标志为1,这些硬件自动完成的功能(不是你编的代码执行的操作)avr sdudio软件模拟仿真是做不到的。

所以,你只能人工设置中断标志为1,此时avr sdudio软件模拟器检测到该位为1,转到定时器中断服务执行(这个中断响应的硬件过程,是avr sdudio软件模拟能够模拟的有限几个功能之一,另一个是USART)。

真正能明白和使用模拟的仿真或在线的调试,是建立在你对AVR的比较了解的基础上。

如果对AVR本身根本不了解和掌握,所有的模拟和在线调试仿真都是浮云。

简单举个例子,如果一个数字文盲,根本不会加、减、乘、除,不知道这些运算是什么意思,那他有个计算器就知道5斤白菜和3斤萝卜共多少钱了?至少要知道什么乘什么,什么加什么,先加还是先乘等运算法则,才能正确按键吧。

学习单片机没有什么捷径,老老实实从基础一点一点的学习。到了一定的积累,你自己就会使用模拟工具和仿真工具的。

使用计算器需要别人教吗?自己摸索一下就会了,因为已经有算数和数学的基础知识和观念。

出0入0汤圆

 楼主| 发表于 2011-11-5 12:43:41 | 显示全部楼层
这么说,ad转换的仿真最好在硬件平台上,在软件里面无法验证ad转换的硬件过程?(我是指ADIF等标志的置位过程)。还有就是进入中断后ADIF应该也是由硬件清零的吧?为什么studio里能实现呢?
另外,我在protus上仿真也是一样,无法完成第二次转换,这么说protus也不能模拟ad转换的硬件过程,也就是说protus也无法完成自由连续转换模式下得ad转换程序的模拟?
我觉得只要明确硬件的工作过程和原理,任何硬件过程产生的结果(是指结果,如置标志位等,比如软件无线电,就是软件模拟无线电的放大,调制,解调等过程)都可以用软件模拟,看来软件仿真还可以做的更好,更自动,更完美。

出0入0汤圆

 楼主| 发表于 2011-11-5 12:54:22 | 显示全部楼层
回复【4楼】huayuliang 花生
回复【3楼】microhard567   
-----------------------------------------------------------------------
这么做不是自动的。。
看看 adate 吧
-----------------------------------------------------------------------

是的,我也想到了,这么做就不是连续自由转换了,属于单次转换了。

出0入0汤圆

 楼主| 发表于 2011-11-5 13:01:00 | 显示全部楼层
按马老师这么说,我原来的程序是没有问题的?(我是说在连续自由转换的工作方面),一会烧到目标板上试试
另外,按我的理解,如果软件没有问题的话,因为我的中断服务函数里有lcd显示程序,中断执行完毕的时间肯定大于一次ad转换的时间,这样执行一次中断,到退出中断的时间里,连续自动模式下工作的ad已经转换了好多次了,这些数据完全丢失了,是吗?这样的话,实际的采样率应该是由中断函数的时间决定的,所以为什么说中断函数尽可能短小。

出0入0汤圆

 楼主| 发表于 2011-11-5 19:13:38 | 显示全部楼层
怎么不见高手来解释了呢?是不是发现孺子不可教了?哈哈

出0入0汤圆

 楼主| 发表于 2011-11-6 13:33:34 | 显示全部楼层
今天把程序再改了一下,这次更简单,进入中断后让一个led亮500ms,出来进入主循环后灭500ms,还是连续自由转换,中断函数中如果加入语句:ADCSRA|=(1<<ADSC); //开启ADC   后一切正常,可以多次进入中断,但删掉该语句后,软件模拟还是只能进一次中断(即只能进行1次ad转换),烧到mega16上和软件模拟的结果一样,我的程序到底错在哪里?为什么进入中断后就不能自动启动下一次转换呢?高手请解答。程序如下:
#include <mega16.h>

#include <delay.h>

#define ADC_VREF_TYPE 0x40

// ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{
unsigned int adc_data;
// Read the AD conversion result
adc_data=ADCW;
PORTB|=0x1;
delay_ms(500);
//ADCSRA|=(1<<ADSC); //开启ADC
// Place your code here

}

// Declare your global variables here

void main(void)
{
// Declare your local variables here

PORTA=0x00;
DDRA=0x00;

PORTB=0x00;
DDRB=0x1;



// ADC initialization
// ADC Clock frequency: 125.000 kHz
// ADC Voltage Reference: AVCC pin
// ADC Auto Trigger Source: Free Running
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0xAD;
SFIOR&=0x1F;

ADCSRA|=(1<<ADSC); //开启ADC
// Global enable interrupts
#asm("sei")

while (1)
      {
      // Place your code here

      PORTB&=0xFE;
      #asm("cli")
      delay_ms(500);
      #asm("sei")
      }
}

出0入0汤圆

发表于 2011-11-6 20:25:27 | 显示全部楼层
"烧到mega16上和软件模拟的结果一样,"

that means your software was faithful in producing the results.

here is my try:


/*
*/

#include <avr/io.h>                                                //we use gcc-avr
#include <avr/interrupt.h>                                //we use adc interrupt
#include "gpio.h"                                                //we use gpio

//hardware configuration
#define IND_PORT                        PORTC
#define IND_DDR                                DDRC
#define IND                                        (1<<0)                //loop indicator on pc0

#define OUT_PORT                        PORTD
#define OUT_DDR                                DDRD
#define OUTs                                0xff                //portd as output
#define OUT(byte_t)                        OUT_PORT = (byte_t)        //output byte
//end hardware configuration

#define ADCCH_ADC0                        0x00                //adc0
#define ADCCH_ADC1                        0x01                //adc1
#define ADCCH_ADC2                        0x02                //adc2
#define ADCCH_ADC3                        0x03                //adc3
#define ADCCH_ADC4                        0x04                //adc4
#define ADCCH_ADC5                        0x05                //adc5
#define ADCCH_ADC6                        0x06                //adc6
#define ADCCH_ADC7                        0x07                //adc7
#define ADCCH_VBG                        0x1e                //Vbg=1.22v
#define ADCCH_GND                        0x1f                //0v=gnd

//global variables
volatile unsigned short adc_result;

void mcu_init(void) {
        IO_CLR(IND_PORT, IND);                                //clear ind
        IO_OUT(IND_DDR, IND);                                //ind as output

        IO_CLR(OUT_PORT, OUTs);                                //clear outs
        IO_OUT(OUT_DDR, OUTs);                                //outs as output
}

//adc isr
ISR(ADC_vect) {
        //adc_result = (ADCH << 8) | ADCL;        //save adch
        IO_FLP(IND_PORT, IND);                                //flip ind
        //OUT(adc_result>>2);                                        //output adc_result
        OUT(ADCH);
}

//initialize the adc module
void adc_init(unsigned char ch) {
        ADCSRA&=~(1<<ADEN);                                                //clear aden
        ADMUX =         (1<<REFS1) | (1<<REFS0) |        //internal Vref used
                                (1<<ADLAR) |                                //results left adjusted
                                (ch & ADCCH_GND)                        //select the channel
                                ;
        SFIOR =                (SFIOR & 0x0f) |                        //clear sfior's adc bits
                                (0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0)        //0b000=free running adc
                                ;
        ADCSRA=                (1<<ADEN) |                                        //adc turned on
                                (1<<ADSC) |                                        //start the 1st conversion
                                (1<<ADATE) |                                //use auto trigger for free running adc
                                (1<<ADIF) |                                        //clear adif by writing 1 to it
                                (1<<ADIE) |                                        //enable adc interrupt
                                (1<<ADPS2) | (0<<ADPS1) | (0<<ADPS0)        //prescaler to 0b100 = 1/16
                                ;
        //ADCSRA|=        (1<<ADSC);                                        //start the adc
}
int main(void)
{

    // Insert code
        mcu_init();                                                        //reset the mcu
        adc_init(ADCCH_ADC0);                                //adc0 on free running
        ei();                                                                //enable global interrupt
    while(1) {
            //IO_FLP(IND_PORT, IND);
    }

    return 0;
}



(原文件名:atmega16 freerunning adc.PNG)


it uses a free-running adc to read the voltage on ADC0 and output its highest 8 bits to PORTD.

出0入0汤圆

 楼主| 发表于 2011-11-6 21:35:40 | 显示全部楼层
你的程序没完全看懂,你的中断函数里面有没有置位adsc的语句?如果没有,那么中断能进去几次?我的程序第一次进入中断后adsc就无故被自动清零了,表示转换停止,按mega16 datasheet上说,只要是连续转换,那么第一次启动之后adsc应该一直为1才对啊。
datasheet上的描述:
  1.“使用ADC 中断标志作为触发源,可以在正在进行的转换结束后即开始下一次ADC 转换。之后ADC 便工作在连续转换模式,持续地进行采样并对ADC 数据寄存器进行更新。第一次转换通过向ADCSRA 寄存器的ADSC 写1 来启动。在此模式下,后续的ADC 转换不依赖于ADC 中断标志ADIF 是否置位。”
  2.“在连续转换模式下,当ADSC 为1 时,只要转换一结束,下一次转换马上开始”
  
连续转换时序图:(注意ADSC始终为1)

datasheet上关于连续转换的时序 (原文件名:连续转换时序.jpg)



ps:在上面的第1点中,有句话不明白:“在此模式下,后续的ADC 转换不依赖于ADC 中断标志ADIF 是否置位”,连续自由转换不是以中断标志ADIF为触发源吗?为什么后续的转换不依赖于ADC 中断标志ADIF 是否置位呢?

出0入0汤圆

 楼主| 发表于 2011-11-6 21:46:41 | 显示全部楼层
在某avr学习网上看到的一段程序,sfior采用默认设置(即0x00,连续转换模式),中断读数,请注意中断函数中有这么一句:ADCSRA |= (1<<ADSC); //ADSC: AD start conversion,还是手动启动了下一次转换,这还是连续转换吗?不是单次转换了吗?
程序如下:
#include <iom16v.h>
#include "D:ICC_HCmmICC.H"

#define H_VAL_DISP_DDR DDRD
#define L_VAL_DISP_DDR DDRB
#define H_VAL_DISP_PORT PORTD
#define L_VAL_DISP_PORT PORTB

const uint8 ADEnStatus[8] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};

uint8 AdcMux; //ADC通道
uint16 AdcVal; //ADC转换值

/*--------------------------------------------------------------------
程序名称:AD转换初始化程序
程序功能:
注意事项:
提示说明:
输 入:
返 回:
--------------------------------------------------------------------*/
void adc_init()
{
/*设置对应的IO口为输入高阻态*/
DDRA &= ADEnStatus[AdcMux];
PORTA &= ADEnStatus[AdcMux];

ADCSRA = 0x00; //disable adc
ADMUX = (1<<REFS1)|(1<<REFS0)|(AdcMux&0x0F); //select adc input channel
ACSR = (1<<ACD); //close analog comparator
ADCSRA=(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1);
}
/*--------------------------------------------------------------------
程序名称:AD转换中断服务程序
程序功能:
注意事项:
提示说明:
输 入:
返 回:
--------------------------------------------------------------------*/
#pragma interrupt_handler adc_isr:15
void adc_isr(void)
{
AdcVal = ADC&0x3FF;
ADMUX = (1<<REFS0)|(AdcMux&0x0F); //使用AVcc作为ADC参考电源
ADCSRA |= (1<<ADSC); //ADSC: AD start conversion
}
/*--------------------------------------------------------------------
程序名称:
程序功能:
注意事项:
提示说明:
输 入:
返 回:
--------------------------------------------------------------------*/
void main(void)
{
H_VAL_DISP_DDR = 0xFF;
L_VAL_DISP_DDR = 0xFF;
AdcMux = 0; //使用ADC通道0
adc_init();
SEI();
while(1)
{
H_VAL_DISP_PORT = (AdcVal&0x300)>>8; //ADC的高2位Val
L_VAL_DISP_PORT = AdcVal&0xFF; //ADC的低8位Val
}
}

出0入0汤圆

 楼主| 发表于 2011-11-8 01:04:23 | 显示全部楼层
datasheet上的描述:
  1.“使用ADC 中断标志作为触发源,可以在正在进行的转换结束后即开始下一次ADC 转换。之后ADC 便工作在连续转换模式,持续地进行采样并对ADC 数据寄存器进行更新。第一次转换通过向ADCSRA 寄存器的ADSC 写1 来启动。在此模式下,后续的ADC 转换不依赖于ADC 中断标志ADIF 是否置位。”
  2.“在连续转换模式下,当ADSC 为1 时,只要转换一结束,下一次转换马上开始”
——————————————————————————————————————————————————————————

另外
马潮老师《avr单片机嵌入式系统原理与应用实践》一书第2版,第323页第3段这样描述:“在自由连续转换模式下,一次转换完毕后马上开始一次新的转换,此时,ADSC位一直保持为'1'”

出0入0汤圆

发表于 2011-11-8 03:40:13 | 显示全部楼层
"datasheet上的描述:"

your issues are two-fold:

1) you don't understand code provided to you and you don't understand embedded coding;
2) you don't understand which documents to trust when and where, and which NOT to trust.

出0入0汤圆

发表于 2011-11-8 08:39:38 | 显示全部楼层
if I run the adc_isr this way:

"//adc isr
ISR(ADC_vect) {
        //adc_result = (ADCH << 8) | ADCL;        //save adch
        if (ADCSRA & (1<<ADSC)) IO_SET(IND_PORT, IND);                                //set ind if ADSC is set
        else IO_CLR(IND_PORT, IND);                        //clear ind if ADSC is cleared
        //OUT(adc_result>>2);                                        //output adc_result
        OUT(ADCH);
}
"

here is the output.

IND pin is on PC0, the 2nd trace from the top.



(原文件名:atmega16 adc 2.PNG)

出0入0汤圆

 楼主| 发表于 2011-11-8 09:54:14 | 显示全部楼层
could you share your  simulink files of proteus and the .hex file ? i will test them on my PC.
thanks a lot .


PS:i need your .hex file because i'm not a gcc user

出0入0汤圆

 楼主| 发表于 2011-11-8 11:32:26 | 显示全部楼层
you have not restart AD convertion again in your interrupt fuction.so i think the 2nd AD convertion can not be auto trigered.give your source code to me via  e-mail,
and i'll test them. e-meil:microhard567@163.com

出0入0汤圆

发表于 2011-11-8 19:51:11 | 显示全部楼层
"you have not restart AD convertion again in your interrupt fuction.so i think the 2nd AD convertion can not be auto trigered."

read the code, watch the wave form and think before you speak.

出0入0汤圆

 楼主| 发表于 2011-11-8 20:37:12 | 显示全部楼层
yes i know your programme is working well.but where did you restart the ad again in INTERRUPUT FUCTION? in which sentance you did that? i really have read your code.
there is my source code(by cvavr),simulink file and .hex file,you can simulink it by avrstudio:点击此处下载 ourdev_693088Y233SL.rar(文件大小:68K) (原文件名:连续自由AD转换实验程序(中断).rar)
thanks again!

出0入0汤圆

发表于 2011-11-8 20:47:49 | 显示全部楼层
"but where did you restart the ad again in INTERRUPUT FUCTION? "

the whole point of a free-running adc is that it runs forever, by itself.

"i really have read your code. "

I am sure you have. but you have no clue how it works.

出0入0汤圆

 楼主| 发表于 2011-11-8 20:54:26 | 显示全部楼层
"the whole point of a free-running adc is that it runs forever, by itself"
yes i argea with you very very much ,and that is what i wanted.but in my code( which was put in upfloar )
the "ADSC" was just set once ,and then it goes to 0,why? i found that throug watching the regester window in
avrstudio.and you can try it again.

出0入0汤圆

 楼主| 发表于 2011-11-8 21:36:45 | 显示全部楼层
好像还真是这么回事,刚才我也学millwood0得方法在中断函数中写入类似语句,用proteus方针了一下,逻辑分析仪显示adsc位还真是1,并不是studio里看到的是0,说明studio的软件方针并没有完全模拟连续转换模式的所有过程,但在proteus里却完全模拟了(难道是studio里因为无法模拟输入电压源造成的?貌似也不是,我在proteus里让ad输入通道开路,结果仍然正确)。为什么studio会这样呢?如果是单次转换他就能很好的模拟啊,我想连续转换和单次转换两者的运行机制应该是差不多的,真的好想弄清楚其中的道理。

下一步要进一步证实,准备烧到板子里试一试。作为新手我想一定要打好基础,把每个问题尽可能的弄清楚。

其实在这之前,我的多通道采集程序已经成功了(加了多次采样去极值平均值滤波),但是不是采用的连续转换模式,而是单次模式,在中断函数里再次手动置位adsc。

说实话,我其实并不觉得连续转换模式有多实用,除非你的任务非常简单,在每次转换周期里能全部完成。但我真的是很想弄清楚连续转换的原理和使用方法,所以才多次发问,谢谢millwood0,是你的程序启发了我,也谢谢马老师的回答。
下一步想好好总结一下连续转换模式的原理和应用方法,以方便想我这样爱钻牛角且悟性不高的新手。

出0入0汤圆

发表于 2011-11-9 01:00:36 | 显示全部楼层
"以方便想我这样爱钻牛角且悟性不高的新手。"

that's called tunnel vision.

you have to open up your mind to other possibilities. remember that bugs are rarely where you think they are.

出0入0汤圆

 楼主| 发表于 2011-11-9 11:31:12 | 显示全部楼层
我并不是说这是bug,只是说studio无法完全模拟连续转换模式,而且这个结论只是我暂时的想法,还有待验证到底是不是studio的问题,就算真的是这样,那么也有可能不是bug,也许是我没设置好,或是该软件设计师其他的考虑,如果真是bug,那么新版的帮助里应该会有说明。我也正在看我使用的版本4.18的帮助里,有没有特别说明不能完全模拟连续模式的问题。就算说了,也不能说那是bug,只能说是缺陷或者不完美(因为proteus可以仿真,说明完全仿真连续模式是可行的)。我个人认为程序的bug应该是程序在意外或特定情况下不能完成预定的功能。

出0入0汤圆

发表于 2011-11-9 22:44:56 | 显示全部楼层
我只花了10分钟时间,证明没有问题。

代码如下(CVAVR):

/*****************************************************
Chip type               : ATmega16
Program type            : Application
AVR Core Clock frequency: 4.000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 256
*****************************************************/

#include <mega16.h>

#define ADC_VREF_TYPE 0x60

int counter;
// ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{
    unsigned char adc_data;
   
    adc_data=ADCH;            // Read the 8 most significant bits of the AD conversion result
    // Place your code here
    counter++;
}

void main(void)
{
    PORTC=0x00;
    DDRC=0x01;                             //PORTC.0控制LED做显示

    // ADC initialization
    // ADC Clock frequency: 500.000 kHz
    // ADC Voltage Reference: AVCC pin
    // ADC Auto Trigger Source: Free Running
    // Only the 8 most significant bits of
    // the AD conversion result are used
    ADMUX=ADC_VREF_TYPE & 0xff;
    ADCSRA=0xAB;
    SFIOR&=0x1F;

    // Global enable interrupts
    #asm("sei")

    ADCSRA |= 1<<ADSC;             //启动第1次的ADC转换

    while (1)
    {
        if (counter >= 20000)
        {
            PORTC.0 = ~PORTC.0;
            counter = 0;
            }
        }
}

直接下到硬件执行,LED开始闪烁了。

如果把ADCSRA |= 1<<ADSC;去掉,LED不会闪烁。
调整 if (counter >= 20000) 后面的数字,比如为10000,LED闪烁的频率加快。

======================================
实际运行结果可以证明AVR芯片本身应该不存在你怀疑ADSC启动的问题,问题还是可能出现在你自己代码本身上(ADC中断中软件延时500ms,已经不符合中断代码尽量短的原则)。
======================================
我基本不用什么AVR STUDIO以及什么proteus的软件模拟。也不太相信这些软件对于相关硬件功能部分的软件模拟结果。比如,AVR一些关键寄存器的2次操作规定必须在4个CLK之内,否则第2次的操作无效,但程序会继续执行下去的。这样的功能,软件很难能模拟正确的结果。简单的东西还会好些,对于比较大的系统,有中断、定时等,时序就非常重要。软件模拟的时序很难做到与真正硬件本身运行的时序相同。可是由于时序的不同,事件发生的时间不同,运行的结果就不一样。

我们编写代码,字面上能看到的是功能实现,具体的操作。但是一个非常重要的东西,时序和时间在代码中是反映不出来的,用汇编,通过每条指令的执行时间计算,还能得到点相关的信息。用C语言这些重要的东西基本都被掩盖了。同样在软件模拟情况下,时序和时间根本做不到与真正的硬件一致的。
==============================================
要测试一个芯片的基本功能,先把多余的东西去掉,用最简单的代码测其最基本的功能是否可以实现。直接到硬件上测试。

如果没有问题,再逐渐把其它的功能加上去,这样比较容易,也能很快的找到问题所在。这是我习惯和推荐的办法

出0入0汤圆

 楼主| 发表于 2011-11-10 00:22:40 | 显示全部楼层
谢谢您的回复。您的计数方法结合led的测试方法给了我启发,是个简单实用的方法。的确,后来我也发现AD的第2次转换实际已经启动了。但今天我又发现一个问题,如果不用中断,那么ad还会自动运转吗?因为进入中断后ADIF会自动清零,首先清零是再次置位的条件。如果不用中断,那么当启动第1次转换后,是不是还需要判断ADIF的值,如果是1(转换完成)就清零?

出0入0汤圆

发表于 2011-11-10 00:56:19 | 显示全部楼层
Using the ADC Interrupt Flag as a trigger source makes the ADC start a new conversion as soon as the ongoing conversion has finished. The ADC then operates in Free Run-ning mode, constantly sampling and updating the ADC Data Register.

The first conversion must be started by writing a logical one to the ADSC bit in ADCSRA.

In this mode the ADC will perform successive conversions independently of whether the ADC Interrupt Flag, ADIF is cleared or not.

以上来自器件手册。

出0入0汤圆

 楼主| 发表于 2011-11-10 01:11:07 | 显示全部楼层
嗯,貌似应该是不需要干预的,改天写个程序实验一下,谢谢老师不厌其烦的回答。还有老师您早点休息啊,注意身体,还不知道您今年年多大了?哈哈

出0入0汤圆

 楼主| 发表于 2011-11-10 18:22:44 | 显示全部楼层
马老师请看这个程序,AD连续转换模式是不是应该启动了(不用中断)?如果是的话,想烧到片子上试一下。通过PB口观察ADCSRA的相关位的值,如ADSC和ADIF,延时主要是防止刷新率太快,STUDIO里面显示不出来变化。
/*****************************************************
This program was produced by the
CodeWizardAVR V2.04.4a Advanced Automatic Program Generator


Project :free running test(ourAVR)
Date    : 2011/11/9
Author  : microhard567
Comments: 演示avr sdudio V4.18 simulater 在模拟连续转换模式
         工作过程方面的缺陷


Chip type               : ATmega16
Program type            : Application
AVR Core Clock frequency: 4.000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 256
*****************************************************/

#include <mega16.h>

#include <delay.h>

#define ADC_VREF_TYPE 0x40


void main(void)
{
// Port A initialization
PORTA=0x00;
DDRA=0x00;

// Port B initialization
PORTB=0x00;
DDRB=0xff;

// ADC initialization
// ADC Clock frequency: 125.000 kHz
// ADC Voltage Reference: AVCC pin
// ADC Auto Trigger Source: Free Running
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0xA5;
SFIOR&=0x1F;

ADCSRA|=(1<<ADSC);


while (1)
      {
       PORTB=ADCSRA;
       delay_ms(5);
      }
}

出0入0汤圆

发表于 2011-11-10 20:16:39 | 显示全部楼层
this is the version without using any interrupt:


int main(void)
{

    // Insert code
        mcu_init();                                                        //reset the mcu
        adc_init(ADCCH_ADC0);                                //adc0 on free running
        //ei();                                                                //enable global interrupt
    while(1) {
            if (ADCSRA & (1<<ADIF)) {
                    ADCSRA|= (ADIF);                        //clear adif by setting it
                    IO_FLP(IND_PORT, IND);                //flip ind pin
                    OUT(ADCH);                                        //output the high 8 bits
                }
    }

    return 0;
}

==============================

here is the output:


(原文件名:atmega16 adc 3.PNG)



"马老师请看这个程序"

you probably want to think about if embedded programming is the right career for you.

出0入0汤圆

发表于 2012-4-1 14:01:12 | 显示全部楼层
很具体的答疑帖,研究中……

出0入0汤圆

发表于 2012-5-17 17:33:30 | 显示全部楼层
看了好久好久......还是没太搞懂。不知道楼主能不能现身说法,跟我这个小菜鸟分享下你的经验想法。目前我也遇到这个问题。

出0入0汤圆

发表于 2012-5-24 08:44:56 | 显示全部楼层
我的經驗,ADC中斷自動轉換:在M48中不能連續自動轉換,需重新開ADC。在M16中卻可以連續轉換,無需重新開ADC。

出0入0汤圆

发表于 2012-6-23 00:52:23 | 显示全部楼层
好贴,标记一下
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-24 06:43

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表