STM32F1 TCA9548A 驱动多个IIC器件

3 篇文章 0 订阅
1 篇文章 0 订阅

TCA9548A的用途就是IIC扩展,每个TCA9548A可以扩展出8路IIC。TCA9548A芯片带有地址选择引脚A0/A1/A2,根据高低电平不同,从MCU的一路IIC最多可以接入8个TCA9548A芯片,从而可以达到扩展出8*8=64路IIC的效果。

在什么情况下会使用到TCA9548A芯片来扩展?当一个MCU想要驱动多个器件地址相同的芯片时,如驱动8个OLED时,OLED的IIC器件地址为0x78,要用MCU引出8路IIC的硬件线路?显然得不偿失,这时候用TCA9548A就再合适不过了。

下面是我使用STM32F1通过一个TCA9548A驱动8个OLED的示例描述

STM32和TCA9548A配合使用需要注意的问题:

1)TCA9548A硬件电路的连接

STM32和TCA9548A连线的上拉电阻我使用的4.7K。

2)STM32按照上述电路图后的代码配置

void i2c_CfgGpio(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(OLED_RCC_I2C_PORT, ENABLE);

	GPIO_InitStructure.GPIO_Pin = OLED_I2C_SCL_PIN | OLED_I2C_SDA_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;  	
	GPIO_Init(OLED_GPIO_PORT_I2C, &GPIO_InitStructure);

	i2c_Stop();
}

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;  这句代码的配置很重要,模式配置的不对,很有可能不好用。

下面是关键部分测试代码:

bsp_oled.c

#ifndef __BSP_OLED_H
#define __BSP_OLED_H
#include "bsp_oled.h"
#endif

#ifndef __CODETAB_H
#define __CODETAB_H
#include "codetab.h"
#endif

void i2c_CfgGpio(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(OLED_RCC_I2C_PORT, ENABLE);

	GPIO_InitStructure.GPIO_Pin = OLED_I2C_SCL_PIN | OLED_I2C_SDA_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;  	
	GPIO_Init(OLED_GPIO_PORT_I2C, &GPIO_InitStructure);

	i2c_Stop();
}


static void i2c_Delay(void)
{
	uint8_t i;
	for (i = 0; i < 10; i++);
}


void i2c_Start(void)
{
	OLED_I2C_SDA_1();
	OLED_I2C_SCL_1();
	i2c_Delay();
	OLED_I2C_SDA_0();
	i2c_Delay();
	OLED_I2C_SCL_0();
	i2c_Delay();
}


void i2c_Stop(void)
{
	OLED_I2C_SDA_0();
	OLED_I2C_SCL_1();
	i2c_Delay();
	OLED_I2C_SDA_1();
}


void i2c_SendByte(uint8_t _ucByte)
{
	uint8_t i;

	for (i = 0; i < 8; i++)
	{		
		if (_ucByte & 0x80)
		{
			OLED_I2C_SDA_1();
		}
		else
		{
			OLED_I2C_SDA_0();
		}
		i2c_Delay();
		OLED_I2C_SCL_1();
		i2c_Delay();	
		OLED_I2C_SCL_0();
		if (i == 7)
		{
			 OLED_I2C_SDA_1(); // ÊÍ·Å×ÜÏß
		}
		_ucByte <<= 1;
		i2c_Delay();
	}
}


uint8_t i2c_ReadByte(void)
{
	uint8_t i;
	uint8_t value;

	value = 0;
	for (i = 0; i < 8; i++)
	{
		value <<= 1;
		OLED_I2C_SCL_1();
		i2c_Delay();
		if (OLED_I2C_SDA_READ())
		{
			value++;
		}
		OLED_I2C_SCL_0();
		i2c_Delay();
	}
	return value;
}


 uint8_t i2c_WaitAck(void)
{
	uint8_t re;

	OLED_I2C_SDA_1();
	i2c_Delay();
	OLED_I2C_SCL_1();
	i2c_Delay();
	if (OLED_I2C_SDA_READ())
	{
		re = 1;
	}
	else
	{
		re = 0;
	}
	OLED_I2C_SCL_0();
	i2c_Delay();
	return re;
}


