| Микроконтролери и електроника 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 ] | |||||||||
| Заглавие: | ||||||||||
Така става по добре, но да използва поне стабилно външно Vref Почва да ме хваща яд на CCS и на PIC ..... |
||||||||||
| Автор: | 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/ |
|