最近在弄课设,需要使用土壤传感器来读取数据,用来测量土壤或其他的湿度数据,我选择使用串口打印数据。
用的控制器是STM32F103C8T6,在网上找了好多代码,各种问题,都没有用,或许的要实现的功能不一样,有些是要在OLED显示的,所以放进去就没用,所以就就写下这篇博客,来弥补这一程序空缺。由于我用的是STM32的芯片,所以那些51的代码都没有试,可能有些有用,有兴趣的可以去试一下。
先介绍硬件及连线,有助于初学者理解。传感器及芯片都是在淘宝的优信电子上面购买的,个人感觉这个店比较好。
最小系统用的是STM32F103C8T6便宜实惠,
传感器用的是YL-69土壤湿度传感器,四线制的,中间两根手动连起来。
连线:
传感器GND–芯片GND
传感器VCC–芯片3.3V
传感器AO–芯片PA1(用于读取实时湿度数据)
传感器DO不连(主要用于超出范围报警)
为什么AO连接PA1,因为AO是传感器的模拟输出(输出的是电压这种连续的值),DO是传感器的数字输出(直接输出0101这样的)。由于AO输出的是模拟量,而单片机只能读取数字量,所以就要做一个ADC(模数转换),PA1是芯片的ADC引脚,用于处理模拟数据的,感兴趣的朋友可以看一下STM32的参考手册里的引脚定义和ADC的详细讲解,是12位的ADC。接线完成后就需要进行代码编写,用的是KEIL5这个软件。
基本上所有的传感器只需要建立两个文件,比如这个传感器,需要建立adc.c和adc.h这两个文件,然后将.c文件处理得到的数据返回到main.c中即可得到数据。有串口打印的话还要添加串口的.c和.h文件,其他的文件都是工程里自带的,就能直接编译然后烧录(注意:这里没有以YL-69.c和YL-69.h来命名,因为这个功能主要是用ADC来读取数据,关于传感器的代码就两行)
先看adc.c,一共就三个函数,代码可以不看,文字一定要看!!
Adc_Init(void)是用来ADC初始化,就是配置ADC的基本属性,具体是哪个通道,哪个引脚,传输的速度等等。。。
Get_Adc(u8 ch)用于获取芯片处理后的010101这样的数据,从传感器传来的模拟量,连续的,这里已经将他数字化
Get_Adc(u8 ch)用于将数字化的数据转换成我们生活中所见的湿度数据,我想你也不想看见010101这样的数据。
adc.c的代码如下:
#include "adc.h"
#include "delay.h"
int shidu1;
void Adc_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);
/*PA_1设置为模拟输入*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//设置ADC分频因子
ADC_DeInit(ADC1);//复位ADC
//初始化ADC参数
ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;
ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;
ADC_InitStruct.ADC_NbrOfChannel=1;
ADC_InitStruct.ADC_ScanConvMode=DISABLE;
ADC_Init(ADC1, &ADC_InitStruct);
ADC_Cmd(ADC1,ENABLE);//使能ADC1
ADC_ResetCalibration(ADC1); //使能复位校准
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
ADC_StartCalibration(ADC1); //开启AD校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
}
u16 Get_Adc(u8 ch) //获取ADC数据
{
ADC_RegularChannelConfig(ADC1,ch,1, ADC_SampleTime_239Cycles5);
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));
return ADC_GetConversionValue(ADC1);
}
u16 Get_Adc_Average(u8 ch,u8 times) //获取土壤湿度数据并返回给主函数
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
delay_ms(1);
}
temp_avrg=temp_val/times;
shidu1=(4092-temp_avrg)/3292*100;
return shidu1;
}
然后adc.h,这是对adc.c的头文件声明,比较简单,adc.h代码如下
#ifndef __ADC_H
#define __ADC_H
#include "sys.h"
//正点原子的adc采集代码
void Adc_Init(void);
u16 Get_Adc(u8 ch);
u16 Get_Adc_Average(u8 ch,u8 times);
extern float temp_avrg;
extern int shidu;
#endif
剩下的就是main.c文件了,因为我是用串口获取了温湿度数据(DHT11)和土壤湿度数据,所以为了只打印土壤湿度数据,我将printf函数的温湿度打印拿出来了,如果有人想打印三个数据,可以放回到printf函数里即可
main.c代码如下
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "stdio.h"
#include "dht11.h"
#include "adc.h"
int shidu;
float temp_avrg=0;
u8 buff[30]; //参数显示缓存数组
u8 DHT11_Temp,DHT11_Hum; //温湿度
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
DHT11_Init();
Adc_Init();
uart_init(9600);
while(1)
{
shidu=Get_Adc_Average(1,10);
DHT11_Read_Data(&DHT11_Temp,&DHT11_Hum);
printf("土壤湿度:%d\r\n",shidu); //将后面这个代码放到printf的相应的位置即可打印空气的温湿度数据了,直接剪切过去(当前温度:%d 当前湿度:%d DHT11_Temp,DHT11_Hum,)
delay_ms(100);
}
}
至此,代码就写完了。下面进行程序测试,用Fly mcu烧录程序,然后用串口打印助手ATK X.COM来打印(可去野火的论坛里下载,资源丰富),如下图:
烧入成功,如下:
最后就进入到紧张自己的打印环节了,准备好湿的纸放到感应区,串口打印结果就会有变化,结果如下:
打印完毕,这个实验到这就算结束了。
因为我的代码是用来测量空气温湿度和土壤湿度的,按照的我提示修改后可打印三个数据,就改一行printf代码,如下:
printf("当前温度:%d 当前湿度:%d 土壤湿度:%d\r\n",DHT11_Temp,DHT11_Hum,shidu);
即可
打印结果如下:
完结!有问题可以评论区交流。
工程在这 链接:https://pan.baidu.com/s/1v6FBqHxaiMLEHFfaoBBnYQ 提取码:hj5d