PIC Vietnam

PIC Vietnam (http://www.picvietnam.com/forum/index.php)
-   Các ngôn ngữ lập trình khác (CCS C, HT PIC,...) (http://www.picvietnam.com/forum/forumdisplay.php?f=12)
-   -   CCS C for PIC16F877A (http://www.picvietnam.com/forum/showthread.php?t=357)

necati 19-05-2007 03:29 AM

frequencymeter
 
Code:

#include <16f628.H>
#use  delay(clock=4000000)//
#fuses NOPROTECT,NOWDT,PUT,noBROWNOUT,noLVP,NOMCLR,xt
#BYTE    PORT_A=0X05
#BYTE    PORT_B=0X06
/***entegreterbiyecisi@yahoo.com***//***entegreterbiyecisi@yahoo.com***/
// LCD STUFF
#define LCD_RS      PIN_b0
#define LCD_EN      PIN_b1
#define LCD_D4      PIN_b2
#define LCD_D5      PIN_b3
#define LCD_D6      PIN_b4
#define LCD_D7      PIN_b5
#define FIRST_LINE  0x00
#define SECOND_LINE 0x40
#define CLEAR_DISP  0x01
#define CURS_ON    0x0e
#define CURS_OFF    0x0c
/***entegreterbiyecisi@yahoo.com***/
#use standard_io ( a )
#use standard_io ( b )
/***entegreterbiyecisi@yahoo.com***/
// proto statements
void LCD_Init        ( void );
void LCD_SetPosition ( unsigned int cX );
void LCD_PutChar    ( unsigned int cX );
void LCD_PutCmd      ( unsigned int cX );
void LCD_PulseEnable ( void );
void LCD_SetData    ( unsigned int cX );
/***entegreterbiyecisi@yahoo.com***//***entegreterbiyecisi@yahoo.com***/
/*************************entegreterbiyecisi@yahoo.com******************************/
int32 ab=0,hz=0;
int1 stept_say=0,data_bitti=0,step,aa=0;
int16 sayi=0,tr=20;
/*************************entegreterbiyecisi@yahoo.com******************************/
#int_timer1
tas(){
ab++;
}
#int_timer0
sn(){sayi=0;
 set_timer0(61);//(255-60)*195*20=1000000us=dahili 1sn icin
 if(tr){ tr--;}
 else{delay_us ( 698 );
      output_low(pin_a0);
      disable_interrupts (global);
      disable_interrupts(int_timer0);
      disable_interrupts(int_timer1);
      sayi=get_timer1();
      aa=1;
      hz=sayi+(65536*ab);
      tr=20;
                              }}
/*************************entegreterbiyecisi@yahoo.com******************************/
  void main() {

      setup_timer_1(t1_external|t1_div_by_1);
      setup_timer_0 (RTCC_INTERNAL|RTCC_DIV_256);
      enable_interrupts(int_timer0); // timer0
      enable_interrupts(int_timer1);
      enable_interrupts(global);
      lcd_init();
      SET_TRIS_A(0b00100000);
      SET_TRIS_B(0b11000000);
      set_timer0(61);
      set_timer1(0);

      LCD_SetPosition(first_LINE+0);
      printf(lcd_putchar,"\NECATi KIYLIOGLU ");
      LCD_SetPosition(second_LINE+1);
      printf(lcd_putchar,"\ 0532 613 65 87");
      delay_ms (500);
      LCD_PutCmd ( CLEAR_DISP );
      sayi=0;
      hz=0;
/*************************entegreterbiyecisi@yahoo.com******************************/
while(true){
  if(aa==1){
      //LCD_PutCmd ( CLEAR_DISP );
      LCD_SetPosition(first_LINE+0);
      printf(lcd_putchar,"\FREQUENCYMETER    ");

    if(999>=hz){
      LCD_SetPosition(second_LINE+0);
      printf(lcd_putchar,"\FRQ=%ldHz          ",hz);}
      //////////////////////////////////////////
    if(hz>=1000){
    if(999999>=hz){
      LCD_SetPosition(second_LINE+0);
      printf(lcd_putchar,"\FRQ=%3.3wKhz        ",hz);}}
      /////////////////////////////////////////////
    if(hz>=1000000){
      LCD_SetPosition(second_LINE+0);
      printf(lcd_putchar,"\FRQ=%2.6wMhz          ",hz);}
      ////////////////////////////////////////////
      delay_ms (1);

      set_timer1(0);
      enable_interrupts(int_timer0);
      enable_interrupts(int_timer1);
      enable_interrupts (global);
      aa=0;
      ab=0;
      }
            }}
/*************************entegreterbiyecisi@yahoo.com******************************/
/***entegreterbiyecisi@yahoo.com***/ //lcd basla
void LCD_Init ( void ){
    LCD_SetData ( 0x00 );
    output_low ( LCD_RS );
    LCD_SetData ( 0x03 );  // init with specific nibbles to start 4-bit mode
    LCD_PulseEnable();
    LCD_PulseEnable();
    LCD_PulseEnable();
    LCD_SetData ( 0x02 );  // set 4-bit interface
    LCD_PulseEnable();      // send dual nibbles hereafter, MSN first
    LCD_PutCmd ( 0x2C );    // function set (all lines, 5x7 characters)
    LCD_PutCmd ( 0x0C );    // display ON, cursor off, no blink
    LCD_PutCmd ( 0x01 );    // clear display
    LCD_PutCmd ( 0x06 );    // entry mode set, increment
    }
/***entegreterbiyecisi@yahoo.com***/
void LCD_SetPosition ( unsigned int cX )
    {
    // this subroutine works specifically for 4-bit Port A
    LCD_SetData ( swap ( cX ) | 0x08 );
    LCD_PulseEnable();
    LCD_SetData ( swap ( cX ) );
    LCD_PulseEnable();
    }
/***entegreterbiyecisi@yahoo.com***/
void LCD_PutChar ( unsigned int cX )
    {
    // this subroutine works specifically for 4-bit Port A
    output_high ( LCD_RS );
    LCD_SetData ( swap ( cX ) );    // send high nibble
    LCD_PulseEnable();
    LCD_SetData ( swap ( cX ) );    // send low nibble
    LCD_PulseEnable();
    output_low ( LCD_RS );
    }
/***entegreterbiyecisi@yahoo.com***/
void LCD_PutCmd ( unsigned int cX )
    {
    // this subroutine works specifically for 4-bit Port A
    LCD_SetData ( swap ( cX ) );    // send high nibble
    LCD_PulseEnable();
    LCD_SetData ( swap ( cX ) );    // send low nibble
    LCD_PulseEnable();
    }
/***entegreterbiyecisi@yahoo.com***/
void LCD_PulseEnable ( void )
    {
    output_high ( LCD_EN );
    delay_us ( 100 );
    output_low ( LCD_EN );
    delay_ms ( 5 );
    }
/***entegreterbiyecisi@yahoo.com***/
void LCD_SetData ( unsigned int cX )
    {
    output_bit ( LCD_D4, cX & 0x01 );
    output_bit ( LCD_D5, cX & 0x02 );
    output_bit ( LCD_D6, cX & 0x04 );
    output_bit ( LCD_D7, cX & 0x08 );
    }
/***entegreterbiyecisi@yahoo.com***/ //lcd son
////////////////////////////////////////////////////////////////////////////


An Hiep 21-05-2007 10:07 AM

Cảm ơn bạn Necati đã Post lên chương trình mà tôi và nhiều anh em đang quan tâm. Tôi muốn hỏi thêm là nếu muốn đo 1 tần số sóng mang nằm trong tín hiệu điều chế thì giải quyết như thế nào. Giả sử có 1 tín hiệu cần điều chế có f = 2KHz độ rộng xung là 2us, tín hiệu sóng mang có f0 = 20MHz, nghĩa là trong 2us của tín hiệu điều chế sẽ có 20*2 = 40 chu kỳ xung của sóng mang trong đó. Bài toán ở đây là đo được tần số 20MHz từ tín hiệu đã điều chế đó.
Rất mong anh Necati và các anh em trong diễn đàn giúp đỡ!
Thanks alot!

An Hiep 21-05-2007 10:34 AM

Tôi đọc kỹ thì thấy chương trình của anh Necati cũng đo tần số liên tục, nhưng sử dụng thêm Timer0 để định thời 1 giây, và Timer1 cũng để lấy giá trị đếm số lần xuất hiện xung vào. Tất nhiên, chương trình viết rất chuyên nghiệp, đó cũng là điều mà tôi và nhiều anh em cần học hỏi thêm rất nhiều. Chân thành cảm ơn anh!

suongrong17 22-05-2007 05:18 PM

Xin hỏi tại sao chương trình dùng ngắt timer0 em làm giống nhu hướng dẫn mà nó không chịu chạy?

suongrong17 22-05-2007 05:36 PM

#include<18F4450.h>
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=20000000)
#use fast_io(b)
#byte portb=0x6
#define led pin_B0
int8 a;
void ngat()
{
delay_ms(1000);
a=a<<1; // dich trai a 1bit
if(a==256)
a=1;
}
main()
{
a=1;
set_tris_b(0);
while(true)
{
ngat();
output_b(a);
}
}
Cách này thì PIC18F4550 cũng dịch leds vô tư. Nhưng mà muốn dùng TIMER0 như của bác nhh . Khi mình làm không hiểu tại sao lại không thể chạy. Nhờ bác chỉ giáo giùm nhé!
#include <18F4550.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=20000000) . Mình đã sửa lại code của nhh như vậy để phù hợp với PIC18F4550, nhưng không hiểu sao vẫn không chạy đơợc. Bạn có thể hướng dẫn kỹ hơn về Interrup và Timer không, cảm on bạn nhiều.

thaithienanh 22-05-2007 08:52 PM

Úi code của bạn sai rồi nếu muốn sử dụng được ngắt thì trong hàm main bạn phải thực hiện cho phép ngắt timer_0 và ngắt toàn cục (global) hoạt động, định xung nhịp cho timer, và hàm ngắt() phải được đặt ngay bên dưới chỉ thị #int_timer0 để trình dịch có thể hiểu được đây là hàm phục vụ ngắt, hàm ngắt() này bạn không thể gọi đến giống như một hàm thông thường đuợc mà nó chỉ được máy gọi đến khi có xuất hiện cờ tràn timer_0, mà khi đã sử dụng ngắt timer (tức ngắt định thời) thì bạn không nên dùng delay trong nó (rất dở),vì ngắt timer được tạo ra để thay thế hoàn hảo cho delay, code của bạn mình sửa như sau :
#include<18F4450.h>
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=4000000)
int16 count=0;
int8 a=1;

#int_timer0
void ngat(){
++count;
if(count==2000) {count=0;a=a<<1;} // dich trai a 1bit
if(a==256) {a=1;count=0; }}

void main(){
enable_interrupts(global);
enable_interrupts(int_timer0);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2); //xung timer = xung máy/2
while(true) {
output_b(a);
}}

