TI INA180 Ammeter chip

Thread Starter

Roseandthistle

Joined Oct 14, 2016
3
Hi all.
First post here. I ordered six chips to try with a Uc (Picaxe) 28X2 driven battery charger. The Picaxe is connected to a 4x20 serial lcd. The data sheet seems straight forward but, I'm not sure where to start with the Rref. I would like to use this on the low power side of the circuit. I am looking at no more then 2A and a 10bit ADC (1023)count.
Has anyone had experience with these chips?
 

LesJones

Joined Jan 8, 2017
4,174
I have not used the INA180 but I have used the INA219 which has the ADC built in. It can be configured to work with between 9 and 12 bits resolution. It comunicates with the microcontroller via an I2C bus. It works well and you can buy the chip mounted on a small PCB with a 0.1 ohm current sense resistor from a number of sellers on ebay. It did take me some time to write the code to communicate with the INA219. I use it with a PIC12F1840. If you are interested I can post the code. I think I paid about £1.60 each for them.

Les.
 

Thread Starter

Roseandthistle

Joined Oct 14, 2016
3
I have not used the INA180 but I have used the INA219 which has the ADC built in. It can be configured to work with between 9 and 12 bits resolution. It comunicates with the microcontroller via an I2C bus. It works well and you can buy the chip mounted on a small PCB with a 0.1 ohm current sense resistor from a number of sellers on ebay. It did take me some time to write the code to communicate with the INA219. I use it with a PIC12F1840. If you are interested I can post the code. I think I paid about £1.60 each for them.

Les.
Thank you, Les.
The Picaxe uses I2C buses and the added adc would free up 1 on the chip.
I would be grateful if you could post the code.
Terry
 

LesJones

Joined Jan 8, 2017
4,174
Here is the source code.

Code:
;   This is for reading voltge and current from an INA219 and transmitting as ASCII string of characters
;    Started 19/02/2017
;   Modified to disable USART receive after recognising station ID (18/03/17)
;   Version V&I_Monitor05   13/06/2017
;   Version V&I_Monitor06   15/06/2017 Adding leading zero blanking to display code.
;   Version V&I_Monitor07   18/06/2017 Adding code to write configuration register.
;******************************************************************************************

