STM32F103 用CS1237 /HX711 芯片制作电子秤

STM32F103 用CS1237 /HX711 芯片制作电子秤

【注:学习STM32总结做的笔记,大神勿喷。有不足之处还望不吝赐教,谢谢。工程代码在最后。】

19年全国大学生电子设计大赛 简易多功能液体容器电子秤 CS1237 HX711 压力传感器 STM32F103 2019年全国大学生电子设计竞赛试题清单 2019年全国大学生电子设计竞赛仪器设备和主要元器件清单


【福利/参考/学习资料】
2019年全国大学生电子设计竞赛仪器设备和主要元器件清单
2019年全国大学生电子设计竞赛试题清单
2017年全国大学生电子设计竞赛仪器设备和主要元器件清单
全国大学生电子设计竞赛资料(收集)
https://pan.baidu.com/s/1Ayy-kWOaLqlpOQgsYy7UUw
https://pan.baidu.com/s/1fhTiDL7GUUBYx-WcJoWHNQ
https://pan.baidu.com/s/1–VqCzF2nMporwkkKYIrXw
https://pan.baidu.com/s/1eIk9hmbHhbBSZ4tW1o1T7Q
(文件太多,只能分开)

本人有幸参与了19年的全国大学生电子设计大赛(广东赛区选拔赛),选择了K题,制作简易多功能液体容器,(即,电子秤与及检测重量、分辨不同液体和高度、密度等物理量)。
STM32F103 用CS1237 /HX711 芯片制作电子秤_第1张图片STM32F103 用CS1237 /HX711 芯片制作电子秤_第2张图片
电子秤制作原理什么的就不多介绍了,下面链接是电子秤制作原理,想具体了解的,可以看看。
http://www.doc88.com/p-695275844769.html
这比赛呢,我们团队使用超声波测高、电子秤测重、PH计测酸、电导计测电导,从物理、化学的角度考虑,通过不同传感器检测不同液体AD值,从而区分不同液体,具体怎么做就不细说了。。


本篇就只简单介绍STM32F103 用CS1237 /HX711 芯片制作电子秤,比赛其他的就不涉及了。

直接上原理图:
STM32F103 用CS1237 /HX711 芯片制作电子秤_第3张图片

测重,用 CS1237 和 HX711 芯片,其实做法一样,只要数据稳定,都能精准检测。程序写法都一样的,反正这两种芯片我都试了,都ok的,但下面我就以CS1237芯片的为例。
下面就看代码吧,我把要注意的都注释说明了,不懂再联系我。
就是为了数据的精准度,我采用了多次分段测量,求重量和AD的关系;然后通过每次测量得到的AD,反推,就能得到一个精准的重量。
注:压力传感器形变测量有最大限制,如果超过后可能会造成永久性物理损坏。

mian.c

#include "stm32f10x.h"
#include "uart.h"
#include "cs1237.h"
#include "key.h"

/*
  2019.8.12 子非鱼
  测重,用 CS1237 和 HX711 芯片,其实做法一样,只要数据稳定,都能精准检测。程序写法都一样的。
*/

float one_weight=0,two_weight,weight,zhun_weight,zhongliang;		//重量

