单片机软件常用设计分享(三)驱动设计之数码屏显示设计

本文介绍了一种单片机软件设计中的数码屏驱动程序,详细阐述了四种显示方式:正常显示、闪烁显示、交替显示和滚动显示。此外,还讨论了驱动的数据结构、代码设计以及如何在实际项目中应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前言

   本人从事单片机软件设计工作多年,既从事过裸机系统的设计,也在小型嵌入式实时操作系统下进行过设计。因在工作当中发现有些人对单片机软件的设计非常随意,尤其是在驱动方面,其考虑问题过于单一,并且应用层与底层驱动之间耦合度较大。基于此,本人整理工作当中做过常用的最基本设计分享到这里,希望对需要的人有所帮助或参考。当然,可能我的设计方法并不是很好,所以也算是一种学习交流。
  在整理的过程中,可能会缺乏统一规划,仅先整理一部分常用的驱动设计。至于其它部分的内容,待今后根据需要再逐一补充。

《驱动设计–数码屏显示驱动》

  数码显示,主要指的是7段LED数码显示。实际上,只要是7段数码显示,甚至米子数码显示均适用于此设计。同样在平时做项目时,经常会遇到要控制数码显示的闪烁、交替及滚屏,对于闪烁,包括持续闪烁和闪烁一定的次数,还包括需要设置闪烁的频率,亮与灭的占空比等等;对于交替显示,将依次显示交替内容,并可以设置更换内容的频率,并可设置持续交替和交替一定的次数;对于滚屏显示同样包括持续滚动还是滚动一定的次数,还包括滚动速度的设置。
  因此,同样还是有必要设计一个统一管理控制数码屏显示的一个驱动程序,使得其在使用时非常的方便。
  另外,这次对驱动进行调试过程中,为了进一步降低软件耦合度,将数码屏设计的所有代码移除。因此,现在的驱动不仅仅适用于7段数码屏,其完全适用于一行或一列的所有显示方式。为了减小修改量,以下仍然对此驱动称为数码屏。

一、数码屏显示方式

  一般包括4种显示方式,正常显示、闪烁显示、交替显示、滚动显示;

1.正常显示

  数码屏按位(digit)显示输出;

2.闪烁显示

  数码屏指定digit位处于两种交替显示状态,即显示与不显示状态;这个需要设置的参数就较多。包括:持续闪烁或闪烁一定次数,闪烁频率,显示占空比等等;

3.交替显示

  数码屏指定digit位按照显示内容交替显示,可设置显示时间及更换的时间,持续显示或显示一定次数;为了简便,这里在设计上有一个限制,即被交替显示的每个文本缓冲区需要设置为长度一致(没有使用的存储位置应该补为空),并将多个文本连续的存放在一个缓冲区中。(当然,如果非要设计长度不一致的文本用以交替显示,则驱动部分需要进行必要的修改);

4.滚动显示

  数码屏显示内容,按照一定的移动速度,由左向右滚动显示。这个可以设置滚动速度,还可以设置持续滚动或滚动一定次数;同时考虑了开始滚动与结束滚动的状态,因此也会有相关参数的设置;

二、数码屏驱动数据结构

  数码屏显示驱动数据结构设计,包括数码屏工作方式、数码屏交替显示参数及状态,数码屏闪烁参数及状态,数码屏滚动参数及状态、数码屏驱动结构,以下分别描述各个部分内容;

1.基本数据结构

  以下DDISP为DIGHIT DISPALAY缩写

1)显示状态

//数码屏显示状态
typedef enum
{
   
	DDISP_STATUS_ON,						//点亮状态
	DDISP_STATUS_OFF						//熄灭状态
}tDDispStatus;

2)计数器

//显示屏计数器
typedef struct
{
   
	uint8_t				max;				//计数最大值(取值0表示持续)
	uint8_t				exec;				//正在执行的计数值
}tDDispCnt;

//显示屏操作起始与终止位置
typedef struct
{
   
	uint8_t				start;				//起始位置(以数字0开始)
	uint8_t				end;				//终止位置
}tDDispPos;

3)显示频率

