Микроконтролери и електроника
http://mcu-bg.com/mcu_site/

Проблем при АЦП на ПИК16Ф887.
http://mcu-bg.com/mcu_site/viewtopic.php?f=7&t=7077
Страница 1 от 1

Автор:  misho [ Пон Авг 24, 2009 8:05 pm ]
Заглавие:  Проблем при АЦП на ПИК16Ф887.

Привет,
Искам чрез потенциометър свързан между Vdd, Vss и RA0 да измервам входното напрежение, след това да го изведа на PC през RS232, като измерване да се прави при всяко препълване на таймера. За опорни напрежения ползвам Vdd и Vss. Проблемът е, че от АЦП-то получавам безмислици. Използвам CCS компилатор в MPLAB среда. Приложил съм кода.

#include <16F887.h>
#include <stdlib.h>

#use fast_io(A)
#use fast_io(C)
#use delay(clock=4000000)
#use rs232(baud = 9600, xmit = PIN_C6, rcv = PIN_C7)
#FUSES INTRC,NOWDT,NOPUT,NOMCLR,NOPROTECT,NOCPD,NOBROWNOUT,NOIESO,NOFCMEN,NOLVP
#byte ADCON1 = 0x9F

unsigned int adc_conversion = 0;
int flag;

void init_io()
{
SET_TRIS_A(0x01);
OUTPUT_B(0x00);
SET_TRIS_C(0x80);
OUTPUT_D(0x00);
OUTPUT_E(0x00);
}

void init_adc()
{
SETUP_ADC_PORTS(sAN0 | VSS_VDD);
SETUP_ADC(ADC_CLOCK_DIV_8);
SET_ADC_CHANNEL(0);
READ_ADC(ADC_START_ONLY);
}

#INT_RTCC
void timer0_interrupt_service()
{
adc_conversion = READ_ADC(ADC_READ_ONLY);
flag = 1;
READ_ADC(ADC_START_ONLY);
}

void main()
{
char mV[20];
unsigned long value = 0;
flag = 0;
init_io();
setup_uart(9600);
init_adc();
ADCON1 = 0x80;
SETUP_TIMER_0(RTCC_INTERNAL | RTCC_DIV_256);
ENABLE_INTERRUPTS(GLOBAL);
ENABLE_INTERRUPTS(INT_RTCC);
while(1)
{
if (flag == 1)
{
flag = 0;
value = adc_conversion*5000/1024;
itoa(value,10,mV);
puts(mV);
putc(0x0D);
}
}
}

Автор:  ToHu [ Пон Авг 24, 2009 8:41 pm ]
Заглавие: 

ммм малко разхвърляно ми седи ето как става :

тва ти е в хедър

#include <16F877A.h>
#device adc=8

#FUSES NOWDT //No Watch Dog Timer
#FUSES
#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

тва ти е кода, реално кода който имаш да напишеш е буквално 5 реда

#include "C:\MyDocuments\Isdelia\test\877.h"

#bit start = 0x1F.2

int1 AD_OK;
int result;


#int_RTCC
RTCC_isr()
{
start = 1;
}

#int_AD
AD_isr()
{
AD_OK=true;
result = read_adc(adc_read_only);

}



void main()
{
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_32);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_RTCC);
enable_interrupts(INT_AD);
enable_interrupts(GLOBAL);

AD_OK=false;

while(true)
{
if(AD_OK)
{
AD_OK=false;
printf("%d \r\n", result);
}

}
}

Автор:  ToHu [ Пон Авг 24, 2009 8:54 pm ]
Заглавие: 

Ама така като ти гледам кода май нещо не ти е съвсем ясно. Гледам че в прекъсването от таймера първо четеш ADC а след това го пускаш, това не е правилно, ти не можеш да знаеш дали е приключило конвертирането когато влизаш в това прекъсване, освен ако не е достатъчно дълго времеро за запълване на тоя таймер. Ако ще четеш така би трябвало да проверяваш първо дали е свършило.
После с това конвертиране което правиш ..... много омотано, имаш printf функция. И не на последно място в CCS израз от сорта result*5000/1024 не е сигурно какъв резултат ще даде ....

