RVMCU課堂「14」: 手把手教你玩轉(zhuǎn)RVSTAR—I2C總線(xiàn)通信篇
系統(tǒng)環(huán)境
軟件平臺(tái)
硬件需求
I2C是由NXP(原PHILIPS)公司開(kāi)發(fā)的兩線(xiàn)式串行總線(xiàn),用于連接微控制器及其外圍芯片,目前已成為一種行業(yè)標(biāo)準(zhǔn),在微控制器設(shè)計(jì)中被大量采用,在RV-STAR所使用的GD32VF103微控制器上也集成了I2C接口。
I2C在應(yīng)用時(shí),在發(fā)送了起始信號(hào)(Start)后,要先發(fā)送一個(gè)7位的從機(jī)地址,緊跟著的第8位是數(shù)據(jù)方向位(R/W),“0”表示接下來(lái)要發(fā)送數(shù)據(jù),“1”表示接下來(lái)要讀數(shù)據(jù)。當(dāng)發(fā)送完這個(gè)8個(gè)位后,如果發(fā)送的地址有設(shè)備存在,這個(gè)設(shè)備應(yīng)該回復(fù)一個(gè)ACK(拉低SDA,輸出“0”),這樣才會(huì)繼續(xù)進(jìn)行通信流程。
OLED液晶屏介紹
OLED(Organic Light-Emitting Diode,有機(jī)發(fā)光二極管)因?yàn)榫邆漭p薄、省電、顯示效果好等特性,被廣泛應(yīng)用手機(jī)、音樂(lè)播放器等電子設(shè)備中。
尺寸 | 0.96英寸 |
分辨率 | 128*64 |
可視角度 | 大于160° |
功耗 | 0.06w |
供電范圍 | 3.3v~5v |
工作溫度 | -30℃~70℃ |
體積 | 27mm*27mm*2mm |
亮度 | 可通過(guò)指令控制 |
驅(qū)動(dòng)芯片 | SSD1306 |
接口 | I2C |
GD32VF103的I2C接口
GD32VF103的I2C(內(nèi)部集成電路總線(xiàn))模塊提供了符合工業(yè)標(biāo)準(zhǔn)的兩線(xiàn)串行制接口,可用于MCU和外部I2C設(shè)備的通訊。I2C總線(xiàn)使用兩條串行線(xiàn):串行數(shù)據(jù)線(xiàn)SDA和串行時(shí)鐘線(xiàn)SCL。I2C接口模塊實(shí)現(xiàn)了I2C協(xié)議的標(biāo)速模式(最高100KHz)和快速模式(最高400KHz),具備CRC計(jì)算和校驗(yàn)功能,支持SMBus(系統(tǒng)管理總線(xiàn))和 PMBus(電源管理總線(xiàn))。此外還支持多主機(jī)I2C總線(xiàn)架構(gòu)。I2C接口模塊也支持DMA模式,可有效減輕CPU的負(fù)擔(dān)。
實(shí)驗(yàn)部分
首先需要將RV-STAR開(kāi)發(fā)板及OLED顯示屏參照下圖使用杜邦線(xiàn)進(jìn)行連線(xiàn):
void I2C_Configuration(void)
{
uint32_t GPIO_SDA, GPIO_SCL;
uint32_t GPIO_PIN_SDA, GPIO_PIN_SCL;
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_I2C1);
GPIO_SDA = GPIOB;
GPIO_PIN_SDA = GPIO_PIN_11;
GPIO_SCL = GPIOB;
GPIO_PIN_SCL = GPIO_PIN_10;
gpio_init(GPIO_SCL, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_SCL);
gpio_init(GPIO_SDA, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_SDA);
i2c_clock_config(I2C1, 400000, I2C_DTCY_2);
i2c_mode_addr_config(I2C1, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x30);
i2c_enable(I2C1);
i2c_ack_config(I2C1, I2C_ACK_ENABLE);
}
void I2C_WriteByte(uint8_t addr, uint8_t data)
{
/* wait until I2C bus is idle */
while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
/* send a start condition to I2C bus */
i2c_start_on_bus(I2C1);
/* wait until SBSEND bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
/* send slave address to I2C bus*/
i2c_master_addressing(I2C1, 0x78, I2C_TRANSMITTER);
/* wait until ADDSEND bit is set*/
while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
/* clear ADDSEND bit */
i2c_flag_clear(I2C1, I2C_FLAG_ADDSEND);
/* send a addr byte */
i2c_data_transmit(I2C1, addr);
/* wait until the transmission data register is empty*/
while(!i2c_flag_get(I2C1, I2C_FLAG_TBE));
/* send a data byte */
i2c_data_transmit(I2C1, data);
/* wait until the transmission data register is empty*/
while(!i2c_flag_get(I2C1, I2C_FLAG_TBE));
/* send a stop condition to I2C bus*/
i2c_stop_on_bus(I2C1);
/* wait until stop condition generate */
while(I2C_CTL0(I2C1)