一、前言
在上一篇中,我們使用軟件模擬IIC對AT24C02進(jìn)行了讀寫,通過查看GD32F30X的參考手冊可以知道,其有2個硬件IIC控制器,現(xiàn)在我們就嘗試使用其硬件IIC進(jìn)行對AT24C02的讀寫。 查看小熊派的原理圖,確定AT24C02其使用的IIC引腳為SCL->PB6、SDA->PB7 查看數(shù)據(jù)手冊可以知道這兩個引腳被I2C0控制器復(fù)用為I2C引腳了,那么就可以滿足我們的使用需求了
二、初始化I2C0控制器
如下所示,將I2C0控制器進(jìn)行初始化
/* 描述:IIC0控制器初始化
* 參數(shù):無
* 返回值:無*/
void i2c0_init(void)
{
/* 使能 GPIOB 時鐘 */
rcu_periph_clock_enable(RCU_GPIOB);
/* 使能 I2C0 時鐘 */
rcu_periph_clock_enable(RCU_I2C0);
/* 初始化 PB6 復(fù)用為 I2C0_SCL, PB7 復(fù)用為 I2C0_SDA */
gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6 | GPIO_PIN_7);
/* 設(shè)置I2C0 為標(biāo)速模式 100 KHz */
i2c_clock_config(I2C0, 100000, I2C_DTCY_2);
/* 設(shè)置為I2C模式,并設(shè)置其為從機(jī)模式下的7位地址 */
i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x78);
/* 使能 I2C0 */
i2c_enable(I2C0);
/* 使能I2C發(fā)送應(yīng)答 */
i2c_ack_config(I2C0, I2C_ACK_ENABLE);
}
三、編寫AT24C02控制函數(shù)
通過查看AT24C02的數(shù)據(jù)手冊可以看到其讀寫時序如下 然后編寫AT24C02的讀取和寫入函數(shù)
#define AT24C02_Addr 0x50 /* AT24C02的7位器件地址 */
/* 描述:AT24C02初始化
* 參數(shù):無
* 返回值:無*/
void at24c02_init(void)
{
i2c0_init();
}
/* 描述:在AT24C02指定地址讀出一個字節(jié)的數(shù)據(jù)
* 參數(shù):ReadAddr: 需要讀出數(shù)據(jù)的地址
* ReadByte: 讀出的數(shù)據(jù)值的存放指針
* 返回值:0:讀取成功 其他:讀取錯誤*/
uint8_t AT24C02_Read_Byte(uint16_t ReadAddr, uint8_t *ReadByte)
{
uint8_t err = 1;
i2c_start_on_bus(I2C0); /* 發(fā)送一個起始位到I2C總線 */
while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)); /* 等待起始位發(fā)送完成 */
i2c_master_addressing(I2C0, AT24C02_Addr<<1, I2C_TRANSMITTER);/* 發(fā)送器件地址,寫數(shù)據(jù) */
while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)); /* 等待從機(jī)地址發(fā)送完成 */
i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); /* 清除從機(jī)地址發(fā)送完成標(biāo)志位 */
while(!i2c_flag_get(I2C0, I2C_FLAG_TBE)); /* 等待IIC發(fā)送區(qū)為空 */
i2c_data_transmit(I2C0, ReadAddr); /* IIC發(fā)送數(shù)據(jù),AT24C02需要讀出數(shù)據(jù)的地址*/
while(!i2c_flag_get(I2C0, I2C_FLAG_TBE)); /* 等待IIC發(fā)送區(qū)為空,即發(fā)送完成 */
i2c_start_on_bus(I2C0); /* 再次發(fā)送一個起始位到I2C總線 */
while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)); /* 等待起始位發(fā)送完成 */
i2c_master_addressing(I2C0, AT24C02_Addr<<1, I2C_RECEIVER); /* 發(fā)送器件地址,讀數(shù)據(jù) */
while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)); /* 等待從機(jī)地址發(fā)送完成 */
i2c_ack_config(I2C0, I2C_ACK_DISABLE); /* 設(shè)置為非應(yīng)答 NACK, 要在清除FLAG_ADDSEND前*/
i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); /* 清除從機(jī)地址發(fā)送完成標(biāo)志位 */
i2c_stop_on_bus(I2C0); /* 發(fā)送一個停止位到I2C總線 */
while(!i2c_flag_get(I2C0, I2C_FLAG_RBNE)); /* 等待數(shù)據(jù)寄存器可讀 */
*ReadByte = i2c_data_receive(I2C0); /* 讀出接收到的數(shù)據(jù) */
i2c_ack_config(I2C0, I2C_ACK_ENABLE); /* 使能應(yīng)答 ACK, */
err = 0;
return err;
}
/* 描述:在AT24C02指定地址寫入一個字節(jié)的數(shù)據(jù)
* 參數(shù):WriteAddr: 需要寫入數(shù)據(jù)的地址
* WriteByte: 要寫入的數(shù)據(jù)
* 返回值:0:寫入成功 其他:寫入錯誤*/
uint8_t AT24C02_Write_Byte(uint16_t WriteAddr,uint16_t WriteByte)
{
uint8_t err = 0;
i2c_start_on_bus(I2C0); /* 發(fā)送一個起始位到I2C總線 */
while(!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)); /* 等待起始位發(fā)送完成 */
i2c_master_addressing(I2C0, AT24C02_Addr<<1, I2C_TRANSMITTER);/* 發(fā)送器件地址,寫數(shù)據(jù) */
while(!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)); /* 等待從機(jī)地址發(fā)送完成 */
i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); /* 清除從機(jī)地址發(fā)送完成標(biāo)志位 */
while(!i2c_flag_get(I2C0, I2C_FLAG_TBE)); /* 等待IIC發(fā)送區(qū)為空 */
i2c_data_transmit(I2C0, WriteAddr); /* IIC發(fā)送數(shù)據(jù),AT24C02要寫入數(shù)據(jù)的地址*/
while(!i2c_flag_get(I2C0, I2C_FLAG_TBE)); /* 等待IIC發(fā)送區(qū)為空,即發(fā)送完成 */
i2c_data_transmit(I2C0, WriteByte); /* IIC發(fā)送數(shù)據(jù),AT24C02要寫入的數(shù)據(jù)*/
while(!i2c_flag_get(I2C0, I2C_FLAG_TBE)); /* 等待IIC發(fā)送區(qū)為空,即發(fā)送完成 */
i2c_stop_on_bus(I2C0); /* 發(fā)送一個停止位到I2C總線 */
return err;
}
四、編寫主函數(shù)
int main(void)
{
uint8_t buff;
uint8_t err;
/* 配置系統(tǒng)時鐘 */
systick_config();
/* 初始化LED */
// led_init();
/* 初始化USART0 */
uart0_init(115200);
/* 初始化AT24C02 */
at24c02_init();
/* 通過串口打印 Hello world! */
u0_printf("Hello world! ");
u0_printf("I am William. \r\n");
err = AT24C02_Write_Byte(0x0a, 0xa5);
if(err == 0)
printf("Write 0xa5 to addr 0x0a ok \r\n");
else
{
printf("Write 0xa5 to addr 0x0a err \r\n");
printf("err num : 0x%x \r\n",err);
}
if(AT24C02_Read_Byte(0x0a, &buff) == 0)
printf("Read data: 0x%x from addr 0x0a ok \r\n", buff);
else
printf("Read data from addr 0x0a err \r\n");
while(1)
{
if(UART0_RX_STAT > 0)
{
UART0_RX_STAT = 0;
u0_printf("RECEIVE %d data:%s \r\n", UART0_RX_NUM, UART0_RX_BUF);
}
delay_1ms(10);
}
}
五、功能驗證
編譯鏈接燒錄到小熊派開發(fā)板,然后觀察串口輸出情況,可以看到讀取和寫入都成功了
六、附錄
|