Ccs c for pic16F877a mục lục I. Tổng quan về ccs vì sao ta sử dung ccs ?


+Mình mới học về PIC.Cho hỏi ADC module có chức năng gì,công dụng ntn trên PIC?



tải về 1.15 Mb.
trang3/15
Chuyển đổi dữ liệu23.08.2016
Kích1.15 Mb.
#26977
1   2   3   4   5   6   7   8   9   ...   15

+Mình mới học về PIC.Cho hỏi ADC module có chức năng gì,công dụng ntn trên PIC? Mình nghĩ cho một điện thế analog thì nó xuất ra tín hiệu digital.Mình đã có đọc đoạn code này nhưng chưa hiểu rõ :

Code:


#include <16F877.h>

#fuses HS,NOWDT,NOPROTECT,NOLVP

#device 16F877*=16 ADC=8

#use delay(clock=10000000)

Int8 adc;

main()


{

setup_adc(adc_clock_internal);

setup_adc_ports(AN0);

set_adc_channel(0);

delay_ms(10);

while(true)

{

adc=read_adc();



output_B(adc);

}

}



TL: ADC là chức năng chuyển đổi tín hiệu analog -> digital (Analog Digital Converter). Nó dùng 1 điện áp để so sánh (Vref) tùy độ phân giải mà điện áp này được chia là nhiểu mức khác nhau (2^n) với 16F877A ADC 10 bit tức Vref dc chia thành 2^10 = 1024 mức. Mỗi mức ADC cách nhau tương ứng với Vref/số mức. Vref = 5V thì mỗi mức ADC của 16F877 ứng với 5V/1024 = 4.88mV. Điện áp trên cổng AN sẽ được so sánh để ra được mức ADC tương ứng. 0V ứng với ADC =0, 4.88mV ứng với ADC =1...Kết quả được chứa trong 2 thanh ghi ADRESH:ADRESL.
Còn mạch cho code trên thì bạn mắc 1 cầu chia áp để đưa điện áp vào chân AN0 là được. Dùng biến trở cho gọn.
Còn PWM thì bạn đọc trong datasheet đó chương 8 phần CAPTURE/COMPARE/PWM MODULES và xem thêm bên ứng dụng điều khiển PID cho động cơ DC.

+Em có đoạn code sau nhưng em không hiểu là lệnh adcHI và adcLO làm gì (với khai báo
char adcHI,adcLO).Anh nào giải thích hộ em

Code:


while(TRUE)

{

adcValue = read_adc(); // Get ADC reading



adcHI = (char)((adcValue >> 5)& 0x1f);

adcLO = (char)((adcValue & 0x1f)|0x80);

putc(adcHI);

putc(adcLO);

delay_ms(10); // Preset delay, repeat every 10ms

}

}



TL: adcHI và adcLO là các biến kiểu char (8-bit), không phải là lệnh.
Trong đoạn lệnh mà bạn đã đưa ra, kết quả của việc biến đổi A/D được tách thành 2 phần, phần cao chứa trong adcHI, còn 5 bit thấp hơn của kết quả được chứa trong adcLO. Bit 7 của adcLO được bật.
Sau đó adcHI và adcLO được xuất ra thông qua hàm putc().

3. DAC

3.1. DAC_1446

// DIGITAL TO ANALOGUE CONVERTER HARDWARE INTERFACE PROGRAM

// COPYRIGHT PROPERTY OF ALPHADATA DESIGNS LIMITED (c) 1999

// WRITTEN FOR THE LTC1446 12 BIT 2-CHANNEL MICRO-WIRE D TO A

// published by permission of Alphadata designs on

// Hi-Tech C website, http://www.workingtex.com/htpic. Thanks!

//------------------------------------------------------

// Version History

//------------------------------------------------------

// Issue 1.0 : 21/12/1999 : First Officially Released

//------------------------------------------------------

#include


#include "h8genlib.h"

#include "ioh8314.h"

#include "sci.h"

#include "spi.h"

#include "dac_1446.h"

extern byte p4dr;

/* call this to write one channel of data to the d to a */

void dac_write(word output)

