HX711 bibliotek för STM32 - Hur kan jag använda SPI?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
DanielM
Inlägg: 2193
Blev medlem: 5 september 2019, 14:19:58

HX711 bibliotek för STM32 - Hur kan jag använda SPI?

Inlägg av DanielM »

Hej!

Nytt bibliotek här! Denna gång har jag skrivit av HX711 viktgivare från bogde (som har MIT licens! :wink: för er sörrhommel) till STM32. Biblioteket fungerar! Jag delar med mig av det till er. Men jag har en fråga. Kan man använda SPI på detta bibliotek? Alltså halv-SPI då man bara läser från HX711.

Titta på denna kod. Här har vi alltså en digital utgång som kallas PD_SCK. Den pulserar.

Kod: Markera allt

	// Set the channel and the gain factor for the next reading using the clock pin.
	for (unsigned int i = 0; i < hx->GAIN; i++) {
		HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_SET);
		for (uint16_t i = 0; i < SMALL_DELAY; i++) {} // Small delay
		HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_RESET);
		for (uint16_t i = 0; i < SMALL_DELAY; i++) { } // Small delay
	}
Sedan har vi denna kod. Den pulserar också. Där DOUT är alltså en ingång på STM32 med ett pull-up motstånd aktiverat.

Kod: Markera allt

static uint8_t shiftIn(HX711 *hx, uint8_t bitOrder) {
	uint8_t value = 0;
	uint8_t i;

	for (i = 0; i < 8; ++i) {
		HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_SET);
		for (uint16_t i = 0; i < SMALL_DELAY; i++) {
		} // Small delay
		if (bitOrder == LSBFIRST)
			value |= HAL_GPIO_ReadPin(hx->DOUT_Port, hx->DOUT_Pin) << i;
		else
			value |= HAL_GPIO_ReadPin(hx->DOUT_Port, hx->DOUT_Pin) << (7 - i);
		HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_RESET);
		for (uint16_t i = 0; i < SMALL_DELAY; i++) {
		} // Small delay
	}
	return value;
}
Kan man använda SPI istället här?

Arbetsexempel:

Kod: Markera allt

#include "main.h"
#include "HX711/HX711.h"

HX711 hx;

int main(void)
{

  HX711_begin(&hx, HX711_PD_SCK_GPIO_Port, HX711_PD_SCK_Pin, HX711_DOUT_GPIO_Port, HX711_DOUT_Pin, 128);
  HX711_set_scale(&hx, 2280.f); // Set scale
  HX711_tare(&hx, 0); // Reset scale to 0

    while (1)
    {
    	  float value = HX711_get_units(&hx, 10);
    	  char text[20];
    	  sprintf(text, "%f", value);
  }
}
HX711.c

Kod: Markera allt

#include "HX711.h"

// Make shiftIn() be aware of clockspeed for
// faster CPUs like ESP32, Teensy 3.x and friends.
// See also:
// - https://github.com/bogde/HX711/issues/75
// - https://github.com/arduino/Arduino/issues/6561
// - https://community.hiveeyes.org/t/using-bogdans-canonical-hx711-library-on-the-esp32/539
static uint8_t shiftIn(HX711 *hx, uint8_t bitOrder) {
	uint8_t value = 0;
	uint8_t i;

	for (i = 0; i < 8; ++i) {
		HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_SET);
		for (uint16_t i = 0; i < SMALL_DELAY; i++) {
		} // Small delay
		if (bitOrder == LSBFIRST)
			value |= HAL_GPIO_ReadPin(hx->DOUT_Port, hx->DOUT_Pin) << i;
		else
			value |= HAL_GPIO_ReadPin(hx->DOUT_Port, hx->DOUT_Pin) << (7 - i);
		HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_RESET);
		for (uint16_t i = 0; i < SMALL_DELAY; i++) {
		} // Small delay
	}
	return value;
}

void HX711_begin(HX711 *hx, GPIO_TypeDef* PD_SCK_Port, uint16_t PD_SCK_Pin, GPIO_TypeDef* DOUT_Port, uint16_t DOUT_Pin, uint8_t gain) {
	// Digital output
	hx->PD_SCK_Port = PD_SCK_Port;
	hx->PD_SCK_Pin = PD_SCK_Pin;
	// Digital pull-up input
	hx->DOUT_Port = DOUT_Port;
	hx->DOUT_Pin = DOUT_Pin;
	// Set gain
	HX711_set_gain(hx, gain);
}

