⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 研讨会范例.asm

📁 一个通过ADC并在LCD上显示出来的电压表 希望对初学者有帮助
💻 ASM
字号:
; ****************************************************************************						*												*
; * 日期	    : 10/21/04; * 版本	    : 0.1	
; * 描述	    : 该程序执行4个功能技巧程序,它们是:多个LED的驱动,
; * 多个按键的识别,更高准度的读取传感器, delta-sigma A/D转换器          										*
; *LED: RC0/RC1/RC2			
; *按键: RA1/AN1				
; *范围选择-> 电位计:RE1/AN6 电阻:RC4		
; *Delta Sigma A/D-> A/D 输入:RA3/CIN- I/O:RB4	
; * 最后修改   : 										*
; *************************************************************************
	list      p=16f877a            ; MCU定义
	#include <p16f877a.inc>        ; MCU特殊寄存器定义
;*****普通寄存器定义 
w_temp        	EQU     0x70     ; 中断中,W寄存器的保护
status_temp   	EQU     0x71    ; 中断中,status寄存器的保护
temp1		equ	0x20	; 临时变量
temp2		equ	0x21		
temp3		equ	0x22	
debounce	equ	0x23		; 按键状态变量
datapointer_l	equ	0x24
datapointer_h	equ	0x25	; 储存 A/D 结果
result_l	equ	0x26
result_h	equ	0x27
counter_l	equ	0x28
counter_h	equ	0x29	; 延时变量
s_ram		equ	0x2a
tmr1_temp	equ	0x2b


;*****************************************************************************
; 定义 PORTC<2:0> 和 TRISC<2:0> 常数,让每一个LED点亮.
; 在LxPORT 中,'1'为 5V 和 '0'为0V .
; 在LxTRIS中, '1'定义脚为输入,但不影响电路
;          '0'定义脚为输出,5V 或 0V, 由LxPORT决定.
; 如果想点亮一只LED,只要把LED的阳极定义输出为5V和阴极输出为0V,;
;其它定义为数字输入    
; 可参考技巧手册技巧TIP#2 .
; 注意根据所提供的原理图定义.
;******************************************************************************
L1PORT	EQU	B'00000000'; ### 设置 PORTC<2:0> ,点亮L1 (REG 4-1)
L1TRIS	EQU	B'11111000'; ### 设置 TRISC<2:0> ,点亮L1 (REG 4-2) 
L2PORT	EQU	B'00000000' ; ### 设置 PORTC<2:0> ,点亮L2 (REG 4-1) 
L2TRIS	EQU	B'11111000'; ### 设置 TRISC<2:0> ,点亮L2 (REG 4-2) 
L3PORT	EQU	B'00000000' ; ### 设置 PORTC<2:0> ,点亮L3 (REG 4-1) 
L3TRIS	EQU	B'11111000'; ### 设置 TRISC<2:0> ,点亮L3 (REG 4-2) 
L4PORT	EQU	B'00000000' ; ### 设置 PORTC<2:0> ,点亮L4 (REG 4-1) 
L4TRIS	EQU	B'11111000'; ### 设置 TRISC<2:0> ,点亮L4 (REG 4-2) 
L5PORT	EQU	B'00000000' ; ### 设置 PORTC<2:0> ,点亮L5 (REG 4-1) 
L5TRIS	EQU	B'11111000'; ### 设置 TRISC<2:0> ,点亮L5 (REG 4-2) 
L6PORT	EQU	B'00000000' ; ### 设置 PORTC<2:0> ,点亮L6 (REG 4-1) 
L6TRIS	EQU	B'11111000'; ### 设置 TRISC<2:0> ,点亮L6 (REG 4-2) 
LEDSOFF	EQU	B'11111000'; ### 设置 TRISC<2:0> ,关闭所有LED (REG 4-2)
;******************************************************************************
;**********************************************************************
	ORG     0x000             ; 复位矢量
	clrf    PCLATH            ; 确保为Page 0
  	goto    main              ; 跳到主程序	
	ORG     0x004             ; 中断入口矢量
	movwf   w_temp            ; 保护 W 寄存器内容
	movf	STATUS,w          ; 保护STATUS寄存器内容
	movwf	status_temp       ; 
