;---------------------------------------------------------------------------*
;[IIC.asm]IIC通信程序                                                       *
;本文件包含:                                                                *
;外部函数:                                                                  *
;    (1)IICInit  : IIC模块初始化                                            *
;    (2)IICread1 : MCU从从机读1个字节                                       *
;    (3)IICwrite1: MCU向从机写1个字节                                       *
;    (4)IICreadN : MCU从从机读N个字节                                       *
;    (5)IICwriteN: MCU向从机写N个字节                                       *
;内部函数:                                                                  *
;    (1)SendSignal:在IIC总线上发送起停信号                                  *
;    (2)  Wait    :等待应答或一个字节数据的传送完成                         *
;硬件连接:                                                                  *
;    MCU的IIC接口与从机的IIC接口相连,AW60的IIC模块的引脚SDA1和SCL1分别      *
;    与PTC1和PTC0引脚复用,这两个引脚应分别与从机的IIC模块的SDA和SCL相连     *
;说    明:本文件与具体的芯片型号有关                                        *
;---------------------------------------------------------------------------*

 ;IIC驱动所需的头文件
 INCLUDE 'MC9S08AW60.inc'
 
 ;声明外部函数
 XDEF   IICInit      ;IIC初始化
 XDEF   SendSignal   ;发送开始或停止信号
 XDEF   Wait         ;应答等待
 XDEF   IICread1     ;MCU从从机读1个字节
 XDEF   IICreadN     ;MCU从从机读N个字节
 XDEF   IICwrite1    ;MCU向从机写1个字节
 XDEF   IICwriteN    ;MCU向从机写N个字节 

 ;引用外部变量 
 XREF ReadData
 XREF WriteData

;---------------------------------------------------------------------------*
;函 数 名: IICInit                                                          *
;功能描述: 对IIC模块进行初始化,默认为允许IIC,IIC总线频率 227KHz,禁止:       *
;          IIC中断,从机接收模式,不发送应答信号                              *
;入    口: 无                                                               *
;出    口: 无                                                               *
;堆栈深度: 2                                                                *
;说    明: 该子程序与具体的芯片型号(MC9S08AW60)有关                         *
;---------------------------------------------------------------------------*
IICInit:
    LDA  #%01001100 ;IIC总线频率:227KHz,SDA保持时间:0.55us
          ;||||||||___ICR   
          ;||_________MULT，2分频
    STA  IIC1F
           
    LDA  #$F0
    STA  IIC1A       ;D7-D1位是MCU作为从机时的地址,最低位不使用
    
    LDA  #%10001000    
          ;||||||||___不用
          ;||||||
          ;||||||_____RSTA位
          ;|||||______不发送应答信号
          ;||||_______接收模式
          ;|||________从机模式
          ;||_________禁止IIC中断
          ;|__________使能IIC模块  
    STA IIC1C
   RTS

;---------------------------------------------------------------------------*
;函 数 名: SendSignal                                                       *
;功能描述: 根据需要产生开始或停止信号                                       *
;入    口: X = 要产生的信号,X = 'S'(Start),产生开始信号;                    *
;          X = 'O'(Over),产生停止信号                                       *
;出    口: 无                                                               *
;堆栈深度: 2                                                                *
;说    明: 无                                                               *
;---------------------------------------------------------------------------*
SendSignal:
    CPX #'S'      
    BNE isornotO
    LDA IIC1C
    ORA #$20
    STA IIC1C   ;主机模式选择位MST由0变为1,可以产生开始信号
    BRA SendSignalEnd
isornotO:
    CPX #'O'
    BNE SendSignalEnd
    LDA IIC1C
    AND #%11011111
    STA IIC1C   ;主机模式选择位MST由1变为0,可以产生停止信号
SendSignalEnd:   
   RTS