int main(void)
{	
	int i;	
	int32_t temp,adc,one_zhongliang; //  ,zhongliang
	
	USART1_Init(); // 初始化串口1 波特率9600
	CS1237_Init_JX();
	delay_ms(300);
	CS1237_Config();
	delay_ms(100);
	USART1_Send_byte(Read_Config());
	
	 
/*第一次取值 用作基准值 用于复位后去皮用 我比赛时没用到这段*/

//	for(i=0;i<20;i++)  /* 用于复位后 循环取第19次值 前面的值用于稳定数据 */
//	{
//		weight = Read_CS1237();/*读取CS1237的数据*/
//		weight = weight + 28000; /* +28000 是因为传感器/芯片的原因导致读回来的值,是负值(-20500~正数++)。需要制零(尽可能接近零),方便从零开始计数。也有些是往负数++ ,这需要看情况。 */
//		if(i==19)
//		{
//		one_weight = weight;
//		}
//	//  printf("*******%f/r/n  ",one_weight);			
//	}		
//	delay_ms(100);


  while (1)
  { 
///
/*
实时按键去皮(清零)
跟上面注释的说明一样的,现在只是实时按键清零而已
*/
		if(KEY1==0)
			{
		delay_ms(10);
		one_weight = Read_CS1237();//读取CS1237的数据
	    one_weight = one_weight + 28000;					
		}
/		
					
		two_weight = Read_CS1237();//读取CS1237的数据
	    two_weight = two_weight + 28000;//取一次值,处理一次
		two_weight = two_weight - one_weight;	/* one_weight定义时值要为零,否则会出错 */
	    weight     = two_weight/100000; //这里对读取CS1237的数据 缩小了100000倍(可以缩小,也可以不缩小。我的缩小了)
		
//		printf("*******%f/r/n  ",weight);
		
/
		
/*
下面采用数据分段计算的方法,以求更高的精度

		    c = ad / g  

被测物质量g                  对应值ad ( weight )                系数c ( ad/g )
50                             0.210                            0.0042
100                            0.420                            0.0042
150                            0.629                            0.00419
200                            0.833                            0.004165
250                            1.044                            0.004176
300                            1.253                            0.004177
...                            ...                              ...
900                            3.766                            0.004184
*/

/*
转化为克
        g  = ad / c
zhongliang = weight / c

判断读取CS1237的数据weight的值,落在哪个区间,然后选取相应的 系数c ( ad/g ) 值
*/

		if(weight>0.001&&weight<0.2101){zhongliang = weight / 0.0042  ;} //50g
		if(weight>0.210&&weight<0.4201){zhongliang = weight / 0.0042  ;} //100g
		if(weight>0.420&&weight<0.6291){zhongliang = weight / 0.00419 ;} //150g		
		if(weight>0.629&&weight<1.8331){zhongliang = weight / 0.004165 ;} //200g
		if(weight>0.833&&weight<1.0441){zhongliang = weight / 0.004176 ;} //250g
		if(weight>1.044&&weight<1.2531){zhongliang = weight / 0.004177 ;} //300g
		if(weight>1.253&&weight<1.4641){zhongliang = weight / 0.004183 ;} //350g
        if(weight>1.464&&weight<1.6661){zhongliang = weight / 0.004165 ;} //400g
		if(weight>1.666&&weight<1.8741){zhongliang = weight / 0.004164 ;} //450g
		if(weight>1.874&&weight<2.0851){zhongliang = weight / 0.00417 ;} //500g
		if(weight>2.085&&weight<2.2961){zhongliang = weight / 0.0041745 ;} //550g
		if(weight>2.296&&weight<2.5071){zhongliang = weight / 0.00418 ;} //600g
		if(weight>2.507&&weight<2.7171){zhongliang = weight / 0.00418 ;} //650g
		if(weight>2.717&&weight<2.9241){zhongliang = weight / 0.004178 ;} //700g
		if(weight>2.924&&weight<3.1381){zhongliang = weight / 0.004175 ;} //750g
		if(weight>3.138&&weight<3.3481){zhongliang = weight / 0.004185 ;} //800g
		if(weight>3.348&&weight<3.5561){zhongliang = weight / 0.0041835 ;} //850g
		if(weight>3.556&&weight<3.7661){zhongliang = weight / 0.0041844 ;} //900g
		if(weight>3.766)               {zhongliang = weight / 0.004191 ;} //900g以上

	    printf("*******%f*********%f/r/n  ",weight,zhongliang);
  }	
  	
}

**

cs1237.c

**

#include "cs1237.h"
#include "uart.h"


//OUT引脚输入输出 方向设置  PA3
#define OUT_IN()  {GPIOA->CRL&=0XFFFF0FFF;GPIOA->CRL|=8<<12;}
#define OUT_OUT() {GPIOA->CRL&=0XFFFF0FFF;GPIOA->CRL|=3<<12;}

// PA2-----CLK
// PA3-----OUT

void Delay1us(void)
{
	__IO uint32_t t=5;
	
	while(t--);
}

void Delay1ms(void)
{
	__IO uint32_t t=8000;
	
	while(t--);
}

void delay_ms(__IO uint16_t ms)
{
	do{
		Delay1ms();
	}while(ms--);
}

// 初始化PA2 PA3
// PA2-----CLK
// PA3-----OUT
void CS1237_Init_JX(void)
{	
	GPIO_InitTypeDef  GPIO_InitStructure;					
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	
	
	// PA2 ----- CLK  设置为输出
	// PA3 ----- OUT  设置为输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;		
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		
	GPIO_Init(GPIOA, &GPIO_InitStructure);
		
	GPIO_SetBits(GPIOA, GPIO_Pin_2);	// CLK拉高
	GPIO_SetBits(GPIOA, GPIO_Pin_3);	// OUT拉高
}