như vậy ở hàm trên ta sẽ thấy sau mỗi lần tràn ngắt timer_0 (sau hai xung máy) biến đếm count sẽ tăng lên 1 đơn vị và cứ thế cho đến khi đạt giá trị 2000 (đây là giá trị mà bạn cần phải tính để chọn đúng thời gian cần làm làm trễ) khi đó biến a sẽ đuợc dịch bit sang trái,....rồi tiếp tục... chắc khúc này bạn hiểu rồi há.

An Hiep 23-05-2007 11:37 AM

Giải thích như bạn thaithienanh là đúng đấy. Bạn phải khai báo thủ tục ngắt cho đúng và trong chương trình chính phải cho phép ngắt (hoặc không) đúng ý đồ thuật toán.
Tiện đây các bạn cho hỏi có cách nào đo được biên độ điện áp của xung vuông có độ rộng xung (thời gian tồn tại mức) nhỏ cỡ 0.4us không? Tôi định dùng ADC thông thường với xung clock nội (thạch anh 20MHz) và dùng thêm các chân phát hiện mức (sườn lên) của xung rồi cho phép lấy ADC nhưng không biết với độ rộng xung hẹp như vậy có khả thi không? Anh em nào biết phương pháp thì giúp tôi với.
Thanks!
-----------------------------------------------------------------------
An Hiệp