;---------------------------------------------------------------------------*
;函 数 名: Wait                                                             *
;功能描述: 在时限内,循环检测接收应答标志位,或传送完成标志位,判断MCU是否     *
;          接收到应答信号或一个字节是否已在总线上传送完毕                   *
;入    口: A = 应答要求, A = 'A'(Ack),等待应答;A = 'T'                      *
;          (Transmission),等待一个字节数据传输完成                          *
;出    口: A, A = 0:收到应答信号或一个字节传送完毕; A =1:                   *
;          未到应答信号或一个字节没传送完                                   *                                                *
;堆栈深度: 2 + 3 = 5                                                        *
;说    明: 无                                                               *
;---------------------------------------------------------------------------*
Wait:
    AIS #-3        ;在堆栈区开辟2个字节作临时变量
    STA 3,SP       ;在等不到应答信号时,要能够保持最开始的值
    LDX #$FF   
    STX 1,SP       ;定义查询超时时限
    LDX #0         ;循环变量
    STX 2,SP       ;存放循环变量
Wait_For:    
    LDX 2,SP
    CPX 1,SP
    BHS Wait_For_End
    CMP #'A'       ;检测A中的传递过来的参数 ,等待应答信号
    BNE isornotT
    LDA IIC1S
    AND #$01
    CMP #0
    BNE Wait_For_Once_End
    LDA #0         ;传送完一个字节后,收到了从机的应答信号
    AIS #3
  RTS
isornotT:
    CMP #'T'       ;等待传送完成一个字节信号
    BNE Wait_For_Once_End
    LDA IIC1S
    AND #$02
    CMP #0
    BEQ Wait_For_Once_End
    LDA IIC1S
    ORA #$02  
    STA IIC1S     ;清IICIF标志位
    LDA #0        ;成功发送完一个字节
    AIS #3
  RTS
Wait_For_Once_End:
    LDA 3,SP
    INCX
    STX 2,SP
    BRA Wait_For
Wait_For_End:  
    CPX 1,SP
    BLO Return
    LDA #1       ;超时,没有收到应答信号或发送完一个字节
Return: 
    AIS #3   
  RTS

;---------------------------------------------------------------------------*
;函 数 名: IICread1                                                         *
;功能描述: 从从机读1个字节数据                                              *
;入    口: (1) H = DeviceAddr:设备地址                                      *
;          (2) X = AccessAddr:访问地址                                      *
;出    口: A = 0,成功读一个字节;A = 1,读一个字节失败                        *
;          X : 带回收到的一个字节数据                                       *
;内部调用: SendSignal,Wait                                                  *
;堆栈深度: 2 + 2 + 5 = 9                                                    *
;说    明: 无                                                               *
;---------------------------------------------------------------------------*
IICread1:
   AIS #-2
   STHX 1,SP
   
   LDA IIC1C
   ORA #$10
   STA IIC1C   ;TX = 1,MCU设置为发送模式
   LDX #'S' 
   JSR SendSignal ;发送开始信号
 
   LDA 1,SP
   AND #$FE
   STA IIC1D   ;发送设备地址,并通知从机接收数据    
   
   LDA #'T'
   JSR Wait    ;等待一个字节数据传送完成        
   CMP #1
   BEQ IICread1_End;没有传送成功,读一个字节失败    
   LDA #'A'
   JSR Wait    ;等待从机应答信号        
   CMP #1
   BEQ IICread1_End;没有等到应答信号,读一个字节失败      
   
   LDA 2,SP    ;发送访问地址
   STA IIC1D
   
   LDA #'T'
   JSR Wait    ;等待一个字节数据传送完成        
   CMP #1
   BEQ IICread1_End;没有传送成功,读一个字节失败    
   LDA #'A'
   JSR Wait    ;等待从机应答信号        
   CMP #1
   BEQ IICread1_End;没有等到应答信号,读一个字节失败
   
   LDA IIC1C
   ORA #$04
   STA IIC1C   ;主机模式下,RSTA位置1,产生重复开始信号    
   
   LDA 1,SP    ;获取设备地址DeviceAddr
   ORA #$01    ;通知从机改为发送数据
   STA IIC1D
   
   LDA #'T'
   JSR Wait    ;等待一个字节数据传送完成        
   CMP #1
   BEQ IICread1_End;没有传送成功,读一个字节失败    
   LDA #'A'
   JSR Wait    ;等待从机应答信号        
   CMP #1
   BEQ IICread1_End;没有等到应答信号,读一个字节失败
   
   LDA IIC1C
   AND #$EF    ;TX = 0,MCU设置为接收模式    
   STA IIC1C
   
   LDX IIC1D   ;读出IIC1D,准备接收数据
   
   LDA #'T'
   JSR Wait    ;等待一个字节数据传送完成        
   CMP #1
   BEQ IICread1_End;没有传送成功,读一个字节失败
   
   LDX #'O'
   JSR SendSignal;发送停止信号 
   
   LDX IIC1D   ;读出接收到的一个数据
   
   LDA #0
   BRA IICread1_Return;正确接收到一个字节数据