; 中断服务程序可从这里开始
	movf    status_temp,w     ; 取回STATUS寄存器内容
	movwf	STATUS            ; 
	swapf   w_temp,f
	swapf   w_temp,w          ; 取回 W 寄存器内容
	retfie                    ; 
main
;	goto	Lab4		; *** 跳到 LAB#4 ***
;	goto	Lab3		; *** 跳到 LAB#3 ***
;	goto	Lab2		; *** 跳到 LAB#2 ***
;********************************************************************
; 定义LxPORT 和 LxTRIS ,点亮每个LED.
; 每个LED时序点亮500ms.
;********************************************************************
Lab1
	bcf	STATUS,RP0
	call	L1
	movlw	5
	call	Delay100Ms
	call	L2
	movlw	5
	call	Delay100Ms
	call	L3
	movlw	5
	call	Delay100Ms
	call	L4
	movlw	5
	call	Delay100Ms
	call	L5
	movlw	5
	call	Delay100Ms
	call	L6
	movlw	5
	call	Delay100Ms
	goto	Lab1
L1	movlw	L1PORT		; 点亮 L1
	movwf	PORTC
	bsf	STATUS,RP0
	movlw	L1TRIS
	movwf	TRISC
	bcf	STATUS,RP0
	return
L2	movlw	L2PORT		; 点亮 L2 
	movwf	PORTC
	bsf	STATUS,RP0
	movlw	L2TRIS
	movwf	TRISC
	bcf	STATUS,RP0
	return
L3	movlw	L3PORT		; 点亮 L3 
	movwf	PORTC
	bsf	STATUS,RP0
	movlw	L3TRIS
	movwf	TRISC
	bcf		STATUS,RP0
	return
L4	movlw	L4PORT		; 点亮 L4 
	movwf	PORTC
	bsf	STATUS,RP0
	movlw	L4TRIS
	movwf	TRISC
	bcf	STATUS,RP0
	return
L5      movlw	L5PORT		; 点亮 L5 
	movwf	PORTC
	bsf	STATUS,RP0
	movlw	L5TRIS
	movwf	TRISC
	bcf	STATUS,RP0
	return
L6      movlw	L6PORT		; 点亮 L6 
	movwf	PORTC
	bsf	STATUS,RP0
	movlw	L6TRIS
	movwf	TRISC
	bcf	STATUS,RP0
	return	
NoLEDS	bsf	STATUS,RP0
	movlw	LEDSOFF		; 关闭所有LED
	movwf	TRISC
	bcf	STATUS,RP0
	return
;********************************************************************************
; 在 RA1/AN1脚上读按键值,用 A/D 测量每个按键电压值.				
; 这段程序是从读最小电压值(无按键按下)到最大值(S2-S7),		
;  并调用Lab1中的点亮程序.							
; 电压值的计算,可参考原理图中的电阻值.						
; 启用 A/D,可定义ADCON0 和 ADCON1特殊寄存器.					
; 可参考技巧手册技巧Tip#5 .							
;********************************************************************************
Lab2
       movlw	B'00000000'; ### 设置 A/D 通道并启动A/D转换 (REG 9-2) 
       movwf	ADCON0
       bsf	STATUS,RP0
       movlw	B'00000000'; #选择A/D时钟为4MHZ INTOSC (TABLE 9-1 & REG 9-3) 
       movwf	ADCON1
       bcf	STATUS,RP0
	call	NoLEDS
RdSwtch	
	movlw	D'25'		; 延时
	call	DelayMs
	call	ConvertL		
	movf	ADRESH,w	; 把结果放到 w
	movwf	temp1
	movlw	D'00'	; ### 选择无按键按下电压值 ###
	subwf	temp1,w	; 2.2K*5V/(2.2K+6*1K)=1.34V -> 1.40*255/5=~72
	btfsc	STATUS,C	; 电压值 <= 1.40V?
	goto	ChkS2
	clrf	debounce
	call	NoLEDS
	goto	RdSwtch	; 跳到再次判断
