本帖最后由 yanglinq 于 2024-11-15 16:48 编辑
/有个项目IO口不够用,又不想换大的CPU,只好用了个QFN24的小芯片通过模拟 IIC来扩展IO口。
/********************************************************************************/
/* @file xl9555.c */
/* @version V1.00 */
/* $author: yuanxihua@21cn.com */
/* $Date: 2023/09/13 01:54 $ */
/* @brief SWM181CBT6 Series XL9555 Driver Sample Code */
/* */
/* @NOTE */
/* Copyright (C) 2010-2023 PM9GZY Technology Corp. All rights reserved. */
/* */
/********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/*
_________________________________________________
| SWM181CBT6 XL9555 |
| |
| PB2 SCL ----> SCL |
| PB1 SDA <---> SDA |
| PE4 INT <--- INT |
|_______________________________________________|
*/
#include <stdint.h>
/* Private typedef -----------------------------------------------------------*/
#define I2C_Delay 10 /* us */
#define I2C_SCL GPIOB, PIN2
#define I2C_SDA GPIOB, PIN1
#define I2C_INT GPIOE, PIN4
/* Private define ------------------------------------------------------------*/
#define XL9555_SLAVEADDR 0x42 /* Clock i2c slave address */
/* Private macro -------------------------------------------------------------*/
#define XL9555_INPUT_PORT0 0x00
#define XL9555_INPUT_PORT1 0x01
#define XL9555_OUTPUT_PORT0 0x02
#define XL9555_OUTPUT_PORT1 0x03
#define XL9555_POLARITY_PORT0 0x04
#define XL9555_POLARITY_PORT1 0x05
#define XL9555_CONFIGURATION_PORT0 0x06
#define XL9555_CONFIGURATION_PORT1 0x07
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
void XL9555_Init(void)
{
GPIO_Init(I2C_INT, 0, 1, 0, 0); //GPIOE.4 配置为输入引脚,开启上拉 INT
GPIO_Init(I2C_SDA, 1, 0, 0, 0); //GPIOB.1 配置为输出引脚,推挽输出 SDA
GPIO_Init(I2C_SCL, 1, 0, 0, 0); //GPIOB.2 配置为输出引脚,推挽输出 SCL
GPIO_SetBit(I2C_SCL); //SCL 高
GPIO_SetBit(I2C_SDA); //SDA 高
}
void XL9555_Pluse(void)
{
GPIO_SetBit(I2C_SCL); //SCL 高
delay_us(I2C_Delay);
GPIO_ClrBit(I2C_SCL); //SCL 低
delay_us(I2C_Delay);
}
void XL9555_Start(void)
{
XL9555_Init();
delay_us(I2C_Delay);
GPIO_Init(I2C_SDA, 1, 0, 0, 0); //I2C_SDA 配置为输出引脚,推挽输出 SDA
GPIO_ClrBit(I2C_SDA); //SDA 低
delay_us(I2C_Delay);
GPIO_ClrBit(I2C_SCL); //SCL 低
delay_us(I2C_Delay);
}
void XL9555_ACK(uint8_t ack)
{
GPIO_Init(I2C_SDA, 1, 0, 0, 0); //I2C_SDA 配置为输出引脚,推挽输出 SDA
if(ack) {GPIO_SetBit(I2C_SDA);} //SDA 高 NAK
else {GPIO_ClrBit(I2C_SDA);} //SDA 低 ACK
delay_us(I2C_Delay);
XL9555_Pluse(); //发送ACK
GPIO_SetBit(I2C_SDA); //SDA 高 /* CPU释放SDA总线 */
}
uint8_t XL9555_WACK(void)
{
GPIO_Init(I2C_SDA, 0, 1, 0, 0); //I2C_SDA 配置为输入引脚,开启上拉 SDA
delay_us(I2C_Delay);
uint8_t ack=GPIO_GetBit(I2C_SDA); //接收ACK
XL9555_Pluse();
return ack;
}
void XL9555_Stop(void)
{
GPIO_Init(I2C_SDA, 1, 0, 0, 0); //I2C_SDA 配置为输出引脚,推挽输出 SDA
GPIO_ClrBit(I2C_SDA); //SDA 低
delay_us(I2C_Delay);
GPIO_SetBit(I2C_SCL); //SCL 高
delay_us(I2C_Delay);
GPIO_SetBit(I2C_SDA); //SDA 高
}
void XL9555_Send_Byte(uint8_t data,uint8_t ack)
{
GPIO_Init(I2C_SDA, 1, 0, 0, 0); //I2C_SDA 配置为输出引脚,推挽输出 SDA
for(int i=0;i<8;i++) //发送DATA
{
if(data&0x80){GPIO_SetBit(I2C_SDA);}
else{GPIO_ClrBit(I2C_SDA);}
data<<=1;XL9555_Pluse();
}
if(XL9555_WACK()!=ack){XL9555_Stop();} //等待ACK应答
}
uint16_t XL9555_Read_Byte(uint8_t ack)
{
uint16_t data=0;
GPIO_Init(I2C_SDA, 0, 1, 0, 0); //I2C_SDA 配置为输入引脚,开启上拉 SDA
for(int i=0;i<8;i++) //接收DATA
{
data<<=1;
if(GPIO_GetBit(I2C_SDA)){data+=1;}else{;}
XL9555_Pluse();
}
XL9555_ACK(ack); //发送ACK或者NAK
return data;
}
uint8_t XL9555_Write_buf(uint8_t addr,uint8_t reg,uint8_t *buf,uint8_t len)
{
XL9555_Init();
XL9555_Start();
XL9555_Send_Byte(addr|0,0); //发送器件地址+写命令+ACK
XL9555_Send_Byte(reg,0); //写寄存器地址+ACK
while(len--){XL9555_Send_Byte(*buf++,0);} //发送数据+ACK
XL9555_Stop();
return 0;
}
uint8_t XL9555_Read_buf(uint8_t addr,uint8_t reg,uint8_t *buf,uint8_t len)
{
XL9555_Init();
XL9555_Start();
XL9555_Send_Byte(addr|0,0); //发送器件地址+写命令+ACK
XL9555_Send_Byte(reg,0); //写寄存器地址+ACK
XL9555_Start();
XL9555_Send_Byte(addr|1,0); //发送器件地址+读命令+ACK
while(len--)
{
if(len==1) {*buf++=XL9555_Read_Byte(1);} //读数据+发送NAK
else {*buf++=XL9555_Read_Byte(0);} //读数据+发送ACK
}
XL9555_Stop(); //产生一个停止条件
return 0;
}
void XL9555_Configuration(uint16_t val)
{
XL9555_Write_buf(XL9555_SLAVEADDR, XL9555_CONFIGURATION_PORT0,(uint8_t *)&val,2);
}
void XL9555_OutPut(uint16_t val)
{
XL9555_Configuration(0x0000);
XL9555_Write_buf(XL9555_SLAVEADDR, XL9555_OUTPUT_PORT0,(uint8_t *)&val,2);
}
uint16_t XL9555_InPut(void)
{
uint16_t val;
XL9555_Configuration(0xffff);
XL9555_Write_buf(XL9555_SLAVEADDR, XL9555_OUTPUT_PORT0,(uint8_t *)&val,2);
return val;
}
uint16_t XL9555_InOutPut(uint16_t set,uint16_t val)
{
XL9555_Configuration(set);
uint8_t *buf=( uint8_t *)&val;
XL9555_Write_buf(XL9555_SLAVEADDR, XL9555_OUTPUT_PORT0,buf,2);
delay_us(1000);
XL9555_Read_buf (XL9555_SLAVEADDR, XL9555_INPUT_PORT0 ,buf,2);
return val;
}
void XL9555_Test(void)
{
uint8_t buf[8];
XL9555_Read_buf(XL9555_SLAVEADDR,0,buf,sizeof(buf));
for(int i=0;i<sizeof(buf);i++){printf("0x%02x ",buf);}
}
//代码完毕
|