有没有大神移植一个HX711称重芯片模块的软件包

发布于 2020-08-10 03:03:53

感觉HX711模块应用范围还比较广,以前用arduino,里面的hx711库非常好用,可惜自己水平有限,没有移植成功到rtt,哪个大神帮忙指导一下,或者移植一个。

查看更多

关注者
0
被浏览
469
armink
armink 2020-08-11

巧了,N 年前我整过这个,分享出来哈,觉得好用希望你能做成软件包

/*
 *   File name: hx711.c
 *  Created on: 2016年3月3日
 *      Author: armink
 * Description: HX711 压力检测芯片驱动
 */

#define LOG_TAG    "HX711"

#include <elog.h>
#include <stm32f4xx_conf.h>
#include <rtthread.h>
#include <easyflash.h>
#include <ef_types.h>
#include <string.h>
#include <stdlib.h>
#include <finsh.h>

#define DOUT_GPIOX                     GPIOA
#define DOUT_PIN                       GPIO_Pin_6
#define DOUT_EXTI_PORT                 EXTI_PortSourceGPIOA
#define DOUT_EXTI_PIN                  EXTI_PinSource6
#define PD_SCK_GPIOX                   GPIOA
#define PD_SCK_PIN                     GPIO_Pin_7
/* SCK 引脚输出高 */
#define PD_SCK_H                       GPIO_SetBits(PD_SCK_GPIOX, PD_SCK_PIN)
/* SCK 引脚输出低 */
#define PD_SCK_L                       GPIO_ResetBits(PD_SCK_GPIOX, PD_SCK_PIN)
/* 获取 DOUT 引脚输出状态 */
#define DOUT                           GPIO_ReadInputDataBit(DOUT_GPIOX, DOUT_PIN)
/* 转换稳定时间(设定:500ms,手册中默认为 400ms) */
#define CONVERT_STABLE_TIME            RT_TICK_PER_SECOND * 500 / 1000
/* 转换周期(设定为 10hz 100ms 转换一次) */
#define CONVERT_PERIOD_TIME            RT_TICK_PER_SECOND * 100 / 1000
/* 传感器检测压力的最大值 */
#define SENSOR_MAX_PRESSURE            60*9.8
/* 传感器检测压力的最小值 */
#define SENSOR_MIN_PRESSURE            0*9.8

/* 校准的偏移量 */
static double cali_offset;
/* 获取压力锁,避免并发获取 */
static struct rt_mutex read_lock;
/* 初始化完成标识 */
static bool init_ok = false;
/* HX711事件 */
static struct rt_event event_hx711dout;
/* HX711已准备好数据事件 */
#define EVENT_HX711DOUT_OK             1<<0

static void delay_us(uint32_t n);
static void set_hx711_dout_irq(bool type);

/**
 * HX711 模块初始化
 */
void hx711_init(void) {
    /* 硬件初始化 */
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = PD_SCK_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DOUT_GPIOX, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = DOUT_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    GPIO_Init(PD_SCK_GPIOX, &GPIO_InitStructure);

    //只要我们使用到外部中断,就必须打开SYSCFG时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
    SYSCFG_EXTILineConfig(DOUT_EXTI_PORT, DOUT_EXTI_PIN);
    EXTI_ClearITPendingBit(EXTI_Line6);
    EXTI_InitStructure.EXTI_Line = EXTI_Line6;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = DISABLE;
    EXTI_Init(&EXTI_InitStructure);
    //中断通道配置在打印头中一样
    NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* 上电初始化 */
    PD_SCK_L;
    PD_SCK_H;
    delay_us(160 + 5);
    PD_SCK_L;
    /* 等待 HX711 内部 AD 转换稳定 */
    uint32_t start_time = rt_tick_get();
    while(DOUT) {
        if(rt_tick_get() - start_time > CONVERT_STABLE_TIME) {
            log_e("错误:压力检测模块初始化失败!");
            break;
        }
        /* 10ms 查询一次 */
        rt_thread_delay(RT_TICK_PER_SECOND * 10 / 1000);
    }
    /* 获取校准的偏移量 */
    cali_offset = ef_get_double("hx711_offset");
    /* 初始化锁 */
    rt_mutex_init(&read_lock, "HX711", RT_IPC_FLAG_FIFO);
    /* 初始化事件 */
    rt_event_init(&event_hx711dout, "hx711dout", RT_IPC_FLAG_PRIO);
    /* 初始化完成 */
    init_ok = true;
}

/**
 * 获取当前压力(目前只使用 A 通道,并且为线程安全的方式)
 *
 * @return 采集回来的实际压力(单位:N)
 */
