;//*****************************************************   
;//Copyright (c) 2025, 苏州华芯微电子股份有限公司
;//All rights reserved                                 
;//
;//文件名称: HS16F1886-IIC
;//摘    要: IIC通讯协议，对AT24C02进行读写数据操作
;//  	    对AT24C02的0X00地址写入0XFA; 读取0X00地址的数据是否是0XFA;如果是则PB2脚输出一个10MS的脉冲信号.
;//
;//当前版本: 1.0                                      
;//作    者: 华芯微MCU组
;//完成日期: 2025.06.20
;//*****************************************************   

;***********************************************************
;files include
#include "HS16P1886.inc"

;A		EQU	0x0
;R		EQU	0x1
;***********************************************************
;用户IO定义

#define		SDA		PORTB,0
#define		SCL		PORTB,1
#define		LED1	PORTB,2    ;



;***********************************************************
;通用寄存器定义
DELAY_US		EQU		040H
DELAY_MS_CNT	EQU		041H
FREG1			EQU		042H
I2C_COUNT		EQU		043H
I2C_DATA		EQU		044H
E2_ADDR			EQU		045H
CONTINUE_CNT	EQU		046H
LCODE_E2        EQU     047H
MCODE_E2        EQU     048H
HCODE_E2        EQU     049H
CS_DATA         EQU     04AH
DELAY_OUTSIDE	EQU		04BH
DELAY_INSIDE	EQU		04CH



STATUS_BUF	    EQU		07EH;中断保护寄存器必须放 0x70-0x7F不要动！！！
ACC_BUF		    EQU		07FH;中断保护寄存器必须放 0x70-0x7F不要动！！！

;===================================
;位定义
#define	F_ACK		  FREG1,0
#define	F_CS_OK		  FREG1,1

;==================================
;常量定义
;==================================
SDA_OUTPUT      EQU     000H                                  
SDA_INPUT       EQU     001H 



;***********************************************************
;/函数入口地址
	ORG	00H
	NOP
	NOP
	GOTO	MAIN_SETUP
;***********************************************************
;/中断入口地址04H
	ORG	04H
	GOTO	INT_PRO
INT_PRO:	
	MOVAR	ACC_BUF		;保存ACC
	SWAPR	STATUS,0
	MOVAR	STATUS_BUF	;保存STATUS
	BCR		STATUS,5   ;切换到BANK0	
	BCR		STATUS,6
	
	
;------------------------------------------------
;           空
;------------------------------------------------
INT_BACK:   ;中断返回	
	SWAPR	STATUS_BUF,0
	MOVAR	STATUS		;恢复STATUS
	SWAPR	ACC_BUF,1
	SWAPR	ACC_BUF,0	;恢复ACC
	RETFIE
;//中断代码结束
;==========================================================================
;初始化设置
MAIN_SETUP:
	CALL	SYS_CPIO_INIT	;系统寄存器和GPIO配置
	CALL	CLR_ALL_RAM  	;清所有ram
	CALL	WDT_Init     	;看门狗初始化
	CLRWDT					;清看门狗
	BCR		STATUS,5		;保证转到bank0/2再操作PORTB
	BCR		STATUS,6
	
	
	
	MOVIA	0XFA	
	MOVAR	CS_DATA   ;写入的数据
	MOVIA	0X00
	MOVAR   E2_ADDR   ;要写的EE地址
    MOVIA   001H                                        
    MOVAR   CONTINUE_CNT  ;连续写几个字节数据         
    MOVIA   CS_DATA       ;如果是连续写时，该数据为要写入数据的首字节   
    MOVAR   FSR
    CALL    WRITE_E2  
	
	
;==============================================================
;==============================================================	
MAIN: ;主循环
	CLRWDT	
	;MOVIA	200
    ;CALL	DELAY_MS
	
	
;=======写一个字节:把0XFA写入到0X00地址==================================	
	
;----------------------------------
	CLRR	CS_DATA
;=======读一个字节:读取0X00地址内的数据==================================	
	MOVIA	0X00
	MOVAR   E2_ADDR    ;要读取的数据EE地址
    MOVIA   001H                    
    MOVAR   CONTINUE_CNT   ;连续读取一个字节数据
    MOVIA   CS_DATA         ;如果是连续读时，该数据为要存放读取数据的首地址  
    MOVAR   FSR               
    CALL    READ_E2   
        
    MOVIA	0XFA
    XORAR	CS_DATA,A     ;判断读取的数据是否是  0XFA
    BTRSS	Z	
    GOTO	CS_NO_EQU		 
