STM32
直播中

李志静

7年用户 1406经验值
私信 关注
[问答]

如何去实现基于AHT20温湿度传感器接stm32的软件I2C呢

I2C通信协议是什么?其工作原理是什么?
如何去实现基于AHT20温湿度传感器接STM32的软件I2C呢?





回帖(5)

周梦斌

2021-12-10 13:56:38
一、I2C通信协议


  I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。
主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下.主机负责产生定时时钟和终止数据传送。

1、工作原理
连接在总线上的节点设备有两种角色:主机模式和从机模式。同一时刻只能有一个节点处于主机模式,其它节点处于从机模式。总线上数据的传送都是由主机发起。I2C总线是没有片选信号线的,所以也得通过协议来找到对应操作的芯片。主器件用于启动总线传输数据,并产生时钟以开放传送的器件,此时任何被寻址的器件都被认为是从器件,在总线上主和从、发和手的关系是不恒定的,而取决于此时数据传送方向。如果主机要发送数据给器件,则主机首先寻址从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件,然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下,主机负责产生时钟和终止数据传送。



  • I2C数据传输基本过程:
    1.主机首先开始发送信号
    2.主机紧接着发送从机地址信息(一个字节),该字节信息中的最低位为读写控制码:1为读,0为写。高7位为从机设备的器件地址
    3.从机然后发出确认信息
    4.主机开始发送信号数据,每当发完一个字节数据后,从机设备给主机发送确认信号
    5.主机最后发送停止信号。
    START开始信号:在SCL时钟线为高电平时,SDA数据线由高变低,产生一个开始信号
    STOP 停止信号:在SCL时钟线为高电平时,SDA数据线由低变高,产生一个停止信号
    ACK确认信号: 当主机写从机设备时,每次写完一个字节,如果数据正确,从机设备将在下一个时钟周期将数据线拉低,来通知主机操作有效。
    当主机读从机设备时,每次正确读完一个字节后,主机将在下一个时钟周期同样也要讲数据线拉低,发出确认信号,来通知从机所发数据以收到
    总之,SCL信号必须要由主机发送
    注意:在读从机设备时,当主机在最后一个字节数据接收完后,不在发送确认信号,直接发送停止信号。还有就是任何时候SCL时钟线为高电平的时候,SDA数据上的电平变化都被认为是起始信号和停止信号,所以数据的改变必须要在时钟为低电平时改变





二、硬件与软件模拟I2C的区别


  原理上:硬件I2C(提供专门的SDA,SCL口)的时钟是由系统产生的,一般由晶振分频产生。模拟I2C通过编程将通用I/O模拟为时钟线和数据线
控制上:硬件I2C通过硬件中断实现各种操作。模拟I2C没有中断的概念,通过IO接口电平置高置低来实现写入和读取
性能上:硬件模式更高效更稳定硬件I2C比软件I2C速度快很多,占用时间也少,并且硬件I2C使用简单,只需要将数据送到指定寄存器就可以了,不需要自己实现时序除了上述基本模式(串行的8位双向数据传输位速率在标准模式下可达100Kbit/s)外,快速模式下可达400Kbit/s,高速模式下可达3,4Mbit/s。这两种模式在硬件威廉希尔官方网站 和软件协议上都有变化可参考百度百科

三、AHT20温湿度传感器接stm32的软件I2C

1、实作内容


  使用i2c通信协议完成温湿度的采集工作,通过串口发往上位机
硬件选用野火的stm32f103指南者开发板,AHT20温度传感器

AHT20数据手册i2c通信相关内容




















2、实验代码

可见AHT20的官网下载相关i2c例程进行参考
打开stm32的空闲工程,将以下文件添加到工程里。
以下为需要用到的代码文件:
main.c

#include "delay.h"
#include "usart.h"
#include "bsp_i2c.h"




int main(void)
{       
        delay_init();     //延时初始化  
        uart_init(115200);         //串口波特率设置为115200
        IIC_Init();
                while(1)
        {
                printf("¿ªÊ¼²âÁ¿£¬ÇëÉԵȣº");
                read_AHT20_once();
                delay_ms(2000);
  }
}


AHT20_i2c.c


#include "bsp_i2c.h"
#include "delay.h"


uint8_t   ack_status=0;
uint8_t   readByte[6];
uint8_t   AHT20_status=0;


uint32_t  H1=0;  //Humility
uint32_t  T1=0;  //Temperature


uint8_t  AHT20_OutData[4];
uint8_t  AHT20sendOutData[10] = {0xFA, 0x06, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF};


