本文介绍了在STM32下的IIC的基本使用方法,通过对板载具备IIC接口EEPROM的读写,完成对IIC驱动程序的测试。
硬件平台:STM32F107VCT6开发板
软件平台:STM32Cube MX + MDK5.22
1. 进行STM32Cube MX的配置
配置PB6和PB7为输出模式,同时配置了USART1进行串口调试使用。然后生成工程。
2. 打开工程,可以看到GPIO的初始化状态
3. 模拟IIC驱动程序源文件代码
/**
* @file iic_dup.c
* @brief IIC上层程序
* @par date version author remarks
* 2016-03-21 v1.0 zbt 初次创建
*
*/
/** 头文件包含区 ------------------------------------------------ */
#include "iic_dup.h"
/** 私有宏(类型定义) -------------------------------------------- */
#define IIC1_SCL(pin_status) HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, pin_status);
#define IIC1_SDA(pin_status) HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, pin_status);
#define IIC1_SCL_IS_HIGH() (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) != GPIO_PIN_RESET)
#define IIC1_SDA_IS_HIGH() (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) != GPIO_PIN_RESET)
/** 私有变量 --------------------------------------------------- */
/** 外部变量 --------------------------------------------------- */
/** 私有函数原型 ----------------------------------------------- */
static void iic_delay(void);
/** 公有函数 --------------------------------------------------- */
/**
* @brief IIC启动
* @param None
* @retval None
* @note 当SCL处于高电平状态时,SDA出现一个下降沿
即产生IIC启动信号
*/
void iic_start(void)
{
IIC1_SCL(GPIO_PIN_SET);
/** SDA产生一个下降沿 */
IIC1_SDA(GPIO_PIN_SET);
iic_delay();
IIC1_SDA(GPIO_PIN_RESET);
iic_delay();
IIC1_SCL(GPIO_PIN_RESET); /**< 拉低准备发送数据 */
iic_delay();
}
/**
* @brief IIC停止
* @param None
* @retval None
* @note 当SCL处于高电平状态时,SDA出现一个上升沿
即产生IIC停止信号
*/
void iic_stop(void)
{
IIC1_SCL(GPIO_PIN_RESET);
iic_delay();
/** SDA产生一个上升沿 */
IIC1_SDA(GPIO_PIN_RESET);
iic_delay();
IIC1_SCL(GPIO_PIN_SET);
iic_delay();
IIC1_SDA(GPIO_PIN_SET);
iic_delay();
}
/**
* @brief IIC发送1byte数据
* @param None
* @retval None
* @note
*/
void iic_sendbyte(uint8_t byte)
{
uint8_t i;
/** 发送一个字节的高7位 */
for (i = 0; i < 8; i++)
{
if (byte & 0x80)
{
IIC1_SDA(GPIO_PIN_SET);
}
else
{
IIC1_SDA(GPIO_PIN_RESET);
}
iic_delay();
IIC1_SCL(GPIO_PIN_SET);
iic_delay();
IIC1_SCL(GPIO_PIN_RESET);
if (i == 7)
{
IIC1_SDA(GPIO_PIN_SET);
}
byte <<= 1;
iic_delay();
}
}
/**
* @brief IIC读取1byte数据
* @param None
* @retval None
* @note
*/
uint8_t iic_readbyte(void)
{
uint8_t i;
uint8_t recv_value = 0;
IIC1_SDA(GPIO_PIN_SET);
iic_delay();
for (i = 0; i < 8; i++)
{
IIC1_SCL(GPIO_PIN_SET);
iic_delay();
recv_value <<= 1;
if (IIC1_SDA_IS_HIGH())
{
recv_value |= 0x01;
}
else
{
recv_value &= ~0x01;
}
iic_delay();
IIC1_SCL(GPIO_PIN_RESET);
}
return recv_value;
}
/**
* @brief IIC等待应答信号
* @param None
* @retval ack_status: 应答状态,0表示应答,1表示设备无响应
*/
uint8_t iic_wait_ack(void)
{
uint8_t ack_status = 0;
/** 在等待应答信号之前,要释放总线,即将SDA置位 */
IIC1_SDA(GPIO_PIN_SET);
iic_delay();
IIC1_SCL(GPIO_PIN_SET);
iic_delay();
if (IIC1_SDA_IS_HIGH())
{
ack_status = 1;
iic_stop();
}
else
{
ack_status = 0;
}
IIC1_SCL(GPIO_PIN_RESET);
iic_delay();
return ack_status;
}
/**
* @brief 主机(主控制器)产生应答信号
* @param None
* @retval None
*/
void iic_ack(void)
{
IIC1_SDA(GPIO_PIN_RESET);
iic_delay();
IIC1_SCL(GPIO_PIN_SET);
iic_delay();
IIC1_SCL(GPIO_PIN_RESET);
iic_delay();
IIC1_SDA(GPIO_PIN_SET);
}
/**
* @brief 主机(主控制器)产生不应答信号
* @param None
* @retval None
*/
void iic_nack(void)
{
IIC1_SDA(GPIO_PIN_SET);
iic_delay();
IIC1_SCL(GPIO_PIN_SET);
iic_delay();
IIC1_SCL(GPIO_PIN_RESET);
iic_delay();
}
/**
* @brief 检测IIC总线上的设备状态
* @param device_addr: 从机设备地址
* @retval ack_status: 0 (正常)or 1(异常)
* @note 主机发送设备地址等待从机应答,若有从机正确的应答信号
则表明IIC总线上挂接了设备,否则表示IIC总线上未检测到
设备
*/
uint8_t iic_check_device_status(uint8_t device_addr)
{
uint8_t ack_status;
if (IIC1_SCL_IS_HIGH() && IIC1_SDA_IS_HIGH())
{
iic_start();
iic_sendbyte(device_addr | IIC_WRITE);
ack_status = iic_wait_ack();
iic_stop();
return ack_status;
}
return 1;
}
/** 私有函数 --------------------------------------------------- */
/**
* @brief 用于模拟IIC时的简单延时
* @param None
* @retval None
*/
static void iic_delay(void)
{
uint8_t i = 0;
uint8_t delay = 5;
while (delay--)
{
i = 10;
while (i--);
}
}
4. AT24C02部分驱动代码
/**
* @file at24c02.c
* @brief at24c02驱动程序
* @par date version author remarks
* 2016-03-21 v1.0 zbt 初次创建
*
*/
/** 头文件包含区 ------------------------------------------------ */
#include "at24c02.h"
#include "iic_dup.h"
/** 私有宏(类型定义) -------------------------------------------- */
#define AT24C02_DEVICE_ADDR 0xA0
#define AT24C02_PAGE_SIZE 8
#define AT24C02_MEM_SIZE 256
#define AT24C02_ADDR_BYTE 1
/** 私有变量 --------------------------------------------------- */
uint8_t test_buffer[AT24C02_MEM_SIZE];
/** 外部变量 --------------------------------------------------- */
/** 私有函数原型 ----------------------------------------------- */
//static void AT24C02_ack(void);
static void AT24C02_error_handle(void);
static void AT24C02_read_test(void);
static void AT24C02_write_test(void);
static void AT24C02_erase_test(void);
/** 公有函数 --------------------------------------------------- */
/**
* @brief AT24C02与主控制器的IIC通讯测试代码
* @param None
* @retval None
*/
void AT24C02_iic_test(void)
{
iic_stop(); /**< 必须先复位IIC总线上的设备到待机模式 */
HAL_Delay(10);
/** 检测总线上是否挂接了IIC设备(此处为AT24C02) */
if (iic_check_device_status(AT24C02_DEVICE_ADDR) == 0)
{
printf("iic device existsn");
}
else
{
printf("no iic device existsn");
}
AT24C02_write_test();
HAL_Delay(5);
AT24C02_read_test();
HAL_Delay(5);
AT24C02_erase_test();
}
/**
* @brief 从AT24C02中读取数据
* @param read_data: 读取到的数据
* @param start_addr: 读取数据的起始地址
* @param data_length: 数据的长度
* @retval None
*/
void AT24C02_read_data(uint8_t *read_data, uint16_t start_addr, uint16_t data_length)
{
uint16_t i;
iic_start();
iic_sendbyte(AT24C02_DEVICE_ADDR | IIC_WRITE);
// AT24C02_ack();
上一篇:使用STM32hal库usart的接收中断分析及出现部分问题的解决
下一篇:基于HAL库 Stm32虚拟IIC总线
推荐阅读最新更新时间:2024-11-06 05:20
设计资源 培训 开发板 精华推荐
- MC33172DR2G 有源带通滤波器的典型应用
- KlipperHead,3D打印喷头小板
- 使用 Microchip Technology 的 TC9491B 的参考设计
- DC2299A-B,LTC3890EGN-1 演示板,6V = VIN = 60V,VOUT1 = 5V at 8A,VOUT2 = 12V at 5A
- 【训练营】PWM小灯
- LTC1147-5、2.5V/2A 降压型稳压器的典型应用电路
- LT1372HVIS8 5V 至 12V 升压转换器的典型应用
- NCP301HSN18T1 1.8V 电压检测器的典型应用,用于具有附加迟滞的微处理器复位电路
- 使用 ON Semiconductor 的 LA4930 的参考设计
- 使用 NXP Semiconductors 的 MC08XS6421EK 的参考设计