CS_YES_EQU :   ;读写数据验证正确,  PB0口输出10MS的高电平 
    BSR		F_CS_OK
    BSR		LED1
    MOVIA	10
    CALL	DELAY_MS
    BCR		LED1
    MOVIA	10
    CALL	DELAY_MS	
    GOTO	CS_EE_END
CS_NO_EQU:  ;  读写数据验证失败   
    BCR		F_CS_OK
   	GOTO	CS_EE_END 
CS_EE_END:

	GOTO	MAIN		

;========================================================
;***********************************************************
;函数名：I2C_START
;功能：  IIC起始信号
;***********************************************************
I2C_START: ;起始信号
        ;CALL    SDA_OUT_SET
        BSR		STATUS,5
		BCR		STATUS,6
		MOVIA   SDA_OUTPUT 
        MOVAR	TRISB             
		BCR		STATUS,5
		BCR		STATUS,6
        CALL    DELAY_2US
        BSR     SDA                 ;SDA = 1
        CALL    DELAY_2US
        BSR     SCL                ;SCL = 1
        CALL    DELAY_2US
        BCR     SDA                ;SDA = 0
        CALL    DELAY_2US
        BCR     SCL                ;SCL = 0
        CALL    DELAY_2US       
        RETURN                         ;      
;***********************************************************  
;函数名：I2C_STOP
;功能：  IIC停止信号
;***********************************************************
 I2C_STOP:  
        ;CALL	SDA_OUT_SET
        BSR		STATUS,5
		BCR		STATUS,6
		MOVIA   SDA_OUTPUT 
        MOVAR	TRISB             
		BCR		STATUS,5
		BCR		STATUS,6
        BCR     SDA                ;SDA = 0
        CALL    DELAY_2US
        BSR     SCL                ;SCL = 1
        CALL    DELAY_2US
        BSR     SDA                ;SDA = 1
        CALL    DELAY_2US
        CALL    DELAY_2US
        BCR     SCL                ;SCL = 0,
        CALL    DELAY_2US
        BCR     SCL                ;SCL = 0,
        CALL    DELAY_2US
        ;CALL	SDA_IN_SET
        BSR		STATUS,5
		BCR		STATUS,6
		MOVIA   SDA_INPUT 
        MOVAR	TRISB             
		BCR		STATUS,5
		BCR		STATUS,6
        RETURN                       
;----------------------------------------------------   

;-------------------------------------------------  
;***********************************************************   
;函数名：I2C_NOACK
;功能：  IIC非应答信号
;*********************************************************** 
I2C_NOACK:  	
        BSR     SDA
        CALL    DELAY_2US
        BSR     SCL
        CALL    DELAY_2US
        BCR     SCL
        CALL    DELAY_2US
        RETURN    
   
;------------------------------------------------------
;***********************************************************   
;函数名：CLOCK_SYN
;功能：  IIC应答信号
;***********************************************************
CLOCK_SYN: ;应答
        ;CALL	SDA_OUT_SET  
        BSR		STATUS,5
		BCR		STATUS,6
		MOVIA   SDA_OUTPUT 
        MOVAR	TRISB             
		BCR		STATUS,5
		BCR		STATUS,6
        BCR     SDA
        CALL    DELAY_2US
        BSR     SCL             
        CALL    DELAY_2US                     
        BCR     SCL             
        GOTO    READ_E2_PAGE_LOOP
;----------------------------------------   
;***************************************************************
;函数名：I2C_READBYTE
;传参：  I2C_DATA：SDA读取的一个字节数据       
;返回值：无
;功能：;读一个字节数据
;引脚：
;备注：
;*********************************************************** 
I2C_READBYTE: ;读一个字节
        ;CALL	SDA_IN_SET
        BSR		STATUS,5
		BCR		STATUS,6
		MOVIA   SDA_INPUT 
        MOVAR	TRISB             
		BCR		STATUS,5
		BCR		STATUS,6
        MOVIA   8
        MOVAR   I2C_COUNT
        CLRR    I2C_DATA

I2C_READBYTE_LOOP:
        RLR     I2C_DATA,R
        BCR     I2C_DATA,0
I2C_BITIN:
        BSR     SDA
        BSR     SCL
        CALL    DELAY_2US
I2C_BIT1:   
        BCR     C
        BTRSC   SDA
        BSR     C     
        BCR     SCL
        CALL    DELAY_2US
        BTRSC   C
        BSR     I2C_DATA,0
        DECRSZ  I2C_COUNT,R
        GOTO    I2C_READBYTE_LOOP