void IIC_Init(void)
{                                             
        GPIO_InitTypeDef GPIO_InitStructure;
        RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOB, ENABLE );       
          
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);

        IIC_SCL=1;
        IIC_SDA=1;

}
//产生IIC起始信号
void IIC_Start(void)
{
        SDA_OUT();     //sda线输出
        IIC_SDA=1;                    
        IIC_SCL=1;
        delay_us(4);
        IIC_SDA=0;//START:when CLK is high,DATA change form high to low
        delay_us(4);
        IIC_SCL=0;//锁住I2C总线,准备发送或接收数据
}          
//²úÉúIICÍ£Ö¹ÐźÅ
void IIC_Stop(void)
{
        SDA_OUT();//sdaÏßÊä³ö
        IIC_SCL=0;
        IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
        delay_us(4);
        IIC_SCL=1;
        IIC_SDA=1;//·¢ËÍI2C×ÜÏß½áÊøÐźÅ
        delay_us(4);                                                                  
}
//µÈ´ýÓ¦´ðÐźŵ½À´
//·µ»ØÖµ£º1£¬½ÓÊÕÓ¦´ðʧ°Ü
//        0£¬½ÓÊÕÓ¦´ð³É¹¦
u8 IIC_Wait_Ack(void)
{
        u8 ucErrTime=0;
        SDA_IN();      //SDAÉèÖÃΪÊäÈë  
        IIC_SDA=1;delay_us(1);          
        IIC_SCL=1;delay_us(1);         
        while(READ_SDA)
        {
                ucErrTime++;
                if(ucErrTime>250)
                {
                        IIC_Stop();
                        return 1;
                }
        }
        IIC_SCL=0;//ʱÖÓÊä³ö0           
        return 0;  
}
//²úÉúACKÓ¦´ð
void IIC_Ack(void)
{
        IIC_SCL=0;
        SDA_OUT();
        IIC_SDA=0;
        delay_us(2);
        IIC_SCL=1;
        delay_us(2);
        IIC_SCL=0;
}
//²»²úÉúACKÓ¦´ð                    
void IIC_NAck(void)
{
        IIC_SCL=0;
        SDA_OUT();
        IIC_SDA=1;
        delay_us(2);
        IIC_SCL=1;
        delay_us(2);
        IIC_SCL=0;
}                                                                              
//IIC·¢ËÍÒ»¸ö×Ö½Ú
//·µ»Ø´Ó»úÓÐÎÞÓ¦´ð
//1£¬ÓÐÓ¦´ð
//0£¬ÎÞÓ¦´ð                          
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
                SDA_OUT();             
    IIC_SCL=0;//À­µÍʱÖÓ¿ªÊ¼Êý¾Ý´«Êä
    for(t=0;t<8;t++)
    {              
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1;           
                delay_us(2);   //¶ÔTEA5767ÕâÈý¸öÑÓʱ¶¼ÊDZØÐëµÄ
                IIC_SCL=1;
                delay_us(2);
                IIC_SCL=0;       
                delay_us(2);
    }         
}             
//¶Á1¸ö×Ö½Ú£¬ack=1ʱ£¬·¢ËÍACK£¬ack=0£¬·¢ËÍnACK   
u8 IIC_Read_Byte(unsigned char ack)
{
        unsigned char i,receive=0;
        SDA_IN();//SDAÉèÖÃΪÊäÈë
  for(i=0;i<8;i++ )
        {
    IIC_SCL=0;
    delay_us(2);
                IIC_SCL=1;
    receive<<=1;
    if(READ_SDA)receive++;   
                delay_us(1);
  }                                         
        if (!ack)
                        IIC_NAck();//·¢ËÍnACK
        else
                        IIC_Ack(); //·¢ËÍACK   
        return receive;
}

void IIC_WriteByte(uint16_t addr,uint8_t data,uint8_t device_addr)
{
        IIC_Start();  
       
        if(device_addr==0xA0) //eepromµØÖ·´óÓÚ1×Ö½Ú
                IIC_Send_Byte(0xA0 + ((addr/256)<<1));//·¢Ë͸ߵØÖ·
        else
                IIC_Send_Byte(device_addr);            //·¢Æ÷¼þµØÖ·
        IIC_Wait_Ack();
        IIC_Send_Byte(addr&0xFF);   //·¢Ë͵͵ØÖ·
        IIC_Wait_Ack();
        IIC_Send_Byte(data);     //·¢ËÍ×Ö½Ú                                                          
        IIC_Wait_Ack();                                
  IIC_Stop();//²úÉúÒ»¸öÍ£Ö¹Ìõ¼þ
        if(device_addr==0xA0) //
                delay_ms(10);
        else
                delay_us(2);
}

uint16_t IIC_ReadByte(uint16_t addr,uint8_t device_addr,uint8_t ByteNumToRead)  //¶Á¼Ä´æÆ÷»ò¶ÁÊý¾Ý
{       
                uint16_t data;
                IIC_Start();  
                if(device_addr==0xA0)
                        IIC_Send_Byte(0xA0 + ((addr/256)<<1));
                else
                        IIC_Send_Byte(device_addr);       
                IIC_Wait_Ack();
                IIC_Send_Byte(addr&0xFF);   //·¢Ë͵͵ØÖ·
                IIC_Wait_Ack();

                IIC_Start();         
                IIC_Send_Byte(device_addr+1);            //·¢Æ÷¼þµØÖ·
                IIC_Wait_Ack();
                if(ByteNumToRead == 1)//LM75ζÈÊý¾ÝΪ11bit
                {
                        data=IIC_Read_Byte(0);
                }
                else
                        {
                                data=IIC_Read_Byte(1);
                                data=(data<<8)+IIC_Read_Byte(0);
                        }
                IIC_Stop();//²úÉúÒ»¸öÍ£Ö¹Ìõ¼þ            
                return data;
}
举报

