单片机普通IO口模拟IIC多机通信,本人已测试通过
用单片机普通I/O口实现多机通信的一种新方法
效 ;而 当 S =0时 ,无 论接 收 到的 R 8是 什 么 ,接 M2 B 收都 有效 。
与 查询 方 式不 同 ,采用 中断方 式 时 ,分机 不 必 一
直处 于监 听 状 态 ,而 可以进 行 相应 的数 据 采集 或 控 制
等其 他工 作 。当主机 有通 讯要 求 时 , 可通 过 P . 1 0向各
关 键 词 : 单 片 机 ;多机 通 讯 ;I O 口 /
1 传统 的 多机 通信 方 式
时 ,如果 允许 主 机与 之通 讯 ,则 可 开外 部 中断 及 总 中
断1 ,否 则关 闭 中断 1 。
在 实际 工 业应 用 中 ,经 常 遇到 需要 多 台计 算 机 配 合 才 能完 成 的数 据 采集 与控 制 系统 的任 务 ,而 多 台计 算 机 配 合 主 要 是 通 过 多 台计 算 机 之 间 的通 信来 实 现 的。 为此 必须 将 它们 按实 际需 要 组成 一 定形 式 的 网络 。 多机通 信 网络 通 常有 5 网络 形 式 : 种 星型 、 型 、总线 树 型 、环型 、分 散 型 网络结 构 。它 们 各有 优缺 点 ,其 中
分机 发送 中断请 求 ( 要求 通 讯 )信 号 ;而 从机 在 工作
总线 型 网络结 构 以 可靠性 好 、接 口简单 、组 成灵 活和
这 种 中 断方 法解 决 了分机 盲 目等待 的 问题 ,分 机 也 能立 即 响应 主机 的通讯请 求 ,但 在 某 些应 用场 合 有
相 当的局 限性 。
( ) 当分 机通 信 波特 率要 求 不一 样 时 ; 1 ( ) 主机 ( 分 机 )还 要 通过 串行 口与别 的设 备 2 或 进 行数 据交 换 时 。
单片机实现双机通信自己的
单片机实现双机通信自己的单片机是一种集成电路芯片,可以实现各种功能。
双机通信是指两台或多台计算机通过网络或其他方式进行数据传输和通信的过程。
在很多应用中,需要使用单片机实现双机通信,以实现数据传输和信息交换等功能。
单片机实现双机通信的基本原理是通过通信端口(例如串口或网络接口等)进行数据的发送和接收。
在这个过程中,需要使用一些通信协议来规定数据的格式和传输的方式。
下面是一种基于串口通信的单片机双机通信的实现方法。
首先,我们需要确定通信的硬件配置。
通常情况下,可以通过串口连接两台单片机,其中一台设置为发送方,另外一台设置为接收方。
发送方将待发送的数据通过串口发送出去,接收方则接收这些数据。
在单片机程序代码的编写方面,我们需要首先配置串口的通信参数,例如波特率、数据位、停止位、奇偶校验等。
这些参数需要在发送方和接收方进行一致配置,以保证数据的正确传输。
接下来,我们需要实现发送和接收的程序。
首先,发送方需要将待发送的数据存储在发送缓冲区中,然后通过串口将数据发送出去。
接收方则需要实时监听串口接收缓冲区中是否有数据到达,并将接收到的数据存储在接收缓冲区中。
另外,为了保证数据的正确传输,通常还要实现一些数据校验机制,例如奇偶校验、循环冗余校验(CRC)等。
这些校验机制可以用于检测和纠正数据传输中的错误。
在程序编写的过程中,还需要考虑到程序的稳定性和容错性。
例如,在发送方发送数据时,可能会遇到发送缓冲区已满的情况,此时需要实现相应的处理机制,例如等待一段时间后再次发送。
同样,在接收方接收数据时,也可能会遇到接收缓冲区溢出的情况,此时需要及时处理,以避免数据的丢失。
最后,在实际应用中,还需要考虑一些高级的功能,例如数据压缩、加密、数据传输速度的控制等。
这些功能可以根据具体的需求进行实现。
总之,单片机实现双机通信是一项复杂的任务,需要考虑到硬件和软件两个方面的因素。
在程序编写的过程中,需要考虑到通信参数的配置、发送和接收的程序编写、数据校验、稳定性和容错性等方面的问题。
用AVR单片机IO口模拟I2C总线操作AT24CXX的通用程序
*c=ret;
return(ret);
}
以下为AT24CXX的操作函数实现:
at24cxx.h:
//AT24CXX.H
#ifndef AT24CXX_H
#define AT24CXX-H
void At24cxxWaitBusy(void);
#include <util/delay.h>
#include <stdint.h>
/*注:
AVR单片机I/O口模拟I2C总线时建议在外部连接上拉电阻
这样可通过改变I/O口输入输出方向的方式来设置高低
输出口保持不变(0)
此时如DDRX寄存器为1则变成输出0
若DDRX为0,则I/O口程高阻,但因外部的上拉电阻,总线相当于设置高
#define TW_READ 1
#define TW_ACK 1
#define TW_NOACK 0
Hale Waihona Puke /*以下两个宏控制AT24CXX的WP引脚,如未连接可定义为空:
#define EEPROM_WRITE_ENABLE
#define EEPROM_WRITE_DISABLE
AT24CXX中WP引脚接地时写允许,接电源(高)时写保护,
如不接,器件内部有接地电阻,即写允许. */
//在CA-M8X板上该引脚通过S7(3)连接MEGA8的PC3
#define EEPROM_WRITE_ENABLE PORTC&=~_BV(PC3),DDRC|=_BV(PC3)
void At24cxxConfig(uint8_t device_addr,uint8_t page_size);
单片机之间 i2c通信
单片机之间 i2c通信
6. 结束通信:通信完成后,主设备发送停止条件(Stop)来结束通信。
需要注意的是,不同的单片机可能会有不同的I2C模块和寄存器配置。在编程时,需要根 据具体的单片机型号和硬件设计来进行相应的配置和操作。
2. 初始化:在每个单片机中,需要初始化I2C模块。这通常包括设置I2C时钟频率、使能 I2C模块等。单片机之间 Nhomakorabeai2c通信
3. 主从模式选择:在I2C通信中,一个单片机可以充当主设备(Master),而其他单片机 则充当从设备(Slave)。主设备负责发起通信,从设备则响应主设备的请求。
4. 发送数据:主设备通过发送起始条件(Start)开始通信,并发送从设备的地址和读/写 位。然后,主设备发送要传输的数据到从设备。
单片机之间 i2c通信
I2C(Inter-Integrated Circuit)是一种串行通信协议,常用于单片机之间的通信。在单 片机中,I2C通信可以实现多个设备之间的数据传输和控制。
以下是单片机之间进行I2C通信的基本步骤:
1. 硬件连接:将多个单片机连接到同一条I2C总线上。I2C总线由两根信号线组成:SDA (数据线)和SCL(时钟线)。所有的设备都共享这两根信号线。
在Keil中,可以使用相应的库函数来实现I2C通信,例如使用STM32的HAL库函数来进行 I2C通信。具体的代码实现会依赖于所使用的单片机型号和开发环境。
单片机io通信
单片机io通信(最新版)目录1.单片机 IO 通信简介2.单片机 IO 通信的基本原理3.单片机 IO 通信的常用方式4.单片机 IO 通信的实际应用5.单片机 IO 通信的未来发展趋势正文【单片机 IO 通信简介】单片机 IO 通信是指单片机与其它设备或者单片机之间的数据传输过程。
IO 通信是单片机系统设计中的重要组成部分,它直接影响到整个系统的性能和稳定性。
在实际应用中,单片机 IO 通信主要用于传感器数据采集、设备控制、数据传输等方面。
【单片机 IO 通信的基本原理】单片机 IO 通信的基本原理是通过 IO 口进行数据输入输出。
IO 口是单片机与外部设备之间的物理接口,可以通过配置 IO 口的工作模式,实现数据的输入输出。
常见的 IO 口工作模式有输入模式、输出模式、复用模式等。
【单片机 IO 通信的常用方式】单片机 IO 通信的常用方式主要有串行通信和并行通信两种。
1.串行通信:串行通信是指数据位按顺序进行传输。
在串行通信中,数据是逐个传输的,因此,传输速度较慢,但是,占用的 IO 口资源较少。
2.并行通信:并行通信是指数据位同时进行传输。
在并行通信中,数据是同时传输的,因此,传输速度较快,但是,占用的 IO 口资源较多。
【单片机 IO 通信的实际应用】单片机 IO 通信在实际应用中主要用于设备控制、数据采集、数据传输等方面。
例如,在智能家居系统中,单片机通过 IO 通信实现对家电设备的控制,实现远程控制和自动化控制。
在工业自动化系统中,单片机通过 IO 通信实现对传感器的数据采集,实现实时监控和数据分析。
STM32用GPIO模拟IIC通讯C语言源码实测可用
STM32用GPIO模拟IIC通讯C语言源码实测可用以下是一段用于STM32的GPIO模拟IIC(I2C)通讯的C语言源码:```c#include "stm32f10x.h"//定义SDA和SCL的GPIO端口和引脚#define SDA_GPIO GPIOB#define SDA_PIN GPIO_Pin_7#define SCL_GPIO GPIOB#define SCL_PIN GPIO_Pin_6//定义IIC的延时函数void IIC_Delayvolatile int i = 100;while (i--);//IIC开始信号void IIC_Start//先置SDA和SCL为高电平GPIO_SetBits(SDA_GPIO, SDA_PIN);GPIO_SetBits(SCL_GPIO, SCL_PIN);IIC_Delay(;//再拉低SDA,产生开始信号GPIO_ResetBits(SDA_GPIO, SDA_PIN); IIC_Delay(;GPIO_ResetBits(SCL_GPIO, SCL_PIN); //IIC停止信号void IIC_Stop//先置SDA为低电平GPIO_ResetBits(SDA_GPIO, SDA_PIN); IIC_Delay(;//再拉高SDA,产生停止信号GPIO_SetBits(SDA_GPIO, SDA_PIN); IIC_Delay(;GPIO_SetBits(SCL_GPIO, SCL_PIN); //IIC发送一个字节数据void IIC_WriteByte(uint8_t data) uint8_t i;for (i = 0; i < 8; i++)//先将SCL拉低GPIO_ResetBits(SCL_GPIO, SCL_PIN);//根据发送数据的当前位决定SDA的电平if ((data<<i) & 0x80)GPIO_SetBits(SDA_GPIO, SDA_PIN); elseGPIO_ResetBits(SDA_GPIO, SDA_PIN); IIC_Delay(;//拉高SCL,使得IIC设备接收数据GPIO_SetBits(SCL_GPIO, SCL_PIN);IIC_Delay(;}//最后拉低SCL,等待应答GPIO_ResetBits(SCL_GPIO, SCL_PIN); //IIC读取一个字节数据uint8_t IIC_ReadByte(uint8_t ack) uint8_t i, data = 0;for (i = 0; i < 8; i++)//先将SCL拉低GPIO_ResetBits(SCL_GPIO, SCL_PIN);//等待IIC设备准备好数据GPIO_SetBits(SCL_GPIO, SCL_PIN);IIC_Delay(;//读取SDA的电平if (GPIO_ReadInputDataBit(SDA_GPIO, SDA_PIN)) data ,= 0x01;if (i < 7)data <<= 1;}//最后拉低SCL,进行应答GPIO_ResetBits(SCL_GPIO, SCL_PIN);if (ack)GPIO_ResetBits(SDA_GPIO, SDA_PIN);elseGPIO_SetBits(SDA_GPIO, SDA_PIN);IIC_Delay(;GPIO_SetBits(SCL_GPIO, SCL_PIN);IIC_Delay(;GPIO_ResetBits(SCL_GPIO, SCL_PIN);return data;int main//使能GPIO端口的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = SDA_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(SDA_GPIO, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = SCL_PIN;GPIO_Init(SCL_GPIO, &GPIO_InitStructure);//执行IIC通讯的操作IIC_Start(;IIC_WriteByte(0xA0);IIC_WriteByte(0x01);IIC_Stop(;while (1);```这段代码使用STM32的GPIO模拟IIC通讯,定义了SDA和SCL的GPIO端口和引脚,并实现了IIC的开始信号、停止信号、发送字节和接收字节的函数。
单片机I2C通信实现
单片机I2C通信实现在单片机中,I2C通信是一种常见的通信协议。
它是一种串行通信协议,用于在集成电路(IC)之间传输数据。
I2C通信协议简化了IC之间的通信过程,使得多个IC可以通过两根信号线进行通信。
本文将详细介绍单片机中的I2C通信实现。
一、I2C通信协议简介I2C(Inter-Integrated Circuit)通信协议由Philips(现在的NXP)公司开发,旨在简化数字集成电路的通信过程。
它使用两根信号线,分别为串行数据线(SDA)和串行时钟线(SCL)。
通过不同的电平状态和时钟脉冲,IC之间可以进行数据传输和控制信号的交换。
二、I2C通信的基本原理在I2C通信协议中,数据的传输是基于主从模式的。
主机(Master)控制整个通信过程,而从机(Slave)被动地接收和发送数据。
主机通过发送起始位和终止位来标识通信的开始和结束。
从机在接收到地址位后,根据地址的匹配情况决定是进行读操作还是写操作。
三、I2C通信的硬件连接为了实现I2C通信,我们需要通过硬件连接将单片机与其他IC连接起来。
首先,我们需要将单片机的SDA引脚连接到其他IC的SDA引脚,用于数据的传输。
其次,我们需要将单片机的SCL引脚连接到其他IC的SCL引脚,用于时钟的同步。
此外,还需要为SDA和SCL引脚添加上拉电阻,以确保信号的正常传输。
四、I2C通信的程序实现在单片机中,我们可以通过编写相应的程序实现I2C通信功能。
以C语言为例,以下是一个简单的I2C通信实现的程序框架:'''#include <reg51.h>// 定义I2C的起始地址和操作码#define I2C_ADDRESS 0x50#define WRITE 0x00#define READ 0x01// 初始化I2C通信void I2C_Init() {// 对应的初始化操作}// 启动I2C通信void I2C_Start() {// 对应的启动操作}// 停止I2C通信void I2C_Stop() {// 对应的停止操作}// 发送一个字节的数据void I2C_SendByte(unsigned char data) { // 对应的发送操作}// 接收一个字节的数据unsigned char I2C_ReceiveByte() {// 对应的接收操作return data;}// 主机发送数据void I2C_MasterSend(unsigned char data) { // 对应的发送操作}// 主机接收数据unsigned char I2C_MasterReceive() {// 对应的接收操作return data;}// 从机发送确认信号void I2C_Acknowledge() {// 对应的确认操作}'''使用上述程序框架,我们可以根据具体的需求进行相关的I2C通信操作。
51单片机IO口线模拟IIC总线3部曲之第3部
本文是对第1,2部的使用说明。
若有错误之处请不吝赐教。
IIC底层驱动包使用说明一:说明:(1) 本软件包是使用51单片机IO口线来模拟IIC总线。
适用于12T周期单片机。
若想移植到单T周期单片机,请自行修改。
(2) IIC总线时钟是通过软件延时的方法产生的,所以对不同频率的时钟,需要做一些调整。
(3) 本驱动是IIC最底层的驱动函数,请勿随意改动本驱动。
(4) 本驱动对外只有两个函数可供使用。
一个是“写多字节函数”IICMCUSendStr(),另一个是“先写多字节,然后重新启动总线写一字节,最后接收多字节函数”IICMCUSendStrSendByteRcvStr()。
关于这两个函数的说明请见第三部分,函数详解。
(5) 针对不同的IIC器件读写时序的不同,您应该自己编写IIC器件的驱动。
二:移植方法:使用时有3个地方需要修改,以实现移植。
SDA,SCL和N_12MHz,这三个变量都在IICLowDriver.H文件中。
并且它们定义在文件最开始的位置。
SDA:IIC数据线。
请根据您的硬件设置来选择正确的IO口。
SCL:IIC时钟线。
请根据您的硬件设置来选择正确的IO口。
N_12MHz:所用时钟频率F(单位MHz)与12MHz的比值。
该变量关系到IIC总线时序的正确与否,一定要设置正确。
其取值见下表。
时钟频率F取值范围(MHz)0 ≤ F ≤ 1212 < F ≤ 2424 < F ≤ 3636 < F ≤ 48N_12MHz取值1234只要设置好这三个变量,就可以方便的使用IIC总线了。
为增加移植时的安全性,这三个变量用了预处理命令,移植时请勿改动预处理命令。
三:函数详解。
1、向IIC总线发送多字节数据函数(对外接口)本函数用于IIC器件的写操作。
//-------------------------------------------------------------------------------////函数名称:IICMCUSendStr//函数功能:向IIC总线发送多字节数据。
I2C总线及单片机模拟I2C总线通信程序编写
I2C总线及单片机模拟I2C总线通信程序编写1、I2C总线I2C总线是Inter-IntegratedCircuit(集成电路总线),这种总线类型是由飞利浦半导体公司在八十年代初设计出来的,主要是用来连接整体电路(ICS) ,IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实时数据传输的控制源。
I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。
所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。
2、数据有效性、起始和终止信号数据位的有效性:I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
起始信号:SCL线为高电平期间,SDA线由高电平向低电平的变化;终止信号:SCL线为高电平期间,SDA线由低电平向高电平的变化。
起始信号和终止信号都由主机发出。
3、数据传送格式1)字节传送与应答每一个字节必须保证是8位长度。
数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。
如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。
2)数据帧格式I2C总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号。
在起始信号后必须传送一个从机的地址(7位),第8位是数据的传送方向位(R/T),用“0”表示主机发送数据(T),“1”表示主机接收数据(R)。
每次数据传送总是由主机产生的终止信号结束。
若主机希望继续占用总线进行新的数据传送,则可以不产生终止信号,马上再次发出起始信号对另一从机进行寻址。
在总线的一次数据传送过程中,可以有以下几种组合方式:a、主机向从机发送数据,数据传送方向在整个传送过程中不变:注:有阴影部分表示数据由主机向从机传送,无阴影部分则表示数据由从机向主机传送。
STC51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码
STC51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码STC 51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码原文:(改自周立功软件包)#include <reg51.h>#include <intrins.h>#define uchar unsigned char /*宏定义*/#define uint unsigned intextern void Delay1us(unsigned char );sbit SDA=P1^6; /*模拟I2C数据传送位*/sbit SCL=P1^7; /*模拟I2C时钟控制位*/bit ack; /*应答标志位*//************************************************************** *****起动总线函数函数原型: void Start_I2c();功能: 启动I2C总线,即发送I2C起始条件.*************************************************************** *****/void Start_I2c(){SDA=1; /*发送起始条件的数据信号*/Delay1us(1);SCL=1;Delay1us(5); /*起始条件建立时间大于4.7us,延时*/SDA=0; /*发送起始信号*/Delay1us(5); /* 起始条件锁定时间大于4μs*/SCL=0; /*钳住I2C总线,准备发送或接收数据 */Delay1us(2);}/************************************************************** *****结束总线函数函数原型: void Stop_I2c();功能: 结束I2C总线,即发送I2C结束条件.*************************************************************** *****/void Stop_I2c(){SDA=0; /*发送结束条件的数据信号*/Delay1us(1); /*发送结束条件的时钟信号*/SCL=1; /*结束条件建立时间大于4us*/Delay1us(5);SDA=1; /*发送I2C总线结束信号*/Delay1us(4);}/*******************************************************************字节数据发送函数函数原型: void SendByte(uchar c);功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对此状态位进行操作.(不应答或非应答都使ack=0)发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
STM32用GPIO模拟IIC(I2C)通讯C语言源码 实测可用
/******************************************************************************
*
* Function Name : I2C_NoAck
* Description : Master Send No Acknowledge Single
SDA_IN();//SDA 设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
Delay_us(I2C_Delayus);
IIC_SCL=1;
receive<<=1;
if(READ_SDA)receive++;
Delay_us(I2C_Delayus);
}
return receive;
IIC_SDA=(dat&0x80)>>7; dat<<=1; Delay_us(I2C_Delayus); //对 TEA5767 这三个延时都是必须的 IIC_SCL=1; Delay_us(I2C_Delayus); IIC_SCL=0; Delay_us(I2C_Delayus); } IIC_RecvACK(); #endif } //************************************** //从 IIC 总线接收一个字节数据 //************************************** u8 IIC_RecvByte(void) { #ifdef BMI160 u8 i=8; u8 ReceiveByte=0;
if(!IIC_RecvACK()){IIC_Stop();return FALSE;} IIC_SendByte((u8) REG_Address); //设置低起始地址 IIC_RecvACK(); IIC_Start(); IIC_SendByte(SlaveAddress+1); IIC_RecvACK();
stm8s使用IO口模拟I2C
stm8s使⽤IO⼝模拟I2C刚⼊职不久,下⾯是使⽤stm8s005k6写的eeprom驱动程序。
EEPROM型号为ST公司的M24C256.#include "bsp_i2c.h"/* 在stm8平台下移植,只需要改下⾯的宏定义即可 */#define PORT_I2C_SCL GPIOC#define PIN_I2C_SCL GPIO_PIN_1#define PORT_I2C_SDA GPIOC#define PIN_I2C_SDA GPIO_PIN_2static void i2c_Delay(void);static void i2c_PinModeOutput(void);static void i2c_PinModeInput(void);static void i2c_SCL(uint8_t stat);static void i2c_SDA(uint8_t stat);static uint8_t i2c_ReadSDA(void);/** 函数名: i2c_InitGpio* 功能说明: 初始化IIC接⼝* 形参: ⽆* 返回值: ⽆*/void i2c_InitGpio(void){GPIO_Init(PORT_I2C_SCL, PIN_I2C_SCL, GPIO_MODE_OUT_PP_LOW_FAST);GPIO_Init(PORT_I2C_SDA, PIN_I2C_SDA, GPIO_MODE_OUT_PP_LOW_FAST);i2c_Stop();}/** 函数名: i2c_Delay* 功能说明: 延时函数* 形参: ⽆* 返回值: ⽆*/static void i2c_Delay(void){uint8_t time = 10;while (time--);}/** 函数名: i2c_PinModeOutput* 功能说明: 将SDA线的端⼝设置为输出* 形参: ⽆* 返回值: ⽆*/static void i2c_PinModeOutput(void){GPIO_Init(PORT_I2C_SDA, PIN_I2C_SDA, GPIO_MODE_OUT_PP_LOW_FAST);}/** 函数名: i2c_PinModeOutput* 功能说明: 将SDA线的端⼝设置为输⼊* 形参: ⽆* 返回值: ⽆*/static void i2c_PinModeInput(void){GPIO_Init(PORT_I2C_SDA, PIN_I2C_SDA, GPIO_MODE_IN_FL_NO_IT);}/** 函数名: i2c_SCL* 功能说明: 控制SCL线电平状态* 形参: stat:0 输出低电平,1 输出⾼电平* 返回值: ⽆*/static void i2c_SCL(uint8_t stat){if (stat){GPIO_WriteHigh(PORT_I2C_SCL, PIN_I2C_SCL);}else{GPIO_WriteLow(PORT_I2C_SCL, PIN_I2C_SCL);}}/** 函数名: i2c_SDA* 功能说明: 控制SDA线电平状态* 形参: stat:0 输出低电平,1 输出⾼电平* 返回值: ⽆*/static void i2c_SDA(uint8_t stat){if (stat){GPIO_WriteHigh(PORT_I2C_SDA, PIN_I2C_SDA);}else{GPIO_WriteLow(PORT_I2C_SDA, PIN_I2C_SDA);}}/** 函数名: i2c_ReadSDA* 功能说明: 读取SDA线电平状态* 形参: ⽆* 返回值: 0 或 1*/static uint8_t i2c_ReadSDA(void){if (GPIO_ReadInputPin(PORT_I2C_SDA, PIN_I2C_SDA)) {return1;}else{return0;}}/** 函数名: i2c_Start* 功能说明: IIC总线起始信号* 形参: ⽆* 返回值: ⽆*/void i2c_Start(void){i2c_PinModeOutput();i2c_SDA(1);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_SDA(0);i2c_Delay();i2c_SCL(0);i2c_Delay();}/** 函数名: i2c_Stop* 功能说明: IIC总线停⽌信号* 形参: ⽆* 返回值: ⽆*/void i2c_Stop(void){i2c_PinModeOutput();i2c_SCL(0);i2c_SDA(0);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_SDA(1);i2c_Delay();}/** 函数名: i2c_WriteByte* 功能说明: IIC总线写数据* 形参: _ucByte:写⼊的⼀个字节数据* 返回值: ⽆*/void i2c_WriteByte(uint8_t _ucByte){uint8_t i;i2c_PinModeOutput();i2c_SCL(0);i2c_Delay();for (i = 0; i < 8; i++){if (_ucByte & 0x80){i2c_SDA(1);}else{i2c_SDA(0);}_ucByte = _ucByte << 1;i2c_SCL(1);i2c_Delay();i2c_SCL(0);i2c_Delay();}i2c_SDA(1);}/** 函数名: i2c_ReadByte* 功能说明: IIC总线读数据* 形参: ⽆* 返回值: recv:读取的⼀个字节数据*/uint8_t i2c_ReadByte(void){uint8_t i;uint8_t recv = 0;i2c_PinModeOutput();i2c_SDA(1);i2c_Delay();i2c_PinModeInput();for (i = 0; i < 8; i++){recv = recv << 1;i2c_SCL(1);i2c_Delay();if (i2c_ReadSDA()){recv |= 0x01;}else{recv |= 0x00;}i2c_SCL(0);i2c_Delay();}return recv;}/** 函数名: i2c_Ack* 功能说明: IIC总线主机主动应答* 形参: ⽆* 返回值: ⽆*/void i2c_Ack(void){i2c_PinModeOutput();i2c_SCL(0);i2c_SDA(0);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_SCL(0);}/** 函数名: i2c_NAck* 功能说明: IIC总线主机主动⾮应答* 形参: ⽆* 返回值: ⽆*/void i2c_NAck(void){i2c_PinModeOutput();i2c_SCL(0);i2c_SDA(1);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_SCL(0);}/** 函数名: i2c_CheckAck* 功能说明: IIC总线检测应答信号* 形参: ⽆* 返回值: 0 应答信号,1 ⾮应答信号*/uint8_t i2c_CheckAck(void){uint8_t time = 0;i2c_PinModeOutput();i2c_SDA(1);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_PinModeInput();while (i2c_ReadSDA()){time++;if (time >= 100){return1;}}i2c_SCL(0);return0;}bsp_i2c.c#ifndef __BSP_I2C_H__#define __BSP_I2C_H__#include "stm8s.h"#define I2C_WR ((uint8_t) 0) /* 写控制bit */ #define I2C_RD ((uint8_t) 1) /* 读控制bit */ #define ACK ((uint8_t) 0)#define NOACK ((uint8_t) 1)void i2c_InitGpio(void);void i2c_Start(void);void i2c_Stop(void);void i2c_WriteByte(uint8_t _ucByte);uint8_t i2c_ReadByte(void);void i2c_Ack(void);void i2c_NAck(void);uint8_t i2c_CheckAck(void);#endif /* __BSP_I2C_H__ */bsp_i2c.h#include "m24256_driver.h"#include "bsp_i2c.h"#include "modbus_driver.h"//uint8_t g_ucIsEEPROMBusy;/** 函数名: M24256_Init* 功能说明: 初始化* 形参: ⽆* 返回值: ⽆*/void M24256_Init(void){i2c_InitGpio();}/** 函数名: M24256_WriteByte* 功能说明: 写⼀个字节* 形参: _usAddress:地址* _ucByte:数据* 返回值: ⽆*/uint8_t M24256_WriteByte(uint16_t _usAddress, uint8_t _ucByte) {uint16_t i;for (i = 0; i < 3000; i++){i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_WR); /* 选中器件 + 写 */ if (i2c_CheckAck() == ACK){break;}}if (i >= 3000){i2c_Stop();return0;}/* 发送地址 */i2c_WriteByte((_usAddress & 0xFF00) >> 8);if (i2c_CheckAck() == NOACK){i2c_Stop();return2;}i2c_WriteByte(_usAddress & 0x00FF);if (i2c_CheckAck() == NOACK){i2c_Stop();return3;}/* 读数据 */i2c_WriteByte(_ucByte);if (i2c_CheckAck() == NOACK){i2c_Stop();return4;}i2c_Stop();/** 函数名: M24256_ReadByte* 功能说明: 读⼀个字节* 形参: _usAddress:地址* 返回值: recv:读取到的⼀个字节数据*/uint8_t M24256_ReadByte(uint16_t _usAddress){uint8_t recv = 0;uint16_t i;for (i = 0; i < 3000; i++){i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_WR); /* 选中器件 + 写 */if (i2c_CheckAck() == ACK){break;}}if (i >= 3000){i2c_Stop();return0;}/* 发送地址 */i2c_WriteByte((_usAddress & 0xFF00) >> 8);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_WriteByte(_usAddress & 0x00FF);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_RD); /* 选中器件 + 读 */if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}recv = i2c_ReadByte();i2c_NAck();i2c_Stop();return recv;}/** 函数名: M24256_ReadBlock* 功能说明: 从串⾏EEPROM指定地址处开始读取若⼲数据* 形参: _usAddress : 起始地址* _usSize : 数据长度,单位为字节* _pReadBuf : 存放读到的数据的缓冲区指针* 返回值: 0 表⽰失败,1表⽰成功*/unsigned char M24256_ReadBlock(unsigned char *_pReadBuf, unsigned short _usSize, unsigned short _usAddress) {uint16_t i;for (i = 0; i < 3000; i++){i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_WR); /* 选中器件 + 写 */if (i2c_CheckAck() == ACK){break;}}if (i >= 3000){i2c_Stop();/* 发送地址 */i2c_WriteByte((_usAddress & 0xFF00) >> 8);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_WriteByte(_usAddress &0x00FF);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_RD); /* 选中器件 + 读 */if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}/* 循环读取数据 */for (i = 0; i < _usSize; i++){_pReadBuf[i] = i2c_ReadByte();if (i != _usSize - 1){i2c_Ack();}else{i2c_NAck(); /* 读完最后⼀个字节,主机发送⾮应答 */}}i2c_Stop();return1;}/** 函数名: M24256_WriteBlock* 功能说明: 向串⾏EEPROM指定地址写⼊若⼲数据,采⽤页写操作提⾼写⼊效率* 形参: _usAddress : 起始地址* _usSize : 数据长度,单位为字节* _pWriteBuf : 存放读到的数据的缓冲区指针* 返回值: 0 表⽰失败,1表⽰成功*/unsigned char M24256_WriteBlock(unsigned char *_pWriteBuf, unsigned short _usSize, unsigned short _usAddress) {uint16_t i, m;uint16_t usAddr;usAddr = _usAddress;for (i = 0; i < _usSize; i++){if ((i == 0) || (usAddr & (EE_PAGE_SIZE - 1)) == 0){i2c_Stop();/* 重复发送起始信号,eeprom要重新开始写要等待10ms左右 */for (m = 0; m < 3000; m++){i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_WR);if (i2c_CheckAck() == ACK){break;}}if (m >= 3000){i2c_Stop(); /* 写eeprom超时 */return0;}/* 发送地址 */i2c_WriteByte((usAddr & 0xFF00) >> 8);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_WriteByte(usAddr & 0x00FF);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}}/* 写⼊数据 */i2c_WriteByte(_pWriteBuf[i]);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}usAddr++;}i2c_Stop();return1;}bsp_eeprom.c#ifndef __M24256_DRIVER_H__#define __M24256_DRIVER_H__#include "stm8s.h"#define EE_MODEL_NAME "M24256"#define EE_DEV_ADDR 0xA0 /* 设备地址 */#define EE_PAGE_SIZE 64 /* 页⾯⼤⼩(字节) */#define EE_SIZE (32*1024) /* 总容量(字节) */#define EE_ADDR_BYTES 1 /* 地址字节个数 */extern unsigned char g_ucIsEEPROMBusy;void M24256_Init(void);uint8_t M24256_WriteByte(uint16_t _usAddress, uint8_t _ucByte);uint8_t M24256_ReadByte(uint16_t _usAddress);unsigned char M24256_ReadBlock(unsigned char *_pReadBuf, unsigned short _usSize, unsigned short _usAddress); unsigned char M24256_WriteBlock(unsigned char *_pWriteBuf, unsigned short _usSize, unsigned short _usAddress); void ee_Test(void);#endif /* __M24256_DRIVER_H__ */bsp_eeprom.h。
gpio模拟i2c 自适应频率
gpio模拟i2c 自适应频率GPIO模拟I2C自适应频率是一种通过软件模拟I2C通信协议的方法,通过利用单片机的GPIO口来模拟I2C总线上的数据通信。
在I2C通信中,主要有两种频率,标准模式(100KHz)和快速模式(400KHz),而在模拟I2C通信时,我们需要实现自适应频率的功能,即根据外部设备的实际工作频率自动调整模拟I2C通信的速率。
实现GPIO模拟I2C自适应频率的关键是根据外部设备的响应时间来动态调整通信速率,从而保证通信的稳定性和可靠性。
下面是一些参考内容,可帮助你实现GPIO模拟I2C自适应频率:1. 定义I2C通信的起始和停止信号:在模拟I2C通信时,首先需要定义起始和停止信号的信号序列,用于区分数据的开始和结束。
2. 设计GPIO口的控制程序:利用单片机的GPIO口模拟I2C通信时,需要编写相应的控制程序,包括发送和接收数据的函数,起始和停止信号的生成,时钟信号的控制等。
3. 自适应频率算法:设计一个自适应频率的算法,根据外部设备的响应时间动态调整通信速率。
可以通过在通信过程中计算通信时间,根据通信时间的长短来自动调整通信速率。
4. 考虑通信的稳定性和可靠性:在设计GPIO模拟I2C自适应频率的过程中,需要考虑通信的稳定性和可靠性,尽量减少通信的误码率,确保数据的准确传输。
5. 调试和优化:在实际应用中,需要对设计的GPIO模拟I2C自适应频率的程序进行调试和优化,确保通信的正常运行,可以通过逐步测试的方式逐步完善功能。
通过以上的参考内容,你可以实现GPIO模拟I2C自适应频率的功能,根据外部设备的实际工作频率来自动调整通信速率,从而实现稳定可靠的通信。
希望以上内容对你有所帮助,祝你实现成功!。
51单片机IO口线模拟IIC总线3部曲之第2部
// 51单片机IO口线模拟IIC总线3部曲之第2部 IICLowDriver.H// 把本文全部复制保存为IICLowDriver.H//**************************************************************************** // 文件名 IICLowDriver.H// 简介:// 使用51单片机IO口线来模拟IIC总线。
适用于12T周期单片机,不能用于单T周期单片机。
// 本文件中是IIC最底层的驱动函数//// 这些底层驱动函数包括IIC总线的起动(IICStart)与关闭(IICStop),MCU对应答信号// 的发送(IICMCUSendACK)与接收(IICMCURcvACK),1字节数据的发送(IICMCUSendSDAByte)// 与接收(IICMCURcvSDAByte)这6个函数。
这6个函数是相互独立的,没有互相调用。
// 针对不同的IIC器件读写时序的不同,您应该自己编写IIC器件的驱动。
// 另外为了适应不同频率的时钟,本驱动中作了相关的设置。
// 详细使用说明请参见《IIC底层驱动包使用说明》。
// 移植说明:// 请修改本文件中的“移植修改”部分来完成移植。
仅需要改动3个地方,SCL// SDA和N_12MHz。
其他预处理命令请不要改动。
//*********************************************************************#define uchar unsigned char//--------------------------头文件包含------------------------------//#include<reg52.h>//-----------------------------移植修改-----------------------------////-----------------------------信号定义-----------------------------//#if defined(SDA_ON)sbit SDA = P1^7; // 模拟I2C数据传送位,移植时请修改此处的IO口#endif#if defined(SCL_ON)sbit SCL = P1^6; // 模拟I2C时钟控制位,移植时请修改此处的IO口#endif//-----------------------------晶振频率之比-------------------------//// N_12MHz:所用晶振频率F(单位MHz)与12MHz的比值。
九齐MCUio口模拟I2C
九齐MCUio⼝模拟I2C IO⼝模拟I2C的要点:1. 数据帧符合标准的I2C协议2. 分的清楚ACK与NACK的区别,是那个设备下拉。
3. 数据位时间符合要求项⽬合作开发,吹⽜扯蛋、交朋友,请联系:186********#include "iic_p.h"#include <ny8.h>#include "main.h"#include <ny8_constant.h>#include <stdint.h>#define sda_out() IOSTA=(IOSTA & ((uint8_t)(~ C_PA6_Input))) //输出#define sda_in() IOSTA=(IOSTA | C_PA6_Input) //输⼊#define sda PORTAbits.PA6 //sda输出⾼#define scl PORTAbits.PA4 //scl输出⾼,写程序注意默认让其保持⾼电平void delayus(uint8_t tim){while(tim--) //2.4us周期 clk_8M{NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();}}void i2c_stop(void){scl = 0;delayus(1);sda = 0;sda_out();delayus(2);scl = 1;delayus(1);sda = 1;}void i2c_start(void){sda = 1; //delayus(1);scl = 1; //发送停⽌位后将SCL及SDA置位delayus(1);sda = 0;delayus(1);}//测试okvoid trandata(uint8_t data){//IOSTB=(IOSTB & ((uint8_t)(~ C_PB2_Input))); //输出uint8_t i;//scl = 0;for( i = 0;i<8;i++ ){scl = 0;delayus(1);if((data & 0x80) == 0x80){sda = 1;}else{sda = 0;data <<=1;delayus(2);scl = 1;delayus(3);}//scl = 0;//delayus(3);//sda = 0; //因该把IO输出禁⽌,不然slaver⽆法下拉}//测试okvoid revdata(uint8_t *data){uint8_t i;//sda_in();for(i=0;i<8;i++){scl = 0;delayus(3);scl = 1;delayus(1);*data <<= 1;if(sda==1){*data |= 0x01; //⾸位置为⼀}else{*data &= 0xfe;}delayus(2);}}//测试okvoid i2c_nack(void){scl = 0;delayus(1);sda = 1;sda_out();delayus(2);scl = 1;delayus(3);}//测试okuint8_t i2c_dectack(void){uint8_t ackflg;scl = 0;delayus(1);sda_in();delayus(2);scl = 1;delayus(1);if(sda ==1){ackflg = 0; //为接收到应答}else{ackflg = 1; //接收到应答}delayus(2);return ackflg;}//测试ok 3msuint8_t i2c_wtdata(uint8_t address,uint8_t data){uint8_t temp,errflg=0;i2c_start();temp = 0xa0; //地址位赋值1010add(R/W)trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据scl = 0;delayus(1);sda = 1;sda_out();temp = address;trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}scl = 0;delayus(1);sda = 1;sda_out();trandata(data);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}// scl = 0;// delayus(3);// sda = 0;// sda_out();i2c_stop();return errflg;}//测试ok //测试不稳定uint8_t curddata(uint8_t *data){uint8_t temp,errflg=0;i2c_start();temp = 0xa1; //地址位赋值1010add(R/W)trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}//sda_out();revdata(data);i2c_nack();i2c_stop();return errflg;}//测试ok 4msuint8_t i2c_rddata(uint8_t address,uint8_t *pdata) {uint8_t temp,errflg=0;i2c_start();temp = 0xa0; //地址位赋值1010000(R/W)trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}scl = 0;delayus(1);sda = 1; //默认为上拉sda_out();temp = address;trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}scl = 0;delayus(1);sda = 1;sda_out();if(curddata(pdata) == 1){errflg = 1;return errflg;}/*//写数据遵守写⼊读出void i2cbus_wt(uint8_t address,uint8_t data){uint8_t temp;do{while(i2c_wtdata(address,data) == 1); //写⼊数据 while(curddata(&temp) == 1); //读出数据} while(data != temp); //⽐较通过视为写⼊成功}*/。
单片机普通IO口模拟IIC多机通信,本人已测试通过
/*说明,该程序是模拟IIC的通信思想,但也不全是,首先本人设计的不是从机与主机的通信,而是两单片机是平等的,单片机A可以向B或其他任何单片机发送数据(通过各个单片机所设置的地址来加以区分),同时单片机A可以也向B或其他任何单片机读取数据。
反之单片机B或其他单片机也可以向A发送数据或读取A的数据,所以各个单片机的代码基本上是一样的,只需根据具体不同的需要调用就行。
由于本人初学单片机,代码写的并不是很好。
望各位多多指教!!!*///单片机A 的代码#include<reg52.h>#define uchar unsigned char#define uint unsigned int#define LOC_address 0x48sbit sda=P1^0;sbit scl=P1^1;sbit STROBE = P1^2;bit R_W;bit START_flag=0;uchar DEV_address;void delay(){uint i;for(i=0;i<=100;i++);}void init(){sda=1;scl=1;STROBE=1;}void start() //启动I2C总线{sda = 1;delay();scl = 1;delay();sda = 0;delay();// 此处scl不能拉低,否则两单片机通信时时序无法保持一致}/*void start_scan(){bit PreState;bit NowState;char NN = 10;PreState = sda; //记录当前SDA状态,用作比较while(scl == 1 && NN--){NowState = sda;if(PreState == 1 && NowState == 0) //如果为下降沿则为开始信号{START_flag = 1;}}}*/void Send_Date(uchar j){unsigned char i;bit temp;scl = 1;while(STROBE);if(STROBE==0){ delay();delay();delay();for (i = 0 ;i < 8 ;i++){if((j<<i)&0x80)temp=1;else temp=0;sda = temp; 、delay();scl = 0;delay();scl = 1;delay();}scl = 0;sda = 1; //释放数据线delay();STROBE=1;}STROBE=1;}uchar Receive_Date(){uchar i,j,k=0xff;scl = 1;STROBE=0;delay();if((!scl)&&(sda)){return k;}if(STROBE==0){while(scl);for(i=0;i<8;i++){while(!scl);if(sda==1)j=1;elsej=0;k=(k<<1)|j;delay();delay();while(scl);}P2=k;return k;}return k;}/*void ChackRdd(){uchar i,j,k=0xff;scl = 1;STROBE=0;delay();if(!STROBE){while(scl);for(i=0;i<8;i++){while(!scl);if(sda==1)j=1;elsej=0;k=(k<<1)|j;delay();delay();while(scl);}P0=k;R_W=k&0x01;DEV_address=(k&0xfe);STROBE=1;}STROBE=1;}void B_work(){if(STROBE){ChackRdd();if(DEV_address==LOC_address){if(R_W){STROBE=(~STROBE);Send_Date(0x55);}else if(!R_W){STROBE=(~STROBE);Receive_Date();}}}}*/void main(){init();while(1)//以下为测试代码。
单片机普通IO口双机通信
12864液晶串口显示发送机P1口与接收机P0口间接一块74H573 发送机:#include<reg52.h>#define uchar unsigned charsbit s1=P3^0;//按键uchar num=0x00;void delay(uchar z){uchar i,j;for(i=z;i>0;i--)for(j=110;j>0;j--);}void key(){if(s1==0){delay(5);if(s1==0){num++;if(num==0x0a){num=0x00;}}while(!s1);}}void main(){while(1){key();P1=num;delay(2);}}接收机:#include <reg52.h>#define uchar unsigned char#define uint unsigned intuint i,j,k;sbit SID = P2^5; //串行数据sbit SCLK = P2^6; //串行同步时钟uchar code table[]="0123456789";/*****延时子程序*****/void delay(uint z){for(i=z;i>0;i--);for(j=110;j>0;j--);}void delay50us(uint z){uint i,j;for(i=z;i>0;i--)for(j=19;j>0;j--);}/*****串行发送一个字节*****/void send_byte(uchar byte){uchar i;for(i=0;i<8;i++){SCLK = 0;byte=byte<<1; //左移一位先发送高位的数据SID = CY; //移出的位给SIDSCLK = 1; //上升沿触发发送SCLK = 0;}}/*****写指令*****/void write_com(uchar com ){delay(5);//检测忙的子程序我们就不写了,因为串行的不支持读操作,我们就用个延时吧send_byte(0xf8); //11111,RW(0),RS(0),0send_byte(0xf0&com); //高四位数据分两次发送,而且把数据放在高四位上发送send_byte(0xf0&com<<4); //低四位(先执行<<)}/*****写数据*****/void write_dat(uchar dat){delay(5);send_byte(0xfa); //11111,RW(0),RS(1),0send_byte(0xf0&dat); //高四位send_byte(0xf0&dat<<4); //低四位(先执行<<)}/*****初始化LCD*****/void init(){delay(100);write_com(0x30);delay50us(4);write_com(0x30);delay50us(4);write_com(0x0c); //打开显示delay50us(4);write_com(0x01); //清屏delay(50);write_com(0x06);delay(10);}void display(){uchar num;uint shu;num=P0;shu=num/10;write_com(0x80); write_dat(table[num]); delay(5);}/*****主函数*****/ void main(void){P0=0x00;init();while(1){display();}}。
STM32用GPIO模拟IIC(I2C)通讯c语言源码-实测可用
if(!IIC_Start())
{//UART1_Put_Char(1);
return FALSE;}
IIC_SendByte(SlaveAddress); //I2C_SendByte(((REG_Address & 0x0700) >>7) | REG_Address & 0xFFFE);//设置高起始地址+器件地址
u8 IIC_RecvACK(void)
{
#ifdef BMI160
SCL_L;
I2C_delay();
SDA_H;
I2C_delay();
SCL_H;
I2C_delay();
if(SDA_read)
{
SCL_L;
I2C_delay();
return FALSE;
}
SCL_L;
I2C_delay();
void IIC_SendByte(u8 dat)
{
#ifdef BMI160
u8 i=8;
while(i--)
{
SCL_L;
I2C_delay();
if(dat&0x80)
SDA_H;
else
SDA_L;
dat<<=1;
I2C_delay();
SCL_H;
I2C_delay();
}
SCL_L;
#else
u8 IIC_RecvByte(void)
{
#ifdef BMI160
u8 i=8;
u8 ReceiveByte=0;
SDA_H;
IO口中断模拟I2C通信方式
{
if(F_long==0)
{
INTbyteflag=0;
F_long=32;
INT_i2c=1;
F_INT_read=1;
F_read_ok=1;
clk_d=0;
INTnum=0;
clk_watch=0;
}
if(clk_over_timer>=2)
{
INT_i2c=0;
INT_i2c=0;
return TRUE;
}
五、
1、相应的代码都是基于STC15系列单片机
2、代码所实现的功能是:主单片机发送指令,12864显示相应内容
3、源代码所需硬件:
12864液晶一个,STC15w204s一片
F_read_ok:接收完数据标志位
INTnum:中断次数标志位
INTre[]:接收数据缓存区
INTbyteflag:接收字节个数标志位
F_long:接收的指令长度
void I2cRead() interrupt 0
{
INTTemp=INTTemp<<1;
INTTemp=INTTemp|SDA;
clk_over_timer=0;
三、
传统的I2C通信方式,SCL负责传送信号脉冲,SDA负责传送数据,SCL为低时,允许传送数据。通过中断方式实现I2C也是遵循了这个原理。与传统I2C的区别在于,当SCL电平变化时,只传送一位数据,所以接收完一个字节数据时,SCL需由高到低变化八次。
四、源代码分析
1、初始化I2C函数
功能:将SDA与SCL电平置高,SDA可以为任何IO口,SCL必须为带有中断的IO口。
INTnum=0;
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/*说明,该程序是模拟IIC的通信思想,但也不全是,首先本人设计的不是从机与主机的通信,而是两单片机是平等的,单片机A可以向B或其他任何单片机发送数据(通过各个单片机所设置的地址来加以区分),同时单片机A可以也向B或其他任何单片机读取数据。
反之单片机B或其他单片机也可以向A发送数据或读取A的数据,所以各个单片机的代码基本上是一样的,只需根据具体不同的需要调用就行。
由于本人初学单片机,代码写的并不是很好。
望各位多多指教!!!*///单片机A 的代码#include<reg52.h>#define uchar unsigned char#define uint unsigned int#define LOC_address 0x48sbit sda=P1^0;sbit scl=P1^1;sbit STROBE = P1^2;bit R_W;bit START_flag=0;uchar DEV_address;void delay(){uint i;for(i=0;i<=100;i++);}void init(){sda=1;scl=1;STROBE=1;}void start() //启动I2C总线{sda = 1;delay();scl = 1;delay();sda = 0;delay();// 此处scl不能拉低,否则两单片机通信时时序无法保持一致}/*void start_scan(){bit PreState;bit NowState;char NN = 10;PreState = sda; //记录当前SDA状态,用作比较while(scl == 1 && NN--){NowState = sda;if(PreState == 1 && NowState == 0) //如果为下降沿则为开始信号{START_flag = 1;}}}*/void Send_Date(uchar j){unsigned char i;bit temp;scl = 1;while(STROBE);if(STROBE==0){ delay();delay();delay();for (i = 0 ;i < 8 ;i++){if((j<<i)&0x80)temp=1;else temp=0;sda = temp; 、delay();scl = 0;delay();scl = 1;delay();}scl = 0;sda = 1; //释放数据线delay();STROBE=1;}STROBE=1;}uchar Receive_Date(){uchar i,j,k=0xff;scl = 1;STROBE=0;delay();if((!scl)&&(sda)){return k;}if(STROBE==0){while(scl);for(i=0;i<8;i++){while(!scl);if(sda==1)j=1;elsej=0;k=(k<<1)|j;delay();delay();while(scl);}P2=k;return k;}return k;}/*void ChackRdd(){uchar i,j,k=0xff;scl = 1;STROBE=0;delay();if(!STROBE){while(scl);for(i=0;i<8;i++){while(!scl);if(sda==1)j=1;elsej=0;k=(k<<1)|j;delay();delay();while(scl);}P0=k;R_W=k&0x01;DEV_address=(k&0xfe);STROBE=1;}STROBE=1;}void B_work(){if(STROBE){ChackRdd();if(DEV_address==LOC_address){if(R_W){STROBE=(~STROBE);Send_Date(0x55);}else if(!R_W){STROBE=(~STROBE);Receive_Date();}}}}*/void main(){init();while(1)//以下为测试代码。
{while(STROBE){while(STROBE){start();}while(!STROBE);/* while(STROBE){Send_Date(0xaa); //发送地址和写指令}while(!STROBE){Send_Date(0x99); //发送数据0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90 }*/while(STROBE){Send_Date(0xab); //发送地址和读指令}}while(!STROBE){STROBE=1;Receive_Date();}}}//单片机B的代码#include<reg52.h>#define uchar unsigned char#define uint unsigned int#define LOC_address 0xaasbit sda=P1^0;sbit scl=P1^1;sbit STROBE = P1^2;bit R_W;bit START_flag=0;uchar DEV_address;void delay(){uint i;for(i=0;i<=100;i++);}/*void start() //启动I2C总线{sda = 1;delay();scl = 1;delay();sda = 0;delay();}*/void start_scan(){bit PreState;bit NowState;char NN = 10;PreState = sda; //记录当前SDA状态,用作比较while(scl == 1 && NN--){NowState = sda;if(PreState == 1 && NowState == 0) //如果为下降沿则为开始信号{START_flag = 1;}}}void Send_Date(uchar j){unsigned char i;bit temp;scl = 1;while(STROBE);if(STROBE==0){ delay();delay();delay();for (i = 0 ;i < 8 ;i++){if((j<<i)&0x80)temp=1;else temp=0;sda = temp;delay();scl = 0;delay();scl = 1;delay();}scl = 0;sda = 1; //释放数据线delay();STROBE=1;}STROBE=1;}uchar Receive_Date(){uchar i,j,k=0xff;scl = 1;STROBE=0;delay();if((!scl)&&(sda)){return k;}if(STROBE==0){while(scl);for(i=0;i<8;i++){while(!scl);if(sda==1)j=1;elsej=0;k=(k<<1)|j;delay();delay();while(scl);}P2=k;return k;}return k;}void ChackRdd(){uchar i,j,k=0xff;scl = 1;STROBE=0;//置低信号告诉单片机A、单片机B已做好准备接收delay();if(!STROBE){while(scl);//等待A响应for(i=0;i<8;i++){while(!scl);if(sda==1)elsej=0;k=(k<<1)|j;delay();delay();while(scl);}P0=k;R_W=k&0x01;DEV_address=(k&0xfe);STROBE=1;}STROBE=1;}void B_work(){if(STROBE){start_scan();if(START_flag){START_flag=0;STROBE=0;delay();STROBE=1;ChackRdd();if(DEV_address==LOC_address){if(R_W){STROBE=(~STROBE);STROBE=1;//必须再次置高,使得两单片机在发送和接收数据时时序保持一致Send_Date(0x80);}else if(!R_W){STROBE=(~STROBE);Receive_Date();}}}}void main() {STROBE=1; scl=1; while(1) {B_work(); }}。