首页 / 资讯中心 / 文章详情

【STM32标准库】铁道山羊--[I2C]软I2C

【STM32标准库】铁道山羊--[I2C]软I2C ★ FEATURED ARTICLE
111一.为什么使用软I2C?正常的I2C的使用操作繁琐并且引脚位置受到限制。软I2C通过按照I2C的数据帧格式发送波形可以在单片机上模拟出软件的I2C。二.软I2C的使用步骤1.对所用IO引脚初始化(这里用的是PA0 | PA1)void My_SI2C_Init(void); //1.初始化GPIOA_Pin_0 | GPIOA_Pin_1 void My_SI2C_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_SI2CA; GPIO_SI2CA.GPIO_PinGPIO_Pin_0 | GPIO_Pin_1; GPIO_SI2CA.GPIO_ModeGPIO_Mode_Out_OD;//通用输出开漏 GPIO_SI2CA.GPIO_SpeedGPIO_Speed_2MHz; GPIO_Init(GPIOA,GPIO_SI2CA); }使用通用输出开漏模式是因为通用输出开漏模式初始为高电压。2.IO读写和延迟函数因为要通过软件的方式去模拟scl和sad的输出波形因此进行以下操作void scl_write(uint8_t level);//向scl写0/1 void sda_write(uint8_t level);//向sda写0/1 uint8_t sda_read(void);//读sad的值 void delay_us(uint32_t us);//微秒延迟函数 void scl_wirte(niut8_t level) { //PA0 if(level0) { GPIO_WirteBit(GPIOA,GPIO_Pin_0,Bit_RESET); } else { GPIO_WirteBit(GPIOA,GPIO_Pin_0,Bit_SET); } } void sda_write(uint8_t level) { //PA1 if(level0) { GPIO_WirteBit(GPIOA,GPIO_Pin_1,Bit_RESET); } else { GPIO_WirteBit(GPIOA,GPIO_Pin_1,Bit_SET); } } uint8_t sad_read(void) { if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1)Bit_SET)//接口作用从引脚读0/1 { return 1; } else { return 0; } } void delay_us(niut32_t us) { uint32_t nus*8; for(uint32_t i0;in;i); }3.发送起始位和停止位起始位在scl为高电压的时候在sda上出现一个下降沿。实现假设起始位发送之前总线处于空闲状态此时scl和sda上都为高低压那么只需在sda上出现一个低电压void SendStart(void) void SendStart(void) { sda_write(0);//向sda写0 delay_us(1);//延迟1微秒 }停止位在scl为高电压的时候在sda上出现一个上升沿。实现假设在停止位发送之前scl处于高电压而sda上电压不确定。可以先向scl和sda上发送一个低电压延迟后再向scl上发送一个高电压再延迟最后往sda上发送一个高电压模拟上升沿。void SendStop(void) void SendStop(void) { scl_write(0); sda_write(0); delay_us(1); scl_write(1); delay_us(1); sda_write(1); delay_us(1); }4.如何发送一个字节想要发送一个字节要先知道如何发送一个比特位1如图蓝色虚线的两部分当scl0发送方准备数据当scl1接收方读取数据2发送一个比特位的代码scl_write(0); sda_write(x);//x为要发送的0/1 delay_us(1); scl_write(1); delay_us(1);3声明一个函数用来发送字节uint8_t SendByte(uint8_t Byte);//参数Byte表示发送字节的内容返回值 0--ack 1--nak(4)如何得到xfor(int8_t i7;i0;i--) { scl_write(0); if((Byte(0x01i))!0) { sda_write(1); } else { sda_write(0); } delay_us(1); scl_write(1); delay_us(1); }5检测从机发送的是ack还是nak(波形比较复杂没讲按波形编程即可)//读取ACK或NAK scl_write(0); sda_write(1);//释放sda delay_us(1); scl_write(1);//延迟后再拉高scl delay_us(1); return sda_read();6发送一个字节总代码uint8_t SendByte(uint8_t Byte);//参数Byte表示发送字节的内容返回值 0--ack 1--nak uint8_t SendByte(uint8_t Byte) { for(int8_t i7;i0;i--) { scl_write(0); if((Byte(0x01i))!0) { sda_write(1); } else { sda_write(0); } delay_us(1); scl_write(1); delay_us(1); } //读取ACK或NAK scl_write(0); sda_write(1);//释放sda delay_us(1); scl_write(1); delay_us(1); return sda_read(); }5.如何接收一个字节1向scl写0向sda写1释放sda。延迟后在scl为高电压时读sda的值scl_write(0); sda_write(1);//释放sda delay_us(1); scl_write(1); delay_us(1); bitsda_read();2获取字节uint8_t bit0; for(int8_t i7;i0;i--) { scl_write(0); sda_write(1); delay_us(1); scl_write(1); delay_us(1); if(sda_read()!0) { byte |(0x01i); } }3回复ACK或NAKscl_write(0); sda_write(!Ack); delay_us(1); scl_write(1); delay_us(1); return byte;4接收总代码uint8_t ReceiveByte(uint8_t Ack) uint8_t ReceiveByte(uint8_t Ack) { uint8_t bit0; for(int8_t i7;i0;i--) { scl_write(0); sda_write(1); delay_us(1); scl_write(1); delay_us(1); if(sda_read()!0) { byte |(0x01i); } } scl_write(0); sda_write(!Ack); delay_us(1); scl_write(1); delay_us(1); return byte; }6.综合与硬件I2C一样int My_SI2C_SendBytes(uint8_t Addr,uint8_t *pData,uint16_t Size) { SendStart(); if(SendByte(Addr0xfe)!0) { SendStop(); return -1; } for(uint32_t i0;iSize;i) { if(SendByte(pData[i])!0) { SendStop(); return -2; } } SendByte(); }int My_SI2C_ReceiveBytes(uint8_t Addr,uint8_t *pBuffer,uint16_t Size) { SendStart(); if(SendByte(Addr|0x01)!0) { SendStop(); return -1; } for(uint32_t i0;iSize-1;i) { pBuffer[i]ReceivByte(1); } PBuffer[Size-1ReceivByte(0); SendStop(); }7.实现上面有错误这是改正且能编译的#include stm32f10x.h void My_SI2C_Init(void); void scl_write(uint8_t level);//向scl写0/1 void sda_write(uint8_t level);//向sad写0/1 uint8_t sda_read(void);//读sad电压 void delay_us(uint32_t us);//微秒延迟函数 void SendStart(void); void SendStop(void); uint8_t SendByte(uint8_t Byte);//参数Byte表示发送字节的内容 uint8_t ReceiveByte(uint8_t Ack); int My_SI2C_SendBytes(uint8_t Addr,uint8_t *pData,uint16_t Size); int My_SI2C_ReceiveBytes(uint8_t Addr,uint8_t *pBuffer,uint16_t Size); int main(void) { My_SI2C_Init(); uint8_t commands[]{0x00,0x8d,0x14,0xaf,0xa5}; My_SI2C_SendBytes(0x78,commands,5); while(1) { } } //1.初始化GPIOA_Pin_0 | GPIOA_Pin_1 void My_SI2C_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_SI2CA; GPIO_SI2CA.GPIO_PinGPIO_Pin_0 | GPIO_Pin_1; GPIO_SI2CA.GPIO_ModeGPIO_Mode_Out_OD; GPIO_SI2CA.GPIO_SpeedGPIO_Speed_2MHz; GPIO_Init(GPIOA,GPIO_SI2CA); GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);//初始高压 GPIO_WriteBit(GPIOA,GPIO_Pin_1,Bit_SET);//初始高压 } void scl_write(uint8_t level) { //PA0 if(level0) { GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET); } else { GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET); } } void sda_write(uint8_t level) { //PA1 if(level0) { GPIO_WriteBit(GPIOA,GPIO_Pin_1,Bit_RESET); } else { GPIO_WriteBit(GPIOA,GPIO_Pin_1,Bit_SET); } } uint8_t sda_read(void) { if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1)Bit_SET)//接口作用从引脚读0/1 { return 1; } else { return 0; } } void delay_us(uint32_t us) { uint32_t nus*8; for(uint32_t i0;in;i); } void SendStart(void) { sda_write(0);//向sda写0 delay_us(1);//延迟1微秒 } void SendStop(void) { scl_write(0); sda_write(0); delay_us(1); scl_write(1); delay_us(1); sda_write(1); delay_us(1); } uint8_t SendByte(uint8_t Byte) { for(int8_t i7;i0;i--) { scl_write(0); if((Byte(0x01i))!0) { sda_write(1); } else { sda_write(0); } delay_us(1); scl_write(1); delay_us(1); } //读取ACK或NAK scl_write(0); sda_write(1);//释放sda delay_us(1); scl_write(1); delay_us(1); return sda_read(); } uint8_t ReceiveByte(uint8_t Ack) { uint8_t byte0; for(int8_t i7;i0;i--) { scl_write(0); sda_write(1); delay_us(1); scl_write(1); delay_us(1); if(sda_read()!0) { byte |(0x01i); } } scl_write(0); sda_write(!Ack); delay_us(1); scl_write(1); delay_us(1); return byte; } int My_SI2C_SendBytes(uint8_t Addr,uint8_t *pData,uint16_t Size) { SendStart(); if(SendByte(Addr0xfe)!0) { SendStop(); return -1; } for(uint32_t i0;iSize;i) { if(SendByte(pData[i])!0) { SendStop(); return -2; } } SendStop(); return 0; } int My_SI2C_ReceiveBytes(uint8_t Addr,uint8_t *pBuffer,uint16_t Size) { SendStart(); if(SendByte(Addr|0x01)!0) { SendStop(); return -1; } for(uint32_t i0;iSize-1;i) { pBuffer[i]ReceiveByte(1); } pBuffer[Size-1]ReceiveByte(0); SendStop(); return 0; }
阅读完成 · 觉得有帮助?
咨询建站