//数码屏显示频率
typedef enum
{
   
	DDISP_FREQ_1_10Hz=100,					//0.1Hz	
	DDISP_FREQ_2_10Hz=50,					//0.2Hz	
	DDISP_FREQ_5_10Hz=20,					//0.5Hz	
	DDISP_FREQ_1Hz=10,						//1Hz	
	DDISP_FREQ_2Hz=5,						//2Hz	
	DDISP_FREQ_5Hz=2,						//5Hz	
	DDISP_FREQ_10Hz=1,						//10Hz
}tDDispFreq;

4)显示方式

  数码屏包括4种显示方式,适合以枚举类型来定义

//数码屏工作方式
typedef enum
{
   
	DDISP_MODE_NORMAL,						//正常方式
	DDISP_MODE_FLASH,						//闪烁方式
	DDISP_MODE_ALTERNATING,					//交替方式
	DDISP_MODE_SCROLL						//滚动方式
}tDDispMode;

2.运行数据

1)闪烁运行数据结构

  此结构记录执行闪烁显示过程中的部分相关数据及状态。

//闪烁显示运行数据
typedef struct
{
   	
	tDDispStatus		status;				//显示状态
	tDDispPos			pos;				//显示内容在数码屏的起止digit位置
	char				*pDispBuff;			//显示内容缓冲区(存储整个digitMax长度显示数据)
	tDDispCnt			repeat;				//重复执行计数值
}tDDispFlash;

2)交替显示运行数据

  此结构记录交替闪烁显示过程中的部分相关数据及状态。

//交替显示运行数据
typedef struct
{
   
	bool				groupDectect;		//显示内容换组检测
	tDDispStatus		status;				//显示状态
	tDDispPos			pos;				//显示内容在数码屏的起止digit位置
	char				*pDispBuff;			//显示内容缓冲区(数组)
	tDDispCnt			group;				//显示内容组数
	tDDispCnt			repeat;				//重复执行计数值
}tDDispAlternate;

3)滚动显示运行数据

  数码屏滚动显示,内容的更换以从左到右(或从上到下)移动方式实现。
  此结构记录滚动显示过程中的部分相关数据及状态。

//滚动显示运行数据
/*-------------------------------------------------------------------------------------------
				滚动开始与结束都存在两种效果
1.	开始滚动时存在从起始位置前有多少空格的设置prefixSpace
	1)	如滚动区域为digit N,则可设置的空格数为0--N;
	2)	不过一般应该设置为0或者N-1/N,设置中间数据似乎有些突兀;
	3)	设置为N,其效果就是全部为空格,即不显示;
2.	结束滚动时存在最后一个字符后面有多少个空格的设置suffixSpace
	1)	如滚动区域为digit N,则可设置的空格数为0--N;
	2)	不过一般应该设置为0或者N-1/N,设置中间数据似乎有些突兀;
	3)	设置为N,其效果就是全部为空格,即不显示;
3,	prefixSpace和suffixSpace应该不会同时设置为N,否则感觉会怪怪的;
-------------------------------------------------------------------------------------------*/
typedef struct
{
   
	tDDispPos			pos;				//显示内容在数码屏的起止digit位置
	char				*pDispBuff;			//显示内容缓冲区
	tDDispCnt			offset;				//显示内容缓冲区偏移位置
	tDDispCnt			prefixSpace;		//前导空格数(exec逐步自减至0)
	tDDispCnt			suffixSpace;		//后缀空格数(出现空格后exec逐步自加至max)
	tDDispCnt			repeat;				//重复执行计数值
}tDDispScroll;

3.控制参数

  用于设置数码屏在多种显示方式中的参数数据,四种显示方式则对应四种参数数据。

//显示控制参数数据(其中pParam根据mode不同而指向不同的显示参数结构)
typedef struct
{
   
	tDDispMode			mode;				//显示模式
	void*				pParam;				//显示参数
}tDDispCtrlParam;

1)正常显示参数

  指定显示区域及显示数据

//正常显示参数
typedef struct
{
   
	tDDispPos			pos;				//显示内容在数码屏的起止digit位置
	char				*pBuff;				//显示内容缓冲区
}tDDispNormalParam;