冯超

2021-12-10 13:56:38
一、I2C通信协议


  I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。
主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件.在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件.然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下.主机负责产生定时时钟和终止数据传送。

1、工作原理
连接在总线上的节点设备有两种角色:主机模式和从机模式。同一时刻只能有一个节点处于主机模式,其它节点处于从机模式。总线上数据的传送都是由主机发起。I2C总线是没有片选信号线的,所以也得通过协议来找到对应操作的芯片。主器件用于启动总线传输数据,并产生时钟以开放传送的器件,此时任何被寻址的器件都被认为是从器件,在总线上主和从、发和手的关系是不恒定的,而取决于此时数据传送方向。如果主机要发送数据给器件,则主机首先寻址从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件,然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下,主机负责产生时钟和终止数据传送。



  • I2C数据传输基本过程:
    1.主机首先开始发送信号
    2.主机紧接着发送从机地址信息(一个字节),该字节信息中的最低位为读写控制码:1为读,0为写。高7位为从机设备的器件地址
    3.从机然后发出确认信息
    4.主机开始发送信号数据,每当发完一个字节数据后,从机设备给主机发送确认信号
    5.主机最后发送停止信号。
    START开始信号:在SCL时钟线为高电平时,SDA数据线由高变低,产生一个开始信号
    STOP 停止信号:在SCL时钟线为高电平时,SDA数据线由低变高,产生一个停止信号
    ACK确认信号: 当主机写从机设备时,每次写完一个字节,如果数据正确,从机设备将在下一个时钟周期将数据线拉低,来通知主机操作有效。
    当主机读从机设备时,每次正确读完一个字节后,主机将在下一个时钟周期同样也要讲数据线拉低,发出确认信号,来通知从机所发数据以收到
    总之,SCL信号必须要由主机发送
    注意:在读从机设备时,当主机在最后一个字节数据接收完后,不在发送确认信号,直接发送停止信号。还有就是任何时候SCL时钟线为高电平的时候,SDA数据上的电平变化都被认为是起始信号和停止信号,所以数据的改变必须要在时钟为低电平时改变





二、硬件与软件模拟I2C的区别


  原理上:硬件I2C(提供专门的SDA,SCL口)的时钟是由系统产生的,一般由晶振分频产生。模拟I2C通过编程将通用I/O模拟为时钟线和数据线
控制上:硬件I2C通过硬件中断实现各种操作。模拟I2C没有中断的概念,通过IO接口电平置高置低来实现写入和读取
性能上:硬件模式更高效更稳定硬件I2C比软件I2C速度快很多,占用时间也少,并且硬件I2C使用简单,只需要将数据送到指定寄存器就可以了,不需要自己实现时序除了上述基本模式(串行的8位双向数据传输位速率在标准模式下可达100Kbit/s)外,快速模式下可达400Kbit/s,高速模式下可达3,4Mbit/s。这两种模式在硬件威廉希尔官方网站 和软件协议上都有变化可参考百度百科

三、AHT20温湿度传感器接stm32的软件I2C

1、实作内容


  使用i2c通信协议完成温湿度的采集工作,通过串口发往上位机
硬件选用野火的stm32f103指南者开发板,AHT20温度传感器

AHT20数据手册i2c通信相关内容




















2、实验代码

可见AHT20的官网下载相关i2c例程进行参考
打开stm32的空闲工程,将以下文件添加到工程里。
以下为需要用到的代码文件:
main.c

#include "delay.h"
#include "usart.h"
#include "bsp_i2c.h"




int main(void)
{       
        delay_init();     //延时初始化  
        uart_init(115200);         //串口波特率设置为115200
        IIC_Init();
                while(1)
        {
                printf("¿ªÊ¼²âÁ¿£¬ÇëÉԵȣº");
                read_AHT20_once();
                delay_ms(2000);
  }
}


AHT20_i2c.c


#include "bsp_i2c.h"
#include "delay.h"


uint8_t   ack_status=0;
uint8_t   readByte[6];
uint8_t   AHT20_status=0;


uint32_t  H1=0;  //Humility
uint32_t  T1=0;  //Temperature


uint8_t  AHT20_OutData[4];
uint8_t  AHT20sendOutData[10] = {0xFA, 0x06, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF};