suongrong17 23-05-2007 04:38 PM

Pic18f4450
 
Trích:

Nguyên văn bởi thaithienanh (Post 8833)
Úi code của bạn sai rồi nếu muốn sử dụng được ngắt thì trong hàm main bạn phải thực hiện cho phép ngắt timer_0 và ngắt toàn cục (global) hoạt động, định xung nhịp cho timer, và hàm ngắt() phải được đặt ngay bên dưới chỉ thị #int_timer0 để trình dịch có thể hiểu được đây là hàm phục vụ ngắt, hàm ngắt() này bạn không thể gọi đến giống như một hàm thông thường đuợc mà nó chỉ được máy gọi đến khi có xuất hiện cờ tràn timer_0, mà khi đã sử dụng ngắt timer (tức ngắt định thời) thì bạn không nên dùng delay trong nó (rất dở),vì ngắt timer được tạo ra để thay thế hoàn hảo cho delay, code của bạn mình sửa như sau :
#include<18F4450.h>
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=4000000)
int16 count=0;
int8 a=1;

#int_timer0
void ngat(){
++count;
if(count==2000) {count=0;a=a<<1;} // dich trai a 1bit
if(a==256) {a=1;count=0; }}

void main(){
enable_interrupts(global);
enable_interrupts(int_timer0);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2); //xung timer = xung máy/2
while(true) {
output_b(a);
}}

