当前位置: 首页 > news >正文

CH585单片机的LCD外设怎么驱动段式LCD

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个SEGR32_PIN_IN_DIS |= 0x0000238F; // 关闭数字输入R32_PIN_IN_DIS |= RB_PBLx_IN_DIS; // 关闭数字输入R16_PIN_CONFIG |= RB_PBHx_IN_DIS; // 操作LCD时,需关闭debugR32_LCD_SEG_EN = 0x063C020F; // SEG0~3 9 19~21 25~26R8_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_Htypedef enum 
{PARM_OK = 0,PARM_ERROR = 1,
}SEG_PARM;// 定义一个结构体来存储整数部分和小数部分的每一位数字
typedef struct {uint8_t int_digits[4];  // 存储小数扩增的整数 11.1 -》 0111 uint8_t int_count;      // 整数部分的数字个数 2uint8_t decimal_count;  // 小数部分的数字个数 1uint8_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

4、在测试的时候发现,如果先初始化串口再初始化LCD会导致显示异常,所以推荐LCD初始化放在串口初始化之前。具体是什么原因还不太了解

相关文章:

  • leetcode149.直线上最多的点数
  • YOLOv5改进CBAM【保姆级教程】
  • OpenCV 图形API(45)颜色空间转换-----将图像从 BGR 色彩空间转换为 YUV 色彩空间函数BGR2YUV()
  • 【教程】Digispark实现串口通信
  • 深入解析Vue3响应式系统:从Proxy实现到依赖收集的核心原理
  • [免费]SpringBoot+Vue博物馆(预约)管理系统【论文+源码+SQL脚本】
  • leetcode 516. Longest Palindromic Subsequence
  • Qt 概述
  • 【Linux】轻量级命令解释器minishell
  • 在线查看网站免费工具 wps, dps, et, ett, wpt 文件格式
  • Java 性能优化:从硬件到软件的全方位思考
  • JavaScript性能优化实战(1):性能优化基础与性能分析工具
  • KRaft面试思路引导
  • 【JavaEE】计算机的工作原理
  • [SpringMVC]请求响应参数传递
  • 系统架构师2025年论文《论基于UML的需求分析》
  • SF6气体回收装置参数特点分享
  • 内网穿透快解析免费开放硬件集成SDK
  • STM32——新建工程并使用寄存器以及库函数进行点灯
  • 目标检测中的损失函数(二) | BIoU RIoU α-IoU
  • 中国乒乓球队公示多哈世乒赛参赛名单,王楚钦孙颖莎混双重组
  • 世界史圆桌|16-18世纪的跨太平洋贸易
  • 美方因涉港问题对中国官员滥施非法单边制裁,外交部:强烈谴责,对等反制
  • 商务部新闻发言人就美国以关税手段胁迫其他国家限制对华经贸合作事答记者问
  • 沃尔沃中国公开赛夺冠,这是吴阿顺与上海的十年之约
  • 管理规模归零,华夏基金“ETF规模一哥”张弘弢清仓卸任所有产品