STM32 HAL库F103系列之IIC实验
创作时间:
作者:
@小白创作中心
STM32 HAL库F103系列之IIC实验
引用
CSDN
1.
https://blog.csdn.net/2302_79878697/article/details/138253223
本文详细介绍了如何使用STM32 HAL库实现IIC通信,并通过AT24C02 EEPROM存储器的读写实验进行验证。文章从IIC总线协议的基础知识开始,逐步讲解了AT24C02的使用方法和具体的代码实现,适合有一定基础的开发者学习参考。
IIC总线协议
IIC总线协议介绍
IIC(Inter Integrated Circuit)是一种同步串行半双工通信总线。其主要特点如下:
- 总线结构:由时钟线SCL和数据线SDA组成,都接有上拉电阻,确保总线空闲状态为高电平。
- 多设备支持:支持多设备连接,允许多主机存在,每个设备都有一个唯一的地址。
- 电容限制:连接到总线上的设备数量受总线的最大电容400pf限制。
- 传输速率:支持三种传输速率:标准模式100k bit/s、快速模式400k bit/s、高速模式3.4Mbit/s。
IIC基本信号实现
起始信号
void iic_start(void)
{
IIC_SDA(1);
IIC_SCL(1);
iic_delay();
IIC_SDA(0);
iic_delay();
IIC_SCL(0);
iic_delay();
}
停止信号
void iic_stop(void)
{
IIC_SDA(0);
iic_delay();
IIC_SCL(1);
iic_delay();
IIC_SDA(1);
iic_delay();
}
检测应答信号
uint8_t iic_wait_ack(void)
{
IIC_SDA(1);
iic_delay();
IIC_SCL(1);
iic_delay();
if (IIC_READ_SDA)
{
iic_stop();
return 1;
}
IIC_SCL(0);
iic_delay();
return 0;
}
发送应答信号
void iic_ack(void)
{
IIC_SCL(0);
iic_delay();
IIC_SDA(0);
iic_delay();
IIC_SCL(1);
iic_delay();
}
发送非应答信号
void iic_nack(void)
{
IIC_SCL(0);
iic_delay();
IIC_SDA(1);
iic_delay();
IIC_SCL(1);
iic_delay();
}
发送1字节数据
void iic_send_byte(uint8_t data)
{
for (uint8_t t = 0; t < 8; t++)
{
IIC_SDA((data & 0x80) >> 7);
iic_delay();
IIC_SCL(1);
iic_delay();
IIC_SCL(0);
data <<= 1;
}
IIC_SDA(1);
}
读取1字节数据
uint8_t iic_read_byte(uint8_t ack)
{
uint8_t receive = 0;
for (uint8_t t = 0; t < 8; t++)
{
receive <<= 1;
IIC_SCL(1);
iic_delay();
if (IIC_READ_SDA)
receive++;
IIC_SCL(0);
iic_delay();
}
if (!ack)
iic_nack();
else
iic_ack();
return receive;
}
IIC配置步骤
- 使能SCL和SDA对应时钟:
__HAL_RCC_GPIOB_CLK_ENABLE() - 设置GPIO工作模式:SDA开漏/SCL推挽输出模式,使用
HAL_GPIO_Init初始化 - 编写基本信号:起始信号、停止信号、应答信号
- 编写读和写函数:
iic_read_byte、iic_send_byte
开漏输出模式的必要性
开漏输出模式的特点是不能输出高电平,必须有外部(或内部)上拉才能输出高电平。这种模式非常适合IIC总线的SDA线,因为:
- 输出时:主机(MCU)输出0可以拉低信号,实现低电平发送;输出1(实际不起作用)由外部上拉电阻上拉,实现高电平发送。
- 输入时:主机(MCU)设置输出1状态,相当于释放SDA脚,外部器件可以主动控制SDA脚的高低电平。
- MCU可以通过读取IDR状态寄存器来检测SDA脚的高低电平状态。
AT24C02 EEPROM存储器
原理图
EEPROM是一种掉电后数据不丢失的存储器,常用于存储配置信息。AT24C02是一个2K bit的EEPROM存储器,使用IIC通信方式。其写操作地址为0xA0,读操作地址为0xA1。
AT24C02读写时序
AT24C02配置步骤
- 初始化IIC接口
- 编写写入/读取一个字节数据函数,遵循读写时序流程编写
- 编写连续读和连续写函数,在2的基础上进行实现
实验:驱动AT24C02实现读和写1字节数据
myiic.c
#include "./BSP/IIC/myiic.h"
#include "./SYSTEM/delay/delay.h"
void iic_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
IIC_SCL_GPIO_CLK_ENABLE();
IIC_SDA_GPIO_CLK_ENABLE();
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);
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);
}
static void iic_delay(void)
{
delay_us(2);
}
void iic_start(void)
{
IIC_SDA(1);
IIC_SCL(1);
iic_delay();
IIC_SDA(0);
iic_delay();
IIC_SCL(0);
iic_delay();
}
void iic_stop(void)
{
IIC_SDA(0);
iic_delay();
IIC_SCL(1);
iic_delay();
IIC_SDA(1);
iic_delay();
}
uint8_t iic_wait_ack(void)
{
IIC_SDA(1);
iic_delay();
IIC_SCL(1);
iic_delay();
if (IIC_READ_SDA)
{
iic_stop();
return 1;
}
IIC_SCL(0);
iic_delay();
return 0;
}
void iic_ack(void)
{
IIC_SCL(0);
iic_delay();
IIC_SDA(0);
iic_delay();
IIC_SCL(1);
iic_delay();
}
void iic_nack(void)
{
IIC_SCL(0);
iic_delay();
IIC_SDA(1);
iic_delay();
IIC_SCL(1);
iic_delay();
}
void iic_send_byte(uint8_t data)
{
for (uint8_t t = 0; t < 8; t++)
{
IIC_SDA((data & 0x80) >> 7);
iic_delay();
IIC_SCL(1);
iic_delay();
IIC_SCL(0);
data <<= 1;
}
IIC_SDA(1);
}
uint8_t iic_read_byte(uint8_t ack)
{
uint8_t receive = 0;
for (uint8_t t = 0; t < 8; t++)
{
receive <<= 1;
IIC_SCL(1);
iic_delay();
if (IIC_READ_SDA)
receive++;
IIC_SCL(0);
iic_delay();
}
if (!ack)
iic_nack();
else
iic_ack();
return receive;
}
myiic.h
#ifndef __MYIIC_H
#define __MYIIC_H
#include "./SYSTEM/sys/sys.h"
#define IIC_SCL_GPIO_PORT GPIOB
#define IIC_SCL_GPIO_PIN GPIO_PIN_6
#define IIC_SCL_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)
#define IIC_SDA_GPIO_PORT GPIOB
#define IIC_SDA_GPIO_PIN GPIO_PIN_7
#define IIC_SDA_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)
#define IIC_SCL(x) do{ x ? HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_SET) : HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_RESET); }while(0)
#define IIC_SDA(x) do{ x ? HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_SET) : HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_RESET); }while(0)
#define IIC_READ_SDA HAL_GPIO_ReadPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN)
void iic_init(void);
void iic_start(void);
void iic_stop(void);
uint8_t iic_wait_ack(void);
void iic_ack(void);
void iic_nack(void);
void iic_send_byte(uint8_t data);
uint8_t iic_read_byte(uint8_t ack);
#endif
24cxx.c
#include "./BSP/IIC/myiic.h"
#include "./BSP/24CXX/24cxx.h"
#include "./SYSTEM/delay/delay.h"
void at24c02_init(void)
{
iic_init();
}
void at24c02_write_one_byte(uint8_t addr, uint8_t data)
{
iic_start();
iic_send_byte(0xA0);
iic_wait_ack();
iic_send_byte(addr);
iic_wait_ack();
iic_send_byte(data);
iic_wait_ack();
iic_stop();
delay_ms(10);
}
uint8_t at24c02_read_one_byte(uint8_t addr)
{
uint8_t rec = 0;
iic_start();
iic_send_byte(0xA0);
iic_wait_ack();
iic_send_byte(addr);
iic_wait_ack();
iic_start();
iic_send_byte(0xA1);
iic_wait_ack();
rec = iic_read_byte(0);
iic_stop();
return rec;
}
24cxx.h
#ifndef __24CXX_H
#define __24CXX_H
#include "./SYSTEM/sys/sys.h"
void at24c02_init(void);
void at24c02_write_one_byte(uint8_t addr, uint8_t data);
uint8_t at24c02_read_one_byte(uint8_t addr);
#endif
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./USMART/usmart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/24CXX/24cxx.h"
int main(void)
{
uint8_t key;
uint8_t i = 0;
uint8_t data = 0;
HAL_Init();
sys_stm32_clock_init(RCC_PLL_MUL9);
delay_init(72);
usart_init(115200);
led_init();
key_init();
at24c02_init();
while (1)
{
key = key_scan(0);
if (key == KEY1_PRES)
{
at24c02_write_one_byte(100, 66);
printf("write data \r\n");
}
if (key == KEY0_PRES)
{
data = at24c02_read_one_byte(100);
printf("read data:%d \r\n", data);
}
i++;
if (i % 20 == 0)
{
LED0_TOGGLE();
i = 0;
}
delay_ms(10);
}
}
热门推荐
官司胜了律师费由谁付
八字命理与中医的关系:理论基础与实践应用
基于AI的健康管理系统:从数据收集到未来展望
《陋室铭》作者争议与流传故事考辨
企业最新战略汇总| 2025,欧派、尚品宅配、志邦、金牌、顾家、玛格怎么干?
科普:羽毛球拍线断后,该如何剪才是正确的?
羽毛球拍断线后如何正确剪线?这份专业指南请收好
塔罗牌怎么测自己的正缘?如何用塔罗牌找到自己的正缘?
八字水多如何取名?五行平衡与吉祥寓意兼备
凡人:韩立境界年龄:217岁凝结元婴,1007岁偷渡灵界跌落成凡人
反问句的句式有哪些?反问句的句式大揭秘:那些你不知道的表达方式!
SCI论文翻译指南:从专业术语到文化差异的全方位解析
有效提问的六种方式
春节临近!谨记:酒后禁驾!
如何设计出令人印象深刻的游戏角色?这些技巧绝对会帮到你
加强股票投资风险控制的方法
且将绣裙易战袍:魏晋南北朝时期的女将女兵
如何在股市中寻找买入机会?这些机会的风险和收益如何平衡?
男性刮胡子频率与寿命无关,但这两个时间点切记别刮胡子
白沙绿茶的口感怎么样?
三极管发射结正偏-集电结反偏理解和分析
紫皮洋葱的功效与作用及禁忌
教你打造适宜的睡眠环境,助你提升睡眠质量!
浮游植物生态与应用探究(探寻海洋中的微观世界——浮游植物)
上海赏秋攻略:梧桐、银杏、枫叶、桂花的最佳观赏地点
电热水器防电技术和安装使用中的四道防漏电安全须知
太危险!泉州一宝妈酒驾当街被查!车上还有孩子……
揭秘打工人梗,网络热词背后的社会现象与思考
股票的涨跌如何进行客观预测?这种预测的依据有哪些?
粤闽浙琼四省第一大姓,全国人口5000万,老家在河南