như vậy ở hàm trên ta sẽ thấy sau mỗi lần tràn ngắt timer_0 (sau hai xung máy) biến đếm count sẽ tăng lên 1 đơn vị và cứ thế cho đến khi đạt giá trị 2000 (đây là giá trị mà bạn cần phải tính để chọn đúng thời gian cần làm làm trễ) khi đó biến a sẽ đuợc dịch bit sang trái,....rồi tiếp tục... chắc khúc này bạn hiểu rồi há.

Thật sự cảm ơn sự chỉ giáo của thaithienanh. Mình cũng đang tập tành chơi với PIC thôi. Trước giờ cũng chưa từng đụng đến các loại vi xử lý thành ra không nắm rõ, khi đọc tài liệu cũng cảm thấy khó hiểu ở phần ngắt. Mình đang dự định dùng con PIC này để làm thành Keyboard USB, viết cả driver cho nó. Nhưng bây giờ cơ bản cũng còn chưa biết, chỉ có ý tửong7 thôi. Nhờ bạn chỉ them cho mình với nhé. Thế nhưng khi đưa trình ngắt này cho chạy thử thì vẫn thấy bặt vô âm tín, không hiểu bị sao nữa.

tranvanthuong 23-05-2007 09:23 PM

cho em hỏi, em đang làm thí nghiệm pic16f84a, làm led chớp tắt theo ý muốn nhưng em muốn dùng 1 biến trở để chỉnh tốc độ delay thì phải làm sao? nhờ các anh chỉ giáo! và em muốn dùng time 0 được không?
(xin lỗi mấy anh, mục này mà em hỏi F84a)

namqn 23-05-2007 11:07 PM

Trích:

Nguyên văn bởi tranvanthuong (Post 8845)
cho em hỏi, em đang làm thí nghiệm pic16f84a, làm led chớp tắt theo ý muốn nhưng em muốn dùng 1 biến trở để chỉnh tốc độ delay thì phải làm sao? nhờ các anh chỉ giáo! và em muốn dùng time 0 được không?
(xin lỗi mấy anh, mục này mà em hỏi F84a)

