16f877 5 kanal ADC sorunu

Başlatan solidus, 23 Nisan 2010, 16:25:23

solidus

Merhaba arkadaşlar, Aşağıdaki kodlarla 877 nin adc sinden faydalanarak 5 ayrı kanalda voltaj takibi yapmaya çalışıyorum. 0,1,ve 2. bitler çalışıyor ama 4 ve 5. bitlerden sonuç alamıyorum LCD'de görünen değer hep sıfır. Hata nerde acaba ?

TRISA=255
OPTION_REG.7=0 
ADCON1=%10100000

For A = 1 To 10 
ADCIN 0,LO_in                      '0 nolu kanaldan Analog değeri oku ve R_in değişkenine aktar. 
TOTAL_LO=TOTAL_LO+LO_in 
NEXT A
LO_VOLT=000
LO_in=LO_in+2                      
LO_VOLT=(LO_in */ 12500)/10         'R_in ile 12500 ü 32 bit olarak çarp ve 10'böl 
ModLO=LO_VOLT // 10             'R_VOLT=R_VOLT  MOD  10 
LO_VOLT=LO_VOLT/10
IF LO_VOLT>=21 THEN
HIGH LOTB_OK
ELSE 
HIGH LOTB_NO
ENDIF 
LCDOUT $FE,$80,"1=",DEC LO_VOLT , " VDC "

For B = 1 To 10 
ADCIN 1,LI_in                      '1 nolu kanaldan Analog değeri oku ve R_in değişkenine aktar. 
TOTAL_LI=TOTAL_LI+LI_in 
NEXT B
LI_VOLT=000
LI_in=LI_in+2                      
LI_VOLT=(LI_in */ 12500)/10         'R_in ile 12500 ü 32 bit olarak çarp ve 10'böl 
ModLI=LI_VOLT // 10             'R_VOLT=R_VOLT  MOD  10 
LI_VOLT=LI_VOLT/10
IF LI_VOLT>=21 THEN
HIGH LINB_OK
ELSE 
HIGH LINB_NO
ENDIF 
LCDOUT $FE,$8B,"2=",DEC LI_VOLT , " VDC  "

For C = 1 To 10 
ADCIN 2,CTR_in                      '2 nolu kanaldan Analog değeri oku ve R_in değişkenine aktar. 
TOTAL_CTR=TOTAL_CTR+CTR_in 
NEXT C
CTR_VOLT=000
CTR_in=CTR_in+2                      
CTR_VOLT=(CTR_in */ 12500)/10         'R_in ile 12500 ü 32 bit olarak çarp ve 10'böl 
ModCTR=CTR_VOLT // 10             'R_VOLT=R_VOLT  MOD  10 
CTR_VOLT=CTR_VOLT/10
IF CTR_VOLT>=21 THEN
HIGH CTR_OK
ELSE 
HIGH CTR_NO
ENDIF 
LCDOUT $FE,$C0,"55555CTR= ",DEC CTR_VOLT , " VDC     " 

For D = 1 To 10 
ADCIN 3,RI_in                      '3 nolu kanaldan Analog değeri oku ve R_in değişkenine aktar. 
TOTAL_RI=TOTAL_RI+RI_in 
NEXT D
RI_VOLT=000
RI_in=RO_in+2                      
RI_VOLT=(RI_in */ 12500)/10         'R_in ile 12500 ü 32 bit olarak çarp ve 10'böl 
ModRI=RI_VOLT // 10             'R_VOLT=R_VOLT  MOD  10 
RI_VOLT=RI_VOLT/10
IF CTR_VOLT>=21 THEN
HIGH RINB_OK
ELSE 
HIGH RINB_NO
ENDIF 
LCDOUT $FE,$9F,"8=",DEC RI_VOLT , " VDC "

For E = 1 To 10 
ADCIN 4,RO_in                      '4 nolu kanaldan Analog değeri oku ve R_in değişkenine aktar. 
TOTAL_RO=TOTAL_RO+RO_in 
NEXT E
RO_VOLT=000
RO_in=RO_in+2                      
RO_VOLT=(RO_in */ 12500)/10         'R_in ile 12500 ü 32 bit olarak çarp ve 10'böl 
ModRO=RO_VOLT // 10             'R_VOLT=R_VOLT  MOD  10 
RO_VOLT=RO_VOLT/10
IF CTR_VOLT>=21 THEN
HIGH ROTB_OK
ELSE 
HIGH ROTB_NO
ENDIF 
LCDOUT $FE,$94,"9=",DEC RO_VOLT , " VDC   "
Kimine göre kralım kimine göre yalanım… Herkes rahatına baksın, ben adamına göre adamım..