void IIC_Init(void)
{                                             
        GPIO_InitTypeDef GPIO_InitStructure;
        RCC_APB2PeriphClockCmd(        RCC_APB2Periph_GPIOB, ENABLE );       
          
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);

        IIC_SCL=1;
        IIC_SDA=1;

}
//产生IIC起始信号
void IIC_Start(void)
{
        SDA_OUT();     //sda线输出
        IIC_SDA=1;                    
        IIC_SCL=1;
        delay_us(4);
        IIC_SDA=0;//START:when CLK is high,DATA change form high to low
        delay_us(4);
        IIC_SCL=0;//锁住I2C总线,准备发送或接收数据
}          
//²úÉúIICÍ£Ö¹ÐźÅ
void IIC_Stop(void)
{
        SDA_OUT();//sdaÏßÊä³ö
        IIC_SCL=0;
        IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
        delay_us(4);
        IIC_SCL=1;
        IIC_SDA=1;//·¢ËÍI2C×ÜÏß½áÊøÐźÅ
        delay_us(4);                                                                  
}
//µÈ´ýÓ¦´ðÐźŵ½À´
//·µ»ØÖµ£º1£¬½ÓÊÕÓ¦´ðʧ°Ü
//        0£¬½ÓÊÕÓ¦´ð³É¹¦
u8 IIC_Wait_Ack(void)
{
        u8 ucErrTime=0;
        SDA_IN();      //SDAÉèÖÃΪÊäÈë  
        IIC_SDA=1;delay_us(1);          
        IIC_SCL=1;delay_us(1);         
        while(READ_SDA)
        {
                ucErrTime++;
                if(ucErrTime>250)
                {
                        IIC_Stop();
                        return 1;
                }
        }
        IIC_SCL=0;//ʱÖÓÊä³ö0           
        return 0;  
}
//²úÉúACKÓ¦´ð
void IIC_Ack(void)
{
        IIC_SCL=0;
        SDA_OUT();
        IIC_SDA=0;
        delay_us(2);
        IIC_SCL=1;
        delay_us(2);
        IIC_SCL=0;
}
//²»²úÉúACKÓ¦´ð                    
void IIC_NAck(void)
{
        IIC_SCL=0;
        SDA_OUT();
        IIC_SDA=1;
        delay_us(2);
        IIC_SCL=1;
        delay_us(2);
        IIC_SCL=0;
}                                                                              
//IIC·¢ËÍÒ»¸ö×Ö½Ú
//·µ»Ø´Ó»úÓÐÎÞÓ¦´ð
//1£¬ÓÐÓ¦´ð
//0£¬ÎÞÓ¦´ð                          
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
                SDA_OUT();             
    IIC_SCL=0;//À­µÍʱÖÓ¿ªÊ¼Êý¾Ý´«Êä
    for(t=0;t<8;t++)
    {              
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1;           
                delay_us(2);   //¶ÔTEA5767ÕâÈý¸öÑÓʱ¶¼ÊDZØÐëµÄ
                IIC_SCL=1;
                delay_us(2);
                IIC_SCL=0;       
                delay_us(2);
    }         
}             
//¶Á1¸ö×Ö½Ú£¬ack=1ʱ£¬·¢ËÍACK£¬ack=0£¬·¢ËÍnACK   
u8 IIC_Read_Byte(unsigned char ack)
{
        unsigned char i,receive=0;
        SDA_IN();//SDAÉèÖÃΪÊäÈë
  for(i=0;i<8;i++ )
        {
    IIC_SCL=0;
    delay_us(2);
                IIC_SCL=1;
    receive<<=1;
    if(READ_SDA)receive++;   
                delay_us(1);
  }                                         
        if (!ack)
                        IIC_NAck();//·¢ËÍnACK
        else
                        IIC_Ack(); //·¢ËÍACK   
        return receive;
}

void IIC_WriteByte(uint16_t addr,uint8_t data,uint8_t device_addr)
{
        IIC_Start();  
       
        if(device_addr==0xA0) //eepromµØÖ·´óÓÚ1×Ö½Ú
                IIC_Send_Byte(0xA0 + ((addr/256)<<1));//·¢Ë͸ߵØÖ·
        else
                IIC_Send_Byte(device_addr);            //·¢Æ÷¼þµØÖ·
        IIC_Wait_Ack();
        IIC_Send_Byte(addr&0xFF);   //·¢Ë͵͵ØÖ·
        IIC_Wait_Ack();
        IIC_Send_Byte(data);     //·¢ËÍ×Ö½Ú                                                          
        IIC_Wait_Ack();                                
  IIC_Stop();//²úÉúÒ»¸öÍ£Ö¹Ìõ¼þ
        if(device_addr==0xA0) //
                delay_ms(10);
        else
                delay_us(2);
}

uint16_t IIC_ReadByte(uint16_t addr,uint8_t device_addr,uint8_t ByteNumToRead)  //¶Á¼Ä´æÆ÷»ò¶ÁÊý¾Ý
{       
                uint16_t data;
                IIC_Start();  
                if(device_addr==0xA0)
                        IIC_Send_Byte(0xA0 + ((addr/256)<<1));
                else
                        IIC_Send_Byte(device_addr);       
                IIC_Wait_Ack();
                IIC_Send_Byte(addr&0xFF);   //·¢Ë͵͵ØÖ·
                IIC_Wait_Ack();

                IIC_Start();         
                IIC_Send_Byte(device_addr+1);            //·¢Æ÷¼þµØÖ·
                IIC_Wait_Ack();
                if(ByteNumToRead == 1)//LM75ζÈÊý¾ÝΪ11bit
                {
                        data=IIC_Read_Byte(0);
                }
                else
                        {
                                data=IIC_Read_Byte(1);
                                data=(data<<8)+IIC_Read_Byte(0);
                        }
                IIC_Stop();//²úÉúÒ»¸öÍ£Ö¹Ìõ¼þ            
                return data;
}
举报

