马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
一、用完软件模拟IIC,虽然实现了一个通用接口,只要是IO口都可以用,但是既然引脚用到了PB6和PB7,这俩都是自带硬件外设IIC的,不消白不消。这里我也给出硬件IIC的实现,不得不说HAL库封装的真好
1.硬件IIC
这里我加入一个编译宏,在main.h中,实现可以切换软硬件IIC
硬件IIC速度不要太快,我开始跳到400000的时间触摸是无效的。
其他的设置都在CubeMx生成的iic文件中。这里利用句柄的情势也可以切换差别的iic。
因为我只利用了IIC1 这里也可以再添加一个参数指明利用的是IIC几。
- #include "iic_hal_hard.h"
- #include "main.h"
- #if IICSOFT == 0
- /* I2C1 init function */
- void MX_I2C1_Init(I2C_HandleTypeDef *hi2cx)
- {
- hi2cx->Instance = I2C1;
- hi2cx->Init.ClockSpeed = 100000;
- hi2cx->Init.DutyCycle = I2C_DUTYCYCLE_2;
- hi2cx->Init.OwnAddress1 = 0;
- hi2cx->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
- hi2cx->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
- hi2cx->Init.OwnAddress2 = 0;
- hi2cx->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
- hi2cx->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
- if (HAL_I2C_Init(hi2cx) != HAL_OK)
- {
- Error_Handler();
- }
- }
- void IICInit(I2C_HandleTypeDef *hi2cx)
- {
- MX_I2C1_Init(hi2cx);
- }
- uint8_t IIC_Write_One_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg,uint8_t data)
- {
- HAL_StatusTypeDef status;
- status = HAL_I2C_Mem_Write(hi2cx, daddr << 1, reg, I2C_MEMADD_SIZE_8BIT, &data, 1, 1000);
- if (status == HAL_OK)
- {
- return SUCCESS;
- }else
- {
- return ERROR;
- }
- }
- uint8_t IIC_Write_Multi_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg,uint8_t length,uint8_t buff[])
- {
- HAL_StatusTypeDef status;
- status = HAL_I2C_Mem_Write(hi2cx, daddr << 1, reg, I2C_MEMADD_SIZE_8BIT, buff, length, 1000);
- if (status == HAL_OK)
- {
- return SUCCESS;// 数据写入寄存器成功
- }
- else
- {
- return ERROR;// 数据写入失败,可能是从机无应答、通信错误等原因
- }
- }
- uint8_t IIC_Read_One_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg)
- {
- HAL_StatusTypeDef status;
- uint8_t RxBuff;
- status = HAL_I2C_Mem_Read(hi2cx, daddr << 1, reg, I2C_MEMADD_SIZE_8BIT, &RxBuff, 1, 1000);
- if (status == HAL_OK)
- {
- return RxBuff;
- }else
- {
- return ERROR;
- }
-
- }
- uint8_t IIC_Read_Multi_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr, uint8_t reg, uint8_t length, uint8_t buff[])
- {
- HAL_StatusTypeDef status;
-
- status = HAL_I2C_Mem_Read(hi2cx, daddr << 1, reg, I2C_MEMADD_SIZE_8BIT, buff, length, 1000);
- if (status == HAL_OK)
- {
- return SUCCESS;
- }else
- {
- return ERROR;
- }
- }
- #endif
复制代码 HAL库封装的,我觉得没有这个中心IIC接口层也可以实现触摸IC的驱动编写。
2 硬件IIC头文件
- #ifndef __IIC_HAL_HARD_H
- #define __IIC_HAL_HARD_H
- #include "stm32f4xx_hal.h"
- #include "main.h"
- //PB6 PB7 IIC1外设
- #if IICSOFT == 0
- extern I2C_HandleTypeDef hi2c1;
- void IICInit(I2C_HandleTypeDef *hi2cx);
- uint8_t IIC_Write_One_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg,uint8_t data);
- uint8_t IIC_Write_Multi_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg,uint8_t length,uint8_t buff[]);
- uint8_t IIC_Read_One_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr,uint8_t reg);
- uint8_t IIC_Read_Multi_Byte(I2C_HandleTypeDef *hi2cx, uint8_t daddr, uint8_t reg, uint8_t length, uint8_t buff[]);
- #endif
- #endif
复制代码 3 修改后的软件IIC
- #include "iic_hal.h"
- #include "delay.h"
- #if IICSOFT == 1
- //SCL 低电平期间 SDA可以任意改变电位 高电平不允许改动 因为要采样
- // SDA输入模式
- void SDA_Input_Mode(iic_bus_t* bus)
- {
- GPIO_InitTypeDef GPIO_InitStructure = {0};
-
- GPIO_InitStructure.Pin = bus->IIC_SDA_PIN;
- GPIO_InitStructure.Pull = GPIO_MODE_INPUT;
- GPIO_InitStructure.Pull = GPIO_PULLUP;
- GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
- HAL_GPIO_Init(bus->IIC_SDA_PORT,&GPIO_InitStructure);
- }
- // SDA输出模式
- void SDA_Output_Mode(iic_bus_t* bus)
- {
- GPIO_InitTypeDef GPIO_InitStructure = {0};
-
- GPIO_InitStructure.Pin = bus->IIC_SDA_PIN;
- GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;//下次不要这样搞,还是用MX来配置后复制,不然容易错
- GPIO_InitStructure.Pull = GPIO_NOPULL;
- GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
- HAL_GPIO_Init(bus->IIC_SDA_PORT,&GPIO_InitStructure);
- }
- //SDA输出一个位
- void SDA_Output(iic_bus_t *bus, uint8_t val)
- {
- if(val)
- HAL_GPIO_WritePin(bus->IIC_SDA_PORT,bus->IIC_SDA_PIN,GPIO_PIN_SET);
- else
- HAL_GPIO_WritePin(bus->IIC_SDA_PORT,bus->IIC_SDA_PIN,GPIO_PIN_RESET);
-
- }
- //SCL输出一个位
- void SCL_Output(iic_bus_t *bus, uint8_t val)
- {
- if(val)
- HAL_GPIO_WritePin(bus->IIC_SCL_PORT,bus->IIC_SCL_PIN,GPIO_PIN_SET);
- else
- HAL_GPIO_WritePin(bus->IIC_SCL_PORT,bus->IIC_SCL_PIN,GPIO_PIN_RESET);
- }
- //SDA输入一位 读一位
- uint8_t SDA_Input(iic_bus_t *bus)
- {
- //我觉得这里可以直接返回读到得值 不用判断了
- return (uint8_t)HAL_GPIO_ReadPin(bus->IIC_SDA_PORT,bus->IIC_SDA_PIN) ;
- }
- //从这个严格定义的角度来说,最后将 SCL 拉低这一步不属于起始信号本身的部分
- //将 SCL 拉低是为了按照 I2C 通信的正确时序,
- //把总线状态调整到适合后续数据传输的起始位置
- void IICStart(iic_bus_t *bus)
- {
- //当 SCL 为高电平时,SDA 从高电平向低电平跳变
- SDA_Output(bus,1);
- delay_us(2);
- SCL_Output(bus,1);
- delay_us(1);
- SDA_Output(bus,0);
- delay_us(1);
- SCL_Output(bus,0);
- delay_us(1); //
-
- }
- //严格来说,I2C 协议中定义的停止信号是当 SCL 为高电平时,
- //SDA 从低电平向高电平跳变
- //为了确保正确的时序过渡:在 I2C 通信中,
- //数据的传输和各种信号的产生都是按照严格的时序进行的
- void IICStop(iic_bus_t *bus)
- {
- //当 SCL 为高电平时,SDA 从低电平向高电平跳变
- SCL_Output(bus,0);
- delay_us(2);
- SDA_Output(bus,0);
- delay_us(1);
- SCL_Output(bus,1);
- delay_us(1); //释放总线
- SDA_Output(bus,1);
- delay_us(1);
-
- }
- uint8_t IICWaitAck(iic_bus_t *bus)
- {
- uint8_t cErrTime = 5;
- SDA_Input_Mode(bus);//将数据线变成输入模式 接受从机的应答
- SCL_Output(bus,1);// 拉高时钟线
- while(SDA_Input(bus))//读到的数一直是1的话就是没有应答
- {
- cErrTime--;//读5次都没有结果就是没有应答 表示接受结束
- delay_us(1);
- if(0 == cErrTime)
- {
- SDA_Output_Mode(bus);
- IICStop(bus);
- return ERROR;
- }
- }
- //如果给了应答 就是读到了0
- SDA_Output_Mode(bus);//转换成输出模式
- SCL_Output(bus,0);//拉低时钟线 为下一个时序做准备
- delay_us(2);
- return SUCCESS;
- }
- void IICSendAck(iic_bus_t *bus)
- {
- SDA_Output(bus,0);//我记得是低电平放上数据
- delay_us(1);
- SCL_Output(bus,1);
- delay_us(1);
- SCL_Output(bus,0);
- delay_us(2);
- }
- void IICSendNotAck(iic_bus_t *bus)
- {
- //我记得是低电平放上数据等时钟线高电平稳定采样 且此时不允许修改数据
- SDA_Output(bus,1);
- delay_us(1);
- SCL_Output(bus,1);
- delay_us(1);
- SCL_Output(bus,0);
- delay_us(2);
- }
- void IICSendByte(iic_bus_t *bus, uint8_t cSendByte)
- {
- uint8_t i;
- for(i=0;i<8;i++)
- {
- SCL_Output(bus,0);
- delay_us(2);
- SDA_Output(bus,((cSendByte >> (7 - i)) & 0x01));
- delay_us(1);
- SCL_Output(bus,1);
- delay_us(1);
- }
- SCL_Output(bus,0);
- delay_us(2);
- }
- uint8_t IICReceiveByte(iic_bus_t *bus)
- {
- uint8_t i, cR_Byte=0;
- uint8_t bit=0;
- SDA_Input_Mode(bus);//接受字节 改成输入模式
- for(i=0;i<8;i++)
- {
- SCL_Output(bus,0); //拉低时钟线 等待从机放数据
- delay_us(2);
- SCL_Output(bus,1);//拉高时钟线 可以采样了
- delay_us(1);
- bit = SDA_Input(bus);
- cR_Byte |= bit << (7-i);
- }
- SCL_Output(bus,0);//拉低时钟线
- SDA_Output_Mode(bus);//改变为输出模式 只有读数据才是输入模式
- return cR_Byte;
- }
- void IICInit(iic_bus_t *bus)
- {
- GPIO_InitTypeDef GPIO_InitStructure = {0};
- //bus->CLK_ENABLE();
-
- GPIO_InitStructure.Pin = bus->IIC_SDA_PIN ;
- //上面给的是开漏 这里变成推挽搞不懂 ,推挽就不用变输入模式了
- GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
- GPIO_InitStructure.Pull = GPIO_NOPULL;
- GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
- HAL_GPIO_Init(bus->IIC_SDA_PORT, &GPIO_InitStructure);
-
- GPIO_InitStructure.Pin = bus->IIC_SCL_PIN ;
- HAL_GPIO_Init(bus->IIC_SCL_PORT, &GPIO_InitStructure);
- }
- //返回1表示失败
- uint8_t IIC_Write_One_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg,uint8_t data)
- {
- IICStart(bus);//开始信号
- IICSendByte(bus,(daddr << 1));//写从机地址
- if(IICWaitAck(bus)) //无应答停止传输
- {
- IICStop(bus);
- //printf("%d\r\n",IICWaitAck(bus)); 第一次初始化器件的时候会非应答
- return 1;
- }
- IICSendByte(bus,reg);
- IICWaitAck(bus);
- IICSendByte(bus,data);
- IICWaitAck(bus);
- IICStop(bus);
- delay_us(1);
- return 0;
-
- }
- uint8_t IIC_Write_Multi_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg,uint8_t length,uint8_t buff[])
- {
- uint8_t i;
- uint8_t* dataPtr = buff;
- IICStart(bus);//开始信号
- IICSendByte(bus,(daddr << 1));//写从机地址
- if(IICWaitAck(bus)) //无应答停止传输
- {
- IICStop(bus);
- return 1;
- }
- IICSendByte(bus,reg);
- IICWaitAck(bus);
- for(i=0;i<length;i++)
- {
- //IICSendByte(bus,buff[i]);
- IICSendByte(bus,*dataPtr++);//利用指针指向缓存区 先解引用给首个元素赋值 再指向下一个字节
- IICWaitAck(bus);
- }
- IICStop(bus);
- delay_us(1);
- return 0;
- }
- uint8_t IIC_Read_One_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg)
- {
- uint8_t cR_Byte=0;
- IICStart(bus);//开始信号
- IICSendByte(bus,(daddr << 1));//写从机地址
- IICWaitAck(bus);
- IICSendByte(bus,reg);
- IICWaitAck(bus);
-
- IICStart(bus);//开始信号
- IICSendByte(bus,(daddr << 1)| 1);//读操作
- IICWaitAck(bus);
- cR_Byte = IICReceiveByte(bus);
- IICSendNotAck(bus);
- IICStop(bus);
- return cR_Byte;
- }
- uint8_t IIC_Read_Multi_Byte(iic_bus_t *bus, uint8_t daddr, uint8_t reg, uint8_t length, uint8_t buff[])
- {
- uint8_t i;
- uint8_t* dataPtr = buff;
- IICStart(bus);//开始信号
- IICSendByte(bus,(daddr << 1)&0xFE );//写从机地址
- IICWaitAck(bus);
- IICSendByte(bus,reg);
- IICWaitAck(bus);
-
-
- IICStart(bus);//开始信号
- IICSendByte(bus,(daddr << 1)| 1);//读操作
- IICWaitAck(bus);
- for(i=0;i<length;i++)
- {
- //buff[i] = IICReceiveByte(bus);
- *dataPtr++ = IICReceiveByte(bus);//右++ 先操作后自加
- if(i<length-1)
- IICSendAck(bus);
- else
- IICSendNotAck(bus);
- }
-
- IICStop(bus);
- return 0;
- }
- #endif
复制代码 4 修改后的软件IIC头文件 (就是加了个宏编译)
- #ifndef __IIC_HAL_H
- #define __IIC_HAL_H
- #include "stm32f4xx_hal.h"
- #include "main.h"
- #if IICSOFT == 1
- typedef struct
- {
- GPIO_TypeDef* IIC_SDA_PORT;
- GPIO_TypeDef* IIC_SCL_PORT;
- uint32_t IIC_SDA_PIN;
- uint32_t IIC_SCL_PIN;
- // void (*CLK_ENABLE)(void);
- }iic_bus_t;//IIC控制器
- void IICStart(iic_bus_t *bus);
- void IICStop(iic_bus_t *bus);
- uint8_t IICWaitAck(iic_bus_t *bus);
- void IICSendAck(iic_bus_t *bus);
- void IICSendNotAck(iic_bus_t *bus);
- void IICSendByte(iic_bus_t *bus, uint8_t cSendByte);
- uint8_t IICReceiveByte(iic_bus_t *bus);
- void IICInit(iic_bus_t *bus);
- uint8_t IIC_Write_One_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg,uint8_t data);
- uint8_t IIC_Write_Multi_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg,uint8_t length,uint8_t buff[]);
- uint8_t IIC_Read_One_Byte(iic_bus_t *bus, uint8_t daddr,uint8_t reg);
- uint8_t IIC_Read_Multi_Byte(iic_bus_t *bus, uint8_t daddr, uint8_t reg, uint8_t length, uint8_t buff[]);
- #endif
- #endif
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |