nuttx-apps/examples/hx711/hx711_main.c
Michał Łyszczek 8669861312 examples/hx711: add new program to test hx711 chip
Signed-off-by: Michał Łyszczek <michal.lyszczek@bofc.pl>
2024-03-02 12:34:39 +08:00

362 lines
9.8 KiB
C

/****************************************************************************
* apps/examples/hx711/hx711_main.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/analog/hx711.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <sys/ioctl.h>
/****************************************************************************
* Private Types
****************************************************************************/
struct hx711_config
{
char dev[32];
char dump;
char channel;
unsigned char gain;
unsigned average;
unsigned loops;
float precision;
int val_per_unit;
int sign;
} g_hx711_config;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: hx711_print_help
*
* Description:
* Prints help onto stdout.
*
****************************************************************************/
static void hx711_print_help(const char *progname)
{
printf("usage: %s [-d <device>] [options]\n"
"\n"
"\t-h print this help message\n"
"\t-d<path> path to hx711 device, default: /dev/hx711_0\n"
"\t-t<prec> tares the scale with specified precision, might"
"take few seconds to complete.\n"
"\t If you set value per unit, precision is in units, "
"otherwise it's raw values.\n"
"\t If units are used, float can be passed like 0.1\n"
"\t-v<val> value read that coresponds to one unit. This value "
"has to be\n"
"\t calibrated first before it's known\n"
"\t-s reverse sign, if values decreses when mass increases, "
"pass this\n"
"\t-D dumps current device settings (like, average, channel, "
"gain etc.)\n"
"\t-a<avg> set how many samples should be averaged before "
"returning value,\n"
"\t values [1..%d] are valid\n"
"\t-c<chan> set channel to read (either 'a' or 'b' is valid)\n"
"\t-g<gain> set adc gain, for channel 'a' 64 and 128 are valid,\n"
"\t for channel 'b', only 64 is valid\n"
"\t-r<num> read this number of samples before exiting, samples "
"will be printed\n"
"\t on stdout as string, one sample per line\n"
"\n"
"Check documentation for full description\n",
progname, HX711_MAX_AVG_SAMPLES);
}
/****************************************************************************
* Name: hx711_parse_args
*
* Description:
* Parses command line arguments
*
****************************************************************************/
static int hx711_parse_args(int argc, FAR char *argv[])
{
int opt;
memset(&g_hx711_config, 0x00, sizeof(g_hx711_config));
while ((opt = getopt(argc, argv, "hd:Dt:a:c:g:r:v:s")) != -1)
{
switch (opt)
{
case 'h':
hx711_print_help(argv[0]);
return 1;
case 'd':
strcpy(g_hx711_config.dev, optarg);
break;
case 't':
g_hx711_config.precision = atof(optarg);
break;
case 'D':
g_hx711_config.dump = 1;
break;
case 'a':
g_hx711_config.average = atoi(optarg);
break;
case 'c':
g_hx711_config.channel = optarg[0];
break;
case 'g':
g_hx711_config.gain = atoi(optarg);
break;
case 'r':
g_hx711_config.loops = atoi(optarg);
break;
case 's':
g_hx711_config.sign = -1;
break;
case 'v':
g_hx711_config.val_per_unit = atoi(optarg);
break;
default:
fprintf(stderr, "Invalid option, run with -h for help\n");
return 1;
}
}
if (g_hx711_config.dev[0] == '\0')
{
strcpy(g_hx711_config.dev, "/dev/hx711_0");
}
return 0;
}
/****************************************************************************
* Name: hx711_set_options
*
* Description:
* Set hx711 options if they were specified on command line
*
* Input Parameters:
* fd - opened hx711 instance
*
****************************************************************************/
int hx711_set_options(int fd)
{
int ret;
/* Set channel to read */
if (g_hx711_config.channel > 0)
{
if ((ret = ioctl(fd, HX711_SET_CHANNEL, g_hx711_config.channel)))
{
fprintf(stderr, "Failed to set channel to %c, error: %s\n",
g_hx711_config.channel, strerror(errno));
return -1;
}
}
/* Set channel ADC gain */
if (g_hx711_config.gain > 0)
{
if ((ret = ioctl(fd, HX711_SET_GAIN, g_hx711_config.gain)))
{
fprintf(stderr, "Failed to set gain to %d, error: %s\n",
g_hx711_config.gain, strerror(errno));
return -1;
}
}
/* Set how many samples to average before printing value */
if (g_hx711_config.average > 0)
{
if ((ret = ioctl(fd, HX711_SET_AVERAGE, g_hx711_config.average)))
{
fprintf(stderr, "Failed to set average to %d, error: %s\n",
g_hx711_config.average, strerror(errno));
return -1;
}
}
/* Set if sign should be reversed or not */
if (g_hx711_config.sign)
{
if ((ret = ioctl(fd, HX711_SET_SIGN, &g_hx711_config.sign)))
{
fprintf(stderr, "Failed to set sign to %d, error: %s\n",
g_hx711_config.sign, strerror(errno));
return -1;
}
}
/* Set what value coresponds to 1 unit */
if (g_hx711_config.val_per_unit > 0)
{
if ((ret = ioctl(fd, HX711_SET_VAL_PER_UNIT,
g_hx711_config.val_per_unit)))
{
fprintf(stderr, "Failed to set val per unit to %d, error: %s\n",
g_hx711_config.val_per_unit, strerror(errno));
return -1;
}
}
return 0;
}
/****************************************************************************
* Name: hx711_dump_options
*
* Description:
* Reads current hx711 settings from kernel driver and dumps them on stdout
*
****************************************************************************/
static void hx711_dump_options(int fd)
{
unsigned average;
unsigned char gain;
char channel;
unsigned val_per_unit;
ioctl(fd, HX711_GET_GAIN, &gain);
ioctl(fd, HX711_GET_CHANNEL, &channel);
ioctl(fd, HX711_GET_AVERAGE, &average);
ioctl(fd, HX711_GET_VAL_PER_UNIT, &val_per_unit);
printf("Current settings for: %s\n", g_hx711_config.dev);
printf("average.............: %u\n", average);
printf("channel.............: %c\n", channel);
printf("gain................: %d\n", gain);
printf("value per unit......: %u\n", val_per_unit);
}
/****************************************************************************
* Name: hx711_read_and_dump
*
* Description:
* Reads configured number of samples, and dumps them to terminal.
*
****************************************************************************/
static int hx711_read_and_dump(int fd)
{
int32_t sample;
while (g_hx711_config.loops--)
{
if (read(fd, &sample, sizeof(sample)) != sizeof(sample))
{
fprintf(stderr, "Error reading from %s, error %s\n",
g_hx711_config.dev, strerror(errno));
return -1;
}
printf("%"PRId32"\n", sample);
}
return 0;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* hx711
****************************************************************************/
int main(int argc, FAR char *argv[])
{
int fd;
if (hx711_parse_args(argc, argv))
{
return 1;
}
fd = open(g_hx711_config.dev, O_RDONLY);
if (fd < 0)
{
fprintf(stderr, "Failed to open %s, error: %s\n", g_hx711_config.dev,
strerror(errno));
return 1;
}
if (hx711_set_options(fd))
{
close(fd);
return 1;
}
if (g_hx711_config.precision)
{
ioctl(fd, HX711_GET_VAL_PER_UNIT, &g_hx711_config.val_per_unit);
if (g_hx711_config.val_per_unit)
{
printf("Taring with %fg precision\n", g_hx711_config.precision);
}
if (ioctl(fd, HX711_TARE, &g_hx711_config.precision))
{
perror("Failed to tare the scale");
close(fd);
return 1;
}
}
if (g_hx711_config.dump)
{
hx711_dump_options(fd);
}
if (g_hx711_config.loops)
{
hx711_read_and_dump(fd);
}
close(fd);
return 0;
}