ChkS2	movlw	D'00'; ### 选择按键S2按下电压值 ###
	subwf	temp1,w	; 2.2K*5V/(2.2K+5*1K)=1.53V -> 1.60*255/5=~82
	btfsc	STATUS,C	; 电压值 <= 1.60V?
	goto	ChkS3	 ; 无, 判断 S3
	movlw	B'00000100'	
	andwf	debounce,f  ; mask out bit 2
	xorwf	debounce,f  ; toggle bit 2, 1=first time button found pressed, 0=2nd
	btfsc	debounce,2  ; button found pressed for two measurements?
	goto	RdSwtch	   ; no
	call	L1
	goto	RdSwtch
ChkS3	movlw	D'00'; ### 选择按键S3按下电压值 ###
	subwf	temp1,w	  ; 2.2K*5V/(2.2K+4*1K)=1.78 -> 1.91*255/5=~98
	btfsc	STATUS,C	; 电压值 <= 1.91V?
	goto	ChkS4	 ; 无, 判断 S4
	movlw	B'00001000'	
	andwf	debounce,f  ; mask out bit 3
	xorwf	debounce,f  ; toggle bit 3, 1=first time button found pressed, 0=2nd
	btfsc	debounce,3  ; button found pressed for two measurements?
	goto	RdSwtch	   ; no
	call	L2
	goto	RdSwtch
ChkS4	movlw	D'00'; ### 选择按键S4按下电压值###
	subwf	temp1,w	; 2.2K*5V/(2.2K+3*1K)=2.12V -> 2.25*255/5=~115
	btfsc	STATUS,C	; 电压值 <= 2.25V?
	goto	ChkS5	; 无, 判断 S5
	movlw	B'00010000'	
	andwf	debounce,f   ; mask out bit 4
	xorwf	debounce,f   ; toggle bit 4, 1=first time button found pressed, 0=2nd
	btfsc	debounce,4    ; button found pressed for two measurements?
	goto	RdSwtch		; no
	call	L3
	goto	RdSwtch
ChkS5	movlw	D'00'; ### 选择按键S5按下电压值 ###
	subwf	temp1,w	; 2.2K*5V/(2.2K+2*1K)=2.62V -> 2.93*255/5=~150
	btfsc	STATUS,C	; 电压值 <= 2.93V?
	goto	ChkS6	; 无, 判断 S6
	movlw	B'00100000'	
	andwf	debounce,f  ; mask out bit 5
	xorwf	debounce,f  ; toggle bit 5, 1=first time button found pressed, 0=2nd
	btfsc	debounce,5  ; button found pressed for two measurements?
	goto	RdSwtch	   ; no
	call	L4
	goto	RdSwtch
ChkS6	movlw	D'00'; ### 选择按键S6按下电压值 ###
	subwf	temp1,w	; 2.2K*5V/(2.2K+1K)=3.44V -> 3.71*255/5=~190
	btfsc	STATUS,C	 ; 电压值 <= 3.71V?
	goto	ChkS7	; 无, 判断 S7
	movlw	B'01000000'	
	andwf	debounce,f ; mask out bit 6
	xorwf	debounce,f ; toggle bit 6, 1=first time button found pressed, 0=2nd
	btfsc	debounce,6 ; button found pressed for two measurements?
	goto	RdSwtch	  ; no
	call	L5
	goto	RdSwtch
ChkS7	movlw	B'10000000'	; S7 按下
	andwf	debounce,f ; mask out bit 7
	xorwf	debounce,f ; toggle bit 7, 1=first time button found pressed, 0=2nd
	btfsc	debounce,7 ; button found pressed for two measurements?
	goto	RdSwtch	; no
	call	L6
	goto	RdSwtch
ConvertL		
	bsf	ADCON0,GO
	btfsc	ADCON0,GO
	goto	$-1
	return
ConvertH		
	bsf	ADCON0,GO
	btfsc	ADCON0,GO
	goto	$-1
	return
