复旦微MCU——FM33LG0驱动TM1629A

复旦微MCU——FM33LG0驱动TM1629A

TM1629A

  1. TM1629A是一款专门用于驱动LED显示屏的驱动芯片。它集成了MCU、数据锁存器、LED高压驱动电路。
  2. 支持16段×8位的显示模式,总共可以驱动128个LED。
  3. 使用串行接口(CLK、STB、DIO)进行通讯。数据在CLK上升沿进行串行移位输入。 含有一个内部450KHz的RC振荡器。
  4. 支持通过调制占空比来调节8个级别的亮度。 通过串行接口可以发送控制命令来设置显示模式、亮度等。STB之后第一个字节是命令代码。
  5. 显示数据写入16个显示寄存器地址00h-0Fh,对应16个段。
  6. 段脚是PMOS开漏输出,连接LED阳极。位脚是NMOS开漏输出,连接LED阴极。 典型应用电路给出了驱动共阴共阳LED显示屏的连接。

典型硬件连接电路

在这里插入图片描述

读写时序

在这里插入图片描述

驱动代码

#ifndef _BSP_TM1629_H
#define _BSP_TM1629_H
#include "fm33lg0xx_fl_gpio.h"
#include "types.h"
// 定义LED状态枚举
typedef enum
{
    LED_OFF = 0x00,
    LED_ON = 0x01,
    LED_BLINKING = 0x02
} LEDState;

// 定义LED位置
typedef struct
{
    u8 grid;
    u8 seg;
} Position;

/***********************************************'参数'********************************************************/
#define NUM_LEDS 32
#define TM1629_CMD_ADDRESS_INC_MODE 0x40
#define TM1629_CMD_ADDRESS_FIXED_MODE 0x44
#define TM1629_CMD_KEY_SCAN 0x42
#define TM1629_CMD_ADDRESS_START 0xC0
#define TM1629_CMD_DISPLAY_ON 0x88
#define TM1629_CMD_DISPLAY_OFF 0x80
/*显示亮度*/
#define TM1629_CMD_PULSE_1_16 0x00
#define TM1629_CMD_PULSE_2_16 0x01
#define TM1629_CMD_PULSE_4_16 0x02
#define TM1629_CMD_PULSE_10_16 0x03
#define TM1629_CMD_PULSE_11_16 0x04
#define TM1629_CMD_PULSE_12_16 0x05
#define TM1629_CMD_PULSE_13_16 0x06
#define TM1629_CMD_PULSE_14_16 0x07
#define TM1629_CMD_DEFAULT_BRIGHTNESS 0x03
/*位码*/
#define GRID5 0x09
#define GRID6 0x0B 
#define GRID7 0x0D
#define GRID8 0x0F
/*段码*/
#define SEG9 0x01
#define SEG10 0x02
#define SEG11 0x04
#define SEG12 0x08
#define SEG13 0x10
#define SEG14 0x20
#define SEG15 0x40
#define SEG16 0x80

/***********************************************'引脚设置'********************************************************/
#define STB_TM_PIN FL_GPIO_PIN_11 // CS
#define STB_TM_PORT GPIOD
#define CLK_TM_PIN FL_GPIO_PIN_0 // CLK
#define CLK_TM_PORT GPIOD
#define DIO_TM_PIN FL_GPIO_PIN_1 // MOSI、MISO
#define DIO_TM_PORT GPIOD
/***********************************************'函数宏定义'********************************************************/
#define STB_HIGH() FL_GPIO_SetOutputPin(STB_TM_PORT, STB_TM_PIN)
#define STB_LOW() FL_GPIO_ResetOutputPin(STB_TM_PORT, STB_TM_PIN)
#define CLK_HIGH() FL_GPIO_SetOutputPin(CLK_TM_PORT, CLK_TM_PIN)
#define CLK_LOW() FL_GPIO_ResetOutputPin(CLK_TM_PORT, CLK_TM_PIN)
#define DIO_HIGH() FL_GPIO_SetOutputPin(DIO_TM_PORT, DIO_TM_PIN)
#define DIO_LOW() FL_GPIO_ResetOutputPin(DIO_TM_PORT, DIO_TM_PIN)
#define DIO_STA() FL_GPIO_GetInputPin(DIO_TM_PORT, DIO_TM_PIN)
/***********************************************'函数声明'********************************************************/
u8 tm1629_read_byte(void);
void tm1629_write_byte(u8 dat);
void tm1629_set_brightness(u8 brightness);
void tm1629_send_data(u8 address, u8 data);
void tm1629_init(void);
void scan_key(u8 *buf);
bool is_keycode_changed(u8 *arr1, u8 *arr2);
void tm1629_update_leds(LEDState *data);
#endif
#include "bsp_tm1629.h"
#include "bsp.h"
#include "bsp_bstim.h"

