STM32的I2C通信实例pcf8591(AD/DA)原创干货

 

STM32的I2C通信实例pcf8591(AD/DA)原创干货_第1张图片

STM32的I2C通信实例pcf8591(AD/DA)原创干货_第2张图片

 

 

STM32的I2C通信实例pcf8591(AD/DA)原创干货_第3张图片

本程序是stm32f103 接pcf8591AD/DA板(YL-PCF8591),I2C通信,I2C通信用的是模拟I2C,不是STM32 自带的硬件I2C外设。实践检验很稳定。SCL接口用PB6,SDA用PB7,与STM32自带的硬件I2C接口针脚是一样的,这是巧合,你也可以随便定义成别Pin针脚。关于GPIO设置,最后有解释。

  1. Pcf8591地址写是0x90,读是0x91,
  2. AIN0地址是0x40 -------AIN3地址是0x43,注意AOUT地址也是0x40

写比较简单看下面程序:下面是DA(数/模转换主程序)主要用写函数。

u8 DACconversion(u8 sla,u8 c,  u8 Val)

{

   Start_I2c();              //启动总线

   SendByte(sla);            //发送器件地址

   ack();                      //8591应答

   SendByte(c);              //发送控制字节

    ack();                  //8591应答

   SendByte(Val);            //发送DAC的数值 

    ack();                       //8591应答

   Stop_I2c();               //结束总线

   return(1);

}

启动:SCL高电平中间SDA高变低,紧接着SCL变低,

停止:SCL低电平变高电平后,SDA低变高,

Ack应答是主机释放SDA后,从机(PCF8591把SDA拉低)。

DA转换的过程是,先开始,发送从机地址90,从机应答后,发送寄存器地址,40代表AIN0(AOUT也是40 ),从机应答后,发送写入的数据,从机应答,结束传输。

是不是很简单?DOUT输出电压范围(0-255对应0-3.3v )输出接口接有蓝色LED,输出电压大于2V,LED 开始亮起了,电压越高,越亮。

----------------------------------------------------------------------------------------------/

下面说明读数据程序,稍微复杂一点。

u8 ADCconversion(u8 sla,u8 c)

{

       u8 d;

   Start_I2c();              //启动总线

   SendByte(sla);            //发送器件地址0x90

   ack();                    //从机接收后应达

   SendByte(c);              //发送控制字节0x43

    ack();                   //从机接收后应达

Stop_I2c();               //停止总线

//------------------------------------------------

Start_I2c();              //启动总线

SendByte(sla+1);           //发送读AIN3指令

ack();                    //从机应对不能少

   d=RcvByte();            //发送DAC的数值 

   Ack_I2c(0);             //主机接收后应答不能少否则不稳定

   Stop_I2c();               //结束总线

   return(d);

}

我们读取第4个AIN口因为接有可变电阻,可以直观看到输入数据变化,AIN3地址是0x43(第一个是光敏)(第二个是热敏)(第三个是直通)

下面分析程序,下面是AD转换,接收第四个AIN的电压信号,0-3.3V对应数字0-255:

AD起始的程序和DA相同,开始-发送从站地址90,从站应答,发送控制字43,从站应答,之后的程序就不一样的,停止

再次开始,发送读指令91,从站应答,主机读8位数据,读到后主机应答0,表示接受到,最后停止传输。(注意没有这个主机接收应答,接收到数据就乱了在数据和255之间乱跳)。

可以看到Ad转换开始停止两次。特别注意,主机接收到数据后,主机回复Ack(0)。不是从机。

///------------------------------------------------------------------------------------------------///

最后说一下关于:IIC的GPIO设置。

void GPIO_init(void)

{

      GPIO_InitTypeDef GPIO_InitStructure;

 

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

     

      GPIO_InitStructure.GPIO_Pin = SCL_Pin | SDA_Pin;     /*初始化IO*/

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      

      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;

      GPIO_Init(GPIOB, &GPIO_InitStructure);

 

      SCL_SET(1);

      flash();

      SDA_SET(1);

      flash();

}

这是GPIO初始化程序,可见GPIO设置为推挽输出,这样I2C的波形用示波器观察就是正经的方波,但是推挽输出只能写数据,I2C读数据的时候必须用in_floating,见下面:

void SDA_IO_IN(void)

{

      GPIO_InitTypeDef GPIO_InitStructure;

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

      GPIO_InitStructure.GPIO_Pin = SDA_Pin;  /*初始化IO*/

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;      

      GPIO_Init(GPIOB, &GPIO_InitStructure);

}

 

void SDA_IO_OUT(void)

{

      GPIO_InitTypeDef GPIO_InitStructure;

      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

      GPIO_InitStructure.GPIO_Pin = SDA_Pin;  /*初始化IO*/

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      

      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;

      GPIO_Init(GPIOB, &GPIO_InitStructure);

}

上面程序可见,SCL(PB6)是主机主导,所以一般设为PP不变(推挽输出),SDA因为读到时候是从机发数据,所以对于SDA(PB7)脚,在写数据时候设置成PP(推挽输出),在读入数据时设置成in_floating。这样的波形很漂亮的方波,用示波器观察很爽,逻辑清晰可见。

也有的程序SCL SDA 都设置成OD(开漏输出)不变,这就不用设置变来变去,也是可以的,就是观察波形的时候,波形底部是方波(因为漏极有场效应管通断),波形上部就是三角锯齿波了,(因为没有上场效应管控制,高电位是靠上拉电阻)。这种设置也是可以用,还简单,就是不利于用示波器观察。

你可能感兴趣的:(单片机,stm32,嵌入式)