张文

2021-12-10 13:57:14
/**********
*ÉÏÃ沿·ÖΪIO¿ÚÄ£¿éI2CÅäÖÃ
*
*´ÓÕâÒÔÏ¿ªÊ¼ÎªAHT20µÄÅäÖÃI2C
*º¯ÊýÃûÓÐIICºÍI2CµÄÇø±ð£¬Çë×¢Ò⣡£¡£¡£¡£¡
*
*2020/2/23×îºóÐÞ¸ÄÈÕÆÚ
*
***********/
void  read_AHT20_once(void)
{
        delay_ms(10);


        reset_AHT20();
        delay_ms(10);


        init_AHT20();
        delay_ms(10);


        startMeasure_AHT20();
        delay_ms(80);


        read_AHT20();
        delay_ms(5);
}




void  reset_AHT20(void)
{


        I2C_Start();


        I2C_WriteByte(0x70);
        ack_status = Receive_ACK();
        if(ack_status) ;
        else printf("1-n-");
        I2C_WriteByte(0xBA);
        ack_status = Receive_ACK();
                if(ack_status) ;
        else printf("2-n-");
        I2C_Stop();


        /*
        AHT20_OutData[0] = 0;
        AHT20_OutData[1] = 0;
        AHT20_OutData[2] = 0;
        AHT20_OutData[3] = 0;
        */
}






void  init_AHT20(void)
{
        I2C_Start();


        I2C_WriteByte(0x70);
        ack_status = Receive_ACK();
        if(ack_status) ;
        else printf("3-n-");       
        I2C_WriteByte(0xE1);
        ack_status = Receive_ACK();
        if(ack_status) ;
        else printf("4-n-");
        I2C_WriteByte(0x08);
        ack_status = Receive_ACK();
        if(ack_status) ;
        else printf("5-n-");
        I2C_WriteByte(0x00);
        ack_status = Receive_ACK();
        if(ack_status) ;
        else printf("6-n-");
        I2C_Stop();
}






void  startMeasure_AHT20(void)
{
        //------------
        I2C_Start();


        I2C_WriteByte(0x70);
        ack_status = Receive_ACK();
        if(ack_status);
        else printf("7-n-");
        I2C_WriteByte(0xAC);
        ack_status = Receive_ACK();
        if(ack_status) ;
        else printf("8-n-");
        I2C_WriteByte(0x33);
        ack_status = Receive_ACK();
        if(ack_status);
        else printf("9-n-");
        I2C_WriteByte(0x00);
        ack_status = Receive_ACK();
        if(ack_status) ;
        else printf("10-n-");
        I2C_Stop();
}






void read_AHT20(void)
{
        uint8_t   i;


        for(i=0; i<6; i++)
        {
                readByte=0;
        }


        //-------------
        I2C_Start();


        I2C_WriteByte(0x71);
        ack_status = Receive_ACK();
        readByte[0]= I2C_ReadByte();
        Send_ACK();


        readByte[1]= I2C_ReadByte();
        Send_ACK();


        readByte[2]= I2C_ReadByte();
        Send_ACK();


        readByte[3]= I2C_ReadByte();
        Send_ACK();


        readByte[4]= I2C_ReadByte();
        Send_ACK();


        readByte[5]= I2C_ReadByte();
        SendNot_Ack();
        //Send_ACK();


        I2C_Stop();


        //--------------
        if( (readByte[0] & 0x68) == 0x08 )
        {
                H1 = readByte[1];
                H1 = (H1<<8) | readByte[2];
                H1 = (H1<<8) | readByte[3];
                H1 = H1>>4;


                H1 = (H1*1000)/1024/1024;


                T1 = readByte[3];
                T1 = T1 & 0x0000000F;
                T1 = (T1<<8) | readByte[4];
                T1 = (T1<<8) | readByte[5];


                T1 = (T1*2000)/1024/1024 - 500;


                AHT20_OutData[0] = (H1>>8) & 0x000000FF;
                AHT20_OutData[1] = H1 & 0x000000FF;


                AHT20_OutData[2] = (T1>>8) & 0x000000FF;
                AHT20_OutData[3] = T1 & 0x000000FF;
        }
        else
        {
                AHT20_OutData[0] = 0xFF;
                AHT20_OutData[1] = 0xFF;


                AHT20_OutData[2] = 0xFF;
                AHT20_OutData[3] = 0xFF;
                printf("ʧ°ÜÁË");


        }
        printf("rn");
        printf("ζÈ:%d.%d",T1/10,T1%10);
        printf("ʪ¶È:%d.%d",H1/10,H1%10);
        printf("rn");
}