SET_SDA_OUTPUT:
		BSR		STATUS,5
		BCR		STATUS,6
		MOVIA   SDA_OUTPUT 
        MOVAR	TRISB             
		BCR		STATUS,5
		BCR		STATUS,6
        ;CALL	SDA_OUT_SET                 
        RETURN
;***************************************************************
;函数名：I2C_WRITEBYTE
;传参：  I2C_DATA：SDA输出的一个字节数据       
;返回值：无
;功能：;写一个字节数据
;引脚：
;备注：
;*********************************************************** 
I2C_WRITEBYTE:  ;发送一个字节
        MOVIA   8
        MOVAR   I2C_COUNT
I2C_WRITEBYTE_ON:
        RLR     I2C_DATA,R        ;要写入的数据
        BTRSS   C                ;按位写入
        GOTO    WRITE_BIT0
WRITE_BIT1:
        BSR     SDA                ;当前位为1, SDA = 1
        GOTO    SET_BIT_END
WRITE_BIT0:
        BCR     SDA                ;当前位为0, SDA = 0
SET_BIT_END:        
        CALL    DELAY_2US
        BSR     SCL                ;SCL = 1
        CALL    DELAY_2US
        BCR     SCL                ;SCL = 0                                                    
        DECRSZ  I2C_COUNT,R     ;写8次      
        GOTO    I2C_WRITEBYTE_ON   
;***********************************************************   
;函数名：I2C_TESTACK
;功能：  IIC等待应答
;***********************************************************   
I2C_TESTACK:  ;等待应答
        ;CALL	SDA_IN_SET
        BSR		STATUS,5
		BCR		STATUS,6
		MOVIA   SDA_INPUT 
        MOVAR	TRISB             
		BCR		STATUS,5
		BCR		STATUS,6
        BSR     SCL                                         
        CALL    DELAY_2US
        BCR     F_ACK
        BTRSS   SDA
        BSR     F_ACK                ;SDA为低电平,表示有应答,应答标志位F_ACK 置1
        BCR     SCL                ;SCL = 0      
        CALL    DELAY_2US
        BSR		STATUS,5
		BCR		STATUS,6
		MOVIA   SDA_OUTPUT 
        MOVAR	TRISB             
		BCR		STATUS,5
		BCR		STATUS,6
        ;CALL	SDA_OUT_SET
        RETURN
;==================================================
;***********************************************************
;函数名：WRITE_E2
;传参：  E2_ADDR:存储数据的EE起始地址
;        CONTINUE_CNT:连续读取几个字节数据
;        FSR:间接寻址，该映射地址为要写入的数据首字节数据地址 
;返回值：无
;功能：;连续写入数据
;引脚：
;备注：
;***********************************************************
WRITE_E2:  ;连续写数据
        CALL    I2C_START                
        MOVIA   0A0H                        
                                                                
        MOVAR   I2C_DATA
        CALL    I2C_WRITEBYTE                ;将A0H写入E2中(表示MCU将写入数据到E2中)
        
        BTRSS   F_ACK
        GOTO    WRITE_E2_PAGE_END 

        MOVR    E2_ADDR,A               ;起始地址
        MOVAR   I2C_DATA
        CALL    I2C_WRITEBYTE        
        BTRSS   F_ACK
        GOTO    WRITE_E2_PAGE_END 
;页写循环        
WRITE_E2_PAGE_LOOP:
        MOVR    INDF,A
        MOVAR   I2C_DATA
        CALL    I2C_WRITEBYTE        
        BTRSS   F_ACK
        GOTO    WRITE_E2_PAGE_END 
        INCR    FSR,R                   ;指向下一个地址单元
        DECRSZ  CONTINUE_CNT,R          ;判断是否结束
        GOTO    WRITE_E2_PAGE_LOOP
        
WRITE_E2_PAGE_END:
        CALL    I2C_STOP
        MOVIA   10
        CALL    DELAY_MS
        RETURN
  
