stm32f4标准库开发——模拟iic主要概念: IIC总线:I2C总线是一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。 IIC总线定义:时钟线:sck数据线:sda 软件模拟:通过软件控制普通GPIO 引脚高低点评切换,来模拟总线时序,从而达到与总线协议一样的效果。 缺点:与使用硬件IIC 相比,会占用更多的 CPU 时间。 实验目的: 本实现通过软件模拟IIC 时序,编写 IIC 发送接收函数。 硬件电路: 本实验的蜂鸣器为有源蜂鸣器 PB8--> IIC_SCL PB9--> IIC_SDA
主要库函数调用:#definesda_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_tiic_wait_ack(void)
{
uint8_tucerrtime = 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_ttxd)
{
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_tiic_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();
returnreceive;
} //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_ttxd);
uint8_tiic_read_byte(unsigned char ack);
uint8_tiic_wait_ack(void);
void iic_ack(void);
void iic_nack(void);
void iic_write_one_byte(uint8_tdaddr, uint8_t addr, uint8_t data);
uint8_tiic_read_one_byte(uint8_t daddr, uint8_t addr);
#endif 编译运行:result如下,编译无报错,无警告。
总结: 理论上gpio操作加上精确的延时,能模拟出任何总线的时序 iic.c将移植部分单独摘取出来,方便未来的移植开发 公众号: 关注公众号InsertingAll,获取嵌入式学习资源,学习更多嵌入式知识
|