;****************************************************************
; 用 A/D 读电位计POT1上的电压值,使用 RE1/AN6脚.		*
; 使用 RC4脚控制R5						*
; 当S2按下,放上R5,抬起时,移去R5				*
; 可参考技巧手册技巧 Tip#13 .					*
;****************************************************************
Lab3
uart_ini
	movlw	B'00000000'
	movwf	PORTC
	movlw	B'10000000'
	movwf	RCSTA
	bsf	STATUS,RP0
	movlw	B'10111111'
	movwf	TRISC
	movlw	D'25'	; 4M --> 2400 baud rate , BRGH = 1,
	movwf	SPBRG		
	movlw	B'00100000'
	movwf	TXSTA
	bcf	PIE1,TXIE
	bcf	STATUS,RP0
RdSw	call	RdSW1
	movwf	temp1
	btfsc	temp1,0		; 若S2按下,temp1<0> = 1
	goto	S2on
	bsf	STATUS,RP0	; S2 没按下
		             ; ### 把 RC4 设为数字输入口 (REG 4-2) 
	bcf	STATUS,RP0
	goto	RdPot
S2on	bsf	STATUS,RP0    ; S2 按下
		             ; ### 把 RC4 设为数字输出口(REG 4-2) 
	bcf	STATUS,RP0
		             ; ### 让 RC4输出'1',放上 R5(REG 4-1) 
RdPot	movlw	B'00000000'; ### 设置 A/D 通道并启动A/D转换 (REG 9-2) 
	movwf	ADCON0
	bsf	STATUS,RP0
	movlw	B'00000000'; ###选择A/D时钟为4MHZ INTOSC (TABLE 9-1 & REG 9-3) 
	movwf	ADCON1
	bcf	STATUS,RP0
	call	ConvertH
	bsf	STATUS,RP0	; 取 A/D 结果
	movf	ADRESL,W
	bcf	STATUS,RP0
	movwf	datapointer_l		
	movf	ADRESH,W
	movwf	datapointer_h	
	call	PC_2400		; 发送到 PC
	movlw	H'5'
	call	Delay100Ms
	goto	RdSw			
RdSW1
	movlw	B'00001001'	; SET A/D CHANNEL AND TURN A/D ON 
	movwf	ADCON0
	bsf	STATUS,RP0
	movlw	B'00000000'	; SELECT A/D CLOCK FOR 4MHZ INTOSC 
	movwf	ADCON1
	bcf	STATUS,RP0
	movlw	D'25'		; debounce delay
	call	DelayMs
	call	ConvertL
	movlw	D'82'		; check if button 2 pressed
	subwf	ADRESH,w	; 2.2K*5V/(2.2K+5*1K)=1.53V -> 1.60*255/5=~82
	btfss	STATUS,C	; is voltage <= 1.60V?
	goto	SwOn1
	retlw	0

SwOn1	movlw	D'25'	; debounce delay
	call	DelayMs
	call	ConvertL	
	movlw	D'77'	; check if button 2 pressed
	subwf	ADRESH,w	; 2.2K*5V/(2.2K+5*1K)=1.53V -> 1.60*255/5=~82
	btfsc	STATUS,C	; is voltage <= 1.60V?
	goto	SwOn2
	retlw	0
SwOn2	retlw	1
PC_2400			; 2400-8-N-1
	bsf	STATUS,RP0
	btfss	TXSTA,TRMT
	goto	$-1
	bcf	STATUS,RP0
	swapf	datapointer_h,W
	andlw	0x0f
	call	Hex_ASCII
	movwf	TXREG	
	bsf	STATUS,RP0
	btfss	TXSTA,TRMT
	goto	$-1
	bcf	STATUS,RP0
	movf	datapointer_h,W
	andlw	0x0f
	call	Hex_ASCII
	movwf	TXREG	
	bsf	STATUS,RP0
	btfss	TXSTA,TRMT
	goto	$-1
	bcf	STATUS,RP0
	swapf	datapointer_l,W
	andlw	0x0f
	call	Hex_ASCII
	movwf	TXREG	
	bsf	STATUS,RP0
	btfss	TXSTA,TRMT
	goto	$-1
	bcf	STATUS,RP0
	movf	datapointer_l,W
	andlw	0x0f
	call	Hex_ASCII
	movwf	TXREG			
	bsf	STATUS,RP0
	btfss	TXSTA,TRMT
	goto	$-1
	bcf	STATUS,RP0
	movlw   '\n'
	movwf	TXREG
	bsf	STATUS,RP0
	btfss	TXSTA,TRMT
	goto	$-1
	bcf	STATUS,RP0
	movlw   '\r'
	movwf	TXREG
	return
