关于STM32模拟IIC的SDA_IN() SDA_OUT()改写

文章详细解析了STM32中如何通过宏定义模拟IIC协议的SDA输入和输出功能,重点在于理解GPIO端口配置,包括PB7和PA4、PB11的例子。配置涉及到对CRL和CRH寄存器的操作,以及根据引脚位置进行适当的移位计算。

正点原子例程模拟IIC中有两行代码是PB7做SDA_IN


#define SDA_IN()  {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}

如果想应用不想看手册的话,改为其他引脚其实是有规律

主要是注意

1.端口PB还是PA还是PC

2.是低位CRL(如PIN4)还是高位CRH(如PIN11)

3.移位多少,pin(X)*4,属于CRL如PIN4 就是<<4*4=16;属于CRH如PIN11 就是<<pin(11-8)*4=12。也就是:判断好GPIO是低8位还是高8位,如PROTAx(x为第几个pin),低8位<< x*4,高8位<<(11-x)*4。


//PA4如下
#define SDA_IN()    {GPIOA->CRL&=0XFFF0FFFF;GPIOA->CRL|=(u32)8<<16;} 
#define SDA_OUT() {GPIOA->CRL&=0XFFF0FFFF;GPIOA->CRL|=(u32)3<<16;}

“0XFFF0FFFF"这里的0对应第4pin。 "CRL"对应0-7PIN,4pin属于CRL 。 "(u32)3<<16"中的16=第pin4*4。


//PB11如下
#define SDA_IN()     {GPIOB->CRH&=0XFFFF0FFF;GPIOA->CRL|=(u32)8<<12;} 
#define SDA_OUT() {GPIOA->CRHL&=0XFFFF0FFF;GPIOA->CRL|=(u32)3<<12;}

“0XFFFF0FFF"这里的0对应第11pin。 "CRH"对应8-15PIN,11pin属于CRH 。 "(u32)3<<12"中的12=第pin(11-8)*4。

