中级会员
 
- 积分
- 421
- 金钱
- 421
- 注册时间
- 2017-3-8
- 在线时间
- 114 小时
|

楼主 |
发表于 2017-6-12 15:53:45
|
显示全部楼层
自己写的,还没测试,希望你们也能用得上。[mw_shl_code=c,true]//模拟IIC
#define SDA_PIN PINC4//数据线pc4
#define SCL_PIN PINC5//时钟线pc5
#define SDA_OUT DDRC|=(1<<SDA_PIN)//数据线输出
#define SDA_IN DDRC&=~(1<<SDA_PIN)//数据线输入
#define SDA_LOW PORTC&=~(1<<SDA_PIN)//数据线拉低
#define SDA_HIGH PORTC|=(1<<SDA_PIN)//数据线拉高
#define SDA_READ PINC&=(1<<SDA_PIN)//读数据线电平值
#define SCL_OUT DDRC|=(1<<SCL_PIN)//时钟线输出
#define SCL_IN DDRC&=~(1<<SCL_PIN)//时钟线输入
#define SCL_LOW PORTC&=~(1<<SCL_PIN)//时钟线拉低
#define SCL_HIGH PORTC|=(1<<SCL_PIN)//时钟线拉高
#define SCL_READ PINC&=(1<<SCL_PIN)//读时钟线电平值
//定义器件地址,全局变量
#define IIC_Address 0xB8
#define IIC_RX_Len 15
unsigned char IIC_TX_Buffer[]={0x03,0x00,0x04};//读温湿度命令
unsigned char IIC_RX_Buffer[IIC_RX_Len]={0x00};//读取到的温湿度
unsigned char Error_Mess[]={"error"};
unsigned char WR_Flag;
//IIC相关函数
void IIC_Init(void);//IIC初始化
void IIC_Start(void);//IIC起始信号
void IIC_Stop(void);//IIC停止信号
void IIC_ACK(void);//主机应答
void IIC_NACK(void);//主机非应答
unsigned char IIC_Wait_NACK(void);//等待应答信号
void IIC_Send_Byte(unsigned char data);//IIC发送一个字节 data:要发送的数据
unsigned char IIC_Read_Byte(unsigned char ack);//读一个字节,ack=1时,发送ACK,ack=0时,发送NACK;
//AM2322相关函数
void Waken(void);//唤醒芯片
void Clear_Data(void);//清空接收缓冲区数据
unsigned int CRC16(unsigned char *ptr,unsigned char len);//计算CRC校验码
/**ptr:接收到数据的首地址;len:数据的长度*/
unsigned char CheckCRC(unsigned char *ptr,unsigned char len);//检验CRC校验码是否正确
/**ptr:接收到数据的首地址;len:数据的长度*/
unsigned char WriteNByte(unsigned char sla,unsigned char *s,unsigned char n);//写入数据,即发送开始命令
/*add:器件地址;*s:数据首地址;n:数据个数*/
unsigned char ReadNByte(unsigned char sla,unsigned char *p,unsigned char n);//读数据,即读温湿度值
/*add:器件地址;*p:保存数据首地址;n:数据个数*/
void press_AM2322_Data(void);//温湿度数据处理
void IIC_Init(void)
{
//设置输出
SDA_OUT;
SCL_OUT;
//输出高电平
SDA_HIGH;
SCL_HIGH;
}
void IIC_Start(void)
{
//起始条件,SCL为高时,SDA产生一个下降沿
SDA_OUT;
SDA_HIGH;
SCL_HIGH;
_delay_us(10);
SDA_LOW;
_delay_us(10);
SCL_LOW;
}
void IIC_Stop(void)
{
//停止条件,SCL为高电平时,SDA产生一个上升沿
SDA_OUT;
SDA_LOW;
SCL_LOW;
_delay_us(10);
SCL_HIGH;
_delay_us(10);
SDA_HIGH;
_delay_us(10);
}
void IIC_ACK(void)
{
//主机应答,SCL为高电平时,SDA始终为低电平
SCL_LOW;
SDA_OUT;
SDA_LOW;
_delay_us(10);
SCL_HIGH;
_delay_us(10);
SCL_LOW;
}
void IIC_NACK(void)
{
//主机非应答,SCL为高电平时,SDA始终为高电平
SCL_LOW;
SDA_OUT;
SDA_HIGH;
_delay_us(10);
SCL_HIGH;
_delay_us(10);
SCL_LOW;
}
unsigned char IIC_Wait_NACK(void)
{
//等待应答信号。返回值:1接收应答失败。返回值:0接收应答成功
unsigned char temptime=0;
SDA_IN;
SDA_HIGH;
_delay_us(10);
SCL_HIGH;
_delay_us(10);
while (SDA_READ)
{
temptime++;
if(temptime>250)
{
IIC_Stop();
return 1;
}
}
SCL_LOW;
return 0;
}
void IIC_Send_Byte(unsigned char data)
{
unsigned char i=0;
SDA_OUT;
SCL_LOW;
for (i=0;i<8;i++)
{
if ((data&0x80)>0)
SDA_HIGH;
else
SDA_LOW;
data<<=1;
SCL_HIGH;
_delay_us(10);
SCL_LOW;
_delay_us(10);
}
SCL_HIGH;
_delay_us(10);
SCL_LOW;
_delay_us(10);
}
unsigned char IIC_Read_Byte(unsigned char ack)
{
//读一个字节,ack=1时,发送ACK,ack=0时,发送NACK;
unsigned char i=0,receive=0;
SDA_IN;
for (i=0;i<8;i++)
{
SCL_LOW;
_delay_us(10);
SCL_HIGH;
_delay_us(10);
receive<<=1;
if (SDA_READ)
{
receive++;
}
_delay_us(10);
}
if (ack==0)
IIC_NACK();
else
IIC_ACK();
return receive;
}
void Waken(void)
{//起始信号+器件地址+等待时间(至少800us)+停止信号
IIC_Start();
IIC_Send_Byte(IIC_Address);
SCL_LOW;
_delay_us(800);
IIC_Stop();
}
void Clear_Data(void)
{
int i;
for (i=0;i<IIC_RX_Len;i++)
{
IIC_RX_Buffer=0x00;//接收数据缓冲区清零
}
}
unsigned int CRC16(unsigned char *ptr,unsigned char len)
{//生成CRC校验码,用于检测数据是否正确
unsigned int crc=0xffff;
unsigned char i;
while (len--)
{
crc^=*ptr++;
for (i=0;i<8;i++)
{
if (crc&0x1)
{
crc>>=1;
crc^=0xa001;
}
else
{
crc>>=1;
}
}
}
return crc;
}
unsigned char CheckCRC(unsigned char *ptr,unsigned char len)
{//检测CRC校验码,判断数据是否正确
unsigned int crc;
crc=(unsigned int)CRC16(ptr,len-2);
if (ptr[len-1]==(crc>>8)&&ptr[len-2]==(crc&0x00ff))
{
return 0xff;
}
else
{
return 0x0;
}
}
unsigned char WriteNByte(unsigned char sla,unsigned char *s,unsigned char n)
{
unsigned char i;
IIC_Start();//IIC起始信号
IIC_Send_Byte(sla);//发送器件地址
for (i=0;i<n;i++)//发送读温湿度命令
{
IIC_Send_Byte(*(s+i));
}
IIC_Stop();//IIC停止信号
return 1;
}
unsigned char ReadNByte(unsigned char sla,unsigned char *p,unsigned char n)
{
unsigned char i;
IIC_Start();//IIC起始信号
IIC_Send_Byte(sla+0x01);//发送器件地址
_delay_us(30);//延时不小于30us,才可以继续发送下一个串行时钟,进行读取数据
for (i=0;i<n-1;i++)
{
*(p+i)=IIC_Read_Byte(1);//读取前n-1个字节数据,并发送应答信号
}
*(p+n-1)=IIC_Read_Byte(0);//读取最后一个字节数据,并发送非应答信号
IIC_Stop();//IIC停止信号
return 1;
}
void press_AM2322_Data(void)
{
int Temp,Hum;
int Temp1,Hum1;
Clear_Data();//清空缓冲区
WR_Flag=0;
Waken();//唤醒传感器
WriteNByte(IIC_Address,IIC_TX_Buffer,3);//发送读数据命令
_delay_ms(2);//至少等待1.5ms发送读取时序、
ReadNByte(IIC_Address,IIC_RX_Buffer,8);//读返回的温湿度数据
_delay_ms(2);
SDA_HIGH;
SCL_HIGH;//释放总线
if (WR_Flag == 0)
{
if (CheckCRC(IIC_RX_Buffer,8))
{
Hum1=IIC_RX_Buffer[2]*256+(IIC_RX_Buffer[3]>>4)*16+(((IIC_RX_Buffer[3]<<4)&0xf0)>>4);
Hum=Hum1/10;
Temp1=IIC_RX_Buffer[4]*256+(IIC_RX_Buffer[5]>>4)*16+(((IIC_RX_Buffer[5]<<4)&0xf0)>>4);
Temp=Temp1/10;
uart0_putchar(Hum, pRTbuf_UART0);
uart0_putchar(Temp, pRTbuf_UART0);
}
else
{
uart0_putchars(Error_Mess,5,pRTbuf_UART0);
}
}
else
{
uart0_putchars(Error_Mess,5,pRTbuf_UART0);
}
}[/mw_shl_code] |
|