搜索
bottom↓
回复: 38

一个己调试好的串口汇编程序

[复制链接]

出0入0汤圆

发表于 2005-3-6 03:27:29 | 显示全部楼层 |阅读模式
发一个己调试好的串口汇编程序,保证可用,欢迎高手批评指正。



点击此处下载armok01120568.txt

出0入0汤圆

发表于 2005-3-6 04:04:19 | 显示全部楼层
佩服!!!但全汇编确实太累...玩玩还可以...

出0入0汤圆

发表于 2005-3-6 10:03:20 | 显示全部楼层
不错 很详细 收

出0入0汤圆

发表于 2005-3-6 10:13:17 | 显示全部楼层
非常详细,对我等新人有很大的提高作用,谢谢。

出0入0汤圆

发表于 2005-3-6 11:46:00 | 显示全部楼层
汇编是基础,应认真学习学习,谢谢

出0入0汤圆

 楼主| 发表于 2005-3-6 16:19:38 | 显示全部楼层
如果大家觉得程序编得还可以看的话,本人将继续上传其他功能模块程序,如:ADC I2C等。

出0入0汤圆

发表于 2005-3-6 20:03:21 | 显示全部楼层
钦佩!!!

出0入0汤圆

发表于 2005-3-6 21:37:06 | 显示全部楼层
把这个程序看懂了,AVR的汇编也学会了

出0入0汤圆

发表于 2005-3-6 22:29:56 | 显示全部楼层
真不简单,这得花多大气力!!!

出0入0汤圆

 楼主| 发表于 2005-3-22 01:22:55 | 显示全部楼层
既然有这么多网友捧场,此段程序还有几个程序要一起链接编译,否则直接使用,会出现错误提示,在此也一并奉上:



注意:与 ADC 有关的程序段应删去,因为这些程序中还需要调用其它子程序。



;*******************************************************************************

;*

;* 子程序名:          CTRLCOM_Manage.asm

;* 程序名称:          控制操作指令处理子程序

;* 版本:              1.0

;* 适用 MCU 型号:     AVR所有型号

;* 使用资源:          r5,r6,r16,r17,r18,r19,r20,r28,r29,r30,r31

;*

;* 程序功能:        

;*   本程序是用于对控制操作指令进行处理操作的子程序,也是系统人-机对话输

;* 入处理的组成部分,对于各种不同输入对象下达的控制操作指令均可在此统一进行

;* 处理。共包括下面列表中这二个子程序。这二个子程序的具体使用方法请参考各自

;* 的说明。

;* ┏───────────┳───────────────────────┓

;* ┃      子程序名称      ┃                子程序功能描述                ┃

;* ┣───────────╋───────────────────────┫

;* ┃CTRLCOM_Initialization┃            处理控制操作指令初始化            ┃

;* ┣───────────╋───────────────────────┫

;* ┃    CTRLCOM_Manage    ┃            识别和处理控制操作指令            ┃

;* ┗───────────┻───────────────────────┛

;*

;* 注释: 

;*   ①.对于不同的输入控制操作指令的对象可通过给通过设置相应的标志字节来区分,

;* 如:对“CCOMALW_USART ”(允许处理 USART 端口的控制操作指令标志)置相同的这

;* 个数值“CTRLCOM_ALWSI”($ca)来确定和识别下达执行相应操作的控制指令的身份。

;* 对于不同的输入对象可自由定义其标志字节。

;*   ②.控制操作指令内容必须放在 SRAM 中的相应位置,由 Y 指针指向其存储地址。

;* 所有控制操作指令的格式为:Control(控制操作指令起始标识字符串)+ 设备编号(4

;* 个字节)+ 控制操作指令具体字。己定义的控制操作指令见子程序“CTRLCOMM_IPFMCOM”

;* (识别和执行控制操作指令处理子程序)的具体说明。

;*   ③.对于新增加的控制操作指令处理程序,在编程时请注意,如果在程序中用到 Y

;* 指针的话,必须对其入栈保护,保证在返回时没有修改 Y 指针数值。否则会导致其他

;* 控制操作指令的识别错误。

;*

;* 编作者:            

;* 编作者 E-Mail:     PTZSW@163.COM

;* 编制日期:          2005年2月18日

;*                  

;*******************************************************************************

;*

;* 指令条数:          1298 + return

;* 指令执行周期:      0 + return

;* 低位寄存器使用:    None

;* 高位寄存器使用:    5 (r16,r17,r18,r19,r20)

;* 指针寄存器使用:    Y,Z

;*

;*******************************************************************************



;******** 本程序需调用的子程序定义:



.include   "USART_INT.asm"          ;USART异步中断接收和发送通信程序

.include   "InsideADC_INT.asm"      ;使用内部模拟/数字转换器进行电压测量程序

.include   "Access_EEPROM.asm"      ;存取 EEPROM (电可擦除只读存储器)程序





;******** 依据硬件设置需修改的 SRAM 存储地址定义:



.equ    CCOMALW_USART  = $0068      ;允许处理 USART 端口的控制操作指令标志

.equ    CCOMA_PDNSCC   = $0069      ;允许处理公共编号的特殊控制操作指令标志





;******** 存储在 EEPROM 中的特定数据起始地址定义:



.equ    CC_EEPROM_DNAr = $0010      ;设备编号在 EEPROM 中的起始地址



.ESEG

.org $0010

DeviceNumber:

.DB "6688"                          ;设备编号



.CSEG





;******** 本程序常数定义:



.equ    CTRLCOM_ALWSI  = $ca        ;允许处理控制操作指令标志值(11001010)



.equ    CCTSSDV_RightI = $af        ;控制操作指令正确标志值(10101111)

.equ    CTRLCOM_MPFMSI = $ab        ;控制操作指令己经执行标志值(10101011)

.equ    CCOMMIPFM_RETI = $cc        ;控制操作指令返回状态标志值(11001100)

.equ    CCOMMIPFM_ENDI = $c3        ;控制操作指令结束状态标志值(11000011)

.equ    CTRLCDN_CharNI = $04        ;设备编号使用的字节数





;******** 本程序寄存器变量定义:



.def    CTRLCOM_TEMP   = r16        ;暂存寄存器

.def    CTRLCOM_TEMP2  = r17        ;暂存寄存器2

.def    CTRLCOM_CNT    = r18        ;循环计数器

.def    CTRLCOM_MIPFM  = r21        ;控制操作指令识别和执行状态寄存器

.def    CTRLCOM_MPFMS  = r22        ;判断控制操作指令执行与否寄存器

.def    CCTSSDV_Right  = r23        ;判断控制操作指令正确与否寄存器





;******** 程序指令代码清单:



;*******************************************************************************

;*

;* 处理控制操作指令初始化子程序 - “CTRLCOM_Initialization”

;*

;* 说明:

;*   本子程序用于初始化处理控制操作指令。

;*   本子程序只需在主程序中运行一次即可,但要在下面的所有程序运行前先执行。

;*

;*******************************************************************************

CTRLCOM_Initialization:

    clr ZL                          ;清除允许处理 USART 端口的控制操作指令标志

    sts CCOMALW_USART,ZL

    ret                             ;子程序返回





;*******************************************************************************

;*

;* 识别和处理控制操作指令子程序 - “CTRLCOM_Manage”

;*

;* 说明:

;*   本子程序用于使用识别和处理控制操作指令。

;*   本子程序要在主程序中不间断地循环运行。

;*

;* SRAM 中标志字节用法:

;*   入口标志:本子程序将检查这些标志,依据这些标志置值来执行不同处理方式。

;*               允许处理 USART 的指令(CCOMALW_USART)= $ca(CTRLCOM_ALWSI)

;*   出口标志:本子程序运行后,将对下面这两个标志置值。

;*               允许处理 USART 的指令(CCOMALW_USART)= $00

;*******************************************************************************



CTRLCOM_Manage:

    lds ZL,CCOMALW_USART            ;检查是否允许处理 USART 端口的控制操作指令?

    cpi ZL,CTRLCOM_ALWSI              ;是,到相应处理

    brne CTRLCOM_Manage1              ;否,则继续

    rcall CTRLCOMM_USART            ;进入由 USART 端口送来控制操作指令处理

    rjmp CTRLCOM_Manage_RET         ;返回

CTRLCOM_Manage1:



;此处可继续插入由其他地方传来控制操作指令处理程序



CTRLCOM_Manage_RET:

    ret                             ;子程序返回





;*** 此段程序用于[由 USART 端口送来控制操作指令]处理

CTRLCOMM_USART:

    lds ZL,USARTAI_TXEnd            ;发送作业是否全部结束?

    cpi ZL,USARTAI_TEndI              ;否,返回,等待发送作业结束

    breq CTRLCOMM_USART1              ;是,则继续

    rjmp CTRLCOMM_USART_RET

CTRLCOMM_USART1:

    lds ZL,USARTAI_RXUPD            ;检查接收作业是否己更新?

    cpi ZL,USARTAI_RUPDI              ;否,直接返回

    breq CTRLCOMM_USART2              ;是,则继续

    rjmp CTRLCOMM_USART_RET

CTRLCOMM_USART2:

    lds ZL,USARTAI_RXEnd            ;检查接收作业是否全部结束?

    cpi ZL,USARTAI_REndI              ;否,转至接收错误处理

    breq CTRLCOMM_USART_CCHead        ;是,则继续

    rjmp CTRLCOMM_USART_Error

CTRLCOMM_USART_CCHead:

    ldi YL,Low(USARTAI_RXDAA+1)     ;置由 USART 端口送来指令地址指针

    ldi YH,High(USARTAI_RXDAA+1)      ;第一个字节为长度数值,不识别

    ldi ZL,Low(ControlHandle_Head*2);置控制操作指令开头标识字符串地址指针

    ldi ZH,High(ControlHandle_Head*2)

    lpm CTRLCOM_CNT,Z+              ;置循环计数器初值=指令字长度数值

    rcall CTRLCOMM_IdentifyCOM      ;对控制操作指令开头标识字符串识别

    cpi CCTSSDV_Right,CCTSSDV_RightI;检查是否为控制操作指令开头标识字符串?

    breq CTRLCOMM_USART_EAddr         ;是,则继续

    rjmp CTRLCOMM_USART_Error         ;否,则转至接收错误处理

CTRLCOMM_USART_EAddr:

    ldi ZL,Low(ControlHandle_Head*2);置控制操作指令开头标识字符串地址指针

    ldi ZH,High(ControlHandle_Head*2)

    lpm CTRLCOM_CNT,Z+              ;读取开头命令字长度数值

    clr CTRLCOM_TEMP

    add YL,CTRLCOM_CNT              ;置 Y 指针为设备地址字符串的地址指针

    adc YH,CTRLCOM_TEMP

    ldi CTRLCOM_CNT,CTRLCDN_CharNI  ;置循环计数器初值=设备地址字长度数值

    ldi EEPROM_AddrL,Low(CC_EEPROM_DNAr)

    ldi EEPROM_AddrH,High(CC_EEPROM_DNAr)

                                    ;置在 EEPROM 中的设备编号地址指针

CTRLCOMM_USART_EAddr1:

    call EEPROM_ReadSingle          ;读取 EEPROM 中的设备编号

    ld CTRLCOM_TEMP2,Y+

    cp EEPROM_Data,CTRLCOM_TEMP2    ;检查是否为本设备的编号数字?

    brne CTRLCOMM_USART_Error         ;否,转到接收错误处理

    adiw EEPROM_AddrL,$01           ; EEPROM 中的设备编号地址指针 + 1

    dec CTRLCOM_CNT                 ;设备地址字长度数值 — 1

    brne CTRLCOMM_USART_EAddr1      ;所有编号识别完否?未完,则继续识别

    rcall CTRLCOMM_IPFMCOM          ;识别和执行控制操作指令处理

    cpi CTRLCOM_MIPFM,CCOMMIPFM_RETI;检查指令识别和执行状态是否为返回?

    breq CTRLCOMM_USART_RET           ;是,转到返回

                                      ;否,则继续

    cpi CTRLCOM_MIPFM,CCOMMIPFM_ENDI;检查指令识别和执行状态是否为结束?

    breq CTRLCOMM_USART_End           ;是,转到结束处理

    rjmp CTRLCOMM_USART_Error         ;否,转到接收错误处理

CTRLCOMM_USART_End:

    ldi ZL,USARTAI_RCOMI            ;置接收命令作业标志值

    sts USARTAI_RXCOM,ZL

    brts CTRLCOMM_USART_End1        ;向对方发送“接收数据正确”命令吗?

    call USART_TX_COMM_AskTX          ;否,发送“向对方请求发送”命令

    rjmp CTRLCOMM_USART_End2