;=========================================  
;***********************************************************
;函数名：READ_E2
;传参：  E2_ADDR:读取EE数据的EE起始地址
;        CONTINUE_CNT:连续读取几个字节数据
;        FSR:间接寻址，该映射地址为存储读取存放数据的首地址
;返回值：无
;功能：;连续读取数据
;引脚：
;备注：
;***********************************************************
READ_E2:    
        CALL    I2C_START       
        MOVIA   0A0H
        MOVAR   I2C_DATA
        CALL    I2C_WRITEBYTE                ;向E2写A0(表示MCU将要写数据(地址或者数据)到E2)
        BTRSS   F_ACK                        
        GOTO    READ_E2_PAGE_END                

        MOVR    E2_ADDR,A
        MOVAR   I2C_DATA
        CALL    I2C_WRITEBYTE           ;向E2发送将要读取的字节的地址
        BTRSS   F_ACK
        GOTO    READ_E2_PAGE_END

        CALL    I2C_START
        MOVIA   0A1H
        MOVAR   I2C_DATA
        CALL    I2C_WRITEBYTE                ;
        BTRSS   F_ACK
        GOTO    READ_E2_PAGE_END
READ_E2_PAGE_LOOP:
        CALL    I2C_READBYTE
        MOVR    I2C_DATA,A              
        MOVAR   INDF    
        INCR    FSR,R
        DECRSZ  CONTINUE_CNT,R          ;判断是否结束
        GOTO    CLOCK_SYN               ;第九个同步时钟
READ_E2_PAGE_END:
        CALL    I2C_STOP
        RETURN
  
   
;===============================================================
;***********************************************************
;函数名：SDA_OUT_SET
;传参：
;返回值：
;功能：SDA设置为输出
;引脚：
;备注：
;***********************************************************
SDA_OUT_SET:  ;
		BSR		STATUS,5
		BCR		STATUS,6
		MOVIA   SDA_OUTPUT 
        MOVAR	TRISB             
		BCR		STATUS,5
		BCR		STATUS,6
		RETURN
;***********************************************************
;函数名：SDA_IN_SET
;传参：
;返回值：
;功能：SDA设置为输入
;引脚：
;备注：
;***********************************************************
SDA_IN_SET:   ;SDA设置为输入
		BSR		STATUS,5
		BCR		STATUS,6
		MOVIA   SDA_INPUT 
        MOVAR	TRISB             
		BCR		STATUS,5
		BCR		STATUS,6
		RETURN
		
	
;====================================
;***********************************************************
;函数名：SYS_CPIO_INIT
;注意寄存器所在 bank 区域
;***********************************************************
SYS_CPIO_INIT:
	BSR		STATUS,5	;转到bank1
	BCR		STATUS,6
	;OPTION_REG(BANK1)
	MOVIA	00CH		;0000 1100
	MOVAR	OPTION_REG	
			;Bit7：INT1EDG：外部中断1触发方式选择位（PB1）;0-falling edge, 1-rising edge
			;Bit6：INTEDG：外部中断触发方式选择位（PB0）	;0-falling edge, 1-rising edge
			

	;PCON(BANK1)(芯片控制寄存器)
	MOVIA	0A0H	;101- ----   	
	MOVAR	PCON	;Bit7：WDTE: WDT（看门狗定时器）使能位	;0-DIS, 1-EN
					
					;Bit5：LVREN: 低电压复位使能位			;0-DIS, 1-EN
	
	;TRISB(BANK1)(I/O口PB控制寄存器)
	MOVIA	01H			;--00 0001 :PORTB输入输出配置寄存器 (0-OUT;1-IN) 
	MOVAR	TRISB		;0-OUT, 1-IN
	
	;WUCON(BANK1)(PORB输入状态变化中断/唤醒控制寄存器)
	MOVIA	00H			;--00 0000 :PORTB变化中断唤醒寄存器 (1-EN;0=DIS)
	MOVAR	WUCON		;0-DIS, 1-EN
	
		;PBIC0(BANK1)(PORB驱动低电平控制寄存器)
		MOVIA	00H			;--00 0000 :
		MOVAR	PBIC0		;0-DIS, 1-EN
        
		;XTCON(BANK1)(外振模式控制寄存器)
		;MOVIA	00H			;--00 0000 :
		;MOVAR	XTCON		;与config同时有效，外振才生效
				;bit5: XTSEN1：外振软件增强使能位 1（与上位机配置共同控制） 0-en;1-dis
				;bit4: XTSEN0：外振软件增强使能位 0（与上位机配置共同控制） 0-en;1-dis
				;bit3: XTEN：外振软件使能位（与上位机配置共同控制）		 0-en;1-dis
				;bit2: XT_TC0S：TC0 低速时钟选择		0-内部低速时钟；1-外部32.768K 
				;bit1: XT_LRCS：低速模式系统时钟选择	0-dis ; 1-EN
				;bit0:	XT_MONE：外振监测使能
	
	BCR		STATUS,5	;转到bank0
	BCR		STATUS,6
	;PDCON(BANK0)(内部下拉控制寄存器)
	MOVIA	0FFH		;---- --11 :bit3:0 PORTA3:0下拉寄存器; bit7:4 PORTB3:0下拉寄存器;1-DIS;0-EN
	MOVAR	PDCON		;0-EN, 1-DIS	
	
	;ODCON(BANK0)(PB漏极开路控制寄存器)
	MOVIA	00H			;--00 0000 :PORTB开漏寄存器 (1-EN;0-DIS)
	MOVAR	ODCON		;0-DIS, 1-EN
	
	;PHCON(BANK0)(PB 内部上拉控制寄存器)
	MOVIA	0FCH		;--11 0011 :PORTB上拉寄存器 (1-DIS;0-EN)
	MOVAR	PHCON		;0-EN, 1-DIS
	
		;DRVC0(BANK0)(PB0 端口大驱动控制寄存器)
		MOVIA	0FFH		;---- -000 :
		MOVAR	DRVC0		;0-EN, 1-DIS
		
		;DRVC1(BANK0)(PB1 端口大驱动控制寄存器)
		MOVIA	0FFH		;---- -000 :
		MOVAR	DRVC1		;0-EN, 1-DIS
		
		;DRVC2(BANK0)(PB2 端口大驱动控制寄存器)
		MOVIA	0FFH		;---- -000 :
		MOVAR	DRVC2		;0-EN, 1-DIS
	
	RETURN
	