uint8_t  Receive_ACK(void)
{
        uint8_t result=0;
        uint8_t cnt=0;


        IIC_SCL = 0;
        SDA_IN();
        delay_us(4);


        IIC_SCL = 1;
        delay_us(4);


        while(READ_SDA && (cnt<100))
        {
                cnt++;
        }


        IIC_SCL = 0;
        delay_us(4);


        if(cnt<100)
        {
                result=1;
        }
        return result;
}






void  Send_ACK(void)
{
        SDA_OUT();
        IIC_SCL = 0;
        delay_us(4);


        IIC_SDA = 0;
        delay_us(4);


        IIC_SCL = 1;
        delay_us(4);
        IIC_SCL = 0;
        delay_us(4);


        SDA_IN();
}






void  SendNot_Ack(void)
{
        SDA_OUT();
        IIC_SCL = 0;
        delay_us(4);


        IIC_SDA = 1;
        delay_us(4);


        IIC_SCL = 1;
        delay_us(4);


        IIC_SCL = 0;
        delay_us(4);


        IIC_SDA = 0;
        delay_us(4);
}




void I2C_WriteByte(uint8_t  input)
{
        uint8_t  i;
        SDA_OUT();
        for(i=0; i<8; i++)
        {
                IIC_SCL = 0;
                delay_ms(5);


                if(input & 0x80)
                {
                        IIC_SDA = 1;
                        //delaymm(10);
                }
                else
                {
                        IIC_SDA = 0;
                        //delaymm(10);
                }


                IIC_SCL = 1;
                delay_ms(5);


                input = (input<<1);
        }


        IIC_SCL = 0;
        delay_us(4);


        SDA_IN();
        delay_us(4);
}       




uint8_t I2C_ReadByte(void)
{
        uint8_t  resultByte=0;
        uint8_t  i=0, a=0;


        IIC_SCL = 0;
        SDA_IN();
        delay_ms(4);


        for(i=0; i<8; i++)
        {
                IIC_SCL = 1;
                delay_ms(3);


                a=0;
                if(READ_SDA)
                {
                        a=1;
                }
                else
                {
                        a=0;
                }


                //resultByte = resultByte | a;
                resultByte = (resultByte << 1) | a;


                IIC_SCL = 0;
                delay_ms(3);
        }


        SDA_IN();
        delay_ms(10);


        return   resultByte;
}




void  set_AHT20sendOutData(void)
{
        /* --------------------------
         * 0xFA 0x06 0x0A temperature(2 Bytes) humility(2Bytes) short Address(2 Bytes)
         * And Check (1 byte)
         * -------------------------*/
        AHT20sendOutData[3] = AHT20_OutData[0];
        AHT20sendOutData[4] = AHT20_OutData[1];
        AHT20sendOutData[5] = AHT20_OutData[2];
        AHT20sendOutData[6] = AHT20_OutData[3];


//        AHT20sendOutData[7] = (drf1609.shortAddress >> 8) & 0x00FF;
//        AHT20sendOutData[8] = drf1609.shortAddress  & 0x00FF;


//        AHT20sendOutData[9] = getXY(AHT20sendOutData,10);
}




void  I2C_Start(void)
{
        SDA_OUT();
        IIC_SCL = 1;
        delay_ms(4);


        IIC_SDA = 1;
        delay_ms(4);
        IIC_SDA = 0;
        delay_ms(4);


        IIC_SCL = 0;
        delay_ms(4);
}






void  I2C_Stop(void)
{
        SDA_OUT();
        IIC_SDA = 0;
        delay_ms(4);


        IIC_SCL = 1;
        delay_ms(4);


        IIC_SDA = 1;
        delay_ms(4);
}
AHT20_i2c.h


#ifndef __BSP_I2C_H
#define __BSP_I2C_H


#include "sys.h"
#include "delay.h"
#include "usart.h"
//使用IIC1 挂载M24C02,OLED,LM75AD,HT1382    PB6,PB7

#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}

//IO操作函数         
#define IIC_SCL    PBout(6) //SCL
#define IIC_SDA    PBout(7) //SDA         
#define READ_SDA   PBin(7)  //输入SDA




//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口                                 
void IIC_Start(void);                                //发送IIC开始信号
void IIC_Stop(void);                                  //发送IIC停止信号
void IIC_Send_Byte(u8 txd);                        //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void);                                 //IIC等待ACK信号
void IIC_Ack(void);                                        //IIC发送ACK信号
void IIC_NAck(void);                                //IIC不发送ACK信号

void IIC_WriteByte(uint16_t addr,uint8_t data,uint8_t device_addr);
uint16_t IIC_ReadByte(uint16_t addr,uint8_t device_addr,uint8_t ByteNumToRead);//寄存器地址,器件地址,要读的字节数  