Hex_ASCII
	movwf	s_ram
	movlw	0x0a
	subwf	s_ram,W
	btfsc	STATUS,C
	goto	HA_C1
	movlw	0x30
	addwf	s_ram,W
	return
HA_C1	movlw	0x37
	addwf	s_ram,w
	return	
;********************************************************************************
; 用1个比较器和1个普通I/O口做Delta-Sigma A/D.					*
; 电位计POT2提供输入电压, RA3作为比较器的CIN-输入端				*
; RB4用来控制充放电C2.								*
; 注意指令数在该程序中很重要,不要添加程序指令.					*
; 可参考技巧手册技巧 Tip#14 							*
;********************************************************************************
Lab4
uart_ini2
	movlw	B'00000000'
	movwf	PORTC
	movlw	B'10000000'
	movwf	RCSTA
	bsf	STATUS,RP0
	movlw	B'10111111'
	movwf	TRISC
	movlw	D'25'	; 4M --> 2400 baud rate , BRGH = 1,
	movwf	SPBRG
	movlw	B'00100000'
	movwf	TXSTA
	bcf	PIE1,TXIE
	bcf	STATUS,RP0
        clrf    counter_l
        clrf    counter_h
        clrf    result_l
        clrf    result_h
        bsf     STATUS,RP0
                        ; ### 打开 参考电压源CVREF, 配置成 ~3V (REG 8-3) 
        movwf   CVRCON
	bsf	TRISA,3
                            ;###把RB4脚从输入设为输出

        movlw   B'00000000'; ### 把RA3配置成 -INPUT  (REG 8-1 & FIG 8-3)         movwf   CMCON 
DSloop
        btfsc   CMCON,C1OUT    ; Is comparator high or low?
        goto    complow        ; Go the low route
comphigh
	 bcf     STATUS,RP0
                             ;###让RB4脚输出'0' ###
        incfsz  result_l,f      ; bump counter
        goto    eat2cycles      ; 
        incf    result_h,f      ; 
        goto    endloop        ; 
complow
	bcf     STATUS,RP0
                             ; ### 让RB4脚输出'1' (REG 4-1) ###
        goto    eat2cycles      ; same here 
eat2cycles
        goto    endloop        ; eat 2 more cycles
endloop
        incfsz  counter_l,f      ; Count this lap through the loop.
        goto    eat5cycles     ; 
        incf    counter_h,f    ; 
        movf    counter_h,w   ; 
        andlw   0x04           ; Are we done? (We're done when bit2 of
        btfsc   STATUS,Z       ; the high order byte overflows to 1).
        goto    DSloop                                 
        goto    exit
eat5cycles
        goto    $+1             
        bsf     STATUS,RP0
        goto    DSloop          ; 
exit
	incf	temp1,F
	btfss	temp1,6
	goto	Lab4
	clrf	temp1
	movf	result_l,W	; fetch A/D results
	movwf	datapointer_l		
	movf	result_h,W
	movwf	datapointer_h	
	call	PC_2400	      ; Display on PC
	goto	Lab4				
;****************
; Subroutines	*
;****************
DelayMs			 ; delay W ms 
	bcf	STATUS,RP0
	movwf	temp3
msloop2	movlw	D'2'	; cal'd for 4MHz clock
	movwf	temp2
msloop1	movlw	D'164'	; cal'd for 4MHz clock
	movwf	temp1
	decfsz	temp1,f
	goto	$-1
	decfsz	temp2,f
	goto	msloop1
	decfsz	temp3,f
	goto	msloop2
	return
Delay100Ms		; delay W*100 ms
	bcf	STATUS,RP0
	movwf	temp3
msloop3	movlw	D'167'	; cal'd for 4MHz clock
	movwf	temp2
msloop4	movlw	D'200'	; cal'd for 4MHz clock
	movwf	temp1
	decfsz	temp1,f
	goto	$-1
	decfsz	temp2,f
	goto	msloop4
	decfsz	temp3,f
	goto	msloop3
	return
	END               ; directive 'end of program'

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -