目录

本文中使用582测试,在整合先前博客中的代码的基础上,加上读写超时,加上返回值,加上16位从机寄存器地址的判断,希望读写各用一个函数就能解决硬件IIC的使用问题。

#include "CH58x_common.h"

#define TIME_OUT    10000            //用于IIC读写超时,等待n次
#define DELAY_IIC DelayUs(5) //用于IIC读写超时,设置一次等待的时长 #define HOST_NO_ADDR 0x66 //随便设置,对主机不影响
#define EEPROM_ADDR 0xA0 //EEPROM设备地址 uint8_t IIC_read_nBytes(uint8_t addr, uint16_t mem, uint8_t mem_16, uint8_t *p_des, uint8_t len);
uint8_t IIC_write_nBytes(uint8_t addr, uint16_t mem, uint8_t mem_16, uint8_t *p_src, uint8_t len); uint8_t wData[32] = {8}; //存放即将写的数据
uint8_t rData[32] = {0}; //存放读取出的数据 uint8_t mem_writing[5] = {0x10, 0x20, 0x30, 0x40, 0x50}; //存放8位的目标内存/寄存器
uint16_t mem_writing2[2] = {0x1020, 0x2022}; //存放16位的目标内存/寄存器 const uint8_t data[5][20] = { //随便写一些数值,每行第一个字节表示之后的字节长度
{8,1,2,3,4,5,6,7,8},
{5,10,48,48,77,3},
{7,168,42,44,145,1,38,44},
{6,4,44,145,1,16,44},
{6,48,47,46,45,44,43},
}; int main()
{
SetSysClock(CLK_SOURCE_PLL_80MHz); GPIOA_SetBits(GPIO_Pin_9); //串口1GPIO初始化,TXD在配置推挽输出前先置位
GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);
GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);
UART1_DefInit(); //串口初始化 GPIOB_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13, GPIO_ModeIN_PU);
I2C_Init(I2C_Mode_I2C, 400000, I2C_DutyCycle_16_9, I2C_Ack_Enable, I2C_AckAddr_7bit, HOST_NO_ADDR);
DelayMs(300); //上电延时
PRINT("---------Init_OK---------\n"); while(1)
{
uint8_t trans_num = 0; for(uint8_t k=0; k<2; k++) //16位目标内存/寄存器读写
{
trans_num = data[k][0] + 1;
memcpy(wData, data[k], trans_num);
PRINT("Writing to 0x%02x:", mem_writing2[k]); for(uint8_t i=0; i<trans_num; i++)
{
PRINT("%x ", wData[i]);
}
PRINT("\n"); IIC_write_nBytes(EEPROM_ADDR, mem_writing2[k], 1, wData, trans_num);
DelayMs(100);
IIC_read_nBytes(EEPROM_ADDR, mem_writing2[k], 1, rData, trans_num); PRINT("Read form 0x%02x:", mem_writing2[k]);
for(uint8_t i=0; i<trans_num; i++)
{
PRINT("%x ", rData[i]);
rData[i] = 0;
}
PRINT("\n");
DelayMs(100);
} DelayMs(500); for(uint8_t k=0; k<5; k++) //16位目标内存/寄存器读写
{
trans_num = data[k][0] + 1;
memcpy(wData, data[k], trans_num);
PRINT("Writing to 0x%02x:", mem_writing[k]); for(uint8_t i=0; i<trans_num; i++)
{
PRINT("%x ", wData[i]);
}
PRINT("\n"); IIC_write_nBytes(EEPROM_ADDR, mem_writing[k], 0, wData, trans_num);
DelayMs(100);
IIC_read_nBytes(EEPROM_ADDR, mem_writing[k], 0, rData, trans_num); PRINT("Read form 0x%02x:", mem_writing[k]);
for(uint8_t i=0; i<trans_num; i++)
{
PRINT("%x ", rData[i]);
rData[i] = 0;
}
PRINT("\n");
DelayMs(100);
} DelayMs(1000);
}
} uint8_t IIC_timeout(uint16_t *p_times) //判断读写等待过程中是否超时
{
(*p_times)++;
DELAY_IIC;
if(*p_times > TIME_OUT)
{
return 1;
}
return 0;
} /***************************************
* 从从机的某寄存器起始,连续读取n个字节的数据
* 参数:addr 从机地址
* mem 内存/寄存器地址
* men_16 是否为16位内存/寄存器地址
* p_des 目的地址指针
* len 读取长度
* 返回值:0:正常
* 1~7:卡在第n步
* 0xFF:卡在连续读的过程中
*/ uint8_t IIC_read_nBytes(uint8_t addr, uint16_t mem, uint8_t mem_16, uint8_t *p_des, uint8_t len)
{
uint16_t i_timeout = 0; //主机通知从机要读取它的哪块内存
while(I2C_GetFlagStatus(I2C_FLAG_BUSY)) //IIC主机判忙
{
if(IIC_timeout(&i_timeout))
return 1;
else i_timeout = 0;
} I2C_GenerateSTART(ENABLE); //起始信号
while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)) //判断BUSY, MSL and SB flags
{
if(IIC_timeout(&i_timeout))
return 2;
else i_timeout = 0;
} I2C_Send7bitAddress(addr, I2C_Direction_Transmitter); //发送器件地址+最低位0表示为“写”
while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) //判断BUSY, MSL, ADDR, TXE and TRA flags
{
if(IIC_timeout(&i_timeout))
return 3;
else i_timeout = 0;
} if(mem_16)
{
I2C_SendData((uint8_t)(mem>>8)); //发送内存地址的高8位 while(!I2C_GetFlagStatus(I2C_FLAG_TXE)) //获取TxE的状态 数据寄存器为空标志位,可以向其中写数据
{
if(IIC_timeout(&i_timeout))
return 4;
else i_timeout = 0;
}
} I2C_SendData((uint8_t)mem); //发送内存地址的低8位
while(!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED)) //判断TRA, BUSY, MSL, TXE and BTF flags
{
if(IIC_timeout(&i_timeout))
return 5;
else i_timeout = 0;
} //直接产生一个重起始信号即可开始读的过程
I2C_GenerateSTART(ENABLE); //重起始信号
while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)) //判断BUSY, MSL and SB flags
{
if(IIC_timeout(&i_timeout))
return 6;
else i_timeout = 0;
} I2C_Send7bitAddress(addr, I2C_Direction_Receiver); //发送地址+最低位1表示为“读”
while(!I2C_CheckEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) //判断BUSY, MSL and ADDR flags
{
if(IIC_timeout(&i_timeout))
return 7;
else i_timeout = 0;
} I2C_GenerateSTOP(DISABLE);
//关闭停止信号使能(某些情况下可能会在此清除PE,这一行可以去掉) for(uint8_t i=0; i<len; i++)
{
if(i == len-1)
I2C_AcknowledgeConfig(DISABLE);
//清除ACK位(某些情况下可能会在此清除PE,这一行可以去掉,但是逻辑分析仪抓时序,会多接收一个字节数据)
//主设备为了能在收到最后一个字节后产生一个NACK信号,必须在读取倒数第二个字节之后(倒数第二个RxNE 事件之后)清除ACK位(ACK=0) while(!I2C_GetFlagStatus(I2C_FLAG_RXNE)) //获取RxEN的状态,等待收到数据
{
if(IIC_timeout(&i_timeout))
return 0xff;
else i_timeout = 0;
} *(p_des+i) = I2C_ReceiveData(); //获得从机的寄存器中的数据
} I2C_GenerateSTOP(ENABLE); //使能停止信号
I2C_AcknowledgeConfig(ENABLE); //传输完毕,再次打开ACK使能 return 0;
} /***************************************
* 向从机某寄内存地址起始,连续写入n个字节的数据
* 参数:addr 从机地址
* mem 寄存器地址
* men_16 是否为16位内存/寄存器地址
* p_src 源地址指针
* len 读取长度
* 返回值:0:正常
* 1~5:卡在第n步
* 0xFF:卡在连续写的过程中
*/
uint8_t IIC_write_nBytes(uint8_t addr, uint16_t mem, uint8_t mem_16, uint8_t *p_src, uint8_t len)
{
uint16_t i_timeout = 0;
//主机通知从机要写它的哪块内存
while(I2C_GetFlagStatus(I2C_FLAG_BUSY)) //IIC主机判忙
{
if(IIC_timeout(&i_timeout))
return 1;
else i_timeout = 0;
} I2C_GenerateSTART(ENABLE); //起始信号
while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)) //判断BUSY, MSL and SB flags
{
if(IIC_timeout(&i_timeout))
return 2;
else i_timeout = 0;
} I2C_Send7bitAddress(addr, I2C_Direction_Transmitter); //发送地址+最低位0表示为“写”
while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) //判断BUSY, MSL, ADDR, TXE and TRA flags
{
if(IIC_timeout(&i_timeout))
return 3;
else i_timeout = 0;
} if(mem_16)
{
I2C_SendData((uint8_t)(mem>>8)); //发送内存地址的高8位 while(!I2C_GetFlagStatus(I2C_FLAG_TXE)) //获取TxE的状态 数据寄存器为空标志位,可以向其中写数据
{
if(IIC_timeout(&i_timeout))
return 4;
else i_timeout = 0;
}
} I2C_SendData((uint8_t)mem); //发送内存地址的低8位 //ACK之后直接写入数据
for(uint8_t i=0; i<len; i++)
{
while(!I2C_GetFlagStatus(I2C_FLAG_TXE)) //获取TxE的状态 数据寄存器为空标志位,可以向其中写数据
{
if(IIC_timeout(&i_timeout))
return 0xff;
else i_timeout = 0;
}
I2C_SendData(*(p_src+i)); //发送数据
} while(!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED)) //判断TRA, BUSY, MSL, TXE and BTF flags
{
if(IIC_timeout(&i_timeout))
return 5;
else i_timeout = 0;
} I2C_GenerateSTOP(ENABLE); //停止信号 return 0;
}

硬件IIC的7位从机地址查询方式读写参考代码的更多相关文章

  1. LPC2478的硬件IIC使用

    LPC2478的IIC使用 LPC2478带有三个IIC接口,每个IIC都可以工作在主机或者从机模式下,LPC的IIC的架构是一种状态机的形式,在不同的的时间做不同的工作之后有不同的状态来表示, 简单 ...

  2. STM32硬件IIC

    /** * @brief 写一个字节到I2C设备中 * @param * @arg pBuffer:缓冲区指针 * @arg WriteAddr:写地址 * @retval 正常返回1,异常返回0 * ...

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

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

  4. 硬件IIC驱动原理

    1.IIC物理层 IIC通信属于同步半双工通信,IIC总线由两根信号线组成.一根是数据线SDA,一根是时钟线SCL,时钟线只能由主机发送给从机,数据线可以双向进行通信,总线上可挂载多个设备,挂载数量受 ...

  5. S3C2440硬件IIC详解

    S3C2440A RISC微处理器可以支持一个多主控IIC 总线串行接口.一条专用串行数据线(SDA)和一条专用串行时钟线(SCL)传递连接到IIC总线的总线主控和外设之间的信息.SDA和SCL线都为 ...

  6. STM32硬件IIC操作

    Stm32具有IIC接口,接口有以下主要特性 多主机功能:该模块既可做主设备也可做从设备 主设备功能 C地址检测 位/10位地址和广播呼叫 支持不同的通讯速度 状态标志: 发送器/接收器模式标志 字节 ...

  7. (转)stm32硬件IIC

    cube与I2C:https://www.cnblogs.com/121792730applllo/p/5044920.html I2C官网:https://www.i2c-bus.org/stand ...

  8. (4)I2C总线的7bit从机地址

    时钟拉伸(Clock stretching)clock stretching通过将SCL线拉低来暂停一个传输.直到释放SCL线为高电平,传输才继续进行.clock stretching是可选的,实际上 ...

  9. VMware12提示 已将该虚拟机配置为使用 64 位客户机操作系统。但是,无法执行 64 位操作。

    VMware12提示 已将该虚拟机配置为使用 64 位客户机操作系统.但是,无法执行 64 位操作. 此主机支持 Intel VT-x,但 Intel VT-x 处于禁用状态 解决办法: 下载LeoM ...

  10. 【电脑常识】如何查看电脑是32位(X86)还是64位(X64),如何知道硬件是否支持64位系统

    开始->运行->输入cmd确定->输入systeminfo 回车 待加载完成,就会看到如下信息(不同版本略有差异): 一.如何查看电脑是32位(X86)还是64位(X64) 方法2: ...

随机推荐

  1. Linux 驱动像单片机一样读取一帧dmx512串口数据

    硬件全志R528 目标:实现Linux 读取一帧dmx512串口数据. 问题分析:因为串口数据量太大,帧与帧之间的间隔太小.通过Linux自带的读取函数方法无法获取到 帧头和帧尾,读取到的数据都是缓存 ...

  2. 双层拖拽事件,用鼠标画矩形,拖动右下角可以再次改变矩形大小,方案一 有BUG

    <template> <div class="mycanvas-container"> <vue-drag-resize :isActive = 't ...

  3. 上传图片文件并立即显示到页面使用 javascript实现鼠标拖动画矩形框以及实现固定区域内随意拖动

    首先,你要设计好鼠标事件处理方法,主要是鼠标左键点击,左键释放,还有鼠标移动方法其次,要了解容什么方式,画一个矩形,设计一个方法:DrawRectgle(左上角,右下角),并且要确定当调用这个方法时, ...

  4. Angularjs的工程化

    Angularjs的工程化 AMD规范和CMD规范 为什么需要模块化管理工具 在编写项目时可能需要加载很多js文件,若b.js依赖a.js,且a.js比b.js大很多,那么浏览器会让b.js等待a.j ...

  5. 【Redis场景3】缓存穿透、击穿问题

    场景问题及原因 缓存穿透: 原因:客户端请求的数据在缓存和数据库中不存在,这样缓存永远不会生效,请求全部打入数据库,造成数据库连接异常. 解决思路: 缓存空对象 对于不存在的数据也在Redis建立缓存 ...

  6. java入门与进阶-P1.3+P1.4

    准备一个java编程软件 eclipse官网: Enabling Open Innovation & Collaboration | The Eclipse Foundation 他是一个免费 ...

  7. file类创建删除功能的方法-file类遍历(文件夹)目录功能

    file类创建删除功能的方法 public boolean createNewFile():当且仅当具有该名称的文件尚不存在时,创建一个新的空文件.public boolean delete(︰删除由 ...

  8. GPS定位解决偏差

    目录 GPS定位解决偏差 开篇 实践 1.解决思路以及步骤 2.实践出真理! 3.上坐标系之间的代码. 希望大家:点赞,留言,关注咯~ 唠家常 今日推荐都在文章中了 GPS定位解决偏差 开篇 大家都知 ...

  9. LinkedHashmap简要说明

    https://segmentfault.com/a/1190000012964859 LinkedHashMap 继承自 HashMap,在 HashMap 基础上,通过维护一条双向链表,解决了 H ...

  10. vue 事件中央总线

    vue 事件中央总线 作用: 实现任意组件间的通信 实现的方法: 有以下两种方式 方式1: 全局事件总线 1.在main.js文件中定义 new Vue({ el: '#app', router, s ...