본문 바로가기

임베디드 (?)

HX711 source codes for Magnet Flux Meter

/*
 * HX711.c
 *
 * Created: 2025-01-14 오전 10:15:09
 *  Author: KyKi
 */ 

#include "cdef.h"
#include "HX711.h"

#include <avr\io.h>
#include <util\delay.h>




sint32 HX711_s32Raw[HX711_CH_count];


void	HX711_Clk(uint8 clk)
{
	if (clk==0)
	{
		ClrBit( PORTC , BIT1 + BIT3 + BIT5 + BIT7 );
		ClrBit( PORTA , BIT7 );
	} else
	{
		SetBit( PORTC , BIT1 + BIT3 + BIT5 + BIT7 );
		SetBit( PORTA , BIT7 );
	}
}

uint8	HX711_ReadData(uint8 ch)
{
	uint8 ret;
	ret = 0;
	if (ch==0) ret = (((PINC & BIT0)>0)? (1) : 0);
	if (ch==1) ret = (((PINC & BIT2)>0)? (1) : 0);
	if (ch==2) ret = (((PINC & BIT4)>0)? (1) : 0);
	if (ch==3) ret = (((PINC & BIT6)>0)? (1) : 0);
	if (ch==4) ret = (((PING & BIT2)>0)? (1) : 0);
	return ret;
}

void INIT_HX711(void)
{
	ClrBit( PORTC , BIT1 + BIT3 + BIT5 + BIT7 ); // clock  OUTPUTs
	SetBit( DDRC  , BIT1 + BIT3 + BIT5 + BIT7 ); 
	ClrBit( PORTA , BIT7 );
	SetBit( DDRA  , BIT7 );
	
	ClrBit( DDRC  , BIT0 + BIT2 + BIT4 + BIT6 ); // din   INPUT
	SetBit( PORTC , BIT0 + BIT2 + BIT4 + BIT6 );  // Pulled UP
	ClrBit( DDRG  , BIT2 );
	SetBit( PORTG , BIT2 );
}

void Task_HX711(void)
{
	uint8	r, clk_counts;
	uint8	timeout = 0;
	sint32  bitidx;
	
	sint32  s32data[HX711_CH_count];
	
	// CH=A  gain=64 --> clk pulse = 27 pulses
	// rate = high = 80Hz sampling = 13msec

	for (r=0;r<HX711_CH_count;r++)
	{
		s32data[r] = 0;
	}
	timeout = 0;
	
	HX711_Clk(0); // clock 0
	
	r = HX711_ReadData(0) + HX711_ReadData(1) + HX711_ReadData(2) + HX711_ReadData(3) + HX711_ReadData(4); 
	while ((r>0) && (timeout<20)) // wait for all zero of data input
	{
		_delay_ms(1);	
		r = HX711_ReadData(0) + HX711_ReadData(1) + HX711_ReadData(2) + HX711_ReadData(3) + HX711_ReadData(4); 
		timeout++;
	}

	if (r==0) // all data ready
	{
		_delay_us(1);

		bitidx = 0x80000000; // setup signed 32bit;
		
		for (clk_counts=0;clk_counts<27;clk_counts++) // make 27 clock pulses
		{
			HX711_Clk(1);
			_delay_us(1);

			if (clk_counts<24) // read out 24 bit
			{
				for (r=0;r<HX711_CH_count;r++)
				{
					if (HX711_ReadData(r)==1)
					{
						s32data[r] = s32data[r] | bitidx;
					}
				}
				
				bitidx = bitidx >> 1;
			}

			HX711_Clk(0);
			_delay_us(1);
		}
		
		for (r=0;r<HX711_CH_count;r++)
		{
			HX711_s32Raw[r] = s32data[r] / (sint32)256; // convert to 24bit
		}
	}
	
}

 

 

/*
 * HX711.h
 *
 * Created: 2025-01-14 오전 10:14:54
 *  Author: KyKi
 */ 


#ifndef HX711_H_
#define HX711_H_

#include "cdef.h"

#define HX711_X			(0)
#define HX711_Y			(1)
#define HX711_Z			(2)
#define HX711_Ref		(3)
#define HX711_Temp		(4)
#define HX711_CH_count	(5)

extern sint32 HX711_s32Raw[HX711_CH_count];

extern void INIT_HX711(void);
extern void Task_HX711(void);




#endif /* HX711_H_ */

 

#include "cdef.h"

