AM2302温湿度传感器驱动调试笔记

手头有一块AM2302温湿度模块,之前没有用过,最近闲暇,就尝试写一下驱动,使用的STM32F103主控MCU,虽然协议很简单,但也零零散散花了3天时间,主要是一方面发现原先用的延时器不准,导致一直调试不成功,所以遇到调试不上,先尽量检查一下延时函数的精确度,不宜偏差过大。

现贴参考代码如下:

#ifndef  _AM2302_H__
#define  _AM2302_H__

#include "bsp.h"

#define AM_SDA_IN()  {AM2302_PORT->CRH&=0xFFFFFF0F;AM2302_PORT->CRH|=((unsigned int)8<<4);}//PB9-SDA
#define AM_SDA_OUT() {AM2302_PORT->CRH&=0xFFFFFF0F;AM2302_PORT->CRH|=(unsigned int)(3<<4);}

#define AM_SDA_SET(x)    (0==x)?(GPIO_ResetBits(AM2302_PORT,AM2302_PIN)):(GPIO_SetBits(AM2302_PORT,AM2302_PIN)) 
#define AM_SDA_READ()    GPIO_ReadInputDataBit(AM2302_PORT,AM2302_PIN)

typedef struct 
{
	unsigned short value:15;
	unsigned short polar:1;
}data_st;

typedef struct
{
  data_st humt;
  data_st temp;
}sensor_st;

extern sensor_st sensor;

void sens_start(void);
void get_byte(unsigned char *gbyte);
unsigned char get_data(sensor_st *sensor_me);
void read_th(void);

#endif 
#include "am2302.h"
#include "delay.h"
#include "string.h"
#include "stdio.h"


#define LEV_HIGH (1)   /*高电平*/
#define LEV_LOW  (0)   /*低电平*/

#define RET_OK     (0) /*返回正常*/
#define RET_FAIL   (1) /*返回失败*/


sensor_st sensor={0,0};

/*
  1.微处理器把数据总线(SDA)拉低一段时间(至少 800µs)[1],通知传感器准备数据。
  2.传感器把数据总线(SDA)拉低 80µs,再接高 80µs 以响应主机的起始信号
  3.收到主机起始信号后,传感器一次性从数据总线(SDA)串出 40 位数据,高位先出
	位数据“0”的格式为: 50 微秒的低电平加 26-28 微秒的高电平;
	位数据“1”的格式为: 50 微秒的低电平加 70 微秒的高电平;
  4.数据完毕后,传感器将继续输出50微妙作为结束信号
*/

//------------------------------------------
//发起准备
unsigned char sens_ready(void)
{

	AM_SDA_OUT();//输出模式
	AM_SDA_SET(0);	
	xDelay_ms(10);
	printf(">> start ok\r\n");
	AM_SDA_SET(1);
    xDelay_us(40); 	
	AM_SDA_IN();//输入模式
	xDelay_us(40);//加延时,以保证信号上升 
	if(LEV_LOW==AM_SDA_READ())//响应信号
	{
	  while(LEV_LOW==AM_SDA_READ());//等待80us低电平过去
	  while(LEV_HIGH==AM_SDA_READ());//等待80us高电平过去
    return RET_OK;	
	}
	else
	{
	  return RET_FAIL;	
	}
}
//------------------------------------------
//获取单字节数据
void get_byte(unsigned char *gbyte)
{
	unsigned char htime=0;
	*gbyte=0;
	for(unsigned char data_bit=0;data_bit<8;data_bit++)
	{
		htime=0;
		xDelay_us(30); 
		if(LEV_LOW==AM_SDA_READ())//
		{
		  while(LEV_LOW==AM_SDA_READ());//等待50us低电平结束		
		}
		while(LEV_HIGH==AM_SDA_READ())//等待高电平结束,并判断当前信号特性值
		{
		 ++htime;	
		 xDelay_us(10);   
		}
		if(3<htime) //如果能计数到30us以上,则说明是电平 “1”
		{ 
		  *gbyte|=(1<<(7-data_bit));
		}	
		else
		{
		  *gbyte&=~(1<<(7-data_bit));		
		}
	}
}

//------------------------------------------
//获取完整数据
unsigned char get_data(sensor_st *sensor_me)
{
	unsigned char gdata[5]={0};

	if(RET_FAIL==sens_ready()) 
	{
	  printf(">> commit fail\r\n");
	  return RET_FAIL;//发起启动
	}
	for(unsigned char i=0;i<5;i++)
	{
	  get_byte(&gdata[i]);
	}	
	xDelay_us(15); 
	while(LEV_LOW==AM_SDA_READ());//等待50us低电平结束(结束信号)	
	AM_SDA_OUT();//输出模式
	AM_SDA_SET(0);	
	xDelay_ms(5);
	RLED_SW(0);
	//校验位=湿度高位+湿度低位+温度高位+温度低位
	if(gdata[4]==(unsigned char)(gdata[0]+gdata[1]+gdata[2]+gdata[3]))//数据校验
	{
		if(0x01==(gdata[0]>>8))  
		{
			gdata[0]&=~0x80;//清除极性位
			sensor_me->temp.polar=1;
		}
	  sensor_me->humt.value=((unsigned short)gdata[0]<<8)|gdata[1];
	  sensor_me->temp.value=((unsigned short)gdata[2]<<8)|gdata[3];
	  printf(">> crc ok\r\n"); 
	  return RET_OK;
	}
	for(unsigned char i=0;i<5;i++)
	printf(">> gdata[%d]:0x%02x\r\n",i,gdata[i]); 
	printf(">> crc fail\r\n");
	return RET_FAIL;
}

//------------------------------------------
//输出数据
void read_am2302(void)
{ 
  if(RET_OK==get_data(&sensor))
  {
	if(0==sensor.temp.polar)//检查温度的极性(最高比特位是否为1)
	{
	 printf(">> Temp:%d.%d;Hum:%d.%d\r\n",sensor.temp.value/10,sensor.temp.value%10,sensor.humt.value/10,sensor.humt.value%10); 	  
	}
	else //条件限制,暂未验证
	{
	 printf(">> Temp:-%d.%d;Hum:%d.%d\r\n",sensor.temp.value/10,sensor.temp.value%10,sensor.humt.value/10,sensor.humt.value%10); 
	}
  }
  else
  {
	printf(">> Data geted fail\r\n");      
  }
}

另外周期读取read_am2302()手册建议是2s以上,过快容易通信不成功。

在这里插入图片描述
调试输出截图如上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值