Thông báo

Collapse
No announcement yet.

lập trình xử lý timeout!

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • lập trình xử lý timeout!

    tui có phần cứng thế này,đơn giản thôi:một nút bấm thường hở ở chân p1.0,một con led hiển thị ở chân p2.0

    nhiệm vụ là khi bấm nút trên 5 lần thì led sáng,nhưng chỉ được thực hiện việc này trong 10 giây,nếu không sẽ nhảy qua làm việc khác

    bạn nào giúp tớ làm cái software đi(điều kiện:không dùng ngắt.Các bạn dùng ngôn ngữ ASM nhé!)
    Last edited by voduychau; 11-05-2006, 22:49.

  • #2
    Để có được thời gian chính xác thì phải dùng timer. Trường hợp của bạn không muốn dùng ngắt thì có thể polling cờ tràn của timer để tính thời gian. Xen kẽ quá trình polling cờ tràn timer, bạn hãy polling cả tín hiệu phím bấm tại chân P1.0.
    Như vậy có 2 quá trình: đếm lần tràn của timer để timeout và đếm lần bấm phím. Rất đơn giản, khi đủ điều kiện để timeout (tức là đủ số lần tràn để đạt 10 giây) thì bạn hãy xóa số đếm lần bấm phím đi, còn số đếm lần bấm phím khi đủ thì cứ việc sáng LED rồi tự xóa về 0.
    Hãy tưởng tượng bài toán này như một người leo cầu thang có 5 bậc để bật một cái đèn. Người đó cứ leo từng bậc 1, nhưng không leo nhanh thì bị timeout bắt quay trở về đầu. Đó là về ý tưởng, lập trình theo đó cũng không khó.

    Thân mến,
    blackmoon.

    Comment


    • #3
      Nếu viết bằng hợp ngữ trên Reads51, giả định rằng phím bấm tạo ra mức 0 tại chân P1.0, thay đổi đề bài một chút rằng bấm đủ 5 lần trong 10 giây thì đảo trạng thái của LED tại chân P2.0, bạn có thể viết như sau:
      Code:
      #include        <sfr51.inc>
      
      #define         KeyCount        r2
      #define         OverflowCount   r3
      Key             bit             0x00
      ;================================================================
                      org     0x0000
                      sjmp    Main
      
                      org     0x0040
      Main:
                      mov     sp,#0x6f
                      acall   Init
              MainLoop:
                      acall   ScanKey
                      acall   CheckTimeout
                      sjmp    MainLoop
      ;================================================================
      Init:
                      ; Initialize timer 0 in 16bit timer mode
                      mov     tmod,#0x01
                      ; Run timer 0
                      setb    tr0
      
                      clr     Key
                      mov     KeyCount,#0
                      mov     OverflowCount,#0
                      ret
      ;================================================================
      ScanKey:
                      ; Key is pressing?
                      jb      p1.0,NotPress
                      ; yes, then check the previous status of Key
                      jb      Key,ExitKey
                      setb    Key
                      ; Increase key count
                      inc     KeyCount
                      ; Enough 5 times?
                      cjne    KeyCount,#5,ExitKey
                      ; if yes, then reset counts
                      mov     KeyCount,#0
                      mov     OverflowCount,#0
                      ; complement LED status
                      cpl     p2.0
                      sjmp    ExitKey
              NotPress:
                      clr     Key
              ExitKey:
                      ret
      ;================================================================
      CheckTimeout:
                      ; overflow?
                      jnb     tf0,ExitTimeout
                      ; yes, then reload timer 0...
                      mov     tl0,#low(-50000)
                      mov     th0,#high(-50000)
                      ; clear flag
                      clr     tf0
                      ; increase overflow count
                      inc     OverflowCount
                      ; enough (200*50ms = 10s)?
                      cjne    OverflowCount,#200,ExitTimeout
                      ; if yes, then reset counts
                      mov     OverflowCount,#0
                      mov     KeyCount,#0
              ExitTimeout:
                      ret
      ;================================================================
      end
      Thân mến,
      blackmoon.
      Last edited by blackmoon; 12-05-2006, 18:30.

      Comment


      • #4
        cách này hơi dài,tớ có viết 1 đoạn khác ngắn hơn một chút,để soạn lại rồi pót cho mọi người xem

        Comment


        • #5
          Đây là chương trình tôi viết bằng C các bạn tham khảo và cho ý kiến

          void main()
          {
          int i=0;
          init_timer0();
          EA = 1;
          while(P1_0=1)
          {
          i=i++
          P1_0 = 0;
          if(i==10){
          P2_0 = !P2_0;
          i=0;}
          if(index>100)break;
          }
          }
          ////////////////////////////////////////////////////////////////////////
          void init_timer0()
          {
          ET0 = 0 ; // Not interrupt Timer0
          TR0 = 0 ; // Timer0 not operate
          TMOD &= 0xF0 ; // Clear Timer0 bit while Timer1 unchange
          TMOD |= 0x01 ; // Set 16 bit for Timer0 manual reload
          TF0 = 0 ; // Not Overflow
          TH0 = TH0_hight ; // Time delay 50ms order to Interrupt
          TL0 = TH0_low ;
          TR0 = 1 ; // Timer0 Operate
          ET0 = 1 ; // Interrupt Enabled
          }
          /////////////////////////////////////////////////////////////
          void timer0(void) interrupt 1
          {
          EA = 0 ; // Disabled Interrupt of System
          TR0 = 0 ; // Timer0 not Operate
          TH0 = TH0_hight ; // interrupt 50 ms
          TL0 = TH0_low ;
          t = t + 1;
          TF0 = 0 ;
          //---------------------------------------------
          index++ ;
          if (index >100) index = 0 ;
          //---------------------------------------------

          TR0 = 1 ;
          EA = 1 ;
          }

          Comment


          • #6
            Nguyên văn bởi kienvtc
            Đây là chương trình tôi viết bằng C các bạn tham khảo và cho ý kiến

            void main()
            {
            int i=0;
            init_timer0();
            EA = 1;
            while(P1_0=1) // "== "chứ không phải là " = "

            {
            i=i++ ;// Thiếu dấu ;
            P1_0 = 0;
            if(i==10){
            P2_0 = !P2_0;
            i=0;}
            if(index>100) break;
            }
            }
            ////////////////////////////////////////////////////////////////////////
            void init_timer0()
            {
            ET0 = 0 ; // Not interrupt Timer0
            TR0 = 0 ; // Timer0 not operate
            TMOD &= 0xF0 ; // Clear Timer0 bit while Timer1 unchange
            TMOD |= 0x01 ; // Set 16 bit for Timer0 manual reload
            TF0 = 0 ; // Not Overflow
            TH0 = TH0_hight ; // Time delay 50ms order to Interrupt
            TL0 = TH0_low ;
            TR0 = 1 ; // Timer0 Operate
            ET0 = 1 ; // Interrupt Enabled
            }
            /////////////////////////////////////////////////////////////
            void timer0(void) interrupt 1
            {
            EA = 0 ; // Disabled Interrupt of System
            TR0 = 0 ; // Timer0 not Operate
            TH0 = TH0_hight ; // interrupt 50 ms
            TL0 = TH0_low ;
            t = t + 1;
            TF0 = 0 ;
            //---------------------------------------------
            index++ ;
            if (index >100) index = 0 ;
            //---------------------------------------------

            TR0 = 1 ;
            EA = 1 ;
            }
            Mình xin có ý kiến về chương trình của bạn thế này. Chương trình của bạn không có xử lý chống rung cho phím bấm.

            Biến t đếm số lần xảy ra ngắt để làm gì hả bạn? Có lẽ trong chương trình này không cần mà dùng cho ứng dụng khác thì đúng hơn.

            Mà yêu cầu của voduychau là không dùng ngắt cơ mà bạn. Nếu dùng ngắt thì đơn giản quá .

            Với lại nếu giữ phím vào chân P1_0 thì bạn định xử lý kiểu gì. Đơn giản chỉ cần thời gian giữ phím lớn hơn thời gian thực hiện các lệnh trong hàm while(1) thì nó sẽ đếm sai số lần nhấn phim sao? vì nó sẽ liên tục thực hiện lệnh trong hàm while(1). Như vậy thì mỗi lần nhấn phím phải được tính là 1 lần nhấn và 1 lần nhả phím.

            Do đó, mình xin đưa ra một giải pháp về thuật giải thôi còn chi tiết chương trình không thì mời các bạn viết.

            Mình dùng Timer0 ở chế độ 16 bit như bạn trên dùng và khởi tạo một thời gian là 50ms. Khi đó 10s là 200 lần xảy ra ngắt Timer0. Mình không dùng ngắt nào cả.

            Code:
            void main(void){
                unsigned  char i, counterTimer, counterKey;
                for(i=0;i <200;i++){
                    Khởi tạo timer0; // trong hàm có lệnh xóa cờ ngắt
                    while( cờ ngắt Timer0 == 0){
                         nếu phím được ấn thì tăng biến đếm counterKey và chờ cho phím nhả ra;
                         
                    };
                   nếu counterKey == 5 thì cho led sáng; và break;
                };
            }
            Thời gian để khẳng định rằng phím được nhấn được lấy trực tiếp từ timer0 lưu vào một biến và chờ cho Timer0 đến một thời gian nữa.

            Không hiểu những điều mình nói có đúng không nhỉ? Mong các bạn cho ý kiến.

            Chúc các bạn thành công.
            Last edited by ngohaibac; 12-05-2006, 22:32.
            Technical sale at WT Microelectronics S'pore
            Hỗ trợ dự án sử dụng các hãng Texas Instrument, STMicro, Freescale, Fairchild, International Rectifier, Ublox, Lumiled, Maxim
            Liên hệ: 0915.560.511 hoặc ngo.haibac@wtmec.com

            Comment


            • #7
              hic,các bạn làm ơn giúp mình bằng ASM,trong Nam ngôn ngữ C cho vdk ko thông dụng lắm
              tớ có đoạn code thế này,ko cần xử lý chống rung đâu vì tớ làm việc đó bằng phần cứng,các bạn chỉ cần nghĩ thật đơn giản,và làm theo những yêu cầu trên là được rồi

              Code:
              org 0000h
              reset:  setb p1.5                  
                        clr p1.4                   ;
                        mov p3,#00000000b          ;
                        mov p3,#00001000b          ;
                        mov p3,#00000000b          ;
              
                      jb p1.0,$                  
                      jnb p1.0,$                
              tang:   inc 30                     
                      cjne 30,#5d,check          
                                                   
                      setb p1.1                   
                      setb p1.2                  
                      call delay8s
                      clr p1.2                    
                      jmp next               
              
              check:  mov r1, #80
              lap1:   mov r2, #200
              lap2:   mov r3, #250
                      jnb p1.0,tang
                      djnz r3,$
                      djnz r2,lap2
                      djnz r1,lap1
                      jmp reset
              cái này trích trong 1 đề tài của tớ,các chân không biết còn đúng ko nữa,lâu quá nên quên mất

              cái này do mấy bạn mới học vdk hỏi mình đấy,vì chưa học lệnh ngắt nên chỉ giới hạn như vậy thôi

              code thật ra ko quá khó,nhưng cũng rất thú vị

              mong được bổ sung!

              Comment


              • #8
                Nguyên văn bởi voduychau
                trong Nam ngôn ngữ C cho vdk ko thông dụng lắm
                Mình không nghĩ thế đâu.
                Đoạn code voduychau đưa ra mình đọc không rõ lắm về ý tưởng, code viết cũng có một số chỗ không hợp lý:
                Code:
                cjne 30,#5d,check
                5d là số gì? Nếu là hexa thì phải là 0x5d hoặc 5dh, nếu là 5 thập phân thì không cần có d ở sau.
                Code:
                jmp next
                next là nhãn ở đâu trong chương trình, làm việc gì ở đó?

                Nói chung voduychau không chú thích ý nghĩa các lệnh mà bạn sử dụng, phần cứng cũng không chỉ ra rõ ràng, nhất là giải thuật xử lý bài toán. Bạn hãy làm rõ những điểm trên để mọi người tham khảo.

                Thân mến,
                blackmoon.

                Comment


                • #9
                  hic,cái này là đồ án của tớ về điều khiển qua điện thoại,viết trên 1 chương trình đặc biệt nền MsDOS,tớ bỏ cái này lâu rồi nên ko nhớ rõ lắm

                  "5d" là số hồi chuông đổ,nếu ko đủ nó sẽ reset,còn nếu đủ thì nó chuyển sang đoạn "next",tớ nghĩ nếu là số hexa mới không cần ghi ký hiệu "h" chứ ?!?

                  Comment


                  • #10
                    Nguyên văn bởi voduychau
                    hic,cái này là đồ án của tớ về điều khiển qua điện thoại,viết trên 1 chương trình đặc biệt nền MsDOS,tớ bỏ cái này lâu rồi nên ko nhớ rõ lắm

                    "5d" là số hồi chuông đổ,nếu ko đủ nó sẽ reset,còn nếu đủ thì nó chuyển sang đoạn "next",tớ nghĩ nếu là số hexa mới không cần ghi ký hiệu "h" chứ ?!?
                    Đoạn chương trình của Châu thiếu hiệp post lên chỉ là một phần, còn nhiều đoạn không hợp lý cho lắm.
                    Theo bạn thì trong Nam, C không thông dụng cho lắm thì điều này ngược lại mới đúng, nếu bạn đã dùng C để viết thì không bao giờ muốn quay lại với ASM.

                    Còn cái đoạn 5d, thì không phải vậy đâu, tất cả các chương trình C viết cho VDK tui đã dùng qua thì có quy luật sau, cội của nó từ C chuẩn:
                    0h hoặc 0x cho HEX, 0b cho nhị phân và không viết gì mặc định là thập phân.

                    Châu nên chú ý đến cách viết của anh Blackmoon, rất tường minh, dễ hiểu, viết mọi người đều hiểu được, đọc chương trình của cậu hơi bị mất thời gian.

                    Comment


                    • #11
                      Theo như đề bài của bạn VDC, giả sử rằng Sw = high khi nhả, và Sw = low khi bấm, T.L tui code thử bằng một technique gọi là State Machine. Code có thể dài hơn của Mod Blackmoon, và có thể chưa được tối ưu, nhưng điểm chính là giới thiệu một cách lập trình tuy không phải là mới mẻ, nhưng không được đề cập đến nhiều trong forum này. Do đó T.L tui mạo muội múa rìu qua mắt thợ. Nếu có gì sai sót xin các vị đại hiệp chỉ giáo thêm cho T.L được mở rộng tầm mắt vậy. Đa tạ lắm thay.

                      PS: Đoạn code này T.L chỉ simulate tren uVision2 và chưa chạy thử trên hardware. Nếu vị đại hiệp nào bỏ chút thời gian debug và chạy thử trên hardware thật, thì có thể modify lại code and include file cho phù hợp. Xin vui lòng post lại bug trong đoạn code dưới đây để chúng ta cùng trao đổi, thảo luận. Đa tạ.
                      Code:
                      ;================================================================================================
                      ;File name	:  StateMachine Main.A51 
                      ;MCU		:  S87C752
                      ;Assembler	:  Keil A51
                      ;Author		:  T.L
                      ;Version	:  1.0
                      ;Date		:  05/16/2006
                      ;========================================
                      Name	Main
                      
                      Extrn	code	(Preset, Delay)	
                      ;========================================
                      $include (REG752.inc)			; Include register defIniLion file.
                      ;========================================
                      ;*	     Equates			*
                      ;========================================
                      SysClk		equ	12000000	;
                      T0_Reload	equ	(65536-15536)	;
                      Sw		equ	P3.4		;
                      Led		equ	P0.3		;
                      State0		equ	0		;
                      State1		equ	2		;
                      State2		equ	4		;
                      ;========================================
                      ;*	   Memory Declaration           *
                      ;========================================
                      iseg		at	30h		; Relocate SP to 30h address
                      Stack:		ds	10h		; Reserve 16 bytes for Stack pointer
                      
                      bseg		at	20h		; Bit segment starts @ 20H
                      Ten_Sec:	dbit	1		;
                      
                      dseg 		at	25h		; Data segment starts @ 25H
                      Sw_Sta:		ds	1		;			
                      Time:		ds	1		;
                      Sw_press:	ds	1		;
                      ;========================================
                      ;*	    Register Usage		*
                      ;========================================
                      ;R0 = Genetral usage
                      ;R1 = Genetral usage
                      ;R2 =
                      ;R3 =
                      ;R4 =
                      ;R5 =
                      ;R6 = Delay counter
                      ;R7 = Delay counter
                      ;========================================
                      ;*	Reset and Interrupt Vectors	*
                      ;========================================
                      cseg	at	0000h			; Reset Vector
                      	ajmp Main			; Jump to Main program
                      	
                      cseg	at	0003h			; Ext Int0 Vector
                      	reti				; Return
                      	
                      cseg	at	000Bh			; T0 Int Vector
                      	ajmp Tick			; 10sec Tick	
                      	
                      cseg	at	0013h			; Ext Int1 Vector
                      	reti				;
                      	
                      cseg	at	001Bh			; T1 Int Vector	
                      	reti				; Return
                      			
                      cseg	at	0023h			; Serial Int Vector
                      	reti				; Return
                      	
                      cseg	at	002Bh			; ADC Int Vector
                      	reti				; Return
                      	
                      cseg	at	0033h			; PWM Int Vector
                      	reti				; Return
                      ;========================================
                      Tick:	djnz Time,Exit			; 10sec timekeeper
                      	clr TR				; Stop Timer0
                      	setb Ten_Sec			; Set flag
                      	mov Time,#200			; Reload counter for next use
                      Exit:	reti				;
                      ;========================================
                      Main_	segment 	code		;
                      	rseg		Main_		;
                      	using		0		; Using Bank 0
                      ;========================================
                      ;*	    Main Program		*
                      ;========================================
                      Main:	mov SP,#Stack-1			; Relocate Stack to upper memory location
                      	acall Preset			; Preset
                      Again:	mov TL,#Low(T0_Reload)		; 50ms
                      	mov TH,#High(T0_Reload)		;
                      	mov Time,#200			; T0 overflow rate = 50ms x 200 = 10s 
                      	mov Sw_press,#5			; Switch press counter
                      
                      Entry:	mov dptr,#Sta_Tb		;
                      	mov A,Sw_Sta			;
                      	jmp @A+dptr			; Go to Jump-Table with Sw_Sta value in Acc
                      
                      ;================================================================================================
                      /* State 0: Waiting for Sw input changes from high to low. Once the transition has been detected,
                      /* Timer0 will kick in and overflow every 50ms. Therefore, it needs 200 counter to reach 10sec */
                      ;================================================================================================
                      
                      Sta_0: 	mov C,Sw			; Read port
                      	jc Out0				; Input still high, no key press
                      	orl Sw_Sta,#2			; 2 bytes offset for each entry of the table
                      	setb TR				; Start T0
                      Out0:	jmp Entry			; Go to State1
                      
                      ;================================================================================================
                      /* State 1: If input has changed from high to low, verify input again. If it is a valid input,
                      /* start counting down the times switch is pressed, and check for the timeout flag. If flag is 
                      /* set, 10sec has elapsed. Reset counter, timer0, Sw_Sta and return to State 0. If flag is off 
                      /* and Sw_press counter is = 0, turns Led on and go to State 2. If input is bounced, go back 
                      /* to State 0 */
                      ;================================================================================================
                      
                      Sta_1:	jbc Ten_Sec,TimeUp		; Test 10Sec flag
                      	mov C,Sw			; Read port
                      	jc Out1				; Invalid key, key bounces
                      	acall Delay			; Debounce 10ms
                      	mov C,Sw			; Read port again
                      	jnc Valid			; Valid key, input has changed from high to low
                      	jmp Out1			; Exit 
                      
                      Valid:	djnz Sw_press,Out1		; Switch has been pressed 5 times		
                      	cpl Led				; Turn Led on
                      	mov Sw_Sta,#4			; 2 bytes offset for each entry of the table
                      Out1:	jmp Entry			; If Sw_press < 5, stay in State1
                      
                      TimeUp: anl Sw_Sta,#0			; 10sec has elapsed, clear flag 
                      	jmp Entry			; Reset Sw_Sta, exit 
                      
                      ;================================================================================================
                      /* State 2: Delay for 30ms then turn Led off. Reset Sw_Sta byte and go back to State 0 */
                      ;================================================================================================
                      
                      Sta_2: 	acall Delay			;
                      	acall Delay			;
                      	acall Delay			;
                      	cpl Led				; Turn Led off
                      	anl Sw_Sta,#0			; Reset State byte
                      	clr Ten_Sec			; Clr flag if it's set
                      	jmp Again			;
                      
                      ;================================================================================================
                      /* State_Table is entered with the value of Sw_Sta in Acc. At the beginning of the table Sw_Sta = 
                      /* 0 for State 0. Ajmp is 2 byte instruction, thus PC = PC+2. Therefore, everytime State changes,
                      /* Sw_Sta increment by 2 for correct entry.      */ 
                      ;================================================================================================
                      
                      Sta_Tb:	ajmp Sta_0			;
                      	ajmp Sta_1			;
                      	ajmp Sta_2			;
                      
                      ;========================================
                      	end				;
                      
                      
                      Name	Preset
                      Public	Preset
                      ;========================================
                      $include (REG752.inc) 
                      ;========================================
                      ;*	     Equates			*
                      ;========================================
                      T0_Reload	equ	(65536-15536)	;
                      Preset_	segment		code		;
                      	rseg		Preset_		;
                      ;========================================
                      ;          Port Configuration
                      ;========================================
                      ;       |PxM1.x|PxM2.x|Mode
                      ;       |  0   |  0   |Bidirectional
                      ;       |  0   |  1   |Push-Pull
                      ;       |  1   |  0   |High Impedance
                      ;       |  1   |  1   |Open Drain
                      ;========================================
                      Preset:	mov P0,#00001000b		; P0 = output, Led off
                      	mov P1,#0FFh			; P1 = input
                      	mov P3,#0FFh			; P3 = input
                      ;========================================
                      ;          Adc Configuration
                      ;========================================
                      	mov ADCON,#0C0h			; Clear ADC control reg
                      	mov ADAT,#00h			;
                      ;========================================
                      ;           PWM Configuration
                      ;========================================
                      	mov PWCM,#00h			; PWM compare
                      	mov PWENA,#0FEh			; Disable PWM output
                      	mov PWMP,#00h			; PWM prescaler
                      ;========================================
                      ;           I2c Configuration
                      ;========================================
                      	mov I2CFG,#00h			;
                      	mov I2CON,#81h			;
                      	mov I2DAT,#80h			;
                      ;========================================
                      ;     Timers/Interrupt Configuration
                      ;========================================
                      	mov TCON,#00h			; T0's clk = internal clk, no ext Int
                      	mov PSW,#00h			; Clear all flags, using Bank 0
                      	mov PCON,#00h			;
                      	mov TL,#Low(T0_Reload)		;
                      	mov TH,#High(T0_Reload)		;
                      	mov RTL,#Low(T0_Reload)		;
                      	mov RTH,#High(T0_Reload)	;
                      ;========================================
                      ;        Interrupt Configuration
                      ;========================================
                      ;       IE.7 EA   = Global interrupt
                      ;	IE.6 EAD  = ADC conversion complete
                      ;       IE.5 ETI  = Timer1 
                      ;       IE.4 ES   = I2C serial port
                      ;       IE.3 EPWM = PWM counter overflow
                      ;       IE.2 EX1  = Extrn int1
                      ;       IE.1 ET0  = Timer0
                      ;       IE.0 EX0  = Extrn int0
                      ;========================================
                      	mov IE,#10000010b		; Enable Global, Timer0
                      ;========================================
                      	clr A				;
                      	mov R0,#2			; Set pointer
                      	mov R1,#45			; Load counter
                      Clrmem:	mov @R0,A			; Clear memory
                      	inc R0				;
                      	djnz R1,Clrmem			;
                      	mov R0,A			; Clear R0
                      	ret				;
                      ;========================================
                      	end				;
                      
                      Name	Delay
                      Public	Delay
                      ;========================================
                      $include (Reg752.inc)		        ; include Register definition file.
                      ;========================================
                      Delay_	segment		code		;
                      	rseg		Delay_		;
                      ;========================================
                      Delay:	mov R7,#20			; 1
                      LoopD:	mov R6,#250			; 1
                      	djnz R6,$			; (2x250)=500
                      	djnz R7,LoopD			; (500x20)+(2+1)x20=10.060ms
                      	ret				;
                      ;========================================
                      	end				;
                      Last edited by thelam; 27-05-2006, 08:39.

                      Comment

                      Về tác giả

                      Collapse

                      voduychau Tìm hiểu thêm về voduychau

                      Bài viết mới nhất

                      Collapse

                      Đang tải...
                      X