void i2c_Ack(void)
{
	OLED_I2C_SDA_0();
	i2c_Delay();
	OLED_I2C_SCL_1();
	i2c_Delay();
	OLED_I2C_SCL_0();
	i2c_Delay();
	OLED_I2C_SDA_1();
}


void i2c_NAck(void)
{
	OLED_I2C_SDA_1();	/* CPUÇý¶¯SDA = 1 */
	i2c_Delay();
	OLED_I2C_SCL_1();	/* CPU²úÉú1¸öʱÖÓ */
	i2c_Delay();
	OLED_I2C_SCL_0();
	i2c_Delay();	
}

void func_tca9548a_select(u8 chn)//0~7
{
	u8 ADDR_TCA9548A = 0x70;
	i2c_Start();
	i2c_SendByte((ADDR_TCA9548A << 1) | OLED_I2C_WR);
//	i2c_SendByte((ADDR_TCA9548A) | OLED_I2C_WR);
	
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;	
	}
		
	i2c_SendByte(1 << chn);
	
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;	
	}
	
	i2c_Stop();

cmd_fail:
	i2c_Stop();
}

u8 func_tca9548a_read_ch(void)
{
	u8 res;
	u8 ADDR_TCA9548A = 0x70;
	i2c_Start();
	i2c_SendByte((ADDR_TCA9548A << 1) | OLED_I2C_WR);
//	i2c_SendByte((ADDR_TCA9548A) | OLED_I2C_WR);
	
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;
	}
	res = i2c_ReadByte();
	
	i2c_NAck();
	
	i2c_Stop();
	cmd_fail:
		i2c_Stop();
	
	return res;
}


uint8_t OLED_CheckDevice(uint8_t _Address)
{
	uint8_t ucAck;
	
	i2c_Start();		/* ·¢ËÍÆô¶¯ÐźŠ*/

	i2c_SendByte(_Address|OLED_I2C_WR);/* ·¢ËÍÉ豸µØÖ· */
	ucAck = i2c_WaitAck();	/* ¼ì²âÉ豸µÄACKÓ¦´ð */

	i2c_Stop();			/* ·¢ËÍÍ£Ö¹ÐźŠ*/

	return ucAck;
}



void I2C_WriteByte(uint8_t addr,uint8_t data){
	
	i2c_Start();
	
	i2c_SendByte(OLED_ADDRESS|OLED_I2C_WR);
	
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;
	}
		
	i2c_SendByte(addr);
	
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;
	}

	i2c_SendByte(data);
	
	if (i2c_WaitAck() != 0)
	{
		goto cmd_fail;
	}	
	
	i2c_Stop();

cmd_fail: 
	i2c_Stop();

}


void WriteCmd(unsigned char I2C_Command)//дÃüÁî
{
	I2C_WriteByte(0x00, I2C_Command);
}


void WriteDat(unsigned char I2C_Data)//дÊý¾Ý
{
	I2C_WriteByte(0x40, I2C_Data);
}


void OLED_Init(void)
{
	delay_ms(10);
	
	WriteCmd(0xAE); //display off
	WriteCmd(0x20);	//Set Memory Addressing Mode	
	WriteCmd(0x10);	//00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
	WriteCmd(0xb0);	//Set Page Start Address for Page Addressing Mode,0-7
	WriteCmd(0xc8);	//Set COM Output Scan Direction
	WriteCmd(0x00); //---set low column address
	WriteCmd(0x10); //---set high column address
	WriteCmd(0x40); //--set start line address
	WriteCmd(0x81); //--set contrast control register
	WriteCmd(0xff); //ÁÁ¶Èµ÷½Ú 0x00~0xff
	WriteCmd(0xa1); //--set segment re-map 0 to 127
	WriteCmd(0xa6); //--set normal display
	WriteCmd(0xa8); //--set multiplex ratio(1 to 64)
	WriteCmd(0x3F); //
	WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
	WriteCmd(0xd3); //-set display offset
	WriteCmd(0x00); //-not offset
	WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency
	WriteCmd(0xf0); //--set divide ratio
	WriteCmd(0xd9); //--set pre-charge period
	WriteCmd(0x22); //
	WriteCmd(0xda); //--set com pins hardware configuration
	WriteCmd(0x12);
	WriteCmd(0xdb); //--set vcomh
	WriteCmd(0x20); //0x20,0.77xVcc
	WriteCmd(0x8d); //--set DC-DC enable
	WriteCmd(0x14); //
	WriteCmd(0xaf); //--turn on oled panel
	
	OLED_CLS();
}