CTRLCOMM_USART_End1:

    call USART_TX_COMM_DataOK         ;是,向对方发送“接收数据正确”命令

CTRLCOMM_USART_End2:

    clr ZL                          ;清除接收作业己更新标志

    sts USARTAI_RXUPD,ZL

    clr ZL                          ;清除允许处理 USART 端口的控制操作指令标志

    sts CCOMALW_USART,ZL

    rjmp CTRLCOMM_USART_RET         ;返回

CTRLCOMM_USART_Error:

    call USART_RXD_Error            ;调用接收错误处理子程序

CTRLCOMM_USART_RET:

    ret                             ;子程序返回





;*******************************************************************************

;*

;* 识别和执行控制操作指令处理子程序 - “CTRLCOMM_IPFMCOM”

;*

;* 说明:

;*   本子程序用于识别和执行控制操作指令处理。本子程序可供其他程序调用,只要在

;* Y 指针中置入相应的控制操作指令字即可执行对此指令的操作。本子程序共设置下列这

;* 些控制操作指令(指令的具体格式见各指令字符串的具体定义):

;* 1.[OpenFullPageADC] - 整页启动内部 ADC 转换指令

;* 2.[OpenSingleGroupADC] - 单组启动内部 ADC 转换指令

;* 3.[OpenSingleChannelADC:X] - 单通道启动内部 ADC 转换指令

;* 4.[TXD@FullPageADC] - 发送整页 ADC 转换结果数据指令

;* 5.[TXD@SingleGroupADC] - 发送单组 ADC 转换结果数据指令

;* 6.[TXD@SingleChannelADC] - 发送单通道 ADC 转换结果数据指令

;* 7.[ChangeDeviceNumber:XXXX] - 修改在 EEPROM 中的 4 个字节设备编号指令

;*

;* 注意:

;*   请慎用4、5、6这几条发送数据指令!如果在前面没有执行相应操作的指令,那

;* 么将会导致收到的数据错误,也可能导致其他程序得到错误的数据。

;*

;* 入口条件:

;*        在调用本程序前,需设置下面这个地址指针数值:

;*          Y 指针 ----- 指向传送来的控制操作指令在 SRAM 中的存储地址

;* 出口条件:

;*         程序运行结束后,将会下面这个标志置不同的数值。

;*  r21 --- 控制操作指令识别和执行状态寄存器(CTRLCOM_MIPFM)

;*         ①.= $cc(CCOMMIPFM_RETI),为控制操作指令返回状态值

;*         ②.= $c3(CCOMMIPFM_ENDI),为控制操作指令结束状态值

;*         ③.= $00 ,为非上面两种状态值

;*

;*******************************************************************************

CTRLCOMM_IPFMCOM:

    clr CTRLCOM_MIPFM               ;清除控制操作指令识别和执行状态

CTRLCOMM_IPFMCOM1:

    ldi ZL,Low(OpenFullPageADC*2)

    ldi ZH,High(OpenFullPageADC*2)

                                    ;置整页启动内部 ADC 转换指令地址指针

    lpm CTRLCOM_CNT,Z+              ;置循环计数器初值=指令字长度数值

    rcall CTRLCOMM_IdentifyCOM      ;对此条控制操作指令进行识别

    cpi CCTSSDV_Right,CCTSSDV_RightI;检查是否为此条控制操作指令?

    brne CTRLCOMM_IPFMCOM2            ;否,则继续

    rcall CTRLCOMM_OFPADC             ;是,调用处理此条控制操作指令程序

    cpi CTRLCOM_MPFMS,CTRLCOM_MPFMSI;检查控制操作指令是否己经执行?

    breq CTRLCOMM_IPFMCOM11           ;是,置控制操作指令结束状态标志值

    ldi CTRLCOM_MIPFM,CCOMMIPFM_RETI  ;否,置控制操作指令返回状态标志值

    rjmp CTRLCOMM_IPFMCOM_RET

CTRLCOMM_IPFMCOM11:

    ldi CTRLCOM_MIPFM,CCOMMIPFM_ENDI

    rjmp CTRLCOMM_IPFMCOM_RET

CTRLCOMM_IPFMCOM2:

    ldi ZL,Low(OpenSingleGroupADC*2)

    ldi ZH,High(OpenSingleGroupADC*2)

                                    ;置单组启动内部 ADC 转换指令地址指针

    lpm CTRLCOM_CNT,Z+              ;置循环计数器初值=指令字长度数值

    rcall CTRLCOMM_IdentifyCOM      ;对此条控制操作指令进行识别

    cpi CCTSSDV_Right,CCTSSDV_RightI;检查是否为此条控制操作指令?

    brne CTRLCOMM_IPFMCOM3            ;否,则继续

    rcall CTRLCOMM_OSGADC             ;是,调用处理此条控制操作指令程序

    cpi CTRLCOM_MPFMS,CTRLCOM_MPFMSI;检查控制操作指令是否己经执行?

    breq CTRLCOMM_IPFMCOM21           ;是,置控制操作指令结束状态标志值

    ldi CTRLCOM_MIPFM,CCOMMIPFM_RETI  ;否,置控制操作指令返回状态标志值

    rjmp CTRLCOMM_IPFMCOM_RET

CTRLCOMM_IPFMCOM21:

    ldi CTRLCOM_MIPFM,CCOMMIPFM_ENDI

    rjmp CTRLCOMM_IPFMCOM_RET

CTRLCOMM_IPFMCOM3:

    ldi ZL,Low(OpenSingleChannelADC_X*2)

    ldi ZH,High(OpenSingleChannelADC_X*2)

                                    ;置单通道启动内部 ADC 转换指令地址指针

    lpm CTRLCOM_CNT,Z+              ;置循环计数器初值=指令字长度数值

    rcall CTRLCOMM_IdentifyCOM      ;对此条控制操作指令进行识别

    cpi CCTSSDV_Right,CCTSSDV_RightI;检查是否为此条控制操作指令?

    brne CTRLCOMM_IPFMCOM4            ;否,则继续

    rcall CTRLCOMM_OSSCADC            ;是,调用处理此条控制操作指令程序

    cpi CTRLCOM_MPFMS,CTRLCOM_MPFMSI;检查控制操作指令是否己经执行?

    breq CTRLCOMM_IPFMCOM31           ;是,置控制操作指令结束状态标志值

    ldi CTRLCOM_MIPFM,CCOMMIPFM_RETI  ;否,置控制操作指令返回状态标志值

    rjmp CTRLCOMM_IPFMCOM_RET

CTRLCOMM_IPFMCOM31:

    ldi CTRLCOM_MIPFM,CCOMMIPFM_ENDI

    rjmp CTRLCOMM_IPFMCOM_RET

CTRLCOMM_IPFMCOM4:

    ldi ZL,Low(TXD_FullPageADC*2)

    ldi ZH,High(TXD_FullPageADC*2)

                                    ;置发送整页 ADC 转换结果数据指令地址指针

    lpm CTRLCOM_CNT,Z+              ;置循环计数器初值=指令字长度数值

    rcall CTRLCOMM_IdentifyCOM      ;对此条控制操作指令进行识别

    cpi CCTSSDV_Right,CCTSSDV_RightI;检查是否为此条控制操作指令?

    brne CTRLCOMM_IPFMCOM5            ;否,则继续

    rcall CTRLCOMM_TXDFPADC           ;是,调用处理此条控制操作指令程序

    cpi CTRLCOM_MPFMS,CTRLCOM_MPFMSI;检查控制操作指令是否己经执行?

    breq CTRLCOMM_IPFMCOM41           ;是,置控制操作指令结束状态标志值

    ldi CTRLCOM_MIPFM,CCOMMIPFM_RETI  ;否,置控制操作指令返回状态标志值

    rjmp CTRLCOMM_IPFMCOM_RET

CTRLCOMM_IPFMCOM41:

    ldi CTRLCOM_MIPFM,CCOMMIPFM_ENDI

    rjmp CTRLCOMM_IPFMCOM_RET

CTRLCOMM_IPFMCOM5:

    ldi ZL,Low(TXD_SingleGroupADC*2)

    ldi ZH,High(TXD_SingleGroupADC*2)

                                    ;置发送单组 ADC 转换结果数据指令地址指针

    lpm CTRLCOM_CNT,Z+              ;置循环计数器初值=指令字长度数值

    rcall CTRLCOMM_IdentifyCOM      ;对此条控制操作指令进行识别

    cpi CCTSSDV_Right,CCTSSDV_RightI;检查是否为此条控制操作指令?

    brne CTRLCOMM_IPFMCOM6            ;否,则继续

    rcall CTRLCOMM_TXDSGADC           ;是,调用处理此条控制操作指令程序

    cpi CTRLCOM_MPFMS,CTRLCOM_MPFMSI;检查控制操作指令是否己经执行?

    breq CTRLCOMM_IPFMCOM51           ;是,置控制操作指令结束状态标志值

    ldi CTRLCOM_MIPFM,CCOMMIPFM_RETI  ;否,置控制操作指令返回状态标志值

    rjmp CTRLCOMM_IPFMCOM_RET

CTRLCOMM_IPFMCOM51:

    ldi CTRLCOM_MIPFM,CCOMMIPFM_ENDI

    rjmp CTRLCOMM_IPFMCOM_RET

CTRLCOMM_IPFMCOM6:

    ldi ZL,Low(TXD_SingleChannelADC*2)

    ldi ZH,High(TXD_SingleChannelADC*2)

                                    ;置发送单通道 ADC 转换结果数据指令地址指针

    lpm CTRLCOM_CNT,Z+              ;置循环计数器初值=指令字长度数值

    rcall CTRLCOMM_IdentifyCOM      ;对此条控制操作指令进行识别

    cpi CCTSSDV_Right,CCTSSDV_RightI;检查是否为此条控制操作指令?

    brne CTRLCOMM_IPFMCOM7            ;否,则继续

    rcall CTRLCOMM_TXDSSCADC          ;是,调用处理此条控制操作指令程序

    cpi CTRLCOM_MPFMS,CTRLCOM_MPFMSI;检查控制操作指令是否己经执行?

    breq CTRLCOMM_IPFMCOM61           ;是,置控制操作指令结束状态标志值

    ldi CTRLCOM_MIPFM,CCOMMIPFM_RETI  ;否,置控制操作指令返回状态标志值

    rjmp CTRLCOMM_IPFMCOM_RET

CTRLCOMM_IPFMCOM61:

    ldi CTRLCOM_MIPFM,CCOMMIPFM_ENDI

    rjmp CTRLCOMM_IPFMCOM_RET

CTRLCOMM_IPFMCOM7:

    ldi ZL,Low(ChangeDeviceNumber_XXXX*2)

    ldi ZH,High(ChangeDeviceNumber_XXXX*2)

                                    ;置修改设备编号指令地址指针

    lpm CTRLCOM_CNT,Z+              ;置循环计数器初值=指令字长度数值

    rcall CTRLCOMM_IdentifyCOM      ;对此条控制操作指令进行识别

    cpi CCTSSDV_Right,CCTSSDV_RightI;检查是否为此条控制操作指令?

    brne CTRLCOMM_IPFMCOM8            ;否,则继续

    rcall CTRLCOMM_ChangeDN           ;是,调用处理此条控制操作指令程序

    cpi CTRLCOM_MPFMS,CTRLCOM_MPFMSI;检查控制操作指令是否己经执行?

    breq CTRLCOMM_IPFMCOM71           ;是,置控制操作指令结束状态标志值

    ldi CTRLCOM_MIPFM,CCOMMIPFM_RETI  ;否,置控制操作指令返回状态标志值

    rjmp CTRLCOMM_IPFMCOM_RET

CTRLCOMM_IPFMCOM71:

    ldi CTRLCOM_MIPFM,CCOMMIPFM_ENDI

    rjmp CTRLCOMM_IPFMCOM_RET

CTRLCOMM_IPFMCOM8:



;此处可继续插入其他控制操作指令识别和执行程序



CTRLCOMM_IPFMCOM_RET:

    ret                             ;子程序返回





;*******************************************************************************

;*

;* 识别控制操作指令子程序 - “CTRLCOMM_IdentifyCOM”

;*

;* 说明:

;*   本子程序用于使用识别控制操作指令。

;*

;* 注意:

;*   程序运行结束后,将恢复 Y 指针为原来的数值。而 Z 指针将更改为该指令

;* 在 Flash 中的存储地址的后一个字节位置。

;*

;* 入口条件:

;*        在调用本程序前,需设置下面这两个地址指针和循环计数器数值:

;*          Z 指针 ----- 指向控制操作指令在 Flash 中的存储地址

;*          Y 指针 ----- 指向传送来的控制操作指令在 SRAM 中的存储地址

