基于STM32驱动TM1638学习笔记——软件篇


      当我们需要通过单片机去驱动一款芯片正常工作的时候,我们第一时间会去阅读它的数据手册,当你没有接触过类似的芯片时候,这个时候越看会感觉脑壳越疼,哪怕等你真的驱动它正常工作以后会发现原来它是如此的简单。大部分人卡在最难的部分无疑是时序上,数据手册里面给出了时序的要求如下:

      抛开复杂的时序,软件其实没那么复杂,首先我们要找到连接的引脚,并进行初始化:

STM32       TM1638

PA5   ----- CLK

PA6   ----- DIO

PA7   ----- STB

3.3V  ----- VCC

GND   ----- GND

      

// 先定义几个"暗号"
#define TM1638_CLK_PIN  GPIO_PIN_5
#define TM1638_DIO_PIN  GPIO_PIN_6
#define TM1638_STB_PIN  GPIO_PIN_7
#define TM1638_PORT     GPIOA

// 初始化GPIO,相当于教STM32怎么"搭讪"
void TM1638_Init(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    // CLK和STB是输出模式,像主动出击的直男
    GPIO_InitStruct.Pin = TM1638_CLK_PIN | TM1638_STB_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(TM1638_PORT, &GPIO_InitStruct);
    
    // DIO是双向的,时而输出时而输入,像恋爱中的忽冷忽热
    GPIO_InitStruct.Pin = TM1638_DIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    HAL_GPIO_Init(TM1638_PORT, &GPIO_InitStruct);
    
    // 先保持高冷姿态
    TM1638_STB_HIGH();
    TM1638_CLK_HIGH();
}

      接下来,我们需要实现最终的就是根据时序完成一个字节的读取和写入操作:

// 发送一个字节,像说一句情话
void TM1638_WriteByte(uint8_t data) {
    for(uint8_t i = 0; i < 8; i++) {
        TM1638_CLK_LOW();  // 先低头示好
        
        // 根据数据位决定是送花(1)还是送巧克力(0)
        if(data & 0x01) {
            TM1638_DIO_HIGH();
        } else {
            TM1638_DIO_LOW();
        }
        
        HAL_Delay(1);  // 停顿一下,别太着急
        TM1638_CLK_HIGH();  // 抬起头等待回应
        HAL_Delay(1);
        
        data >>= 1;  // 准备下一句情话
    }
}

// 接收一个字节,像等待对方回复
uint8_t TM1638_ReadByte(void) {
    uint8_t data = 0;
    
    // 先把DIO设置为输入模式,像竖起耳朵听回复
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = TM1638_DIO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(TM1638_PORT, &GPIO_InitStruct);
    
    for(uint8_t i = 0; i < 8; i++) {
        TM1638_CLK_LOW();
        HAL_Delay(1);
        
        // 读取DIO状态,像揣摩对方心思
        if(HAL_GPIO_ReadPin(TM1638_PORT, TM1638_DIO_PIN)) {
            data |= (1 << i);
        }
        
        TM1638_CLK_HIGH();
        HAL_Delay(1);
    }
    
    // 读完切回输出模式,继续主动出击
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    HAL_GPIO_Init(TM1638_PORT, &GPIO_InitStruct);
    
    return data;
}

      有了读取和写入的操作,我们就可以尝试让数码管显示一个数字,需要自定义显示的数组,这个跟数码管的连接相关,这里应用共阴极数码管,最最通用的连接方式下的数组定义及显示函数:

// 显示数字,像送出一份礼物
void TM1638_DisplayNum(uint8_t pos, uint8_t num) {
    const uint8_t digitToSegment[] = {
        0x3F,  // 0
        0x06,  // 1
        0x5B,  // 2
        0x4F,  // 3
        0x66,  // 4
        0x6D,  // 5
        0x7D,  // 6
        0x07,  // 7
        0x7F,  // 8
        0x6F   // 9
    };
    
    TM1638_STB_LOW();  // 开始深情告白
    TM1638_WriteByte(0x44);  // 固定地址模式
    TM1638_STB_HIGH();
    
    TM1638_STB_LOW();
    TM1638_WriteByte(0xC0 | (pos << 1));  // 设置显示位置
    
    // 送出数字"礼物"
    TM1638_WriteByte(digitToSegment[num]);
    
    TM1638_STB_HIGH();
}

      TM1638还支持软件设置数码管的显示亮度,这比我们用三极管调电阻的方式方便太多了:

// 设置亮度,像调节恋爱热度
void TM1638_SetBrightness(uint8_t brightness) {
    // 亮度范围0-7,7最亮
    brightness = brightness > 7 ? 7 : brightness;
    
    TM1638_STB_LOW();
    TM1638_WriteByte(0x88 | brightness);
    TM1638_STB_HIGH();
}

      除了点数码管以外,它还支持扫描按键输入功能(真心对得起这个价格):

// 读取按键状态,像揣摩对方心思
uint8_t TM1638_ReadKeys(void) {
    uint8_t keys = 0;
    
    TM1638_STB_LOW();
    TM1638_WriteByte(0x42);  // 读取按键指令
    
    for(uint8_t i = 0; i < 4; i++) {
        keys |= TM1638_ReadByte() << i;
    }
    
    TM1638_STB_HIGH();
    
    return keys;  // 每个bit代表一个按键状态
}

      以下是终极的示例代码:

int main(void) {
    HAL_Init();
    SystemClock_Config();
    TM1638_Init();
    
    // 先来个"自我介绍"
    TM1638_SetBrightness(7);  // 最大亮度示爱
    
    // 显示"520"表白
    TM1638_DisplayNum(0, 5);
    TM1638_DisplayNum(1, 2);
    TM1638_DisplayNum(2, 0);
    
    while(1) {
        // 持续关注"女神"的反馈(按键)
        uint8_t keys = TM1638_ReadKeys();
        
        if(keys != 0) {
            // 如果有按键按下,改变显示内容
            TM1638_DisplayNum(3, keys % 10);
        }
        
        HAL_Delay(100);
    }
}

      在实际调试中可能会遇到的问题:

1. 数码管无显示情况

   - 检查硬件连接,是不是"红线"(VCC)接错了。

   - 确认STM32的GPIO时钟已开启,有时候可以连上示波器调到触发状态看下波形。

2.数码管显示乱码(显示不正常)

   - 检查时序延迟,是不是时序太快了,示波器该上了。

   - 确认数码管是共阴还是共阳。

3.按键读取数据不准

   - 检查上拉电阻是否接好。

   - 增加去抖动处理。

      到这里本篇的内容就结束了,希望对大家有所帮助,感谢阅读!

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 3
收藏 3
关注 150
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