16x16LED点阵屏之电梯爬行楼层指示程序设计

效果展示

电梯爬行效果展示

概要

在我们日常生活中经常乘坐电梯,电梯里面和外面都有指示牌,他指示着电梯的楼层和上下移动的方向,人们都根据指示牌来乘坐电梯,电梯的指示牌有数码管和点阵屏的,接下来我们用MCU(51单片机)来控制16x16LED点阵屏,实现电梯指示实验。
我们的16x16LED点阵屏是采用WS2811芯片控制的R、G、B三种颜色LED灯,每一个像素点都包含R、G、B三种颜色。我们怎样来实现以上的效果呢?
本文讲述显示数字取模、函数接口和代码展示等,尽量让读者读懂理解

数字字模表

电梯指示屏显示0-9数字的字模表,字体取模工具生成对应的字模。
在这里插入图片描述
8x8数字模表

uint8_t code Digit8x8_tb[][8]=
{
// 1(0) 2(1) 3(2) 4(3) 5(4) 6(5) 7(6) 8(7) 9(8) 0(9)
{0x00,0x00,0x3E,0x41,0x41,0x41,0x3E,0x00},/*"0",0*/
{0x00,0x00,0x00,0x42,0x7F,0x40,0x00,0x00},/*"1",0*/
{0x00,0x00,0x62,0x51,0x49,0x49,0x46,0x00},/*"2",0*/
{0x00,0x00,0x22,0x41,0x49,0x49,0x36,0x00},/*"3",0*/
{0x00,0x00,0x18,0x14,0x12,0x7F,0x10,0x00},/*"4",0*/
{0x00,0x00,0x2F,0x49,0x49,0x49,0x31,0x00},/*"5",0*/
{0x00,0x00,0x3E,0x49,0x49,0x49,0x32,0x00},/*"6",0*/
{0x00,0x00,0x01,0x01,0x79,0x05,0x03,0x00},/*"7",0*/
{0x00,0x00,0x36,0x49,0x49,0x49,0x36,0x00},/*"8",0*/
{0x00,0x00,0x26,0x49,0x49,0x49,0x3E,0x00},/*"9",0*/

{0x00,0x00,0x08,0x04,0x7E,0x04,0x08,0x00},/*"向上",0*/
{0x00,0x00,0x10,0x20,0x7E,0x20,0x10,0x00},/*"向下",0*/
};

8x6数字模表

uint8_t code Digit8x6_tb[][6] =
{
// 1(0) 2(1) 3(2) 4(3) 5(4) 6(5) 7(6) 8(7) 9(8) 0(9)
	{0x3E,0x41,0x41,0x41,0x3E,0x00},/*"0",0*/
	{0x00,0x42,0x7F,0x40,0x00,0x00},/*"1",0*/
	{0x62,0x51,0x49,0x49,0x46,0x00},/*"2",0*/
	{0x22,0x41,0x49,0x49,0x36,0x00},/*"3",0*/
	{0x18,0x14,0x12,0x7F,0x10,0x00},/*"4",0*/
	{0x2F,0x49,0x49,0x49,0x31,0x00},/*"5",0*/
	{0x3E,0x49,0x49,0x49,0x32,0x00},/*"6",0*/
	{0x01,0x01,0x79,0x05,0x03,0x00},/*"7",0*/
	{0x36,0x49,0x49,0x49,0x36,0x00},/*"8",0*/
	{0x26,0x49,0x49,0x49,0x3E,0x00},/*"9",0*/
	{0x08,0x04,0x7E,0x04,0x08,0x00},/*"向上",10*/
	{0x10,0x20,0x7E,0x20,0x10,0x00},/*"向下",11*/
};

程序设计

先前条件

1)我们已将16x16LED点阵屏的驱动写好,驱动程序控制WS2811芯片中的256个像素。
2)内存变量映射:

#define LED_NUM_MAX  256
typedef struct
{
    uint8_t  Level;         			// 屏幕亮度
    uint16_t Status[LED_NUM_MAX/16];    // 256个灯的状态
    uint8_t  ColourID[LED_NUM_MAX];     // 256个灯颜色
}RGB_UNIT_T;
// 定义一个变量
RGB_UNIT_T xdata ctl_rgb={0};

ctl_rgb变量将控制 256个像素灯的内存
Level:整个屏幕亮度
Status:映射为256个灯的亮与灭
ColourID:映射为256个灯的颜色ID,颜色ID是指颜色表中的序号

