SF32LB52-i2c驱动TM1650

文章目录

一、简介

如何使用SF32LB52驱动 TM1650 I2C 数码管设备

参考例程:IIC eeprom 例程

二、SF32LB52-I2C介绍

1.主要特性

SF32LB52的HPSYS有4个I2C设备,分别为I2C1~4

这里需要注意的是 硬件i2c作为主设备/从设备地址寻址为7bit寻址

7bit寻址:设备会将地址左移1位并在最后位拼接上读写标志位

如:写TM1650控制需要在0x48地址写入控制数据 7bit寻址时写入地址需要是0x24,设备左移一位后就是0x48

2.I2C结构

从下面结构图可以看出,I2C设备共有 4输入 4 输出

其中:

fclk:时钟输入信号

dma_req:DMA请求信号

dma_ack:DMA响应信号

int trigger:中断请求信号

scl_i/scl_o:i2c 时钟输入输出

sda_i/sda_o:数据输入输出

结合上面的结构图和下面的图可以发现,所有的IO口都可以配置成I2C功能

三、I2C配置流程

1.GPIO配置

需要将选择的IO口配置为I2C功能,且配置上拉模式

这里选择配置IO口为PAD_PA39和PAD_PA40,选择I2C1设备

c 复制代码
	HAL_PIN_Set(PAD_PA39, I2C2_SCL, PIN_PULLUP, 1); // i2c io select
    HAL_PIN_Set(PAD_PA40, I2C2_SDA, PIN_PULLUP, 1);

2.I2C配置


用户手册中提供了相应的初始化流程

这里i2c选择了标准模式,需要注意每个模式的最大速率值

c 复制代码
        /* I2C 模式选择 */
        hwp_i2c1->CR &= ~0x03; hwp_i2c1->CR |= 0x00;  //I2C standard mode
        /* I2C 速率配置 */
        hwp_i2c1->LCR = 0xA0;  //fclk = 48MHz时,默认max100KHz
        hwp_i2c1->WCR = 0xA0;  
        /* 配置I2C中断 */
        hwp_i2c1->IER = 0x00;  //关闭中断
        /* 使能I2C */
        hwp_i2c1->CR &= ~0x06; hwp_i2c1->CR |= 0x06;  //使能I2C

模式选择位

标志模式,标准模式max速率为100khz

因此根据计算公式,当fclk为48Mhz时,SLV+max(SLV,CNT*2+6)+7+DNF) 需要大于480,其中DNF为滤波数字滤波器延迟,这里没有开启数字滤波器


使能I2C使能,至此I2C初始化已经完成,后续是I2C数据发送接收流程

3.I2C收发

用户手册中也给出了发送接收等流程配置。

当然SF32LB52在SDK中也有相应函数的封装,使用rt_i2c_transfer函数进行数据传输

c 复制代码
rt_i2c_transfer(i2c_bus, &msg1, 1);

四、TM1650

接下来说明如何i2c驱动TM1650显示数码管

对于硬件i2c驱动设备,完成配置硬件驱动后只需要给相应地址写入对应数据即可。

1.地址与数据

TM1650控制数码管显示共两个配置

1.模式命令:地址0x48 数据:显示命令,如下图(控制显示亮度、7/8段显示、开关)

2.现存命令:地址0x68、0x6A、0x6C、0x6E 一一对应四个数码管的显示 数据:共阴极数码管显示


2.指令格式

指令格式如下:需要先配置亮度等控制指令,然后再配置对应数码管的显示

-> 0x48[地址] ->0x41[4级亮度、8段显示、开启] -> 0x68[第一个数码管] ->0x33[显示数据] ->0x6A[第二个数码管] ->0x44[显示数据] ...

c 复制代码
void set_brightness(uint8_t brightness)
{
    msg1.addr   = 0x24;
    msg1.flags  = RT_I2C_WR;
    msg1.len    = 1;
    msg1.buf = &brightness;
    rt_i2c_transfer(i2c_bus, &msg1, 1);
}

void set_data(uint8_t data)
{
    msg2.addr   = 0x34;
    msg2.flags  = RT_I2C_WR;
    msg2.len    = 1;
    msg2.buf = &data;
    rt_i2c_transfer(i2c_bus, &msg2, 1);
}
void main(void)
{
		...
    set_brightness(0x01);
    set_data(0x34);
    ...
}

五、示例代码

1.硬件iic

c 复制代码
#include "rtthread.h"
#include "bf0_hal.h"
#include "drv_io.h"
#include "stdio.h"
#include "string.h"
#include "board.h"

#define DBG_TAG "eeprom_i2c"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

/* i2c  */

static struct rt_i2c_bus_device *i2c_bus = NULL;

/* i2c */
//Version 5.0

#define EEPROM_I2C_ADDRESS         0x50  // 7bit device address of EEPROM

/***************************************************
EEPROM interfaces
****************************************************/

uint8_t RECEIVED = 0;
uint8_t TEST_ADDR[] =
{
    0x01,
    0x02,
    0x03,
    0x04
};
uint8_t TEST_DATA[] =
{
    0x11,
    0x22,
    0x33,
    0x44
};