#include <avr\io.h>
#include <avr\interrupt.h>
#include <avr\wdt.h>
#include <avr\eeprom.h>
#include <util\delay.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>

#include "uart2.h"
#include "Max1167.h"

#include "HX711.h"

uint32	CalFactor[4];

/* ************************************
	PIN configuration
	
	Max1167
	DIN = C3
	DOUT = C2
	SCLK = C1
	CS = C0
	
	Batt voltage = ADC7  PF7
	LCD TX = PE1 (TX0)
	LCD RX = PE0 (RX0)
	
	COMM TX = PD3 (TX1)
	COMM RX = PD2 (RX1)

****************************************** */
uint16 SaveEEP_Reqeust = 0;
uint16 Stream_Reqeust = 0;
uint16 Cal_Reqeust = 0;

#define RxStrings	UART2_CH1_au8RxBuff
#define RxLength	UART2_CH1_u8RxLen

void	Comm_RX_Parser(void)
{
	uint8 r,k;
	char * param[5];
	
	char cmd;
	double  param1,param2,param3,param4;
	param[0]=RxStrings;
	
	k=1;
	for (r=0;r<RxLength;r++)
	{
		if (RxStrings[r]==',')
		{
			RxStrings[r]=0;
			param[k] = RxStrings+r+1;
			k = k + 1;
		}
	}

	cmd = param[0][0];
	param1 = atof( param[1] );
	param2 = atof( param[2] );
	param3 = atof( param[3] );
	param4 = atof( param[4] );
	
	if (cmd=='W') /* Write Cal factors */
	{
		CalFactor[0] = (uint32)(param1*10000);
		CalFactor[1] = (uint32)(param2*10000);
		CalFactor[2] = (uint32)(param3*10000);
		CalFactor[3] = (uint32)(param4*10000);
		SaveEEP_Reqeust = 1;
	}

	if (cmd=='S') /* Read Cal factors */
	{
		Stream_Reqeust = 500;
	}
	if (cmd=='T') /* Read Cal factors */
	{
		Stream_Reqeust = 0;
	}

	if (cmd=='C') /* Read Cal factors */
	{
		Cal_Reqeust = Cal_Reqeust + 1;
	}
	
}

void	CMD_RX_Parser(void)
{
	/*
	if ((RXCHAR[0]=='U') && (RXCHAR[1]=='0')) RemoteSw_Up = 0;
	if ((RXCHAR[0]=='U') && (RXCHAR[1]=='1')) RemoteSw_Up = 1;

	if ((RXCHAR[0]=='D') && (RXCHAR[1]=='0')) RemoteSw_Dn = 0;
	if ((RXCHAR[0]=='D') && (RXCHAR[1]=='1')) RemoteSw_Dn = 1;
	 
	if ((RXCHAR[0]=='L') && (RXCHAR[1]=='0')) RemoteSw_Local = 0;
	if ((RXCHAR[0]=='L') && (RXCHAR[1]=='1')) RemoteSw_Local = 1;
	 
	if ((RXCHAR[0]=='R') && (RXCHAR[1]=='0')) RemoteSw_RunStop = 0;
	if ((RXCHAR[0]=='R') && (RXCHAR[1]=='1')) RemoteSw_RunStop = 1;

	if ((RXCHAR[0]=='P') && (RXCHAR[1]=='0')) RemoteSw_Purge = 0;
	if ((RXCHAR[0]=='P') && (RXCHAR[1]=='1')) RemoteSw_Purge = 1;
	*/
}




void	SaveEEPROM(void)
{
	
	eeprom_write_dword( (uint32_t *)0  ,  0xFFFFFFFF );
	eeprom_write_dword( (uint32_t *)4  ,  0xFFFFFFFF );
	eeprom_write_dword( (uint32_t *)8  ,  0xFFFFFFFF );
	eeprom_write_dword( (uint32_t *)12 ,  0xFFFFFFFF );
	

	eeprom_write_dword( (uint32_t *)0  ,  CalFactor[0]   );
	eeprom_write_dword( (uint32_t *)4  ,  CalFactor[1]   );
	eeprom_write_dword( (uint32_t *)8  ,  CalFactor[2]   );
	eeprom_write_dword( (uint32_t *)12 ,  CalFactor[3]   );
	

}