ete

Programda bazı eksikler görüyorum. Sorunun kaynağı bunlar olabilirmi?
Olabilirmi diyorum çünki programın tamamını buraya koymadığın belli oluyor.
Her neyse ben gördüklerimi söyleyeyim.

Değişken tanımlamalarını göremiyorum. Kullandığın değişkenler byte cisnidenmi word cinsindenmi belli değil.
Sorunun birinci kaynağı word olması gereken bir değişkeni byte cinsinden kullanmış olabilirsin.

ikincisi,  ADC okumasının kaç bit yapılacağı belirlenmemiş.

Programa aşağıdaki satırları ilave et.

DEFINE ADC_BITS  8    ' ADCIN çözünürlüğü (Bit)
DEFINE ADC_CLOCK 1    ' ADC clock kaynağı (Fosc/8)
DEFINE ADC_SAMPLEUS 3 ' ADC örnekleme zamanı (uSec)

üçüncüsü,  ADCON1 registeri 7 bitini 1 yapmışsın bu biti sıfır yap.
ADCON1=%00100000

Bu aşamadan sonra doğru ADC okuması yapabilirsin.
ADC okuma kısmında işlevini anlayamadığım bazı satırlar mevcut. Mesela,
TOTAL_LO=TOTAL_LO+LO_in   satırı ne işe yarıyor. Komut şeklinden sanki 10 adet ADC oku ve bunun ortalamasını al
şeklinde birşey yapacağın anlaşılıyor ama bir daha TOTAL_LO değişkenini bir yerlerde kullanmamışsın.
Şayet bunu kullanacak isen döngüye başlamadan evvel TOTAL_LO değerini sıfırlaman gerekir.
Aksi halde toplam hep yanlış değer alır. Daha doğrusu TOTAL_LO değeri 65535'i aşıncaya kadar sayılar toplanmaya devam eder.

LO_VOLT=000  şeklinde bir eşitleme Basicde yoktur. Komut çalışır ama sonraki iki adet sıfır dikkate alınmaz. Tek sıfır yeterlidir.

LO_VOLT=(LO_in */ 12500)/10 şeklinde bir komut yerine   LO_VOLT=(LO_in */ 1250) yazılması aynı sonucu verecektir. Boşuna büyük sayı ile çarpıp sonra 10 bölmek yersiz. Tabiiki düşündüğün başka bir şey varsa onuda bilmek isterim.
Örnek vermek gerekir ise  Lo_in=129 iken her iki türlü hesap yapalım,
129 * 12500/256= 6298 bulunacaktır. Bunu 10 a bölersek Lo_Volt=629 bulunur
Şimdi aynı örneği 10 bölmeden yapalım yani 1250 ile çarparak yapalım.
129 x 1250 /256 = 629 bulunacaktır. Gördüğün gibi zaten bu değer üzerinden mod alıp  62 ve 9 değerlerini elde ediyorsun.
Sonuç değişmiyor gördüğün gibi.

Ete





Bilgi hazinedir paylaştıkça büyür.            http://etepic.com

solidus

Merhaba ETE hocam,
8 kanal 10 bit ADC için ADCON1=%10100000 yazdım yanlış değil sanırım. Dediğiniz gibi 10 adet ölçüm ve ortalama alma yolunu seçtim. Tavsiyeniz üzere LO_VOLT=(LO_in */ 1250) şeklinde kullandım. Sonuçta dediğiniz gibi bi değişiklik olmadı Matematik :) Dediğiniz gibi programın tamamını vermedim. Ama 5 kanaldada değişken durumu aşağıdaki gibi. ADC' nin kaç bit olacağı yazlıydı aşağıdaki gibi ben kopyalamayı unutmuşum..

DEFINE ADC_BITS     10  ' Set number of bits in result
DEFINE ADC_CLOCK    3   ' Set clock source (rc = 3)
DEFINE ADC_SAMPLEUS 50' Set sampling time in microseconds

LO_IN         VAR WORD  'ADC'den okunan digital verilerin tutulacağı etiket 
LO_VOLT     VAR WORD  'Hesaplama işleminde kullanılacaklar değişkenler 
ModLO        VAR BYTE  'MOD alma (//) (kalan bulma değişkenleri) 
LO               VAR BYTE 
TOTAL_LO   VAR WORD  'Örnekleme sayısını fazlalaştırmak için
Kimine göre kralım kimine göre yalanım… Herkes rahatına baksın, ben adamına göre adamım..