2)闪烁显示参数

  指定闪烁区域及闪烁数据(以下对部分参数作了说明描述)

typedef struct
{
   
	/*-------------------------------------------------------------------------------------
							pBuff与onlyFlashData参数说明
	1,	pBuff!=NULL时,其数据与onlyFlashData设置相关
		A,	onlyFlashData=TRUE,pBuff仅存放闪烁数据,其余数据从当前显示获取pBuff[0]被写入显存的
		pos.start位置,其余以此类推;
		B,	onlyFlashData=FALSE,pBuff存放完整数据,其显示界面与当前显示内容无关.
		pBuff[pos.start]被写入显存的pos.start位置,其余以此类推;
	2,	pBuff==NULL时,其数据与当前显示内容关联

							onlyChange参数说明
	onlyChange=TRUE时,除pos及pBuff必须设置数据外,其余数据不必设置,同时控制函数也将不检查其余
	数据.存储关系参考1,A说明
	---------------------------------------------------------------------------------------*/
	bool				onlyChange;			//仅仅更改闪烁数据(适用于闪烁修改数据)
	bool				onlyFlashData;		//取值TRUE,指示pBuff内存储的仅是FLASH数据,取值FALSE存储完整数据
	tDDispFreq			freq;				//闪烁频率	
	uint8_t				dutyRatio;			//取值范围[10/20/30/40/50]	
	uint8_t				counter;			//闪烁次数[0--255],0表示持续闪烁
	tDDispPos			pos;				//显示内容在数码屏的起止digit位置
	char				*pBuff;				//显示(闪烁)内容缓冲区(可以设置为NULL)
}tDDispFlashParam;

3)交替显示参数

  指定显示区域及交替显示的数据组

typedef struct
{
   
	uint8_t				counter;			//交替显示次数[0--255],0表示持续执行交替显示
	uint8_t				group;				//显示内容组数
	uint16_t			onTimems;			//显示时间(ms)
	uint16_t			offTimems;			//更换显示时间(ms)<可以设置为0,则直接切换到下一组>
	tDDispPos			pos;				//显示内容在数码屏的起止digit位置
	char				*pBuff;				//显示内容缓冲区(组)
}tDDispAlternateParam;

4)滚动显示参数

  指定显示区域及滚动显示的数据

typedef struct
{
   
	uint8_t				counter;			//重复执行次数[0--255],0表示持续执行滚动显示
	uint8_t				charTotal;			//滚动字符总数(不能小于滚动区域digit数)
	uint8_t				prefixSpace;		//前导空格数(必须小于等于滚动区域digit数)
	uint8_t				suffixSpace;		//后缀空格数(必须小于等于滚动区域digit数)
	uint16_t			timems;				//滚动一个字符显示时间(不小于扫描时间,且应该取整数<不强制要求>)
	tDDispPos			pos;				//显示滚动内容在数码屏的起止digit位置
	char				*pBuff;				//显示内容缓冲区
}tDDispScrollParam;

4.驱动数据结构

  注:这里取消了digit数码屏的定义

1)数码屏驱动函数原型定义

typedef void(*tDDispVoid)(void);					//数码屏无参函数原型
typedef bool(*tDDispCtrlFunc)(tDDispCtrlParam*);	//数码屏工作控制函数原型
typedef void(*tDDispOutputFunc)(char*);				//数码屏输出控制函数原型

2)数码屏驱动函数

  以下驱动函数由初始化时外部提供,用以安装

//数码屏驱动函数
typedef struct
{
   
    tDDispOutputFunc	output;				//安装的数码屏输出控制函数
	tDDispVoid			init;				//安装的数码屏底层初始化函数(可以设置为空)
	tDDispVoid			unInit;				//安装的数码屏底层去初始化函数(可以设置为空)
	tDDispVoid			lock;				//安装的数码屏互斥锁获取函数(可以设置为空)
	tDDispVoid			unLock;				//安装的数码屏互斥锁归还函数(可以设置为空)
}tDDispDrvFunc;

3)数码屏驱动安装参数

  此参数传递给初始化函数

