LỚP DD07KSTN

LỚP DD07KSTN


 
Trang ChínhCalendarTrợ giúpTìm kiếmThành viênNhómĐăng kýĐăng Nhập
July 2018
MonTueWedThuFriSatSun
      1
2345678
9101112131415
16171819202122
23242526272829
3031     
CalendarCalendar
Latest topics
Keywords

Share | 
 

 Bài tập Counter0

Go down 
Tác giảThông điệp
rockc4
trưởng phòng
trưởng phòng


Tổng số bài gửi : 35
Join date : 30/03/2010

Bài gửiTiêu đề: Bài tập Counter0   Sat May 22, 2010 2:44 pm

Chào các bạn, có nhiều cách để viết một chương trình = C cho VĐK.
Sau buổi học Timer / Ngắt, có một số bạn đã làm bài tập và nộp bài, cách viết khác nhau và kết quả cũng khác nhau Very Happy
Đây là chương trình dùng Counter 0, đếm đến 10 thì bật LED (RE1) trong thời gian 300ms thì tắt.
Chị sẽ viết một vài chương trình mẫu, để các bạn tham khảo cách viết chương trình chuyên nghiệp.

Ngoài ra trong chương trình này mình có sử dụng 2 chương trình con, được viết trước hàm main().
Chương trình con / cũng như chương trình ngắt, có thể viết trước / hoặc sau main().

Tuy nhiên, chương trình con nếu đc viết sau main() thì trước main vẫn phải khai báo:
ví dụ:
void init_port(void); //khai báo chương trình con

main()
{...}

void init_port(void)
{
//chương trình con ở đây
}

Lưu ý, khi các bạn chạy thử trên board mainpic của mình thì sửa lại 1 số chỗ cho đúng: .
- Sửa Config bits: chị dùng board học PIC, thạch anh nội
- Led nối với portE1, cấp mức 1 thì sáng, 0 thì tắt.
- Nút nhấn có treo trở lên nguồn, gắn vào RA4, bình thường = 1, khi nhấn = 0;

Code:

/****************************************************************
 *
 * PIC Training Course
 *
 ****************************************************************/

/****************************************************************
 *
 *   Module         : main.c
 *   Description      : Counter0 / Count to 10 then Light On LED 1
 *  Tool         : HI-TECH PIC
 *   Chip         : 16F887A
 *    History         : 19/05/2010
 *            
 *   Author         : Ho Thanh Phuong, CLB NCKH         
 *   Hardware notes   :
 *            - Hardware: LED1 assembles with RE1; RE1 = 1: light on LED1
 *            - A button is connected with RA4 (T0CKI);
 *                Normal: RA4 = 1; push down: RA4 =0
 ****************************************************************/
 

 /****************************************************************
 * IMPORT
 ****************************************************************/

#include <htc.h>
 
__CONFIG(INTIO & WDTDIS & PWRTEN & MCLREN & UNPROTECT & DUNPROTECT & BORDIS & IESODIS & FCMDIS & LVPDIS);

#define _XTAL_FREQ    4000000
#define   ON         1
#define   OFF         0
 
 /****************************************************************
 * EXTERN
 ****************************************************************/

   /*none...*/

/*****************************************************************
GLOBAL VARIABLE
******************************************************************/

   /*none...*/

/*****************************************************************
* ROUTINES
******************************************************************/
                  
/* -- void init_port(void) --------------------------------------
 *
 * Description   : disable all analog pins, init RE1 as output .
 * Parameters   : none
 * Return      : don't care
 */
void init_port(void)
{
   ANSEL = 0;      //AN[0-7] are analogs pins
   ANSELH = 0;      //AN[8-13] are analogs pins
   TRISE1 = 0;      //RE1 as output
   RE1 = OFF;      //Turn off Led1
}                     

/* -- void init_counter0(void) --------------------------------------
 *
 * Description   : initialization counter 0
 * Parameters   : none
 * Return      : don't care
 */
void init_counter0(void)
{
   TRISA4 = 1;      //init PortA[4] as input to use external clock for Counter0
   
   T0CS=1;        // Clock Select:    1:    External clock for Counter 0
               //                0:    Internal clock for Timer 0
   T0SE=1;        // Source Edge:      1:   Falling Edge
               //               0:   Rising Edge
   PSA=1;          // PreScaler:      1:   Not use
               //               0:   Use     

   TMR0=0xF6;      // Overflow after 10 pulses
   
   GIE=1;         // Global Interrupt Enable               
   T0IF=0;         // Clear Timer0 Interrupt Flag           
   T0IE=1;         // Timer0 Interrupt Enable             
}

