AM2320 温湿度计 单总线读取数据

 温湿度计 用单总线方式读取数据

AM2320支持IIC通信和单总线通信,这里只用单总线:

使用单总线时的接线方式时,只需接第二引脚SDA,SCL接地就行。

通信时序图:

由时序可见通信非常简单,关键点要把握好每个时序的时间。

程序思路:

1.握手:

先是发送0.8~20ms的开始信号,然后等待AM2320的应答,要确保应答信号是先是80us的低电平和80us的高电平。

2.数据传输。

AM2320发出应答后就会在跟着的低电平(48~50us)后返回数据位,用高电平的时间长短来区分信号‘1’和‘0’。手册说'0'是22~30us,'1'是60~75us,本人测试时并不对,通过对电平时间的测量发现,'0'在4~8us之间,'1'在14~16us之间。可能是延时函数引起的误差。一切以实际情况为准。

程序源码:

#include "stm32f10x.h"
#include "usart.h"
#include "delay.h"
#define AM2320_Pin GPIOB,GPIO_Pin_7
#define AM2320_Port	GPIO_ReadInputDataBit(AM2320_Pin)
#define AM2320_Port_H	GPIO_SetBits(AM2320_Pin)
#define AM2320_Port_L	GPIO_ResetBits(AM2320_Pin)

//void delay_us(uint32_t n)  延时多少微秒,n就输入多少! 
//{  
//	SysTick->LOAD=72*n;      //装载计数值,因为时钟72M,72次在1μs   
//	SysTick->CTRL=0x00000005;//时钟来源设为为HCLK(72M),打开定时器   
//	while(!(SysTick->CTRL&0x00010000)); //等待计数到0   
//	SysTick->CTRL=0x00000004;//关闭定时器 
//}
//void delay_ms(uint32_t n)  延时多少微秒,n就输入多少! 
//{  
//	SysTick->LOAD=72000*n;      //装载计数值,因为时钟72M,72次在1μs   
//	SysTick->CTRL=0x00000005;//时钟来源设为为HCLK(72M),打开定时器   
//	while(!(SysTick->CTRL&0x00010000)); //等待计数到0   
//	SysTick->CTRL=0x00000004;//关闭定时器 
//}
void AM2320_Init()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7|GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	AM2320_Port_H;
}
unsigned char AM2320_start()
{
	unsigned char status=0,wait;
	AM2320_Port_H;
	//_nop_();
	AM2320_Port_L;
	delay_ms(2);//>=800us,0.8~20ms
	AM2320_Port_H;//release
	wait=0;
	status=0x00;
	while(AM2320_Port==1&&wait<200)//主机释放总线时间,20~200us
	{
		wait++;
		delay_us(1);
	}
	if(wait>=200)//没回应
		status|=0x08;
	wait=0;
	while(AM2320_Port==0&&wait<90)//响应低电平 75~85us
	{
		delay_us(1);
		wait++;
	}
	if(wait>=90)//no ack
		status|=0x04;
	wait=0;
	while(AM2320_Port==1&&wait<200)//响应高电平时间 75~85us
	{
		delay_us(1);
		wait++;
	}
	if(wait>=200)//no ack
		status|=0x02;
	return status;
}
unsigned char AM2320_Read(unsigned char *dat)//读40位
{
	unsigned char tmp=0,i,j,wait,status=0;
	for(i=0;i<5;i++)//5 byte, 40 bit
	{
		for(j=0;j<8;j++)//one byte
		{
			tmp<<=1;
			wait = 0;
			while(AM2320_Port==0&&wait<100)//信号间隔低电平时间48~55us
			{
				wait++;
				delay_us(1);
			}
			if(wait>=100)
				status|=0x10;
			wait=0;
			while(AM2320_Port==1&&wait<100)//22~75us
			{
				delay_us(1);
				wait++;
			}
			if(wait>=2&&wait<=8)//信号‘0’时间: 22~30us
			{
				tmp |=0x00;
			}
			if(wait>=9&&wait<=20)//信号‘1’时间: 68~75us 
			{
				tmp |=0x01;
			}
			if(wait>=100)
			{
				status|=0x20;
			}
			//printf("wait:%d\n",wait);
			//*****************************
			//如果数据不正确或者没数据回来时,把时序的时间打印出来
			//此次数据时序在时间在 4~8us,14~15us范围内,可能delay_us不准确!!!!!!!
		}
		*dat=tmp;
		dat++;
		tmp=0;
	}
	if((*dat+*(dat+1)+*(dat+2)+*(dat+3))==*(dat+4))
	{
		return status|=0x40;
	}
	else
		return status|=0x80;
}
int main()
{
	u8 status;
	u8 a=0;
	u16 H,T,C;
	u8 AM2320_Read_buff[5];
	AM2320_Init();
	SysTick_Init(1);
	USART_Config(115200);
	printf(" hello world\n");
	while(1)
	{
		if(a)
		{
			a=0;
			GPIO_SetBits(GPIOB,GPIO_Pin_8);
		}
		else
		{
			GPIO_ResetBits(GPIOB,GPIO_Pin_8);
			a=1;
		}
		status=AM2320_start();
	//	printf("status1:%x\n",status);
		status|=AM2320_Read(AM2320_Read_buff);
		printf("status2:%x\n",status);
		H=AM2320_Read_buff[0]*256+AM2320_Read_buff[1];
		T=AM2320_Read_buff[2]*256+AM2320_Read_buff[3];
		C=AM2320_Read_buff[4];
		for(a=0;a<5;a++)
		printf("%x\t",AM2320_Read_buff[a]);
		printf("H:%f,T:%f C,C:%d\n",(float)H*0.1,(float)T*0.1,C);
//		while(1)
//		{
		delay_ms(100);
//		printf("test1\n");
		delay_ms(200);
//		printf("test2\n");
		delay_ms(200);
//		printf("test3\n");
//		}
	}
}

AM2320

printf和delay函数请自行编写

猜你喜欢

转载自blog.csdn.net/u013866683/article/details/72846468