;*  r18 --- 循环计数器(CTRLCOM_CNT)= 控制操作指令字符串长度数值

;* 出口条件:

;*      ①.经过识别后,如果是 Z 指针指向的控制操作指令,将对此标志置值。

;*  r23 --- 控制操作指令正确(CCTSSDV_Right)= $af(CCTSSDV_RightI)

;*      ②.经过识别后,如果不是 Z 指针指向的控制操作指令,将清除此标志。

;*  r23 --- 控制操作指令正确(CCTSSDV_Right)= $00

;*

;*******************************************************************************

CTRLCOMM_IdentifyCOM:

    push YL                         ;压入 Y 指针的数值到堆栈

    push YH

    clr CCTSSDV_Right               ;清除控制操作指令正确标志

CTRLCOMM_IdentifyCOM1:

    lpm CTRLCOM_TEMP,Z+             ;读控制操作指令字

    ld CTRLCOM_TEMP2,Y+

    cp CTRLCOM_TEMP,CTRLCOM_TEMP2   ;比较控制操作指令字是否相等?

    brne CTRLCOMM_IdentifyCOM_RET     ;否,直接返回

                                      ;是,则继续读下一控制操作指令字

    dec CTRLCOM_CNT                 ;循环计数器 — 1

    brne CTRLCOMM_IdentifyCOM1

    ldi CCTSSDV_Right,CCTSSDV_RightI;置控制操作指令正确标志值

CTRLCOMM_IdentifyCOM_RET:

    pop YH                          ;弹出堆栈中的 Y 指针数值

    pop YL

    ret                             ;子程序返回





;*******************************************************************************

;!!!注意:下面所有的控制操作指令处理程序,在返回时均不能修改 Y 指针数值。

;*******************************************************************************



;*******************************************************************************

;*

;* 所有控制操作指令开头标识字符串 - “ControlHandle_Head”

;*

;*******************************************************************************

ControlHandle_Head:

.DB $07,"Control"                   ;控制操作指令开头标识字符(Control)

;   │   │

;   │   控制操作指令开头标识字符(Control)

;   本指令字符串字符长度数值(不包括自已在内共 7 个字符)





;*******************************************************************************

;*

;* 以整页方式启动内部 ADC 转换进行测量指令 - “OpenFullPageADC”

;*

;*******************************************************************************

OpenFullPageADC:

.DB $0f,"OpenFullPageADC"

;   │   │

;   │   控制操作指令字(OpenFullPageADC)

;   本指令字符串字符长度数值(不包括自已在内共 15 个字符)



;*** 此段程序用于此条控制操作指令处理

CTRLCOMM_OFPADC:

    clr CTRLCOM_MPFMS               ;清除控制操作指令己经执行标志值

    lds ZL,IADCI_StaFUP             ;检查启动整页ADC转换是否己完成?

    cpi ZL,IADCI_StaFUPI              ;是,则继续

    breq CTRLCOMM_OFPADC_RET          ;否,直接返回

    ldi CTRLCOM_TEMP,IADCI_StaFUPI  ;置启动整页 ADC 转换标志值

    sts IADCI_StaFUP,CTRLCOM_TEMP

    ldi CTRLCOM_MPFMS,CTRLCOM_MPFMSI;置控制操作指令己经执行标志值

    set                             ;置 T 标志

CTRLCOMM_OFPADC_RET:

    ret                             ;子程序返回





;*******************************************************************************

;*

;* 以单组方式启动内部 ADC 转换指令 - “OpenSingleGroupADC”

;*

;*******************************************************************************

OpenSingleGroupADC:

.DB $12,"OpenSingleGroupADC"

;   │   │

;   │   控制操作指令字(OpenSingleGroupADC)

;   本指令字符串字符长度数值(不包括自已在内共 18 个字符)



;*** 此段程序用于此条控制操作指令处理

CTRLCOMM_OSGADC:

    clr CTRLCOM_MPFMS               ;清除控制操作指令己经执行标志值

    lds ZL,IADCI_StaFUP             ;检查启动整页ADC转换是否己完成?

    cpi ZL,IADCI_StaFUPI              ;是,则继续

    breq CTRLCOMM_OSGADC_RET          ;否,直接返回

    lds ZL,IADCI_StaGro             ;检查启动单组ADC转换是否己完成?

    cpi ZL,IADCI_StaGroI              ;是,则继续

    breq CTRLCOMM_OSGADC_RET          ;否,直接返回

    ldi CTRLCOM_TEMP,IADCI_StaGroI  ;置启动单组 ADC 转换标志值

    sts IADCI_StaGro,CTRLCOM_TEMP

    ldi CTRLCOM_MPFMS,CTRLCOM_MPFMSI;置控制操作指令己经执行标志值

    set                             ;置 T 标志

CTRLCOMM_OSGADC_RET:

    ret                             ;子程序返回





;*******************************************************************************

;*

;* 以单通道方式启动内部 ADC 转换指令 - “OpenSingleChannelADC:X”

;*

;*******************************************************************************

OpenSingleChannelADC_X:

.DB $15,"OpenSingleChannelADC:",$00

;   │   │                     │

;   │   │                     ADC 模拟通道数与增益选择数值

;   │   控制操作指令字(OpenSingleChannelADC:X)

;   本指令字符串字符有效长度数值(不包括自已在内共 21 个字符)

;   注:最后这个“X”字符为 ADC 模拟通道数与增益选择数值,由传送方具体确定。

;       最后这个“X”字符为变量,不需要对其进行指令识别,因此不包括在本指令

;       字符串字符长度数值中。



;*** 此段程序用于此条控制操作指令处理

CTRLCOMM_OSSCADC:

    push YL                         ;压入 Y 指针的数值到堆栈

    push YH

    clr CTRLCOM_MPFMS               ;清除控制操作指令己经执行标志值

    lds ZL,IADCI_StaFUP             ;检查启动整页ADC转换是否己完成?

    cpi ZL,IADCI_StaFUPI              ;是,则继续

    breq CTRLCOMM_OSSCADC_RET         ;否,直接返回

    lds ZL,IADCI_StaGro             ;检查启动单组ADC转换是否己完成?

    cpi ZL,IADCI_StaGroI              ;是,则继续

    breq CTRLCOMM_OSSCADC_RET         ;否,直接返回

    lds ZL,IADCI_SinEnd             ;检查单通道 ADC 转换是否己结束?

    cpi ZL,IADCI_SinEndI              ;是,则继续

    breq CTRLCOMM_OSSCADC_RET         ;否,直接返回

    ldi ZL,Low(OpenSingleChannelADC_X*2)

    ldi ZH,High(OpenSingleChannelADC_X*2)

    lpm CTRLCOM_CNT,Z               ;置 Y 指针指向本指令字符串的最后一个字符,

    clr CTRLCOM_TEMP                  ;根据定义传送来的最后一个字符,

    add YL,CTRLCOM_CNT                ;为要测量的 ADC 模拟通道数与增益选择值

    adc YH,CTRLCOM_TEMP

    ld CTRLCOM_TEMP,Y               ;置 ADC 模拟通道数与增益选择值

    sts IADCI_SMUXNum,CTRLCOM_TEMP

    call IADCI_Start_SSingle        ;启动单通道单个ADC转换

    ldi CTRLCOM_MPFMS,CTRLCOM_MPFMSI;置控制操作指令己经执行标志值

    set                             ;置 T 标志

CTRLCOMM_OSSCADC_RET:

    pop YH                          ;弹出堆栈中的 Y 指针数值

    pop YL

    ret                             ;子程序返回



;*******************************************************************************

;*

;* 要求发送整页 ADC 转换结果数据指令 - “TXD@FullPageADC”

;*

;*******************************************************************************

TXD_FullPageADC:

.DB $0f,"TXD@FullPageADC"

;   │   │

;   │   控制操作指令字(TXD@FullPageADC)

;   本指令字符串字符长度数值(不包括自已在内共 15 个字符)



;*** 此段程序用于此条控制操作指令处理

CTRLCOMM_TXDFPADC:

    clr CTRLCOM_MPFMS               ;清除控制操作指令己经执行标志值

    lds ZL,IADCI_StaFUP             ;检查启动整页ADC转换是否己完成?

    cpi ZL,IADCI_StaFUPI              ;是,则继续

    breq CTRLCOMM_TXDFPADC_RET        ;否,直接返回

    lds ZL,CCOMALW_USART            ;检查是否允许处理 USART 端口的控制操作指令?

    cpi ZL,CTRLCOM_ALWSI              ;是,到相应处理

    brne CTRLCOMM_TXDFPADC2           ;否,则继续

    rcall CTRLCOMM_TXDFPADC_USART

    rjmp CTRLCOMM_TXDFPADC_End

CTRLCOMM_TXDFPADC2:



;此处可继续插入由其他地方传来此条控制操作指令处理程序



CTRLCOMM_TXDFPADC_End:

    clr ZL                          ;清除允许处理整页 ADC 转换结果数据标志

    sts IADCI_PDPALW,ZL

    ldi CTRLCOM_MPFMS,CTRLCOM_MPFMSI;置控制操作指令己经执行标志值

    clt                             ;清除 T 标志

CTRLCOMM_TXDFPADC_RET:

    ret                             ;子程序返回





;此段程序用于[由 USART 端口送来此条控制操作指令]处理

CTRLCOMM_TXDFPADC_USART:

    clr ZL                          ;清除允许更新发送数据标志

    sts DataUPD_TXALW,ZL

    ldi ZL,Low(IADCI_CDataPA)       ;置整页 ADC 转换结果数据的地址指针

    ldi ZH,High(IADCI_CDataPA)

    ldi YL,Low(USARTAI_TXDAA)       ;置从 USART 端口发送数据的地址指针

    ldi YH,High(USARTAI_TXDAA)

    ld CTRLCOM_CNT,Z                ;置循环计数器初值

CTRLCOMM_TXDFPADC_USART1:

    ld CTRLCOM_TEMP,Z+              ;读整页 ADC 转换结果数据

    st Y+,CTRLCOM_TEMP              ;写入从 USART 端口发送地址

    dec CTRLCOM_CNT                 ;循环计数器 — 1

    brne CTRLCOMM_TXDFPADC_USART1

    ret                             ;子程序返回





;*******************************************************************************

;*

;* 要求发送单组 ADC 转换结果数据指令 - “TXD@SingleGroupADC”

;*

;*******************************************************************************

TXD_SingleGroupADC:

.DB $12,"TXD@SingleGroupADC"

;   │   │

;   │   控制操作指令字(TXD@SingleGroupADC)

;   本指令字符串字符长度数值(不包括自已在内共 18 个字符)



;*** 此段程序用于此条控制操作指令处理

CTRLCOMM_TXDSGADC:

    clr CTRLCOM_MPFMS               ;清除控制操作指令己经执行标志值

    lds ZL,IADCI_StaGro             ;检查启动单组ADC转换是否己完成?

    cpi ZL,IADCI_StaGroI              ;是,则继续

    breq CTRLCOMM_TXDSGADC_RET        ;否,直接返回

    lds ZL,CCOMALW_USART            ;检查是否允许处理 USART 端口的控制操作指令?

    cpi ZL,CTRLCOM_ALWSI              ;是,到相应处理

    brne CTRLCOMM_TXDSGADC2           ;否,则继续

    rcall CTRLCOMM_TXDSGADC_USART

    rjmp CTRLCOMM_TXDSGADC_End

CTRLCOMM_TXDSGADC2:



;此处可继续插入由其他地方传来此条控制操作指令处理程序



CTRLCOMM_TXDSGADC_End:

    clr ZL                          ;清除允许处理单组 ADC 转换结果数据标志

    sts IADCI_GDPALW,ZL

    ldi CTRLCOM_MPFMS,CTRLCOM_MPFMSI;置控制操作指令己经执行标志值

    clt                             ;清除 T 标志

CTRLCOMM_TXDSGADC_RET:

    ret                             ;子程序返回





;此段程序用于[由 USART 端口送来此条控制操作指令]处理