#define CLK_WIDTH (2)
Position leds[NUM_LEDS] = {
    {GRID5, SEG9},  {GRID5, SEG10}, {GRID5, SEG11}, {GRID5, SEG12}, {GRID5, SEG13}, {GRID5, SEG14}, {GRID5, SEG15},
    {GRID5, SEG16}, {GRID6, SEG9},  {GRID6, SEG10}, {GRID6, SEG11}, {GRID6, SEG12}, {GRID6, SEG13}, {GRID6, SEG14},
    {GRID6, SEG15}, {GRID6, SEG16}, {GRID7, SEG9},  {GRID7, SEG10}, {GRID7, SEG11}, {GRID7, SEG12}, {GRID7, SEG13},
    {GRID7, SEG14}, {GRID7, SEG15}, {GRID7, SEG16}, {GRID8, SEG9},  {GRID8, SEG10}, {GRID8, SEG11}, {GRID8, SEG12},
    {GRID8, SEG13}, {GRID8, SEG14}, {GRID8, SEG15}, {GRID8, SEG16}};

u8 GRID5_CACHE = 0x00;
u8 GRID6_CACHE = 0x00;
u8 GRID7_CACHE = 0x00;
u8 GRID8_CACHE = 0x00;
/*******************************************************************************************************
 * @brief 设置数据引脚为输入
 *
 ******************************************************************************************************/
void DIO_SET_IN(void)
{
    FL_GPIO_InitTypeDef cfg;
    cfg.pin = DIO_TM_PIN;
    cfg.mode = FL_GPIO_MODE_INPUT;
    cfg.outputType = FL_GPIO_OUTPUT_OPENDRAIN;
    cfg.pull = FL_DISABLE;
    cfg.remapPin = FL_DISABLE;
    FL_GPIO_Init(DIO_TM_PORT, &cfg);
}

/*******************************************************************************************************
 * @brief 设置数据引脚为输出
 *
 ******************************************************************************************************/
void DIO_SET_OUT(void)
{
    FL_GPIO_InitTypeDef cfg;
    cfg.pin = DIO_TM_PIN;
    cfg.mode = FL_GPIO_MODE_OUTPUT;
    cfg.outputType = FL_GPIO_OUTPUT_OPENDRAIN;
    cfg.pull = FL_DISABLE;
    cfg.remapPin = FL_DISABLE;
    FL_GPIO_Init(DIO_TM_PORT, &cfg);
}

/*******************************************************************************************************
 * @brief 从TM1629读一个字节
 *
 * @return u8 低位在前
 ******************************************************************************************************/
u8 tm1629_read_byte(void)
{
    // DIO设置成输入
    DIO_SET_IN();
    bsp_delayus(CLK_WIDTH);

    u8 data = 0;
    CLK_HIGH();
    bsp_delayus(CLK_WIDTH);
    for (u8 i = 0; i < 8; i++)
    {
        CLK_LOW();
        bsp_delayus(CLK_WIDTH);
        data >>= 1;
        if (DIO_STA())
        {
            data |= 0x80;
        }
        else
        {
            data &= 0x7f;
        }
        CLK_HIGH();
        bsp_delayus(CLK_WIDTH);
    }
    return data;
}

/*******************************************************************************************************
 * @brief 向TM1629写一个字节,在上升沿数据有效
 *
 * @param dat 低字节在前
 ******************************************************************************************************/
