1 使用M2Asm创建新工程
1.1 创建新文件夹存放工程文件
- 在新建文件夹下创建 main.asm 汇编文件
1.2 在编译软件 M2Asm 上创建工程
-
点击 M2Asm软件的 file->New Project,选中 main.asm 文件,并点击“打开”
-
M2Asm 显示如下
1.3 填写 main.asm 代码框架
-
填写工程信息,可不填
;******************************************************************************* ; FILENAME : ; AUTHOR : ; PURPOSE : ; REVISION Date : ; UPDATE Date : ; CHECKSUM : ; END DATE : ;*******************************************************************************
-
选择芯片
chip SN8P2711B
-
自动生成 SONIX_CODE_OPTION 信息(该步骤也可放在最后,且可随时更改)
填写芯片型号后,点击 M2Asm 的 Go 可自动生成 SONIX_CODE_OPTION 信息。
详细说明请参考章节 《2 编译说明SONIX_CODE_OPTION》 -
添加官方系统头文件
.nolist ; do not list the macro file INCLUDESTD MACRO1.H INCLUDESTD MACRO2.H INCLUDESTD MACRO3.H
该头文件可在 M2Asm 软件安装目录下找到
-
添加用户头文件
.list ; Enable the listing function include user_ram.h ……
在用户头文件中可定义变量、宏、引脚等
BIT0 EQU 01H …… R0 DS 1 …… PIN_LED EQU P5.1
-
代码区
;-------------------------------------------------------------------------------
; Code section
;-------------------------------------------------------------------------------
.CODE
ORG 0 ;Code section start
JMP Reset ;Reset vector 上电/复位开始执行的程序
ORG 8
JMP ISR ;中断服务函数入口
ORG 10h
;-------------------------------------------------------------------------------
; Program reset section
;-------------------------------------------------------------------------------
Reset:
…… ; 初始化等操作
LOOP:
…… ; 功能逻辑操作
JMP LOOP
ISR:
……
RETI
-
添加用户其他汇编文件
INCLUDE key.asm ……
-
工程代码结束
ENDP
-
总的代码框架
;*******************************************************************************
; FILENAME :
; AUTHOR :
; PURPOSE :
; REVISION Date :
; UPDATE Date :
; CHECKSUM :
; END DATE :
;*******************************************************************************
chip SN8P2711B
//{{SONIX_CODE_OPTION
.Code_Option LVD LVD_H ; 2.4V Reset Enable LVD36 bit of PFLAG for 3.6V Low Voltage Indicator
.Code_Option Reset_Pin P04
.Code_Option Watch_Dog Always_On ; Watchdog still enable even in Green and Sleep mode
.Code_Option High_Clk IHRC_16M ; Internal 16M RC Oscillator
.Code_Option Fcpu #7 ; Fcpu = Fosc/16
.Code_Option Security Enable
.Code_Option Noise_Filter Enable
//}}SONIX_CODE_OPTION
.nolist ; do not list the macro file
INCLUDESTD MACRO1.H
INCLUDESTD MACRO2.H
INCLUDESTD MACRO3.H
.list ; Enable the listing function
include user_ram.h
;-------------------------------------------------------------------------------
; Code section
;-------------------------------------------------------------------------------
.CODE
ORG 0 ;Code section start
JMP Reset ;Reset vector 上电/复位开始执行的程序
ORG 8
JMP ISR ;中断服务函数入口
ORG 10h
;-------------------------------------------------------------------------------
; Program reset section
;-------------------------------------------------------------------------------
Reset:
…… ; 初始化等操作
LOOP:
…… ; 功能逻辑操作
JMP LOOP
ISR:
……
RETI
INCLUDE key.asm
ENDP
1.4 将用户文件添加进 M2Asm 软件工程目录
- 在 main.asm 添加用户 .asm 文件和 .h 文件后,点击M2Asm软件即可自动添加
1.5 点击编译生成可烧录文件
- 点击M2ASM工具栏编辑按钮
- 编译成功,没有错误
2 编译说明SONIX_CODE_OPTION
3 重要寄存器说明
3.1 程序状态寄存器PFLAG
- C:进位标志。
1 = 加法运算后有进位、减法运算没有借位发生或移位后移出逻辑“1”或比较运算的结果 ≥ 0;
0 = 加法运算后没有进位、减法运算有借位发生或移位后移出逻辑“0”或比较运算的结果 < 0。 - DC:辅助进位标志。
1 = 加法运算时低四位有进位,或减法运算后没有向高四位借位;
0 = 加法运算时低四位没有进位,或减法运算后有向高四位借位。 - Z:零标志。
1 = 算术/逻辑/分支运算的结果为零;
0 = 算术/逻辑/分支运算的结果非零。
3.2 堆栈指针 STKP
- Bit[2:0] STKPBn :堆栈指针(n = 0 ~ 2)。
- Bit 7 GIE :全局中断控制位。
0 = 禁止;
1 = 使能。
3.3 OSCM寄存器
寄存器 OSCM 控制振荡器的状态和系统的工作模式。
- Bit 1 STPHX :高速振荡器控制位。
0 = 运行;
1 = 停止,内部低速 RC 振荡器仍然运行。 - Bit 2 CLKMD :系统时钟模式控制位。
0 = 普通(双时钟)模式,高速时钟作为系统时钟;
1 = 低速模式,低速时钟作为系统时钟。 - Bit[4:3] CPUM[1:0] :CPU 工作模式控制位。
00 = 普通模式;
01 = 睡眠模式;
10 = 绿色模式;
11 = 系统保留。
3.4 RAM初始化
上电后需要将RAM初始化为0
INIT_RAM:
CLR Y
B0MOV Z,#0x3F ; 需要清零地址范围 3F~00H
INIT_RAM_LOOP:
CLR @YZ ; 给@YZ地址清零,第一次地址为 0x3F
DECMS Z ; Z ← Z - 1,如果 Z = 0,则跳过下一条指令。
JMP INIT_RAM_LOOP ; 若 Z 不为 0,则循环
CLR @YZ ; 清地址为 0x00 处内容
RET ; 退出函数
RAM 数据寻址指针
3.5 引脚初始化
MOV A,#0x0C ; P0.2,P0.3 配置为输出模式
B0MOV P0M,A ;
MOV A,#0xF3 ; P0.2,P0.3 配置为禁止上拉
B0MOV P0UR,A
MOV A,#0x00 ; P0.2,P0.3 初始化为低电平
MOV P0,A
- PnM 引脚模式寄存器
寄存器 PnM 控制 I/O 口的工作模式,n = 0~5,即P0 ~ P5 端口。
PnM[的Bit[7:0] :
0 = 输入模式;
1 = 输出模式。 - 引脚上拉模式
I/O 引脚内置上拉电阻,仅在输入模式下有效。I/O 引脚的上拉电阻由 PnUR 寄存器控制,n = 0~5,即P0 ~ P5 端口。
PnUR 的Bit[7:0] :
0 时,禁止上拉电阻;
1 时,使能上拉电阻。
4 逻辑运算应用
4.1 判断指令 BTS0、BTS1
BTS0 M.b | 如果 M.b = 0,则跳过下一条指令 |
---|---|
BTS1 M.b | 如果 M.b = 1,则跳过下一条指令 |
4.2 用 XOR(异或)判断两变量是否相同
异或运算:相同为0,不同为1;进行异或运算后(也是逻辑运算),零标志(Z)状态会改变:
-
Z:零标志。
1 = 逻辑运算的结果为零;
0 = 逻辑运算的结果非零。
应用举例:B0MOV A,var1 XOR A,#AA ; 异或运算:var1与#AA相同,则FZ==1,var1与#AA不同,则FZ==0 B0BTS0 FZ ; FZ 为 0 时,则跳过下一条指令 JMP JMP_XXX ...
4.3 用SUB(减法)判断两变量大小
SUB A,M | A ← A – M,如果产生借位则 C=0,否则 C=1。 |
---|---|
SUB M,A | M ← A – M,如果产生借位则 C=0,否则 C=1。 |
应用举例: |
;subtract word, SUBW 算法
SUBW MACRO m_minuend,m_subtrahend //m_minuend=m_minuend-m_subtrahend
MOV A,m_minuend
SUB A,m_subtrahend
MOV m_minuend,A // save low byte
MOV A,m_minuend+1
SBC A,m_subtrahend+1
MOV m_minuend+1,A // save high byte
ENDM
;------------------------------------------------------------------------------------------
AAA DS 2 ; 临时双字节寄存器AAA
BBB DS 2 ; 临时双字节寄存器BBB
;------------------------------------------------------------------------------------------
;双字节变量的比较
B0MOV A,var1 + 0 ; var1 + 0:表示字节1
B0MOV AAA + 0,A
B0MOV A,var1 + 1 ; var1 + 1:表示字节2
B0MOV AAA + 1,A
MOV A,#CON1$L ; #CON1$L 低字节
B0MOV BBB+0,A
MOV A,#CON1$M ; #CON1$M 中字节
B0MOV BBB + 1,A
SUBW AAA,BBB ; var1 -CON1(AAA >= BBB,FC为1)
B0BTS1 FC ; 也可以用 B0BTS0
JMP JMP_XXX ; var1 < CON1
... ; var1 > CON1
;------------------------------------------------------------------------------------------
;单字节变量的比较
B0MOV A,var1 ;
B0MOV AAA ,A
MOV A,#CON1 ;
B0MOV BBB,A
SUBW AAA,BBB ; var1 -CON1(AAA >= BBB,FC为1)
B0BTS1 FC ; 也可以用 B0BTS0
JMP JMP_XXX ; var1 < CON1
... ; var1 > CON1
4.4 用@JMP_A 跳转表实现如C语言switch功能
B0MOV A, BUF0 ; “BUF0”从 0 至 4。
@JMP_A 5 ; 列表个数为 5。
JMP A0POINT ; ACC = 0,跳至 A0POINT。
JMP A1POINT ; ACC = 1,跳至 A1POINT。
JMP A2POINT ; ACC = 2,跳至 A2POINT。
JMP A3POINT ; ACC = 3,跳至 A3POINT。
JMP A4POINT ; ACC = 4,跳至 A4POINT。
5 按键检测程序
5.1 按键引脚连接同一个端口
例如:key0、key1、key2、key3 分别连接 P1端口的P1.0、P1.1、P1.2、P1.3;
;最后 keycode 返回的是序号,而不是 TBL_KEY 表中的值
KEYIN:
MOV A,P1 ; (有按键按下,相应位为0)
XOR A,#0xFF ; 此处是为了避免不按键时与结束码相同,键码取反(即有按键按下,相应位为1)(XOR:相同为0,不同为1)
AND A,#0x0F ; 屏蔽非按键IO口
KEYIN1:
B0MOV R1,A ; A 保存了按键值,如果只有P1.0按下,则A值为0x01
MOV A,#0xFF
B0MOV R0,A ; R1 为按键状态,R0 为0xFF
KEYIN2:
B0MOV Y,#TBL_KEY$M
B0MOV Z,#TBL_KEY$L
INCMS R0 ; 第一遍R0 == 0 ;第二遍 R0 == 1;...
NOP
B0MOV A,R0 ; A 即 R0 的值;
B0ADD Z,A ; 第一遍 Z == #TBL_KEY$L;第二遍 Z 为 #TBL_KEY$L 的下一个地址;...(ADD,如果产生进位则 C = 1,否则 C = 0。 )
B0BTS1 FC ;
JMP FIND_KEYTBL
INCMS Y
NOP
FIND_KEYTBL:
MOVC ; 查表(执行完 MOVC 指令后,所查找数据低字节内容被存入 ACC 中,而数据高字节内容被存入 R 寄存器。)
CMPRS A,R1 ; A 存储的是 TBL_KEY 表中的值,R1 即按键状态
JMP KEYIN3 ; A != R1 ,
B0MOV A,R0 ; A == R1 , 将 R0 序号(0、1、2、3...)赋值给keycode,而不是将TBL_KEY 表中的值
B0MOV keycode,A
RET
KEYIN3:
CMPRS A,#0xFF ; 比较,如果相等则跳过下一条指令(0xFF是TBL_KEY表中结尾的值,所以前面值都不等,最后一个就一定等)
JMP KEYIN2 ; 没有查完 TBL_KEY 表,循环查找
B0MOV keycode,A ;
RET
TBL_KEY: ; 如key0(P1.0)按下,按键值为0x01,
DW 0x0000 ; ---------------> 无按键按下
DW 0x0001 ; ---------------> key0 按下
DW 0x0002 ; ---------------> key1 按下
DW 0x0004 ; ---------------> key2 按下
DW 0x0008 ; ---------------> key3 按下
DW 0x00FF ; ---------------> 无定义的按键值
5.2 按键引脚连接不同端口
例如:key0、key1、key2、key3 分别连接 P1端口的P5.4、P5.5、P1.2、P1.3;
KEYIN:
MOV A,P1
XOR A,#0xFF ; 此处是为了避免不按键时与结束码相同,键码取反
AND A,#(BIT2|BIT3) ; 屏蔽非按键IO口(读取P1^2,P1^3)
B0MOV R1,A
MOV A,P5
XOR A,#0xFF ; 此处是为了避免不按键时与结束码相同,键码取反
AND A,#(BIT4|BIT5) ; 屏蔽非按键IO口(读取P5^4,P5^5)
OR R1,A ; 综合P1 & P5两个IO口
KEYIN1:
MOV A,#0xFF
B0MOV R0,A
KEYIN2:
B0MOV Y,#TBL_KEY$M
B0MOV Z,#TBL_KEY$L
INCMS R0
NOP
B0MOV A,R0
B0ADD Z,A
B0BTS1 FC
JMP FIND_KEYTBL
INCMS Y
NOP
FIND_KEYTBL:
MOVC ;
CMPRS A,R1
JMP KEYIN3
B0MOV A,R0
B0MOV keycode,A
RET
KEYIN3:
CMPRS A,#0xFF
JMP KEYIN2
B0MOV keycode,A ;
RET
TBL_KEY: ; 如key0(P5.4)按下,按键值为0x10,
DW 0x0000 ; ---------------> 无按键按下
DW 0x0010 ; ---------------> key0 按下
DW 0x0020 ; ---------------> key1 按下
DW 0x0004 ; ---------------> key2 按下
DW 0x0008 ; ---------------> key3 按下
DW 0x0030 ; ---------------> key0&key1 同时按下
DW 0x00FF ; ---------------> 无定义的按键值
6 定时器的使用
例如配置SN8P2711B定时器1(TC1),参考文章《SN8P2711B_英文参考手册.PDF》章节如下
- TC1 INTERRUPT OPERATION
- TIMER/COUNTER 1 (TC1)
.DATA
ORG 0h ; Data section start address 0
AccBuf DS 1
PflagBuf DS 1
.CODE
ORG 0 ;Code section start
JMP Reset ;Reset vector
ORG 8
JMP Inte_Service ;中断服务函数
ORG 10h
Reset:
……
CALL Fun_Time_Init
……
;-------------------------------------------------------------------------------
;定时器中断初始化函数,间隔10ms周期中断。Fcpu = 16Mhz / 16
;-------------------------------------------------------------------------------
Fun_Time_Init:
B0BCLR FTC1IEN ; 禁止TC1 中断
B0BCLR FTC1ENB ; 禁止TC1 定时器
B0BCLR FGIE ; 关闭全局中断(在 STKP 寄存器)
CLR TC1M ; 清 TC1M
MOV A,#0x20 ; Set TC1 Clock=fcpu/64 = 16M/16/64 = 15625
OR TC1M,A ;
MOV A,#0x64;
MOV TC1C,A ; TC1间隔Cycle=10.0ms ,TC1C = 256 - (0.01 * 15625) ≈ 100
B0BCLR FTC1IRQ ; 清TC1中断请求标志
B0BSET FTC1IEN ; 使能TC1中断
B0BSET FTC1ENB ; 开启TC1 定时器
B0BSET FGIE ; 使能全局中断
RET
;-------------------------------------------------------------------------------
;定时器中断服务函数
;-------------------------------------------------------------------------------
Inte_Service:
;Save ACC and PFLAG to buffers.
b0xch A,AccBuf ; A <---> AccBuf ,将A值存于AccBuf
b0mov A,PFLAG
b0mov PflagBuf,A
;-------------user routine config start---------------
B0BTS1 FTC1IRQ ; Check TC1IRQ
JMP EXIT_INT ; TC1IRQ = 0, exit interrupt vector
NOP
B0BCLR FTC1IRQ ; Reset TC1IRQ
MOV A, #0x64
B0MOV TC1C, A ; Reset TC1C
;-------------user routine logic start---------------
……
;-------------user routine end------------------------
;Load ACC and PFLAG from buffers.
EXIT_INT:
b0mov A, PflagBuf
b0mov PFLAG, A ; Restore the PFlag
b0xch A,AccBuf ; Restore the Reg. A
RETI