STM32F1 GPIO模拟I2C

gpio:

     通用输入输出端口的简称,也就是stm32可控制的引脚,stm32芯片的GPIO分为很多组,每组16个引脚。stm32f103vet的芯片共有5组GPIO引脚

一、gpio工作模式

  

输入模式:

  1. 模拟输入:输入模拟信号,用于ADC采集。

  2. 浮空输入:输入不确定,完全由外部的输入决定。

  3. 上拉输入:默认电平由上拉电阻决定

  4. 下拉输入:默认电平由下拉电阻决定

输出模式:

  1. 开漏输出:上方的P-MOS管完全不工作(关闭),如果控制输出为0,低电平,则N-MOS管导通,使输出接地。如果控制输出为1,高电平,则N-MOS管关闭,所以引脚既不输出高电平,也不输出低电平,为高阻态。

  2. 推免输出:输出寄存器上的0激活N-MOS,为低电平。而输出寄存器上的1将激活P-MOS,为高电平

复用模式:输出数据寄存器无效,输出信号源来自其他外设,可工作在推免及开漏模式。输入有效

  1. 复用开漏输出:

  2. 复用推免输出:

二、BERR寄存器

i2c协议

 

    I2C 总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成。通信原理是通过对SCL和SDA线高低电平时序的控制,来产生I2C总线协议所需要的信号进行数据的传递。在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平。

I2C通信方式为半双工,只有一根SDA线,同一时间只可以单向通信,

 

I2C物理通信特点

(1)它是一个支持设备的总线。在一个I2C通信总线中,可连接多个I2C通信设备,支持多个通信主机及多个通信从机。

(2)一个I2C总线只使用两条线路,一条双向串行数据线(SDA),一条串行时钟线(SCL)

(3)每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。

(4)总线通过上拉电阻接到电源。当I2C设备空闲时,会输出高阻态,而当设备都空闲时,都输出高阻态时,有上拉电阻吧总线拉成高电平。

(5)多个主机同时使用总线时,为防止数据冲突,会利用仲裁的方式决定由那个设备占用总线。

I2C协议层

(6)具有三种传输模式:标准模式传输效率为100kbps,快速模式为400kbps,高速模式可达3.4Mbps。

 

 

I2C的协议定义了通信的起始和停止信号、数据有效性、响应、仲裁、时钟同步和地址广播环节等。

 

起始和停止信号:

起始(S):当SCL线是高电平时,SDA线从高电平向低电平切换。

停止(P):当SCL线是高电平时,SDA线从低电平向高电平切换。

数据有效性:

SDA数据线在SCL的每个时钟周期只传输一位数据。传输时,SCL为高电平时SDA表示的数据有效,及此时,SDA为高电平时表示数据为“1”,为低电平是表示的数据为“0”。当SCL为低电平时,SDA数据无效。

地址及数据方向:

I2C协议规定设备的地址可以是7位或10位,实际总7位的地址应用比较广泛。紧跟设备地址的一个数据位用来表示数据传输方向。数据方向位为“1”时表示主机读从机数据,为“0”时,表示主机向从机写数据。

读数据时主机会释放SDA信号线的控制,有从机控制SDA线

响应:

I2C数据和地址传输都带响应。响应包括“应答(ACK)”和“非应答(NACK)”

应答信号(ACK):SCL为高电平时,SDA为低电平.

非应答信号(NACK):SCL为低电平时,SDA为高电平.

 

iic发送/接收数据

 

数据包以8bit为单位进行发送/接收,每发送/接收一个字节的数据,主机必需发送/接收到一个应答信号才能进行下一步操作。当SCL为高电平时,主机发送/接收数据,为低时,根据要发送的数据改变SDA输出。

 

gpio模拟iic

 

//iic_sht20.h

#include "stm32f1xx_hal.h"

 

#define GPIO_PORT_I2C      GPIOA                 // GPIO端口

#define I2C_SCL_PIN        SCL_Pin             // 连接到SCL时钟线的GPIO

#define I2C_SDA_PIN        SDA_Pin             // 连接到SDA数据线的GPIO

#define W_ADDR        0X81   

#define R_ADDR        0X80

 

/*commnd*/

#define T_HOST_MEASURE       0xe3u

#define RH_HOST_MEASURE    0xe5u

#define T_NOHOST_MEASURE   0xf3u

#define RH_NOHOST_MEASURE  0xf5u

#define WRITE_USER_REG     0xd6u

#define READ_USER_REG      0xd7u

#define RESET              0xfeu

/* 定义读写SCL和SDA的宏 */

#define I2C_SCL_1()  GPIO_PORT_I2C->BSRR = I2C_SCL_PIN                   // SCL = 1

#define I2C_SCL_0()  GPIO_PORT_I2C->BSRR = (uint32_t)I2C_SCL_PIN << 16U   // SCL = 0

 

#define I2C_SDA_1()  GPIO_PORT_I2C->BSRR=I2C_SDA_PIN   // SDA = 1                                   

#define I2C_SDA_0()  GPIO_PORT_I2C->BSRR = (uint32_t)I2C_SDA_PIN << 16U  // SDA = 0

 

void i2c_Start(void);

void i2c_Stop(void);

void i2c_Ack(void);

void i2c_SendByte(uint8_t _ucByte);

uint8_t i2c_ReadByte(void);

uint8_t i2c_WaitAck(void);

GPIO_PinState I2C_SDA_READ(void);