bool HX711_is_ready(HX711 *hx) {
	return !HAL_GPIO_ReadPin(hx->DOUT_Port, hx->DOUT_Pin);
}

void HX711_set_gain(HX711 *hx, uint8_t gain) {
	switch (gain) {
	case 128:		// channel A, gain factor 128
		hx->GAIN = 1;
		break;
	case 64:		// channel A, gain factor 64
		hx->GAIN = 3;
		break;
	case 32:		// channel B, gain factor 32
		hx->GAIN = 2;
		break;
	}
}

long HX711_read(HX711 *hx) {

	// Wait for the chip to become ready.
	HX711_wait_ready(hx, 0);

	// Define structures for reading data into.
	unsigned long value = 0;
	uint8_t data[3] = { 0 };
	uint8_t filler = 0x00;

	// Pulse the clock pin 24 times to read the data.
	data[2] = shiftIn(hx, MSBFIRST);
	data[1] = shiftIn(hx, MSBFIRST);
	data[0] = shiftIn(hx, MSBFIRST);

	// Set the channel and the gain factor for the next reading using the clock pin.
	for (unsigned int i = 0; i < hx->GAIN; i++) {
		HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_SET);
		for (uint16_t i = 0; i < SMALL_DELAY; i++) {} // Small delay
		HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_RESET);
		for (uint16_t i = 0; i < SMALL_DELAY; i++) { } // Small delay
	}

	// Replicate the most significant bit to pad out a 32-bit signed integer
	if (data[2] & 0x80) {
		filler = 0xFF;
	} else {
		filler = 0x00;
	}

	// Construct a 32-bit signed integer
	value = (unsigned long) (filler << 24)
			| (unsigned long) (data[2] << 16)
			| (unsigned long) (data[1] << 8)
			| (unsigned long) (data[0]);

	return (long) value;
}

void HX711_wait_ready(HX711 *hx, unsigned long delay_ms) {
	// Wait for the chip to become ready.
	// This is a blocking implementation and will
	// halt the sketch until a load cell is connected.
	while (!HX711_is_ready(hx)) {
		// Probably will do no harm on AVR but will feed the Watchdog Timer (WDT) on ESP.
		// https://github.com/bogde/HX711/issues/73
		HAL_Delay(delay_ms);
	}
}

bool HX711_wait_ready_retry(HX711 *hx, int retries, unsigned long delay_ms) {
	// Wait for the chip to become ready by
	// retrying for a specified amount of attempts.
	// https://github.com/bogde/HX711/issues/76
	int count = 0;
	while (count < retries) {
		if (HX711_is_ready(hx)) {
			return true;
		}
		HAL_Delay(delay_ms);
		count++;
	}
	return false;
}

bool HX711_wait_ready_timeout(HX711 *hx, unsigned long timeout, unsigned long delay_ms) {
	// Wait for the chip to become ready until timeout.
	// https://github.com/bogde/HX711/pull/96
	unsigned long millisStarted = HAL_GetTick();
	while (HAL_GetTick() - millisStarted < timeout) {
		if (HX711_is_ready(hx)) {
			return true;
		}
		HAL_Delay(delay_ms);
	}
	return false;
}

long HX711_read_average(HX711 *hx, uint8_t times) {
	long sum = 0;
	for (uint8_t i = 0; i < times; i++) {
		sum += HX711_read(hx);
		// Probably will do no harm on AVR but will feed the Watchdog Timer (WDT) on ESP.
		// https://github.com/bogde/HX711/issues/73
		HAL_Delay(0);
	}
	return sum / times;
}

float HX711_get_value(HX711 *hx, uint8_t times) {
	return HX711_read_average(hx, times) - hx->OFFSET;
}

float HX711_get_units(HX711 *hx, uint8_t times) {
	return HX711_get_value(hx, times) / hx->SCALE;
}

void HX711_tare(HX711 *hx, uint8_t times) {
	float sum = HX711_read_average(hx, times);
	HX711_set_offset(hx, sum);
}

void HX711_set_scale(HX711 *hx, float scale) {
	hx->SCALE = scale;
}

