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

一、简介

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测试程序

猜你喜欢

转载自blog.csdn.net/qq_36347513/article/details/107330387