本文为CSDN博主「被追杀的晨曦」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/double_lee3/article/details/90205474
#include "SN7326.h"
#include <stdio.h>
#include <string> // for STL string class
#include "define.h"
extern bool(__stdcall *InitializeWinIo)(void);
extern void(__stdcall *ShutdownWinIo)(void);
extern PBYTE(__stdcall *MapPhysToLin)(PBYTE pbPhysAddr, DWORD dwPhysSize, HANDLE *pPhysicalMemoryHandle);
extern bool(__stdcall *UnmapPhysicalMemory)(HANDLE PhysicalMemoryHandle, PBYTE pbLinAddr);
extern bool(__stdcall *GetPhysLong)(PBYTE pbPhysAddr, PDWORD pdwPhysVal);
extern bool(__stdcall *SetPhysLong)(PBYTE pbPhysAddr, DWORD dwPhysVal);
extern bool(__stdcall *GetPortVal)(WORD wPortAddr, PDWORD pdwPortVal, BYTE bSize);
extern bool(__stdcall *SetPortVal)(WORD wPortAddr, DWORD dwPortVal, BYTE bSize);
extern bool(__stdcall *InstallWinIoDriver)(PSTR pszWinIoDriverPath, bool IsDemandLoaded);
extern bool(__stdcall *RemoveWinIoDriver)(void);
/*
*FunctionName: I2CDelay
* Purpose : I2C时序模拟SCL时间间隔(周期),需要根据Slave性能及单片机工作频率调整
* Parameters : 无
*/
static void I2C_Delay(void) {
__asm {
nop
nop
nop
nop
}
}
/*
* FunctionName: I2CStart
* Purpose: 模拟I2C开始信号, SCL电平拉高,SDA由高变低,I2C开始传输数据
* Parameters: 无
*/
static void SN7325_i2c_START(void) {
SN7325_I2C_SCL_H;
SN7325_I2C_SDA_H;
I2C_Delay();
SN7325_I2C_SDA_L;
SN7325_I2C_SCL_L;
}
static void SN7325_i2c_RESTART(void) {
SN7325_I2C_SCL_L;
SN7325_I2C_SCL_H;
SN7325_I2C_SDA_H;
I2C_Delay();
SN7325_I2C_SDA_L;
SN7325_I2C_SCL_L;
}
/*
* FunctionName: I2CStop
* Purpose: 模拟I2C结束信号,SCL电平拉高,SDA由低边高,I2C停止传输数据
* Parameters: 无
*/
static void SN7325_i2c_STOP(void) {
int i;
SN7325_I2C_SCL_H;
SN7325_I2C_SDA_L;
I2C_Delay();
SN7325_I2C_SDA_H;
}
/*
* FunctionName: I2CSendNoACK
* Purpose: 模拟I2C无ACK响应
* Parameters: 无
*/
static void SN7325_i2c_NOACK(void) {
SN7325_I2C_SDA_H;
SN7325_I2C_SCL_H;
SN7325_I2C_SCL_L;
}
/*
* FunctionName: I2CCheckACK
* Purpose:把串口设置为输入模式,测试串口是否有响应
* Parameters: 无
*/
static bool SN7325_i2c_WAITACK(void) {
unsigned long tempACK = 0;
unsigned long res = 0;
unsigned long time_out = 0;
SN7325_I2C_SDA_L;
SetPhysLong((PBYTE)KEY_IO5_ADDR, 0x00908200);//输入模式
SN7325_I2C_SCL_H;
do {
GetPhysLong((PBYTE)KEY_IO5_ADDR, (PDWORD)&tempACK);//获取ack
if (tempACK)
res =1;
else
res = 0;
time_out++;
if (time_out > 3)//超时处理
{
res = 0;
}
} while (( !res )||(time_out> 3));
SN7325_I2C_SCL_L;
return res;
}
/*
* FunctionName: I2CTWRITE8BIT
* Purpose:模拟I2C发送一个字节数据,从低位开始写
* Parameters: sendData-发送的一个字节数据
*/
static void SN7325_i2c_WRITE8B(unsigned char input) {
unsigned char serialNum;
for (serialNum = 8; serialNum >= 1; serialNum--)
{
if (input & 0x80) {//判断最高位是否为1
SN7325_I2C_SDA_H;
}
else {
SN7325_I2C_SDA_L;
}
SN7325_I2C_SCL_H;
I2C_Delay();
SN7325_I2C_SCL_L;
input <<= 1;//数据左移一位
}
}
/*
* FunctionName: I2CTREAD8BIT
* Purpose:模拟I2C接收一个字节数据
* Parameters: 无
*/
static unsigned char SN7325_i2c_READ8B(void)
{
unsigned char serialNum;
unsigned char I2CBUF = 0;
unsigned long SDAStatus = 0;
SetPhysLong((PBYTE)KEY_IO5_ADDR, 0x00908200); //设置SDA/串口为输入模式
for (serialNum = 8; serialNum >=1; serialNum--) {
I2CBUF <<= 1;
SN7325_I2C_SCL_H;
GetPhysLong((PBYTE)KEY_IO5_ADDR, (PDWORD)&SDAStatus);
if (SDAStatus) {
I2CBUF |= 0x01;
//I2CBUF++;//表示读取数据
}
SN7325_I2C_SCL_L;
}
printf("I2CBUF = %x", I2CBUF);
return I2CBUF;
}
/*
写寄存器的标准流程为
1. Master发起START
2. Master发送I2C addr(7bit)和w操作0(1bit),等待ACK
3. Slave发送ACK
4. Master发送reg addr(8bit),等待ACK
5. Slave发送ACK
6. Master发送data(8bit),即要写入寄存器中的数据,等待ACK
7. Slave发送ACK
8. 第6步和第7步可以重复多次,即顺序写多个寄存器
9. Master发起STOP
*/
void SN7325_Write_i2c(unsigned char WriteDeviceAddress, unsigned char Command, unsigned char Wdata)
{
SN7325_i2c_START();
SN7325_i2c_WRITE8B(WriteDeviceAddress);
SN7325_i2c_WAITACK();
SN7325_i2c_WRITE8B(Command);
SN7325_i2c_WAITACK();
SN7325_i2c_WRITE8B(Wdata);
SN7325_i2c_NOACK();
SN7325_i2c_STOP();
}
/*
I2C读寄存器函数的时序:
1、主设备发出开始信号
2、写入从设备地址
3、主设备接收从设备发来的应答信号
4、写入寄存器地址
5、主设备接收应答信号
6、主设备再次发出开始信号
7、主设备向从设备写入(从设备的地址+1),此时加1表示要从寄存器中读数据
8、从设备给出应答信号
9、从从设备的寄存器中读出数据传给变量
10、主设备发出停止信号
11、返回读出的数据
*/
unsigned short SN7325_Read_i2c(unsigned char ReadDeviceAddress, unsigned char Command)
{
unsigned char r_byte;
SN7325_i2c_START();
SN7325_i2c_WRITE8B(ReadDeviceAddress - 1); //先写入从设备的地址。表示要向从设备中写地址和数据
SN7325_i2c_WAITACK();
SN7325_i2c_WRITE8B(Command); //写入寄存器的地址,数据将从些地址中读出
SN7325_i2c_WAITACK();
//SN7325_i2c_RESTART();
SN7325_i2c_START();
SN7325_i2c_WRITE8B(ReadDeviceAddress); //发送器件地址,地址LSB最后一位为0代表写入,1代表读取
SN7325_i2c_WAITACK();
r_byte = SN7325_i2c_READ8B();
//SN7325_i2c_WAITACK();//lsx add
SN7325_i2c_NOACK();
SN7325_i2c_STOP();
//r_byte = SN7325_i2c_READ8B(); //从地址regaddr中读出数据
return r_byte;
}