概要
ロードセル とPICマイコンを使って重さをはかろうと思いました。重さを計るにはいろいろ方法があってロードセルという機器を使えば、簡単に重さを計ることが、可能です。今回は、ロードセルセンサと、HX711というロードセルからのデータを使いやすいように変換してくれる、HX711というモジュールを使用します。
プログラムを作成するのに以下の記事を参考にしました。
使用する機器
ロードセルを使うには
ロードセルセンサと、 HX711 モジュールをただ繋げば、重さが取得できるようではないみたいで、計るものを載せる台のようなものもうまく作成しないといけません。しかし、Amazonでロードセルセンサと HX711 と台が一緒になったものが売っていたのでそれを使います。
配線図(Fritzing)
プログラムコードでは、LCDに重さを計るコードを記述していますが、配線図では省いています。
雑ですが、 HX711 に以下のような配線をすれば、重さを取得できます。
プログラムコード (loadcell.h)
プログラムコードはGitHubにも公開しています。
#include <xc.h>
#include <stdint.h>
//RA0
#define CELL_CLK 0x01
//RA1
#define CELL_DAT 0x02
//DIVIDE value
#define DIVIDE_VAL 493
unsigned long weight_dat;
unsigned long weight_zero;
/**
* get scale value
* @param scale count
* @return
*/
unsigned long get_scale_val(int n);
/**
* scale value to gram value
* @param count
* @return gram value
*/
float scale_convert_gram(unsigned long count);
プログラムコード (locadcell.c)
最初に参考にしたこのサイトのコードを使って書いていました。
でも、270gを超えると値がおかしくなって、正確な値が出なくなったのですが、
どうやら HX711 は、24bitの最上位ビットをXORしないといけなかったようです。
get_scal_val()でロードセルの値を取得します。get_scal_val(3)と入れると3回取得した平均値を返します。
使用するマイコンのメモリと相談しながら値を設定してください。
scale_convert_gramでget_scal_valで取得した値をグラムに変換します。
#include "loadcell.h"
#include "./mcc_generated_files/mcc.h"
/**
* LoadCell clock pin set low
*/
void set_CELL_CLK_LOW(){ LATA &= ~ CELL_CLK;}
/**
* LoadCell clock pin set high
*/
void set_CELL_CLK_HIGH(){ LATA |= CELL_CLK;}
int get_CELL_DAT_VAL(){
if(CELL_DAT == 0x01){ return PORTAbits.RA0; }
if(CELL_DAT == 0x02){ return PORTAbits.RA1; }
if(CELL_DAT == 0x04){ return PORTAbits.RA2; }
if(CELL_DAT == 0x08){ return PORTAbits.RA3; }
if(CELL_DAT == 0x10){ return PORTAbits.RA4; }
if(CELL_DAT == 0x20){ return PORTAbits.RA5; }
if(CELL_DAT == 0x40){ return PORTAbits.RA6; }
if(CELL_DAT == 0x80){ return PORTAbits.RA7; }
return 0;
}
unsigned long get_scale_val(int n)
{
set_CELL_CLK_LOW();
unsigned long weight_count = 0;
unsigned long weight_add = 0;
for (uint8_t j = 0; j < n; j++)
{
while (get_CELL_DAT_VAL() == 0);
while (get_CELL_DAT_VAL() == 1);
__delay_us(10);
uint8_t i;
for (i = 0; i < 24; i++){
weight_count <<= 1;
set_CELL_CLK_HIGH();
__delay_us(10);
set_CELL_CLK_LOW();
weight_count += get_CELL_DAT_VAL();
__delay_us(10);
}
for (i = 0; i < 1; i++){ //i=1:ChAGain128 2:ChBGain32 3:ChAGain64
set_CELL_CLK_HIGH();
__delay_us(10);
set_CELL_CLK_LOW();
__delay_us(10);
};
weight_add += weight_count;
weight_count = 0;
}
weight_count = weight_add / n;
/** 最上位ビットをXORで値を変更する。 */
/** 24th bit flip*/
weight_count = weight_count ^ 0x800000;
return weight_count;
}
float scale_convert_gram(unsigned long count)
{ //ADCのカウント値をグラムに変換
float temp = count - weight_zero;
temp = temp / DIVIDE_VAL;
return temp;
}
プログラムコード (main.c)
#include "mcc_generated_files/mcc.h"
#include "loadcell.h"
#include "lcd_lib.h"
#include <stdio.h>
char gramstr[16];
char valstr[16];
void main(void)
{
SYSTEM_Initialize();
//set digital mode
ANSELA = 0x00;
ANSELB = 0x00;
//RA0 cell clock is output
//RA1 cell data is input
TRISA = 0x02;
//init LATA
LATA = 0x00;
LATB = 0x00;
//init i2c
SSPADD = 0x13;
SSPCON1 = 0x28;
SSPCON2 = 0x0;
SSPSTAT = 0;
lcd_init();
lcd_backlight();
lcd_set_cursor(0, 0);
lcd_print("Initialize");
lcd_set_cursor(0, 1);
lcd_print("Load cell Unit");
__delay_ms(1000);
weight_zero = get_scale_val(3);
lcd_clear();
sprintf(valstr, "%lu val ", weight_zero);
lcd_print(valstr);
__delay_ms(500);
lcd_clear();
sprintf(valstr, "Divide val: %d", DIVIDE_VAL);
lcd_print(valstr);
__delay_ms(1500);
while (1)
{
weight_dat = get_scale_val(8);
float weight_gram = scale_convert_gram(weight_dat);
sprintf(valstr, "%lu val", weight_dat);
sprintf(gramstr, "%3.2f gram", weight_gram);
lcd_clear();
lcd_print(valstr);
lcd_set_cursor(0, 1);
lcd_print(gramstr);
__delay_ms(1000);
}
}
動作確認
うまく動いているみたいです。調理用の秤で重さを計ったところ、298gとでましたので、2gほど誤差がありましたが、 get_scal_val(3) の3の値をもっと増やせば、正確な値が出せると思います。
PICのI2Cの設定についての記事はこちら