本文共 3210 字,大约阅读时间需要 10 分钟。
使用GPIO引脚模拟SDA和SCL总线实现软件模拟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(); }
转载地址:http://lawzi.baihongyu.com/