void	LoadEEPROM(void)
{
	CalFactor[0] = eeprom_read_dword( (uint32_t *)0 );
	CalFactor[1] = eeprom_read_dword( (uint32_t *)4 );
	CalFactor[2] = eeprom_read_dword( (uint32_t *)8 );
	CalFactor[3] = eeprom_read_dword( (uint32_t *)12 );

	if ((CalFactor[0]<10) || (CalFactor[0]>90000)) CalFactor[0] = 10000;
	if ((CalFactor[1]<10) || (CalFactor[1]>90000)) CalFactor[1] = 10000;
	if ((CalFactor[2]<10) || (CalFactor[2]>90000)) CalFactor[2] = 10000;
	if ((CalFactor[3]<10) || (CalFactor[3]>90000)) CalFactor[3] = 10000;
}



#define DGUS_RUN_SW		0x2131
#define DGUS_STOP_SW	0x4032
#define DGUS_PSTART_SW	0x2333
#define DGUS_PSTOP_SW	0x2434
#define DGUS_LOCAL_SW	0x2535
#define DGUS_RMT_SW		0x5E36


uint8	DGUS_RxBuff[20];



void DGUS_Rx_Frame_Run(void)
{
	/*
	// first is len. others is data
	uint16	addr = 0;
	uint16	va  = 0;
	
	addr = (((uint16)DGUS_RxBuff[2]) << 8) + (uint16)DGUS_RxBuff[3];
	va   = (((uint16)DGUS_RxBuff[5]) << 8) + (uint16)DGUS_RxBuff[6];
	
	if (addr==0) // switch input
	{
		Local_Remote_Saved = RemoteSw_Local;
		
		if (va==DGUS_RUN_SW)    RemoteSw_RunStop = 1;
		if (va==DGUS_STOP_SW)   RemoteSw_RunStop = 0;
		if (va==DGUS_PSTART_SW) RemoteSw_Purge = 1;
		if (va==DGUS_PSTOP_SW)  { RemoteSw_Purge = 0; if (Fan3MinCounter>1) {Fan3MinCounter=1;}  }
		if (va==DGUS_LOCAL_SW)  { RemoteSw_Local = 0; }
		if (va==DGUS_RMT_SW)	{ RemoteSw_Local = 1; }
			
		if (Local_Remote_Saved != RemoteSw_Local)	
		{
			if (RemoteSw_Local==1) { Last_SV_DGUS = SV; } // to remote ?
			if (RemoteSw_Local==0) { SV = Last_SV_DGUS; LastContentsCrc=0xff; } // to local ?
		}
		
			
	}
	
	if (addr==0x5000)	{ if (va>SV_range) va=SV_range; SV = va; LastContentsCrc=0xff;  LocalSV=SV; }

	if (addr==0x5110)	SV_range        = va;
	if (addr==0x5120)	Control_Voltage = va;
	if (addr==0x5130)
	{
		Control_Freq    = va;
		
		if (va==1979) // special routine for reset total_timer by Freq set by 1979
		{
			if (Totaltime!=0)
			{
				Totaltime = 0;	
				Request_SaveEEPROM(); 
			}
		}
	}
	if (addr==0x5140)	Control_Gain    = va;
	*/
		
}

uint8	headercheck_1 = 0xFF;
uint8	headercheck_2 = 0xFF;
uint8	header_ok = 0;
uint16	DGUS_timeout = 0;
uint8	DGUS_Rx_Len = 0;

void Rx_Char( uint8 rxc )
{
	
	if (header_ok==0)
	{
		headercheck_1 = headercheck_2;
		headercheck_2 = rxc;
		if ((headercheck_1==0x5A) && (headercheck_2==0xA5))
		{
			header_ok = 1;
			DGUS_timeout = 0;
			DGUS_Rx_Len = 0;
			headercheck_1 = 0;
			headercheck_2 = 0;
			
		}
	} else
	{
		DGUS_RxBuff[DGUS_Rx_Len] = rxc;
		DGUS_Rx_Len++;
		
		if (DGUS_Rx_Len>DGUS_RxBuff[0])
		{
			
			header_ok = 0;		
			DGUS_timeout = 0;
			DGUS_Rx_Len = 0;
			headercheck_1 = 0;
			headercheck_2 = 0;
			
			DGUS_Rx_Frame_Run();
		}
	}
}


uint8	DGUS_TX_BUFF[20];
void DGUS_TX(uint8 len , uint8 * buff_)
{
	uint8 r;
	DGUS_TX_BUFF[0] = 0x5A;
	DGUS_TX_BUFF[1] = 0xA5;
	DGUS_TX_BUFF[2] = len;

	for (r=0;r<len;r++)
	{
		DGUS_TX_BUFF[r+3] = buff_[r];
	}

	UART_Put_Buff(len+3,DGUS_TX_BUFF);
}

