赞
踩
详细的介绍可以看这位博主的帖子:那头时空。
着急的朋友就不用看了,简单来说段码液晶屏的驱动需要交流电,有些MCU会自带LCD液晶驱动,而通常我们则会采用像HT1621B这样的LCD驱动器来控制段码屏。
简单来说,HT1621B最多可以控制具有128个显示点位的段码屏,与MCU之间的通信仅需三线即可CS片选线,低电平有效、WR写时钟线,上升沿写入、DATA线,串行数据输入/输出。
详细的内容请看数据手册:HT1621B数据手册。
最简单的连接方式就是将段码屏SEG0-SEG13(我这个屏SEG脚有14个,这种屏都是定制的,具体你要用几个脚要看你定制的屏有几个) 和HT1621B的SEG0-SEG13按照顺序对应的连到一起 (如果你的硬件是乱序相连的,那你就只能在软件上进行一下转换了,也就是你写入数据的地址可能不是从0开始的,也可能不连续),将段码屏COM0-COM3和HT1621B的COM0-COM3按照顺序对应的连到一起 。将HT1621B的CS、WR、DATA与MCU的3个IO口(任选)相连,这样硬件的连接就完成了。
时序图如下
从图中可看出,在片选为低电平且写时钟线的上升沿时才能写入数据。
/** * @brief 写数据到HT1621 * @param Data:要写入的数据bits * @param num:传送数据位数 * @retval 无 */ void write_bit_ht1621(uint8_t data, uint8_t num) { uint8_t i; for (i = 0; i < num; i++) { LCD_WR_0(); /* 拉低WR脚 Data线上的数据在WR脚位上升沿写入 */ if (((data & 0x80) >> 7) == 1) /* 如果当前bit为1,就拉高DATA引脚 */ { LCD_DATA_1(); } else if (((data & 0x80) >> 7) == 0) /* 如果当前bit为0,就拉低DATA引脚 */ { LCD_DATA_0(); } LCD_WR_1(); /* 当前这一bit写完,拉高WR脚,为下次WR为上升沿做准备 */ data <<= 1; /* 当前位用完了,移到下一位继续上述动作 */ } }
首先,我们先了解一下HT1621B的地址映射,如下图
这个图的意思就是SEG0就是地址0,程序中传地址时你可以写为十进制的0也可以写为十六进制的0,每个地址位可以控制4个位,对应LCD屏上4个点的显示(在下面数码管中,a、b、c、d就代表4个点)
在编写具体的显示程序时,要根据厂商给出的真值表进行编写,如下图是我所用的,
我的思路是,14个地址,一个地址4bit,那就相当于7个8bit数据,所以我定义了1个char型的数组有7个元素。HT1621B是支持连续写的。
/* 真值表顺序 FGEABCD */ /* 0,1,2,3,4,5,6,7,8,9,灭 */ const char num[] = {0x5F, 0x06, 0x3D, 0x2F, 0x66, 0x6B, 0x7B, 0x0E, 0x7F, 0x6F, 0x00}; char dispnum[7] = {0x00}; /** * @brief 将要显示的数据写到HT1621 * @param Addr:写入初始地址 * @param Data:要写入的数据 * @param Mode:COMMAND_CODE(0X80) / WRITE_DATA_CODE(0XA0) * @retval 无 */ void write_ht1621(uint8_t addr, uint8_t data) { LCD_CS_0(); write_bit_ht1621(WRITE_DATA_CODE, 3); /* 命令模式或数据模式 */ write_bit_ht1621(addr << 2, 6); /* 写入地址 */ write_bit_ht1621(data, 8); /* 写入数据 */ LCD_CS_1(); }
这里可能会有人有疑问,时序图中数据是低位先传,而我们这里却是高位先传,不用担心我们在编写真值表时已经将低位放在了高位,所以完全没问题。
从时序图中可以看出,命令模式码有3位,而命令代码有9位,但最后一位0、1都行,有些朋友喜欢直接舍弃不管它,而我则是把C8和3位命令码放在一起 C0和C7放在一起注意不同的排序方法,命令代码的值不同,数据手册有详细的命令代码
/* HT1621 命令定义 */ #define COMMAND_CODE 0x80 /* 命令码 */ #define WRITE_DATA_CODE 0xA0 /* 写命令 */ #define HT1621_SYS_EN 0x02 /* 打开系统振荡器 */ #define HT1621_RC256 0x30 /* 内部时钟 */ #define HT1621_BIAS 0x52 /* 1/3duty 4com LCD偏置 */ /** * @brief 写命令到HT1621 * @param Cmd:命令 * @retval 无 */ void write_cmd_ht1621(uint8_t cmd) { LCD_CS_0(); /* 拉低CS脚 CS拉低时WR有效 */ write_bit_ht1621(COMMAND_CODE, 4); /* 写入命令标志100 0x80 */ write_bit_ht1621(cmd, 8); /* 写入命令数据 */ LCD_CS_1(); /* 拉高CS脚 */ }
从真值表来看,有些单个符号在和数码管显示混在了一起,这时只需使用位与和位或就可以单独控制它了,可以看下lcd_display(),看下各位就有思路了。
#ifndef __HT1621_H #define __HT1621_H #include "stm32f10x.h" /* HT1621硬件连接端口定义 */ #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 HT1621_RD_PORT GPIOB /* GPIO端口 */ #define HT1621_RD_CLK RCC_APB2Periph_GPIOB /* GPIO端口时钟 */ #define HT1621_RD_PIN GPIO_Pin_15 /* 定义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 LCD_RD_0() GPIO_ResetBits(HT1621_RD_PORT, HT1621_RD_PIN) #define LCD_RD_1() GPIO_SetBits(HT1621_RD_PORT, HT1621_RD_PIN) /* HT1621 命令定义 */ #define COMMAND_CODE 0x80 /* 命令码 */ #define WRITE_DATA_CODE 0xA0 /* 写命令 */ #define HT1621_SYS_EN 0x02 /* 打开系统振荡器 */ #define HT1621_RC256 0x30 /* 内部时钟 */ #define HT1621_BIAS 0x52 /* 1/3duty 4com LCD偏置 */ #define HT1621_SYS_DIS 0x00 /* 关振系统荡器和LCD偏压发生器 */ #define HT1621_LCD_OFF 0x20 /* 关闭LCD偏压 */ #define HT1621_LCD_ON 0x03 /* 打开LCD偏压 */ #define HT1621_XTAL 0x14 /* 外部接时钟 */ #define HT1621_WDT_DIS 0X05 /* 关闭看门狗 */ #define HT1621_TONE_ON 0x09 /* 打开声音输出 */ #define HT1621_TONE_OFF 0x08 /* 关闭声音输出 */ #define LCD_ON 0x06 /* 打开LCD 偏压发生器1000 0000 0 11 0 */ #define LCD_OFF 0x04 /* 关闭LCD显示 */ /* 设置变量寄存器函数 */ #define SBI(x, y) (x |= (1 << y)) /*置位寄器x的第y位*/ #define CBI(x, y) (x &= ~(1 <<y )) /*清零寄器x的第y位*/ static void gpio_config(void); static void read_gpio_config(void); void ht1621_init(void); void ht1621_all_on(uint8_t num); /* 全部显示 */ void ht1621_all_off(uint8_t num); /* 清除显示 */ void HT1621_all_on_num(uint8_t num, uint8_t xx); /* 全部点亮,显示相同数字 */ void lcd_display(long int t, char p, char s6, char s7, char s8, char s9, char s10, char s11,char s12) ; uint8_t read_ht1621(uint8_t addr); /* 读HT1621返回的数据 */ void lcd_on(void); /* 液晶显示打开 */ void lcd_off(void); /* 液晶显示关闭 */ void write_ht1621(uint8_t addr, uint8_t data); /* 将要显示的数据写到HT1621 */ void write_cmd_ht1621(uint8_t cmd); /* 写命令到HT1621 */ void write_bit_ht1621(uint8_t data, uint8_t num); /* 写数据到HT1621 */ #endif /* _BOARD_HT1621_H */
/** **************************************************************************** * @file ht1621.c * @author BJX * @version V1.0 * @date 2024-3-23 * @brief HT1621段码液晶屏驱动 **************************************************************************** * @attention * * 平台:STM F103C8 * **************************************************************************** */ #include "./ht1621/ht1621.h" #include "./delay/delay.h" #include "./usart/usart.h" uint8_t ram_buf[14] = {0}; /* ht1621缓存数组 */ /* 真值表顺序AFEHBGCD */ /*0,1,2,3,4,5,6,7,8,9,*/ const char num[] = {0xeb, 0x0a, 0xad, 0x8f, 0x4e, 0xc7, 0xe7, 0x8a, 0xef, 0xcf}; char dispnum[7] = {0x00, 0x00, 0x00, 0x00, 0x00}; /** * @brief lcd段码液晶屏显示函数 * @param 无 * @retval 无 */ void lcd_display(long int t, char p, char s6, char s7, char s8, char s9, char s10, char s11,char s12) { unsigned char i; dispnum[0] = 0x11; dispnum[1] = num[t / 1000]; dispnum[2] = num[(t / 100) % 10]; dispnum[3] = num[(t / 10) % 10]; dispnum[4] = num[t%10]; if( dispnum[1] == num[0]) { dispnum[1] = num[10]; } switch (p) { case 1: SBI(dispnum[0], 5); /* S2点亮 */ break; case 2: SBI(dispnum[0], 5); /* S2点亮 */ SBI(dispnum[0], 6); /* S3点亮 */ break; case 3: SBI(dispnum[0], 5); /* S2点亮 */ SBI(dispnum[0], 6); /* S3点亮 */ SBI(dispnum[0], 7); /* S4点亮 */ break; case 4: SBI(dispnum[0], 5); /* S2点亮 */ SBI(dispnum[0], 6); /* S3点亮 */ SBI(dispnum[0], 7); /* S4点亮 */ SBI(dispnum[0], 3); /* S5点亮 */ break; default: CBI(dispnum[0], 5); CBI(dispnum[0], 6); CBI(dispnum[0], 7); CBI(dispnum[0], 3); break; } if (s6 == 1) SBI(dispnum[0], 2); else CBI(dispnum[0], 2); if (s7 == 1) SBI(dispnum[1], 7); else CBI(dispnum[1], 7); if (s8 == 1) SBI(dispnum[2], 7); else CBI(dispnum[2], 7); if (s9 == 1) SBI(dispnum[3], 7); else CBI(dispnum[3], 7); if (s10 == 1) SBI(dispnum[4], 7); else CBI(dispnum[4], 7); if (s11 == 1) SBI(dispnum[5], 7); else CBI(dispnum[5], 7); if (s12 == 1) SBI(dispnum[6], 7); else CBI(dispnum[6], 7); for (i = 0; i < 7; i++) { write_ht1621(i * 2, dispnum[i]); } } /** * @brief HT1621初始化 * @param 无 * @retval 无 */ void ht1621_init(void) { /* 引脚配置相关 */ gpio_config(); Delay_ms(500); /* 延时使LCD工作电压稳定 */ /* 配置HT1621 */ lcd_off(); write_cmd_ht1621(HT1621_SYS_EN); /* 打开系统振荡器 */ write_cmd_ht1621(HT1621_RC256); /* 使用RC_256K系统时钟源,片内RC振荡器 */ write_cmd_ht1621(HT1621_BIAS); /* BIAS 13 4个公共口 */ lcd_on(); } /** * @brief 液晶显示关闭 * @param 无 * @retval 无 */ void lcd_off(void) { write_cmd_ht1621(LCD_OFF); } /** * @brief 液晶显示打开 * @param 无 * @retval 无 */ void lcd_on(void) { write_cmd_ht1621(LCD_ON); } /** * @brief 清除显示 * @param 无 * @retval 无 */ void ht1621_all_off(uint8_t num) { uint8_t i; uint8_t addr = 0; for (i = 0; i < num; i++) { write_ht1621(addr, 0x00); addr += 2; } } /** * @brief 全部显示 * @param 无 * @retval 无 */ void ht1621_all_on(uint8_t num) { uint8_t i; uint8_t addr = 0; for (i = 0; i < num; i++) { write_ht1621(addr, 0xff); addr += 2; } } /** * @brief 全部点亮,显示相同数字 * @param 无 * @retval 无 */ void HT1621_all_on_num(uint8_t num, uint8_t xx) { uint8_t i; uint8_t addr = 0; for (i = 0; i < num; i++) { write_ht1621(addr, xx); addr += 2; } } /** * @brief 将要显示的数据写到HT1621 * @param Addr:写入初始地址 * @param Data:要写入的数据 * @param Mode:COMMAND_CODE(0X80) / WRITE_DATA_CODE(0XA0) * @retval 无 */ void write_ht1621(uint8_t addr, uint8_t data) { LCD_CS_0(); write_bit_ht1621(WRITE_DATA_CODE, 3); /* 命令模式或数据模式 */ write_bit_ht1621(addr << 2, 6); /* 写入地址 */ write_bit_ht1621(data, 8); /* 写入数据 这里是对应单个SEG写的 故而为4 */ LCD_CS_1(); } /** * @brief 读HT1621返回的数据 * @param Addr:读数据的地址 * @retval 读到的数据 */ uint8_t read_ht1621(uint8_t addr) { uint8_t data = 0; uint8_t i; LCD_CS_0(); Delay_us(10); write_bit_ht1621(0XC0, 3); /* 命令模式或数据模式 */ write_bit_ht1621(addr << 2, 6); /* 写入地址 */ read_gpio_config(); for (i = 0; i < 4; i++) { LCD_RD_1(); Delay_us(10); if (GPIO_ReadInputDataBit(HT1621_DATA_PORT, HT1621_DATA_PIN) == 1) { data |= 0x08; } LCD_RD_0(); Delay_us(10); data >>= 1; } LCD_CS_1(); Delay_us(10); gpio_config(); return data; } /** * @brief 写数据到HT1621 * @param Data:要写入的数据bits * @param num:传送数据位数 * @retval 无 */ void write_bit_ht1621(uint8_t data, uint8_t num) { uint8_t i; for (i = 0; i < num; i++) { LCD_WR_0(); /* 拉低WR脚 Data线上的数据在WR脚位上升沿写入 */ if (((data & 0x80) >> 7) == 1) /* 如果当前bit为1,就拉高DATA引脚 */ { LCD_DATA_1(); } else if (((data & 0x80) >> 7) == 0) /* 如果当前bit为0,就拉低DATA引脚 */ { LCD_DATA_0(); } LCD_WR_1(); /* 当前这一bit写完,拉高WR脚,为下次WR为上升沿做准备 */ data <<= 1; /* 当前位用完了,移到下一位继续上述动作 */ } } /** * @brief 写命令到HT1621 * @param Cmd:命令 * @retval 无 */ void write_cmd_ht1621(uint8_t cmd) { LCD_CS_0(); /* 拉低CS脚 CS拉低时WR有效 */ write_bit_ht1621(COMMAND_CODE, 4); /* 写入命令标志100 0x80 */ write_bit_ht1621(cmd, 8); /* 写入命令数据 */ LCD_CS_1(); /* 拉高CS脚 */ } /** * @brief 引脚初始化 * @param 无 * @retval 无 */ static void gpio_config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(HT1621_CS_CLK | HT1621_DATA_CLK | HT1621_WR_CLK | HT1621_RD_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); GPIO_InitStructure.GPIO_Pin = HT1621_RD_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(HT1621_RD_PORT, &GPIO_InitStructure); LCD_CS_1(); LCD_DATA_1(); LCD_WR_1(); LCD_RD_1(); } /** * @brief 读引脚初始化 * @param 无 * @retval 无 */ static void read_gpio_config(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = HT1621_DATA_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(HT1621_DATA_PORT, &GPIO_InitStructure); } /****************************** END OF FILE ******************************/
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。