//配置CS1237芯片
void CS1237_Config(void)
{
	unsigned char i;
	unsigned char dat;
	unsigned int count_i=0;//溢出计时器
	
	dat = 0X0C;   //芯片地配置 内部REF 输出40HZ PGA=128 通道A 0X1C   
	OUT_OUT();
	GPIO_SetBits(GPIOA, GPIO_Pin_3); //OUT引脚拉高
	OUT_IN();
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);// 时钟拉低
	while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)==1) //等待CS237准备好
	{
		delay_ms(1);
		count_i++;
		if(count_i > 300)
		{
			OUT_OUT();
			GPIO_SetBits(GPIOA, GPIO_Pin_3); // OUT引脚拉高
			GPIO_SetBits(GPIOA, GPIO_Pin_2); // CLK引脚拉高
			return;//超时,则直接退出程序
		}
	}
	for(i=0;i<29;i++)// 1 - 29
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_2);	// CLK=1;
		Delay1us();
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);	// CLK=0;
		Delay1us();
	}
	OUT_OUT();
	GPIO_SetBits(GPIOA, GPIO_Pin_2);Delay1us();GPIO_SetBits(GPIOA, GPIO_Pin_3);GPIO_ResetBits(GPIOA, GPIO_Pin_2);Delay1us();//30
	GPIO_SetBits(GPIOA, GPIO_Pin_2);Delay1us();GPIO_SetBits(GPIOA, GPIO_Pin_3);GPIO_ResetBits(GPIOA, GPIO_Pin_2);Delay1us();//31
	GPIO_SetBits(GPIOA, GPIO_Pin_2);Delay1us();GPIO_ResetBits(GPIOA, GPIO_Pin_3);GPIO_ResetBits(GPIOA, GPIO_Pin_2);Delay1us();//32
	GPIO_SetBits(GPIOA, GPIO_Pin_2);Delay1us();GPIO_ResetBits(GPIOA, GPIO_Pin_3);GPIO_ResetBits(GPIOA, GPIO_Pin_2);Delay1us();//33
	GPIO_SetBits(GPIOA, GPIO_Pin_2);Delay1us();GPIO_SetBits(GPIOA, GPIO_Pin_3);GPIO_ResetBits(GPIOA, GPIO_Pin_2);Delay1us();//34
	GPIO_SetBits(GPIOA, GPIO_Pin_2);Delay1us();GPIO_ResetBits(GPIOA, GPIO_Pin_3);GPIO_ResetBits(GPIOA, GPIO_Pin_2);Delay1us();//35
	GPIO_SetBits(GPIOA, GPIO_Pin_2);Delay1us();GPIO_SetBits(GPIOA, GPIO_Pin_3);GPIO_ResetBits(GPIOA, GPIO_Pin_2);Delay1us();//36
	//37     写入了0x65
	GPIO_SetBits(GPIOA, GPIO_Pin_2);	// CLK=1;
	Delay1us();
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);	// CLK=0;
	Delay1us();
	
	for(i=0;i<8;i++)// 38 - 45个脉冲了,写8位数据
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_2);	// CLK=1;
		Delay1us();
		if(dat&0x80)
			GPIO_SetBits(GPIOA, GPIO_Pin_3);// OUT = 1
		else
			GPIO_ResetBits(GPIOA, GPIO_Pin_3);
		dat <<= 1;
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);	// CLK=0;
		Delay1us();
	}
	GPIO_SetBits(GPIOA, GPIO_Pin_3);// OUT = 1
	GPIO_SetBits(GPIOA, GPIO_Pin_2);	// CLK=1;
	Delay1us();
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);	// CLK=0;
	Delay1us();
}