//数码屏驱动安装参数
typedef struct
{
   	
	bool				alwaysScan;			//总是扫描标志(表示需要不断刷新以维持显示)
	uint8_t				scanUnit;			//数码屏扫描时间[10/20/30/40/50]	
	uint8_t				digitMax;			//数码屏最大digit
	tDDispDrvFunc		drvFunc;			//数码屏驱动函数	
}tDDispInitParam;

4)驱动结构

//数码屏基本结构
typedef struct
{
   
	bool				cntDetect;			//计数检测标志(取值TRUE才可以检测计数值)
	uint16_t			count;				//计数器
   	uint16_t			onCntMax;			//点亮计数器最大值
	uint16_t			offCntMax;			//熄灭计数器最大值
	tDDispMode			mode;				//显示模式
	tDDispTrig			trig;				//数码屏点亮及熄灭触发标志	
	char				*pDispBuff;			//正常显示内容缓冲区
    char				*pFuncDispBuff;		//功能显示缓冲区
   	tDDispFlash			*pFlash;			//闪烁运行数据
   	tDDispAlternate		*pAlternate;		//交替显示数据
   	tDDispScroll		*pScroll;			//滚动显示数据
}tDDisp;

//数码屏驱动提供给应用层的操作句柄
typedef struct
{
   
	tDDispVoid			poll;				//poll函数
	tDDispCtrlFunc		ctrl;				//数码屏控制功能函数
}tDDispHandle;

//数码屏驱动程序使用的数据结构
typedef struct
{
   
	uint8_t				scanUnit;			//数码屏扫描时间单位,ms	
	uint8_t				digitMax;			//数码屏最大digit
	bool				alwaysScan;			//总是扫描标志(表示需要不断刷新)
	bool				needChange;			//数码屏需要改变状态时,将被设置为TRUE)	
	tDDisp_Lock			swLock;				//数码屏软件互斥锁	
	tDDisp				disp;				//数码屏运行数据
	tDDispDrvFunc		drvFunc;			//外部安装的驱动函数	
	tDDispHandle		handle;				//外部调用的功能函数(此类型说明在后面安装驱动中说明)
}tDDispDriver;

三、数码屏驱动代码设计

说明:本次改动已经取消字库定义部分,但为了给有需要的朋友参考如何设计7段数码屏的字库,将保留1-1)至1-3)部分内容。

1.字库定义(驱动中已经取消)

注意:驱动中定义了底层输出操作函数中空格符如下定义(最好底层设计与此一致)

#define	DDISP_SPACE			' '

1)字符索引号定义(7段数码屏示例)

#define	CH_0			0
#define	CH_1			1
#define	CH_2			2
#define	CH_3			3
#define	CH_4			4
#define	CH_5			5
#define	CH_6			6
#define	CH_7			7
#define	CH_8			8
#define	CH_9			9
#define	CH_A			10
#define	CH_b			11
#define	CH_C			12
#define	CH_c			13
#define	CH_d			14
#define	CH_E			15
#define	CH_F			16
#define	CH_g			17
#define	CH_H			18
#define	CH_I			19
#define	CH_J			20
#define	CH_L			21
#define	CH_N			22
#define	CH_n			23
#define	CH_O			24
#define	CH_o			25
#define	CH_P			26
#define	CH_q			27
#define	CH_r			28
#define	CH_S			29
#define	CH_T			30
#define	CH_U			31
#define	CH_u			32
#define	CH_y			33
//7段数码段定义
//   --a--
// |         |
// f          b
// |         |
//   --g--
// |         |
// e         c
// |         |
//   --d--   。p
#define	CH_Seg_a		34//7段数码a段
#define	CH_Seg_b		35//7段数码b段
#define	CH_Seg_c		36//7段数码c段
#define	CH_Seg_d		37//7段数码d段
#define	CH_Seg_e		38//7段数码e段
#define	CH_Seg_f		39//7段数码f段
#define	CH_Seg_g		40//7段数码g段
#define	CH_Seg_Point	41//7段数码小数点P
//
#define	CH_LFBracket	42//左括号
#define	CH_RTBracket	43//右括号
#define	CH_Line			44//横线
#define	CH_UnderLine	45//下划线
#define	CH_EquLine		46//等号线
#define	CH_NULL			47//空(无显示)