CTRLCOMM_TXDSGADC_USART:

    clr ZL                          ;清除允许更新发送数据标志

    sts DataUPD_TXALW,ZL

    clr CTRLCOM_TEMP                ;清除暂存寄存器

    ldi CTRLCOM_CNT,((IADCI_CDGNumI-1)*2)

                                    ;置循环计数器初值= 测量的通道数目

    lds ZL,IADCI_CDPPL              ;置单组 ADC 转换结果数据最后存储地址指针

    lds ZH,IADCI_CDPPH

    sub ZL,CTRLCOM_CNT              ; ADC 转换结果数据存储地址指针,

    sbc ZH,CTRLCOM_TEMP               ;返回单组数据首个数据存储地址

    ldi YL,Low(USARTAI_TXDAA)       ;置从 USART 端口发送数据的地址指针

    ldi YH,High(USARTAI_TXDAA)

    ldi CTRLCOM_TEMP,((IADCI_CDGNumI-1)*2+3)

                                    ;发送转换结果数据总长度数值

                                    ;= 测量的通道数目+ 3 个字节

    st Y+,CTRLCOM_TEMP              ;写入从 USART 端口发送首个数据地址中

    ldi CTRLCOM_CNT,((IADCI_CDGNumI-1)*2)

                                    ;置循环计数器初值

CTRLCOMM_TXDSGADC_USART1:

    ld CTRLCOM_TEMP,Z+              ;读整页 ADC 转换结果数据

    st Y+,CTRLCOM_TEMP              ;写入从 USART 端口发送地址

    dec CTRLCOM_CNT                 ;循环计数器 — 1

    brne CTRLCOMM_TXDSGADC_USART1

    clr CTRLCOM_TEMP                ;清除暂存寄存器

    st Y+,CTRLCOM_TEMP              ;清除最后两个字节

    st Y+,CTRLCOM_TEMP

    ldi DCRC2B_DLength,((IADCI_CDGNumI-1)*2+3)

                                    ;置校验的数据长度初值

    ldi ZL,Low(USARTAI_TXDAA)       ;Z 指针指向发送数据首个字节

    ldi ZH,High(USARTAI_TXDAA)

    call DataCheck_CRC2B            ;生成发送数据序列的 CRC 码

    ret                             ;子程序返回





;*******************************************************************************

;*

;* 要求发送单通道 ADC 转换结果数据指令 - “TXD@SingleChannelADC”

;*

;*******************************************************************************

TXD_SingleChannelADC:

.DB $14,"TXD@SingleChannelADC"

;   │   │

;   │   控制操作指令字(TXD@SingleChannelADC)

;   本指令字符串字符长度数值(不包括自已在内共 20 个字符)



;*** 此段程序用于此条控制操作指令处理

CTRLCOMM_TXDSSCADC:

    clr CTRLCOM_MPFMS               ;清除控制操作指令己经执行标志值

    lds ZL,IADCI_SinEnd             ;检查单通道 ADC 转换是否己结束?

    cpi ZL,IADCI_SinEndI              ;是,则继续

    breq CTRLCOMM_TXDSSCADC_RET       ;否,直接返回

    lds ZL,CCOMALW_USART            ;检查是否允许处理 USART 端口的控制操作指令?

    cpi ZL,CTRLCOM_ALWSI              ;是,到相应处理

    brne CTRLCOMM_TXDSSCADC2          ;否,则继续

    rcall CTRLCOMM_TXDSSCADC_USART

    rjmp CTRLCOMM_TXDSSCADC_End

CTRLCOMM_TXDSSCADC2:



;此处可继续插入由其他地方传来此条控制操作指令处理程序



CTRLCOMM_TXDSSCADC_End:

    clr ZL                          ;清除允许处理单个 ADC 转换结果数据标志

    sts IADCI_SDPALW,ZL

    ldi CTRLCOM_MPFMS,CTRLCOM_MPFMSI;置控制操作指令己经执行标志值

    clt                             ;清除 T 标志

CTRLCOMM_TXDSSCADC_RET:

    ret                             ;子程序返回





;此段程序用于[由 USART 端口送来此条控制操作指令]处理

CTRLCOMM_TXDSSCADC_USART:

    clr ZL                          ;清除允许更新发送数据标志

    sts DataUPD_TXALW,ZL

    ldi YL,Low(USARTAI_TXDAA)       ;置从 USART 端口发送数据的地址指针

    ldi YH,High(USARTAI_TXDAA)

    lds CTRLCOM_TEMP2,(IADCI_CDataSH+IADCI_CDSNumI*2-2)

                                    ;取二进制 ADC 转换结果数据

    lds CTRLCOM_TEMP,(IADCI_CDataSH+IADCI_CDSNumI*2-1)

;--------------------------------------------------------------------------

;注:如果需要 BCD 码的 ADC 转换结果数据,用下面这两条指令代替上面两条指令。

;    lds CTRLCOM_TEMP2,IADCI_CDataSH ;取 BCD 码单个 ADC 转换结果数据

;    lds CTRLCOM_TEMP,(IADCI_CDataSH+1)

;--------------------------------------------------------------------------

    ldi CTRLCOM_CNT,(1*2+3)         ;置本次发送数据的总字节长度值

    st Y+,CTRLCOM_CNT               ;写入总字节长度值到 USART 端口发送地址

    st Y+,CTRLCOM_TEMP2             ;写入数据高字节到 USART 端口发送地址

    st Y+,CTRLCOM_TEMP              ;写入数据低字节到 USART 端口发送地址

    clr CTRLCOM_TEMP                ;清除暂存寄存器

    st Y+,CTRLCOM_TEMP              ;清除最后两个字节

    st Y+,CTRLCOM_TEMP

    ldi DCRC2B_DLength,(1*2+3)      ;置校验的数据长度初值

    ldi ZL,Low(USARTAI_TXDAA)       ;Z 指针指向发送数据首个字节

    ldi ZH,High(USARTAI_TXDAA)

    call DataCheck_CRC2B            ;生成发送数据序列的 CRC 码

    ret                             ;子程序返回





;*******************************************************************************

;*

;* 修改在 EEPROM 中的 4 个字节设备编号指令 - “ChangeDeviceNumber:XXXX”

;*

;*******************************************************************************

ChangeDeviceNumber_XXXX:

.DB $13,"ChangeDeviceNumber:",$36,$36,$38,$38

;   │   │                    │

;   │   │                    4 个字节设备编号数值

;   │   控制操作指令字(ChangeDeviceNumber:XXXX)

;   本指令字符串字符有效长度数值(不包括自已在内共 19 个字符)

;   注:最后这 4 个“XXXX”字符为设备编号数值,由传送方具体确定。最后这 4 个

;       “XXXXX”字符为设备编号数值,为变量,不需要对其进行指令识别,因此不包

;       括在本指令字符串字符长度数值中。



;*** 此段程序用于此条控制操作指令处理

CTRLCOMM_ChangeDN:

    push YL                         ;压入 Y 指针的数值到堆栈

    push YH

    ldi ZL,Low(ChangeDeviceNumber_XXXX*2)

    ldi ZH,High(ChangeDeviceNumber_XXXX*2)

    lpm CTRLCOM_CNT,Z               ;置 Y 指针指向本指令字符串的最后 4 个字符,

    clr CTRLCOM_TEMP                  ;根据定义传送来的最后 4 个字符,

    add YL,CTRLCOM_CNT                ;为 4 个字节设备编号数值

    adc YH,CTRLCOM_TEMP

    mov ZL,YL

    mov ZH,YH

    ldi EEPROM_DNum,CTRLCDN_CharNI  ;置写入到 EEPROM 中的数据个数

    ldi EEPROM_AddrL,Low(CC_EEPROM_DNAr)

    ldi EEPROM_AddrH,High(CC_EEPROM_DNAr)

                                    ;置在 EEPROM 中的设备编号地址指针

    call EEPROM_Write_FSRAM         ;写入设备编号数值到 EEPROM 中

    ldi CTRLCOM_MPFMS,CTRLCOM_MPFMSI;置控制操作指令己经执行标志值

    set                             ;置 T 标志

CTRLCOMM_ChangeDN_RET:

    pop YH                          ;弹出堆栈中的 Y 指针数值

    pop YL

    ret                             ;子程序返回







;*******************************************************************************

;*

;* 子程序名:         DataCheck_CRC2B.asm

;* 程序名称:         2字节数据循环冗余检测校验程序

;* 版本:           1.0

;* 适用 MCU 型号:    AVR所有型号

;* 入口条件:                              16

;*                   Z 指针(指向数据序列 X  ×F(X) 的 SRAM 存储地址)

;*                                                 16

;*                 DCRC2B_DLength (r20)(校验的 X  ×F(X) 数据长度)

;* 出口条件:

;*                                                          16

;*                   余式R(X)(校验字节)在 YL:YH 中,亦在 X  ×F(X)

;*                   最后两个字节中。

;* 使用资源:         r16,r17,r18,r19,r20,r28,r29,r30,r31

;*

;* 程序功能:  

;*   本程序是用于数据循环冗余检测校验处理。校验用的为2位监督码(CRC码)

;*

;* 注意:

;*   ①.校验用的为2位监督码(CRC码)必须放在数据序列的的最后两个位置。经

;*      本程序校验后这2位将为“$00,$O0”或恢复原来设置的数据值。

;*   ②.生成的2位监督码(CRC码)也是放在数据序列的的最后两个位置。在调用

;*      本程序前,必须对这2位清为“$00,$O0”或设置校验的数据值。

;*

;* 注释:

;*   ①.本子程序用于数据循环冗余检测校验处理。其生成 CRC 校验码的公式为:

;*         16

;*        X  ×F(X)/P(X)=Q(X)+R(X)/P(X)

;*               16

;*        其中:X  ×F(X) 为数据序列 F(X) 后面再加 2 字节 $00

;*              P(X) 为除数多项式

;*              Q(X) 为商

;*              R(X) 为余式,即生成的 CRC 校验码

;*                                         16   12   5

;*   ②.本子程序选用的除数多项式:P(X)=X  +X  +X +1=$11021

;*                  16                                   16

;*   ③.发送时将 X  ×F(X)+R(X) 发送出去。接收方再将 X  ×F(X)除以 P(X) ,

;*        如果得到余式 R(X)=$0000,表示接收正确。

;*   ④.本子程序的除以除数 P(X) 并非为通常的被除数除以除数的算术除法运算,

;*        而是用不计借位的减法,即位异或(半加)进行计算。程序中只将最高位

;*        =1 的数据在 YL:YH 中与立即数 $8005 进行异或操作。

;*   ⑤.本子程序最大校验数据序列 F(X) 的长度不超过 254 个字节,每字节为

;*         8 位二进制数。

;*                                    16

;*   ⑥.两个校验字节必须放在数据序列 X  ×F(X) 的最后两个位置。

;*        在本子程序运行后除放在最后两个位置外,亦放在 YL:YH 中。

;*

;* 编作者:          

;* 编作者 E-Mail:     PTZSW@163.COM

;* 编制日期:          2005年1月18日

;*

;*******************************************************************************

;*

;* 指令条数:          38 + return

;* 指令执行周期:     17611 + return (Min)

;*                    18692 + return (Max)

;* 低位寄存器使用:    None

;* 高位寄存器使用:    4 (r16,r17,r18,r19,r20)

;* 指针寄存器使用:    Y,Z

;* 状态寄存器使用:    None

;*

;*******************************************************************************



;******** 本程序寄存器变量定义:



.def    DCRC2B_TEMP    = r16        ;暂存寄存器

.def    DCRC2B_RDIVH   = r17        ;除数多项式的除数高字节

.def    DCRC2B_RDIVL   = r18        ;除数多项式的除数低字节

.def    DCRC2B_BitNum  = r19        ;校验的字节位数

.def    DCRC2B_DLength = r20        ;校验的数据序列长度





;******** 程序指令代码清单:



DataCheck_CRC2B:

    clr YL                          ;清除余式R(X)(校验字节)的寄存器

    clr YH

    ldi DCRC2B_RDIVH,$10            ;                 16   12   5

    ldi DCRC2B_RDIVL,$21            ;除数多项式P(X)=X  +X  +X +1=$11021

DataCheck_CRC2B1:

    ldi DCRC2B_BitNum,$08           ; 8 位/每字节

    ld DCRC2B_TEMP,Z+               ;取 Z 指针指向的 SRAM 中数据

DataCheck_CRC2B2:

    lsl DCRC2B_TEMP

    rol YH

    rol YL

    brcc DataCheck_CRC2B3           ;当移出位为 1 时,

    eor YL,DCRC2B_RDIVH             ;将寄存器 YL:YH 中的内容

    eor YH,DCRC2B_RDIVL             ;与立即数 $1021 异或

DataCheck_CRC2B3:

    dec DCRC2B_BitNum               ;位数-1

    brne DataCheck_CRC2B2

    dec DCRC2B_DLength              ;数据长度-1

    brne DataCheck_CRC2B1      

    st -Z,YH

    st -Z,YL

    ret                             ;子程序返回





;*******************************************************************************

;*

;* 子程序名:          Access_EEPROM.asm

;* 程序名称:          存取 EEPROM (电可擦除只读存储器)程序

;* 版本:            1.0

;* 适用 MCU 型号:     AVR所有型号