void tm1629_write_byte(u8 dat)
{
    // DIO设置成输出
    DIO_SET_OUT();
    CLK_HIGH();
    bsp_delayus(CLK_WIDTH);
    for (u8 i = 0; i < 8; i++)
    {
        if (dat & 0x01)
        {
            DIO_HIGH();
        }
        else
        {
            DIO_LOW();
        }
        CLK_LOW();
        bsp_delayus(CLK_WIDTH);
        CLK_HIGH();
        bsp_delayus(CLK_WIDTH);
        dat >>= 1;
    }
}

/*******************************************************************************************************
 * @brief 设置地址工作模式
 *
 * @param mode TM1629_CMD_ADDRESS_INCREASE_MODE     地址自动增加
 *             TM1629_CMD_ADDRESS_FIXED_MODE        固定地址
 ******************************************************************************************************/
void tm1629_set_mode(u8 mode)
{
    STB_LOW();
    bsp_delayus(CLK_WIDTH);
    tm1629_write_byte(mode);
    STB_HIGH();
    bsp_delayus(CLK_WIDTH);
}

/*******************************************************************************************************
 * @brief 向指定地址发送一字节数据
 *
 * @param address 处于地址固定模式,需先指定地址再发送数据
 * @param data 数据
 ******************************************************************************************************/
void tm1629_send_data(u8 address, u8 data)
{
    STB_LOW();
    bsp_delayus(CLK_WIDTH);
    // 地址写入命令
    tm1629_write_byte(TM1629_CMD_ADDRESS_START | address);
    // 数据写入命令
    tm1629_write_byte(data);
    STB_HIGH();
    bsp_delayus(CLK_WIDTH);
}

/*******************************************************************************************************
 * @brief 打开显示并设置亮度
 *
 * @param brightness 共八级亮度0x00~0x07
 ******************************************************************************************************/
void tm1629_set_brightness(u8 brightness)
{
    STB_LOW();
    bsp_delayus(CLK_WIDTH);
    tm1629_write_byte(TM1629_CMD_DISPLAY_ON | brightness);
    STB_HIGH();
    bsp_delayus(CLK_WIDTH);
}

/*******************************************************************************************************
 * @brief 向显示地址全写0,所有显示为灭
 *
 ******************************************************************************************************/
void tm1629_clear_display(void)
{
    u8 i;
    tm1629_set_mode(TM1629_CMD_ADDRESS_FIXED_MODE);
    for (i = 0; i < 16; i++)
    {
        STB_LOW();
        bsp_delayus(CLK_WIDTH);
        tm1629_write_byte(TM1629_CMD_ADDRESS_START + i);
        tm1629_write_byte(0x00);
        STB_HIGH();
        bsp_delayus(CLK_WIDTH);
    }
    tm1629_set_brightness(TM1629_CMD_DEFAULT_BRIGHTNESS);
}

/*******************************************************************************************************
 * @brief 将指定id的LED点亮
 *
 * @param id 序号
 ******************************************************************************************************/
void tm1629_led_on(u8 id)
{
    switch (leds[id].grid)
    {
    case GRID5:
        GRID5_CACHE |= (leds[id].seg);
        tm1629_send_data(GRID5, GRID5_CACHE);
        break;
    case GRID6:
        GRID6_CACHE |= (leds[id].seg);
        tm1629_send_data(GRID6, GRID6_CACHE);
        break;
    case GRID7:
        GRID7_CACHE |= (leds[id].seg);
        tm1629_send_data(GRID7, GRID7_CACHE);
        break;
    case GRID8:
        GRID8_CACHE |= (leds[id].seg);
        tm1629_send_data(GRID8, GRID8_CACHE);
        break;
    default:
        LOG("error grid!");
    }
}

/*******************************************************************************************************
 * @brief 将指定id的LED熄灭
 *
 * @param id 序号
 ******************************************************************************************************/