函数接口说明

/*********************************************************************
 * 功能:  SW2811_SendRGBData()
 *
 * 注解:  发送R、G、B 3 个字节
 *
 * 输入:  None.
 *
 * 输出:  None.
 **********************************************************************/
void WS2812_SendRGBData(uint8_t r_Data,uint8_t g_Data,uint8_t b_Data);

/*********************************************************************
 * 功能:  SW2811_16x16Refresh()
 *
 * 注解:  16*16 屏刷新输出
 *
 * 输入:  None.
 *
 * 输出:  None.
 **********************************************************************/
void WS2812_16x16Refresh(void);


/*********************************************************************
 * 功能:  WS2812_Digit_X_Y_8x8()
 *
 * 注解:  显示8x8的点阵字模
 *
 * 输入:  x_line : x坐标 0-15   y_line:  y坐标 0-15  num: 数字 0-9
 *
 * 输出:  None.
 **********************************************************************/
void WS2812_Digit_X_Y_8x8(uint8_t x_line,uint8_t y_line, uint8_t num);

/*********************************************************************
 * 功能:  WS2812_Digit_X_Y_8x6()
 *
 * 注解:  显示8x6的点阵字模
 *
 * 输入:  x_line : x坐标 0-15   y_line:  y坐标 0-15 ; num : num: 数字 0-9
 *
 * 输出:  None.
 **********************************************************************/
void WS2812_Digit_X_Y_8x6(uint8_t x_line,uint8_t y_line, uint8_t num);


/*********************************************************************
 * 功能:  WS2812_clear_xy_num()
 *
 * 注解:  x_line : x坐标 0-15   y_line:  y坐标 0-15 : 清除n 列
 *
 * 输入:  None.
 *
 * 输出:  None.
 **********************************************************************/
void WS2812_clear_xy_num(uint8_t x_line,uint8_t y_line, uint8_t n);


/*********************************************************************
 * 功能:  WS2812_MediateDisplayNum()
 *
 * 注解:  居中显示 2位数字
 *
 * 输入:  显示 num 楼层数 0-99
 *
 * 输出:  None.
 **********************************************************************/
void WS2812_MediateDisplayNum( uint8_t num);

/*********************************************************************
 * 功能:  SW2811_DisplayUP()
 *
 * 注解:  向上移动
 *
 * 输入:  x_line : x坐标 0-15   y_line:  y坐标 0-15
 *
 * 输出:  None.
 **********************************************************************/
void SW2811_DisplayUP(uint8_t x_line,uint8_t y_line, uint8_t num);

/*********************************************************************
 * 功能:  WS2812_displayWay()
 *
 * 注解:  电梯方向处理函数
 *
 * 输入:  None.
 *
 * 输出:  None.
 **********************************************************************/
void WS2812_displayWay(void);

/*********************************************************************
 * 功能:  SW2811_Init()
 *
 * 注解:  WS2812_初始化
 *
 * 输入:  None.
 *
 * 输出:  None.
 **********************************************************************/
void WS2812_Init(void);

代码展示

void WS2812_Digit_X_Y_8x8(uint8_t x_line,uint8_t y_line, uint8_t num)
{
    uint16_t  i,j;
    uint8_t  *hanzi_tb;

	// 获取点阵状态
	hanzi_tb = &Digit8x8_tb[num][0];
	for( i = 0; i < 8; i++)
	{
        ctl_rgb.Status[i+x_line] &= ~(0x00FF<<y_line);
		ctl_rgb.Status[i+x_line] |= (uint16_t)hanzi_tb[i]<<(y_line);
	}
}


void WS2812_Digit_X_Y_8x6(uint8_t x_line,uint8_t y_line, uint8_t num)
{
    uint16_t  i,j;
    uint8_t  *hanzi_tb;
	uint16_t  temp;

	// 获取点阵状态
	hanzi_tb = &Digit8x6_tb[num][0];
	for( i = 0; i < 6; i++)
	{
        ctl_rgb.Status[i+x_line] &= ~(0x00FF<<y_line);
        temp = (uint16_t)hanzi_tb[i]<<y_line;
		ctl_rgb.Status[i+x_line] |= temp;
	}

    // 更新颜色
	for(i = 0; i < 6; i++)
    {
        for(j = 0; j < 8; j++)
        {
            if(y_line<8)
            {
				ctl_rgb.ColourID[((i+x_line)<<4) + y_line+j] = 15;
            }
            else
            {
				ctl_rgb.ColourID[((i+x_line)<<4) + 8+j] = 15;
            }
        }
    }
}