;* 使用资源:          r16,r17,r24,r25,r30,r31

;*

;* 程序功能:        

;*   本程序是向 EEPROM (电可擦除只读存储器)存取数据子程序,共包括四个子

;* 程序。二个为存取单个字节数据到 EEPROM 中的子程序,二个为与 SRAM (静态随

;* 机存储器)交换存取多个字节数据的子程序。

;*

;* 编作者:            

;* 编作者 E-Mail:     PTZSW@163.COM

;* 编制日期:          2005年3月8日

;*

;*******************************************************************************

;*

;* 指令条数:          66 + return

;* 指令执行周期:      0 + return

;* 低位寄存器使用:    None

;* 高位寄存器使用:    4 (r16,r17,r24,r25)

;* 指针寄存器使用:    Z

;*

;*******************************************************************************



;******** 本程序寄存器变量定义:



.def    EEPROM_Data    = r16        ;从 EEPROM 存取的数据

.def    EEPROM_DNum    = r17        ;存取 EEPROM 数据的个数

.def    EEPROM_AddrL   = r24        ;存取 EEPROM 地址低字节

.def    EEPROM_AddrH   = r25        ;存取 EEPROM 地址高字节





;******** 程序指令代码清单:



;*******************************************************************************

;* 本程序共包括下面四个子程序:

;*

;* “EEPROM_WriteSingle” -------- 写入单个字节数据到 EEPROM 中子程序

;*             入口条件: EEPROM_AddrL(r24)---- 写入到 EEPROM 的地址低字节

;*                       EEPROM_AddrH(r25)---- 写入到 EEPROM 的地址高字节

;*                       EEPROM_Data(r16)----- 写入到 EEPROM 中的数据

;*

;* “EEPROM_ReadSingle” --------- 从 EEPROM 中读取单个字节数据子程序

;*             入口条件: EEPROM_AddrL(r24)---- 从 EEPROM 中读取的地址低字节

;*                       EEPROM_AddrH(r25)---- 从 EEPROM 中读取的地址高字节

;*             出口条件: EEPROM_Data(r16)----- 从 EEPROM 中读取的数据

;*

;* “EEPROM_Write_FSRAM” -------- 从 SRAM 中写入多个字节数据到 EEPROM 中子程序

;*             入口条件: EEPROM_AddrL(r24)---- 写入到 EEPROM 的地址低字节

;*                       EEPROM_AddrH(r25)---- 写入到 EEPROM 的地址高字节

;*                       Z 指针 ---------------- 指向在 SRAM 中数据的起始地址

;*                       EEPROM_DNum(r17)----- 写入到 EEPROM 中的数据个数

;*

;* “EEPROM_Read_TSRAM” --------- 从 EEPROM 中读取多个字节数据到 SRAM 中子程序

;*             入口条件: EEPROM_AddrL(r24)---- 从 EEPROM 中读取的地址低字节

;*                       EEPROM_AddrH(r25)---- 从 EEPROM 中读取的地址高字节

;*                       Z 指针 ---------------- 指向在 SRAM 中数据的起始地址

;*                       EEPROM_DNum(r17)----- 从 EEPROM 中读取的数据个数

;*             出口条件: Z 指针 ---------------- 指向在 SRAM 中数据的起始地址

;*

;*******************************************************************************



;*******************************************************************************

;*

;* 写入单个字节数据到 EEPROM 中子程序 - “EEPROM_WriteSingle”

;*

;* 说明:

;*   本子程序是在等待 EEPROM 就绪后编程,使用两个寄存器地址变量“EEPROM_AddrL

;* :EEPROM_AddrH”(r24:r25),将寄存器变量“EEPROM_Data”(r16)中的单个字节数

;* 据写入到指定地址的 EEPROM 中。

;*

;* 入口条件:

;*        在调用本程序前,需设置下面这三个寄存器数值:

;*          EEPROM_AddrL(r24)--------- 写入到 EEPROM 的地址低字节

;*          EEPROM_AddrH(r25)--------- 写入到 EEPROM 的地址高字节

;*          EEPROM_Data(r16)---------- 写入到 EEPROM 中的数据

;*

;* 指令条数:          9 + return

;* 指令执行周期:      13 + return

;* 低位寄存器使用:    None

;* 高位寄存器使用:    3 (r16,r24,r25)

;* 指针寄存器使用:    None

;*

;*******************************************************************************

EEPROM_WriteSingle:

    sbic EECR,EEWE                  ;如果 EEWE 不清除

    rjmp EEPROM_WriteSingle         ;等待,上一次 EEPROM 写操作结束

    out EEARH,EEPROM_AddrH          ;输出写入的 EEPROM 地址高位

    out EEARL,EEPROM_AddrL          ;输出写入的 EEPROM 地址低位

    out EEDR,EEPROM_Data            ;输出写入的 EEPROM 数据

    cli                             ;禁止全局中断

                                      ;此指令用于在写 EEPROM 时,如果发生中断,

                                      ;将导致写操作超时,造成写 EEPROM 失败。

    sbi EECR,EEMWE                  ;设置 EEPROM 主机写使能   

    sbi EECR,EEWE                   ;设置 EEPROM 写使能

                                      ;该指令需 4 个时钟周期,

                                      ;由于它暂停 CPU 2 个时钟周期

    sei                             ;打开全局中断

    ret                             ;子程序返回





;*******************************************************************************

;*

;* 从 EEPROM 中读取单个字节数据子程序 - “EEPROM_ReadSingle”

;*

;* 说明:

;*   本子程序是在等待 EEPROM 就绪后编程,使用两个寄存器地址变量“EEPROM_AddrL

;* :EEPROM_AddrH”(r24:r25),将指定地址的 EEPROM 中的单个字节数据读取到寄存器

;* 变量“EEPROM_Data”(r16)中。

;*

;* 入口条件:

;*        在调用本程序前,需设置下面这两个寄存器数值:

;*          EEPROM_AddrL(r24)--------- 从 EEPROM 中读取数据的地址低字节

;*          EEPROM_AddrH(r25)--------- 从 EEPROM 中读取数据的地址高字节

;* 出口条件:

;*         程序运行结束后,将对会下面这个寄存器变量置值。

;*          EEPROM_Data(r16)---------- 从 EEPROM 中读取的数据

;*

;* 指令条数:          6 + return

;* 指令执行周期:      9 + return

;* 低位寄存器使用:    None

;* 高位寄存器使用:    3 (r16,r24,r25)

;* 指针寄存器使用:    None

;*

;*******************************************************************************

EEPROM_ReadSingle:

    sbic EECR,EEWE                  ;如果 EEWE 不清除

    rjmp EEPROM_ReadSingle          ;等待

    out EEARH,EEPROM_AddrH          ;输出读取的 EEPROM 地址高位

    out EEARL,EEPROM_AddrL          ;输出读取的 EEPROM 地址低位

    sbi EECR,EERE                   ;设置 EEPROM 读使能

                                      ;该指令需 4 个时钟周期,

                                      ;由于它暂停 CPU 2 个时钟周期

    in EEPROM_Data,EEDR             ;从 EEPROM 中读取数据

    ret                             ;子程序返回





;*******************************************************************************

;*

;* 从 SRAM 中写入多个字节数据到 EEPROM 中子程序 - “EEPROM_Write_FSRAM”

;*

;* 说明:

;*   本子程序是将从 Z 指针指向起始地址的在 SRAM 中多个字节数据,写入到由两个寄

;* 存器地址变量“EEPROM_AddrL:EEPROM_AddrH”(r24:r25)指向起始地址的 EEPROM 中。

;* 每次写入的数据字节数均不超过 255 个字节。

;*

;* 入口条件:

;*        在调用本程序前,需设置下面这几个寄存器数值:

;*          EEPROM_AddrL(r24)--------- 写入到 EEPROM 的起始地址低字节

;*          EEPROM_AddrH(r25)--------- 写入到 EEPROM 的起始地址高字节

;*          Z 指针 --------------------- 指向在 SRAM 中多个字节数据的起始地址

;*          EEPROM_DNum(r17)---------- 写入到 EEPROM 中的数据个数

;*

;* 指令条数:          29 + return

;* 指令执行周期:      26 + return(Min:EEPROM_DNum =$01)

;*                    9676 + return(Max:EEPROM_DNum =$ff)

;* 低位寄存器使用:    None

;* 高位寄存器使用:    4 (r16,r17,r24,r25)

;* 指针寄存器使用:    Z

;*

;*******************************************************************************

EEPROM_Write_FSRAM:

    sbic EECR,EEWE                  ;如果 EEWE 不清除

    rjmp EEPROM_Write_FSRAM         ;等待,上一次 EEPROM 写操作结束

    ld EEPROM_Data,Z+               ;从 SRAM 中读取数据

    out EEARH,EEPROM_AddrH          ;输出写入的 EEPROM 起始地址高位

    out EEARL,EEPROM_AddrL          ;输出写入的 EEPROM 起始地址低位

    out EEDR,EEPROM_Data            ;将数据写入到 EEPROM 中

    cli                             ;禁止全局中断

                                      ;此指令用于在写 EEPROM 时,如果发生中断,

                                      ;将导致写操作超时,造成写 EEPROM 失败。

    sbi EECR,EEMWE                  ;设置 EEPROM 主机写使能   

    sbi EECR,EEWE                   ;设置 EEPROM 写使能

                                      ;该指令需 4 个时钟周期,

                                      ;由于它暂停 CPU 2 个时钟周期

    sei                             ;打开全局中断

    dec EEPROM_DNum                 ;数据个数 — 1

    cpi EEPROM_DNum,$01

    brlo EEPROM_Write_FSRAM_RET     ;写完否?写完则结束

EEPROM_Write_FSRAM1:

    sbic EECR,EEWE                  ;如果 EEWE 不清除

    rjmp EEPROM_Write_FSRAM1        ;等待,上一次 EEPROM 写操作结束

    ld EEPROM_Data,Z+               ;从 SRAM 中读取数据

    in EEPROM_AddrL,EEARL           ;获得地址低位

    in EEPROM_AddrH,EEARH           ;获得地址高位

    adiw EEPROM_AddrL,0x01          ;地址 + 1

    out EEARH,EEPROM_AddrH          ;输出写入的 EEPROM 起始地址高位

    out EEARL,EEPROM_AddrL          ;输出写入的 EEPROM 起始地址低位

    out EEDR,EEPROM_Data            ;将数据写入到 EEPROM 中

    cli                             ;禁止全局中断

                                      ;此指令用于在写 EEPROM 时,如果发生中断,

                                      ;将导致写操作超时,造成写 EEPROM 失败。

    sbi EECR,EEMWE                  ;设置 EEPROM 主机写使能   

    sbi EECR,EEWE                   ;设置 EEPROM 写使能

                                      ;该指令需 4 个时钟周期,

                                      ;由于它暂停 CPU 2 个时钟周期

    sei                             ;打开全局中断

    dec EEPROM_DNum                 ;数据个数 — 1

    brne EEPROM_Write_FSRAM1        ;写完否?未完则继续

EEPROM_Write_FSRAM_RET:

    ret                             ;子程序返回





;*******************************************************************************

;*

;* 从 EEPROM 中读取多个字节数据到 SRAM 中子程序 - “EEPROM_Read_TSRAM”

;*

;* 说明:

;*   本子程序是将由两个寄存器地址变量“EEPROM_AddrL:EEPROM_AddrH”(r24:r25)

;* 指向起始地址的 EEPROM 中,读取多个字节数据到从 Z 指针指向起始地址的 SRAM 中。

;* 每次读取的数据字节数均不超过 255 个字节。

;*

;* 入口条件:

;*        在调用本程序前,需设置下面这几个寄存器数值:

;*          EEPROM_AddrL(r24)--------- 从 EEPROM 中读取数据的地址低字节

;*          EEPROM_AddrH(r25)--------- 从 EEPROM 中读取数据的地址高字节

;*          Z 指针 --------------------- 指向在 SRAM 中多个字节数据的起始地址

;*          EEPROM_DNum(r17)---------- 从 EEPROM 中读取的数据个数

;*

;* 指令条数:          22 + return

;* 指令执行周期:      22 + return(Min:EEPROM_DNum =$01)

;*                    4084 + return(Max:EEPROM_DNum =$ff)

;* 低位寄存器使用:    None

;* 高位寄存器使用:    4 (r16,r17,r24,r25)

;* 指针寄存器使用:    Z

;*

;*******************************************************************************