/**
 * @brief Initialization work before power on EEPROM and
 * @author RDA Ri'an Zeng
 * @date 2008-11-05
 * @param void
 * @return bool:if true,the operation is successful;otherwise is failed
 * @retval
 */
unsigned char EEPROM_init(void)
{

    //uint8_t slaveAddr = EEPROM_I2C_ADDRESS; // 7bit address of device
    HAL_StatusTypeDef ret;

    //1. pin mux
#ifdef SF32LB52X
    HAL_PIN_Set(PAD_PA39, I2C1_SCL, PIN_PULLUP, 1); // i2c io select
    HAL_PIN_Set(PAD_PA40, I2C1_SDA, PIN_PULLUP, 1);
#elif defined(SF32LB58X)
    HAL_PIN_Set(PAD_PB28, I2C6_SCL, PIN_PULLUP, 0); // i2c io select
    HAL_PIN_Set(PAD_PB29, I2C6_SDA, PIN_PULLUP, 0);
#endif

    // 2. i2c init
    // find i2c1
#ifdef SF32LB52X
    i2c_bus = rt_i2c_bus_device_find("i2c1");
#elif defined(SF32LB58X)
    i2c_bus = rt_i2c_bus_device_find("i2c6");
#endif

    rt_kprintf("i2c_bus:0x%x\n", i2c_bus);
    if (i2c_bus)
    {
#ifdef SF32LB52X
        rt_kprintf("Find i2c bus device I2C1\n");
#elif defined(SF32LB58X)
        rt_kprintf("Find i2c bus device I2C6\n");
#endif
        // open rt_device i2c2
        // rt_device_open((rt_device_t)i2c_bus, RT_DEVICE_FLAG_RDWR);
        // //rt_i2c_open(i2c_bus, RT_DEVICE_FLAG_RDWR);
        // struct rt_i2c_configuration configuration =
        // {
        //     .mode = 0,
        //     .addr = 0,
        //     .timeout = 500, //Waiting for timeout period (ms)
        //     .max_hz = 100000, //I2C rate (hz)
        // };
        // // config I2C parameter
        // rt_i2c_configure(i2c_bus, &configuration);
        /* I2C 模式选择 */
        hwp_i2c1->CR &= ~0x03; hwp_i2c1->CR |= 0x00;  //I2C standard mode
        /* I2C 速率配置 */
        hwp_i2c1->LCR = 0xA0;  //fclk = 48MHz时,默认100KHz
        hwp_i2c1->WCR = 0xA0;  
        /* 配置I2C中断 */
        hwp_i2c1->IER = 0x00;  //关闭中断
        /* 使能I2C */
        hwp_i2c1->CR &= ~0x06; hwp_i2c1->CR |= 0x06;  //使能I2C
        


    }
    else
    {
#ifdef SF32LB52X
        LOG_E("Can not found i2c bus I2C2, init fail\n");
#elif defined(SF32LB58X)
        LOG_E("Can not found i2c bus I2C6, init fail\n");
#endif
        return -1;
    }
    return 0;
}

void EEPROM_write_data(uint8_t addr, uint8_t data)
{
    HAL_StatusTypeDef ret;
    ret = rt_i2c_mem_write(i2c_bus, EEPROM_I2C_ADDRESS, addr, 8, &data, 1);
    LOG_D("i2c write reg:0x%x,data:0x%x,ret:%d\n", addr, data, ret);
}

void EEPROM_read_data(uint8_t addr, uint8_t *pdata)
{
    HAL_StatusTypeDef ret;
    uint8_t buf[2];

    ret = rt_i2c_mem_read(i2c_bus, EEPROM_I2C_ADDRESS, addr, 8, pdata, 1);  // ret: return data size
    LOG_D("i2c read reg:0x%x,pdata:0x%x,ret:%d\n", addr, *pdata, ret);
}

void delayms(unsigned short int ms)
{
    HAL_Delay(ms);
}

/// @brief read and write eeprom to test
/// @param
void EEPROM_test(void)
{
    unsigned char i = 0;

    for (i = 0; i < 4; i++)
    {
        EEPROM_write_data(TEST_ADDR[i], TEST_DATA[i]);
        delayms(5); //5ms delay for AT240C8SC write time cycle
    }

    for (i = 0; i < 4; i++)
    {
        EEPROM_read_data(TEST_ADDR[i], &RECEIVED);
    }
}
#include "i2c.h"
struct rt_i2c_msg msg1;
struct rt_i2c_msg msg2;

void set_brightness(uint8_t brightness)
{
    msg1.addr   = 0x24;
    msg1.flags  = RT_I2C_WR;
    msg1.len    = 1;
    msg1.buf = &brightness;
    rt_i2c_transfer(i2c_bus, &msg1, 1);
}

void set_data(uint8_t data)
{
    msg2.addr   = 0x34;
    msg2.flags  = RT_I2C_WR;
    msg2.len    = 1;
    msg2.buf = &data;
    rt_i2c_transfer(i2c_bus, &msg2, 1);
}