void WS2812_clear_xy_num(uint8_t x_line,uint8_t y_line, uint8_t n)
{
    uint16_t  i;
	// 获取点阵状态
	for( i = 0; i < n; i++)
	{
        ctl_rgb.Status[i+x_line] &= ~(0x00FF<<y_line);
	}
}

void WS2812_MediateDisplayNum( uint8_t num)
{
	uint8_t shi;
    uint8_t ge;

	if(num>99) return;

	shi = num/10;
	ge  = num%10;

	if(num < 10)
    {
        WS2812_clear_xy_num(0,8,16);
		WS2812_Digit_X_Y_8x6(6,9,ge);  // 显示
    }
    else
    {
		WS2812_Digit_X_Y_8x6(3,9,shi);
        WS2812_Digit_X_Y_8x6(9,9,ge);
    }
}

void SW2811_DisplayUP(uint8_t x_line,uint8_t y_line, uint8_t num)
{
    uint16_t  i;
    uint8_t  *hanzi_tb;
    uint16_t  temp;

	if(Displayoffset>7) Displayoffset = 0;


	hanzi_tb = &Digit8x6_tb[num][0];
	for( i = 0; i < 6; i++)
	{
        ctl_rgb.Status[i+x_line] &= ~(0x00FF<<y_line);
        temp = ((uint16_t)hanzi_tb[i]<<8)+hanzi_tb[i];
		ctl_rgb.Status[i+x_line] |= (uint8_t)((temp<<y_line) >> Displayoffset);
	}
    // 向上移屏
    Displayoffset  += 1;
}

void WS2812_displayWay( void)
{
	//WS2812_Digit_X_Y_8x6(6,0,10);
	SW2811_DisplayUP(6,0,10);
}

/*********************************************************************
 * 功能:  display_handle()
 *
 * 注解:  显示处理函数
 *
 * 输入:  None.
 *
 * 输出:  None.
 **********************************************************************/
void display_handle(void)
{
	if(timer0_count >= 5)
    {   // 100ms cycle
		timer0_count = 0;

		// 100ms 轮询1次
        //HanZi_DisplayLeft();
		time_count++;
        if(time_count>=8)
        {
            time_count = 0;
			floor_level ++;
	        if(floor_level > 33)
	        {
				floor_level = 0;
	        }
			WS2812_MediateDisplayNum(floor_level);  // 显示楼层数字
        }

        WS2812_displayWay();  // 显示箭头方向
    }
}
/*********************************************************************
 * 功能:  display_run()
 *
 * 注解:  显示刷新函数 timer0_OutTime_Flag 20 ms周期
 *
 * 输入:  None.
 *
 * 输出:  None.
 **********************************************************************/
void display_run(void)
{
    uint16_t xdata i;
	uint8_t xdata r_Data;
	uint8_t xdata g_Data;
	uint8_t xdata b_Data;
    uint8_t xdata data1,data2;

    if(timer0_OutTime_Flag)
    {   // 20ms cycle
        timer0_OutTime_Flag  = 0;
		//uart_printf("20ms cycle");

		WS2812_16x16Refresh();  // 刷新显示

		if(COM1.RX_TimeOut > 0)		// uart rx
		{
			if(--COM1.RX_TimeOut == 0)
			{
                uart_rx_handle(RX1_Buffer,COM1.RX_Cnt);
				COM1.RX_Cnt = 0;
			}
		}
    }
}

显示处理函数和显示刷新函数 中,timer0_count和timer0_OutTime_Flag 是定时器0中断 以20ms为周期的
/********************* Timer0中断函数************************/
void timer0_int (void) interrupt TIMER0_VECTOR
{
timer0_OutTime_Flag = 1;
timer0_count ++;
}

小结

电梯楼层指示屏程序开发,还挺考验程序员逻辑思维的,这里需要掌握以下3方面知识:①学会显示字体进行取模 ②C语言功底要好,学会C语言拼字、组合、位运算等 ③ 需要构造不同需求的函数接口,如在x和y坐标显示数字。以上是主要电梯楼层指示屏程序,对此您有何评论?

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小武编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值