////////////////////////////////////////////////////////////////////////// /// COPYRIGHT NOTICE /// Copyright (c) 2018, 传控科技 /// All rights reserved. /// /// @file iic_sim /// @brief iic 模拟io 版本, 和cpu无关,唯一需要修改的就是头函数中的管脚定义 /// @info 如无必要请勿修改 ///(本文件实现的功能的详述) /// /// @version 1.1 CCsens technology /// @author CC /// @date 20180102 // ////////////////////////////////////////////////////////////////////////// ///#include "msp_iicM1.h" #include "msp_iicM2.h" /*------------------------------------------------ 端口定义 在I2C总线传输数据过程中,每传输一个字节, 都要跟一个应答状态位。接收器接收数据的情况 可以通过应答位来告知发送器。应答位的时钟脉冲 仍由主机产生,而应答位的数据状态则遵循“谁 接收谁产生”的原则,即总是由接收器产生应答位, 在响应的时钟脉冲期间接收器必须将SDA 线拉 低,使它在这个时钟脉冲的高电平期间保持稳定的低电平(见图9) , 当然必须考虑建立和保持时间 (详细请查阅表6) 。主机向从机发送数据时, 应答位由从机产生;主机从从机接收数据时,应答位 由主机产生。 I2C总线标准规定: 应答位为0表示接收器应答 (ACK) , 常常简记为A; 为1则表示非应答 (NACK) , 常简记为NA。发送器发送LSB之后,应当释放SDA线(拉高SDA) , 以等待接收器产生应答位。 如果接收器在接收完最后一个字节的数据, 或者不能再接收更多的数据时,应当产生非应答信 号来通知发送器。发送器如果发现接收器产生了非应答状态, 则应当终止发送。 ------------------------------------------------*/ ///<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< void L0_IICM2_SCL(unsigned char v) { if(v) { L0_IICM2_SCL_ON();/// L0_SCL_ON(); L0_slc2_1_delay(); } else { L0_IICM2_SCL_OFF();///L0_SCL_OFF(); L0_slc2_0_delay(); } } void L0_IICM2_SDA(unsigned char v) { if(v) { L0_IICM2_SDA_ON(); L0_slc2_1_delay(); } else { L0_IICM2_SDA_OFF(); L0_slc2_0_delay(); } } void L0_IICM2_INIT(unsigned char v) { if (v) { //L0_IIC_SIM2_INIT(); L0_IICM2_SCL_init(); L0_IICM2_SDA_init(); L0_IICM2_SDA(1); L0_IICM2_SCL(1); }else { } } unsigned char L0_IICM2_SDA_ask(void) { return L0_IICM2_SDA_AT(); } ///<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< /**************** void L0_I2C_Reset(void) { L0_I2C_SCL(1); L0_I2C_SDA(1); //确认释放总线 } ********************/ #define L0_IIC_SIM2_INIT() #define L0_IIC_SIM2_close() //********************************************** //送起始位 IO_SDA=1->0 void L0_IICM2_Start(void) { ///L0_IIC_SIM2_INIT(); L0_IICM2_SDA(1); L0_IICM2_SCL(1); L0_IICM2_SDA(0); L0_IICM2_SCL(0); } //************************************************ //送停止位 IO_SDA = 0->1 void L0_IICM2_Stop(void) { L0_IICM2_SDA(0); L0_IICM2_SCL(1); L0_IICM2_SDA(1); L0_IIC_SIM2_INIT(); L0_IIC_SIM2_close(); } //************************************************ //主应答(包含ack:IO_SDA = 0和no_ack:IO_SDA = 0) void L0_IICM2_Ack(void) { //设置SDA 口为输出 L0_IICM2_SCL(0); L0_IICM2_SDA(0); L0_IICM2_SCL(1); L0_IICM2_SCL(0); L0_IICM2_SDA(1); } void L0_IICM2_NoAck(void) { //设置SDA 口为输出 L0_IICM2_SCL(0); L0_IICM2_SDA(1); L0_IICM2_SCL(1); L0_IICM2_SCL(0); } /****** I2C总线标准规定: 应答位为0表示接收器应答 (ACK) , 常常简记为A; 为1则表示非应答 (NACK) ,常简记为NA。 发送器发送LSB之后,应当释放SDA线(拉高SDA) , 以等待接收器产生应答位。 如果接收器在接收完最后一个字节的数据, 或者不能再接收更多的数据时,应当产生非应答信 号来通知发送器。发送器如果发现接收器产生了非应答状态, 则应当终止发送。 // 检测 SDA是否回ACK bit L0_I2C_Test_Ack(void) { //设置SDA 口为输入 bit ACK_Flag = 0; L0_I2C_SCL(0); L0_I2C_SDA(1); L0_I2C_SCL(1); if(IO_SDA = 0) ACK_Flag = 1; else ACK_Flag = 0; L0_I2C_SCL(0); return ACK_Flag; // return 1;// debug } *******/ //************************************************* //字节发送程序 //发送c(可以是数据也可是地址),送完后接收从应答 //不考虑从应答位 void L0_IICM2_SendData(unsigned char c) { unsigned char ack=8; unsigned char BitCnt=8;//一字节8位 //设置SDA 口为输出 for(BitCnt = 0;BitCnt < 8;BitCnt ++) //要传送的数据长度为8位 { if((c << BitCnt ) & 0x80) L0_IICM2_SDA(1); //判断发送位 else L0_IICM2_SDA(0); L0_IICM2_SCL(1); //置时钟线为高,通知被控器开始接收数据位 L0_IICM2_SCL(0); }//8clk L0_IICM2_SDA(1); //8位发送完后释放数据线,准备接收应答位 L0_IICM2_SCL(1); ///gRccUs05 += L0_I2C_SDA_ask(); L0_IICM2_SCL(0); L0_IICM2_delay(); } //************************************************** //字节接收程序 //接收器件传来的数据,此程序应配合|主应答函数|i2c_ack_main(void)使用 //return: uchar型1字节 unsigned char L0_IICM2_ReceiveData(void) { unsigned char BitCnt=8,IIC_RX_Data = 0; L0_IICM2_SDA(1); //读入数据 设置SDA 口为输入 for(BitCnt = 0;BitCnt<8;BitCnt++) { L0_IICM2_delay(1); L0_IICM2_SCL(0); //置时钟线为低,准备接收数据位 L0_IICM2_SCL(1); //置时钟线为高使数据线上数据有效 L0_IICM2_delay(1); IIC_RX_Data = IIC_RX_Data << 1; if(1 == L0_IICM2_SDA_ask()) IIC_RX_Data = IIC_RX_Data + 1; //读数据位,接收的数据位放入retc中 L0_IICM2_delay(1); }// 8clk up L0_IICM2_SCL(0); return IIC_RX_Data; } /// 读取 n个数据 放入p中 void L1_IICM2_ReadNByte(unsigned char Sal, unsigned char *p,unsigned char n) { unsigned char i; L0_IICM2_Start(); // 启动I2C L0_IICM2_SendData((Sal)| 0x01); //发送器件地址 for(i = 0;i < n-1;i ++) //读取字节数据 { *(p + i) = L0_IICM2_ReceiveData(); //读取数据 ///printf("%x ",(int)(*(p + i))); L0_IICM2_Ack(); //__/```\__ } *(p + n - 1) = L0_IICM2_ReceiveData(); L0_IICM2_NoAck(); L0_IICM2_Stop(); } #if 0 主机从从设备读取多个字节 Master ST SAD+W SUB SR SAD+R MAK MAK NMAK SP Slave SAK SAK SAK DATA DATA DATA 0x19 0001 1001 0011 001R #endif /////////////////////////////// ///写入一个reg 为后续的写命令或者读取服务 void L1_IICM2_WriteReg(unsigned char sla,unsigned char reg) { L0_IICM2_Start(); //启动I2C L0_IICM2_SendData(sla);//发送器件地址 L0_IICM2_SendData(reg); } // sla.(reg)=cmd void L2_IICM2_WriteCmd(unsigned char sla,unsigned char reg,unsigned char cmd) { L1_IICM2_WriteReg(sla,reg); L0_IICM2_SendData(cmd); L0_IICM2_Stop(); /***************** if(gRccUs05 >0)///测试iic有效否 发现没有结果 { L0_uart0_uc(gRccUs05);gRccUs05 = 0; } ***************/ } //读取reg地址的n个数据 sla.(reg) sla.(reg+1)................ sla.(reg+n) void L2_IICM2_ReadReg(unsigned char sla,unsigned char reg, unsigned char *r,unsigned char n) { // U8 d[1]; //S ADD W A REG A L1_IICM2_WriteReg(sla,reg); //S ADD R A D1 A D2 A.....DX N P L1_IICM2_ReadNByte(sla,r,n); } //读取reg地址的n个数据 sla.(reg) sla.(reg+1)................ sla.(reg+n) unsigned char L2_IICM2_Read1Reg1D(unsigned char sla,unsigned char reg) { U8 d; // U8 d[1]; //S ADD W A REG A L1_IICM2_WriteReg(sla,reg); //S ADD R A D1 A D2 A.....DX N P L1_IICM2_ReadNByte(sla,&d,1); return d; } #if 0////不可删除 ///S 80H A Register Address A S 81H A Data NA P void L2_tws_ReadReg000(unsigned char sla,unsigned char reg, unsigned char *v) { unsigned char ack=8; unsigned char BitCnt=8;//一字节8位 // U8 d[1]; //S ADD W A REG A //// L1_I2C_WriteReg(sla,reg); //step 1---- L0_I2C_Start(); //启动I2C //step 2----L0_I2C_SendData(sla);//发送器件地址 //设置SDA 口为输出 for(BitCnt = 0;BitCnt < 8;BitCnt ++) //要传送的数据长度为8位 { if((sla << BitCnt ) & 0x80) L0_I2C_SDA(1); //判断发送位 else L0_I2C_SDA(0); L0_I2C_SCL(1); //置时钟线为高,通知被控器开始接收数据位 L0_I2C_SCL(0); }//8clk L0_I2C_SDA(1); //8位发送完后释放数据线,准备接收应答位 L0_I2C_SCL(1); L0_I2C_SCL(0); //step 3---L0_I2C_SendData(reg); for(BitCnt = 0;BitCnt < 8;BitCnt ++) //要传送的数据长度为8位 { if((reg << BitCnt ) & 0x80) L0_I2C_SDA(1); //判断发送位 else L0_I2C_SDA(0); L0_I2C_SCL(1); //置时钟线为高,通知被控器开始接收数据位 L0_I2C_SCL(0); }//8clk L0_I2C_SDA(1); //8位发送完后释放数据线,准备接收应答位 L0_I2C_SCL(1); L0_I2C_SCL(0); //step 4---- L0_I2C_Start(); //启动I2C //step 5--- //设置SDA 口为输出 sla|=0x01; for(BitCnt = 0;BitCnt < 8;BitCnt ++) //要传送的数据长度为8位 { if((sla << BitCnt ) & 0x80) L0_I2C_SDA(1); //判断发送位 else L0_I2C_SDA(0); L0_I2C_SCL(1); //置时钟线为高,通知被控器开始接收数据位 L0_I2C_SCL(0); }//8clk L0_I2C_SDA(1); //8位发送完后释放数据线,准备接收应答位 L0_I2C_SCL(1); L0_I2C_SCL(0); //step 6---receive data //设置SDA 口为输出 *v = L0_I2C_ReceiveData(); L0_I2C_SCL(1); L0_I2C_SCL(0);/// send NA //step 7--- P L0_I2C_Stop(); } ///S 80H A Register Address A S 81H A Data NA P #endif