EEPROM_Read_TSRAM:

    sbic EECR,EEWE                  ;如果 EEWE 不清除

    rjmp EEPROM_Read_TSRAM          ;等待,上一次 EEPROM 写操作结束

    out EEARH,EEPROM_AddrH          ;输出读取的 EEPROM 地址高位

    out EEARL,EEPROM_AddrL          ;输出读取的 EEPROM 地址低位

    sbi EECR,EERE                   ;设置 EEPROM 读使能

                                      ;该指令需 4 个时钟周期,

                                      ;由于它暂停 CPU 2 个时钟周期

    in EEPROM_Data,EEDR             ;从 EEPROM 中读取数据

    st Z+,EEPROM_Data               ;写入到 SRAM 中

    dec EEPROM_DNum                 ;数据个数 — 1

    cpi EEPROM_DNum,$01

    brlo EEPROM_Read_TSRAM_RET     ;写完否?写完则结束

EEPROM_Read_TSRAM1:

    sbic EECR,EEWE                  ;如果 EEWE 不清除

    rjmp EEPROM_Read_TSRAM1         ;等待,上一次 EEPROM 写操作结束

    in EEPROM_AddrL,EEARL           ;获得地址低位

    in EEPROM_AddrH,EEARH           ;获得地址高位

    adiw EEPROM_AddrL,0x01          ;地址 + 1

    out EEARH,EEPROM_AddrH          ;输出读取的 EEPROM 地址高位

    out EEARL,EEPROM_AddrL          ;输出读取的 EEPROM 地址低位

    sbi EECR,EERE                   ;设置 EEPROM 读使能

                                      ;该指令需 4 个时钟周期,

                                      ;由于它暂停 CPU 2 个时钟周期

    in EEPROM_Data,EEDR             ;从 EEPROM 中读取数据

    st Z+,EEPROM_Data               ;写入到 SRAM 中

    dec EEPROM_DNum                 ;数据个数 — 1

    brne EEPROM_Read_TSRAM1         ;读取完否?未完则继续

EEPROM_Read_TSRAM_RET:

    ret                             ;子程序返回







;*************************************************************************

;*

;* 文件名:             ATmega16def.inc

;* 文件标题:           ATmega16 单片机内部寄存器名和位名定义文件

;* 版本:               1.0

;* 适用 MCU 型号:      ATmega16 (ATMEL公司生产的单片机)

;*

;* 编作者:            

;* 编作者联系电话:     

;* 编作者 E-mail:      PTZSW@163.com

;* 编制日期:           2004年8月8日

;*                  

;*************************************************************************

;* 说明:

;*

;*   如果在编制的汇编语言源程序文件中如果包括了此定义文件,则数据手册

;* 中列出的所有I/O寄存器名和I/O寄存器位名都能在编制的程序中使用。

;*

;*   I/O寄存器名用十六进制地址表示。

;*

;*   I/O寄存器位名用数字0~7表示位数。

;*

;*   另外,由六个寄存器组成的三个(对数据空间间接寻址用)地址指针

;* X、Y、Z也分别被命名为:XL:XH、YL:YH、ZL:ZH。

;*

;*   片内SRAM数据存储空间的最高地址数也被定义。

;*

;*   请注意在指令中使用的位名是意义不相同的。如指令"sbr"/"cbr"表示的是

;* 置/清除寄存器中的指定位和"sbrs"/"sbrc"表示的是如果寄存器中的指定位被

;* 置位/清除则跳一行执行。如下面这些指令例子:

;*

;* in r16,PORTB                    ;读取 PORTB 寄存器中的内容

