使用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(); }

STM32—IIC通信(软件实现底层函数)的更多相关文章

  1. 半吊子的STM32 — IIC通信

    半双工通信模式:以字节模式发送(8位): 两线式串行总线,SDA(数据信号)和SCL(时钟信号)两条信号线都为高电平时,总线为空闲状态:起始时,SCL稳定为高电平,SDA电平由高向低跳变:停止时,SC ...

  2. STM32 IIC双机通信—— HAL库硬件IIC版

    参考传送门 关于IIC的原理这里我就不多说了,网上有很多很好的解析,如果要看我个人对IIC的理解的话,可以点击查看,这里主要讲一下怎样利用STM32CubeMx实现IIC的通讯,经过个人实践,感觉HA ...

  3. 基于51单片机IIC通信的PCF8591学习笔记

    引言 PCF8591 是单电源,低功耗8 位CMOS 数据采集器件,具有4 个模拟输入.一个输出和一个串行I2C 总线接口.3 个地址引脚A0.A1 和A2 用于编程硬件地址,允许将最多8 个器件连接 ...

  4. 基于51单片机IIC通信的AT24C02学习笔记

    引言 最近在学习几种串行通信协议,感觉收获很多,这篇文章是学习IIC总线协议的第一篇文章,以后还会再写一篇关于PCF8591 IIC通信的ADDA转换芯片的文章. 关于IIC总线 IIC 即Inter ...

  5. Stm32串口通信(USART)

    Stm32串口通信(UART) 串口通信的分类 串口通信三种传递方式 串口通信的通信方式 串行通信的方式: 异步通信:它用一个起始位表示字符的开始,用停止位表示字符的结束.其每帧的格式如下: 在一帧格 ...

  6. STM32串口通信UART使用

    STM32串口通信UART使用 uart使用的过程为: 1. 使能GPIO口和UART对应的总线时钟 2. 配置GPIO口的输出模式 3. 配置uart口相关的基本信息 4. 使能uart口的相关的中 ...

  7. 【Java】Java socket通信使用read,readline函数的阻塞问题

    Socket通信是Java网络编程中比较基础的部分,其原理其实就是源ip,源端口和目的ip,目的端口组成的套接字通信.其底层还设及到了TCP协议的通信. Java中的Socket通信可以通过客户端的S ...

  8. STM32 对内部FLASH读写接口函数(转)

    源:STM32 对内部FLASH读写接口函数 因为要用内部FLASH代替外部EEPROM,把参数放在STM32的0x08000000+320K处,其中20K是bootloader,300K是应用程序. ...

  9. STM32 串口通信使用奇偶校验

    STM32串口通信如果使用奇偶校验,需要设置数据位长度为9bit USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USAR ...

随机推荐

  1. getopt模块的学习

    在运行程序时,可能需要根据不同的条件,输入不同的命令行选项来实现不同的功能.目前有短选项和长选项两种格式.短选项格式为"-"加上单个字母选项:长选项为"--"加 ...

  2. ctf实验吧Once More

    题目链接:http://ctf5.shiyanbar.com/web/more.php 思路分析:显然是后台逻辑代码. 1.ereg函数有漏洞,可以使用%00截断,这个就做笔记了好吧.这个函数大致意思 ...

  3. PHP大文件分片上传的实现方法

    一.前言 在网站开发中,经常会有上传文件的需求,有的文件size太大直接上传,经常会导致上传过程中耗时太久,大量占用带宽资源,因此有了分片上传. 分片上传主要是前端将一个较大的文件分成等分的几片,标识 ...

  4. 软件测试跟踪工具Bugzilla的安装 - Linux版本

    首先查看Linux当前版本 输入"uname -a ",可显示电脑以及操作系统的相关信息 输入"cat /proc/version",说明正在运行的内核版本 输 ...

  5. 结对开发_石家庄地铁查询web系统

    结对开发:队友田昕可 大二上学期做过只有两号线的地铁查询系统,但是只能在控制台操作.这一次将线路加到了六条,并且要求web实现,下面简述一下设计思路和具体代码实现: 1.数据库建表 于我们自己习惯而言 ...

  6. final修饰符(3)-基本类型变量和引用类型变量的区别

    final修饰基本类型变量 当使用final修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变 final修饰引用类型变量 当使用final修饰引用类型变量时,它保存的仅仅是一 ...

  7. 关于Xpath定位方法知道这些基本够用

    一.写在前面 之前写过一些关于元素定位的文章,但是感觉都是很碎片,现在想做个整合,便有了这篇文章. 二.xpath的定位方法 关于xpath定位方法,网上写的已经很成熟了,现已百度首页为例,如下图: ...

  8. java并发编程基础——线程的创建

    一.基础概念 1.进程和线程 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程.(进程是资源分配的最小单位) 线程:同一类线程共享代码和数据 ...

  9. Leetcode春季打卡第四天:994. 腐烂的橘子

    Leetcode春季打卡第四天:994. 腐烂的橘子 Leetcode春季打卡第四天:994. 腐烂的橘子 思路 思路是采用广度优先搜索,一层一层遍历. 首先先扫描矩阵,将坏橘子放进队列,记录正常橘子 ...

  10. Mplus 8.3 Combo Version for Win/Mac安装破解教程

    Mplus 8.3是一个统计建模程序,它为研究人员提供了一个灵活的工具来分析数据.本文提供其破解版安装包下载,亲测可永久免费使用,支持Windows 和 Mac操作系统. Mplus 8.3界面简单, ...