ete

#3
Ben 8 bit olduğunu tahmin etmiştim.
Peki bu durumda makismum voltaj değeri ne olacak onuda bildirirsen daha uygun olacak.
Benim hesabıma göre 500V (maksimum) ölçeceksin ama bir kezde senden duymak isterim.

Bu durumda Adcon1 registeri 7. bitini 1 yapacaksın bu doğru.
Programın ADC okuma kısmınıda aşağıdaki şekilde değiştir;

TOTAL_LO=0
For A = 1 To 10
ADCIN 0,LO_in                      '0 nolu kanaldan Analog değeri oku ve R_in değişkenine aktar.
TOTAL_LO=TOTAL_LO+LO_in+1
NEXT A
LO_in=Total_lo/10       
LO_VOLT=(LO_in */ 1250)        'R_in ile 12500 ü 32 bit olarak çarp ve 10'böl
ModLO=LO_VOLT // 10             'R_VOLT=R_VOLT  MOD  10
LO_VOLT=LO_VOLT/10
IF LO_VOLT>=21 THEN
HIGH LOTB_OK
ELSE
HIGH LOTB_NO
ENDIF
LCDOUT $FE,$80,"1=",DEC LO_VOLT ,",",dec modlo, " VDC "

Çalışmıyor deme sakın zira denedim 0-500V arası ölçüm yapıyor bu şekilde.

Diğer ADC kanallarınıda bu şekilde düzenlersin.

Ete

Bilgi hazinedir paylaştıkça büyür.            http://etepic.com

solidus

ETE Hocam,
Aslında tüm okumalar 0-50 VDC aralığında yapılacak. Ancak sorun adc kanallarından ilk 3 tanesinden okuma yapabiliyorum fakat 4 ve 5. kanaldan okuma yapamıyorum. Buna çözüm bulamadım..
Kimine göre kralım kimine göre yalanım… Herkes rahatına baksın, ben adamına göre adamım..

ete

#5
Hepsi çalışıyor denedim.
AN4 pini 7 nolu pin (PortA.5) ve An5 pini ise 8 nolu pin (PortE.0) dır. Şaşırmayasın.

Okunan ADC değerinin istenilen bir seviye okumasın adapte edilmesi için genel mantık aşağıdaki şekildedir.
Maksimum okuma senin örneğine göre 50V olsun.
Okunan ADC değerleri kaç adettir 0-1023 arasında toplam 1024 adettir. O halde birim okumaya denk gelecek Voltaj değeri
50/1024 bölümünden  0,048828125 olarak hesaplanır. Sonuçta elde edeceğimiz rakam 256 ya bölünmüş değer olacağı için bu sayıyı 256 ile çarparız.    0,048828125  * 256 =12,5  bulunacaktır. Çıkan sayının tamamını hesaplamada kullanabilmemiz için virgülden kurtarmamız gerekecektir. O halde sayıyı 10 ile çarpar çıkan sonucu sonradan 10'a böleriz.
Bu durumda elde edeceğimiz sonuç yine tam sayı olacaktır. Halbuki virgülden sonra tek hane hassasiyetide istiyoruz. O  halde bu sayıyı bir kez daha 10 ile çarparız ve sonucu bu sefer 100 e (önce 10 a bölüp kusurat hesabını yapmamız sonra tekrar 10 a bölerek esas bulacağımız sayıyı bulmamız gerekir) bölmemiz gerekecektir.
Şimdi bir örnek yapalım.

Okunan ham değer 511 olsun Buna +1 ekliyoruz sonra hesabımızı yapıyoruz.
Volt=(512 */1250)/10=250 bulunacaktır.
Kusurat=Volt//10 = 0 bulunacaktır.
Volt=Volt/10 = 25 bulunacaktır.

Umarım anlaşılmıştır.

Ete
Bilgi hazinedir paylaştıkça büyür.            http://etepic.com

solidus

Hocam çok özür dilerim. Tamamen benim hatam 4. kanalı seçerken hata yapmışım. Şemadan düzelltim sorun çözüldü. Okumadan ezbercilik yapmışım.
Kimine göre kralım kimine göre yalanım… Herkes rahatına baksın, ben adamına göre adamım..

solidus