void OLED_SetPos(unsigned char x, unsigned char y) 
{ 
	WriteCmd(0xb0+y);
	WriteCmd(((x&0xf0)>>4)|0x10);
	WriteCmd((x&0x0f)|0x01);
}


void OLED_Fill(unsigned char fill_Data)//È«ÆÁÌî³ä
{
	unsigned char m,n;
	for(m=0;m<8;m++)
	{
		WriteCmd(0xb0+m);		//page0-page1
		WriteCmd(0x00);		//low column start address
		WriteCmd(0x10);		//high column start address
		for(n=0;n<130;n++)
			{
				WriteDat(fill_Data);
			}
	}
}


void OLED_CLS(void)//ÇåÆÁ
{
	OLED_Fill(0x00);
}



void OLED_ON(void)
{
	WriteCmd(0X8D);  //ÉèÖõçºÉ±Ã
	WriteCmd(0X14);  //¿ªÆôµçºÉ±Ã
	WriteCmd(0XAF);  //OLED»½ÐÑ
}



void OLED_OFF(void)
{
	WriteCmd(0X8D);  //ÉèÖõçºÉ±Ã
	WriteCmd(0X10);  //¹Ø±ÕµçºÉ±Ã
	WriteCmd(0XAE);  //OLEDÐÝÃß
}



void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
{
	unsigned char c = 0,i = 0,j = 0,k = 0;
	switch(TextSize)
	{
		case 1:
		{
			while(ch[j] != '\0')
			{
				c = ch[j] - 32;
				if(x > 126)
				{
					x = 0;
					y++;
				}
				OLED_SetPos(x,y);
				for(i=0;i<6;i++)
					WriteDat(F6x8[c][i]);
				x += 6;
				j++;
			}
		}break;
		case 2:
		{
			while(ch[j] != '\0')
			{
				c = ch[j] - 32;
				if(x > 120)
				{
					x = 0;
					y++;
				}
				OLED_SetPos(x,y);
				for(i=0;i<8;i++)
					WriteDat(F8X16[c*16+i]);
				OLED_SetPos(x,y+1);
				for(i=0;i<8;i++)
					WriteDat(F8X16[c*16+i+8]);
				x += 8;
				j++;
			}
		}break;
        case 3:
        {
            while(ch[j] != '\0')
            {
                c = ch[j] - 48;
                if(x > 120)
                {
                    x = 0;
                    y++;
                }
                for(k=0;k<4;k++)
                {
                    OLED_SetPos(x,y+k);
                    for(i=0;i<8;i++)
                        WriteDat(F16X32[c*16*4+k*16+i]);
                    OLED_SetPos(x+8,y+k);
                    for(i=0;i<8;i++)
                        WriteDat(F16X32[c*16*4+k*16+8+i]);
                }
                x += 16;
                j++;
        }
        case 4:
        {
            while(ch[j] != '\0')
            {
                c = ch[j];
                if(c >= '0')
                {
                    c -= '0';
                }
                else
                {
                    c = 10;
                }
                if(x > 120)
                {
                    x = 0;
                    y++;
                }
                for(k=0;k<6;k++)
                {
                    OLED_SetPos(x,y+k);
                    for(i=0;i<8;i++)
                        WriteDat(F24X48[c*16*9+k*24+i]);
                    OLED_SetPos(x+8,y+k);
                    for(i=0;i<8;i++)
                        WriteDat(F24X48[c*16*9+k*24+8+i]);
                    OLED_SetPos(x+16,y+k);
                    for(i=0;i<8;i++)
                        WriteDat(F24X48[c*16*9+k*24+16+i]);
                }
                x += 24;
                j++;
            }
        }
      }
	}
}

 
void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
	unsigned char wm=0;
	unsigned int  adder=32*N;
	OLED_SetPos(x , y);
	for(wm = 0;wm < 16;wm++)
	{
		WriteDat(F16x16[adder]);
		adder += 1;
	}
	OLED_SetPos(x,y + 1);
	for(wm = 0;wm < 16;wm++)
	{
		WriteDat(F16x16[adder]);
		adder += 1;
	}
}



