一、简介

STM32F103学习笔记(4)——LCD段码屏HT1621使用-编程知识网

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

STM32F103学习笔记(4)——LCD段码屏HT1621使用-编程知识网
STM32F103学习笔记(4)——LCD段码屏HT1621使用-编程知识网

二、字符显示原理

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

例如要控制的液晶的装脚成品图部分如下:
STM32F103学习笔记(4)——LCD段码屏HT1621使用-编程知识网
着重看一个液晶数码管,我们了解原理就行。可以看到图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)。
STM32F103学习笔记(4)——LCD段码屏HT1621使用-编程知识网
HT1621的RAM 地址映射如下图所示:
STM32F103学习笔记(4)——LCD段码屏HT1621使用-编程知识网
可以清楚的看到要控制液晶段对应SEG号作为6位地址,COM号对应作为4位数据写入,此时注意4位数据的高低位。写数据到RAM命令格式为:101+6位RAM地址+4位数据,其中RAM地址为SEG序号。

例如我们在图3的第二个液晶数码管上显示数字,首先我们根据图3得到地址映射关系,先写入地址SEG4中的四位数据(COM3,COM2,COM1,COM0),再写如地址SEG5中的四位数据(COM3,COM2,COM1,COM0),对应关系如下:
STM32F103学习笔记(4)——LCD段码屏HT1621使用-编程知识网
所以如果在图3中显示“5”,则在显示的液晶段对应地址上写1,不显示写0,如下图所示。所以SEG4地址应写入的数据为0110 ,SEG5地址应写入数据1101。
STM32F103学习笔记(4)——LCD段码屏HT1621使用-编程知识网

三、命令格式

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” 时,新的操作模式类型码应先运行。

四、时序图及程序流程

STM32F103学习笔记(4)——LCD段码屏HT1621使用-编程知识网
STM32F103学习笔记(4)——LCD段码屏HT1621使用-编程知识网
STM32F103学习笔记(4)——LCD段码屏HT1621使用-编程知识网
STM32F103学习笔记(4)——LCD段码屏HT1621使用-编程知识网

五、硬件连接

功能口 引脚
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:100LCD_WR_0();                         // WR = 0vTaskDelay(1);LCD_DATA_1();                       // DATA = 1vTaskDelay(1);LCD_WR_1();                         // WR = 1vTaskDelay(1);LCD_WR_0();                         // WR = 0vTaskDelay(1);LCD_DATA_0();                       // DATA = 0vTaskDelay(1);LCD_WR_1();                         // WR = 1vTaskDelay(1);LCD_WR_0();                         // WR = 0vTaskDelay(1);LCD_DATA_0();                       // DATA = 0vTaskDelay(1);LCD_WR_1();                         // WR = 1vTaskDelay(1);// Datasheet中命令后的C8为0LCD_WR_0();                         // WR = 0vTaskDelay(1);LCD_DATA_0();                       // DATA = 0vTaskDelay(1);LCD_WR_1();                         // WR = 1vTaskDelay(1);// Datasheet中命令后的C7~C0for(i = 0; i < 8; i++){LCD_WR_0();                     // WR = 0vTaskDelay(1);if((cmd << i) & 0x80){LCD_DATA_1();               // DATA = 1}else{LCD_DATA_0();               // DATA = 0}vTaskDelay(1);LCD_WR_1();                     // WR = 1vTaskDelay(1);}LCD_CS_1();                         // CS = 1vTaskDelay(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:101LCD_WR_0();                         // WR = 0vTaskDelay(1);LCD_DATA_1();                       // DATA = 1vTaskDelay(1);LCD_WR_1();                         // WR = 1vTaskDelay(1);LCD_WR_0();                         // WR = 0vTaskDelay(1);LCD_DATA_0();                       // DATA = 0vTaskDelay(1);LCD_WR_1();                         // WR = 1vTaskDelay(1);LCD_WR_0();                         // WR = 0vTaskDelay(1);LCD_DATA_1();                       // DATA = 1vTaskDelay(1);LCD_WR_1();                         // WR = 1vTaskDelay(1);// 写入地址,Datasheet中A5~A0for(i = 0; i < 6; i++){LCD_WR_0();                     // WR = 0vTaskDelay(1);if((addr << i) & 0x80){LCD_DATA_1();               // DATA = 1}else{LCD_DATA_0();               // DATA = 0}vTaskDelay(1);LCD_WR_1();                     // WR = 1vTaskDelay(1);}// 写入数据,Datasheet中D0~D3for(i = 0; i < 4; i++){LCD_WR_0();                     // WR = 0vTaskDelay(1);if((data >> (3 - i)) & 0x01){LCD_DATA_1();               // DATA = 1}else{LCD_DATA_0();               // DATA = 0}vTaskDelay(1);LCD_WR_1();                     // WR = 1vTaskDelay(1);}LCD_CS_1();                         // CS = 1vTaskDelay(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:101LCD_WR_0();                         // WR = 0vTaskDelay(1);LCD_DATA_1();                       // DATA = 1vTaskDelay(1);LCD_WR_1();                         // WR = 1vTaskDelay(1);LCD_WR_0();                         // WR = 0vTaskDelay(1);LCD_DATA_0();                       // DATA = 0vTaskDelay(1);LCD_WR_1();                         // WR = 1vTaskDelay(1);LCD_WR_0();                         // WR = 0vTaskDelay(1);LCD_DATA_1();                       // DATA = 1vTaskDelay(1);LCD_WR_1();                         // WR = 1vTaskDelay(1);// 写入地址,Datasheet中A5~A0for(i = 0; i < 6; i++){LCD_WR_0();                     // WR = 0vTaskDelay(1);if((addr << i) & 0x80){LCD_DATA_1();               // DATA = 1}else{LCD_DATA_0();               // DATA = 0}vTaskDelay(1);LCD_WR_1();                     // WR = 1vTaskDelay(1);}// 写入数据,Datasheet中两组D0~D3for(i = 0; i < 8; i++){LCD_WR_0();                     // WR = 0vTaskDelay(1);if((data >> (7 - i)) & 0x01){LCD_DATA_1();               // DATA = 1}else{LCD_DATA_0();               // DATA = 0}vTaskDelay(1);LCD_WR_1();                     // WR = 1vTaskDelay(1);}LCD_CS_1();                         // CS = 1vTaskDelay(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_ */

七、使用例子

STM32F103学习笔记(4)——LCD段码屏HT1621使用-编程知识网

/********************************************************************** 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				0x10HT1621_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测试程序