#7
Hocam byte tipi bir değişken belirleyip değerini her arttırdığımda farklı bir döngüye dallandırmaya çalıştım ama finalde takıldım. Mesela, değişkenin değeri 8 olduğunda son adlı etikete dallanmasını istiyorum ama bu etikete gitmiyor program. Voltaj ölçüm kısmında sıkışıp kalıyor. Ne ileri ne de geri gidiyor. (Butonlara basmanın bi faydası olmuyor.) Unuttuğum bişey mi var acaba ?  ADC işlemi sona erdiğinde bir biti kontrol ediyorduk yanlış hatırlamıyorsam. Onunla bi ilgisi olabilirmi ? İlgili isis çizim ve kodlar ekteki linkte.İncelem şansınız olursa sevinirim.

http://www.dosya.tc/DOSYA.rar.html


Upload server değiştirildi...
Kimine göre kralım kimine göre yalanım… Herkes rahatına baksın, ben adamına göre adamım..

ete

Verdiğin dosyayı yüklemeye çalıştım ama farklı dosya çıkıyor. Önce Dosya.rar diyor ama sonra php uzantılı bir şey gelmeye çalışıyor o nedenle yüklemedim.

Genelde ADC okumalarında sabit tek rakam yerine aralık vermek en uygunu olur. Bu şekilde herhangi bir nedenle o rakama ulaşılamaz ise aralık mutlaka gerçekleşir ve dallanma olur yoksa sorun çıkabilir. Onu bir dene istersen.

En azında okumadan sonra dallanmakistediğin yer için değeri sabit olarak ver bakalım oraya dallanıyormu.

Ete
Bilgi hazinedir paylaştıkça büyür.            http://etepic.com

solidus

Upload serveri değiştirdim hocam.
Kimine göre kralım kimine göre yalanım… Herkes rahatına baksın, ben adamına göre adamım..

ete

Bilgi hazinedir paylaştıkça büyür.            http://etepic.com

solidus

Kimine göre kralım kimine göre yalanım… Herkes rahatına baksın, ben adamına göre adamım..

ete

#12
Link sağlam dosyayı yükledim. Programa baktım ancak bahsini ettiğin yönlendirme satırlarını göremedim.

Bu arada ADC okumalarını doğru yapayım dedim fakat baktımki donanım doğru değil.
Voltaj girişlerinde gerilim bölücü kullanmışsın ama o şekilde bir bölücü ile bu olmaz.
Maksimum voltaj 50 V ise Bu voltajı 10'a bölecek bir gerilim bölücü kullanman gerekir. Böylece 50V da pic ADc girişine 5V gelecektir.

Seri direncin olan 100K yerine 9K direnç takarsan bölücü doğru şekilde çalışabilmektedir. Tabiiki 9K standart değil ama bir ayarlı direnç ile kolaylıkla ayarlanabilir.

Ete
Bilgi hazinedir paylaştıkça büyür.            http://etepic.com

solidus

EMERGENCY:
If ILERI=1 Then
A=A+1
EndIf
While ILERI=1
Wend

If GERI=1 Then
A=A-1
EndIf
While GERI=1
Wend

If A=0 Then GoSUB SEC_EMER
If A=1 Then GoSUB KARTRIC_EMER
If A=2 Then GoSUB M32_EMER
If A=3 Then GoSUB PROB_EMER
If A=4 Then GoSUB OVRRD_EMER
IF A=5 THEN GOSUB KONT_EMER
If A=6 Then GoSUB BAS_EMER
If A=7 Then GoSUB OLCME
IF A=8 THEN GOTO SON

GoTo EMERGENCY

Kodun bu kısmında  A değişkeninin değerini butona her basıldığında arttırıyorum ve bu şekilde dallanmaları sağlıyorum. A=7 koşulu sağlanana kadar her şey normal fakat A=8 olduğunda program  ölçme etiketinden çıkarak son etiketine gitmeli ama olmuyor.
Kimine göre kralım kimine göre yalanım… Herkes rahatına baksın, ben adamına göre adamım..

ete

Sebebi gayte basit.
Ölçme kısmında bir hata yapmışsın,
For A = 1 To 10
ADCIN 0,LO_in                   '0 nolu kanaldan Analog değeri oku ve LO_in değişkenine aktar.
TOTAL_LO=TOTAL_LO+LO_in+1
NEXT A
şeklinde bir döngü kullanmışsınve döngü değişkenin "A" dolayısıyla bu döngü sonunda A nın gerçekdeğeri kayboluyor. 7 den birden 12 ye atlıyor tabiiki ve istediğin olmuyor.

Ete
Bilgi hazinedir paylaştıkça büyür.            http://etepic.com