uint8 dgusstr[10];

void	DGUS_Write_Var4(uint16 addr, sint32 value)
{
	dgusstr[0] = 0x82;
	dgusstr[1] = (addr >> 8);
	dgusstr[2] = (addr & 0x00FF);
	dgusstr[3] = (value >> 24);
	dgusstr[4] = (value >> 16);
	dgusstr[5] = (value >> 8);
	dgusstr[6] = (value & 0x00FF);
	
	
	DGUS_TX(7,dgusstr);
}

void	DGUS_Write_Var(uint16 addr, sint16 value)
{
	dgusstr[0] = 0x82;
	dgusstr[1] = (addr >> 8);
	dgusstr[2] = (addr & 0x00FF);
	dgusstr[3] = (value >> 8);
	dgusstr[4] = (value & 0x00FF);
	
	DGUS_TX(5,dgusstr);
}


void	Change_DGUS_Screen( uint8 screen_num )
{
	// 5a a5 07 82 00 84 5a 01 00 00
	dgusstr[0] = 0x82;
	dgusstr[1] = 0x00;
	dgusstr[2] = 0x84;
	dgusstr[3] = 0x5a;
	dgusstr[4] = 0x01;
	dgusstr[5] = 0x00;
	dgusstr[6] = screen_num;
	
	DGUS_TX(7,dgusstr); _delay_ms(10);
}



void	vInit(void)
{
	// vInitMax1167();
	
	INIT_HX711();
	
	UART2_vReset();
	UART2_vOpenPort(0 ,   9600 , CONF_8BIT_NOPAR_1STOP); // CH0 = LCD
	UART2_vOpenPort(1 ,   9600 , CONF_8BIT_NOPAR_1STOP); // CH0 = COMM
	

	// RTC Clock Setup
	TIMSK = 1; // timer0 overflow intr enable.
	TCCR0 = 5; // clk / 256 / 128 = 450 Hz
	
	// setup ADC
	ADMUX = 0x46; // 01000110
	ADCSRA = 0xD7; // 10000111 // Start ADC
}

uint16	tenmiliseccounter;
uint8	SecEvent;
ISR(TIMER0_OVF_vect)
{
	tenmiliseccounter++;
	if (tenmiliseccounter>=450)
	{
		tenmiliseccounter = 0;
		SecEvent++;
	}
}


#define GAIN_1		0
#define GAIN_2		1

uint8	ADC_ConversionStarted = 0;
void	ADC_vStart(uint8 ch , uint8 gain)
{
	// ADCSRA = 0b11010111; /* ADC conversion start with single start. Prescale = 115kHz */
	// ADCSRA = 0b01010111; /* turn off ADC */

	ADCSRA = 0b10010111;
	ADMUX = (0b01000000) | ch; /* REF = 01 : external AVCC REF, */
	ADCSRA = 0b11010111; /* ADC conversion start with single start. Prescale = 115kHz */
	ADC_ConversionStarted = 1;
}


uint16	ADC_u16ReadADC(void)
{
	uint16	lo,hi;
	
	if (ADC_ConversionStarted==0)
	{
		return (0);
	} else
	{
		while ((ADCSRA & 0x40) > 0) /*wait until conversion completed*/
		{
		}
		ADC_ConversionStarted = 0;
		lo = ADCL;
		hi = ADCH;
		
		// ADCSRA = 0b01010111;
		
		return ((hi<<8) | (lo));
	}
}



float	fADC_Raw[5];
uint32  RefV , BattV;
float	X,Y,Z,T;

float	X_,Y_,Z_,T_;

char text[50];

float	Read_Avg(uint8 ch)
{
	float raw;
	uint16 r;
	
	raw = 0;
	for (r=0;r<320;r++)
	{
		raw = raw + (float)ReadMax1167(ch);
	}
	raw = raw / 320.0f;	

	return (raw);
}