void tm1629_led_off(u8 id)
{
    switch (leds[id].grid)
    {
    case GRID5:
        GRID5_CACHE &= ~(leds[id].seg);
        tm1629_send_data(GRID5, GRID5_CACHE);
        break;
    case GRID6:
        GRID6_CACHE &= ~(leds[id].seg);
        tm1629_send_data(GRID6, GRID6_CACHE);
        break;
    case GRID7:
        GRID7_CACHE &= ~(leds[id].seg);
        tm1629_send_data(GRID7, GRID7_CACHE);
        break;
    case GRID8:
        GRID8_CACHE &= ~(leds[id].seg);
        tm1629_send_data(GRID8, GRID8_CACHE);
        break;
    default:
        LOG("error grid!");
    }
}

/*******************************************************************************************************
 * @brief 更新LED状态
 *
 * @param data 数据
 * @param length 数据长度
 ******************************************************************************************************/
void tm1629_update_leds(LEDState *led_status)
{

    static u32 last = 0;
    static u32 timeout = 200;
    static u32 last_blink_on = 0;
    u32 now = bsp_get_tick();

    if (now - last < timeout)
    {
        return;
    }
    last_blink_on = !last_blink_on;
    timeout = last_blink_on ? 800 : 200;
    last = now;

    for (u8 i = 0; i < 32; i++)
    {
        switch (led_status[i])
        {
        case LED_ON:
            tm1629_led_on(i);
            break;
        case LED_OFF:
            tm1629_led_off(i);
            break;
        case LED_BLINKING:
            if (last_blink_on)
            {
                tm1629_led_on(i);
            }
            else
            {
                tm1629_led_off(i);
            }
            break;
        default:
            LOG("Invalid ID\n");
        }
    }
}

/*******************************************************************************************************
 * @brief 按键扫描函数
 *
 ******************************************************************************************************/
void scan_key(u8 *buf)
{
    STB_LOW();
    bsp_delayus(CLK_WIDTH);
    tm1629_write_byte(TM1629_CMD_KEY_SCAN);
    bsp_delayus(2); // 发送读取命令后,延时2us
    for (u8 i = 0; i < 2; i++)
    {
        buf[i] = tm1629_read_byte();
    }
    STB_HIGH();
    bsp_delayus(CLK_WIDTH);
}
/*******************************************************************************************************
 * @brief 检测键值数组是否变化
 *
 * @param arr1
 * @param arr2
 * @return true
 * @return false
 ******************************************************************************************************/
bool is_keycode_changed(u8 *arr1, u8 *arr2)
{
    if (memcmp(arr1, arr2, 2) == 0)
    {
        return false; // 内存块内容相同,返回 true
    }
    return true; // 内存块内容不同,返回 false
}
/*******************************************************************************************************
 * @brief 初始化TM1629,将所有LED熄灭,并设置地址模式为固定
 *
 ******************************************************************************************************/
void tm1629_init()
{
    tm1629_clear_display();
}```

​​​

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
复旦FM17550是一种硬件设计,它是为了满足特定需求而设计的一款型电子设备。复旦FM17550硬件设计采用了先进的技术和工艺,具有高性能和可靠性。 复旦FM17550硬件设计的主要特点包括:一、小巧便携,体积小且重量轻,可以方便地携带和使用;二、高性能的处理器和大容量的存储器,可以处理和存储大量的数据;三、丰富的接口和通信功能,可以与其他设备进行连接和交互;四、稳定可靠的电源和电路设计,可以保证设备的正常工作和长久使用。 复旦FM17550硬件设计的应用领域广泛,可以应用于物联网、智能家居、智能医疗、智能交通等领域。在物联网领域,复旦FM17550可以作为终端设备,与其他设备进行通信和数据传输,实现信息的采集和监控。在智能家居领域,复旦FM17550可以作为控制中心,与各种家居设备进行连接和控制,实现智能化的家居管理。在智能医疗领域,复旦FM17550可以用于医疗设备的控制和数据管理,提高医疗服务的效率和质量。在智能交通领域,复旦FM17550可以应用于交通信号控制和车辆管理等方面,提升交通系统的智能化水平。 总之,复旦FM17550硬件设计是一种高性能、可靠性强且具有广泛应用领域的型电子设备,将在物联网、智能家居、智能医疗、智能交通等领域发挥重要作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值