double hx711_get_pressure(void) {
    int32_t cur_ad = 0;
    const double k = (SENSOR_MIN_PRESSURE - SENSOR_MAX_PRESSURE) / (0 - ((1 << 24) - 1));

    /* 读取压力前,必须保证模块被初始化完成 */
    ELOG_ASSERT(init_ok);
    /* 获取锁 */
    rt_mutex_take(&read_lock, RT_WAITING_FOREVER);
    /* 等待 HX711 已准备好数据输出*/
    set_hx711_dout_irq(true);
    PD_SCK_L;
    rt_uint32_t eRecv;
    rt_event_control(&event_hx711dout, RT_IPC_CMD_RESET, NULL);
    if (rt_event_recv(&event_hx711dout, EVENT_HX711DOUT_OK, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
            CONVERT_PERIOD_TIME, &eRecv) != RT_EOK) {
        log_e("错误:获取压力检测模块数据失败!");
        rt_kprintf("hx711dout_ok_timeout\n");
        cur_ad = 0;
        goto exit;
    }
    set_hx711_dout_irq(false);
    /* 读取数据 */
    for (int i = 0; i < 24; i++) {
        PD_SCK_H;
        PD_SCK_H;
        PD_SCK_L;
        PD_SCK_L;
        cur_ad <<= 1;
        if (DOUT) {
            cur_ad ++;
        }
    }
    /* 下次数据为通道 A 128 增益 */
    for (int i = 0; i < 1; i++) {
        PD_SCK_H;
        PD_SCK_H;
        PD_SCK_L;
        PD_SCK_L;
    }

    /* 检查 24 位数据的最高位,如果为 1,则表示为负数,需要进行转换  */
    if (cur_ad & (1 << 23)) {
        /* 所有 24 位取反 */
        for(int i = 0; i < 24 ; i ++) {
            cur_ad ^= (1 << i);
        }
        /* 转换数据为负数 */
        cur_ad *= -1;
    }

exit:
    /* 释放锁 */
    rt_mutex_release(&read_lock);
    set_hx711_dout_irq(false);

    return (double) cur_ad * k + cali_offset;
}

/**
 * 校准 HX711
 *
 * @param offset 校准值
 */
void hx711_calibrate(double offset) {
    ef_set_double("hx711_offset", offset);
    ef_save_env();
    cali_offset = offset;
}

/**
 * 微妙级延时函数(72M主频)
 *
 * @param n 微秒
 */
static void delay_us(uint32_t n) {
    uint32_t i = 0;

    while (n--) {
        i = 10;
        while (i--);
    }
}

/**
 * 设置MCU对应的HX711数据输出口的中断检测
 * @param type true 使能,false 失能
 */
static void set_hx711_dout_irq(bool type) {
    EXTI_InitTypeDef EXTI_InitStructure;

    EXTI_ClearITPendingBit(EXTI_Line6);
    EXTI_InitStructure.EXTI_Line = EXTI_Line6;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    if (type) {
        EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    } else {
        EXTI_InitStructure.EXTI_LineCmd = DISABLE;
    }
    EXTI_Init(&EXTI_InitStructure);
}

/**
 * 获取HX711数据输出的电平
 * @return
 */
uint8_t get_hx711dout(void) {
    return DOUT;
}

/**
 * 发送HX711准备好数据事件
 */
void event_hx711dout_ok_send(void) {
    rt_event_send(&event_hx711dout, EVENT_HX711DOUT_OK);
}

static void hx711(uint8_t argc, char **argv) {
#include <hx711.h>
    if (argc == 1) {
        rt_kprintf("当前压力为:%dN\n", (int32_t)hx711_get_pressure());
    } else if (argc == 2) {
        /* 校准压力(采用去皮方式) */
        if (!strcmp(argv[1], "cali")) {
            hx711_calibrate(hx711_get_pressure() * -1.0);
        } else {
            /* 连续获取 N 秒的压力 */
            uint32_t start_time = rt_tick_get();
            uint32_t timeout = atoi(argv[1]);
            while (1) {
                if ((rt_tick_get() - start_time) > (timeout * RT_TICK_PER_SECOND)) {
                    /* \033[?25h 显示光标 */
                    rt_kprintf("\033[?25h\n");
                    break;
                }
                /* \033[?25l 隐藏光标,只刷新本行 */
                rt_kprintf("\033[?25l当前压力为:%05dg ,剩余刷新时间 %02d S\r",
                        (int32_t) (hx711_get_pressure() * 1000.0 / 9.8),
                        timeout - (rt_tick_get() - start_time) / RT_TICK_PER_SECOND);
                /* 100ms 更新一次 */
                rt_thread_delay(RT_TICK_PER_SECOND * 100 / 1000);
            }
        }
    }
}
MSH_CMD_EXPORT(hx711, hx711 [<second> get pressure|<cali> calibrate]);
3 个回答
aozima
aozima 2020-08-10
拒绝白嫖,拒绝键盘侠!

没用过这个芯片,具体遇到啥问题呢?

NIC_TSE
NIC_TSE 2020-08-10

低速AD,CSDN上教程很多

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览