/* -- void interrupt isr()   -----------------------------------------
 *
 * Description   : Interrupt Service Routine
 * Parameters   : none
 * Return      : don't care
 * Notes      :
 */
void interrupt isr()
{   
   if(T0IE && T0IF)
   {
      T0IF=0;      // Clear Timer0 Interrupt Flag 
         TMR0=0xF6;   
           
      RE1=ON;   // Light off Led1
      __delay_ms(150);
      __delay_ms(150);
      RE1 = OFF;   
   }                  
}

 /****************************************************************
 * MAIN
 ****************************************************************/   
 
/* -- void main (void)   -----------------------------------------
 *
 * Description   : External Interrupt control.
 * Parameters   : none
 * Return      : don't care
 * Notes      :
 */
 
void main(void)
{      
   init_port();
   init_counter0();
   while(1);
}

/****************************************************************
 * END OF main.c
 ****************************************************************/

download file .c ở đây
mediafire.com ?gr4iywm0zdc

Vấn đề của chương trình này là: Nếu các bạn dùng phím nhấn để tạo clock đếm xung cho COunter0, thì sẽ có hiện tượng rung phím.
Khi bạn chỉ nhấn phím 1 lần, nhưng bộ counter đọc đc 2,3 xung --> nhấn chưa tới 10 lần đèn đã báo.

Vậy sẽ giải quyết thế nào?

Các bạn xem chương trình, có gì thắc mắc mình sẽ trao đổi ở đây.


Được sửa bởi rockc4 ngày Sat May 22, 2010 9:30 pm; sửa lần 1.
Về Đầu Trang Go down
Xem lý lịch thành viên
blue
giám đốc điều hành
giám đốc điều hành
avatar

Tổng số bài gửi : 96
Join date : 28/12/2009
Age : 28
Đến từ : ninh thuận

Bài gửiTiêu đề: Re: Bài tập Counter0   Sat May 22, 2010 5:11 pm

chị phương nói đúng,sẽ bị rung phím.e nhớ thầy Mỹ có nói là chống rung được bằng phần cứng (dùng RC gì đó),tiếc là e ngủ quên mất (trụ được 30 phút đầu, nửa tỉnh nửa mê trong suốt quãng thời gian còn lại Sleep ).chị phương chỉ lại cho e phương pháp này đi
còn e dùng delay để giải quyết thôi.e đang sửa lại đoạn code đó,nhưng chưa test thử nên chưa dám đưa lên đây.sẽ đưa lên ngay khi test xong

lol!
Về Đầu Trang Go down
Xem lý lịch thành viên
Lee
phó tổng giám đốc
phó tổng giám đốc
avatar

Tổng số bài gửi : 106
Join date : 29/12/2009
Age : 28
Đến từ : Tây Ninh

Bài gửiTiêu đề: Re: Bài tập Counter0   Sat May 22, 2010 6:11 pm