// 读取芯片的配置数据
unsigned char Read_Config(void)
{
	unsigned char i;
	unsigned char dat=0;//读取到的数据
	unsigned int count_i=0;//溢出计时器
//	unsigned char k=0,j=0;//中间变量
	
	OUT_OUT();
	GPIO_SetBits(GPIOA, GPIO_Pin_3); //OUT引脚拉高
	OUT_IN();
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);//时钟拉低
	while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)==1)//等待芯片准备好数据
	{
		delay_ms(1);
		count_i++;
		if(count_i > 300)
		{
			OUT_OUT();
			GPIO_SetBits(GPIOA, GPIO_Pin_2);	// CLK=1;
			GPIO_SetBits(GPIOA, GPIO_Pin_3);	// OUT=1;
			return 1;//超时,则直接退出程序
		}
	}

	for(i=0;i<29;i++)// 产生第1到29个时钟
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_2);	// CLK=1;
		Delay1us();
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);	// CLK=0;
		Delay1us();
	}
	
	OUT_OUT();
	
	GPIO_SetBits(GPIOA, GPIO_Pin_2); // CLK=1;
	Delay1us();
	GPIO_SetBits(GPIOA, GPIO_Pin_3); 
	GPIO_ResetBits(GPIOA, GPIO_Pin_2); // CLK=0;
	Delay1us();// 这是第30个时钟
	
	GPIO_SetBits(GPIOA, GPIO_Pin_2); // CLK=1;
	Delay1us();
	GPIO_ResetBits(GPIOA, GPIO_Pin_3);
	GPIO_ResetBits(GPIOA, GPIO_Pin_2); // CLK=0;
	Delay1us();// 这是第31个时钟
	
	GPIO_SetBits(GPIOA, GPIO_Pin_2); // CLK=1;
	Delay1us();
	GPIO_SetBits(GPIOA, GPIO_Pin_3);
	GPIO_ResetBits(GPIOA, GPIO_Pin_2); // CLK=0;
	Delay1us();//32
	
	GPIO_SetBits(GPIOA, GPIO_Pin_2); // CLK=1;
	Delay1us();
	GPIO_ResetBits(GPIOA, GPIO_Pin_3);
	GPIO_ResetBits(GPIOA, GPIO_Pin_2); // CLK=0;
	Delay1us();//33
	
	GPIO_SetBits(GPIOA, GPIO_Pin_2); // CLK=1;
	Delay1us();
	GPIO_SetBits(GPIOA, GPIO_Pin_3); 
	GPIO_ResetBits(GPIOA, GPIO_Pin_2); // CLK=0;
	Delay1us();//34
	
	GPIO_SetBits(GPIOA, GPIO_Pin_2); // CLK=1;
	Delay1us();
	GPIO_SetBits(GPIOA, GPIO_Pin_3);
	GPIO_ResetBits(GPIOA, GPIO_Pin_2); // CLK=0;
	Delay1us();//35
	
	GPIO_SetBits(GPIOA, GPIO_Pin_2); // CLK=1;
	Delay1us();
	GPIO_ResetBits(GPIOA, GPIO_Pin_3);
	GPIO_ResetBits(GPIOA, GPIO_Pin_2); // CLK=0;
	Delay1us();//36
	
	GPIO_SetBits(GPIOA, GPIO_Pin_3);
	GPIO_SetBits(GPIOA, GPIO_Pin_2);	// CLK=1;
	Delay1us();
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);	// CLK=0;
	Delay1us();//37     写入0x56 即读命令
	
	dat=0;
	OUT_IN();
	for(i=0;i<8;i++)// 第38 - 45个脉冲了,读取数据
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_2);	// CLK=1;
		Delay1us();
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);	// CLK=0;
		Delay1us();
		dat <<= 1;
		if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)==1)
			dat++;
	}
	
	//第46个脉冲
	GPIO_SetBits(GPIOA, GPIO_Pin_2);	// CLK=1;
	Delay1us();
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);	// CLK=0;
	Delay1us();
	
	OUT_OUT();
	GPIO_SetBits(GPIOA, GPIO_Pin_3); //OUT引脚拉高
	
	return dat;
}

//读取ADC数据,返回的是一个有符号数据
int32_t Read_CS1237(void)
{
	unsigned char i;
	uint32_t dat=0;//读取到的数据
	unsigned int count_i=0;//溢出计时器
	int32_t temp;
	
	OUT_OUT();
	GPIO_SetBits(GPIOA, GPIO_Pin_3); //OUT引脚拉高
	OUT_IN();
	GPIO_ResetBits(GPIOA, GPIO_Pin_2);//时钟拉低
	while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)==1)//等待芯片准备好数据
	{
		delay_ms(1);
		count_i++;
		if(count_i > 300)
		{
			OUT_OUT();
			GPIO_SetBits(GPIOA, GPIO_Pin_2);	// CLK=1;
			GPIO_SetBits(GPIOA, GPIO_Pin_3);	// OUT=1;
			return 1;//超时,则直接退出程序
		}
	}
	
	dat=0;
	for(i=0;i<24;i++)//获取24位有效转换
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_2);	// CLK=1;
		Delay1us();
		dat <<= 1;
		if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)==1)
			dat ++;
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);	// CLK=0;
		Delay1us();
	}
	
	for(i=0;i<3;i++)//接着前面的时钟 再来3个时钟
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_2);	// CLK=1;
		Delay1us();
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);	// CLK=0;
		Delay1us();
	}
	
	OUT_OUT();
	GPIO_SetBits(GPIOA, GPIO_Pin_3); // OUT = 1;
	
	if(dat&0x00800000)// 判断是负数 最高位24位是符号位
	{
		temp=-(((~dat)&0x007FFFFF) + 1);// 补码变源码
	}
	else
		temp=dat; // 正数的补码就是源码
	
	return temp;
}


cs1237.h


#ifndef __CS1237_H
#define __CS1237_H


#include "stm32f10x.h"

void Delay1us(void);
void Delay1ms(void);
void delay_ms(__IO uint16_t ms);
void CS1237_Init_JX(void);
void CS1237_Config(void);
unsigned char Read_Config(void);
int32_t Read_CS1237(void);

#endif

【注:文件源码是Keil uVision5–STM32工程文件】
参考文件源码下载链接:
https://download.csdn.net/download/qq_28056277/11541590
原创文章,转载请注明出处,谢谢。

你可能感兴趣的:(STM32单片机学习开发篇,STM32F103,CS1237,HX711,电子秤制作)