感觉HX711模块应用范围还比较广,以前用arduino,里面的hx711库非常好用,可惜自己水平有限,没有移植成功到rtt,哪个大神帮忙指导一下,或者移植一个。
巧了,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]);
多谢热心回复,我学习