Àh, cái vụ chống rung phím bằng phần cứng hôm đó t còn tỉnh để nghe . Chúng ta sẽ dùng 1 cái tụ, mắc cái tụ giữa mass và điện trở kéo lên nguồn(cách mắc giống như mạch để reset) để san bằng các gai xuất hiện do rung phím, giống như cách lọc gợn sóng.( Nếu nhớ không nhầm là như thế ).
Còn về chương trình trên, t làm giống chị P, có điều khi ấn phím lần thứ 10 thì led sẽ nhấp nhái, ấn lần thứ 11 thì led tắt, cứ thế đến lần 20 thì led lại chớp tắt.....
Code:
void interrupt isr()
{ if(T0IE && T0IF)
{ T0IF=0;
TMR0=0xF6;
PORTE ^=7; // xor 3bit RE0,RE1,RE2. 7=111B
}
c=TMR0;
while(TMR0==c) // CHO SU THAY DOI CUA BUTTON
{ __delay_ms(150); // CHO LED NHAY
PORTE ^=7;
}
PORTE=0xFF; // DUA PORTE VE TRANG THAI BAN DAU, LED CHI SANG O LAN THU 10, SAU DO RESET LAI. (xuất 0 thì led sáng, xuất 1 thì led tắt)
}
Còn về phần rung phím, ý tưởng cũng giống như thầy Mỹ nói: See and Wait(hay W a S ấy, không nhớ rõ do gật gù ). Khi phát hiện ra sự thay đổi của nút nhấn thì chưa cho TMR0 tăng liền, mà phải chờ cho đến khi nút nhấn được xác lập, của 8051 là 30ms, còn PIC thì không biết bao nhiêu, chắc cũng khoảng đó). Sau đó hỏi lại phím 1 lấn nữa để xác nhận việc chuyển mức, nếu có chuyển trạng thái thì cho TMR0 tăng lên 1.
Code:/nằm trong main()
* while(1)
* { c=TMR0;
* if(RA4==0)
* { __delay_ms(30); TMR0=c; } // CHO SU ON DINH CUA PHIM NHAN
* if(RA4==0) TMR0=TMR0+1; // NEU RA4=0 THI THAT SU CO NHAN PHIM, // KHI DO MOI TANG TMR0
* __delay_ms(50); // CHO RA4 TRO VE GIA
TRI 1
* }
Ở đây, TMR0 đếm lên khi có xung kích cạnh xuống.
Chương trình t chưa test được vì mô phỏng bằng protues sẽ ko phát hiện được rung phím. Còn phần cứng thì chắc là do config bit nên chạy sai hết cả(mô phỏng protues thì ok).Anh em xem góp ý sữa chữa cái đoạn code này dùm nghen.
Và rất quan trọng, t chưa hiểu hết các ý nghĩa của các từ khóa config bit, đọc datasheet thấy có 1 số bit nằm trong từ khóa, còn 1 số từ khóa khác k biết ý nghĩa là gì tại nó không có trong datasheet, chẳng hạn XT hay RC.
Anh em biết ý nghĩa từ khóa nào thì post lên, tổng hợp lại cho đỡ rối cái config( config mà sai là chạy sai lất hết , hiện chưa biết chỉnh sữa lại config lại như thế nào! )
Về Đầu Trang Go down
Xem lý lịch thành viên
Lee
phó tổng giám đốc
phó tổng giám đốc
avatar

Tổng số bài gửi : 106
Join date : 29/12/2009
Age : 28
Đến từ : Tây Ninh

Bài gửiTiêu đề: Re: Bài tập Counter0   Sat May 22, 2010 10:56 pm

Phát hiện đầu tiên vể code chống rung phím, nhờ kil89.
Code(repair lần 1):
while(1)
* { c=TMR0;
odd=RA4;
* if(odd==1 &&RA4==0)
* { __delay_ms(30); TMR0=c; } // CHO SU ON DINH CUA PHIM NHAN
* if(odd==1 && RA4==0) TMR0=TMR0+1;
* }
Đoạn code này làm cho việc TMR0 tăng không còn phụ thuộc vào bit T0SE( tại mình tự tay cho nó tăng mà). Ý tưởng: TMR0 chỉ tăng khi trạng thái trước đó là 1, trạng thái sau là 0,VD nếu có thằng nào ấn nút rồi giữ luôn thì trạng thái trước sẽ là 0, và trạng thái sau cũng là 0=>ko tăng TMR0. ( Cái này áp dụng tốt cho 8051, pic được hỗ trợ đếm khi có kick cạnh lên hay cạnh xuống nên chắc có lẽ sẽ có giải thuật tốt hơn)
Về Đầu Trang Go down
Xem lý lịch thành viên
rockc4
trưởng phòng
trưởng phòng


Tổng số bài gửi : 35
Join date : 30/03/2010

Bài gửiTiêu đề: Re: Bài tập Counter0   Sat May 22, 2010 11:49 pm

Cách của Hiệp cũng là cách người ta thường dùng để đọc phím từ 1 chân bất kì (ko phải chân ngắt), với 1 biến đếm (vai trò TMR0 trong đoạn code này) để mỗi khi có sự thay đổi trạng thái phím (1 --> 0 chẳng hạn) thì biến đếm đc tăng lên.
Đoạn code kiểm tra trạng thái trong phần while(1) là cách thường dùng để chống rung phím.

Theo cách trên Timer0 không tự tăng - mà đc cộng thêm sau mỗi lần xác nhận là có nhấn phím. Cho nên nói chính xác là, nó chưa hẳn là chức năng counter của bộ timer.

Nếu phần cứng không phải là phím nhất mà là lazer, hồng ngoại, cảm biến khác ... thì sẽ không phải nhức đầu vì phần chống rung phím này (chuyển qua ngâm cứu chống nhiễu Very Happy )