GPIO_PinState I2C_SCL_READ(void);

uint8_t i2c_CheckDevice(uint8_t _Address);

uint8_t sht20_send_cmd(uint8_t cmd, uint8_t *buf, uint8_t size);

 

 

//iic_sht20.c

#include "iic_sht20.h"

static void i2c_Delay(void)

{

    uint8_t i,j;

    for (i = 0; i < 255; i++)

    {

        for(j=0;j<255;j++);

    }

}

 

GPIO_PinState I2C_SDA_READ(void)  

{

    return     HAL_GPIO_ReadPin(GPIOA,SDA_Pin);

}

GPIO_PinState I2C_SCL_READ(void)

{

    return HAL_GPIO_ReadPin(GPIOA,SCL_Pin);

}

/***

*主机发送数据,需要设置为开漏输出模式 选用推免输出可能会产生很大的电流,烧毁器件, 而*开漏输出不接上拉电阻不能输出高电平,加上拉电阻时电流由上拉电阻决定,因此使用开漏输出

*/

void set_mode_out(void)   

{

    GPIO_InitTypeDef GPIO_InitStruct = {0};

        GPIO_InitStruct.Pin = SDA_Pin;

        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; 

        GPIO_InitStruct.Pull = GPIO_NOPULL;

        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

void set_mode_in(void)   //接收数据,需要设置为浮空输入

{

        GPIO_InitTypeDef GPIO_InitStruct = {0};

        GPIO_InitStruct.Pin = SDA_Pin;

        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

        GPIO_InitStruct.Pull = GPIO_NOPULL;

        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

 

void i2c_Start(void)// 开始信号,当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 

 

    I2C_SDA_1();

    I2C_SCL_1();

    i2c_Delay();

    I2C_SDA_0();

    i2c_Delay();

    I2C_SCL_0();

    i2c_Delay();

}

 

void i2c_Stop(void)

{

    I2C_SDA_0();

    I2C_SCL_1();

    i2c_Delay();

    I2C_SDA_1();

    i2c_Delay();

}

void i2c_SendByte(uint8_t _ucByte)

{

    uint8_t i;

    for (i = 0; i < 8; i++)

    {

        if (_ucByte & 0x80)

        {

            I2C_SDA_1();

        }

        else

        {

            I2C_SDA_0();

        }

        i2c_Delay();

        I2C_SCL_1();

        i2c_Delay();

        I2C_SCL_0();

        if (i == 7)

        {

             I2C_SDA_1();     // 释放总线

        }

        _ucByte <<= 1;        

        i2c_Delay();

    }

}

uint8_t i2c_ReadByte(void)

{

    uint8_t i;

    uint8_t value;

    set_mode_in();

    value = 0;

    for (i = 0; i < 8; i++)

    {

        value <<= 1;

        I2C_SCL_1();

        if (GPIO_PIN_SET==I2C_SDA_READ())

        {

            value|=0x01;

        }

        I2C_SCL_0();

        i2c_Delay();

    }

    set_mode_out();

    return value;

}

 

 

uint8_t i2c_WaitAck(void)

{

    uint8_t re;

 

    I2C_SDA_1();    /* CPU释放SDA总线 */

    set_mode_in();

    I2C_SCL_1();    /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */

    i2c_Delay();

    if (GPIO_PIN_SET==HAL_GPIO_ReadPin(GPIOA,I2C_SDA_PIN))    

    {

        re = 1;

    }

    else

    {

        re = 0;

    }

    I2C_SCL_0();

    i2c_Delay();

    set_mode_out();

    return re;

}

 

void i2c_Ack(void)

{

    set_mode_out();

    I2C_SDA_0();    /* CPU驱动SDA = 0 */

    I2C_SCL_1();    

    i2c_Delay();

    I2C_SCL_0();

    i2c_Delay();

}

 

void i2c_NAck(void)

{

    I2C_SDA_1();    /* CPU驱动SDA = 1 */

    i2c_Delay();

    I2C_SCL_1();    

    i2c_Delay();

    I2C_SCL_0();

    i2c_Delay();

}

 

uint8_t i2c_CheckDevice(uint8_t _Address)

{

    uint8_t ucAck;

       i2c_Stop();

    if(I2C_SDA_READ() && I2C_SCL_READ())

    {

        i2c_Start();    

        i2c_SendByte(_Address);

        ucAck = i2c_WaitAck();    

        i2c_Stop();        

        return ucAck;

    }

    return 2;    /* I2C总线异常 */

}

 

/*      */

uint8_t Measure(uint8_t *buf,uint8_t cmd,uint8_t size)

{

        if(size<3)      /*两个数据位和一个校验位*/

    {

        return 1;

    }

    i2c_Stop();

    i2c_Start();

    i2c_SendByte(0x80);

    if(i2c_WaitAck()!=0)

    {

        return 1;

    }

    i2c_SendByte(cmd);    //测量命令

    if(i2c_WaitAck()!=0)

    {

       return 2;

    }

    i2c_Start();

    i2c_SendByte(0x81);

    if(i2c_WaitAck()!=0)

    {

          return 3;

    }    

        HAL_Delay(66);     //sht20测量延时

        buf[0]=i2c_ReadByte();

        i2c_Ack();

        buf[1]=i2c_ReadByte();

    i2c_Ack();

    buf[2]=i2c_ReadByte();

    i2c_NAck();

         i2c_Stop();

    

    return 0;

}

 

 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值