void  read_AHT20_once(void);
void  reset_AHT20(void);
void  init_AHT20(void);       
void  startMeasure_AHT20(void);
void  read_AHT20(void);
uint8_t  Receive_ACK(void);
void  Send_ACK(void);
void  SendNot_Ack(void);
void I2C_WriteByte(uint8_t  input);
uint8_t I2C_ReadByte(void);       
void  set_AHT20sendOutData(void);
void  I2C_Start(void);
void  I2C_Stop(void);
#endif


usart.c


#include "sys.h"
#include "usart.h"




//STM32F103核心板例程
//库函数版本例程
/********** mcudev.taobao.com 出品  ********/




//   
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_UCOS
#include "includes.h" //ucos 使用   
#endif
//  
//STM32开发板
//串口1初始化   


//   



//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB   
#if 1
#pragma import(__use_no_semihosting)            
//标准库需要的支持函数                 
struct __FILE
{
int handle;


};


FILE __stdout;      
//定义_sys_exit()以避免使用半主机模式   
void _sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{      
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
return ch;
}
#endif


/*使用microLib的方法*/
/*
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (uint8_t) ch);


while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {}
   
    return ch;
}
int GetKey (void)  {


    while (!(USART1->SR & USART_FLAG_RXNE));


    return ((int)(USART1->DR & 0x1FF));
}
*/

#if EN_USART1_RX   //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0;       //接收状态标记   
  
void uart_init(u32 bound){
    //GPIO端口设置
  GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
     //USART1_TX   PA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);
   
    //USART1_RX   PA.10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);  


   //Usart1 NVIC 配置


    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
  
   //USART 初始化设置


USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式


    USART_Init(USART1, &USART_InitStructure); //初始化串口
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
    USART_Cmd(USART1, ENABLE);                    //使能串口


}
举报

宋玉红

2021-12-10 13:58:18
void USART1_IRQHandler(void)                 //串口1中断服务程序
{
u8 Res;
#ifdef OS_TICKS_PER_SEC   //如果时钟节拍数定义了,说明要使用ucosII了.
OSIntEnter();   
#endif
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据

if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收   
}  
}
}     
     }
#ifdef OS_TICKS_PER_SEC   //如果时钟节拍数定义了,说明要使用ucosII了.
OSIntExit();   
#endif
}
#endif


usart.h


#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "sys.h"


//STM32F103核心板例程
//库函数版本例程
/********** mcudev.taobao.com 出品  ********/


//  
//STM32开发板
//串口1初始化   


#define USART_REC_LEN   200   //定义最大接收字节数 200
#define EN_USART1_RX  1     //使能(1)/禁止(0)串口1接收
   
extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART_RX_STA;          //接收状态标记
//如果想串口中断接收,请不要注释以下宏定义
void uart_init(u32 bound);
#endif


delay.c


#include "delay.h"
#include "sys.h"


//STM32F103ºËÐÄ°åÀý³Ì
//¿âº¯Êý°æ±¾Àý³Ì
/********** mcudev.taobao.com ³öÆ·  ********/




//   
//Èç¹ûʹÓÃucos,Ôò°üÀ¨ÏÂÃæµÄÍ·Îļþ¼´¿É.
#if SYSTEM_SUPPORT_UCOS
#include "includes.h" //ucos ʹÓà  
#endif
//  


//STM32¿ª·¢°å
//ʹÓÃSysTickµÄÆÕͨ¼ÆÊýģʽ¶ÔÑÓ³Ù½øÐйÜÀí
//°üÀ¨delay_us,delay_ms


//   
static u8  fac_us=0;//usÑÓʱ±¶³ËÊý
static u16 fac_ms=0;//msÑÓʱ±¶³ËÊý
#ifdef OS_CRITICAL_METHOD  //Èç¹ûOS_CRITICAL_METHOD¶¨ÒåÁË,˵Ã÷ʹÓÃucosIIÁË.
//systickÖжϷþÎñº¯Êý,ʹÓÃucosʱÓõ½
void SysTick_Handler(void)
{   
OSIntEnter(); //½øÈëÖжÏ
    OSTimeTick();       //µ÷ÓÃucosµÄʱÖÓ·þÎñ³ÌÐò               
    OSIntExit();        //´¥·¢ÈÎÎñÇл»ÈíÖжÏ
}
#endif