Người ta thường dùng bộ ADC trong PIC (tất nhiên đang nói đến những chip có module ADC) để đọc giá trị của biến trở rồi điều chỉnh thời gian/tốc độ chớp tắt. Với PIC16F84A (không có module ADC), bạn vẫn có thể làm được điều đó, nhưng dùng một cách khác, được đề cập đến trong app. note 863 của Microchip. Bạn tìm đọc app. note đó trên web site của Microchip.

Thân,

suongrong17 24-05-2007 07:15 PM

quét led 7 segment.
 
Cảm ơn anh thaithienanh nhiều, mình đã làm được rồi.Đã OK phần ngắt. Chiều nay mới quét và hiển thị 2x7 segment leds. Cho nó đếm, đã dần hiểu đựoc7 lập trình vi điầu khiển. Mong đựoc7 các bác chỉ giáo nhiều hơn nữa.

đây là chưong7 trình mà mình mới viết, mai sẽ sử dụng ngắt và timer để làm lại.

Code:

#include<18F4550.h>
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=10000000)
#use fast_io(b)
#use fast_io(a)
#byte portb=0x6

BYTE CONST LED_MAP[10] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x58,0x00,0x10};
int8 a,i,j;

void ngat()
{

a++;
  if(a>=100)
  a=0;
  }
void main()
{set_tris_a(0);
 a=0;
set_tris_b(0);
while(true)
{  i=0;while(i<=200)
 {i++;
 output_b(led_map[a/10]);
 output_high(PIN_B7);
  output_low(PIN_A0);
  delay_ms(3);
  output_high(PIN_A0);
  output_b(led_map[a%10]);
    output_low(PIN_A1);
    delay_ms(3);
  output_high(PIN_A1);
  } 
 ngat();
}
return;
}


phamthaihoa 24-05-2007 10:28 PM

Trích:

Nguyên văn bởi tranvanthuong (Post 8845)
cho em hỏi, em đang làm thí nghiệm pic16f84a, làm led chớp tắt theo ý muốn nhưng em muốn dùng 1 biến trở để chỉnh tốc độ delay thì phải làm sao? nhờ các anh chỉ giáo! và em muốn dùng time 0 được không?
(xin lỗi mấy anh, mục này mà em hỏi F84a)

Làm như anh namqn là ok roài, nhưng con 16F84A không có comparator nên bạn sẽ phải thêm một con comparator ngoài, ví dụ LM393

hawinter 29-05-2007 06:38 PM

Em làm mạch đo nhiệt độ sử dụng LM335Z để hiển thị LCD .
Code:

#include <16F877A.h>
#include <DEFS_16F877A.h>
#device*=16 adc=10
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#define RS RB3
#define RW RB4
#define E RB5
#byte lcd_data = PORTD  // Dia chi PORTD
int8 hight,low,i;
float value;
void convert_bcd(int8 a){
  low=a%10;
  hight=a/10;
  low+=0x30;//doi ra ma ASCII de hien thi LCD
  hight+=0x30;
}

byte lcd_read_byte()
{
  byte read_byte;
  set_tris_D(0xFF);      // PORTD = input
  RW = 1;
  delay_cycles(1);
  E  = 1;
  delay_cycles(1);
  read_byte = lcd_data;
  E  = 0;
  set_tris_D(0x00);      // PORTD = output
  return(read_byte);
}
/* Goi 1byte den LCD */
void lcd_send_byte( byte address, byte n )
{
  RS = 0;
  while ( bit_test(lcd_read_byte(),7) ) ;
  RS = address;
  delay_cycles(1);
  RW = 0;
  delay_cycles(1);
  E  = 0;
  lcd_data = n;
  delay_cycles(1);
  E = 1;
  delay_us(2);
  E = 0;
}

/* Khoi tao ban dau cho LCD */
void lcd_init()
{
    byte const lcd_init_string[4] = {0x38, 0x0C, 1 , 6};
    byte i;
    set_tris_D(0x00);
    RS = 0;
    RW = 0;
    E  = 0;
    delay_ms(15);
    for(i=1;i<=3;++i)
      {
        lcd_data = 3;
        delay_cycles(1);
        E = 1;
        delay_us(2);
        E = 0;
        delay_ms(5);
      }
    lcd_data = 2;
    delay_cycles(1);
    E = 1;
    delay_us(2);
    E = 0;
    delay_ms(5);
    for(i=0;i<=3;++i)
      {
        lcd_send_byte(0,lcd_init_string[i]);
      }
}
void lcd_gotoxy( BYTE x, BYTE y) {
  BYTE address;

  if(y!=1)
    address=0x40;
  else
    address=0;
  address+=x-1;
  lcd_send_byte(0,0x80|address);
}
void lcd_putc( char c) {
  switch (c) {
    case '\f'  : lcd_send_byte(0,1);
                  delay_ms(2);
                                          break;
    case '\n'  : lcd_gotoxy(1,2);        break;
    case '\b'  : lcd_send_byte(0,0x10);  break;
    default    : lcd_send_byte(1,c);    break;
  }
}
main()
{
  set_tris_B(0);
  set_tris_D(0);
  set_tris_A(0xFF);
  lcd_init();
  delay_ms(100);
  lcd_gotoxy(3,1);
  lcd_putc("hello");
  lcd_gotoxy(1,2);
  lcd_putc("Welcom Everybody");
  delay_ms(2000);
  lcd_send_byte(0,1);//xoa LCD
  lcd_send_byte(0,6);
  setup_adc(ADC_CLOCK_INTERNAL);
  setup_adc_ports(AN0);
  set_adc_channel(0);
  delay_ms(100);
  value=(float)read_adc();
  value=(value-558.5)/2.048;
  convert_bcd((int8)value);
  delay_us(20);
  lcd_putc("nhiet do:");
  while(1)
  {
      value=(float)read_adc();
      value=(value-558.5)/2.048;
      convert_bcd((int8)value);
      delay_ms(1000);
      lcd_gotoxy(2,4);
      lcd_putc(hight);
      lcd_putc(low);
      lcd_putc(" do C");
      //delay_ms(1000);
  }
 }

Chương trình có tham khảo từ các bài viết trên Picvietnam và dientuvietnam.
khi chay chương trình thì giá trị nhiệt độ hiển thị chỉ quanh các giá trị 50,52,54,56,48,58 em cũng không biết tại sao .Xin các bậc tiền bối giải đáp hộ .

hawinter 29-05-2007 10:18 PM

Các sư huynh dúp em với đau đầu quá mà vẫn chưa tìm ra nguyên nhân ???
Cho em hỏi thêm là trong CCS để truy cập đến các thanh ghi thì làm thế nào nhỉ .

huybo02 30-05-2007 09:28 PM

Bạn kiểm tra lại Vref trên LM335 thử xem. Chương trình trên ứng với Vref = 5V. Nếu Vref có giá trị khác bạn phải tính lại các số cho biểu thức
" value=(value-558.5)/2.048;"
Với 5V thì:
5V = 1024 muc (ADC 10bit 2^10 = 1024) => 10mV tuong ung voi 2.048 muc ADC
0oC = 273oK => 0oC ung voi muc dien the 2.73V ung voi 559 muc ADC
Nhiet do = dien the Analog/10 - 273
Tuong ung
Nhiet do = (adc -559)/2.024

Còn truy cập thanh ghi thì có lẽ giống như khai báo địa chỉ port I/O lúc đầu
VD: #byte portb = 0x06;
Lúc này ta có thể gán giá trị vào portb:
portb = 0xFF;
hay đọc giá trị từ portb ra ngoài:
data = portb;
Đối với các thanh ghi khác chắc cũng như vậy. Đặt tên thanh ghi, định nghĩa địa chỉ và truy xuất
Bạn thử xem <<< chưa thử :D


Múi giờ GMT. Hiện tại là 09:02 PM.

Tên diễn đàn: vBulletin Version 3.8.11
Được sáng lập bởi Đoàn Hiệp.
Copyright © PIC Vietnam