原创 stm32f4标准库开发——模拟iic

2022-1-22 23:11 1962 11 11 分类: MCU/ 嵌入式 文集: stm32f4标准库开发
stm32f4标准库开发——模拟iic 主要概念:

 IIC总线:I2C 总线是一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。

 IIC总线定义:时钟线:sck 数据线:sda

 软件模拟:通过软件控制普通 GPIO 引脚高低点评切换,来模拟总线时序,从而达到与总线协议一样的效果。

 缺点:与使用硬件 IIC 相比,会占用更多的 CPU 时间。

 

实验目的:

 本实现通过软件模拟 IIC 时序,编写 IIC 发送接收函数。

 

硬件电路:

 本实验的蜂鸣器为有源蜂鸣器

 PB8 -->  IIC_SCL

 PB9 -->  IIC_SDA

 

 

主要库函数调用:

#define sda_in()  {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;}
#define sda_out() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;}
#define iic_sda_out(x)        PBout(9)=x
#define iic_scl_out(x)        PBout(8)=x
#define iix_read_sda()        PBin(9)

 

代码:

//iic.c
#include "iic.h"
#include "base.h"
#include "delay.h"

//***********************************************************************
//移植修改部分
#define sda_in()  {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;}
#define sda_out() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;}
#define iic_sda_out(x)        PBout(9)=x
#define iic_scl_out(x)        PBout(8)=x
#define iix_read_sda()        PBin(9)

static void iic_gpio_init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

static void iic_gpio_deinit(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}
//***********************************************************************


void iic_init(void)
{           
    iic_gpio_init();
   
    iic_scl_out(1);
    iic_sda_out(1);
}

void iic_deinit(void)
{           
    iic_gpio_deinit();
   
    iic_scl_out(1);
    iic_sda_out(1);
}

void iic_start(void)
{
    sda_out();
    iic_sda_out(1);            
    iic_scl_out(1);
    delay_us(4);
     iic_sda_out(0);
    delay_us(4);
    iic_scl_out(0);
}

void iic_stop(void)
{
    sda_out();
    iic_scl_out(0);
    iic_sda_out(0);
     delay_us(4);
    iic_scl_out(1);
    iic_sda_out(1);
    delay_us(4);                                   
}

uint8_t iic_wait_ack(void)
{
    uint8_t ucerrtime = 0;
    sda_in();
    iic_sda_out(1);
    delay_us(1);       
    iic_scl_out(1);
    delay_us(1);     
    while(iix_read_sda())
    {
        ucerrtime++;
        if(ucerrtime > 250)
        {
            iic_stop();
            return 1;
        }
    }
    iic_scl_out(0);  
    return 0
}

void iic_ack(void)
{
    iic_scl_out(0);
    sda_out();
    iic_sda_out(0);
    delay_us(2);
    iic_scl_out(1);
    delay_us(2);
    iic_scl_out(0);
}

void iic_nack(void)
{
    iic_scl_out(0);
    sda_out();
    iic_sda_out(1);
    delay_us(2);
    iic_scl_out(1);
    delay_us(2);
    iic_scl_out(0);
}   

void iic_send_byte(uint8_t txd)
{                       
    uint8_t t;
   
    sda_out();         
    iic_scl_out(0);
    for(t = 0; t < 8; t++)
    {             
        iic_sda_out((txd & 0x80) >> 7);
        txd <<= 1;       
        delay_us(2);
        iic_scl_out(1);
        delay_us(2);
        iic_scl_out(0);   
        delay_us(2);
    }     
}

uint8_t iic_read_byte(unsigned char ack)
{
    unsigned char i, receive = 0;
   
    sda_in();
    for(i = 0; i < 8; i++ )
    {
        iic_scl_out(0);
        delay_us(2);
        iic_scl_out(1);
        receive <<= 1;
        if(iix_read_sda())
            receive++;  
        delay_us(1);
    }                     
    if (!ack)
        iic_nack();
    else
        iic_ack();
    return receive;
}

//iic.h
#ifndef _IIC_H
#define _IIC_H

#include "stdint.h"

void iic_init(void);
void iic_deinit(void);
void iic_start(void);
void iic_stop(void);
void iic_send_byte(uint8_t txd);
uint8_t iic_read_byte(unsigned char ack);
uint8_t iic_wait_ack(void);
void iic_ack(void);
void iic_nack(void);

void iic_write_one_byte(uint8_t daddr, uint8_t addr, uint8_t data);
uint8_t iic_read_one_byte(uint8_t daddr, uint8_t addr);     

#endif

 

编译运行:result

如下,编译无报错,无警告。

 

总结:

 理论上gpio操作加上精确的延时,能模拟出任何总线的时序

 iic.c将移植部分单独摘取出来,方便未来的移植开发

 

公众号:

 关注公众号 InsertingAll,获取嵌入式学习资源,学习更多嵌入式知识

 

作者: 嵌入式搬砖, 来源:面包板社区

链接: https://mbb.eet-china.com/blog/uid-me-3894741.html

版权声明:本文为博主原创,未经本人允许,禁止转载!

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
11
关闭 站长推荐上一条 /3 下一条