//³õʼ»¯ÑÓ³Ùº¯Êý
//µ±Ê¹ÓÃucosµÄʱºò,´Ëº¯Êý»á³õʼ»¯ucosµÄʱÖÓ½ÚÅÄ
//SYSTICKµÄʱÖӹ̶¨ÎªHCLKʱÖÓµÄ1/8
//SYSCLK:ϵͳʱÖÓ
void delay_init()  
{


#ifdef OS_CRITICAL_METHOD  //Èç¹ûOS_CRITICAL_METHOD¶¨ÒåÁË,˵Ã÷ʹÓÃucosIIÁË.
u32 reload;
#endif
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //Ñ¡ÔñÍⲿʱÖÓ  HCLK/8
fac_us=SystemCoreClock/8000000; //ΪϵͳʱÖÓµÄ1/8  

#ifdef OS_CRITICAL_METHOD  //Èç¹ûOS_CRITICAL_METHOD¶¨ÒåÁË,˵Ã÷ʹÓÃucosIIÁË.
reload=SystemCoreClock/8000000; //ÿÃëÖӵļÆÊý´ÎÊý µ¥Î»ÎªK   
reload*=1000000/OS_TICKS_PER_SEC;//¸ù¾ÝOS_TICKS_PER_SECÉ趨Òç³öʱ¼ä
//reloadΪ24λ¼Ä´æÆ÷,×î´óÖµ:16777216,ÔÚ72MÏÂ,Ô¼ºÏ1.86s×óÓÒ
fac_ms=1000/OS_TICKS_PER_SEC;//´ú±íucos¿ÉÒÔÑÓʱµÄ×îÉÙµ¥Î»   
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;    //¿ªÆôSYSTICKÖжÏ
SysTick->LOAD=reload;  //ÿ1/OS_TICKS_PER_SECÃëÖжÏÒ»´Î
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;    //¿ªÆôSYSTICK   
#else
fac_ms=(u16)fac_us*1000;//·ÇucosÏÂ,´ú±íÿ¸ömsÐèÒªµÄsystickʱÖÓÊý   
#endif
}     


#ifdef OS_CRITICAL_METHOD //ʹÓÃÁËucos
//ÑÓʱnus
//nusΪҪÑÓʱµÄusÊý.         
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //LOADµÄÖµ      
ticks=nus*fac_us;  //ÐèÒªµÄ½ÚÅÄÊý     
tcnt=0;
told=SysTick->VAL;         //¸Õ½øÈëʱµÄ¼ÆÊýÆ÷Öµ
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{     
if(tnow else tcnt+=reload-tnow+told;     
told=tnow;
if(tcnt>=ticks)break;//ʱ¼ä³¬¹ý/µÈÓÚÒªÑÓ³ÙµÄʱ¼ä,ÔòÍ˳ö.
}  
};      
}
//ÑÓʱnms
//nms:ÒªÑÓʱµÄmsÊý
void delay_ms(u16 nms)
{
if(OSRunning==TRUE)//Èç¹ûosÒѾ­ÔÚÅÜÁË     
{   
if(nms>=fac_ms)//ÑÓʱµÄʱ¼ä´óÓÚucosµÄ×îÉÙʱ¼äÖÜÆÚ
{
    OSTimeDly(nms/fac_ms);//ucosÑÓʱ
}
nms%=fac_ms; //ucosÒѾ­ÎÞ·¨ÌṩÕâôСµÄÑÓʱÁË,²ÉÓÃÆÕͨ·½Ê½ÑÓʱ   
}
delay_us((u32)(nms*1000)); //ÆÕͨ·½Ê½ÑÓʱ,´ËʱucosÎÞ·¨Æô¶¯µ÷¶È.
}
#else//²»ÓÃucosʱ
//ÑÓʱnus
//nusΪҪÑÓʱµÄusÊý.         
void delay_us(u32 nus)
{
u32 temp;      
SysTick->LOAD=nus*fac_us; //ʱ¼ä¼ÓÔØ     
SysTick->VAL=0x00;        //Çå¿Õ¼ÆÊýÆ÷
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;          //¿ªÊ¼µ¹Êý  
do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(1<<16)));//µÈ´ýʱ¼äµ½´ï   
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;       //¹Ø±Õ¼ÆÊýÆ÷
SysTick->VAL =0X00;       //Çå¿Õ¼ÆÊýÆ÷  
}
//ÑÓʱnms
//×¢ÒânmsµÄ·¶Î§
//SysTick->LOADΪ24λ¼Ä´æÆ÷,ËùÒÔ,×î´óÑÓʱΪ:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLKµ¥Î»ÎªHz,nmsµ¥Î»Îªms
//¶Ô72MÌõ¼þÏÂ,nms<=1864
void delay_ms(u16 nms)
{        
u32 temp;   
SysTick->LOAD=(u32)nms*fac_ms;//ʱ¼ä¼ÓÔØ(SysTick->LOADΪ24bit)
SysTick->VAL =0x00;           //Çå¿Õ¼ÆÊýÆ÷
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;          //¿ªÊ¼µ¹Êý  
do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(1<<16)));//µÈ´ýʱ¼äµ½´ï   
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;       //¹Ø±Õ¼ÆÊýÆ÷
SysTick->VAL =0X00;       //Çå¿Õ¼ÆÊýÆ÷        
}
#endif


delay.h


#ifndef __DELAY_H
#define __DELAY_H     
#include "sys.h"
//  


//STM32F103核心板例程
//库函数版本例程
/********** mcudev.taobao.com 出品  ********/




//使用SysTick的普通计数模式对延迟进行管理
//包括delay_us,delay_ms


//   
void delay_init(void);
void delay_ms(u16 nms);
void delay_us(u32 nus);


#endif


将以上文件放到工程目录,并添加入工程,模拟管脚 PB6 为SCl,PB7 为SDA
举报

更多回帖

×
20
完善资料,
赚取积分