使用GPIO引脚模拟SDA和SCL总线实现软件模拟IIC通信,IIC的具体通信协议层和物理层链接:IIC
#ifndef __BSP_IIC_H
#define __BSP_IIC_H
#include "stm32f10x.h"
#define SCL_PORT GPIOA
#define SCL_PIN GPIO_Pin_2
#define SCL_MOOD GPIO_Mode_Out_OD
#define SCL_SPEED GPIO_Speed_50MHz
#define SDA_PORT GPIOA
#define SDA_PIN GPIO_Pin_3
#define SDA_MOOD GPIO_Mode_Out_OD
#define SDA_SPEED GPIO_Speed_50MHz
#define SDA_1() GPIO_SetBits(SDA_PORT, SDA_PIN)
#define SDA_0() GPIO_ResetBits(SDA_PORT, SDA_PIN)
#define SCL_1() GPIO_SetBits(SCL_PORT, SCL_PIN)
#define SCL_0() GPIO_ResetBits(SCL_PORT, SCL_PIN)
#define SDA_READ GPIO_ReadInputDataBit(SDA_PORT, SDA_PIN)
/* ACK原型为acknowledge,意为:报告已收到 */
void Delay(void);
void IIC_START(void);
void IIC_STOP(void);
void IIC_ACK(void);
void IIC_NACK(void);
uint8_t IIC_ReadACK(void);
void IIC_SendByte(uint8_t data) ;
uint8_t IIC_ReadByte(void);
void IIC_GPIO_Config(void);
#endif /* __BSP_IIC_H */
void Delay(void)
{
uint8_t i;
/*
下面的时间是通过逻辑分析仪测试得到的。
工作条件:CPU主频72MHz ,MDK编译环境,1级优化
循环次数为10时,SCL频率 = 205KHz
循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us
循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us
*/
for (i = 0; i < 10; i++);
}
/* SCL高电平时期SDA产生下降沿表示起始信号 */
void IIC_START(void)
{
SDA_1();
SCL_1();
Delay();
SDA_0();
Delay();
SCL_0();
Delay();
}
/* SCL高电平时期SDA产生上升沿表示停止信号 */
void IIC_STOP(void)
{
SDA_0();
SCL_1();
Delay();
SDA_1();
Delay();
/* 停止信号后SDA和SCL都为高电平 */
}
/* SCL高电平时期 SDA保持低电平代表 应答信号 */
void IIC_ACK(void)
{
SDA_0();
Delay();
SCL_1();
Delay();
SCL_0();
Delay();
SDA_1();
/* 随后释放SDA总线 */
}
/* SCL高电平时期 SDA保持高电平代表 非应答信号 */
void IIC_NACK(void)
{
SDA_1();
Delay();
SCL_1();
Delay();
SCL_0();
/* SDA已经为高电平,无需释放 */
}
/* CPU产生一个SCL时钟,读取应答 ACK:0 NACK:1*/
/* 因为SDA平时为高电平,所以没有收到应答时,SDA还为高电平,即读取到 1 为非应答 */
uint8_t IIC_ReadACK(void)
{
uint8_t k;
/* 释放SDA总线 */
SDA_1();
Delay();
/* SCL为高电平时,才会读取有效数据 */
SCL_1();
Delay();
/* 读取信号 */
if(SDA_READ==1)
k=1;
else
k=0;
/* 收到信号后SCL要拉低 */
SCL_0();
Delay();
return k;
}
/* 发送一个字节,先发送高位 */
void IIC_SendByte(uint8_t data)
{
uint8_t n=0x01;
int i;
SCL_0();
Delay();
for(i=7;i>=0;i--)
{
if(n&(data>>i))
{
SDA_1();
Delay();
SCL_1();
Delay();
}
else
{
SDA_0();
Delay();
SCL_1();
Delay();
}
SCL_0();
Delay();
}
/* 发送完一个字节后释放SDA总线 */
SDA_1();
Delay();
}
/* 读取一个字节,在CPU产生的SCL高电平时期读取 */
uint8_t IIC_ReadByte(void)
{
// uint8_t i,data=0;
// for(i=0;i<8;i++)
// {
// SCL_1();
// Delay();
// if(SDA_READ)
// {
// data++; /* 利用自增实现对最低位写 1 */
// }
// data<<=1;
// SCL_0();
// Delay();
//
// }
// return data;
//
uint8_t i;
uint8_t temp = 0;
for(i=0;i<8;i++)
{
temp<<=1;
SCL_1();
Delay();
if( SDA_READ==1 )
{
temp += 1;
}
SCL_0();
Delay();
}
return temp;
}
/* 配置SCL和SDA对应的GPIO引脚,模式都为开漏输出 */
void IIC_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Pin = SCL_PIN;
GPIO_InitStruct.GPIO_Mode = SCL_MOOD;
GPIO_InitStruct.GPIO_Speed = SCL_SPEED;
GPIO_Init(SCL_PORT, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = SDA_PIN;
GPIO_InitStruct.GPIO_Mode = SDA_MOOD;
GPIO_InitStruct.GPIO_Speed = SDA_SPEED;
GPIO_Init(SDA_PORT, &GPIO_InitStruct);
/* 给一个停止信号,使IIC总线上所有设备处于复位 */
IIC_STOP();
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章