signed int main(void)
{
	cli(); // global intr disable
	wdt_disable();
	vInit();
	sei();
	LoadEEPROM();

	_delay_ms(500);
	
	Task_HX711();

	while (1)
	{
		Task_HX711();
		
		fADC_Raw[0] = HX711_s32Raw[HX711_X];
		fADC_Raw[1] = HX711_s32Raw[HX711_Y];
		fADC_Raw[2] = HX711_s32Raw[HX711_Z];
		fADC_Raw[3] = HX711_s32Raw[HX711_Temp];
		fADC_Raw[4] = HX711_s32Raw[HX711_Ref]; // 2.5V ref

		
		// read raw analog data
		ADC_vStart( 6 , 0 ); _delay_ms(20);
		RefV = ADC_u16ReadADC();
		ADC_vStart( 7 , 0 ); _delay_ms(20);
		BattV = ADC_u16ReadADC();

		BattV = round(100.0f * 5.0649f * ((float)BattV) / 1023.0f); 
		RefV  = round(100.0f * 5.0649f * ((float)RefV) / 1023.0f);

		if (fADC_Raw[4]>0.0f)
		{
			X = 2.5f*fADC_Raw[0]/fADC_Raw[4]; // calc to Voltage
			X = (X-2.5f) * 45.4545f * ((float)CalFactor[0])/10000.0f; // 2.5V is Zero, 45.45uT/V is SCale
		
			Y = 2.5f*fADC_Raw[1]/fADC_Raw[4]; // calc to Voltage
			Y = (Y-2.5f) * 45.4545f * ((float)CalFactor[1])/10000.0f; // 2.5V is Zero, 45.45uT/V is SCale

			Z = 2.5f*fADC_Raw[2]/fADC_Raw[4]; // calc to Voltage
			Z = (Z-2.5f) * 45.4545f * ((float)CalFactor[2])/10000.0f; // 2.5V is Zero, 45.45uT/V is SCale

			T = 2.5f*fADC_Raw[3]/fADC_Raw[4]; // calc to Voltage
			T = (T-2.5f)*1000 * 0.025f * ((float)CalFactor[3])/10000.0f-1.0f; // 2.5V is Zero, 0.25oC/mV 273.17K = 0oC
		}


		X_=X_*0.0 + X*1.0;
		Y_=Y_*0.0 + Y*1.0;
		Z_=Z_*0.0 + Z*1.0;
		T_=T_*0.0 + T*1.0;

		DGUS_Write_Var4(0x5000,(sint32)round(X_*1000)); _delay_ms(5);
		DGUS_Write_Var4(0x5010,(sint32)round(Y_*1000)); _delay_ms(5);
		DGUS_Write_Var4(0x5020,(sint32)round(Z_*1000)); _delay_ms(5);
		DGUS_Write_Var(0x5030,(sint16)round(T_*10)); _delay_ms(5);
		DGUS_Write_Var(0x5040,(sint16)BattV); _delay_ms(25);
		
		
		if (Stream_Reqeust>0)
		{
			UART_vPut(1,"$I,");
			dtostrf(X_,8,3,text); UART_vPut(1,text); UART_vPut(1,",");
			dtostrf(Y_,8,3,text); UART_vPut(1,text); UART_vPut(1,",");
			dtostrf(Z_,8,3,text); UART_vPut(1,text); UART_vPut(1,",");
			dtostrf(T_,5,1,text); UART_vPut(1,text); UART_vPut(1,",");
			
			dtostrf(((float)BattV)/100.0f,5,2,text); UART_vPut(1,text); UART_vPut(1,",");
			dtostrf(((float)RefV)/100.0f,5,2,text); UART_vPut(1,text); UART_vPut(1,"#\r\n");
			
			Stream_Reqeust = Stream_Reqeust - 1;
		}

		if (Cal_Reqeust>0)
		{
			UART_vPut(1,"$C,");
			dtostrf(((float)CalFactor[0])/10000.0,6,4,text); UART_vPut(1,text); UART_vPut(1,",");
			dtostrf(((float)CalFactor[1])/10000.0,6,4,text); UART_vPut(1,text); UART_vPut(1,",");
			dtostrf(((float)CalFactor[2])/10000.0,6,4,text); UART_vPut(1,text); UART_vPut(1,",");
			dtostrf(((float)CalFactor[3])/10000.0,6,4,text); UART_vPut(1,text); UART_vPut(1,"#\r\n");
			
			Cal_Reqeust = Cal_Reqeust - 1;;
		}
		
		
		if (SaveEEP_Reqeust)
		{
			SaveEEP_Reqeust = 0;
			SaveEEPROM();
			Cal_Reqeust = 1;
		}
	}

	return (0);
}


/*  protocol examples
$I,  20.533,   8.935,  48.418, 22.9, 4.27, 2.51#
$C,1.0000,1.0000,1.0000,1.0000#
*/