Còn với bộ counter, mình không kiểm soát được việc nó đọc bao nhiêu xung, cứ mỗi xung thì nó lại tự tăng giá trị chứa trong TMR0.
cách tốt nhất để đảm bảo có lẽ là dùng delay. Vấn đề là dùng delay thế nào?

NGoài ra để hạn chế rung = phần cứng thì nên gắn thêm tụ C như Hiệp nói.
Về Đầu Trang Go down
Xem lý lịch thành viên
Nhok_kid
phó giám đốc
phó giám đốc
avatar

Tổng số bài gửi : 66
Join date : 29/12/2009
Age : 28
Đến từ : Hà Tĩnh

Bài gửiTiêu đề: Re: Bài tập Counter0   Sun May 23, 2010 12:52 am

Mình dùng cách này (chưa test ^ ^ do ko có gì test cả - cháy mạch nạp rồi)
Ý tưởng : vẫn dùng cạnh tác động (ở đây mình chọn cạnh xuống), khi nhấn nút, lập tức TMR0 tăng lên, mình lưu lại giá trị này và sau 30ms nạp lại cho TMR0 nhằm xóa mọi tác động nếu có trong 30ms đó.

đoạn chương trình trong main

while(1)
{
while(RA4); // chờ nhấn phím, thoát ra ngay khi nhấn phím
c = TMR0; // lưu giá trị dc tăng lên 1 của TMR0
__delay_ms(30);
TMR0 = c; // loại bỏ mọi tác động trong thời gian delay
}

nếu nhấn phím giữ hoài thì khi quay lại vòng lặp giá trị TMR0 sẽ chỉ thay đổi khi có cạnh xuống xuất hiện thời điểm sau lệnh TMR0 = c và trc lệnh c= TMR0 =>> thời gian rất ngắn, theo mình thì ko có sai số chỗ này.
Về Đầu Trang Go down
Xem lý lịch thành viên
blue
giám đốc điều hành
giám đốc điều hành
avatar

Tổng số bài gửi : 96
Join date : 28/12/2009
Age : 28
Đến từ : ninh thuận

Bài gửiTiêu đề: Re: Bài tập Counter0   Sun May 23, 2010 11:12 am

cách của Lee và Đại và của mình nữa,ý tưởng là giống nhau.mình đã test thử rồi,chạy ok.chỉ góp ý là mỗi lần bấm phím sẽ gồm nhấn xuống và thả ra.trạng thái thả ra,tức RA4 =1 trở lại chính là thời điểm kết thúc nhấn phím.ta sẽ bắt thời điểm này để làm led hiển thị
Về Đầu Trang Go down
Xem lý lịch thành viên
Nhok_kid
phó giám đốc
phó giám đốc
avatar

Tổng số bài gửi : 66
Join date : 29/12/2009
Age : 28
Đến từ : Hà Tĩnh

Bài gửiTiêu đề: Re: Bài tập Counter0   Sun May 23, 2010 1:17 pm

cách của Hiệp thì hiểu rồi nhưng cách của Hải đâu?
Về Đầu Trang Go down
Xem lý lịch thành viên
blue
giám đốc điều hành
giám đốc điều hành
avatar

Tổng số bài gửi : 96
Join date : 28/12/2009
Age : 28
Đến từ : ninh thuận

Bài gửiTiêu đề: Re: Bài tập Counter0   Sun May 23, 2010 1:55 pm

đây:
Spoiler:
 
Về Đầu Trang Go down
Xem lý lịch thành viên
anhcmut
phó phòng
phó phòng


Tổng số bài gửi : 24
Join date : 10/06/2010

Bài gửiTiêu đề: cho em hỏi cái này chut.   Fri Feb 25, 2011 12:34 pm

mình dùng counter0 mà dùng dao động nội để đưa vào chân A4 dùng để đếm xung được không ạ?
Về Đầu Trang Go down
Xem lý lịch thành viên
Sponsored content




Bài gửiTiêu đề: Re: Bài tập Counter0   

Về Đầu Trang Go down
 
Bài tập Counter0
Về Đầu Trang 
Trang 1 trong tổng số 1 trang

Permissions in this forum:Bạn không có quyền trả lời bài viết
LỚP DD07KSTN :: Câu lạc bộ nghiên cứu khoa học :: PIC 16-
Chuyển đến