温湿度计 用单总线方式读取数据
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~20msAM2320_Port_H;//releasewait=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 ackstatus|=0x04;wait=0;while(AM2320_Port==1&&wait<200)//响应高电平时间 75~85us{delay_us(1);wait++;}if(wait>=200)//no ackstatus|=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;}elsereturn 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函数请自行编写