IICread1_End:
   LDA #1
IICread1_Return:
   AIS #2
 RTS

;---------------------------------------------------------------------------*                                            
;函 数 名: IICwrite1                                                        *
;功能描述: 向从机写1个字节数据                                              *
;入    口: H = DeviceAddr,设备地址; X = AccessAddr,访问地址;                *
;          A : 要发给从机的1个字节数据                                      *
;出    口: A = 0,成功写一个字节;A = 1,写一个字节失败                        *
;堆栈深度: 2 + 3 + 5 = 10                                                   *
;内部调用: SendSignal,Wait                                                  *
;说    明: 无                                                               *
;---------------------------------------------------------------------------*
IICwrite1:
   AIS #-3
   STHX 1,SP    ;设备地址和访问首址
   STA 3,SP     ;要发给从机的数据
   
   LDA IIC1C
   ORA #$10
   STA IIC1C    ;TX = 1,MCU设置为发送模式
   LDX #'S' 
   JSR SendSignal;发送开始信号
 
   LDA 1,SP
   AND #$FE
   STA IIC1D    ;发送设备地址,并通知从机接收数据    
   
   LDA #'T'
   JSR Wait     ;等待一个字节数据传送完成        
   CMP #1
   BEQ IICwrite1_End;没有传送成功,写一个字节失败    
   LDA #'A'
   JSR Wait         ;等待从机应答信号        
   CMP #1
   BEQ IICwrite1_End;没有等到应答信号,写一个字节失败      
   
   LDA 2,SP
   STA IIC1D    ;发送访问地址,并通知从机接收数据
   
   LDA #'T'
   JSR Wait     ;等待一个字节数据传送完成        
   CMP #1
   BEQ IICwrite1_End;没有传送成功,写一个字节失败    
   LDA #'A'
   JSR Wait     ;等待从机应答信号        
   CMP #1
   BEQ IICwrite1_End;没有等到应答信号,写一个字节失败
   
   LDA 3,SP
   STA IIC1D    ;发送要传递的数据
   
   LDA #'T'
   JSR Wait     ;等待一个字节数据传送完成        
   CMP #1
   BEQ IICwrite1_End;没有传送成功,写一个字节失败    
   LDA #'A'
   JSR Wait     ;等待从机应答信号        
   CMP #1
   BEQ IICwrite1_End;没有等到应答信号,写一个字节失败
   
   LDX #'O' 
   JSR SendSignal;发送停止信号
   LDA #0
   AIS #3
 RTS 
IICwrite1_End:
   LDA #1
   AIS #3
 RTS

;---------------------------------------------------------------------------*
;函 数 名: IICreadN                                                         *
;功能描述: 从从机读N个字节数据                                              *
;入    口: (1) H = DeviceAddr:设备地址                                      *
;          (2) X = AccessAddr:访问地址                                      *
;          (3) ReadData:读出数据                                            *
;          (4) A = 从从机读的字节个数                                       *
;出    口: A = 0,成功读N个字节;A = 1,读N个字节失败                          *
;内部调用: IICread1                                                         *
;堆栈深度: 2 + 5 + 9 = 16                                                   *
;说    明: 无                                                               *
;---------------------------------------------------------------------------* 
IICreadN: 
   AIS #-5 
   STHX 3,SP    ;存放设备地址和访问首地址
   STA 5,SP     ;存入从从机读的字节个数
    
   CLRA
   STA 1,SP
   STA 2,SP     ;两个临时变量,都为循环变量
   
