Merhaba
Sonunda işini iyi yapan bir çinliye denk geldim ve sapa sağlam efsane bir pickit3 satın aldım. Alete IPE veya mplapx IDE' si üzerinden veya ccs c üzerinden sonunda bir şeyleri sorunsuzca gönderebiliyorum. Bir kaç kodu denemeye de başladım. PWM ile alakalı bir yer danışacağım. Basitçe örneğim pot üzerinden okunan analogu PWM ile lede gönderiyor. Çalışıyor mu diye sorarsanız evet çalışıyor ama max PWM' e ulaşamıyorum.
float bilgi = 0;
int16 bilgint = 0;
int16 analogRead(int8 ch);
void main()
{
set_tris_b(0x00);
set_tris_c(0x00);
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_16,200,4);
set_pwm1_duty(0);
while(TRUE)
{
bilgi = analogRead(1);
bilgi = bilgi * 200 / 1023;
bilgint = (int16)bilgi;
set_pwm1_duty(bilgint);
}
}
PIC16F877A, 20Mhz
Kullandığım timer2' nin setup kısmını işleme soktuğumuzda PWM'in Hertz'i 388,68Hz olarak çıkıyor.(Sanırım, birde siz bakın)
Başta da belirttiğim gibi 0-5V arası PWM'i süremiyorum sanırım 0-3V arası çalışıyor en üst noktaya ulaşamıyorum. Yardımcı olabilir misiniz?
programın tamamı yok
adc kaç bit belli değil
set_pwm1_duty() içine 16 bit veri gönderirsen hesap değişir
şu anki pwm frekansı 1554 Hz
10 bitlik okuma istiyorsan kod
#include <16F877.h>
#device adc=10
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
//================================
void main()
{
int16 value;
setup_ccp1(CCP_PWM);
// Set the PWM frequency for 245 Hz (with a 4 MHz crystal)
setup_timer_2(T2_DIV_BY_16, 254, 1);
setup_port_a(AN0);
setup_adc(ADC_CLOCK_DIV_8); // Divisor for 4 MHz crystal
set_adc_channel(0);
delay_us(20);
while(1)
{
value = read_adc(); // 10-bit ADC result
set_pwm1_duty(value);
}
}
ADC main.h dosyası içinde zaten 10bit olarak tanımlı.
Sizin kullandığınız "value" değişken int16 benim metottan gönderdiğimde int16 :
int16 analogRead(int8 ch); //Kolaylık olsun diye Arduino'da alışkın olduğum gibi tanımladım
Bu arada bir yanlışlık var 20Mhz kristalde yazdığınız PWM frekansı 1554Hz değil, 1225,49Hz'tir.
Ayrıca halen çözüme ulaşmış değilim :)
Mesajımda gönderme gereği duymadığım kodları paylaşayım :
//Main.h Dosyası
#include <16F874A.h>
#device ADC=10
#use delay(crystal=20000000)
#include <main.h>
float bilgi = 0;
int16 bilgint = 0;
int16 analogRead(int8 ch);
void main()
{
set_tris_b(0x00);
set_tris_c(0x00);
output_b(0x00);
setup_adc(adc_clock_div_32);
setup_adc_ports(ALL_ANALOG);
enable_interrupts(INT_AD);
enable_interrupts(GLOBAL);
setup_timer_2(T2_DIV_BY_1,170,1); //Frekansı değiştirdim şu haliyle 1827,49Hz
setup_ccp1(CCP_PWM);
set_pwm1_duty(0); //Başlangıçta sıfıra sabitledim
while(TRUE)
{
bilgi = analogRead(1); //Oluşturduğum fonksiyondan analog bilgisini alıyorum.
bilgi = bilgi * 170 / 1023; //Aşmaması için 170'e kadar oranlıyorum.
bilgint = (int16)bilgi; //Float'ın virgüllerinden kurtulmak için int16'ya dönüştürüyorum
set_pwm1_duty(bilgint); //Artık bu hesaplanan değeri gönderiyorum
}
}
int16 analogRead(int8 ch)
{
set_adc_channel(ch); //İstenilen kanal ch değişkeni ile gönderiliyor
delay_us(20); //Bekliyoruz
return read_adc(); //Okunan değeri temiz bir şekilde geri döndürüyoruz
}
Adc 10 bit , Pwm de 10 bit.
Pwm den 5 volt alabilmek için 1023 değerini yazmanız gerekiyor.
Adc den okudugunuz değeri 200 ile çarpıp 1023 bölünce, pwm e
yükleyebileceğiniz en büyük değer 200 olur.
aliveli nin verdigi koddaki gibi direk adc değerini pwm e yüklemeniz gerekiyor.
@sadogan PWM görev çevrimi süresi PWM periyodu süresinden daha fazla olmaması gerekmiyor mu? Yani 200 aşmamam gerekmez mi? Ben bu bilgiye dayanarak 10biti sınırladım.
XC8 ile olsa olmaz mı?
RA0(AN0) adc giriş,
RC2(CCP1) pwm çıkışı...
// PIC16F877A Configuration Bit Settings
// 'C' source line config statements
// CONFIG
#pragma config FOSC = EXTRC // Oscillator Selection bits (RC oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = ON // Data EEPROM Memory Code Protection bit (Data EEPROM code-protected)
#pragma config WRT = HALF // Flash Program Memory Write Enable bits (0000h to 0FFFh write-protected; 1000h to 1FFFh may be written to by EECON control)
#pragma config CP = ON // Flash Program Memory Code Protection bit (All program memory code-protected)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.
#include <xc.h>
#include <stdint.h>
#define _XTAL_FREQ 20000000
#define MAX_DUTY 500 - 1
/*
*/
void PWM(unsigned int duty)
{
CCPR1L = duty >> 2; // Set MSB values
CCP1CON = ((duty & 3) << 4) | 0x0C; // set initial duty and set PWM mode bits.
}
/*
*/
void mcuInit(void)
{
PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;
ADCON1bits.PCFG = 0b1110;
TRISA = 0xFF;
TRISB = 0x00;
TRISC = 0x00;
TRISD = 0x00;
}
/*
*/
void pwmInit(void)
{
/*
* http://eng-serve.com/pic/pic_pwm.html
*
* PWM Register Values
* Oscillator Frequency Fosc = 20000000
* Clock Frequency Fclk = 5000000
* PWM Freq = 10000 desired...actual: 10000
* Prescaler Value = 4
* PR2 = 124
* Maximum duty value = 500
* Requested Duty Value = 0
*
* Code Provided AS IS....Use at your own risk!
*/
// be sure to set PWM port as output
T2CON = 0b00000101; // prescaler + turn on TMR2;
PR2 = 0b01111100;
CCPR1L = 0b00000000; // set duty MSB
CCP1CON = 0b00001100; // duty lowest bits + PWM mode
}
/*
*/
void adcInit(void)
{
ADCON1bits.ADCS2 = 0b1;
ADCON0bits.ADCS = 0b11;
ADCON0bits.CHS = 0b000;
ADCON1bits.ADFM = 0b1;
}
/*
*/
unsigned int adcOku(void)
{
unsigned int deger;
ADCON0bits.CHS = 0b000;
ADCON0bits.ADON = 0b1;
__delay_us(20); //akustik zamanı
ADCON0bits.GO_nDONE = 1;
while (ADCON0bits.GO_nDONE == 1);
ADCON0bits.ADON = 0b0;
deger = (unsigned int)(ADRESH << 8) | ADRESL ;
if(deger > MAX_DUTY) deger = MAX_DUTY; //en fazla duty degeri
return deger;
}
/*
*/
void main(void)
{
mcuInit();
adcInit();
pwmInit();
while(1)
{
PWM(adcOku());
}
}
XC8 kullanmakta da sakınca yok lakin merak ediyorum CCS yerine XC8 mi öğrenilmeli mi diye :)
Kodlarınızı da hemen deneyeceğim.
Timer2 yapılandırmasını setup_timer_2(T2_DIV_BY_1,255,1); Bu şekilde değiştirip adc değerini direk yükleyip test etinizmi ?
setup_timer_2(T2_DIV_BY_1,170,1);
Şeklinde bırakarak değeri herhangi bir oranlamaya sokmadan gönderdim ve çalıştı fakat kafam karışık nasıl oldu da 1023'ü kabul etti?
@mehmet Kodunuzu yükledim ve gerekli bağlantıları yaptım fakat çalışmadı.
(http://www.zimagez.com/miniature/ekrangrnts2017-05-2823-41-20.php)
(http://www.zimagez.com/zimage/ekrangrnts2017-05-2823-41-20.php)
(http://www.zimagez.com/miniature/ekrangrnts2017-05-2823-42-25.php)
(http://www.zimagez.com/zimage/ekrangrnts2017-05-2823-42-25.php)
(http://www.zimagez.com/miniature/ekrangrnts2017-05-2823-43-33.php)
(http://www.zimagez.com/zimage/ekrangrnts2017-05-2823-43-33.php)