【注:学习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题,制作简易多功能液体容器,(即,电子秤与及检测重量、分辨不同液体和高度、密度等物理量)。
电子秤制作原理什么的就不多介绍了,下面链接是电子秤制作原理,想具体了解的,可以看看。
http://www.doc88.com/p-695275844769.html
这比赛呢,我们团队使用超声波测高、电子秤测重、PH计测酸、电导计测电导,从物理、化学的角度考虑,通过不同传感器检测不同液体AD值,从而区分不同液体,具体怎么做就不细说了。。
本篇就只简单介绍STM32F103 用CS1237 /HX711 芯片制作电子秤,比赛其他的就不涉及了。
测重,用 CS1237 和 HX711 芯片,其实做法一样,只要数据稳定,都能精准检测。程序写法都一样的,反正这两种芯片我都试了,都ok的,但下面我就以CS1237芯片的为例。
下面就看代码吧,我把要注意的都注释说明了,不懂再联系我。
就是为了数据的精准度,我采用了多次分段测量,求重量和AD的关系;然后通过每次测量得到的AD,反推,就能得到一个精准的重量。
注:压力传感器形变测量有最大限制,如果超过后可能会造成永久性物理损坏。
#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);
}
}
**
**
#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;
}
#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
原创文章,转载请注明出处,谢谢。