1、首先这里只讲应用,不讲具体原理。
要驱动段式LCD,这里就要知道占空比的调整,比如1/4为例就需要4个COM口。这4个COM口由单片机自行驱动,你不用管。就像硬件IIC和SPI,时序问题不用你去操心,你要做的就是向对应的缓存内去写值就行了。
首先你们的段式LCD一定有一个真值表
在这里教你怎么看这个真值表
首先会有
PIN SEG0 SEG1 SEG2 SEG3 ...
COM3 COM3
COM2 COM2
COM1 COM1
COM0 COM0
通常真值表就长这样,一般段式LCD由段码管和特殊符号组成,如果有4个断码管,它们只要写出一组,其他的可以通过便宜来进行操作。特殊符号就特殊处理。
只需关心SEG0 跟单片机的哪个SEG缓存接上了,CH585的SEG是一个寄存器装了8个SEG,最多28个。也就是4位代表1个SEG,正好对上了4个COM
然后回到如何看真值表呢,就是SEG里为1的地方会被点亮,比如你往4个SEG寄存器缓存内写1,也就是全部写0xFFFFFFFF,那就可控制这28个SEG全亮。
看表算值的时候,高位到低位是COM3~COM0 SEG(n+1)~SEG(n)这样。一般断码管只占用2个SEG,所以表示一个断码管的数字一般是8位 ,以一个虚无的断码为例
0 对应的是
dPIN ~ SEG(0) SEG(1) <-----------------
| COM3 1 1
| COM2 1 1
| COM1 0 1
v COM0 0 0
那需要完成点亮SEG0的高2位,SEG1的高三位,也就是SEG0,SEG1组合起来的值 0x ec
当然两个COM口的话同理,位序排列不错就是写1点亮对应的位,写0熄灭
2、参考代码,没有实现显示浮点数那个功能,实在是想不出来怎么处理好。
#include "CH58x_common.h"
#include "CH58x_lcd.h"
#include "lcd.h"
#include <math.h>
#include <stdio.h> // 添加标准输入输出库
//显示浮点数有问题
NumberUnion g_num_union;
// 段码屏用到了PA8,PA9 串口1不能用来打印
void lcd_init(void)
{
// 1 选择并打开32KHZ时钟源 官方例程里并未操作时钟
// 2 配置要用的IO为模拟输入 浮空态(可不配置,例程未配置)
GPIOB_ModeCfg(0, GPIO_ModeIN_Floating);
GPIOB_ModeCfg(1, GPIO_ModeIN_Floating);
GPIOB_ModeCfg(2, GPIO_ModeIN_Floating);
GPIOB_ModeCfg(3, GPIO_ModeIN_Floating);
GPIOB_ModeCfg(4, GPIO_ModeIN_Floating);
GPIOB_ModeCfg(5, GPIO_ModeIN_Floating);
GPIOB_ModeCfg(6, GPIO_ModeIN_Floating);
GPIOB_ModeCfg(7, GPIO_ModeIN_Floating);
GPIOB_ModeCfg(9, GPIO_ModeIN_Floating);
GPIOB_ModeCfg(18, GPIO_ModeIN_Floating);
GPIOB_ModeCfg(19, GPIO_ModeIN_Floating);
GPIOB_ModeCfg(20, GPIO_ModeIN_Floating);
GPIOB_ModeCfg(21, GPIO_ModeIN_Floating);
GPIOA_ModeCfg(8, GPIO_ModeIN_Floating);
GPIOA_ModeCfg(9, GPIO_ModeIN_Floating);
// 3 选择要加载到RAM0~RAM3的数据
LCD_WriteData0(0);
LCD_WriteData1(0);
LCD_WriteData9(0);
LCD_WriteData10(0);
LCD_Write_SEG25_DATA(0);
LCD_Write_SEG26_DATA(0);
LCD_Write_SEG9_DATA(0);
// 4 配置LCD参数
// COM口由配置的占空比和偏置自动驱动,只需配置SEG的RAM即可,SEG一共有28根线,但是只用到了11个SEG
R32_PIN_IN_DIS |= 0x0000238F; // 关闭数字输入
R32_PIN_IN_DIS |= RB_PBLx_IN_DIS; // 关闭数字输入
R16_PIN_CONFIG |= RB_PBHx_IN_DIS; // 操作LCD时,需关闭debug
R32_LCD_SEG_EN = 0x063C020F; // SEG0~3 9 19~21 25~26
R8_LCD_CMD = RB_LCD_SYS_EN | RB_LCD_ON |
(LCD_CLK_256 << 5) | //256HZ
(LCD_1_4_Duty << 3) |
(LCD_1_3_Bias << 2);
}
// 定义一个数组来存储数字段码
const uint8_t digit_segments[10] = {
SEG_0, SEG_1, SEG_2, SEG_3, SEG_4,
SEG_5, SEG_6, SEG_7, SEG_8, SEG_9
};
// 定义一个宏函数指针数组来存储写数据宏
#define CALL_LCD_WRITE_DATA(index, data) \
switch (index) { \
case 0: LCD_WriteData0(data); break; \
case 1: LCD_WriteData1(data); break; \
case 2: LCD_WriteData9(data); break; \
case 3: LCD_WriteData10(data); break; \
}
// decFlag = 0不显示带小数点的数字 decFlag = 1 显示带小数点的数字
SEG_PARM lcd_display_NUMBER(uint8_t num, uint8_t pos, uint8_t decFlag) //通过
{
SEG_PARM parm = PARM_OK;
if (!(num >= 0 && num <= 9 && pos >= 0 && pos <= 3))
{
printf("\n LCD Num Parameter Error\n");
return PARM_ERROR;
}
if (decFlag == 1)
{
CALL_LCD_WRITE_DATA(pos, (digit_segments[num]|(0x01<<4)));
}
else
{
CALL_LCD_WRITE_DATA(pos, digit_segments[num]);
}
return parm;
}
3、头文件
SEG0~9的值的具体表示要根据真值表来确定
#ifndef _LCD_H
#define _LCD_H
typedef enum
{
PARM_OK = 0,
PARM_ERROR = 1,
}SEG_PARM;
// 定义一个结构体来存储整数部分和小数部分的每一位数字
typedef struct {
uint8_t int_digits[4]; // 存储小数扩增的整数 11.1 -》 0111
uint8_t int_count; // 整数部分的数字个数 2
uint8_t decimal_count; // 小数部分的数字个数 1
uint8_t dot_pos ;
uint8_t reserve[5];
} DecimalNumberParts;
typedef struct {
uint8_t int_digits[4]; // 存储整数部分的每一位数字,最多 4 位
uint8_t int_count; // 整数部分的数字个数
uint8_t reserve[7];
} NumberParts;
// 定义共用体
typedef union {
DecimalNumberParts decimal;
NumberParts integer;
} NumberUnion;
// 段码表 // 其中数码管和小数点可以进行偏移,在真值表内可以看出为SEG5~SEG12是4个8段数码管的配置基本一致
//数码管数字 0~9
#define SEG_0 0xaf
#define SEG_1 0xa0
#define SEG_2 0xcb
#define SEG_3 0xe9
#define SEG_4 0xe4
#define SEG_5 0x6d
#define SEG_6 0x6f
#define SEG_7 0xa8
#define SEG_8 0xef
#define SEG_9 0xed
#define SEG_dot 0x10
#define LCD_Write_SEG0_DATA(d) (R32_LCD_RAM0 = (R32_LCD_RAM0 & 0xfffffff0) | ((uint32_t)d))
#define LCD_Write_SEG1_DATA(d) (R32_LCD_RAM0 = (R32_LCD_RAM0 & 0xffffff0f) | ((uint32_t)d)<<4)
#define LCD_Write_SEG2_DATA(d) (R32_LCD_RAM0 = (R32_LCD_RAM0 & 0xfffff0ff) | ((uint32_t)d)<<8)
#define LCD_Write_SEG3_DATA(d) (R32_LCD_RAM0 = (R32_LCD_RAM0 & 0xffff0fff) | ((uint32_t)d)<<12)
#define LCD_Write_SEG4_DATA(d) (R32_LCD_RAM0 = (R32_LCD_RAM0 & 0xfff0ffff) | ((uint32_t)d)<<16)
#define LCD_Write_SEG5_DATA(d) (R32_LCD_RAM0 = (R32_LCD_RAM0 & 0xff0fffff) | ((uint32_t)d)<<20)
#define LCD_Write_SEG6_DATA(d) (R32_LCD_RAM0 = (R32_LCD_RAM0 & 0xf0ffffff) | ((uint32_t)d)<<24)
#define LCD_Write_SEG7_DATA(d) (R32_LCD_RAM0 = (R32_LCD_RAM0 & 0x0fffffff) | ((uint32_t)d)<<28)
#define LCD_Write_SEG8_DATA(d) (R32_LCD_RAM1 = (R32_LCD_RAM1 & 0xfffffff0) | ((uint32_t)d))
#define LCD_Write_SEG9_DATA(d) (R32_LCD_RAM1 = (R32_LCD_RAM1 & 0xffffff0f) | ((uint32_t)d)<<4)
#define LCD_Write_SEG10_DATA(d) (R32_LCD_RAM1 = (R32_LCD_RAM1 & 0xfffff0ff) | ((uint32_t)d)<<8)
#define LCD_Write_SEG11_DATA(d) (R32_LCD_RAM1 = (R32_LCD_RAM1 & 0xffff0fff) | ((uint32_t)d)<<12)
#define LCD_Write_SEG12_DATA(d) (R32_LCD_RAM1 = (R32_LCD_RAM1 & 0xfff0ffff) | ((uint32_t)d)<<16)
#define LCD_Write_SEG13_DATA(d) (R32_LCD_RAM1 = (R32_LCD_RAM1 & 0xff0fffff) | ((uint32_t)d)<<20)
#define LCD_Write_SEG14_DATA(d) (R32_LCD_RAM1 = (R32_LCD_RAM1 & 0xf0ffffff) | ((uint32_t)d)<<24)
#define LCD_Write_SEG15_DATA(d) (R32_LCD_RAM1 = (R32_LCD_RAM1 & 0x0fffffff) | ((uint32_t)d)<<28)
#define LCD_Write_SEG16_DATA(d) (R32_LCD_RAM2 = (R32_LCD_RAM2 & 0xfffffff0) | ((uint32_t)d))
#define LCD_Write_SEG17_DATA(d) (R32_LCD_RAM2 = (R32_LCD_RAM2 & 0xffffff0f) | ((uint32_t)d)<<4)
#define LCD_Write_SEG18_DATA(d) (R32_LCD_RAM2 = (R32_LCD_RAM2 & 0xfffff0ff) | ((uint32_t)d)<<8)
#define LCD_Write_SEG19_DATA(d) (R32_LCD_RAM2 = (R32_LCD_RAM2 & 0xffff0fff) | ((uint32_t)d)<<12)
#define LCD_Write_SEG20_DATA(d) (R32_LCD_RAM2 = (R32_LCD_RAM2 & 0xfff0ffff) | ((uint32_t)d)<<16)
#define LCD_Write_SEG21_DATA(d) (R32_LCD_RAM2 = (R32_LCD_RAM2 & 0xff0fffff) | ((uint32_t)d)<<20)
#define LCD_Write_SEG22_DATA(d) (R32_LCD_RAM2 = (R32_LCD_RAM2 & 0xf0ffffff) | ((uint32_t)d)<<24)
#define LCD_Write_SEG23_DATA(d) (R32_LCD_RAM2 = (R32_LCD_RAM2 & 0x0fffffff) | ((uint32_t)d)<<28)
#define LCD_Write_SEG24_DATA(d) (R32_LCD_RAM3 = (R32_LCD_RAM3 & 0xfffffff0) | ((uint32_t)d))
#define LCD_Write_SEG25_DATA(d) (R32_LCD_RAM3 = (R32_LCD_RAM3 & 0xffffff0f) | ((uint32_t)d)<<4)
#define LCD_Write_SEG26_DATA(d) (R32_LCD_RAM3 = (R32_LCD_RAM3 & 0xfffff0ff) | ((uint32_t)d)<<8)
#define LCD_Write_SEG27_DATA(d) (R32_LCD_RAM3 = (R32_LCD_RAM3 & 0xffff0fff) | ((uint32_t)d)<<12)
/**
* @brief LCD 初始化函数
* @description 用于初始化 LCD 相关的 IO 口、配置 LCD 参数等操作。
* @param 无
* @return 无
*/
extern void lcd_init(void);
/**
* @brief 在 LCD 上显示数字
* @description 根据输入的数字、位置和是否显示小数点的标志,在 LCD 的指定位置显示数字。
* @param num 要显示的数字(0 到 9)
* @param pos 显示的位置(0 到 3)
* @param decFlag 是否显示小数点的标志,0 表示不显示,1 表示显示
* @return SEG_PARM 类型的值,PARM_OK 表示操作成功,PARM_ERROR 表示参数错误操作失败
*/
extern SEG_PARM lcd_display_NUMBER(uint8_t num, uint8_t pos, uint8_t decFlag);
extern void lcd_clear_disp(void);//清屏
#endif