CCS C ile 16F877A üzerinden Analog Sinyal gönderme

Başlatan halnpx, 11 Aralık 2019, 01:24:24

halnpx

Merhabalar arkadaşlar,

CCS C ile 16F877A PIC Aportundan hem analog sinyal okuma hem de sinyal göndermeye çalışıyorum, farklı pinlerden işlem yapmak istiyorum.
Sinyal okumada problem yaşamıyorum fakat sinyal göndermede sorun yaşıyorum.
Kodu aşağıda paylaşıyorum.
AN7 (E2) yi çıkış olarak ayarlıyorum, diğerleri giriş. AN7 den aldığım sinyal aşağıdaki koda göre 3.75V / 1.25V / 2.5V dan birisi olmalı fakat 0.5V gibi bir değer okuyorum. Çıkıştan voltajı ölçerek kontrol ediyorum.
analog sinyal göndermek için farklı önerileriniz varsa yöntem de değiştirebilirim.

DAC ile sinyal göndermek için hazır bir kod kullanıyorum. Aldığım kod 8 bit için hazırlanmıştı. Ben setup_dac() ve dac_write() içindeki "value" ve "data" yı int16 ya çevirdim, orjinal halinde int8 idi. 10bit DAC kullanmak istiyorum, 0-1023 arası bir range oluyor haliyle.

NOT: RS232 çıkışlarını bilgisayara giden veri için kullanıyorum o portlar meşgul oluyor.

Yardımlarınızı rica ederim.

#include <16F877A.h>            // işlemci kütüphanesinin bilgilerinin olduğu dosya çağırılıyor
#device adc=10
#fuses XT, NOWDT, NOPROTECT, NOBROWNOUT, NOLVP, NOPUT, NOWRT, NODEBUG, NOCPD
#include <math.h>                // Matematik işlemlerin kütüphanesi çağırılıyor
#include <stdlib.h>              // rs232 kodları için kütüphane çağırılıyor
#include <string.h>              // string işlemleri için kütüphane çağırılıyor
#use delay (clock=4000000)      // osilatör hızı ayarlanıyor
#use rs232 (baud=9600, xmit=pin_C6, rcv=pin_C7, parity=N, bits=8, stop=1) // RS232 portu için başlangıç ayarları yapılıyor
#use fast_io(a)                  // Port yönlendirme komutları A portu için geçerli
#use fast_io(b)                  // Port yönlendirme komutları B portu için geçerli
#use fast_io(e)                  // Port yönlendirme komutları E portu için geçerli

//------------------------------------------------------------------------------
//DAC yazdırma için fonk.
// Constants used in setup_dac() are: 
#define DAC_OFF  0
#define DAC_VSS_VDD  0x80
#define DAC_VREF_VDD  0x81
#define DAC_VSS_VREF  0x84
#define DAC_VREF_VREF 0x85
#define DAC_VSS_FVR  0x88
#define DAC_VREF_FVR  0x89
// The following may be OR'ed in with the above using |
#define DAC_OUTPUT2  0x10
#define DAC_OUTPUT    0x20

#byte DAC1CON0 = 0x118 
#byte DAC1CON1 = 0x119 

void setup_dac(int16 value) 
{ 
DAC1CON0 = value; 
} 

void dac_write(int16 data) 
{ 
DAC1CON1 = data; 
} 

//------------------------------------------------------------------------------
  // Bütün değişkenler burada tanımlanıyor
  int1 kntrl=0;
  const int8 delay_1=150;
  const int8 delay_2=150;
  const int8 delay_3=150;
  const int8 err=3;
  int16 position, position_target, target_num, dev;
  int16 signal;

  char msg_send[40];
  char msg_rcvd[35];