;***********************************************************
;函数名：BANK0_RAM_CLR
;***********************************************************
CLR_ALL_RAM:
	MOVIA	0X3F
	MOVAR	40H
	MOVIA	0X7F
	MOVAR	FSR
	
RAM_CLR_LOOP:	
	CLRR	INDF
	DECR	FSR,1
	DECRSZ	40H,1
	GOTO	RAM_CLR_LOOP
	RETURN
	
;***********************************************************
;函数名：DELAY
;传参：循环体调用次数
;返回值：
;功能：延时4个指令周期  Fcpu=4M时候延时1us，延时有误差
;引脚：
;备注：
;***********************************************************
DELAY:					
	MOVAR	DELAY_US	
DELAY_LOOP_US:	
	CLRWDT				;1;/清看门狗
	DECRSZ	DELAY_US,1	;1/(2)
	GOTO	DELAY_LOOP_US	;2	
	RETURN		
	
	
;***********************************************************
;函数名：DELAY_MS
;传参：1-255ms
;返回值：
;功能：ms级延时
;引脚：
;备注：
;***********************************************************
DELAY_MS:    
        MOVAR   DELAY_OUTSIDE 
;---------------------------
DELAY_LOOP:
        MOVIA   197
        MOVAR   DELAY_INSIDE
DELAY_LOOP_INSIDE:
        CLRWDT
        GOTO    $+1
        GOTO    $+1
        GOTO    $+1
        GOTO    $+1
        GOTO    $+1
        GOTO    $+1
        GOTO    $+1
        GOTO    $+1
        DECRSZ  DELAY_INSIDE,R
        GOTO    DELAY_LOOP_INSIDE
        DECRSZ  DELAY_OUTSIDE,R
        GOTO    DELAY_LOOP        
DELAY_2US:       
        CLRWDT
        NOP    
        NOP
        NOP	
        NOP	
        NOP	
        RETURN 
;***********************************************************
;函数名：WDT_Init
;***********************************************************
/****WDT overflow reset，have no wakeup funtions****；
则看门狗复位时间仅由烧录配置：288ms；512ms；766ms；1024ms；
*/
WDT_Init:
	CLRWDT
	BSR		STATUS,5	;RP0;转到bank1
	BCR		STATUS,6
	;OPTION_REG(BANK1)
	MOVIA	00CH		;0000 1100
	MOVAR	OPTION_REG	
			;Bit7：INT1EDG：外部中断1触发方式选择位（PB1）;0-falling edge, 1-rising edge
			;Bit6：INTEDG：外部中断触发方式选择位（PB0）	;0-falling edge, 1-rising edge

	;PCON(BANK1)(芯片控制寄存器)
	MOVIA	0A0H	;101- ----   	
	MOVAR	PCON	;Bit7：WDTE: WDT（看门狗定时器）使能位	;0-DIS, 1-EN
					;Bit5：LVREN: 低电压复位使能位			;0-DIS, 1-EN
						
	BCR		STATUS,5	;转到bank0
	BCR		STATUS,6
	RETURN