;* sbr r16,(1<<PB6)+(1<<PB5)       ;PB6 和 PB5 置1(使用屏蔽,而不是 bit# )

;* out PORTB,r16                   ;输出到 PORTB 寄存器中

;*

;* in r16,TIFR                     ;读取定时器中断标志寄存器中的内容

;* sbrc r16,TOV0                   ;检查溢出标志(使用 bit# )

;* rjmp TOV0_is_set                ;如果被置1,则跳转到 TOV0_is_set 标号

;* ...                             ;否则转到此行执行其他指令……

;*

;*************************************************************************







;******** 单片机型号定义:



.device   ATmega16





;******** I/O 寄存器定义:



.equ    SREG      =$3f      ;状态寄存器

.equ    SPH       =$3e      ;堆栈指针高字节

.equ    SPL       =$3d      ;堆栈指针低字节

.equ    OCR0      =$3c      ;输出比较寄存器

.equ    GIMSK     =$3b       ;通用中断屏蔽寄存器(为保持兼容性,两个名称都一同定义)

.equ    GICR      =$3b      ;通用中断屏蔽寄存器(GIMSK 的新名称)

.equ    GIFR      =$3a      ;通用中断标志寄存器

.equ    TIMSK     =$39      ;定时器中断屏蔽寄存器

.equ    TIFR      =$38      ;定时器中断标志寄存器

.equ    SPMCR     =$37      ;保存程序存储器控制寄存器

.equ    I2CR      =$36       ;TWI控制寄存器(为保持兼容性,两个名称都一同定义)

.equ    TWCR      =$36      ;TWI控制寄存器

.equ    MCUCR     =$35      ;MCU控制寄存器

.equ    MCUSR     =$34       ;MCU控制与状态寄存器(为保持兼容性,两个名称都一同定义)

.equ    MCUCSR    =$34      ;MCU控制与状态寄存器

.equ    TCCR0     =$33      ;定时器/计数器0控制寄存器

.equ    TCNT0     =$32      ;定时器/计数器0(8位)

.equ    OSCCAL    =$31      ;振荡器标定寄存器

.equ    SFIOR     =$30      ;特殊功能IO寄存器

.equ    TCCR1A    =$2f      ;定时器/计数器1控制寄存器A

.equ    TCCR1B    =$2e      ;定时器/计数器1控制寄存器B

.equ    TCNT1H    =$2d      ;定时器/计数器1高字节

.equ    TCNT1L    =$2c      ;定时器/计数器1低字节

.equ    OCR1AH    =$2b      ;定时器/计数器1输出比较寄存器A高字节

.equ    OCR1AL    =$2a      ;定时器/计数器1输出比较寄存器A低字节

.equ    OCR1BH    =$29      ;定时器/计数器1输出比较寄存器B高字节

.equ    OCR1BL    =$28      ;定时器/计数器1输出比较寄存器B低字节

.equ    ICR1H     =$27      ;定时器/计数器1输入捕获寄存器高字节

.equ    ICR1L     =$26      ;定时器/计数器1输入捕获寄存器低字节

.equ    TCCR2     =$25      ;定时器/计数器2控制寄存器

.equ    TCNT2     =$24      ;定时器/计数器2(8位)

.equ    OCR2      =$23      ;定时器/计数器2输出比较寄存器

.equ    ASSR      =$22      ;异步方式状态寄存器

.equ    WDTCR     =$21      ;看门狗定时器控制寄存器

.equ    UBRRHI    =$20       ;USART波特率寄存器(为保持兼容性,两个名称都一同定义)

.equ    UBRRH     =$20      ;USART波特率寄存器(注意:UCSRC 等于 UBRRH)

.equ    EEARH     =$1f      ;EEPROM地址寄存器高字节

.equ    EEARL     =$1e      ;EEPROM地址寄存器低字节

.equ    EEDR      =$1d      ;EEPROM数据寄存器

.equ    EECR      =$1c      ;EEPROM控制寄存器

.equ    PORTA     =$1b      ;端口A数据寄存器

.equ    DDRA      =$1a      ;端口A数据方向寄存器

.equ    PINA      =$19      ;端口A输入引脚地址

.equ    PORTB     =$18      ;端口B数据寄存器

.equ    DDRB      =$17      ;端口B数据方向寄存器

.equ    PINB      =$16      ;端口B输入引脚地址

.equ    PORTC     =$15      ;端口C数据寄存器

.equ    DDRC      =$14      ;端口C数据方向寄存器

.equ    PINC      =$13      ;端口C输入引脚地址

.equ    PORTD     =$12      ;端口D数据寄存器

.equ    DDRD      =$11      ;端口D数据方向寄存器

.equ    PIND      =$10      ;端口D输入引脚地址

.equ    SPDR      =$0f      ;SPI数据寄存器

.equ    SPSR      =$0e      ;SPI状态寄存器

.equ    SPCR      =$0d      ;SPI控制寄存器

.equ    UDR       =$0c      ;USART I/O 数据寄存器

.equ    USR       =$0b       ;USART控制和状态寄存器A(为保持兼容性,两个名称都一同定义)

.equ    UCSRA     =$0b      ;USART控制和状态寄存器A

.equ    UCR       =$0a       ;USART控制和状态寄存器B(为保持兼容性,两个名称都一同定义)

.equ    UCSRB     =$0a      ;USART控制和状态寄存器B

.equ    UCSRC     =$20      ;USART控制和状态寄存器C(注意:UCSRC 等于 UBRRH)

.equ    UBRR      =$09       ;USART波特率寄存器(为保持兼容性,两个名称都一同定义)

.equ    UBRRL     =$09      ;USART波特率寄存器

.equ    ACSR      =$08      ;模拟比较器控制和状态寄存器

.equ    ADMUX     =$07      ;ADC多路选择寄存器

.equ    ADCSR     =$06      ;ADC控制和状态寄存器

.equ    ADCH      =$05      ;ADC数据寄存器高字节

.equ    ADCL      =$04      ;ADC数据寄存器低字节

.equ    I2DR      =$03       ;TWI数据寄存器为(为保持兼容性,两个名称都一同定义)

.equ    TWDR      =$03      ;TWI数据寄存器

.equ    I2AR      =$02       ;TWI(从机)地址寄存器(为保持兼容性,两个名称都一同定义)

.equ    TWAR      =$02      ;TWI(从机)地址寄存器

.equ    I2SR      =$01       ;TWI状态寄存器(为保持兼容性,两个名称都一同定义)

.equ    TWSR      =$01      ;TWI状态寄存器

.equ    I2BR      =$00       ;TWI比特率寄存器(为保持兼容性,两个名称都一同定义)

.equ    TWBR      =$00      ;TWI比特率寄存器





;******** 位定义:



; GIMSK / GICR —— 通用中断屏蔽寄存器

.equ    INT1      =7        ;外部中断请求1使能位

.equ    INT0      =6        ;外部中断请求0使能位

.equ    INT2      =5        ;外部中断请求2使能位

.equ    IVSEL     =1        ;中断向量选择位

.equ    IVCE      =0        ;中断向量修改使能位



; GIFR —— 通用中断标志寄存器

.equ    INTF1     =7        ;外部中断请求1标志位

.equ    INTF0     =6        ;外部中断请求0标志位

.equ    INTF2     =5        ;外部中断请求2标志位



; TIMSK —— 定时器中断屏蔽寄存器

.equ    TOIE0     =0        ;T/C0溢出中断使能位

.equ    OCIE0     =1        ;T/C0输出比较匹配中断使能位

.equ    TOIE1     =2        ;T/C1溢出中断使能位

.equ    OCIE1B    =3        ;T/C1输出比较B匹配中断使能位

.equ    OCIE1A    =4        ;T/C1输出比较A匹配中断使能位

.equ    TICIE1    =5        ;T/C1输入捕捉中断使能位

.equ    TOIE2     =6        ;T/C2溢出中断使能位

.equ    OCIE2     =7        ;T/C2输出比较匹配中断使能位



; TIFR —— 定时器中断标志寄存器

.equ    TOV0      =0        ;T/C0溢出标志位

.equ    OCF0      =1        ;T/C0输出比较匹配标志位

.equ    TOV1      =2        ;T/C1溢出标志位

.equ    OCF1B     =3        ;T/C1输出比较B匹配标志位

.equ    OCF1A     =4        ;T/C1输出比较A匹配标志位

.equ    ICF1      =5        ;T/C1输入捕捉标志位

.equ    TOV2      =6        ;T/C2溢出标志位

.equ    OCF2      =7        ;T/C2输出比较匹配标志位



; SPMCR —— 保存程序存储器控制寄存器

.equ    SPMIE     =7        ;SPM中断使能位

.equ    ASB       =6        ;RWW区忙标志位

.equ    ASRE      =4        ;RWW区读使能位

.equ    BLBSET    =3        ;BOOT锁定位设置

.equ    PGWRT     =2        ;页写入

.equ    PGERS     =1        ;页擦除

.equ    SPMEN     =0        ;存贮程序存储器使能位



; TWCR —— TWI控制寄存器

.equ    TWINT     =7        ;TWI中断标志

.equ    TWEA      =6        ;使能TWI应答

.equ    TWSTA     =5        ;TWI开始状态标志位

.equ    TWSTO     =4        ;TWI结束状态标志位

.equ    TWWC      =3        ;TWI写碰撞标志

.equ    TWEN      =2        ;TWI使能位

.equ    TWIE      =0        ;使能TWI 中断



; MCUCR —— MCU控制寄存器

.equ    SM2       =7        ;休眠模式选择位2

.equ    SE        =6        ;休眠使能位

.equ    SM1       =5        ;休眠模式选择位1

.equ    SM0       =4        ;休眠模式选择位0

.equ    ISC11     =3        ;INT1中断触发方式控制位1

.equ    ISC10     =2        ;INT1中断触发方式控制位0

.equ    ISC01     =1        ;INT0中断触发方式控制位1

.equ    ISC00     =0        ;INT0中断触发方式控制位0



; MCUSR —— MCU控制与状态寄存器

.equ    ISC2      =6        ;INT2中断触发方式控制位

;.equ   JTRF      =4        ;JATG复位标志位

.equ    WDRF      =3        ;看门狗复位标志位

.equ    BORF      =2        ;掉电检测复位标志位

.equ    EXTRF     =1        ;外部复位标志位

.equ    PORF      =0        ;上电复位标志位



; TCCR0 —— 定时器/计数器0控制寄存器

.equ    FOC0      =7        ;强制输出比较

.equ    PWM0      =6         ;此位名定义已经不再使用!要使用 WGM00

.equ    WGM00     =6        ;波形产生模式控制位0

.equ    COM01     =5        ;比较匹配输出模式控制位1

.equ    COM00     =4        ;比较匹配输出模式控制位0

.equ    CTC0      =3         ;此位名定义已经不再使用!要使用 WGM01

.equ    WGM01     =3        ;波形产生模式控制位1

.equ    CS02      =2        ;时钟选择控制位2

.equ    CS01      =1        ;时钟选择控制位1

.equ    CS00      =0        ;时钟选择控制位0



; SFIOR —— 特殊功能IO寄存器

.equ    ADTS2     =7        ;ADC自动触发源控制位2

.equ    ADTS1     =6        ;ADC自动触发源控制位1

.equ    ADTS0     =5        ;ADC自动触发源控制位0

.equ    ADHSM     =4        ;

.equ    ACME      =3        ;模拟比较器多路复用器使能位

.equ    PUD       =2        ;禁用上拉电阻

.equ    PSR2      =1        ;T/C2预分频复位

.equ    PSR10     =0        ;T/C1与T/C0预分频器复位



; TCCR1A —— 定时器/计数器1控制寄存器A

.equ    COM1A1    =7        ;通道A的比较输出模式控制位1

.equ    COM1A0    =6        ;通道A的比较输出模式控制位0

.equ    COM1B1    =5        ;通道B的比较输出模式控制位1

.equ    COM1B0    =4        ;通道B的比较输出模式控制位0

.equ    FOC1A     =3        ;通道A强制输出比较

.equ    FOC1B     =2        ;通道B强制输出比较

.equ    PWM11     =1         ;此位名定义已经不再使用!要使用 WGM11

.equ    PWM10     =0         ;此位名定义已经不再使用!要使用 WGM10

.equ    WGM11     =1        ;波形产生模式控制位1

.equ    WGM10     =0        ;波形产生模式控制位0



; TCCR1B —— 定时器/计数器1控制寄存器B

.equ    ICNC1     =7        ;输入捕捉噪声抑制器使能位

.equ    ICES1     =6        ;输入捕捉触发沿选择位

.equ    CTC11     =4         ;此位名定义已经不再使用!要使用 WGM13

.equ    CTC10     =3         ;此位名定义已经不再使用!要使用 WGM12

.equ    CTC1      =3         ;此位名定义已经不再使用!要使用 WGM12

.equ    WGM13     =4        ;波形产生模式控制位3

.equ    WGM12     =3        ;波形产生模式控制位2

.equ    CS12      =2        ;时钟选择控制位2

.equ    CS11      =1        ;时钟选择控制位1

.equ    CS10      =0        ;时钟选择控制位0



; TCCR2 —— 定时器/计数器2控制寄存器

.equ    FOC2      =7        ;强制输出比较

.equ    PWM2      =6         ;此位名定义已经不再使用!要使用 WGM20

.equ    WGM20     =6        ;波形产生模式控制位0

.equ    COM21     =5        ;比较匹配输出模式控制位1

.equ    COM20     =4        ;比较匹配输出模式控制位0

.equ    CTC2      =3         ;此位名定义已经不再使用!要使用 WGM21

.equ    WGM21     =3        ;波形产生模式控制位1

.equ    CS22      =2        ;时钟选择控制位2

.equ    CS21      =1        ;时钟选择控制位1

.equ    CS20      =0        ;时钟选择控制位0



; ASSR —— 异步方式状态寄存器

.equ    AS2       =3        ;异步T/C2

.equ    TCN2UB    =2        ;T/C2更新中

.equ    OCR2UB    =1        ;输出比较寄存器2更新中

.equ    TCR2UB    =0        ;T/C2控制寄存器更新中



; WDTCR —— 看门狗定时器控制寄存器

.equ    WDTOE     =4        ;看门狗修改使能位

.equ    WDE       =3        ;看门狗使能位

.equ    WDP2      =2        ;看门狗定时器预分频器控制位2

.equ    WDP1      =1        ;看门狗定时器预分频器控制位1

.equ    WDP0      =0        ;看门狗定时器预分频器控制位0



; EECR —— EEPROM控制寄存器

.equ    EERIE     =3        ;使能EEPROM准备好中断

.equ    EEMWE     =2        ;EEPROM主机写使能

.equ    EEWE      =1        ;EEPROM写使能

.equ    EERE      =0        ;EEPROM读使能



; PORTA —— 端口A数据寄存器

.equ    PA7       =7

.equ    PA6       =6

.equ    PA5       =5

.equ    PA4       =4

.equ    PA3       =3

.equ    PA2       =2

.equ    PA1       =1

.equ    PA0       =0



; DDRA —— 端口A数据方向寄存器

.equ    DDA7      =7        ;引脚7的方向(输入/输出)控制位

.equ    DDA6      =6        ;引脚6的方向(输入/输出)控制位

.equ    DDA5      =5        ;引脚5的方向(输入/输出)控制位

.equ    DDA4      =4        ;引脚4的方向(输入/输出)控制位

.equ    DDA3      =3        ;引脚3的方向(输入/输出)控制位

.equ    DDA2      =2        ;引脚2的方向(输入/输出)控制位

.equ    DDA1      =1        ;引脚1的方向(输入/输出)控制位

.equ    DDA0      =0        ;引脚0的方向(输入/输出)控制位



; PINA —— 端口A输入引脚地址

.equ    PINA7     =7

.equ    PINA6     =6

.equ    PINA5     =5

.equ    PINA4     =4

.equ    PINA3     =3

.equ    PINA2     =2

.equ    PINA1     =1

.equ    PINA0     =0



; PORTB —— 端口B数据寄存器

.equ    PB7       =7

.equ    PB6       =6

.equ    PB5       =5

.equ    PB4       =4

.equ    PB3       =3

.equ    PB2       =2

.equ    PB1       =1

.equ    PB0       =0



; DDRB —— 端口B数据方向寄存器

.equ    DDB7      =7        ;引脚7的方向(输入/输出)控制位

.equ    DDB6      =6        ;引脚6的方向(输入/输出)控制位

.equ    DDB5      =5        ;引脚5的方向(输入/输出)控制位

.equ    DDB4      =4        ;引脚4的方向(输入/输出)控制位

.equ    DDB3      =3        ;引脚3的方向(输入/输出)控制位

.equ    DDB2      =2        ;引脚2的方向(输入/输出)控制位

.equ    DDB1      =1        ;引脚1的方向(输入/输出)控制位

.equ    DDB0      =0        ;引脚0的方向(输入/输出)控制位



; PINB —— 端口B输入引脚地址

.equ    PINB7     =7

.equ    PINB6     =6

.equ    PINB5     =5

.equ    PINB4     =4

.equ    PINB3     =3

.equ    PINB2     =2

.equ    PINB1     =1

.equ    PINB0     =0



; PORTC —— 端口C数据寄存器

.equ    PC7       =7

.equ    PC6       =6

.equ    PC5       =5

.equ    PC4       =4

.equ    PC3       =3

.equ    PC2       =2

.equ    PC1       =1

.equ    PC0       =0



; DDRC —— 端口C数据方向寄存器

.equ    DDC7      =7        ;引脚7的方向(输入/输出)控制位

.equ    DDC6      =6        ;引脚6的方向(输入/输出)控制位

.equ    DDC5      =5        ;引脚5的方向(输入/输出)控制位

.equ    DDC4      =4        ;引脚4的方向(输入/输出)控制位

.equ    DDC3      =3        ;引脚3的方向(输入/输出)控制位

.equ    DDC2      =2        ;引脚2的方向(输入/输出)控制位

.equ    DDC1      =1        ;引脚1的方向(输入/输出)控制位

.equ    DDC0      =0        ;引脚0的方向(输入/输出)控制位



; PINC —— 端口C输入引脚地址

.equ    PINC7     =7

.equ    PINC6     =6

.equ    PINC5     =5

.equ    PINC4     =4

.equ    PINC3     =3

.equ    PINC2     =2

.equ    PINC1     =1

.equ    PINC0     =0



; PORTD —— 端口D数据寄存器

.equ    PD7       =7

.equ    PD6       =6

.equ    PD5       =5

.equ    PD4       =4

.equ    PD3       =3

.equ    PD2       =2

.equ    PD1       =1

.equ    PD0       =0



; DDRD —— 端口D数据方向寄存器

.equ    DDD7      =7        ;引脚7的方向(输入/输出)控制位

.equ    DDD6      =6        ;引脚6的方向(输入/输出)控制位

.equ    DDD5      =5        ;引脚5的方向(输入/输出)控制位

.equ    DDD4      =4        ;引脚4的方向(输入/输出)控制位

.equ    DDD3      =3        ;引脚3的方向(输入/输出)控制位

.equ    DDD2      =2        ;引脚2的方向(输入/输出)控制位

.equ    DDD1      =1        ;引脚1的方向(输入/输出)控制位

.equ    DDD0      =0        ;引脚0的方向(输入/输出)控制位



; PIND —— 端口D输入引脚地址

.equ    PIND7     =7

.equ    PIND6     =6

.equ    PIND5     =5

.equ    PIND4     =4

.equ    PIND3     =3

.equ    PIND2     =2

.equ    PIND1     =1

.equ    PIND0     =0



; SPSR —— SPI状态寄存器

.equ    SPIF      =7        ;SPI中断标志位

.equ    WCOL      =6        ;写碰撞标志

.equ    SPI2X     =0        ;SPI倍速



; SPCR —— SPI控制寄存器

.equ    SPIE      =7        ;SPI中断使能位

.equ    SPE       =6        ;使能SPI

.equ    DORD      =5        ;发送数据次序(LSB/MSB字节先后顺序)

.equ    MSTR      =4        ;主/从机模式选择

.equ    CPOL      =3        ;时钟极性控制位

.equ    CPHA      =2        ;时钟相位控制位

.equ    SPR1      =1        ;SPI时钟速率选择控制位1

.equ    SPR0      =0        ;SPI时钟速率选择控制位0



; UCSRA —— USART控制和状态寄存器A

.equ    RXC       =7        ;USART接收结束

.equ    TXC       =6        ;USART发送结束

.equ    UDRE      =5        ;USART数据寄存器空

.equ    FE        =4        ;帧错误

;.equ    OR        =3         ;数据溢出

.equ    DOR       =3        ;数据溢出( OR 的新名称)

.equ    PE        =2        ;奇偶校验错误

.equ    U2X       =1        ;倍速发送

.equ    MPCM      =0        ;多处理器通信模式



; UCSRB —— USART控制和状态寄存器B

.equ    RXCIE     =7        ;接收结束中断使能位

.equ    TXCIE     =6        ;发送结束中断使能位

.equ    UDRIE     =5        ;数据寄存器空中断使能位

.equ    RXEN      =4        ;接收使能位

.equ    TXEN      =3        ;发送使能位

.equ    CHR9      =2         ;字符长度

.equ    UCSZ2     =2        ;字符长度控制位2( CHR9 的新名称)

.equ    RXB8      =1        ;接收数据位8(接收数据的第9个数据位)

.equ    TXB8      =0        ;发送数据位8(发送数据的第9个数据位)



;UCSRC —— USART控制和状态寄存器C

.equ    URSEL     =7        ;寄存器选择控制位

.equ    UMSEL     =6        ;USART模式选择控制位

.equ    UPM1      =5        ;奇偶校验模式选择控制位1

.equ    UPM0      =4        ;奇偶校验模式选择控制位0

.equ    USBS      =3        ;停止位的位数选择控制位

.equ    UCSZ1     =2        ;字符长度控制位1

.equ    UCSZ0     =1        ;字符长度控制位0

.equ    UCPOL     =0        ;时钟极性控制位



; ACSR —— 模拟比较器控制和状态寄存器

.equ    ACD       =7        ;模拟比较器禁用

.equ    ACBG      =6        ;模拟比较器的能隙基准源选择控制位

.equ    ACO       =5        ;模拟比较器输出

.equ    ACI       =4        ;模拟比较器中断标志位

.equ    ACIE      =3        ;模拟比较器中断使能位

.equ    ACIC      =2        ;模拟比较器输入捕捉使能位

.equ    ACIS1     =1        ;模拟比较器中断模式选择控制位1

.equ    ACIS0     =0        ;模拟比较器中断模式选择控制位0



; ADMUX —— ADC多路选择寄存器

.equ    REFS1     =7        ;参考电压选择控制位1

.equ    REFS0     =6        ;参考电压选择控制位0

.equ    ADLAR     =5        ;ADC转换结果数据存放形式控制位(左/右对齐)

.equ    MUX4      =4        ;模拟通道与增益选择控制位4

.equ    MUX3      =3        ;模拟通道与增益选择控制位3

.equ    MUX2      =2        ;模拟通道与增益选择控制位2

.equ    MUX1      =1        ;模拟通道与增益选择控制位1

.equ    MUX0      =0        ;模拟通道与增益选择控制位0



; ADCSR —— ADC控制和状态寄存器

.equ    ADEN      =7        ;ADC使能位

.equ    ADSC      =6        ;ADC开始转换

.equ    ADFR      =5        ;ADC自动触发使能位

.equ    ADATE     =5         ;ADC自动触发使能位

.equ    ADIF      =4        ;ADC中断标志位

.equ    ADIE      =3        ;ADC中断使能位

.equ    ADPS2     =2        ;ADC预分频器选择控制位2

.equ    ADPS1     =1        ;ADC预分频器选择控制位1

.equ    ADPS0     =0        ;ADC预分频器选择控制位0



; TWAR —— TWI(从机)地址寄存器

.equ    TWGCE     =0        ;TWI广播识别使能位





;******** 指针寄存器定义:



.def    XL        =r26      ;X指针寄存器低字节

.def    XH        =r27      ;X指针寄存器高字节

.def    YL        =r28      ;Y指针寄存器低字节

.def    YH        =r29      ;Y指针寄存器高字节

.def    ZL        =r30      ;Z指针寄存器低字节

.def    ZH        =r31      ;Z指针寄存器高字节





;******** 片内存储器空间定义:



.equ    FLASHEND  =$1fff    ;程序存储器最大地址数【8K×16位字长】(Flash Memory)

.equ    E2END     =$1ff     ;电可擦除只读存储器最大地址数【512×8位字长】(EEPROM)

.equ    RAMEND    =$45f     ;数据存储器最大地址数【8位字长】(SRAM)

                            ;(1K随机存储器+64个I/O寄存器+32个通用寄存器)





;******** 引导程序区空间定义:



;                          byte groups

;                          /\/--\/--\/--\

.equ    BOOTSTART       =$1e00            ;此定义已经不再使用!为保持兼容性暂时保留

;.equ    LARGEBOOTSTART  =$0c00            ;最大引导程序区大小为 2KB

;.equ    SMALLBOOTSTART  =$0f80            ;最小引导程序区大小为 256B

.equ    SMALLBOOTSTART  =0b1111110000000  ;($1F80)最小引导程序区大小为 256B(2页)

.equ    SECONDBOOTSTART =0b1111100000000  ;($1F00)第二引导程序区大小为 512B(4页)

.equ    THIRDBOOTSTART  =0b1111000000000  ;($1E00)第三引导程序区大小为 1KB(8页)

.equ    LARGEBOOTSTART  =0b1110000000000  ;($1C00)最大引导程序区大小为 2KB(16页)





;******** 页字数定义:



.equ    PAGESIZE        =64                ;每页的字数为 64【16位字长】





;******** 中断向量地址定义:



.equ    INT0addr  =$002     ;外部中断请求0向量地址

.equ    INT1addr  =$004     ;外部中断请求1向量地址

.equ    OC2addr   =$006     ;定时器/计数器2比较匹配中断向量地址

.equ    OVF2addr  =$008     ;定时器/计数器2溢出中断向量地址

.equ    ICP1addr  =$00a     ;定时器/计数器1输入捕获中断向量地址

.equ    OC1Aaddr  =$00c     ;定时器/计数器1A比较匹配中断向量地址

.equ    OC1Baddr  =$00e     ;定时器/计数器1B比较匹配中断向量地址

.equ    OVF1addr  =$010     ;定时器/计数器1溢出中断向量地址

.equ    OVF0addr  =$012     ;定时器/计数器0溢出中断向量地址

.equ    SPIaddr   =$014     ;SPI串行传输结束中断向量地址

.equ    URXCaddr  =$016     ;USART接收结束中断向量地址

.equ    UDREaddr  =$018     ;USART数据寄存器空中断向量地址

.equ    UTXCaddr  =$01a     ;USART传送结束中断向量地址

.equ    ADCCaddr  =$01c     ;ADC转换结束中断向量地址

.equ    ERDYaddr  =$01e     ;EEPROM就绪中断向量地址

.equ    ACIaddr   =$020     ;模拟比较器中断向量地址

.equ    TWIaddr   =$022     ;两线串行接口中断向量地址

.equ    INT2addr  =$024     ;外部中断请求2向量地址

.equ    OC0addr   =$026     ;定时器/计数器0比较匹配中断向量地址

.equ    SPMRaddr  =$028     ;保存程序存储器内容就绪中断向量地址





;★★★★★ 定义文件结束!!! ★★★★★

出0入0汤圆

发表于 2005-3-22 08:36:05 | 显示全部楼层
佩服啊,AVR我还从没用纯汇编写过呢!

出0入0汤圆

发表于 2005-3-22 10:28:05 | 显示全部楼层
佩服!!我目前也用匯編編寫,但我比較菜

出0入0汤圆

发表于 2005-3-26 12:48:44 | 显示全部楼层
真功夫啊



在程序中我有些地方不明白还请您或其它高手们指点:

如:在USART_RXCINT子程中

lds ZL,USARTAI_RXAPL            ;置接收作业地址指针

    lds ZH,USARTAI_RXAPH

    in USARTAI_TEMP,UDR             ;从 USART 数据寄存器取出接收数据

    st Z,USARTAI_TEMP                 ;存储进 SRAM 中

    adiw ZL,$01                     ;接收作业地址指针 + 1  

    sts USARTAI_RXAPL,ZL              ;存储回 SRAM 中

    sts USARTAI_RXAPH,ZH



请问“in USARTAI_TEMP,UDR             ;从 USART 数据寄存器取出接收数据

    st Z,USARTAI_TEMP                 ;存储进 SRAM 中

”不是将UDR取出接收数据,放置在USARTAI_RXAPL和USARTAI_RXAPH吗?

而后存回SRAM的是不是加1后的USARTAI_RXAPL和USARTAI_RXAPH两地址,所存放在SRAM中的位置是不是仍然在USARTAI_RXAPL和USARTAI_RXAPH; 那不是要将UDR取出接收数据覆盖掉吗
-----此内容被huai903于2005-03-27,01:24:34编辑过

出0入0汤圆

发表于 2005-3-26 17:02:17 | 显示全部楼层
重新拜读此程序,我是初手;借用您的程序书写方式,达到汇编的可读性与规范性,学习您的编程思考方法,进一步提高自己考虑问题的周全性,丰富自己的编程经验和技巧。
-----此内容被huai903于2005-03-27,08:48:36编辑过

出0入0汤圆

发表于 2005-3-27 21:21:52 | 显示全部楼层
写EEProm中有1 bug

例如:

   调用 EEPROM_WriteSingle 前,全局中断是关闭的

   EEPROM_WriteSingle 完成后全局中断是打开的

   在某些应用中会导致全局中断非法打开

出0入0汤圆

 楼主| 发表于 2005-3-28 21:26:09 | 显示全部楼层
回 huai903 的问题:

   将UDR取出接收数据,放置在USARTAI_RXAPL和USARTAI_RXAPH这两个地址指针指向的SRAM中,USARTAI_RXAPL和USARTAI_RXAPH是用来存储Z指针本身的值,不是其指向的SRAM。如Z指针指向$0100,那么USARTAI_RXAPL=$00:USARTAI_RXAPH=$01,而UDR取出的数据存在地址为$0100的SRAM中。

-----此内容被LYStudio于2005-04-02,01:05:11编辑过


-----此内容被LYStudio于2005-04-02,01:05:27编辑过

出0入0汤圆

 楼主| 发表于 2005-3-28 21:35:09 | 显示全部楼层
leon101010 ARC的蜈蚣:

    谢谢您指出的问题,这确实是我不注意细节的疏忽。解决此问题的方法将状态寄存器入栈保护后取消 SEI 指令即可。再次谢谢您!

    另外我所写的程序较冗长,有些可以删去,此是为程序可靠性多增加的。

出0入0汤圆

发表于 2005-4-8 22:48:33 | 显示全部楼层
LYStudio 磊元大哥,你有沒有LCDM模塊/鍵盤(按鍵)的子程式.TKS!!

出0入0汤圆

 楼主| 发表于 2005-4-9 02:48:42 | 显示全部楼层
有LCDM模塊/鍵盤(按鍵)的子程序,其中LCDM模塊为较早编程,水平不高,我正唯备直写。LCDM模塊的控制芯片为HD61202/3,128*64点阵。

出0入0汤圆

发表于 2005-12-7 11:46:22 | 显示全部楼层
好贴!太感谢楼主了!收藏!!

出0入0汤圆

发表于 2005-12-7 17:55:54 | 显示全部楼层
厉害,特别是每一条都注释了,厉害厉害,PFPF!!!!

出0入0汤圆

发表于 2005-12-7 23:24:05 | 显示全部楼层
经典...如果我有此精力,肯定搞个汇编宏玩玩...就如同书写C一样方便,但确是用汇编写的.

出0入0汤圆

发表于 2006-1-23 12:22:28 | 显示全部楼层
佩服啊,LYStudio 磊元大哥,

出0入0汤圆

发表于 2006-2-9 22:59:13 | 显示全部楼层
这么好的一个贴,建议阿莫将它置顶!今天我找了好久,才重新找到!

出0入0汤圆

发表于 2006-3-12 21:33:09 | 显示全部楼层
感谢,本人正在学习中,用处很大,收了.

出0入0汤圆

发表于 2006-6-15 10:12:15 | 显示全部楼层
请问磊元大哥,AVR中的位是怎样定义的,而51就是很方便:如

FLG1    BIT     00H

FLG2    BIT     01H

或者是

FLG1    =       00H

FLG2    =       01H

或者是

FLG1    BIT     20H.0

FLG2    BIT     20H.1

或者是

FLG1    =       20H.0

FLG2    =       20H.1

出0入0汤圆

发表于 2006-6-21 11:04:01 | 显示全部楼层
顶~~

出0入0汤圆

发表于 2006-8-24 11:14:42 | 显示全部楼层
DDDDDDDD

楼主要是把硬件也贴出来就更好了

出0入211汤圆

发表于 2007-3-27 13:33:35 | 显示全部楼层
ldi ZL,Low(ChangeDeviceNumber_XXXX*2)

ldi ZH,High(ChangeDeviceNumber_XXXX*2)

为什么后面都要*2啊!不明白阿!

出0入0汤圆

发表于 2007-4-1 12:57:28 | 显示全部楼层
LYStudio 磊元大哥神啊!这么复杂的程序用汇编写.

佩服!佩服!

出0入0汤圆

发表于 2007-12-27 10:17:03 | 显示全部楼层
强贴,强顶!希望能有更多的汇编例程供大家学习。

出0入0汤圆

发表于 2007-12-27 10:28:34 | 显示全部楼层
好强悍的汇编,不顶不行...

出10入95汤圆

发表于 2007-12-29 17:15:49 | 显示全部楼层
楼主厉害啊,佩服啊!

出0入0汤圆

发表于 2008-4-7 16:04:17 | 显示全部楼层
不顶不行,阿莫应该也来灌几桶

出0入0汤圆

发表于 2009-9-2 15:14:00 | 显示全部楼层
太谢谢楼主了,学习中!!!

出0入0汤圆

发表于 2010-6-19 10:57:01 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-6-19 15:50:29 | 显示全部楼层
谢谢贡献,学习了

出0入0汤圆

发表于 2010-9-30 09:14:01 | 显示全部楼层
厉害!顶
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-7 15:12

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表