//------------------------------------------------------------------------------
#int_rda  // RX ucuna veri gelince meydana gelen kesme
void serial_read ()
{
  disable_interrupts(int_rda); // int_rda kesmesini pasif yap
  
      for(i=0;i<rl;i++){
        msg_rcvd[i] = getc();
      }

}
//------------------------------------------------------------------------------
void channel_read(){
  // ADC veri okuma
  set_adc_channel(5);
  delay_us(delay_1);
  position=read_adc();
  delay_us(delay_1);
}
//------------------------------------------------------------------------------
void channel_write(){
  // rs232 üzerinden bilgisayara status bilgileri gönderiliyor
  //......
  printf("%s \r\n", msg_send);
}
//------------------------------------------------------------------------------
void Pdrive(){
  position_target = target_num;
      while(abs(-position+position_target)>err){
        
 dev = -position+position_target;
        
 if(sgn(dev)>0){
                signal = 768;    // 3.75V a denk gelmesi bekleniyor
                }else{
                signal = 256;    // 1.25V a denk gelmesi bekleniyor
                }
                
                channel_read();
 
        }
 signal=511        // 2.5V a denk gelmesi bekleniyor
        set_adc_channel(7);
        delay_us(delay_2);
        dac_write(signal);
        delay_ms(delay_3);

}
//------------------------------------------------------------------------------
int sgn(double v) {
  if (v < 0) return -1;
  return 1;
}
//------------------------------------------------------------------------------
void main()
{

  setup_adc_ports(ALL_ANALOG);              // A0, A1, A2, A3, A4, A5, E0, E1, E2
  setup_adc(ADC_CLOCK_DIV_32);              
  setup_dac(DAC_VSS_VDD | DAC_OUTPUT);
  setup_psp(PSP_DISABLED);
  setup_spi(SPI_SS_DISABLED);
  setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
  setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
  setup_timer_2(T2_DISABLED,0,1);
  setup_comparator(NC_NC_NC_NC);
  setup_vref(FALSE);

  // Program kodları başlıyor
  
  set_tris_a(0x1F);      // A0-A4 giriş yapılıyor, AN1 - AN4 arası giriş yapılıyor
  set_tris_e(0x03);      // E0-E1 giriş, E2 çıkış yapılıyor, AN5 & AN6 giriş, AN7 çıkış yapılıyor
  set_tris_b(0x00);      // B portu çıkış yapılıyor
  output_b(0x00);        // B portunun çıkışları sıfırlanıyor
  
  output_high(PIN_B7);    // Cihazın çalıştığını gösteren led yakılıyor
  
  enable_interrupts(INT_RDA);
  enable_interrupts(GLOBAL);
  
  While(1){
  
  channel_read();    // analog sinyal okunuyor
  channel_write();    // okunan analog değer TX üzerinden bilgisayara gönderiliyor
  
  //Bazı kodlarla gelen rx kesmesi mesajının içinden bilgi (target_num bilgisi vs) çekiliyor, kntrl=0/1 yapılıyor
  
  if(kntrl==true){
  Pdrive();
  kntrl=false
  }
  
  enable_interrupts(INT_RDA);

  }
}

madpic

16f877 de dac modülü yok yanılmıyorsam . başka bir model pic olabilirmi acabaa.
İlla f877 ile olacaksa da  pwm modülü ile çok hassas olmasada
birkaç pasif elemanla halledilebilir.

halnpx

#2
Merhabalar,

Ben aslında pic'te port diagramında AN tanımlarını görünce ve analog okumayı da sorunsuz yapınca analog çıkış  da yapabileceğim fikrine kapılmıştım. Siz belirtince datasheet'e bakayım dedim ve tataaaa, analog özelliği sadece okuma içinmiş  :-[  zavallı ben.

Bu durumda ne yapabilirim, önerileriniz nedir?
Hızlıca bakınca MCP4921 gibi bir entegre ile TX ucundan çıkacak bir değeri (anladığım 0-1023 gibi, yanlış anlamış da olabilirim) analog 0-5V arası çıkışa çevirebiliyor. rs232 pinlerini bilgisayarla iletişim için kullandığımdan aynı TX portunu pic'in kontrol ettiği bir switch'e bağlamak mantıklı bir çözüm olabilir mi?

veya direk pinlerden dijital çıkış alıp harici başka bir DAC kullanmak, en az 10-bit ihtiyacım var. PWM ile 10-bit lik dönüşüme eşdeğer bir (çözünürlük olarak) sonuç alabilir miyim? PWM yöntemiyle elde etmek için yardımcı olacak önerileriniz varsa deneyebilirim, olacak gibi değilse bir de oralarda debelenmeyeyim  ;)
işe yarar bir çözüm için önerileriniz ne olur?

Teşekkürler,

ziyaretci

Aynı Tx'i kullanabilirsiniz. Fakat PC tarafını bu durum hakkında bilgilendirmeniz gerekir yanlış veri gitmemesi adına. Ya da Tx hattı için harici bir kanal oluştirabilirsiniz. 4x1 MUX ya da basitçe mantıksal kapılarla oluşturabilirsiniz. Eleman kullanmak istemiyorsanız, boş herhangi iki pine yazılımsal port atayabilirsiniz.

DAC için harici entegreler var. Ben bir tane 8 bitlik MCP41010 biliyorum, dijital 10k pot olarak kullanılıyor.

Daha hassas yani 10 ve üstü bitlik bir DAC çözümü için yazılımsal bir PWM oluşturarak çıkışta uygun bir RC kullandığınızda istediğiniz çözünürlükte bir analog sinyal elde edebilirsiniz. Belli bir noktaya kadar tabi. Aslında kastettiğimin literatürdeki adı "Buck(azaltan) Converter". Bunun için boş bir pin ve boş bir timer donanımı gerekiyor. Birde anahtarlama elemanı.


sadogan

16F877 di tarih oldu.
Yeni nesil serilerde 5bit ve 8 bit dac olan modeller var.
PIC16F1789 gibi.

halnpx

Yorumlarınız için teşekkürler,

harici entegreyi deneyeceğim sanrım daha hızlı olacak. Bir sonraki çalışmamda baştan bütün parçaları dikkatli değerlendirecem, amatörlük  :)