IICreadN_For:   
   LDA 1,SP
   CMP 5,SP
   BHS IICreadN_For_End
InnerFor:
   LDA 2,SP
   CMP #15     ;最小延时(发送的每个字节之间要有时间间隔)
   BHS DoIf
   NOP
   INCA
   STA 2,SP
   BRA InnerFor
DoIf:
   CLRA
   STA 2,SP    ;下次再进入内循环时可以从0开始
   
   LDHX 3,SP
   JSR IICread1
   CMP #1
   BEQ IICreadN_End;其中一个字节没有接收到,返回失败标志:1
   LDA #ReadData
   ADD 1,SP    ;此时A中放入的是数据要放入的地址,X中放入的是
               ;要放入的数据
   PSHA
   TXA
   PULX        ;X与A中的数交换
   CLRH
   STA ,X
   
   LDA 1,SP
   INCA
   STA 1,SP
   LDX 4,SP
   INCX
   STX 4,SP 
   BRA IICreadN_For
IICreadN_For_End:
   LDA 1,SP
   CMP 5,SP
   BLO IICreadN_Return
   LDA #0      ;成功接收N个数据,返回成功标志:0
   AIS #5     
 RTS
IICreadN_End:
   LDA #1
IICreadN_Return:  
   AIS #5 
 RTS 

;---------------------------------------------------------------------------*
;函 数 名: IICwriteN                                                        *
;功能描述: 向从机写N个字节数据                                              *
;入    口: (1) H = DeviceAddr:设备地址                                      *
;          (2) X = AccessAddr:访问地址                                      *
;          (3) WriteData:要写入的数据                                       *
;          (4) A = 写入数据个数                                             *
;出    口: A = 0,成功写N个字节;A = 1,写N个字节失败                          *
;内部调用: IICwrite1                                                        *
;堆栈深度: 2 + 5 + 10 = 17                                                  *
;说    明: 无                                                               *
;---------------------------------------------------------------------------*
IICwriteN:
   AIS #-5
               
   STHX 4,SP   ;暂存访问首地址和设备地址 
   STA 3,SP    ;存入向从机写的字节个数
  
   CLRA
   STA 1,SP
   STA 2,SP    ;两个临时变量,都为循环变量
   
IICwriteN_For:   
   LDX 1,SP
   CPX 3,SP
   BHS IICwriteN_For_End
IICwriteN_InnerFor:
   LDX 2,SP
   CPX #15     ;最小延时(发送的每个字节之间要有时间间隔)  
   BHS IICwriteN_DoIf
   NOP
   INCX
   STX 2,SP
   BRA IICwriteN_InnerFor
IICwriteN_DoIf:
   CLRX
   STX 2,SP    ;下一次内循环时从0开始
   CLRH
   LDX 1,SP
   LDA WriteData,X;A中放入要传入的数据
   LDHX 4,SP
   JSR IICwrite1
   CMP #1
   BEQ IICwriteN_End;其中一个字节没有发送出去,返回失败标志:1
   
   LDA 1,SP
   INCA
   STA 1,SP
   LDX 5,SP
   INCX       ;以便下一次的访问地址加1 
   STX 5,SP
   BRA IICwriteN_For
IICwriteN_For_End:
   LDA 1,SP
   CMP 3,SP
   BLO IICwriteN_Return
   LDA #0     ;成功发送N个数据,返回成功标志:0
   AIS #5
 RTS
IICwriteN_End:
   LDA #1
IICwriteN_Return:
   AIS #5
 RTS 