#ifndef __MPUIIC_H #define __MPUIIC_H #include "sys.h" //IO方向设置 ---PB11 #define MPU_SDA_IN() {GPIOB->CRH &= 0XFFFF0FFF;GPIOB->CRH |= 8<<12;} //上拉/下拉 输入模式 #define MPU_SDA_OUT() {GPIOB->CRH &= 0XFFFF0FFF;GPIOB->CRH |= 3<<12;} //推挽输出 输出模式 //IO操作函数 #define MPU_IIC_SCL PBout(10) //SCL #define MPU_IIC_SDA PBout(11) //SDA #define MPU_READ_SDA PBin(11) //输入SDA //IIC所有操作函数 void MPU_IIC_Delay(void); //IIC延时2ms函数 void MPU_IIC_Init(void); //初始化IIC的IO口 void MPU_IIC_Start(void); //发送IIC开始信号 void MPU_IIC_Stop(void); //发送IIC停止信号 void MPU_IIC_Send_Byte(u8 txd); //IIC发送一个字节 u8 MPU_IIC_Read_Byte(unsigned char ack);//IIC读取一个字节 u8 MPU_IIC_Wait_Ack(void); //IIC等待ACK信号 void MPU_IIC_Ack(void); //IIC发送ACK信号 void MPU_IIC_NAck(void); //IIC不发送ACK信号 void IMPU_IC_Write_One_Byte(u8 daddr,u8 addr,u8 data); u8 MPU_IIC_Read_One_Byte(u8 daddr,u8 addr); #endif #include "mpuiic.h" #include "delay.h" /********************************************** 函数名称:MPU_IIC_Delay 函数功能:MPU IIC延时函数,延时2ms 函数参数:无 函数返回值:无 **********************************************/ void MPU_IIC_Delay(void) { delay_us(2); } /********************************************** 函数名称:MPU_IIC_Init 函数功能:MPU IIC初始化 函数参数:无 函数返回值:无 **********************************************/ void MPU_IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //先使能外设IO PORTB时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11; //端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIO GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11); //PB10,PB11 输出高 } /********************************************** 函数名称:MPU_IIC_Start 函数功能:MPU IIC发送起始信号 函数参数:无 函数返回值:无 **********************************************/ void MPU_IIC_Start(void) { MPU_SDA_OUT(); //SDA线 输出 MPU_IIC_SDA=1; MPU_IIC_SCL=1; MPU_IIC_Delay(); MPU_IIC_SDA=0; //START:当SCL线处于高电平时,SDA线突然从高变低,发送起始信号 MPU_IIC_Delay(); MPU_IIC_SCL=0; //钳住I2C总线,准备发送或接收数据 } /********************************************** 函数名称:MPU_IIC_Stop 函数功能:MPU IIC发送停止信号 函数参数:无 函数返回值:无 **********************************************/ void MPU_IIC_Stop(void) { MPU_SDA_OUT(); //SDA线输出 MPU_IIC_SCL=0; MPU_IIC_SDA=0; //STOP:当SCL线处于高电平时,SDA线突然从低变高,发送停止信号 MPU_IIC_Delay(); MPU_IIC_SCL=1; MPU_IIC_SDA=1; //发送I2C总线结束信号 MPU_IIC_Delay(); } /********************************************** 函数名称:MPU_IIC_Wait_Ack 函数功能:MPU IIC等待信号到来 函数参数:无 函数返回值:1:接收应答信号成功 0:接收应答信号失败 **********************************************/ u8 MPU_IIC_Wait_Ack(void) { u8 ucErrTime=0; MPU_SDA_IN(); //SDA设置为输入 MPU_IIC_SDA=1;MPU_IIC_Delay(); MPU_IIC_SCL=1;MPU_IIC_Delay(); while(MPU_READ_SDA) { ucErrTime++; if(ucErrTime>250) { MPU_IIC_Stop(); return 1; } } MPU_IIC_SCL=0;//时钟输出0 return 0; } /********************************************** 函数名称:MPU_IIC_Ack 函数功能:MPU IIC产生应答信号 函数参数:无 函数返回值:无 **********************************************/ void MPU_IIC_Ack(void) { MPU_IIC_SCL=0; MPU_SDA_OUT(); MPU_IIC_SDA=0; MPU_IIC_Delay(); MPU_IIC_SCL=1; MPU_IIC_Delay(); MPU_IIC_SCL=0; } /********************************************** 函数名称:MPU_IIC_NAck 函数功能:MPU IIC不产生应答信号 函数参数:无 函数返回值:无 **********************************************/ void MPU_IIC_NAck(void) { MPU_IIC_SCL=0; MPU_SDA_OUT(); MPU_IIC_SDA=1; MPU_IIC_Delay(); MPU_IIC_SCL=1; MPU_IIC_Delay(); MPU_IIC_SCL=0; } /********************************************** 函数名称:MPU_IIC_Send_Byte 函数功能:MPU IIC发送一个字节 函数参数:txd:要发送的数据 函数返回值:无 注意:IIC发送字节是一个一个位发送的,发送一个字节需要发送八次 **********************************************/ void MPU_IIC_Send_Byte(u8 txd) { u8 t; MPU_SDA_OUT(); MPU_IIC_SCL=0; //拉低时钟开始数据传输 for(t=0;t<8;t++) { MPU_IIC_SDA=(txd&0x80)>>7; txd<<=1; MPU_IIC_SCL=1; MPU_IIC_Delay(); MPU_IIC_SCL=0; MPU_IIC_Delay(); } } /********************************************** 函数名称:MPU_IIC_Read_Byte 函数功能:MPU IIC读取一个字节 函数参数:ack: 1,发送ACK 0,发送NACK 函数返回值:接收到的数据 注意:IIC读取字节是一个一个位读取的,读取一个字节需要读取八次 **********************************************/ u8 MPU_IIC_Read_Byte(unsigned char ack) { unsigned char i,receive=0; MPU_SDA_IN(); //SDA设置为输入 for(i=0;i<8;i++) { MPU_IIC_SCL=0; MPU_IIC_Delay(); MPU_IIC_SCL=1; receive<<=1; if(MPU_READ_SDA)receive++; //如果读到了数据 MPU_IIC_Delay(); } if (!ack) MPU_IIC_NAck(); //发送nACK else MPU_IIC_Ack(); //发送ACK return receive; } 改为可以在HAL库使用
最新发布
09-20
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值