float HX711_get_scale(HX711 *hx) {
	return hx->SCALE;
}

void HX711_set_offset(HX711 *hx, long offset) {
	hx->OFFSET = offset;
}

long HX711_get_offset(HX711 *hx) {
	return hx->OFFSET;
}

void HX711_power_down(HX711 *hx) {
	HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_SET);
}

void HX711_power_up(HX711 *hx) {
	HAL_GPIO_WritePin(hx->PD_SCK_Port, hx->PD_SCK_Pin, GPIO_PIN_RESET);
}

HX771.h

Kod: Markera allt

#ifndef SRC_HX711_HX711_H_
#define SRC_HX711_HX711_H_

#include "main.h"
#include "stdbool.h"

#define SMALL_DELAY 10
#define LSBFIRST 0
#define MSBFIRST 1
typedef struct {
	// Power Down and Serial Clock Input Pin - This must be output!
	GPIO_TypeDef *PD_SCK_Port;
	uint16_t PD_SCK_Pin;

	// Serial Data Output Pin - This must be pull-up!
	GPIO_TypeDef *DOUT_Port;
	uint16_t DOUT_Pin;

	uint8_t GAIN;		// amplification factor
	long OFFSET;		// used for tare weight
	float SCALE;		// used to return weight in grams, kg, ounces, whatever
} HX711;

// Initialize library with data output pin, clock input pin and gain factor.
// Channel selection is made by passing the appropriate gain:
// - With a gain factor of 64 or 128, channel A is selected
// - With a gain factor of 32, channel B is selected
// The library default is "128" (Channel A).
void HX711_begin(HX711 *hx, GPIO_TypeDef* PD_SCK_Port, uint16_t PD_SCK_Pin, GPIO_TypeDef* DOUT_Port, uint16_t DOUT_Pin, uint8_t gain);

// Check if HX711 is ready
// from the datasheet: When output data is not ready for retrieval, digital output pin DOUT is high. Serial clock
// input PD_SCK should be low. When DOUT goes to low, it indicates data is ready for retrieval.
bool HX711_is_ready(HX711 *hx);

// Wait for the HX711 to become ready
void HX711_wait_ready(HX711 *hx, unsigned long delay_ms);
bool HX711_wait_ready_retry(HX711 *hx, int retries, unsigned long delay_ms);
bool HX711_wait_ready_timeout(HX711 *hx, unsigned long timeout, unsigned long delay_ms);

// set the gain factor; takes effect only after a call to read()
// channel A can be set for a 128 or 64 gain; channel B has a fixed 32 gain
// depending on the parameter, the channel is also set to either A or B
void HX711_set_gain(HX711 *hx, uint8_t gain);

// waits for the chip to be ready and returns a reading
long HX711_read(HX711 *hx);

// returns an average reading; times = how many times to read
long HX711_read_average(HX711 *hx, uint8_t times);

// returns (read_average() - OFFSET), that is the current value without the tare weight; times = how many readings to do
float HX711_get_value(HX711 *hx, uint8_t times);

// returns get_value() divided by SCALE, that is the raw value divided by a value obtained via calibration
// times = how many readings to do
float HX711_get_units(HX711 *hx, uint8_t times);

// set the OFFSET value for tare weight; times = how many times to read the tare value
void HX711_tare(HX711 *hx, uint8_t times);

// set the SCALE value; this value is used to convert the raw data to "human readable" data (measure units)
void HX711_set_scale(HX711 *hx, float scale);

// get the current SCALE
float HX711_get_scale(HX711 *hx);

// set OFFSET, the value that's subtracted from the actual reading (tare weight)
void HX711_set_offset(HX711 *hx, long offset);

// get the current OFFSET
long HX711_get_offset(HX711 *hx);

// puts the chip into power down mode
void HX711_power_down(HX711 *hx);

// wakes up the chip after power down mode
void HX711_power_up(HX711 *hx);

#endif /* SRC_HX711_HX711_H_ */
DanielM
Inlägg: 2193
Blev medlem: 5 september 2019, 14:19:58

Re: HX711 bibliotek för STM32 - Hur kan jag använda SPI?

Inlägg av DanielM »

Har kollat runt lite på Arduino-bibliotek och alla verkar bit-langa. Så antar att jag får göra det också. :)
Varsågoda!
Skriv svar