📄 研讨会范例.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 + -