{

byte count;



byte block;

byte ops[3];

//char s[50];

/* Select ADC device */

spi_dac_select();

//Format output data

if (output<0x1000) {

ops[0]=0;

ops[1]=output >> 8;

ops[2]=output;

} else {

ops[0] = output >> 4;

ops[1] = (output << 4) + 0x0F;

ops[2] = 0xFF;

}

// ops[0]= ((byte*)&output)[1];



// ops[1]= ((byte*)&output)[2];

// ops[2]= ((byte*)&output)[3];

// sprintf(s,"%02X %02X %02X\r\n",ops[0],ops[1],ops[2]);

// sci_put_string(0,s);

/* output three blocks of eight bits */

for (block=0;block<3;block++) {

for (count=0;count<8;count++) {

if ((ops[block] & 0x80) == 0) spi_lodata(); else spi_hidata();

spi_hiclock();

spi_loclock();

ops[block] = ops[block] << 1;

}

}



spi_dac_deselect();

}

/* call this to set up the hardware ports */



void dac_initialise(void)

{

dac_write(0);



}

// end


4. Timer
Trong Pic16f877a có 3 timer :
+ Timer0 : 8 bit
+ Timer1 : 16 bit
+ Timer2 : 8 bit
Timer dùng cho nhiều ứng dụng : định thời, capture, pwm, ...

Timer có nhiều kiểu chia tần, dùng chia trước và sau (prescale và postscale) là chia trước và chia sau, có nhiều cách đặt tỉ lệ cho Timer từ 1:1 - 1:256 tức là cách chia này giúp cho ta nhận được xung kích vào Timer sẽ được chậm đi n lần ( 1:n ) so với 1Tcy (Fosc/4), và như vậy ta sẽ được xung kich chậm hơn:


setup_timer_0(RTCC_INTERNAL|RTCC_DIV_4); // 4Mhz => dùng dao động nội, chế độ prescal 1:4 => clock cho Timer0 la Fosc/4/4 = Fosc/16.
Khi này ta có Fosc/4 => Tcy = 1us. Ttimer0 = Fosc/16 => 4us
Timer0 tràn 8 bit => 4x8bit = 1024us.
8 bit có 256 trạng thái chứ không phải 255 trạng thái, do đó x256,
Còn cách thứ 2 Postscale (Only Timer2) thì nó sẽ đếm số lần tràn của Timer2, Nghĩa là: 1:2 - 2 làn tràn cho ra 1 lần xung .....
1:16 - 16 làn Timer2 tràn
Giả sử Áp dụng với Timer2 thay Timer0 ở trên và với postscale 1:8 ta sẽ thu được đầu ra là : 4x256x8 = 8192 us
4.1. Timer0
Thanh ghi tác động:
Các lệnh:

Code:


setup_TIMER_0(mode);

setup_COUNTERS (rtcc_state, ps_state); // hay setup_WDT()

set_TIMER0(value); // hay set_RTCC(value) :xác định giá trị ban đầu (8bit) cho Timer0

get_TIMER0(); // hay get_RTCC() :trả về số nguyên (8bit) của Timer0

Trong đó mode là một hoặc hai constant (nếu dùng hai thì chèn dấu "|"ở giữa) được định nghĩa trong file 16F877A.h gồm :

RTCC_INTERNAL : chọn xung clock nội


RTCC_EXT_L_TO_H : chọn bit cạnh lên trên chân RA4
RTCC_EXT_H_TO_L : chọn bit cạnh xuống trên chân RA4
RTCC_DIV_2 :chia prescaler 1:2
RTCC_DIV_4 1:4
RTCC_DIV_8 1:8
RTCC_DIV_16 1:16
RTCC_DIV_32 1:32
RTCC_DIV_64 1:64
RTCC_DIV_128 1:128
RTCC_DIV_256 1:256
rtcc_state là một trong những constant sau:
RTCC_INTERNAL
RTCC_EXT_L_TO_H
RTCC_EXT_H_TO_L
ps_state là một trong những constant sau:
RTCC_DIV_2
RTCC_DIV_4
RTCC_DIV_8
RTCC_DIV_16
RTCC_DIV_32
RTCC_DIV_64
RTCC_DIV_128
RTCC_DIV_256
WDT_18MS
WDT_36MS
WDT_72MS
WDT_144MS
WDT_288MS
WDT_576MS
WDT_1152MS
WDT_2304MS
Mình cũng chưa hiểu ý nghĩa của hàm WDT_..., ko biết có phải khai báo như trên thì sau khoảng thời gian ms bao nhiêu đó đặt sau WDT_ thì sẽ reset lại Pic ?????
4.2. Timer1
Thanh ghi tác động:
Các lệnh:

Code:


setup_TIMER_1(mode);

set_TIMER1(value); // xác định giá trị ban đầu (16bit) cho Timer1

get_TIMER1(); // trả về số nguyên (16bit) của Timer1

mode gồm (có thể kết hợp bằng dấu "|"):


T1_DISABLED : tắt Timer1


T1_INTERNAL : xung clock nội (Fosc/4)
T1_EXTERNAL : xung clock ngoài trên chân RC0
T1_EXTERNAL_SYNC : xung clock ngoài đồng bộ
T1_CLK_OUT
T1_DIV_BY_1
T1_DIV_BY_2
T1_DIV_BY_4
T1_DIV_BY_8
4.3. Timer2
Thanh ghi tác động:
Các lệnh:

Code:


setup_TIMER_2(mode, period, postscale);

set_TIMER2(value); // xác định giá trị ban đầu (8bit) cho Timer2

get_TIMER2(); // trả về số nguyên 8bit

Với mode gồm (co the ket hop bang dau "|"):


T2_DISABLED
T2_DIV_BY_1
T2_DIV_BY_4
T2_DIV_BY_16
period là số nguyên từ 0-255, xác định giá trị xung reset
postscale là số nguyên 1-16, xác định reset bao nhiêu lần trước khi ngắt.

Code:

///////////////////////////////////////////////////////////////////////

//// EX_STWT.C ////

//// ////

//// This program uses the RTCC (timer0) and interrupts to keep a ////

//// real time seconds counter. A simple stop watch function is ////

//// then implemented. ////

//// ////

//// Configure the CCS prototype card as follows: ////

//// Insert jumpers from: 11 to 17 and 12 to 18. ////

///////////////////////////////////////////////////////////////////////

#include<16f877a.h>

#fuses HS,NOLVP,NOWDT,PUT

#use delay(clock=20000000)

#use rs232(baud=9600,xmit=PIN_C6,rcv=PIN_C7)
#define high_start 76

byte seconds, high_count;


#INT_RTCC //Interrupt procedure

clock_isr() { //called every time RTCC

high_count -= 1; //flips from 255 to 0

if(high_count==0) {

++seconds;

high_count=high_start; //Inc SECONDS counter every

} //76 times to keep time

}

void main() { //A simple stopwatch program



byte start, time;
high_count = high_start;

setup_timer_0( RTCC_INTERNAL | RTCC_DIV_256 );

set_timer0(0);

enable_interrupts(INT_RTCC);

enable_interrupts(GLOBAL);

do {


printf("Press any key to begin.\n\r");

getc();


start = seconds;

printf("Press any key to stop.\r\n");

getc();

time = seconds - start;



printf("%U seconds.\n\r", time);

} while (TRUE);

}

4.4. 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



///////////////////////////////////////////////////////////////////////////

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ế đó.

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.
5. INTERRUPT
Các lệnh dùng cho ngắt:

Code:


enable_interrupts(level); //cho phép ngắt kiểu level

disable_interrupts(level); //cấm ngắt kiểu level

ext_int_edge(edge); // chọn cách lấy xung loại edge

level bao gồm:


GLOBAL : ngắt toàn cục
INT_RTCC : tràn TMR0
INT_RB : có thay đổi trạng thái một trong các chân RB4 đến RB7
INT_EXT : ngắt ngoài
INT_AD : chuyển đổi AD đã hoàn tất
INT_TBE : bộ đệm chuyển RS232 trống
INT_RDA : data nhận từ RS232 sẵn sàng
INT_TIMER1 : tràn TMR1
INT_TIMER2 : tràn TMR2
INT_CCP1 : có capture hay compare trên CCP1
INT_CCP2 : có capture hay compare trên CCP2
INT_SSP : có hoạt động SPI hay I2C
INT_PSP : có data vào cổng parallel slave
INT_BUSCOL : xung đột bus
INT_EEPROM : ghi vào eeprom hoàn tất
INT_TIMER0 : tràn TMR0
INT_COMP : kiểm tra bằng nhau comparator
edge bao gồm:
L_TO_H : cạnh lên
H_TO_L : cạnh xuống
Sau khai báo trên để vào đoạn chương trình ngắt, khai báo:
#INT_.........
Ví dụ vào thực thi ngắt ngoài, ta có đoạn code:

Code:


#INT_EXT

void ngat_ngoai()

{

//Chương trình ngắt tại đây



}

5.1. Ngắt Timer0

Đây là chương trình dùng ngắt Timer0 định thì 1s.


Đầu tiên led ở chân RB0 sáng, sau 1s sẽ dịch sang trái, nghĩa là led 1 trên chân RB1 sáng , lần lượt như vậy cho các led trên portB và lặp lại mãi mãi.

Code:


#include <16F877A.h>

#fuses NOWDT,PUT,XT,NOPROTECT

#use delay(clock=4000000)

#byte PORTB = 0x06


int16 count;

int8 a;


//Chuong trinh ngat TMR0

#int_timer0

void interrupt_timer0()

{

set_timer0(6);



++count;

if(count == 2000) // 2000*500us = 500000us = 1s

{

count=0;


rotate_left(&a,1);

}

}



//Chuong trinh chinh

void main(void)

{

set_tris_b(0);



enable_interrupts(int_timer0);

setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2);

enable_interrupts(global);

set_timer0(6);// T_dinhthi = 2*(256 - 6)*1us = 500us

a = 0x01;

while(true)

{

PORTB = a;



}

}

Trích:

Mình cũng chưa hiểu ý nghĩa của hàm WDT_..., ko biết có phải khai báo như trên thì sau khoảng thời gian ms bao nhiêu đó đặt sau WDT_ thì sẽ reset lại Pic ?????

WDT là "chó giữ nhà" (Watchdog Timer). Bộ phận này có nhiệm vụ reset lại PIC sau một khoảng thời gian định trước. WDT sẽ reset vi điều khiển khi bộ đếm của WDT bị tràn. Mục đích của nó là tránh trường hợp vi điều khiển bị "treo" khi phải hoạt động liên tục trong một khoảng thời gian lâu dài.
Thời gian định trước này phụ thuộc vào tần số loại thạch anh sử dụng và bộ chia tần số trước (prescaler) của WDT.
Ta thấy WDT chỉ liên quan đến Timer 0, còn các Timer khác không có liên quan. Đó là tại vì WDT có bộ chia tần số (prescaler) dùng chung với Timer 0. Lưu ý là muốn sử dụng WDT cần chú ý đến phần khai báo các "fuse" ở đầu chương trình.

Trích:


rtcc_state là một trong những constant sau:
RTCC_INTERNAL
RTCC_EXT_L_TO_H
RTCC_EXT_H_TO_L

Mỗi Timer đều có 2 tác dụng:
Tác dụng định thời: Timer sẽ dựa vào các xung tạo ra bởi bộ dao động (thạch anh, dao động RC, ...) cung cấp cho vi điều khiển để đếm. Và dựa vào tần số bộ dao động, giá trị các bộ chia tần số và giá trị của Timer, ta có thể xác định được thời gian thực. Như vậy trong trường hợp muốn Timer hoạt động ở chế độ định thời, ta phải khai báo rtcc_state là "RTCC_INTERNAL" (xử dụng tần số dao động nội).
Tác dụng đếm: Timer sẽ dựa vào các xung lấy từ môi trường bên ngoài để đếm. Tùy theo Timer mà ta sử dụng chân lấy xung tương ứng (Timer 0 là chân RA4, Timer1 là chân RC0). Các xung này có tác dụng phản ánh các hiện tượng trong thực tế, và việc đếm các xung cũng đồng nghĩa với việc đếm các hiện tượng đó. Và để linh động hơn trong quá trình xử lí, Timer còn cho phép chọn cạnh tác động lên bộ đếm (chế độ này chỉ có ở Timer 0). Như vậy muốn Timer hoạt động ở chế độ đếm, ta phải khai báo rtcc_state là một trong 2 trường hợp còn lại (sử dụng dao động ngoài).

Trích:


ps_state là một trong những constant sau:
RTCC_DIV_2
RTCC_DIV_4
RTCC_DIV_8
RTCC_DIV_16
RTCC_DIV_32
RTCC_DIV_64
RTCC_DIV_128
RTCC_DIV_256
WDT_18MS
WDT_36MS
WDT_72MS
WDT_144MS
WDT_288MS
WDT_576MS
WDT_1152MS
WDT_2304MS

Ở đây có đến 2 hàm dùng để ấn định tỉ số chia của prescaler, một hàm là "RTCC_DIV_...", một hàm là "WDT_ ...". Đó là bởi vì Timer 0 và WDT dùng chung bộ chia tần số. Khi bộ chia được Timer 0 sử dụng thì WDT không đựoc hỗ trợ với bộ chia này nữa. Như vậy sự khác biệt về thao tác giữa 2 hàm này có thể là như sau:
Hàm "RTCC_DIV_..." : cho phép Timer 0 sử dụng bộ chia tần số, không cho phép WDT sử dụng và ấn định tỉ số chia của nó.
Hàm "WDT_ ..." : cho phép WDT 0 sử dụng bộ chia tần số, không cho phép Timer 0 sử dụng và ấn định tỉ số chia của nó.

Trích:


T2_DISABLED
T2_DIV_BY_1
T2_DIV_BY_4
T2_DIV_BY_16
period là số nguyên từ 0-255, xác định giá trị xung reset
postscale là số nguyên 1-16, xác định reset bao nhiêu lần trước khi ngắt.
hôm nay 09:30 AM

Ta có thể nhận thấy là Timer 2 có đến 2 bộ chia tần số trước và sau, một bộ prescaler được đính kèm vào các chế độ hoạt động của Timer 2 (T2_DIV_BY_1, T2_DIV_BY_4, T2_DIV_BY_16), một bộ là postscaler cis tỉ số chia từ 1:16. Như vậy nó cho phép việc lựa chọn tỉ số chia linh động hơn.
Timer 2 không hoạt động ở chế độ đếm. Chức năng của nó chủ yếu là tác động lên tốc độ baud cho MSSP thì phải. Không nhớ rõ lắm.

Trích:


postscale là số nguyên 1-16, xác định reset bao nhiêu lần trước khi ngắt.

Cái này để mình coi lại đã, tại sao nó lại xác định reset bao nhiêu lần trước khi ngắt ??. Phải coi lại cái sơ đồ khối của Timer 2 mới biết được.

Một cách viết khác để tham khảo với hy vọng viết C sao cho dễ hiểu :-)
#include <16F877A.h>
#fuses NOWDT, PUT, XT, NOPROTECT
#use delay(clock=4000000)

#define INITIAL_VALUE 6

byte count;
byte led;

void change_led(void);

#int_timer0
void interrupt_timer0() {
set_timer0(INITIAL_VALUE);
count++;
if (count == 2000) {
count = 0;
change_led();
}
}
void main() {
set_tris_b(0);
enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER0);
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_2); // set mod
set_timer0(INITIAL_VALUE); // set initial value
count = 0;
led = 1;
while (true)
output_b(led);
}
void change_led() {
led = led << 1;
if (led == 0)
led = 1;
}



Thứ nhất khi nào hàm con interrupt_timer0() được gọi
Thứ hai, việc tính toán định thì 1s được tính như thế nào.
Thứ ba, biến a được khai báo là số nguyên 8bit. Phạm vi từ 0->255,làm sao bằng 256 đc.

1. Ngắt Timer0 được gọi khi Timer 0 bị tràn từ 0xff sang 0x00 với điều kiện phải có 2 khai cho phép ngắt timer 0 và ngắt toàn cục:

Code:


enable_interrupts(int_timer0);

enable_interrupts(global);

2. Việc tính toán thời gian tràn của Timer rất dễ, xem luồng "PIC6f877A từ dễ tới khó", hoặc tìm đâu đó trong diễn đàn này phần mềm "PIC Timer Calculator".
3. Biến a 8bit int, ko thể có giá trị 256 -> đúng vậy.



tải về 1.15 Mb.

Chia sẻ với bạn bè của bạn:
1   2   3   4   5   6   7   8   9   ...   15




Cơ sở dữ liệu được bảo vệ bởi bản quyền ©hocday.com 2024
được sử dụng cho việc quản lý

    Quê hương