2)字符定义(7段数码屏示例)

//实际使用时Seg_xx可以被修改(其可对应I/O口)
#define	Seg_p			0x80
#define	Seg_a			0x40
#define	Seg_b			0x20
#define	Seg_c			0x10
#define	Seg_d			0x08
#define	Seg_e			0x04
#define	Seg_f			0x02
#define	Seg_g			0x01
#define	Seg_null		0x00
//实际使用时可以不修改
#define	FONT_0			Seg_a|Seg_b|Seg_c|Seg_d|Seg_e|Seg_f
#define	FONT_1			Seg_b|Seg_c
#define	FONT_2			Seg_a|Seg_b|Seg_d|Seg_e|Seg_g
#define	FONT_3			Seg_a|Seg_b|Seg_c|Seg_d|Seg_g
#define	FONT_4			Seg_b|Seg_c|Seg_f|Seg_g
#define	FONT_5			Seg_a|Seg_c|Seg_d|Seg_f|Seg_g
#define	FONT_6			Seg_a|Seg_c|Seg_d|Seg_e|Seg_f|Seg_g
#define	FONT_7			Seg_a|Seg_b|Seg_c|Seg_f
#define	FONT_8			Seg_a|Seg_b|Seg_c|Seg_d|Seg_e|Seg_f|Seg_g
#define	FONT_9			Seg_a|Seg_b|Seg_c|Seg_d|Seg_f|Seg_g
#define	FONT_A			Seg_a|Seg_b|Seg_c|Seg_e|Seg_f|Seg_g
#define	FONT_b			Seg_c|Seg_d|Seg_e|Seg_f|Seg_g
#define	FONT_C			Seg_a|Seg_d|Seg_e|Seg_f
#define	FONT_c			Seg_d|Seg_e|Seg_g
#define	FONT_d			Seg_b|Seg_c|Seg_d|Seg_e|Seg_g
#define	FONT_E			Seg_a|Seg_d|Seg_e|Seg_f|Seg_g
#define	FONT_F			Seg_a|Seg_e|Seg_f|Seg_g
#define	FONT_g			Seg_a|Seg_b|Seg_c|Seg_d|Seg_f|Seg_g
#define	FONT_H			Seg_b|Seg_c|Seg_e|Seg_f|Seg_g
#define	FONT_I			Seg_e|Seg_f
#define	FONT_J			Seg_b|Seg_c|Seg_d|Seg_e
#define	FONT_L			Seg_d|Seg_e|Seg_f
#define	FONT_N			Seg_a|Seg_b|Seg_c|Seg_e|Seg_f
#define	FONT_n			Seg_c|Seg_e|Seg_g
#define	FONT_O			Seg_a|Seg_b|Seg_c|Seg_d|Seg_e|Seg_f
#define	FONT_o			Seg_c|Seg_d|Seg_e|Seg_g
#define	FONT_P			Seg_a|Seg_b|Seg_e|Seg_f|Seg_g
#define	FONT_q			Seg_a|Seg_b|Seg_c|Seg_f|Seg_g
#define	FONT_r			Seg_e|Seg_g
#define	FONT_S			Seg_a|Seg_c|Seg_d|Seg_f|Seg_g
#define	FONT_T			Seg_a|Seg_e|Seg_f
#define	FONT_U			Seg_b|Seg_c|Seg_d|Seg_e|Seg_f
#define	FONT_u			Seg_c|Seg_d|Seg_e
#define	FONT_y			Seg_b|Seg_c|Seg_d|Seg_f|Seg_g
#define	FONT_Seg_a		Seg_a
#define	FONT_Seg_b		Seg_b
#define	FONT_Seg_c		Seg_c
#define	FONT_Seg_d		Seg_d
#define	FONT_Seg_e		Seg_e
#define	FONT_Seg_f		Seg_f
#define	FONT_Seg_g		Seg_g
#define	FONT_Seg_Point	Seg_p
#define	FONT_LFBracket	Se
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值