美文网首页物联网loT从业者物联网相关技术研究
STM32F103学习笔记(4)——LCD段码屏HT1621使用

STM32F103学习笔记(4)——LCD段码屏HT1621使用

作者: Leung_ManWah | 来源:发表于2020-07-14 09:00 被阅读0次

    一、简介

    HT1621 是 128 点 内存映象和多功能的 LCD 驱动器 HT1621 的软件配置特性使它适用于多种 LCD 应用场合包括 LCD 模块和显示子系统。用于连接主控制器和 HT1621 的管脚只有 4 或 5 条 HT1621,还有一个节电命令用于降低系统功耗。


    二、字符显示原理

    液晶管点亮和熄灭原理分别为在对应的RAM地址中写1和写0。首先需要清楚所驱动控制的液晶的COM-SEG对应关系,然后需要了解HT1621的32×4RAM地址映射。

    例如要控制的液晶的装脚成品图部分如下:



    着重看一个液晶数码管,我们了解原理就行。可以看到图3中是第2个液晶数码管,有7段,分别为A,B,C,D,E,F,G。也就分别为下面COM\SEG地址对应关系图中的2A,2B,2C,2D,2E,2F,2G。

    液晶的显示字符的部分COM公共端输出口和SEG段输出口的分布如下表所示,同理我们可以看到例如:2D对应(SEG5,COM0),2E对应(SEG5,COM1),2F对应(SEG5,COM2),2A对应(SEG5,COM3),2C对应(SEG4,COM1),2G对应(SEG4,COM2),2B对应(SEG4,COM3)。


    HT1621的RAM 地址映射如下图所示:

    可以清楚的看到要控制液晶段对应SEG号作为6位地址,COM号对应作为4位数据写入,此时注意4位数据的高低位。写数据到RAM命令格式为:101+6位RAM地址+4位数据,其中RAM地址为SEG序号。

    例如我们在图3的第二个液晶数码管上显示数字,首先我们根据图3得到地址映射关系,先写入地址SEG4中的四位数据(COM3,COM2,COM1,COM0),再写如地址SEG5中的四位数据(COM3,COM2,COM1,COM0),对应关系如下:


    所以如果在图3中显示“5”,则在显示的液晶段对应地址上写1,不显示写0,如下图所示。所以SEG4地址应写入的数据为0110 ,SEG5地址应写入数据1101。

    三、命令格式

    HT1621 可以用软件设置 两种模式的命令可以配置 HT1621 和传送 LCD 所显示的数据。HT1621 的配置模式称为命令模式,命令模式类型码为 100。命令模式包括一个系统配置命令,一个系统频率选择命令,一个 LCD 配置命令,一个声音频率选择命令,一个定时器/WDT设置命令和一个操作命令。数据模式包括 READWRITEREAD-MODIFY-WRITE 操作,下表是数据和命令模式类型码表。

    操作 模式 类型码
    READ 数据 110
    WRITE 数据 101
    READ-MODIFY-RITE 数据 101
    COMMAND 命令 100

    模式命令应在数据或命令传送前运行。如果执行连续的命令,命令模式代码即 100,将被忽略。当系统在不连续命令模式或不连续地址数据模式下,管脚/CS 应设为 “1” 而且先前的操作模式将复位。当管脚/CS 返回 “0” 时,新的操作模式类型码应先运行。

    四、时序图及程序流程




    五、硬件连接

    功能口 引脚
    CS PB.12
    DATA PB.14
    WR PB.13

    六、移植文件

    注意:延时函数使用了FreeRTOS的vTaskDelay任务延时函数
    链接:https://pan.baidu.com/s/1lXWqJIr9Q07al4H3FwNb6Q 提取码:dsuy
    board_ht1621.cboard_ht1621.h 两个文件加入到工程

    6.1 board_ht1621.c

    /*********************************************************************
     * INCLUDES
     */
    #include "FreeRTOS.h"
    #include "task.h"
    
    #include "board_ht1621.h"
    
    static void gpioConfig(void);
    
    /*********************************************************************
     * PUBLIC FUNCTIONS
     */
    /**
     @brief 初始化LCD屏,HT1621芯片
     @param 无
     @return 无
    */
    void HT1621_Init(void)
    {
        gpioConfig();
        
        vTaskDelay(10);
        
        LCD_CS_1();
        LCD_DATA_1();
        LCD_WR_1();
        
        vTaskDelay(100);                    // 延时使LCD工作电压稳定
        
        HT1621_WriteCommand(HT1621_SYS_EN); // 打开系统振荡器
        HT1621_WriteCommand(HT1621_BIAS);   // BIAS 13 4个公共口
        HT1621_WriteCommand(HT1621_RC256);  // 使用RC_256K系统时钟源,片内RC振荡器
        HT1621_WriteCommand(HT1621_WDT_DIS);
        HT1621_WriteCommand(HT1621_LCD_ON);
    }
    
    /**
     @brief 写入命令,命令标志100
     @param cmd -[in] 命令数据
     @return 无
    */
    void HT1621_WriteCommand(uint8_t cmd)
    {
        uint8_t i;
        
        LCD_CS_0();                         // CS = 0 
        vTaskDelay(1);
        
        // 写入命令标志,DATA:100
        LCD_WR_0();                         // WR = 0
        vTaskDelay(1);
        LCD_DATA_1();                       // DATA = 1
        vTaskDelay(1);
        LCD_WR_1();                         // WR = 1
        vTaskDelay(1);
        
        LCD_WR_0();                         // WR = 0
        vTaskDelay(1);
        LCD_DATA_0();                       // DATA = 0
        vTaskDelay(1);
        LCD_WR_1();                         // WR = 1
        vTaskDelay(1);
        
        LCD_WR_0();                         // WR = 0
        vTaskDelay(1);
        LCD_DATA_0();                       // DATA = 0
        vTaskDelay(1);
        LCD_WR_1();                         // WR = 1
        vTaskDelay(1);
        
        // Datasheet中命令后的C8为0
        LCD_WR_0();                         // WR = 0
        vTaskDelay(1);
        LCD_DATA_0();                       // DATA = 0
        vTaskDelay(1);
        LCD_WR_1();                         // WR = 1
        vTaskDelay(1);
        
        // Datasheet中命令后的C7~C0
        for(i = 0; i < 8; i++)
        {
            LCD_WR_0();                     // WR = 0
            vTaskDelay(1);
            if((cmd << i) & 0x80)
            {
                LCD_DATA_1();               // DATA = 1
            }
            else
            {
                LCD_DATA_0();               // DATA = 0
            }
            vTaskDelay(1);
            LCD_WR_1();                     // WR = 1
            vTaskDelay(1);
        }
        
        LCD_CS_1();                         // CS = 1
        vTaskDelay(1);
    }
    
    /**
     @brief 写入4位数据,写入数据标志101
     @param addr -[in] 写入起始地址
     @param data -[in] 写入数据,因为HT1621的数据位4位,所以实际写入数据为参数的后4位
     @return 无
    */
    void HT1621_WriteData4Bit(uint8_t addr, uint8_t data)
    {
        uint8_t i;
        
        LCD_CS_0();                         // CS = 0 
        vTaskDelay(1);
        
        // 写入数据标志,DATA:101
        LCD_WR_0();                         // WR = 0
        vTaskDelay(1);
        LCD_DATA_1();                       // DATA = 1
        vTaskDelay(1);
        LCD_WR_1();                         // WR = 1
        vTaskDelay(1);
        
        LCD_WR_0();                         // WR = 0
        vTaskDelay(1);
        LCD_DATA_0();                       // DATA = 0
        vTaskDelay(1);
        LCD_WR_1();                         // WR = 1
        vTaskDelay(1);
        
        LCD_WR_0();                         // WR = 0
        vTaskDelay(1);
        LCD_DATA_1();                       // DATA = 1
        vTaskDelay(1);
        LCD_WR_1();                         // WR = 1
        vTaskDelay(1);
        
        // 写入地址,Datasheet中A5~A0
        for(i = 0; i < 6; i++)
        {
            LCD_WR_0();                     // WR = 0
            vTaskDelay(1);
            if((addr << i) & 0x80)
            {
                LCD_DATA_1();               // DATA = 1
            }
            else
            {
                LCD_DATA_0();               // DATA = 0
            }
            vTaskDelay(1);
            LCD_WR_1();                     // WR = 1
            vTaskDelay(1);
        }
        // 写入数据,Datasheet中D0~D3
        for(i = 0; i < 4; i++)
        {
            LCD_WR_0();                     // WR = 0
            vTaskDelay(1);
            if((data >> (3 - i)) & 0x01)
            {
                LCD_DATA_1();               // DATA = 1
            }
            else
            {
                LCD_DATA_0();               // DATA = 0
            }
            vTaskDelay(1);
            LCD_WR_1();                     // WR = 1
            vTaskDelay(1);
        }
        
        LCD_CS_1();                         // CS = 1
        vTaskDelay(1);    
    }
    
    /**
     @brief 写入8位数据,写入数据标志101
     @param addr -[in] 写入起始地址
     @param data -[in] 写入数据
     @return 无
    */
    void HT1621_WriteData8Bit(uint8_t addr, uint8_t data)
    {
        uint8_t i;
        
        LCD_CS_0();                         // CS = 0 
        vTaskDelay(1);
        
        // 写入数据标志,DATA:101
        LCD_WR_0();                         // WR = 0
        vTaskDelay(1);
        LCD_DATA_1();                       // DATA = 1
        vTaskDelay(1);
        LCD_WR_1();                         // WR = 1
        vTaskDelay(1);
        
        LCD_WR_0();                         // WR = 0
        vTaskDelay(1);
        LCD_DATA_0();                       // DATA = 0
        vTaskDelay(1);
        LCD_WR_1();                         // WR = 1
        vTaskDelay(1);
        
        LCD_WR_0();                         // WR = 0
        vTaskDelay(1);
        LCD_DATA_1();                       // DATA = 1
        vTaskDelay(1);
        LCD_WR_1();                         // WR = 1
        vTaskDelay(1);
        
        // 写入地址,Datasheet中A5~A0
        for(i = 0; i < 6; i++)
        {
            LCD_WR_0();                     // WR = 0
            vTaskDelay(1);
            if((addr << i) & 0x80)
            {
                LCD_DATA_1();               // DATA = 1
            }
            else
            {
                LCD_DATA_0();               // DATA = 0
            }
            vTaskDelay(1);
            LCD_WR_1();                     // WR = 1
            vTaskDelay(1);
        }
        // 写入数据,Datasheet中两组D0~D3
        for(i = 0; i < 8; i++)
        {
            LCD_WR_0();                     // WR = 0
            vTaskDelay(1);
            if((data >> (7 - i)) & 0x01)
            {
                LCD_DATA_1();               // DATA = 1
            }
            else
            {
                LCD_DATA_0();               // DATA = 0
            }
            vTaskDelay(1);
            LCD_WR_1();                     // WR = 1
            vTaskDelay(1);
        }
        
        LCD_CS_1();                         // CS = 1
        vTaskDelay(1);       
    }
    
    
    /*********************************************************************
     * LOCAL FUNCTIONS
     */
    /**
     @brief 引脚初始化
     @param 无
     @return 无
    */
    static void gpioConfig(void)
    {
        GPIO_InitTypeDef GPIO_InitStructure;
    
        RCC_APB2PeriphClockCmd(HT1621_CS_CLK|HT1621_DATA_CLK|HT1621_WR_CLK, ENABLE);
        
        GPIO_InitStructure.GPIO_Pin = HT1621_CS_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(HT1621_CS_PORT, &GPIO_InitStructure);
        
        GPIO_InitStructure.GPIO_Pin = HT1621_DATA_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(HT1621_DATA_PORT, &GPIO_InitStructure);
        
        GPIO_InitStructure.GPIO_Pin = HT1621_WR_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(HT1621_WR_PORT, &GPIO_InitStructure);
    }
    
    /****************************************************END OF FILE****************************************************/
    

    6.2 board_ht1621.h

    #ifndef _BOARD_HT1621_H_
    #define _BOARD_HT1621_H_
    
    /*********************************************************************
     * INCLUDES
     */
    #include "stm32f10x.h"
    
    /*********************************************************************
     * DEFINITIONS
     */
    #define HT1621_CS_PORT              GPIOB                   // GPIO端口
    #define HT1621_CS_CLK               RCC_APB2Periph_GPIOB    // GPIO端口时钟
    #define HT1621_CS_PIN               GPIO_Pin_12             // 定义HT1621的CS管脚
    
    #define HT1621_DATA_PORT            GPIOB                   // GPIO端口
    #define HT1621_DATA_CLK             RCC_APB2Periph_GPIOB    // GPIO端口时钟
    #define HT1621_DATA_PIN             GPIO_Pin_14             // 定义HT1621的DATA管脚
    
    #define HT1621_WR_PORT              GPIOB                   // GPIO端口
    #define HT1621_WR_CLK               RCC_APB2Periph_GPIOB    // GPIO端口时钟
    #define HT1621_WR_PIN               GPIO_Pin_13             // 定义HT1621的WR管脚
    
    #define LCD_CS_0()                  GPIO_ResetBits(HT1621_CS_PORT, HT1621_CS_PIN) 
    #define LCD_CS_1()                  GPIO_SetBits(HT1621_CS_PORT, HT1621_CS_PIN) 
    #define LCD_DATA_0()                GPIO_ResetBits(HT1621_DATA_PORT, HT1621_DATA_PIN) 
    #define LCD_DATA_1()                GPIO_SetBits(HT1621_DATA_PORT, HT1621_DATA_PIN)
    #define LCD_WR_0()                  GPIO_ResetBits(HT1621_WR_PORT, HT1621_WR_PIN) 
    #define LCD_WR_1()                  GPIO_SetBits(HT1621_WR_PORT, HT1621_WR_PIN)
    
    #define COMMAND_CODE                0x80                    // 命令码
    #define WRITE_DATA_CODE             0xA0                    // 写命令
    
    #define HT1621_BIAS                 0x52                    // 1/3duty 4com
    #define HT1621_SYS_DIS              0x00                    // 关振系统荡器和LCD偏压发生器
    #define HT1621_SYS_EN               0x02                    // 打开系统振荡器
    #define HT1621_LCD_OFF              0x04                    // 关闭LCD偏压
    #define HT1621_LCD_ON               0x06                    // 打开LCE偏压
    #define HT1621_XTAL                 0x28                    // 外部接时钟
    #define HT1621_RC256                0x30                    // 内部时钟
    #define HT1621_WDT_DIS              0X0A                    // 关闭看门狗
    #define HT1621_TONE_ON              0x12                    // 打开声音输出
    #define HT1621_TONE_OFF             0x10                    // 关闭声音输出
    
    /*********************************************************************
     * API FUNCTIONS
     */
    void HT1621_Init(void);
    void HT1621_WriteCommand(uint8_t cmd);
    void HT1621_WriteData4Bit(uint8_t addr, uint8_t data);
    void HT1621_WriteData8Bit(uint8_t addr, uint8_t data);
    
    #endif /* _BOARD_HT1621_H_ */
    

    七、使用例子

    /*********************************************************************
     * DEFINITIONS
     */
    #define TEMP_ADDR               0x00
    #define FOURTH_8_MHz_ADDR       0x04
    #define FOURTH_8_ADDR           0x08
    #define THIRD_8_75us_ADDR       0x0C
    #define THIRD_8_ADDR            0x10
    #define SECOND_8_POINT_ADDR     0x14
    #define SECOND_8_ADDR           0x18
    #define FIRST_8_50us_ADDR       0x1C
    #define FIRST_8_ADDR            0x20
    #define FM_SOUND_1_ADDR         0x24
    #define SIGNAL_ADDR             0x28
    
    #define DISPLAY_ALARM           0x03
    #define DISPLAY_FM              0x04
    #define DISPLAY_1_1             0x08
    #define DISPLAY_MHZ             0x10
    
    HT1621_Init();
    HT1621_WriteData4Bit(TEMP_ADDR, 0x00);                              // ℃灭
    HT1621_WriteData4Bit(SIGNAL_ADDR, 0x00);                            // 信号灭
    HT1621_WriteData4Bit(FM_SOUND_1_ADDR, DISPLAY_ALARM | DISPLAY_FM);  // 报警+FM亮
    HT1621_WriteData8Bit(FOURTH_8_MHz_ADDR, DISPLAY_MHZ);               // MHz亮
    
    /**
     @brief LCD屏显示频率
     @param frequency -[in] 频率
     @return 无
    */
    void LCD_ShowFrequency(uint32 frequency)
    {
        calculateHundreds(frequency);                                       // 百位
        calculateTens(frequency);                                           // 十位
        calculateOnes(frequency);                                           // 个位
        calculateDecimals(frequency);                                       // 小数位
    }
    
    /**
     @brief 计算频率百位,如87.5MHz,则百位0
     @param frequency -[in] 频率
     @return 无
    */
    static void calculateHundreds(uint32 frequency)
    {
        if(frequency / 100000 == 1)
        {
            s_alarm |= DISPLAY_1_1;
            HT1621_WriteData4Bit(FM_SOUND_1_ADDR, s_alarm);                 // 1亮
        }
        else
        {
            s_alarm &= 0x07;
            HT1621_WriteData4Bit(FM_SOUND_1_ADDR, s_alarm);                 // 1灭
        }
    }
    
    /**
     @brief 计算频率十位,如87.5MHz,则十位8
     @param frequency -[in] 频率
     @return 无
    */
    static void calculateTens(uint32 frequency)
    {
        if(frequency / 10000 % 10 == 0)
        {
            HT1621_WriteData8Bit(FIRST_8_50us_ADDR, 0xAF);                  // 0
        }
        else if(frequency / 10000 % 10 == 8)
        {
            HT1621_WriteData8Bit(FIRST_8_50us_ADDR, 0xEF);                  // 8
        }
        else if(frequency / 10000 % 10 == 9)
        {
            HT1621_WriteData8Bit(FIRST_8_50us_ADDR, 0xED);                  // 9
        }   
    }
    
    /**
     @brief 计算频率个位,如87.5MHz,则个位7
     @param frequency -[in] 频率
     @return 无
    */
    static void calculateOnes(uint32 frequency)
    {
        if(frequency / 1000 % 10 == 0)
        {
            HT1621_WriteData8Bit(SECOND_8_POINT_ADDR, 0xBF);                // 0.
        }
        else if(frequency / 1000 % 10 == 1)
        {
            HT1621_WriteData8Bit(SECOND_8_POINT_ADDR, 0xB0);                // 1.
        }
        else if(frequency / 1000 % 10 == 2)
        {
            HT1621_WriteData8Bit(SECOND_8_POINT_ADDR, 0xDB);                // 2.
        }   
        else if(frequency / 1000 % 10 == 3)
        {
            HT1621_WriteData8Bit(SECOND_8_POINT_ADDR, 0xF9);                // 3.
        } 
        else if(frequency / 1000 % 10 == 4)
        {
            HT1621_WriteData8Bit(SECOND_8_POINT_ADDR, 0xF4);                // 4.
        }
        else if(frequency / 1000 % 10 == 5)
        {
            HT1621_WriteData8Bit(SECOND_8_POINT_ADDR, 0x7D);                // 5.
        }
        else if(frequency / 1000 % 10 == 6)
        {
            HT1621_WriteData8Bit(SECOND_8_POINT_ADDR, 0x7F);                // 6.
        }
        else if(frequency / 1000 % 10 == 7)
        {
            HT1621_WriteData8Bit(SECOND_8_POINT_ADDR, 0xB8);                // 7.
        }
        else if(frequency / 1000 % 10 == 8)
        {
            HT1621_WriteData8Bit(SECOND_8_POINT_ADDR, 0xFF);                // 8.
        }
        else if(frequency / 1000 % 10 == 9)
        {
            HT1621_WriteData8Bit(SECOND_8_POINT_ADDR, 0xFD);                // 9.
        }
    }
    
    /**
     @brief 计算频率小数位,如87.5MHz,则小数位5
     @param frequency -[in] 频率
     @return 无
    */
    static void calculateDecimals(uint32 frequency)
    {
        if(frequency / 100 % 10 == 0)
        {
            HT1621_WriteData8Bit(THIRD_8_75us_ADDR, 0xAF);                  // 0
        }
        else if(frequency / 100 % 10 == 1)
        {
            HT1621_WriteData8Bit(THIRD_8_75us_ADDR, 0xA0);                  // 1
        }
        else if(frequency / 100 % 10 == 2)
        {
            HT1621_WriteData8Bit(THIRD_8_75us_ADDR, 0xCB);                  // 2
        }   
        else if(frequency / 100 % 10 == 3)
        {
            HT1621_WriteData8Bit(THIRD_8_75us_ADDR, 0xE9);                  // 3
        } 
        else if(frequency / 100 % 10 == 4)
        {
            HT1621_WriteData8Bit(THIRD_8_75us_ADDR, 0xE4);                  // 4
        }
        else if(frequency / 100 % 10 == 5)
        {
            HT1621_WriteData8Bit(THIRD_8_75us_ADDR, 0x6D);                  // 5
        }
        else if(frequency / 100 % 10 == 6)
        {
            HT1621_WriteData8Bit(THIRD_8_75us_ADDR, 0x6F);                  // 6
        }
        else if(frequency / 100 % 10 == 7)
        {
            HT1621_WriteData8Bit(THIRD_8_75us_ADDR, 0xA8);                  // 7
        }
        else if(frequency / 100 % 10 == 8)
        {
            HT1621_WriteData8Bit(THIRD_8_75us_ADDR, 0xEF);                  // 8
        }
        else if(frequency / 100 % 10 == 9)
        {
            HT1621_WriteData8Bit(THIRD_8_75us_ADDR, 0xED);                  // 9
        }
    }
    

    • 由 Leung 写于 2020 年 7 月 14 日

    • 参考:STM32液晶显示HT1621驱动原理及程序代码
        HT1621B段码 LCD屏驱动 51单片机驱动程序
        HT1621测试程序

    相关文章

      网友评论

        本文标题:STM32F103学习笔记(4)——LCD段码屏HT1621使用

        本文链接:https://www.haomeiwen.com/subject/jvyacktx.html