void  EEPROM_example(void)
{
    EEPROM_init();
    set_brightness(0x01);
    set_data(0x34);

    //EEPROM_test();
}

uint8_t g_main_flag = 0;
/**
  * @brief  Main program
  * @param  None
  * @retval 0 if success, otherwise failure number
  */
int main(void)
{
    rt_kprintf("main!!\n");
    LOG_D("Start i2c eeprom rtt demo!\n"); // Output a start message on console using printf function
    EEPROM_example();
    LOG_D("i2c end!\n"); // Output a end message on console using printf function


    //hwp_i2c1.



    while (1)
    {
        rt_thread_mdelay(5000);
        //rt_kprintf("__main loop__\r\n");
    }

    return RT_EOK;
}

2.软件iic

c 复制代码
#include "rtthread.h"
#include "bf0_hal.h"
#include "drv_io.h"
#include "stdio.h"
#include "string.h"
#include "board.h"
#include "drv_gpio.h"
#include "ulog.h"

#define DBG_TAG "TM1650"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#define TM1650_SCL GET_PIN(1,41)
#define TM1650_SDA GET_PIN(1,42)


#define SET_SCL(x) rt_pin_write(TM1650_SCL, x)
#define SET_SDA(x) rt_pin_write(TM1650_SDA, x)


#define READ_SDA rt_pin_read(TM1650_SDA)

void I2C_Start(void)
{
    SET_SDA(1);
    SET_SCL(1);
    rt_thread_mdelay(1);
    SET_SDA(0);
    rt_thread_mdelay(1);
    SET_SCL(0);
    LOG_I("I2C Start Condition");
}

void I2C_ACK(void)
{
    uint8_t timeout = 0;
    SET_SCL(1);
    rt_thread_mdelay(1);
    SET_SCL(0);
    //rt_pin_mode(TM1650_SDA, PIN_MODE_INPUT);
    while(READ_SDA&&timeout<=100)
    {
        timeout++;
        LOG_I("I2C ACK Waiting...");
    }
    //rt_pin_mode(TM1650_SDA, PIN_MODE_OUTPUT);
    rt_thread_mdelay(1);
    SET_SCL(0);
    LOG_I("I2C ACK Received");
}

void I2C_Stop(void)
{
    SET_SDA(0);
    SET_SCL(1);
    rt_thread_mdelay(1);
    SET_SDA(1);
    rt_thread_mdelay(1);
    LOG_I("I2C Stop Condition");
}


void I2C_Send_Byte(uint8_t byte)
{
    SET_SCL(0);
    rt_thread_mdelay(1);

    for(int i=0;i<8;i++)
    {
        if(byte&0x80)
            SET_SDA(1);
        else
            SET_SDA(0);
        rt_thread_mdelay(1);
        byte <<= 1;
        SET_SCL(1);
        rt_thread_mdelay(1);
        SET_SCL(0);
        rt_thread_mdelay(1);
    }
    LOG_I("I2C Sent Byte: 0x%02X", byte);
}

void TM1650_GPIO_init(void)
{
    /* Initialize GPIO pins */
    rt_pin_mode(TM1650_SCL, PIN_MODE_OUTPUT);
    rt_pin_mode(TM1650_SDA, PIN_MODE_OUTPUT);
    
    /* Set initial state */
    rt_pin_write(TM1650_SCL, PIN_LOW);//
    rt_pin_write(TM1650_SDA, PIN_HIGH);//

    LOG_D("GPIO initialized for TM1650 I2C communication.");
}

void TM1650_Brightness_Set(uint8_t data)
{
    I2C_Start();
    I2C_Send_Byte(0x48);
    I2C_ACK();
    I2C_Send_Byte(data);
    I2C_ACK();
    I2C_Stop();
    LOG_D("TM1650 Displayed data 0x%02X at address 0x%02X", data, 0x24);
}


void TM1650_Display(uint8_t DIG, uint8_t data)
{
    I2C_Start();
    I2C_Send_Byte(0x68 + DIG);
    I2C_ACK();
    I2C_Send_Byte(data);
    I2C_ACK();
    I2C_Stop();
    LOG_D("TM1650 Displayed data 0x%02X at address 0x%02X", data, 0x34 + DIG);
}

/**
  * @brief  Main program
  * @param  None
  * @retval 0 if success, otherwise failure number
  */
int main(void)
{
    TM1650_GPIO_init();
    TM1650_Brightness_Set(0x09); // Set brightness to maximum
    TM1650_Display(2, 0x32); // Display full brightness on digit 0

    while (1)
    {
        rt_thread_mdelay(5000);
        //rt_kprintf("__main loop__\r\n");
    }

    return RT_EOK;
}
相关推荐
西岸行者2 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意2 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码2 天前
嵌入式学习路线
学习
毛小茛2 天前
计算机系统概论——校验码
学习
babe小鑫2 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms2 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下2 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。2 天前
2026.2.25监控学习
学习
im_AMBER2 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J2 天前
从“Hello World“ 开始 C++
c语言·c++·学习