void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
{
	unsigned int j=0;
	unsigned char x,y;

  if(y1%8==0)
		y = y1/8;
  else
		y = y1/8 + 1;
	for(y=y0;y<y1;y++)
	{
		OLED_SetPos(x0,y);
    for(x=x0;x<x1;x++)
		{
			WriteDat(BMP[j++]);
		}
	}
}



 uint8_t OLED_Test(void) 
{
  if (OLED_CheckDevice(OLED_ADDRESS) == 1)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}	



 void OLED_ShowTest(void) 
{
    unsigned char i; 
	  if(OLED_Test()==0)
		{          
			i = 1;
		}
		else
		{
			i = 2;
		}
		
//		while(1)
//	{
		OLED_Fill(0xFF);
		delay_s(1);
		
		OLED_Fill(0x00);
		delay_s(1);
		
		for(i=0;i<4;i++)
		{
			OLED_ShowCN(22+i*16,0,i);
		}
		delay_s(1);
		OLED_ShowStr(0,3,(unsigned char*)"Wildfire Tech",1);				
		OLED_ShowStr(0,4,(unsigned char*)"Hello wildfire",2);				
		delay_s(2);
		OLED_CLS();
		OLED_OFF();
		delay_s(1);
		OLED_ON();
		OLED_DrawBMP(0,0,128,8,(unsigned char *)BMP1);
		delay_s(1);
//	}    
}

main.c

#ifndef __STM32F10X_H
#define __STM32F10X_H
#include "stm32f10x.h"
#endif

#ifndef __BSP_BEEP_H
#define __BSP_BEEP_H
#include "bsp_beep.h"
#endif

#ifndef __BSP_LED_H
#define __BSP_LED_H
#include "bsp_led.h"
#endif

#ifndef __BSP_OLED_H
#define __BSP_OLED_H
#include "bsp_oled.h"
#endif


int main()
{
	uint32_t tmp;
	
	init_beep();
	init_led();
	
	i2c_CfgGpio();
	
	func_led2_on();
	func_led3_on();
	func_led4_on();
	
	func_beep_play();
	for (tmp = 0; tmp < 3000000; tmp++);
	func_beep_stop();
	for (tmp = 0; tmp < 3000000; tmp++);
	
	func_tca9548a_select(0);//0~7	
	OLED_Init();					         	
	func_tca9548a_select(1);//0~7	
	OLED_Init();					         	
	func_tca9548a_select(2);//0~7	
	OLED_Init();					         	
	func_tca9548a_select(3);//0~7	
	OLED_Init();					         	
	func_tca9548a_select(4);//0~7	
	OLED_Init();					         	
	func_tca9548a_select(5);//0~7	
	OLED_Init();					         	
	func_tca9548a_select(6);//0~7	
	OLED_Init();					         	
	func_tca9548a_select(7);//0~7	
	OLED_Init();					       	
	
	for(;;)
	{
		func_tca9548a_select(0);
		OLED_ShowTest();
		func_tca9548a_select(1);
		OLED_ShowTest();
		func_tca9548a_select(2);
		OLED_ShowTest();
		func_tca9548a_select(3);
		OLED_ShowTest();
		func_tca9548a_select(4);
		OLED_ShowTest();
		func_tca9548a_select(5);
		OLED_ShowTest();
		func_tca9548a_select(6);
		OLED_ShowTest();
		func_tca9548a_select(7);
		OLED_ShowTest();
	}
	
}

注意,当STM32选择了TCA9548A的8个通道中的某一个后,TCA9548A就会保持这个通道,并透传IIC的消息,就可以直接向操作OLED一样发数据了。那么怎么选择TCA9548A的某一个通道呢?TCA9548A内部只有一个8位寄存器,置高的通道被选中。

最后就是效果了

 

评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值