STM32F1 TCA9548A 驱动多个IIC器件
TCA9548A的用途就是IIC擴展,每個TCA9548A可以擴展出8路IIC。TCA9548A芯片帶有地址選擇引腳A0/A1/A2,根據(jù)高低電平不同,從MCU的一路IIC最多可以接入8個TCA9548A芯片,從而可以達到擴展出8*8=64路IIC的效果。
在什么情況下會使用到TCA9548A芯片來擴展?當一個MCU想要驅(qū)動多個器件地址相同的芯片時,如驅(qū)動8個OLED時,OLED的IIC器件地址為0x78,要用MCU引出8路IIC的硬件線路?顯然得不償失,這時候用TCA9548A就再合適不過了。
下面是我使用STM32F1通過一個TCA9548A驅(qū)動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" #endifvoid 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?y?ˉSDA = 1 */i2c_Delay();OLED_I2C_SCL_1(); /* CPU2úéú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(); /* ·¢?í???ˉD?o? */i2c_SendByte(_Address|OLED_I2C_WR);/* ·¢?íéè±?μ??· */ucAck = i2c_WaitAck(); /* ?ì2aéè±?μ?ACKó|′e */i2c_Stop(); /* ·¢?íí£?1D?o? */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)//D′?üá? {I2C_WriteByte(0x00, I2C_Command); }void WriteDat(unsigned char I2C_Data)//D′êy?Y {I2C_WriteByte(0x40, I2C_Data); }void OLED_Init(void) {delay_ms(10);WriteCmd(0xAE); //display offWriteCmd(0x20); //Set Memory Addressing Mode WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,InvalidWriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7WriteCmd(0xc8); //Set COM Output Scan DirectionWriteCmd(0x00); //---set low column addressWriteCmd(0x10); //---set high column addressWriteCmd(0x40); //--set start line addressWriteCmd(0x81); //--set contrast control registerWriteCmd(0xff); //áá?èμ÷?ú 0x00~0xffWriteCmd(0xa1); //--set segment re-map 0 to 127WriteCmd(0xa6); //--set normal displayWriteCmd(0xa8); //--set multiplex ratio(1 to 64)WriteCmd(0x3F); //WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM contentWriteCmd(0xd3); //-set display offsetWriteCmd(0x00); //-not offsetWriteCmd(0xd5); //--set display clock divide ratio/oscillator frequencyWriteCmd(0xf0); //--set divide ratioWriteCmd(0xd9); //--set pre-charge periodWriteCmd(0x22); //WriteCmd(0xda); //--set com pins hardware configurationWriteCmd(0x12);WriteCmd(0xdb); //--set vcomhWriteCmd(0x20); //0x20,0.77xVccWriteCmd(0x8d); //--set DC-DC enableWriteCmd(0x14); //WriteCmd(0xaf); //--turn on oled panelOLED_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)//è??áì?3? {unsigned char m,n;for(m=0;m<8;m++){WriteCmd(0xb0+m); //page0-page1WriteCmd(0x00); //low column start addressWriteCmd(0x10); //high column start addressfor(n=0;n<130;n++){WriteDat(fill_Data);}} }void OLED_CLS(void)//???á {OLED_Fill(0x00); }void OLED_ON(void) {WriteCmd(0X8D); //éè??μ?oé±?WriteCmd(0X14); //?a??μ?oé±?WriteCmd(0XAF); //OLED??D? }void OLED_OFF(void) {WriteCmd(0X8D); //éè??μ?oé±?WriteCmd(0X10); //1?±?μ?oé±?WriteCmd(0XAE); //OLEDDY?? }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;elsey = 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" #endifint 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一樣發(fā)數(shù)據(jù)了。那么怎么選擇TCA9548A的某一個通道呢?TCA9548A內(nèi)部只有一個8位寄存器,置高的通道被選中。
最后就是效果了
?
總結
以上是生活随笔為你收集整理的STM32F1 TCA9548A 驱动多个IIC器件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: flask 下载文件
- 下一篇: 基于ros打开realsense摄像头