;   INA219 notes
;   12 Bit A to D  (Count 4096)
;
;    Default configuration 0x399F  (b'0011 1001 1001 1111)
;   BRNG (Bit 13) set  = 32V FSR (default value)  7.8125 mV per bit
;   PG   b'11'   ±320 mV   (Shunt voltage)       0.01 mV per bit
;   Mode    b'111 (0x07) Shunt and bus, continuous
;   SADC     b'0011 (0x03) 12 bit  Conversion time 532 us
;   BADC   b'0011 (0x03) 12 bit  Conversion time 532 us

;   Calibration register

;******************************************************************************************
;
;  OSC  : Internal OSC 4 MHz
;
;******************************************************************************************
  LIST  P=PIC12F1840,ST=OFF,R=DEC
  INCLUDE  "P12F1840.inc"

  __CONFIG _CONFIG1,  _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF &  _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF


  __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_HI & _LVP_OFF

;*******************************************************************************
; Constants
;*******************************************************************************

Station_ID   equ   'E'   ;Station identification character for this station
;Conf_Value     EQU   0x019F     ;0x019F is the default config value   
Conf_Value     EQU   0x019B     ;0x019F Set for `triggered volage and current   


Cal_Value     EQU   D'4096'  ;0x01000

RAM_START  equ  0x20


; The periods are timed with timer1 which is set to run at the internal clock
; rate (4 Mhz) of Fosc/4 or 1.0MHz which is equal to a 1 uS period.




;DELAY_6MS   equ   D'2993'    ;Value to give delay of 6 mS
RX_Timer   equ   D'200'

CR     EQU   0x0D     ;Carriage return
LF     EQU   0x0A     ;Line Feed   

Conf_Reg   EQU   0x00
Shunt_Volt_Reg   EQU   0x01
Bus_Volt_Reg   EQU   0x02
Power_Reg   EQU   0x03
Current_Reg   EQU   0x04
Calib_Reg   EQU   0x05

;*******************************************************************************
; Pin Assignments
;*******************************************************************************
;
;   PIC signals
;
   #DEFINE     TX_Data     PORTA, 0     ;
   #DEFINE     SCL     PORTA, 1     ;
;
   #DEFINE     SDA     PORTA, 2     ; I2c Data
;   #DEFINE     Button     PORTA, 3     ; Push button to trigger  read (Not used)


; I/O pin use
;   RA0   TX      (Pin 7)  (To pin 4 on programmer connection)
;   RA1   SCL      (Pin 6)  (To pin 5 on programmer connection)
;   RA2   I2c Data       (Pin 5)
;   RA3   Trigger button     (Pin 4)   NOTE THIS PIN CAN ONLY BE USED AS AN INPUT.   
;            (This is VPP for programming This could be connected to pin 3 or 5 of the header to program the chip on header.)
;   RA4 (AN3)   Not used     (Pin 3)  (Use for LED for testing)
;   RA5    RX     (Pin 2)  (Moved from RA1 )




;  Define GENERAL PURPOSE RAM AREA (80 bytes maximum)

;*******************************************************************************
; File Register Variables
;*******************************************************************************
  cblock  RAM_START

param1:   1  ; parameter 1  (Used in delay cycles routine)
param2:   1  ; parameter 2  (Used in delay cycles routine)
Temp_1:   1     ;Used in 2 second delay

tmpData:   1     ; Used in output_hexbyte routine

; delay counters
Del_Count:  1
   
ADC_Temp_L:   1
ADC_Temp_H:   1

Raw_Data0:   1     ;
Raw_Data1:   1   ;
Raw_Data2:   1   ;
Raw_Data3:   1   ;
Raw_Data4:   1   ;

; byte counter
  bytcnt:  1

;These are the ASCII values for the character

ESEVN:   1     ; 10 000,000 (digit 8)
ESIX:   1     ; 1000,000s (digit 7 )
EFIVE:   1     ; 100,000s digit 6 store
EFOUR:   1     ; 10,000s digit 5 store
ETHREE:   1     ; 1000s digit 4 store
ETWO:   1     ; 100s digit 3 store
EONE:   1     ; 10s digit 2 store
EZERO:   1     ; 1's digit 1 store



COUNT:   1

BCD1:   1     ; overrange
BCD2:   1     ; MS decimal value
BCD3:   1     ;
BCD4:   1     ; decimal value
BCD5:   1     ; ls decimal value
   
BIN1:   1     ; LS binary value
BIN2:   1     ;
BIN3:   1     ;
BIN4:   1     ; MS binary value

TEMP:   1

Text_Pointer: 1
String_offset: 1   ;Holds offset fron stsrt of Sting table of required string

RX_Count:   1

; I2C variables
W_Data_H:   1   ;Data to be written to INA219 register
W_Data_L:   1


Flags01:   1     ;
;     Bit 0
;     Bit 1     ;Negative flag.  (For shunt voltage)

Flags02:   1     ;
;     Bit 0     ;Leading zero blanking flag. Set when zero needs to be replaced by a space
DP_Pos:     1     ;Number of digits before decimal point


  endc
;*******************************************************************************
; Common RAM (0x70 to 0x7F)
;*******************************************************************************

TX_temp     EQU 0x70     ;Temporary storage for character to be transmitted.
RX_Temp     EQU 0x71     ;Temporary storage for received character.
BS_Temp     EQU 0x72     ;Temporary storage for "BSR" during bank select
W_Temp     EQU 0x73     ;Temporary storage for "W" during bank select
INA219_Reg   EQU 0x74     ;Register to read in INA219
;
;*******************************************************************************
;  Define Macro  Takes 2 uS
;*******************************************************************************
SELBANK MACRO  #BANK_NO
  MOVLB  #BANK_NO   ;1 cycle - 1 uS   
  ENDM


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

  ORG  0x00
  GOTO  START
  ORG  0x04
  GOTO  START
START
; *****************************
;  Initialise+

; *****************************
; Initialise OSC (4MHz, IntOSC)
 ;  SELBANK 1  ; SET BANK1
   banksel   OSCCON
  MOVLW  B'11101010'   
  MOVWF  OSCCON

   BCF   INTCON,GIE     ;All interrupts off

; Initialise I/O port
;select alternate function

   BANKSEL   APFCON       ;Bank 2
   BSF   APFCON,RXDTSEL     ;Move RX to RA5 so that SCK can be used

;  SELBANK 1  ; SET BANK1
   BANKSEL   TRISA
  MOVLW  B'00101110'     ; Bits 0, 4 output Bit 1, 2,  3, 5 input.
  MOVWF  TRISA

;Set pullup on PORTA,3

   BCF   OPTION_REG,NOT_WPUEN

     SELBANK 4  ; SET BANK 4
   MOVLW   B'00001000'
   MOVWF   WPUA


; Initialized Comparitor.
     SELBANK 2  ; SET BANK2
     MOVLW  B'00000000'     ; Comparator disabled.
   MOVWF   CM1CON0       ;In bank 2
     SELBANK 0  ; SET BANK0

   CLRF   PORTA     ;Set all outputs low



; Initialized EUSART
     SELBANK 3  ; SET BANK 3
   MOVLW   B'00000000'
   MOVWF   BAUDCON

   BSF   TXSTA,BRGH   ; Set baud rate high bit
     BSF  TXSTA,TXEN  ;enable transmission  

   MOVLW   0x19     ; Decimal 25 for 9600 baud rate
   MOVWF   SPBRGL
   MOVLW   0x00
   MOVWF   SPBRGH

   BSF  RCSTA,SPEN  ;enable serial port
   BSF  RCSTA,CREN  ;enable receive


   

     SELBANK 0  ; SET BANK0

; Initialized Timer 1
     SELBANK 0  ; SET BANK0

   MOVLW   B'00010100'   ;Clock source FOSC, 1:2 prescale, Dedicated Timer1 oscillator circuit disabled,
  ;Do not synchronize external clock input, Timer off

   MOVWF   T1CON     ;With 4 Mhz clock timer will increment every 500 nS

   MOVLW   0x00     ;All bits clear (Gate control not used.)
   MOVWF   T1GCON

; Initialized I2c
   CALL   Init_I2C

     SELBANK 0  ; SET BANK0




;load calibration value to INA219

   MOVLW   HIGH Cal_Value
   MOVWF   W_Data_H
   MOVLW   LOW Cal_Value
   MOVWF   W_Data_L

   MOVLW   Calib_Reg
   CALL    Write_INA219

; *****************************
;  Program main
; *****************************
; Main loop


MAIN:

Wait_Rx_Chr:       ;Wait for a received character

   BCF   PORTA,4     ;TEST switch off LED


   SELBANK 3
   BSF  RCSTA,CREN  ;enable receive
   SELBANK 0

   CALL   SerialReceive


   XORLW   '#'     ;Wait for # character.
   BTFSS   STATUS,Z
   GOTO   Wait_Rx_Chr   ; Not # character

;   GOTO   Skip     ;  For testing to skip ID character check

   MOVLW   RX_Timer   ; Number of 10 mS to wait for station ID character
   MOVWF   RX_Count


Test_DAV:
     btfsc  PIR1,RCIF  ;check if data received
   GOTO   Read_Data
   CALL   Delay_10mS
   DECFSZ   RX_Count
   GOTO   Test_DAV
   GOTO   Wait_Rx_Chr



Read_Data:

   SELBANK 3  ; SET BANK 3
     movf  RCREG,W     ;get received data into W
   BCF  RCSTA,CREN     ;disable receive

     SELBANK 0  ; SET BANK 0

   XORLW   Station_ID
   BTFSS   STATUS,Z
   GOTO   Wait_Rx_Chr   ; Not this station

Skip:

   CALL   Set_INA219_Config   ;Also triggers a reading

   CALL   Delay_100mS     ;Wait for result to be available

   MOVLW   Conf_Reg
   Call   Read_INA219
   
   MOVLW   LOW TXT_Conf
   Call   String_out

   CALL   send_data     ;Output in raw HEX format

   MOVLW   Shunt_Volt_Reg
   Call   Read_INA219

;Clear Sign flag
   BCF   Flags01,1
;Check the sign bit
   BTFSS   Raw_Data0,7
   GOTO   Display_ShuntV     ;For positive value
   BSF   Flags01,1     ;Set negative flag bit

;Complement 16 bit value
   COMF   Raw_Data0
   COMF   Raw_Data1
;Convert ons's complement to two's complement  (Add one)
   INCFSZ   Raw_Data1
   GOTO   Comp_End1
   INCFSZ   Raw_Data1
Comp_End1:

Display_ShuntV:
   MOVLW   LOW TXT_ShuntV
   Call   String_out

   CALL   send_data     ;Output in raw HEX format
   MOVLW   ' '       ;Space character
   CALL   SerialTransmit

   MOVLW   '='
   CALL   SerialTransmit

   MOVLW   ' '       ;Space character
   CALL   SerialTransmit

   MOVLW   '+'       ;Positive sign character
   BTFSC   Flags01,1     ;Test negative flag
   MOVLW   '-'       ;Negative sign character
   CALL   SerialTransmit

   MOVLW   0x03
   MOVWF   DP_Pos
   CALL   Output_Decimal     ;Output in decimal

   MOVLW   LOW TXT_mV
   Call   String_out



   MOVLW   Bus_Volt_Reg
   Call   Read_INA219

   BCF   Flags01,0
   BCF   Flags01,1

   BTFSC   Raw_Data1,0
   BSF   Flags01,0     ;Bus voltage overflow flag

   BTFSC   Raw_Data1,1
   BSF   Flags01,1     ;Bus voltage Conversion Ready flag

;Shift bits to correct position

   BCF   STATUS,C     ;Clear carry bit
   RRF   Raw_Data0
   RRF   Raw_Data1

;Clear bits 0 & 1
   BCF   Raw_Data1,0
   BCF   Raw_Data1,1


   MOVLW   LOW TXT_B_Volt
   Call   String_out
   CALL   send_data     ;Output in raw HEX format

   MOVLW   ' '       ;Space character
   CALL   SerialTransmit

   MOVLW   '='
   CALL   SerialTransmit

   MOVLW   ' '       ;Space character
   CALL   SerialTransmit

   MOVLW   0x02
   MOVWF   DP_Pos
   CALL   Output_Decimal     ;Output in decimal

   MOVLW   LOW TXT_Volts
   Call   String_out

   MOVLW   Power_Reg
   Call   Read_INA219
; Now divide by 5000 (Decimal) by multiplying HEX value by 2 (One left shift) and divide by 1000 (Right shift decimal 4 places.)
   BCF   STATUS,C     ;Clear carry bit
   RLF   Raw_Data1
   RLF   Raw_Data0

   MOVLW   LOW TXT_Power
   Call   String_out
   CALL   send_data     ;Output in raw HEX format

   MOVLW   ' '       ;Space character
   CALL   SerialTransmit

   MOVLW   '='
   CALL   SerialTransmit

   MOVLW   ' '       ;Space character
   CALL   SerialTransmit

   MOVLW   0x02
   MOVWF   DP_Pos
   CALL   Output_Decimal     ;Output in decimal

   MOVLW   LOW TXT_Watts
   Call   String_out


   MOVLW   Current_Reg
   Call   Read_INA219
;Clear Sign flag
   BCF   Flags01,1
;Check the sign bit
   BTFSS   Raw_Data0,7
   GOTO   Dispaly_Current     ;For positive value
   BSF   Flags01,1     ;Set negative flag bit

;Complement 16 bit value
   COMF   Raw_Data0
   COMF   Raw_Data1
;Convert ons's complement to two's complement  (Add one)
   INCFSZ   Raw_Data1
   GOTO   Comp_End2
   INCFSZ   Raw_Data1
Comp_End2:



Dispaly_Current:
   MOVLW   LOW TXT_Current
   Call   String_out
   CALL   send_data     ;Output in raw HEX format

   MOVLW   ' '       ;Space character
   CALL   SerialTransmit

   MOVLW   '='
   CALL   SerialTransmit

   MOVLW   ' '       ;Space character
   CALL   SerialTransmit

   MOVLW   '+'       ;Positive sign character
   BTFSC   Flags01,1     ;Test negative flag
   MOVLW   '-'       ;Negative sign character
   CALL   SerialTransmit

   MOVLW   0x01
   MOVWF   DP_Pos
   CALL   Output_Decimal     ;Output in decimal

   MOVLW   LOW TXT_Amps
   Call   String_out


   MOVLW   Calib_Reg
   Call   Read_INA219

   MOVLW   LOW TXT_Cal
   Call   String_out
   CALL   send_data     ;Output in raw HEX format

   CALL   CRLF       ;Send CR / LF to serial port

   CALL Delay_100mS

   GOTO   Wait_Rx_Chr
;     --------------------------------------------------------------------------------------


; *****************************
;  Subroutines
; *****************************
           
;*****************************************************************************   
;
;  Function :  SerialTransmit
;  This function sends the byte in W over the RS232 port. The
;  function will wait until previous data has been sent
;
;  Input:  Byte in W
;
;  Output:   
;
;*****************************************************************************   
SerialTransmit:
;   MOVWF   TX_temp
     btfss  PIR1,TXIF  ;check that buffer is empty
     goto  $-1
     SELBANK 3  ; SET BANK 3
;   MOVF   TX_temp,W   
     movwf  TXREG  ;transmit byte
     SELBANK 0  ; SET BANK 0
     return
;*****************************************************************************
   
SerialReceive:

     btfss  PIR1,RCIF  ;check if data received
     goto  SerialReceive  ;wait until new data
   SELBANK 3  ; SET BANK 3
     movf  RCREG,W  ;get received data into W
     SELBANK 0  ; SET BANK 0
     return

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

;****************************************************************************************   
;*                       *
;*   Read INA219                   *
;*   Input   INA219 register address in W Reg.           *
;*                       *
;* Result High byte in ADC_Temp_H & Raw_Data0. Low byte in ADC_Temp_L & Raw_Data1   *
;*                       *
;****************************************************************************************  

Read_INA219:
   MOVWF INA219_Reg   ;Save required !NA219 register address   

   CALL   I2C_start

;Select register
   MOVLW  B'10000000'  ;control byte Slave address 0 (in bits 1 to 7) (Bit 0 set to indicate a read from slave.)
   CALL   I2C_TX

   MOVF   INA219_Reg,W   
   CALL   I2C_TX       ;Send register address

   CALL   I2C_restart

     MOVLW    B'10000001'  ;control byte  Slave address (Bit 0 set to indicate a read from slave.)
   CALL   I2C_TX

   CALL   I2C_RX
   MOVWF   ADC_Temp_H
   MOVWF   Raw_Data0
   CALL   I2C_RX
   MOVWF   ADC_Temp_L
   MOVWF   Raw_Data1
;   CALL   NACK
   CALL   I2C_stop

   RETURN




;****************************************************************************************   
;*                       *
;*   Write INA219                   *
;*   Input   INA219 register address in W Reg.           *
;*     Data to be written in W_Data_H &  W_Data_L                   *
;*                       *
;* Result 16 bit data written to selected register in INA219         *
;*                       *
;****************************************************************************************  

Write_INA219:
   MOVWF INA219_Reg   ;Save required INA219 register address   

   CALL   I2C_start

;Select register
   MOVLW  B'10000000'  ;control byte Slave address 0 (in bits 1 to 7) (Bit 0 set to indicate a read from slave.)
   CALL   I2C_TX

   MOVF   INA219_Reg,W   
   CALL   I2C_TX       ;Send register address

   MOVF   W_Data_H,W   
   CALL   I2C_TX       ;Send high byte of data to be written

   MOVF   W_Data_L,W   
   CALL   I2C_TX       ;Send high byte of data to be written

;   CALL   NACK
   CALL   I2C_stop

   RETURN

Set_INA219_Config:

;****************************************************************************************   
;*                       *
;*   Load configuration value to INA219             *
;*   Input   Constant Conf_Value               *
;*     This also triggers a reading               *
;*                       *
;*                       *
;****************************************************************************************  

Set_INA219_Config:

   MOVLW   HIGH Conf_Value
   MOVWF   W_Data_H
   MOVLW   LOW Conf_Value
   MOVWF   W_Data_L

   MOVLW   Conf_Reg
   CALL    Write_INA219
   RETURN


;       *************** Start of I2C subroutines ************
Init_I2C:
  ; I2C In Master Mode

   MOVLW  B'00101000'       ;Enable (Bit 5) ,  ; I2C Master,  clock = FOSC/(4 * (SSPADD + 1))
   BANKSEL   SSP1CON1       ;(Bank 4)
   MOVWF   SSP1CON1
   
  ; I2C Bit Rate Setup

     MOVLW  0X09
   MOVWF  SSP1ADD       ;(Bank 4)

   
  ; I2C Slew Rate Control

;   BANKSEL   SSPSTAT       ; Not needed Allready in this bank. (Bank 4)
   BSF   SSPSTAT,SMP
   RETURN


;*****************************************************************************   
;
;  Function :  I2C_CTX   
;  Sends a byte over the I2C bus, and detects an ACK
;
;  Input:  8 bit byte in W
;
;  Output:  W=1 == No ACK, W=0 == ACK received
;
;*****************************************************************************   


I2C_CTX:
   BCF   PIR1,SSP1IF
   BANKSEL   SSPBUF       ;Bank 4
   MOVWF   SSPBUF

  ; Wait for I2C Transmit to complete
   BANKSEL   SSP1STAT     ;Bank 4
   BTFSS   SSP1STAT,BF  ;Check buffer is full
   GOTO   I2C_CTX02
   BANKSEL   PIR1       ;Back to bank 0

I2C_CTX01:
   BTFSS   PIR1,SSP1IF
   GOTO   I2C_CTX01     ;Loop until interrupt flag is set
   GOTO   I2C_CTX03

I2C_CTX02:
   BANKSEL   PIR1       ;Back to bank 0
;   MOVLW   0x10     ;Bit 4 set     TEST CODE
;   XORWF   PORTA     ;       TEST CODE

   GOTO   I2C_CTX02       ; ?????

I2C_CTX03:
  ; Test I2C ACK Result read from slave
   BANKSEL   SSP1CON2
   MOVLW   0X01     ;1 = Acknowledge was not received from slave
   BTFSS   SSP1CON2,ACKSTAT
   MOVLW   0X00     ;0 = Acknowledge was received from slave
   BANKSEL   PIR1       ;Back to bank 0
   RETURN


;*****************************************************************************   
;
;  Function :  I2C_TX  (Send data byte)
;  Sends an 8 bit byte over the I2C bus and monitors the ACK bit,
;  causing a system reset if not received
;
;  Input:  8 bit byte in W
;
;  Output:  None
;
;*****************************************************************************   
;tx   


I2C_TX:
   CALL I2C_CTX
   IORLW   0X00  ;Check that the expected acknowledge is received
   BTFSS   STATUS,Z     ;Expect 0 = Ack received
   GOTO   I2C_Err       ;Try again
   RETURN



;*****************************************************************************   
;
;  Function :  I2C_RX
;  receives an 8 bit byte over the I2C bus
;  This function blocks until the byte is received
;
;  Input:  None
;
;  Output:  Received byte in W
;
;*****************************************************************************   
;
I2C_RX:
   BCF   PIR1,SSP1IF  ;Clear the interrupt flag before rx (In bank 0)
   BANKSEL   SSP1CON2     ;Bank 4
   BSF   SSP1CON2,RCEN     ;Recieve enable
   BANKSEL   PIR1       ;Back to bank 0

RX01:
   BTFSS   PIR1,SSP1IF
   GOTO   RX01       ;Loop until interrupt bit is set
   BANKSEL SSPBUF       ;Bank 4
   MOVF   SSPBUF,W

   BANKSEL   PIR1       ;Back to bank 0   
   BCF   PIR1,SSP1IF  ;Clear the interrupt flag

   BANKSEL   SSP1CON2     ;Bank 4
   BCF   SSP1CON2,ACKDT
   BSF   SSP1CON2,ACKEN   

   BANKSEL   PIR1       ;Back to bank 0   
RX02:
   BTFSS   PIR1,SSP1IF
   GOTO   RX02       ;Loop until interrupt bit is set

   BCF   PIR1,SSP1IF  ;Clear the interrupt flag
   RETURN   


;*****************************************************************************   
;
;  Function :  NACK
;  Asserts a NACK condition on the BUS
;
;  Input:  None
;
;  Output:  Received byte in W
;
;*****************************************************************************   
;
NACK:
   BANKSEL   PIR1       ;Back to bank 0
   BCF   PIR1,SSP1IF  ;Clear the interrupt flag
   BANKSEL   SSP1CON2
   BSF   SSP1CON2,ACKDT  ;Set ACKDT to transmit an NACK Bit
   BSF   SSP1CON2,ACKEN  ;start Acknowledge Sequence
   BANKSEL   PIR1       ;Back to bank 0

NAC01:
   BTFSS   PIR1,SSP1IF
   GOTO   NAC01
   RETURN

;*****************************************************************************   
;
;  Function :  i2c_error
;  Error handler. We do none, allowing the watchdog to cause  
;  a reset
;
;  Input:  None
;
;  Output:  None
;
;*****************************************************************************   
;i2c_Error
;  sleep
;  nop
;  goto  i2c_error

I2C_Err:
;   SLEEP

;  Test code            Toggles LED every 2 seconds
   MOVLW   0x10     ;Bit 4 set
   XORWF   PORTA
   CALL Delay_2_Sec
;       End of test code
   NOP
   GOTO I2C_Err



;*****************************************************************************   
;
;  Function :  I2C_start
;  Generate a start condition on the I2C bus
;
;  Input:  None
;
;  Output:  None
;
;*****************************************************************************   
;
I2C_start:
   BANKSEL   SSP1CON2     ;Bank 4
   BSF   SSP1CON2,SEN

I2C_strt01:
   BTFSC   SSP1CON2,SEN  ;Poll until end of start condition
   GOTO   I2C_strt01

   BANKSEL   PIR1       ;Back to bank 0
   RETURN


;*****************************************************************************   
;
;  Function :  restart
;  Generate a restart condition on the bus
;
;  Input:  None
;
;  Output:  None
;
;  Bank on exit  0
;
;*****************************************************************************   
;
I2C_restart:
   BANKSEL   SSP1CON2
   BSF   SSP1CON2,RSEN

I2C_rst01:
   BTFSC   SSP1CON2,RSEN
   GOTO   I2C_rst01

   BANKSEL   PIR1       ;Back to bank 0
   RETURN

;*****************************************************************************   
;
;  Function :  I2C_stop
;  generate an I2C stop condition on the bus
;
;  Input:  None
;
;  Output:  None
;
;*****************************************************************************   
;
I2C_stop:
   BANKSEL   SSP1CON2
   BSF   SSP1CON2,PEN

I2C_stp01:
   BTFSC   SSP1CON2,PEN
   GOTO   I2C_stp01

   BANKSEL   PIR1       ;Back to bank 0
   RETURN

;     ***************** End of I2C subroutines ***************
;

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



Delay_10mS:       ;Need to set param to (10000 - 14)/2  = 9986/2 = 4993 = 0x1381
   MOVLW   0x13
   MOVWF   param2
   MOVLW   0x81
   MOVWF   param1
   GOTO   delay_cycles

Delay_100mS:
   MOVLW   0xC3
   MOVWF   param2
   MOVLW   0x49
   MOVWF   param1
   GOTO   delay_cycles
   
Delay_2_Sec:
   MOVLW   D'20'
   MOVWF   Temp_1
D2_Loop:
   CALL   Delay_100mS
   DECFSZ   Temp_1
   GOTO   D2_Loop
   RETURN

;*******************************************************************************
; Function:  delay_cycles
; Description: Delay a specified number of instruction cycles including
;  interrupt cycles.  The function call overhead adds between
;  13 and 16 cycles of delay on top of the specified value.
; With 4 Mhz system clock and 1:2 prescale
;Delay will be  param * 2 uS + (13 * 1uS)  + 0 to 3 uS
;     = param * 2 uS + (13 to16.0 uS)  (Use 14 uS for calculation.)
;  So param = No. of uS/2 - 7
; Parameters:  param1 - least significant byte of 16 bit cycle delay
;  param2 - most significant byte of 16 bit cycle delay
; Returns:  None
;*******************************************************************************
delay_cycles:
  comf  param1,F  ; negate the delay by complementing the     (1 uS)    (1 cycle)
  comf  param2,F  ; low and high bytes         (1 uS)    (1 cycle)
  bcf  T1CON,TMR1ON  ; stop timer 1           (1 uS)    (1 cycle)
  movf  param1,W  ; move the low byte of the delay into     (1 uS)    (1 cycle)
  movwf  TMR1L  ; timer 1           (1 uS)    (1 cycle)
  movf  param2,W  ; move the high byte of the delay into     (1 uS)    (1 cycle)
  movwf  TMR1H  ; timer 1           (1 uS)    (1 cycle)
  bcf  PIR1,TMR1IF  ; clear the timer 1 rollover flag     (1 uS)    (1 cycle)
  bsf  T1CON,TMR1ON  ; turn on timer 1         (1 uS)    (1 cycle)
   
tmr1_check:   
  btfss  PIR1,TMR1IF  ; wait for the timer 1 rollover flag to     1 uS while looping    (2 uS) (2 cycle) on exit
  goto  tmr1_check  ; trigger
  return         ;             (2 uS)   (2 cycle)

;**********************************************************************************
; Subroutine BCD (to convert 28-bit binary to 8-digit BCD)
; Binary value is in BIN1, BIN2, BIN3 & BIN4. BIN1 is LSB, BIN4 is MSB
; Result in BCD is in BCD1, BCD2, BCD3, BCD4 & BCD5. BCD1 is for overrange,
; BCD2 is MSB, BCD5 is LSB
;**********************************************************************************

BIN_BCD:   
   bcf   STATUS,C   ; clear carry bit
   movlw   D'32'
   movwf   COUNT     ; 32 in count
   clrf   BCD1     ; set BCD registers to 0
   clrf   BCD2
   clrf   BCD3
   clrf   BCD4
   clrf   BCD5

LOOPBCD:
   rlf   BIN1,f     ; LSB shift left binary registers
   rlf   BIN2,f
   rlf    BIN3,f
   rlf   BIN4,f     ; MSB
   rlf   BCD5,f     ; LSB shift left BCD registers
   rlf   BCD4,f
   rlf   BCD3,f
   rlf   BCD2,f
   rlf   BCD1,f     ; MSB

   decfsz   COUNT,f     ; reduce count value return when 0
   goto   DECADJ     ; continue decimal adjust
   
; result in BCD1-5. (BCD1 overrange, BCD2 MS byte)

   swapf   BCD2,w     ; get ms nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   ESEVN     ; ms digit
   movf   BCD2,w     ; get 2nd ms nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   ESIX

   swapf   BCD3,w     ; get next nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   EFIVE     ; ms digit
   movf   BCD3,w     ; get next nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   EFOUR
   
   swapf   BCD4,w     ; get ms nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   ETHREE     ; ms digit
   movf   BCD4,w     ; get 2nd ms nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   ETWO

   swapf   BCD5,w     ; get ms nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   EONE     ; ms digit
   movf   BCD5,w     ; get 2nd ms nibble
   andlw   0x0F
   iorlw   0x30     ; convert to ASCII
   movwf   EZERO
   return       ; completed decimal to BCD operation

; subroutine decimal adjust

DECADJ   movlw   BCD5     ; BCD LSB address
   movwf   FSR1L     ; pointer for BCD5
   CLRF   FSR1H
   call   ADJBCD     ; subroutine to adjust BCD
   movlw   BCD4
   movwf   FSR1L
   CLRF   FSR1H
   call    ADJBCD
   movlw   BCD3
   movwf   FSR1L
   CLRF   FSR1H
   call    ADJBCD
   movlw   BCD2
   movwf   FSR1L
   CLRF   FSR1H
   call    ADJBCD
   movlw   BCD1
   movwf   FSR1L
   CLRF   FSR1H
   call    ADJBCD
   goto   LOOPBCD

; subroutine adjust BCD

ADJBCD   movlw   0x03     ; w has 03
   addwf   INDF1,w     ; add 03 to BCDx register (x is 1-5)
   movwf   TEMP     ; store w
   btfsc   TEMP,3     ; test if >7
   movwf   INDF1     ; save as LS digit
   movlw   0x30     ; 3 for MSbyte
   addwf   INDF1,w     ; add 30 to BCDx register
   movwf   TEMP     ; store w
   btfsc   TEMP,7     ; test if >7
   movwf   INDF1     ; save as MS digit
   return       ; end subroutine



;**********************************************************************************
;
;
Output_Decimal:

   CLRF   BIN4     ;Clear top 3 bytes (Not used.)
   CLRF   BIN3
   CLRF   BIN2
   
   MOVF   Raw_Data0,W   ;ADC high byte
   MOVWF   BIN2   

   MOVF   Raw_Data1,W   ;ADC low byte
   MOVWF   BIN1   

   CALL   BIN_BCD

   BSF   Flags02,0     ;Set leading zero blanking flag



   MOVLW   '0'   
   SUBWF   EFOUR, W     ;Is it a ASCII zero ?
   BTFSS   STATUS,Z
   BCF   Flags02,0     ;Clear leading zero blanking flag if character was not ASCII zero
   DECF   DP_Pos, W     ;Test if DP_Pos = 1
   BTFSC   STATUS,Z
   GOTO   LZ42   
   BTFSS   Flags02,0     ;Is leading zero blanking bit set ?
   GOTO   LZ42
   MOVLW   '0'
   SUBWF   EFOUR, W     ;Is it a ASCII zero ?
   BTFSS   STATUS,Z
   GOTO   LZ42
   MOVLW   ' '       ;ASCII space character
   GOTO   LZ43

LZ42:
   MOVF   EFOUR, W
LZ43:
     CALL  SerialTransmit   



   DECF   DP_Pos, F
   BTFSS   STATUS,Z
   GOTO   LZ31   
   MOVLW   '.'   ;ASCII DP character
     CALL  SerialTransmit   
   BCF   Flags02,0     ;Clear leading zero blanking flag after decimal point position
LZ31:

   MOVLW   '0'   
   SUBWF   ETHREE, W     ;Is it a ASCII zero ?
   BTFSS   STATUS,Z
   BCF   Flags02,0     ;Clear leading zero blanking flag if character was not ASCII zero
   DECF   DP_Pos, W     ;Test if DP_Pos = 1
   BTFSC   STATUS,Z
   GOTO   LZ32   
   BTFSS   Flags02,0     ;Is leading zero blanking bit set ?
   GOTO   LZ32
   MOVLW   '0'
   SUBWF   ETHREE, W     ;Is it a ASCII zero ?
   BTFSS   STATUS,Z
   GOTO   LZ32
   MOVLW   ' '       ;ASCII space character
   GOTO   LZ33
LZ32:
   MOVF   ETHREE, W
LZ33:
     CALL  SerialTransmit   



   DECF   DP_Pos, F
   BTFSS   STATUS,Z
   GOTO   LZ21   
   MOVLW   '.'   ;ASCII DP character
     CALL  SerialTransmit
   BCF   Flags02,0     ;Clear leading zero blanking flag after decimal point position
   
LZ21:

   MOVLW   '0'   
   SUBWF   ETWO, W     ;Is it a ASCII zero ?
   BTFSS   STATUS,Z
   BCF   Flags02,0     ;Clear leading zero blanking flag if character was not ASCII zero
   DECF   DP_Pos, W     ;Test if DP_Pos = 1
   BTFSC   STATUS,Z
   GOTO   LZ22   
   BTFSS   Flags02,0     ;Is leading zero blanking bit set ?
   GOTO   LZ22
   MOVLW   '0'
   SUBWF   ETWO, W     ;Is it a ASCII zero ?
   BTFSS   STATUS,Z
   GOTO   LZ22
   MOVLW   ' '       ;ASCII space character
   GOTO   LZ23

LZ22:
   MOVF   ETWO, W
LZ23:
     CALL  SerialTransmit   



   DECF   DP_Pos, F
   BTFSS   STATUS,Z
   GOTO   LZ11   
   MOVLW   '.'   ;ASCII DP character
     CALL  SerialTransmit
   BCF   Flags02,0     ;Clear leading zero blanking flag after decimal point position
   
LZ11:

   MOVLW   '0'   
   SUBWF   EONE, W     ;Is it a ASCII zero ?
   BTFSS   STATUS,Z
   BCF   Flags02,0     ;Clear leading zero blanking flag if character was not ASCII zero
   DECF   DP_Pos, W     ;Test if DP_Pos = 1
   BTFSC   STATUS,Z
   GOTO   LZ12   
   BTFSS   Flags02,0     ;Is leading zero blanking bit set ?
   GOTO   LZ12
   MOVLW   '0'
   SUBWF   EONE, W     ;Is it a ASCII zero ?
   BTFSS   STATUS,Z
   GOTO   LZ12
   MOVLW   ' '       ;ASCII space character
   GOTO   LZ13

LZ12:
   MOVF   EONE, W
LZ13:
     CALL  SerialTransmit   

   MOVF   EZERO, W
     CALL  SerialTransmit

   RETURN


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

;Output the data in HEX format
send_data:
; initialize the FSR0
     movlw  Raw_Data0
     movwf  FSR0L
   CLRF   FSR0H
; set byte counter
     movlw  0x2
     movwf  bytcnt

sendloop:
     movf  INDF0,w  ; get a byte of data

   CALL   output_hexbyte
; point to the next byte
     incf  FSR0L
     decfsz  bytcnt,f
     goto  sendloop
; All 5 bytes of data outputted
   RETURN
;

;*****************************************************************************   
;
;  Function :  output_hexbyte
;  Outputs the byte W to serial port
;  Input:  data in W
;
;  Output:  Data displayed
;
;*****************************************************************************   
output_hexbyte:
   MOVWF   tmpData
     swapf  tmpData,W
     sublw  0x09
     swapf  tmpData,W
     andlw  0x0F
     btfss  STATUS,DC
     addlw  'A' - .10 - '0'
     addlw  '0'
     call  SerialTransmit
     movfw  tmpData
     sublw  0x09
     movfw  tmpData
     andlw  0x0F
     btfss  STATUS,DC
     addlw  'A' - .10 - '0'
     addlw  '0'
     call  SerialTransmit
     return

;********************************************************************************
;*                     *   
;*  Send CR / LF to serial port             *
;*                     *  
;********************************************************************************
CRLF:
   MOVLW   0x0D     ;C/R
   CALL   SerialTransmit
   MOVLW   0x0A     ;L/F
   CALL   SerialTransmit
   RETURN

;*****************************************************************************   
;
;  Function :  Output text string
;  Sends an ASCII text string to the serial port
;
;  Input:  Offset from start of string table of required text string in "W"
;
;
;  Output:  Data displayed
;
;*****************************************************************************   
String_out:
     MOVWF  Text_Pointer
   DECF   Text_Pointer, F       ;Correct for increment due to  addwf  PCL, F instruction
   
String_001:
     movlw  HIGH String_table
     movwf  PCLATH   
     movf  Text_Pointer, W
     call  String_table
     xorlw  0
     btfsc  STATUS, Z
     return
   
     call  SerialTransmit
     incf  Text_Pointer, F
     goto  String_001

     org  0x300

String_table:
     addwf  PCL, F

TXT_Conf:
   retlw   CR
   retlw   LF
   retlw   'C'
   retlw   'o'
   retlw   'n'
   retlw   'f'
   retlw   'i'
   retlw   'g'
   retlw   'u'
   retlw   'r'
   retlw   'a'
   retlw   't'
   retlw   'i'
   retlw   'o'
   retlw   'n'
   retlw   ' '
   retlw   '0'
   retlw   'x'
     retlw   0x00

TXT_ShuntV:
   retlw   CR
   retlw   LF
   retlw   'S'
   retlw   'h'
   retlw   'u'
   retlw   'n'
   retlw   't'
   retlw   ' '
     retlw   'v'
     retlw   'o'
     retlw   'l'
     retlw   't'
   retlw   'a'
   retlw   'g'
   retlw   'e'
   retlw   ' '
   retlw   '0'
   retlw   'x'
     retlw   0x00

TXT_B_Volt:
   retlw   CR
   retlw   LF
   retlw   'B'
   retlw   'u'
   retlw   's'
   retlw   ' '
     retlw   'v'
     retlw   'o'
     retlw   'l'
     retlw   't'
     retlw   's'
   retlw   ' '
   retlw   '0'
   retlw   'x'
     retlw   0x00

TXT_Power:
   retlw   CR
   retlw   LF
     retlw   'P'
     retlw   'o'
     retlw   'w'
     retlw   'e'
     retlw   'r'
   retlw   ' '
   retlw   '0'
   retlw   'x'
     retlw   0x00

TXT_Current
   retlw   CR
   retlw   LF
     retlw   'C'
     retlw   'u'
     retlw   'r'
     retlw   'r'
     retlw   'r'
     retlw    'e'
     retlw   'n'
     retlw   't'
   retlw   ' '
   retlw   '0'
   retlw   'x'
     retlw   0x00

TXT_Cal:
   retlw   CR
   retlw   LF
     retlw   'C'
     retlw   'a'
     retlw   'l'
     retlw   'i'
     retlw   'b'
     retlw   'r'
     retlw   'a'
     retlw   't'
     retlw   'i'
     retlw   'o'
     retlw   'n'
     retlw   ' '
   retlw   '0'
   retlw   'x'
     retlw   0x00

TXT_Volts:
     retlw   ' '
   retlw   'V'
   retlw   'o'
     retlw   'l'
     retlw   't'
     retlw   's'
     retlw   ' '
     retlw   0x00

TXT_mV:
     retlw   ' '
   retlw   'M'
   retlw   'i'
   retlw   'l'
   retlw   'i'
   retlw   'v'
   retlw   'o'
     retlw   'l'
     retlw   't'
     retlw   's'
     retlw   ' '
     retlw   0x00

TXT_Amps:
     retlw   ' '
   retlw   'A'
   retlw   'm'
     retlw   'p'
     retlw   's'
     retlw   ' '
     retlw   0x00

TXT_Watts:
     retlw   ' '
   retlw   'W'
   retlw   'a'
     retlw   't'
     retlw   't'
     retlw   's'
     retlw   ' '
     retlw   0x00

String_table_end:
  retlw  0
   
  IF ( (String_table & 0x0FF) >= (String_table_end & 0x0FF) )
  MESSG  "String_table overflow"
  ENDIF

   end
The code is for a remote voltage and current unit communicating via HC-12 modules To get a reading from this the base station (A PC running a terminal emulator program.) sends a "#" character followed by the satation ID ( Letter "E" in this case which equates the constant Station_ID to the letter E at the beginning of the program.) The station then responds with a string of ASCII characters that shows the raw data from the sensor and the voltage and current values. (I think from memory it is setup to work with a 0.025 current sense resistor.) You will probably be able to use just the code that reads the INA219 data and get rid of the code that displays the data as text.

Les.
 
Top