行业知识
stm32——hal库学习笔记(IIC)
2026-11-02 09:38:48
来源:互联网转载
一、IIC总线协议介绍(掌握)
二、AT24C02介绍(了解)
三、AT24C02读写时序(掌握)
四、AT24C02驱动步骤(掌握)
五、编程实战(掌握)
myiic.c
#include "./BSP/IIC/myiic.h"#include "./SYSTEM/delay/delay.h"/** * @brief 初始化IIC * @param 无 * @retval 无 */void iic_init(void){ GPIO_InitTypeDef gpio_init_struct; IIC_SCL_GPIO_CLK_ENABLE(); /* SCL引脚时钟使能 */ IIC_SDA_GPIO_CLK_ENABLE(); /* SDA引脚时钟使能 */ gpio_init_struct.Pin = IIC_SCL_GPIO_PIN; gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */ gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */ gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */ HAL_GPIO_Init(IIC_SCL_GPIO_PORT, &gpio_init_struct);/* SCL */ gpio_init_struct.Pin = IIC_SDA_GPIO_PIN; gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD; /* 开漏输出 */ HAL_GPIO_Init(IIC_SDA_GPIO_PORT, &gpio_init_struct);/* SDA */ /* SDA引脚模式设置,开漏输出,上拉, 这样就不用再设置IO方向了, 开漏输出的时候(=1), 也可以读取外部信号的高低电平 */ iic_stop(); /* 停止总线上所有设备 */}/** * @brief IIC延时函数,用于控制IIC读写速度 * @param 无 * @retval 无 */static void iic_delay(void){ delay_us(2); /* 2us的延时, 读写速度在250Khz以内 */}/** * @brief 产生IIC起始信号 * @param 无 * @retval 无 */void iic_start(void){ IIC_SDA(1); IIC_SCL(1); iic_delay(); IIC_SDA(0); /* START信号: 当SCL为高时, SDA从高变成低, 表示起始信号 */ iic_delay(); IIC_SCL(0); /* 钳住I2C总线,准备发送或接收数据 */ iic_delay();}/** * @brief 产生IIC停止信号 * @param 无 * @retval 无 */void iic_stop(void){ IIC_SDA(0); /* STOP信号: 当SCL为高时, SDA从低变成高, 表示停止信号 */ iic_delay(); IIC_SCL(1); iic_delay(); IIC_SDA(1); /* 发送I2C总线结束信号 */ iic_delay();}/** * @brief 等待应答信号到来 * @param 无 * @retval 1,接收应答失败 * 0,接收应答成功 */uint8_t iic_wait_ack(void){ uint8_t waittime = 0; uint8_t rack = 0; IIC_SDA(1); /* 主机释放SDA线(此时外部器件可以拉低SDA线) */ iic_delay(); IIC_SCL(1); /* SCL=1, 此时从机可以返回ACK */ iic_delay(); while (IIC_READ_SDA) /* 等待应答 */ { waittime++; if (waittime > 250) { iic_stop(); rack = 1; break; } } IIC_SCL(0); /* SCL=0, 结束ACK检查 */ iic_delay(); return rack;}/** * @brief 产生ACK应答 * @param 无 * @retval 无 */void iic_ack(void){ IIC_SDA(0); /* SCL 0 -> 1 时 SDA = 0,表示应答 */ iic_delay(); IIC_SCL(1); /* 产生一个时钟 */ iic_delay(); IIC_SCL(0); iic_delay(); IIC_SDA(1); /* 主机释放SDA线 */ iic_delay();}/** * @brief 不产生ACK应答 * @param 无 * @retval 无 */void iic_nack(void){ IIC_SDA(1); /* SCL 0 -> 1 时 SDA = 1,表示不应答 */ iic_delay(); IIC_SCL(1); /* 产生一个时钟 */ iic_delay(); IIC_SCL(0); iic_delay();}/** * @brief IIC发送一个字节 * @param data: 要发送的数据 * @retval 无 */void iic_send_byte(uint8_t data){ uint8_t t; for (t = 0; t > 7); /* 高位先发送 */ iic_delay(); IIC_SCL(1); iic_delay(); IIC_SCL(0); data uint8_t i, receive = 0; for (i = 0; i 8) /* 原理说明见:at24cxx_read_one_byte函数, 本函数完全类似 */ iic_start(); /* 发送起始信号 */ if (EE_TYPE AT24C16) /* 24C16以上的型号, 分2个字节发送地址 */ { iic_send_byte(0XA0); /* 发送写命令, IIC规定最低位是0, 表示写入 */ iic_wait_ack(); /* 每次发送完一个字节,都要等待ACK */ iic_send_byte(addr >> 8);/* 发送高字节地址 */ } else { iic_send_byte(0XA0 + ((addr >> 8) uint8_t temp; uint16_t addr = EE_TYPE; temp = at24cxx_read_one_byte(addr); /* 避免每次开机都写AT24CXX */ if (temp == 0X55) /* 读取数据正常 */ { return 0; } else /* 排除第一次初始化的情况 */ { at24cxx_write_one_byte(addr, 0X55); /* 先写入数据 */ temp = at24cxx_read_one_byte(255); /* 再读取数据 */ if (temp == 0X55)return 0; } return 1;}/** * @brief 在AT24CXX里面的指定地址开始读出指定个数的数据 * @param addr : 开始读出的地址 对24c02为0~255 * @param pbuf : 数据数组首地址 * @param datalen : 要读出数据的个数 * @retval 无 */void at24cxx_read(uint16_t addr, uint8_t *pbuf, uint16_t datalen){ while (datalen--) { *pbuf++ = at24cxx_read_one_byte(addr++); }}/** * @brief 在AT24CXX里面的指定地址开始写入指定个数的数据 * @param addr : 开始写入的地址 对24c02为0~255 * @param pbuf : 数据数组首地址 * @param datalen : 要写入数据的个数 * @retval 无 */void at24cxx_write(uint16_t addr, uint8_t *pbuf, uint16_t datalen){ while (datalen--) { at24cxx_write_one_byte(addr, *pbuf); addr++; pbuf++; }}"STM32 IIC TEST"};#define TEXT_SIZE sizeof(g_text_buf) /* TEXT字符串长度 */int main(void){ uint8_t key; uint16_t i = 0; uint8_t datatemp[TEXT_SIZE]; HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */ delay_init(72); /* 延时初始化 */ usart_init(115200); /* 串口初始化为115200 */ usmart_dev.init(72); /* 初始化USMART */ led_init(); /* 初始化LED */ lcd_init(); /* 初始化LCD */ key_init(); /* 初始化按键 */ at24cxx_init(); /* 初始化24CXX */ lcd_show_string(30, 50, 200, 16, 16, "STM32", RED); lcd_show_string(30, 70, 200, 16, 16, "IIC TEST", RED); lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED); lcd_show_string(30, 110, 200, 16, 16, "KEY1:Write KEY0:Read", RED); /* 显示提示信息 */ while (at24cxx_check()) /* 检测不到24c02 */ { lcd_show_string(30, 130, 200, 16, 16, "24C02 Check Failed!", RED); delay_ms(500); lcd_show_string(30, 130, 200, 16, 16, "Please Check! ", RED); delay_ms(500); LED0_TOGGLE(); /* 红灯闪烁 */ } lcd_show_string(30, 130, 200, 16, 16, "24C02 Ready!", RED); while (1) { key = key_scan(0); if (key == KEY1_PRES) /* KEY1按下,写入24C02 */ { lcd_fill(0, 150, 239, 319, WHITE); /* 清除半屏 */ lcd_show_string(30, 150, 200, 16, 16, "Start Write 24C02....", BLUE); at24cxx_write(0, (uint8_t *)g_text_buf, TEXT_SIZE); lcd_show_string(30, 150, 200, 16, 16, "24C02 Write Finished!", BLUE); /* 提示传送完成 */ } if (key == KEY0_PRES) /* KEY0按下,读取字符串并显示 */ { lcd_show_string(30, 150, 200, 16, 16, "Start Read 24C02.... ", BLUE); at24cxx_read(0, datatemp, TEXT_SIZE); lcd_show_string(30, 150, 200, 16, 16, "The Data Readed Is: ", BLUE); /* 提示传送完成 */ lcd_show_string(30, 170, 200, 16, 16, (char *)datatemp, BLUE); /* 显示读到的字符串 */ } i++; if (i == 20) { LED0_TOGGLE(); /* 红灯闪烁 */ i = 0; } delay_ms(10); }}