п.с. всъщност умношено по 5000 е нормално да връща глупости, явно си РС програмист, int e 8 битово, и освен това по този начин трябва да декларираш много голяма променлива, тъй като и 16 битово ще се препълни при 1024*5000, кеото ще е факт при 5 В на входа....

иии последно, по тоя начин не можеш да мериш захранващото напрежение, тъй като то ти е и опорно, за да мериш захранващото трябва да имаш ИОН

Автор:  RM [ Пон Авг 24, 2009 10:19 pm ]
Заглавие: 

Код:
...................................... а в .h файла трябва да има         #device adc=10
#BYTE ADRESL=0x9E
#BYTE ADRESH=0x1E
#int_AD
void  AD_isr(void)
{
    setup_adc(ADC_CLOCK_INTERNAL);
    set_adc_channel(0);
}

long create2word(long tempval){
char resulthi,resultlo;
      resulthi=ADRESH;   
      resultlo=ADRESL;

      tempval=resulthi<<8;
      tempval=tempval|resultlo;   
      return tempval;
                     }

...............................

   read_adc(ADC_START_ONLY);
   sleep();
   tempval=Read_ADC(ADC_READ_ONLY);
   valuebin_tmp=create2word(tempval);

................................................. anywhere in mine();
setup_adc_ports(sAN0|VSS_VREF);
setup_adc(ADC_CLOCK_INTERNAL);
enable_interrupts(INT_AD);


Така става по добре, но да използва поне стабилно външно Vref
Почва да ме хваща яд на CCS и на PIC ..... :evil: кат чели не са толко черни :evil:

Автор:  misho [ Пон Авг 24, 2009 11:14 pm ]
Заглавие: 

Благодаря за отговорите. Както сте разбрали съм начинаещ и имам много да уча. Като се снабдя с външно Vref ще пробвам пак.

Автор:  ToHu [ Вто Авг 25, 2009 11:46 am ]
Заглавие: 

RM.... абе може и да не се пише толкова сложно, CCS в това отношение е малко умен да му се невиди, може да си декларираш int16 или каквото там искаш и да четеш с read_adc() директно 10 битова стойност, но трябва да си казал на компилатора че ще ползваш 10 битово ADC, при менима директива че ще е 8 битово. По принцип за да има стабилно отчитане е хубаво да се осреднят няколко отчета, т.е. това което съм написал ще стане нещо от сорта :

#int_AD
AD_isr()
{
temp+=read_adc(adc_read_only); // тук се натрупват няколко отчета в променлива temp
count++;
if(count>3) // те тук си правиш проверка колко отчета си направил
{
count=0;
AD_OK=true;
result = temp>>2; // дели се на 4, тъй като натрупвам 4 отчета, т.е. средно аритметично
temp=0;
}

така имаш усреднение от 4 отчета, това разбира се може да се напише по различни начини, показвам принципа а не стил на писане, въпреки че аз предпочитам да е точно така вместо четенето да е в else на IF-а.

После преобразуването в mV най добре да стане с нещо от сорта :

(result*39)>>3, това ако работи с 16 битово число, 39 ~ 5000*8/1024 , не е само 5000 / 1024 за да се запази точността. Ако работи с 32 битово число вече може да е още по точно, трябва да прецени колко му трябва, като това всъщност зависи не само от това с каква точност смята а и от разредноста на ADC-то, от неговата грешка и от точноста на опорното напрежение.

п.с. относно CCS е перфектен за процесорчето за кеото е създаден, от друга страна пък това процесорче е перфектно за някои нужди, така че си имат своето местенце ..... на мен силабс ми допадат, обаче колкот и да си кривя душата няма начин да напишеш толкова проста програмка за толквоа кратко време, докато инициализираш серийния, докато се сетиш кои бяха регистрите, щото там не мога фи запомня на изсут и тва си е ... та си има предимства, просто процесорче за прости неща ...

Страница 1 от 1 Часовете са според зоната UTC + 2 часа [ DST ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/