74HC595驱动点阵屏(24_24)

项目开发中遇到的问题:

1、上电瞬间点阵屏显示乱码问题:

猜测:由于BK3431Q芯片加电时所有I/O为高电平,加电时可能595上电比BK3431Q快,所以上电被认为是一个正脉冲跳变,结果595内部的寄存器初始值被输出,网上看论坛别人给出的解决方案如下:
1.试试RCK反相后再进595,这样BK3431Q上电时的脉冲反相后成为负的,使595不输出.
2.OE用单片机I/O控制,由于上电时BK3431Q为高电平,所以无输出,然后程序控制595输出.
3.加大C26的值,让595的OE输出比51复位慢.

加粗的是本人采用的解决办法

硬件电路图:

74HC595驱动点阵屏(24_24)_第1张图片

点阵屏是在网上购置的现成的32*32的点阵改的24*24,行低电平灯亮,列高电平灯亮(由于列用到了MOS管反向,实际控制中单片机的相应位送低电平)

由于硬件上的限制,此点阵屏只能列扫描,mos管才能发挥作用,如若用行扫描,led灯显示亮度会很弱

74HC595驱动点阵屏(24_24)_第2张图片

 

字模取模方式如下图所示:

74HC595驱动点阵屏(24_24)_第3张图片

74hc595Led.c源代码:

#include "gpio.h"
#include "74hc595Led.h"
#include "BK3435_reg.h"
#include "uart.h"
#include "app_task.h" 

#define HC595_SH_CLK    0X13    //74HC595的时钟
#define HC595_DS_DATA   0X33    //74HC595的数据
#define HC595_ST_LATCH  0x12    //74HC595的锁存

#define SCL_HIGH()        gpio_set(HC595_SH_CLK,1)
#define SCL_LOW()         gpio_set(HC595_SH_CLK,0)
#define SDA_HIGH()        gpio_set(HC595_DS_DATA,1)
#define SDA_LOW()         gpio_set(HC595_DS_DATA,0)
#define LATCH_HIGH()      gpio_set(HC595_ST_LATCH,1)
#define LATCH_LOW()       gpio_set(HC595_ST_LATCH,0)

#define SDA_SetInput()	  gpio_config(HC595_DS_DATA,INPUT,PULL_NONE)
#define SDA_SetOutput()   gpio_config(HC595_DS_DATA,OUTPUT,PULL_NONE)
#define SDA_READ()        gpio_get_input(HC595_DS_DATA)

bool StartDelayFlag = 0;   // 1表示延时  0 表示不延时
DisplayTag DisplayTagFlag = NoFlag;
//uint8_t TempBuf[48] = {0};
bool DisplayModeChangeFlag = 0;
DisplayContent DisplayBuf[ARRAY_RANK_NUM] =
{
	{
		RIGHT2LEFT_COLUMN_SCAN_DISPLAY_MODE,
		5,
		0x01,
		#if 1
		{0x00,0x00,0x00,0x00,0x00,0x08,0x00,0xE1,0x8C,0x01,0x23,0x88,0x06,0x25,0x18,0x38,
		0x59,0x10,0x10,0x61,0x10,0x01,0xC2,0x20,0x01,0x82,0x20,0x01,0x00,0x20,0x03,0xFF,
		0xFE,0x01,0xFF,0xFE,0x01,0x00,0x40,0x01,0x01,0x80,0x01,0x06,0x00,0x3F,0xFC,0x00,
		0x3E,0x08,0x00,0x01,0x0C,0x00,0x01,0x07,0x04,0x01,0x03,0x06,0x03,0xFF,0xFE,0x03,
		0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x00}/*"纳",0*/
		/* (24 X 24 , 宋体 ) */
		#else
		
		{0x40,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}/*"未命名文件",0*/
		/* (24 X 24 ) */
		#endif
	},
	{
		DOWN2UP_LINE_SCAN_DISPLAY_MODE,
		5,
		0x1,
		{0x00,0x00,0x00,0x00,0x00,0x80,0x01,0x01,0x00,0x01,0x06,0x00,0x21,0x08,0x00,0x1D,
		0x3F,0xFE,0x09,0xF0,0x00,0x03,0x98,0x00,0x01,0x0E,0x00,0x01,0x00,0x80,0x01,0x10,
		0x80,0x21,0x10,0x80,0x19,0x10,0x80,0x1D,0x10,0x80,0x01,0xFF,0xFE,0x01,0xFF,0xFE,
		0x06,0x10,0x80,0x19,0x10,0x80,0x31,0x10,0x80,0x21,0x30,0x80,0x02,0x11,0x00,0x00,
		0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00}/*"祥",0*/
		/* (24 X 24 , 宋体 ) */
	},
	{
		UP2DOWN_LINE_SCAN_DISPLAY_MODE,
		5,
		0x01,
		{0x00,0x00,0x00,0x00,0x00,0x20,0x08,0x40,0x40,0x08,0x41,0x80,0x08,0x46,0x00,0x08,
		0x5C,0x00,0x1F,0xFF,0xFE,0x1F,0xFF,0xFE,0x10,0x48,0x00,0x30,0x8C,0x00,0x10,0x86,
		0x80,0x00,0x00,0x80,0x00,0x20,0x80,0x04,0x10,0x80,0x03,0x1C,0x80,0x03,0x01,0x00,
		0x00,0x01,0x00,0x00,0x01,0x00,0x3F,0xFF,0xFE,0x20,0x01,0x00,0x00,0x02,0x00,0x00,
		0x06,0x00,0x00,0x02,0x00,0x00,0x00,0x00}/*"科",0*/
		/* (24 X 24 , 宋体 ) */	
	},
	{
		LEFT2RIGHT_COLUMN_SCAN_DISPLAY_MODE,
		5,
		0x01,
		{0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x00,0x01,0x04,0x04,0x01,0x04,0x06,0x7F,
		0xFF,0xFE,0x3F,0xFF,0xFC,0x21,0x08,0x00,0x02,0x10,0x02,0x02,0x10,0x02,0x01,0x10,
		0x02,0x01,0x10,0x04,0x01,0x1C,0x08,0x01,0x13,0x08,0x01,0x10,0xD0,0x3F,0xF0,0x30,
		0x21,0x10,0x70,0x01,0x11,0xC8,0x01,0x17,0x0C,0x01,0x1C,0x04,0x02,0x10,0x06,0x02,
		0x00,0x06,0x00,0x00,0x04,0x00,0x00,0x00}/*"技",0*/
		/* (24 X 24 , 宋体 ) */
	}
};

uint8_t Mould[3];  	    //控制该列的取模值,低电平亮灯,每个模组16行,占2字节   //行
uint8_t upright[3];		//控制某一列,高电平亮灯,每个模组16列,占2字节     //列
uint8_t LED2X64[LED2X64LEN] = {0};		//开辟缓存空间,被定时器随时调用。每列两个字节,多加2个用于移位操作。
uint8_t DisplayTotal =0;      //根据APP 发过来的数据随时改变
uint8_t CharDisplayInd1 = 0;  //记录汉字索引
uint8_t CharDisplayInd2 = 0;  //记录汉字点阵索引
ScanDisplay StartDisplayFlag = NoScan;
uint8_t DelayDisplayNextNUM = 0;
uint8_t DelayDisplayNextNumLimit = 0;

//======================================================================================
//发送数据到595芯片
//======================================================================================
void HC595WriteLineScan(void)				//74HC595发送数据。行用来扫描
{
	uint8_t i,j=1;
	static uint8_t DisplayInd_1 = 0;	
	static uint32_t kkk_1=0x1;				    //用于16行轮流控制  这个初始值决定从哪一行开始扫描

	//Mould[3]=~LED2X64[DisplayInd_1+3];	  //i=0,把缓存的第01号字节发送到第一个模组的最右边的8位。
	Mould[2]=~LED2X64[DisplayInd_1+2];
	Mould[1]=~LED2X64[DisplayInd_1+1];		  //i=0,把缓存的第01号字节发送到第一个模组的最右边的8位。
	Mould[0]=~LED2X64[DisplayInd_1+0];		  //i=0,把缓存的第00号字节发送到第一个模组的最左边的8位。

	//upright[3]=~((kkk_1>>24)&0xff);
	upright[2]=~((kkk_1>>16)&0xff);
	upright[1]=~((kkk_1>>8)&0xff);					//16位变量KKK,取高8位。控制第一个模组的0~7行。
	upright[0]=~(kkk_1&0xff);						//16位变量KKK,取低8位。控制第一个模组的8~15行。

	//循环控制0~16行
	if(kkk_1&0x800000)
	kkk_1 = (kkk_1<<1)|0x01;
	else
	kkk_1 = (kkk_1<<1);
	
	DisplayInd_1+=3;
	DisplayInd_1=DisplayInd_1%72;

	SDA_HIGH();
	SCL_HIGH();
	LATCH_LOW();

	for(i=0;i<8;i++)					//发送给每个模组的 U4 ,低电平整行可以亮,高电平整行全灭。
	{
		SCL_LOW();
		//if (Mould[j*3-3]&0x80)
		if (Mould[j*3-3]&0x01)
			SDA_HIGH();
		else
			SDA_LOW();
		//Mould[j*3-3]<<=1;
		Mould[j*3-3]>>=1;
		SCL_HIGH();
	}
	for(i=0;i<8;i++)					//发送给每个模组的 U3 ,低电平整行可以亮,高电平整行全灭。
	{
		SCL_LOW();
		//if (Mould[j*3-2]&0x80)
		if (Mould[j*3-2]&0x01)
			SDA_HIGH();
		else
			SDA_LOW();
		//Mould[j*3-2]<<=1;
		Mould[j*3-2]>>=1;
		SCL_HIGH();
	}
	for(i=0;i<8;i++)					//发送给每个模组的 U4 ,低电平整行可以亮,高电平整行全灭。
	{
		SCL_LOW();
		//if (Mould[j*3-1]&0x80)
		if (Mould[j*3-1]&0x01)
			SDA_HIGH();
		else
			SDA_LOW();
		//Mould[j*3-1]<<=1;
		Mould[j*3-1]>>=1;
		SCL_HIGH();
	}

	for(i=0;i<8;i++) 					//发送给每个模组的 U2 ,高电平整列可以亮,低电平整列灭。
	{
		SCL_LOW();					    //时钟拉低
		//if(upright[j*3-1]&0x1)         //从最后一个字节开始,先高位后低位。
		if(upright[j*3-1]&0x80) 
			SDA_HIGH();
		else
			SDA_LOW();
		//upright[j*3-1]>>=1;				//字节左移
		upright[j*3-1]<<=1;
		SCL_HIGH();						//时钟上升沿拷贝
	}
	
	for(i=0;i<8;i++)					//发送给每个模组的 U1 ,高电平整列可以亮,低电平整列灭。
	{
		SCL_LOW();
		//if (upright[j*3-2]&0x1)   //先送低位
		if (upright[j*3-2]&0x80)
			SDA_HIGH();
		else
		SDA_LOW();
		//upright[j*3-2]>>=1;
		upright[j*3-2]<<=1;
		SCL_HIGH();	
	}
	for(i=0;i<8;i++) 					//发送给每个模组的 U2 ,高电平整列可以亮,低电平整列灭。
	{
		SCL_LOW();					    //时钟拉低
		//if(upright[j*3-3]&0x1)         //从最后一个字节开始,先高位后低位。
		if(upright[j*3-3]&0x80)
			SDA_HIGH();
		else
			SDA_LOW();
		//upright[j*3-3]>>=1;				//字节左移
		upright[j*3-3]<<=1;	
		SCL_HIGH();						//时钟上升沿拷贝
	}
	
	LATCH_HIGH();						//锁存脉冲信号,上升沿。
	SDA_HIGH();							//延时
	LATCH_LOW();						//锁存脉冲信号复位。
}


void HC595WriteColumnScan(void)   //74HC595发送数据。列用来扫描
{
	uint8_t i,j=1;
	static uint8_t DisplayInd = 0;	
	static uint32_t kkk=0x800000;				//用于16列轮流控制

	//Mould[3]=~LED2X64[DisplayInd+3];        //DisplayInd=0,把缓存的第03号字节发送到最左边的上8位。
	Mould[2]=~LED2X64[DisplayInd+2];
	Mould[1]=~LED2X64[DisplayInd+1];		
	Mould[0]=~LED2X64[DisplayInd+0];		//DisplayInd=0,把缓存的第00号字节发送到最左边的上8位。


//每个都取反是因为硬件有MOS管反向
//	upright[3]=~((kkk>>24)&0xff);      //取高8位。控制的0~7列。
	upright[2]=~((kkk>>16)&0xff);         
	upright[1]=~((kkk>>8)&0xff);
	upright[0]=~(kkk&0xff);			//取低8位。控制24~31列。

	//循环控制0~31列
	if(kkk&0x1)
	kkk = (kkk>>1)|0x800000;
	else
	kkk = (kkk>>1);
	
	DisplayInd+=3;
	DisplayInd=DisplayInd%72;

	SDA_HIGH();
	SCL_HIGH();
	LATCH_LOW();
	
	for(i=0;i<8;i++) 			    //发送给每个模组的 U7 ,高电平整列可以亮,低电平整列灭。
	{
		SCL_LOW();					//时钟拉低
		if(upright[j*3-1]&0x80)      //先高位后低位。
			SDA_HIGH();
		else
			SDA_LOW();
		upright[j*3-1]<<=1;			//字节左移
		SCL_HIGH();					//时钟上升沿拷贝
	}
	for(i=0;i<8;i++)				//发送给每个模组的 U6 ,高电平整列可以亮,低电平整列灭。
	{
		SCL_LOW();
		if (upright[j*3-2]&0x80)
			SDA_HIGH();
		else
			SDA_LOW();
		upright[j*3-2]<<=1;
		SCL_HIGH();	
	}
	for(i=0;i<8;i++)		//发送给每个模组的 U5,高电平整列可以亮,低电平整列灭。
	{
		SCL_LOW();
		if (upright[j*3-3]&0x80)
			SDA_HIGH();
		else
			SDA_LOW();
		upright[j*3-3]<<=1;
		SCL_HIGH();	
	}

	
	for(i=0;i<8;i++)    //发送给每个模组的 U3 ,低电平整行可以亮,高电平整行全灭。
	{
		SCL_LOW();
		//if (Mould[j*3-1]&0x80)
		if (Mould[j*3-1]&0x1)
			SDA_HIGH();
		else
		SDA_LOW();

		//Mould[j*3-1]<<=1;
		Mould[j*3-1]>>=1;
		SCL_HIGH();
	}
	for(i=0;i<8;i++)   //发送给每个模组的 U2 ,低电平整行可以亮,高电平整行全灭。
	{
		SCL_LOW();
		//if (Mould[j*3-2]&0x80)
		if (Mould[j*3-2]&0x1)
			SDA_HIGH();
		else
			SDA_LOW();
		//Mould[j*3-2]<<=1;
		Mould[j*3-2]>>=1;
		SCL_HIGH();
	}
	for(i=0;i<8;i++)	   //发送给每个模组的 U1 ,低电平整行可以亮,高电平整行全灭。						
	{
		SCL_LOW();
		//if (Mould[j*3-3]&0x80)
		if (Mould[j*3-3]&0x1)
			SDA_HIGH();
		else
			SDA_LOW();
		//Mould[j*3-3]<<=1;
		Mould[j*3-3]>>=1;
		SCL_HIGH();
	}

	LATCH_HIGH();									//锁存脉冲信号,上升沿。
	SDA_HIGH();									//延时
	LATCH_LOW();	
}

/*************************************
* 闪烁模式:有小变大,有大变小 右移、右移 、下飘、上移
*时间
*************************************/
void WjInitDisplayContent(void)
{
	uint8_t i;
	
}

void WjClearDisplay(void)
{
	uint8_t i;
	//清理显示缓冲区
	for(i=0;i= DelayDisplayNextNumLimit)
	{	
		DelayDisplayNextNUM = 0;
		StartDelayFlag = 0;
		if (CharDisplayInd1 == 0)   //说明是最后一个 中间延时一会重新开始显示
		{
			DisplayTagFlag = EndFlag; 
		}
		DisplayBuf[3] = DisplayBuf[0];
	}
}
//检测下一帧数据,由于连续向左、向右、向上、向下函数调用
static void WjSeriesDisplayDetectNextFrame(void)
{
	uint8_t i;
	switch(DisplayBuf[3].Mode)
	{
		case SERIES_RIGHT_SHIFT_DISPLAY_MODE:
			for(i=LED2X64LEN-1;i>2;i--)  //每次调用函数时让TransformObjBuf数组里面的数据循环右移一列赋值给LED2X64数组
			{
				LED2X64[i] = LED2X64[i-3];
			}
			//UART_PRINTF("#####wj -->>StartDelayFlag = %d\r\n",StartDelayFlag);
			if (!StartDelayFlag)
			{
				LED2X64[i-2] = DisplayBuf[3].DisplayBuf[ARRAY_ROW_NUM-1-CharDisplayInd2-2];       //i = 1   -->>1
				LED2X64[i-1] = DisplayBuf[3].DisplayBuf[ARRAY_ROW_NUM-1-CharDisplayInd2-1];   //i = 1;  -->>0
				LED2X64[i] = DisplayBuf[3].DisplayBuf[ARRAY_ROW_NUM-1-CharDisplayInd2];       //i = 1   -->>1
				CharDisplayInd2 += 3;
			}
			else
			{
				LED2X64[i-2] = 0x0;
				LED2X64[i-1] = 0x0;
				LED2X64[i] = 0x0;
			}	
			break;
	
		case SERIES_LEFT_SHIFT_DISPLAY_MODE:
			for(i=0;i>StartDelayFlag = %d\r\n",StartDelayFlag);
			if(!StartDelayFlag)
			{
				LED2X64[i]   = DisplayBuf[3].DisplayBuf[CharDisplayInd2];
				LED2X64[i+1] = DisplayBuf[3].DisplayBuf[CharDisplayInd2+1];
				LED2X64[i+2] = DisplayBuf[3].DisplayBuf[CharDisplayInd2+2];
				CharDisplayInd2 += 3;
			}
			else
			{
				LED2X64[i+2] = 0x0;
				LED2X64[i+1] = 0x0;
				LED2X64[i] = 0x0;
			}
			break;
		default:
			break;
	}
	
	if (CharDisplayInd2 >=ARRAY_ROW_NUM)   //一个汉字显示完毕,进入下一个汉字赋值
	{
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
		}
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);
		if ((DisplayBuf[3].Mode == DisplayBuf[0].Mode)&&(CharDisplayInd1 != 0))
		{
			DelayDisplayNextNumLimit = SERIES_DISPLAY_DELAY_NEXT_CHAR_NUM;
		}
		else
		{
			DelayDisplayNextNumLimit = DISORDER_DISPLAY_DELAY_NEXT_CHAR_NUM;
		}
		//开启调用延时函数
		StartDelayFlag = 1;
		DelayDisplayNextNUM = 0;
		
	}	
}
void WjNoDisplay(void)
{
	memset(LED2X64,0,ARRAY_ROW_NUM);
	CharDisplayInd1++;
	DisplayTagFlag = MidFlag;
	if (CharDisplayInd1 >= DisplayTotal)   //闪到最后一个汉字接着闪第一个
	{
			//开启调用延时函数,最后一个到第一个的显示时间拉长一点
		CharDisplayInd1 = 0;
	}
	flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);

	//uart_send(DisplayBuf[0].DisplayBuf,128);
	if(DisplayBuf[3].Mode!= DisplayBuf[0].Mode) 	//在这里判断如果显示模式变化。在进入下次调用模式切换时清除显示缓冲
	{
		DisplayModeChangeFlag = 1;
		DisplayBuf[3] = DisplayBuf[0];
	}
	
}
void WjStaticDisplay(void)
{
	static bool flag = 0;
	
	//if (!flag)
	{
		DisplayBuf[3] = DisplayBuf[0];

		memcpy(LED2X64,DisplayBuf[3].DisplayBuf,ARRAY_ROW_NUM);
		CharDisplayInd1++;
		DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)   //闪到最后一个汉字接着闪第一个
		{
			//开启调用延时函数,最后一个到第一个的显示时间拉长一点
			CharDisplayInd1 = 0;
		}
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);

		//uart_send(DisplayBuf[0].DisplayBuf,128);
		if(DisplayBuf[3].Mode!= DisplayBuf[0].Mode) 	//在这里判断如果显示模式变化。在进入下次调用模式切换时清除显示缓冲
		{
			DisplayModeChangeFlag = 1;
			DisplayBuf[3] = DisplayBuf[0];
		}
	}
	/*
	else //解决相同两个字连着显示看不出闪烁效果
	{
		memset(LED2X64,0,LED2X64LEN);
	}
	 flag = !flag;
	*/
}

//Elem:需要移位的数组
// sum: 数组的大小
// k : 需要移位的位数

//uint8_t Tempbuf[3] = {0x00,0xE1,0x8C};
static uint8_t WjBitLeftShiftElem(uint8_t * Elem,uint8_t Sum,uint8_t k)  //循环上移中调用
{
	uint8_t i;
	//exceedB: 本元素溢出值
	//exceedA: 上一元素溢出值
	uint8_t exceedA=0,exceedB=0;
	char Msk=0;  //用于计算溢出位的掩码,如k=6时,其掩码值为00000011(二进制)
	for (i=0;i<8-k;i++)
	{
		Msk=Msk|(1<0;i--)
	{
		exceedB=(Elem[i-1]&(~Msk))>>(8-k);//计算溢出数据
		Elem[i-1]=(Elem[i-1]<>k)|exceedA;
		//UART_PRINTF("Elem[%d] = 0X%x\r\n",i-1,Elem[i]);
		exceedA=(exceedB<<(8-k));
	}

	return exceedA;
}
//连续向左向右平移
void WjSeriesLeftRightShiftDisplay(void)
{

	//UART_PRINTF("#####wj CharDisplayInd2 = %d StartDelayFlag = %d\r\n",CharDisplayInd2 ,StartDelayFlag);
	if((CharDisplayInd2 == 0)&&(!StartDelayFlag))
	{
		DisplayBuf[3] = DisplayBuf[0];
		//UART_PRINTF("------------->>FUZHI_1");
	}

	WjSeriesDisplayDetectNextFrame();
}

//连续向上平移
void WjSeriesUpShiftDisplay(void)
{
	uint8_t i;
	
	for (i = 0;i < 24; i++)
	{
		WjBitLeftShiftElem(&LED2X64[3*i],3,1);
	}
	if (!StartDelayFlag)
	{
		for(i = 0;i< 24;i++)
		{	
			LED2X64[3*i+2] = LED2X64[3*i+2]|(WjBitLeftShiftElem (&DisplayBuf[3].DisplayBuf[3*i],3,1));
		}
		
		CharDisplayInd2 += 3;
	}
	
	if (CharDisplayInd2 >=  ARRAY_ROW_NUM/*+2*/)
	{
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		//DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
		}
		//UART_PRINTF("######wj CharDisplayInd1 = %d\r\n",CharDisplayInd1);
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);

		
		if ((DisplayBuf[3].Mode == DisplayBuf[0].Mode)&&(CharDisplayInd1 != 0))
		{
			DelayDisplayNextNumLimit = SERIES_DISPLAY_DELAY_NEXT_CHAR_NUM;
		}
		else
		{
			DelayDisplayNextNumLimit = DISORDER_DISPLAY_DELAY_NEXT_CHAR_NUM;
		}
		//开启调用延时函数
		StartDelayFlag = 1;
		DelayDisplayNextNUM = 0;
		
	}
}

//连续向下平移	
void WjSeriesDownShiftDisplay()
{
	uint8_t i;
	
	for (i = 0;i < 24; i++)
	{
		WjBitRightShiftElem(&LED2X64[3*i],3,1);
	}
	if (!StartDelayFlag)
	{
		for(i = 0;i< 24;i++)
		{	
			LED2X64[3*i] = LED2X64[3*i]|(WjBitRightShiftElem (&DisplayBuf[3].DisplayBuf[3*i],3,1));
		}
		
		CharDisplayInd2 += 3;
	}
	
	if (CharDisplayInd2 >=  ARRAY_ROW_NUM/*+2*/)
	{
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		//DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
		}
		//UART_PRINTF("######wj CharDisplayInd1 = %d\r\n",CharDisplayInd1);
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);

		
		if ((DisplayBuf[3].Mode == DisplayBuf[0].Mode)&&(CharDisplayInd1 != 0))
		{
			DelayDisplayNextNumLimit = SERIES_DISPLAY_DELAY_NEXT_CHAR_NUM;
		}
		else
		{
			DelayDisplayNextNumLimit = DISORDER_DISPLAY_DELAY_NEXT_CHAR_NUM;
		}
		//开启调用延时函数
		StartDelayFlag = 1;
		DelayDisplayNextNUM = 0;
		
	}
}

//向左平移
void WjLeftShiftDisplay(void)
{
	uint8_t i;
	
	for(i=0;i>StartDelayFlag = %d\r\n",StartDelayFlag);
	if (CharDisplayInd2 < ARRAY_ROW_NUM)    //
	{
		LED2X64[i]   = DisplayBuf[3].DisplayBuf[CharDisplayInd2];
		LED2X64[i+1] = DisplayBuf[3].DisplayBuf[CharDisplayInd2+1];
		LED2X64[i+2] = DisplayBuf[3].DisplayBuf[CharDisplayInd2+2];
	}
	else
	{
		LED2X64[i] = 0;
		LED2X64[i+1] = 0;
		LED2X64[i+2] = 0;
	}
	CharDisplayInd2 += 3;
	//UART_PRINTF("###### --->> CharDisplayInd2 = %d\r\n",CharDisplayInd2);
	if (CharDisplayInd2 >=ARRAY_ROW_NUM/*+2*/)   //一个汉字显示完毕,进入下一个汉字赋值
	{
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
			//DisplayTagFlag = EndFlag;
		}
		//UART_PRINTF("###### --->>CharDisplayInd1 = %d  CharDisplayInd2 = %d\r\n",CharDisplayInd1,CharDisplayInd2);
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);
		//if(DisplayBuf[3].Mode!= DisplayBuf[0].Mode) 	//在这里判断如果显示模式变化。在进入下次调用模式切换时清除显示缓冲
		{
			DisplayModeChangeFlag = 1;  //该种不管模式切不切,每次都需要这个变量等于1去清屏
			DisplayBuf[3] = DisplayBuf[0];   //20180716
		}
	}
	
}
//向右平移
void WjRightShiftDisplay(void)
{
	uint8_t i;
	
	for(i=LED2X64LEN-1;i>2/*1*/;i--)  //每次调用函数时让TransformObjBuf数组里面的数据循环右移一列赋值给LED2X64数组
	{
		LED2X64[i]= LED2X64[i-3];
	}
	
	LED2X64[i-2] = DisplayBuf[3].DisplayBuf[/*31*/71-CharDisplayInd2-2];   //i = 1;  -->>0
	LED2X64[i-1] = DisplayBuf[3].DisplayBuf[/*31*/71-CharDisplayInd2-1];   //i = 1;  -->>0
	LED2X64[i] = DisplayBuf[3].DisplayBuf[/*31*/71-CharDisplayInd2];       //i = 1   -->>1
	CharDisplayInd2 += 3;

	if (CharDisplayInd2 >=ARRAY_ROW_NUM)   //一个汉字显示完毕,进入下一个汉字赋值
	{
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
			//DisplayTagFlag = EndFlag;
		}
		//UART_PRINTF("###### --->>CharDisplayInd1 = %d  CharDisplayInd2 = %d\r\n",CharDisplayInd1,CharDisplayInd2);
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);
		//if(DisplayBuf[3].Mode!= DisplayBuf[0].Mode) 	//在这里判断如果显示模式变化。在进入下次调用模式切换时清除显示缓冲
		{
			DisplayModeChangeFlag = 1;  //该种不管模式切不切,每次都需要这个变量等于1去清屏
			DisplayBuf[3] = DisplayBuf[0];   //20180716
		}
	}
}

//向上平移
void WjUpShiftDisplay(void)
{
	uint8_t i;

	for (i = 0;i < 24; i++)
	{
		WjBitLeftShiftElem(&LED2X64[3*i],3,1);
	}

	for(i = 0;i< 24;i++)
	{	
		LED2X64[3*i+2] = LED2X64[3*i+2]|(WjBitLeftShiftElem (&DisplayBuf[3].DisplayBuf[3*i],3,1));
	}
	
	CharDisplayInd2 += 3;

	if (CharDisplayInd2 >=  ARRAY_ROW_NUM/*+2*/)
	{
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
		}
		//UART_PRINTF("######wj CharDisplayInd1 = %d\r\n",CharDisplayInd1);
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);
		//if(DisplayBuf[3].Mode!= DisplayBuf[0].Mode) 	//在这里判断如果显示模式变化。在进入下次调用模式切换时清除显示缓冲
		{
			DisplayModeChangeFlag = 1;  //该种不管模式切不切,每次都需要这个变量等于1去清屏
			DisplayBuf[3] = DisplayBuf[0];   //20180716
		}	
	}
}

//向下平移
void WjDownShiftDisplay(void)
{
	uint8_t i;

	for (i = 0;i < 24; i++)
	{
		WjBitRightShiftElem(&LED2X64[3*i],3,1);
	}

	for(i = 0;i< 24;i++)
	{	
		LED2X64[3*i] = LED2X64[3*i]|(WjBitRightShiftElem (&DisplayBuf[3].DisplayBuf[3*i],3,1));
	}
	
	CharDisplayInd2 += 3;

	if (CharDisplayInd2 >=  ARRAY_ROW_NUM/*+2*/)
	{
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
		}
		//UART_PRINTF("######wj CharDisplayInd1 = %d\r\n",CharDisplayInd1);
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);
		//if(DisplayBuf[3].Mode!= DisplayBuf[0].Mode) 	//在这里判断如果显示模式变化。在进入下次调用模式切换时清除显示缓冲
		{
			DisplayModeChangeFlag = 1;  //该种不管模式切不切,每次都需要这个变量等于1去清屏
			DisplayBuf[3] = DisplayBuf[0];   //20180716
		}	
	}
}

//左右对开
void WjLeftRightOpenDisplay(void)
{
	uint8_t i;
	static uint8_t LeftInd = ARRAY_ROW_NUM/2-1/*15*//*35*/;
	static uint8_t RightInd = ARRAY_ROW_NUM/2/*16*//*36*/;
	
	LED2X64[LeftInd] = DisplayBuf[3].DisplayBuf[LeftInd];
	LED2X64[RightInd]= DisplayBuf[3].DisplayBuf[RightInd];
	
	if(LeftInd > 0) 
		LeftInd--;
	RightInd++;

	for(i=LeftInd;i>0;i--)
	{
		LED2X64[i]= 0;
	}
	for(i = RightInd;i ARRAY_ROW_NUM)  //一个汉字显示结束
	{
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		LeftInd = ARRAY_ROW_NUM/2-1/*15*//*35*/;
		RightInd = ARRAY_ROW_NUM/2/*16*//*36*/;
		DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
			//DisplayTagFlag = EndFlag;
		}
		//UART_PRINTF("###### --->>CharDisplayInd1 = %d  CharDisplayInd2 = %d\r\n",CharDisplayInd1,CharDisplayInd2);
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);
		//if(DisplayBuf[3].Mode!= DisplayBuf[0].Mode) 	//在这里判断如果显示模式变化。在进入下次调用模式切换时清除显示缓冲
		{
			DisplayModeChangeFlag = 1;  //该种不管模式切不切,每次都需要这个变量等于1去清屏
			DisplayBuf[3] = DisplayBuf[0];   //20180716
		}
	}
}

//左右闭合
void WjLeftRightCloseDisplay(void)
{
	uint8_t i;
	static uint8_t LeftInd = 0;
	static uint8_t RightInd = ARRAY_ROW_NUM-1;

	LED2X64[LeftInd] = DisplayBuf[3].DisplayBuf[LeftInd];
	LED2X64[RightInd]= DisplayBuf[3].DisplayBuf[RightInd]; 
	
	LeftInd++;
	RightInd--;
	//UART_PRINTF("###### wj LeftInd = %d RightInd = %d \r\n",LeftInd,RightInd);
	CharDisplayInd2 = 1;  //在这里没有任何意思,只是表示正在给一个汉字描点
	if (LeftInd >= (ARRAY_ROW_NUM/2))  //一个汉字显示结束
	{
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		LeftInd = 0;
		RightInd = ARRAY_ROW_NUM-1;
		DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
			//DisplayTagFlag = EndFlag;
		}
		//UART_PRINTF("###### --->>CharDisplayInd1 = %d  CharDisplayInd2 = %d\r\n",CharDisplayInd1,CharDisplayInd2);
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);
		//if(DisplayBuf[3].Mode!= DisplayBuf[0].Mode) 	//在这里判断如果显示模式变化。在进入下次调用模式切换时清除显示缓冲
		{
			DisplayModeChangeFlag = 1;  //该种不管模式切不切,每次都需要这个变量等于1去清屏
			DisplayBuf[3] = DisplayBuf[0];   //20180716
		}
	}
	else
	{
		for(i=LeftInd;i>(ARRAY_ROW_NUM/2);i++)
		{
			LED2X64[i]= 0;
		}
		for(i = RightInd;i<(ARRAY_ROW_NUM/2);i--)
		{
			LED2X64[i]= 0;
		}
	}
	
}


//上下对开
void WjUpDownOpenDisplay(void)
{
	uint8_t i;
	static uint32_t LineMask= 0x001800;
	uint32_t TempValue = 0;
	for (i = 0;i < 24; i++)
	{
		TempValue = ((uint32_t)(DisplayBuf[3].DisplayBuf[3*i])<<16)|
			        ((uint32_t)(DisplayBuf[3].DisplayBuf[3*i+1])<<8)|
			        (uint32_t)(DisplayBuf[3].DisplayBuf[3*i+2]);	
		TempValue = LineMask&TempValue;
		LED2X64[3*i] = (uint8_t)(TempValue>>16);
		LED2X64[3*i+1] = (uint8_t)(TempValue>>8);
		LED2X64[3*i+2] = (uint8_t)(TempValue);
	}
	LineMask = (LineMask<<1)|(LineMask>>1);

	if (LineMask > 0xffffff)
	{
		LineMask = 0x001800;
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
			//DisplayTagFlag = EndFlag;
		}
		//UART_PRINTF("###### --->>CharDisplayInd1 = %d  CharDisplayInd2 = %d\r\n",CharDisplayInd1,CharDisplayInd2);
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);
		//if(DisplayBuf[3].Mode!= DisplayBuf[0].Mode) 	//在这里判断如果显示模式变化。在进入下次调用模式切换时清除显示缓冲
		{
			DisplayModeChangeFlag = 1;  //该种不管模式切不切,每次都需要这个变量等于1去清屏
			DisplayBuf[3] = DisplayBuf[0];   //20180716
		}
	}
}

void WjUpDownCloseDisplay(void)
{
	uint8_t i;
	static uint32_t LineMask= 0x800001;
	uint32_t TempValue = 0;
	for (i = 0;i < 24; i++)
	{
		TempValue = ((uint32_t)(DisplayBuf[3].DisplayBuf[3*i])<<16)|
			        ((uint32_t)(DisplayBuf[3].DisplayBuf[3*i+1])<<8)|
			        (uint32_t)(DisplayBuf[3].DisplayBuf[3*i+2]);	
		TempValue = LineMask&TempValue;
		LED2X64[3*i] = (uint8_t)(TempValue>>16);
		LED2X64[3*i+1] = (uint8_t)(TempValue>>8);
		LED2X64[3*i+2] = (uint8_t)(TempValue);
	}
	LineMask = LineMask|(0xffffff&(LineMask<<1))|(LineMask>>1);
	CharDisplayInd2+=6;
	//UART_PRINTF("LineMask = 0x%x   CharDisplayInd2 = %d\r\n",LineMask,CharDisplayInd2);
	if (CharDisplayInd2 > ARRAY_ROW_NUM)
	{
		LineMask = 0x800001;
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
			//DisplayTagFlag = EndFlag;
		}
		//UART_PRINTF("###### --->>CharDisplayInd1 = %d  CharDisplayInd2 = %d\r\n",CharDisplayInd1,CharDisplayInd2);
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);
		//if(DisplayBuf[3].Mode!= DisplayBuf[0].Mode) 	//在这里判断如果显示模式变化。在进入下次调用模式切换时清除显示缓冲
		{
			DisplayModeChangeFlag = 1;  //该种不管模式切不切,每次都需要这个变量等于1去清屏
			DisplayBuf[3] = DisplayBuf[0];   //20180716
		}
	}
}

//从左到右扫描显示
void WjLeft2RightScanDisplay(void)
{
	uint8_t i;
	
	LED2X64[CharDisplayInd2]  = DisplayBuf[3].DisplayBuf[CharDisplayInd2];
	LED2X64[CharDisplayInd2+1]= DisplayBuf[3].DisplayBuf[CharDisplayInd2+1];
	LED2X64[CharDisplayInd2+2]= DisplayBuf[3].DisplayBuf[CharDisplayInd2+2];
	CharDisplayInd2 += 3;

	if ((CharDisplayInd2 > ARRAY_ROW_NUM))  //一个汉字显示结束
	{
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
			//DisplayTagFlag = EndFlag;
		}
		//UART_PRINTF("###### --->>CharDisplayInd1 = %d  CharDisplayInd2 = %d\r\n",CharDisplayInd1,CharDisplayInd2);
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);
		//if(DisplayBuf[3].Mode!= DisplayBuf[0].Mode) 	//在这里判断如果显示模式变化。在进入下次调用模式切换时清除显示缓冲
		{
			DisplayModeChangeFlag = 1;  //该种不管模式切不切,每次都需要这个变量等于1去清屏
			DisplayBuf[3] = DisplayBuf[0];   //20180716
		}
	}
}
//从右到左扫描显示
void WjRight2LeftScanDisplay(void)
{
	uint8_t i;
	
	LED2X64[ARRAY_ROW_NUM - 1-CharDisplayInd2]= DisplayBuf[3].DisplayBuf[ARRAY_ROW_NUM - 1-CharDisplayInd2];
	LED2X64[ARRAY_ROW_NUM - 2-CharDisplayInd2]= DisplayBuf[3].DisplayBuf[ARRAY_ROW_NUM - 2-CharDisplayInd2];
	LED2X64[ARRAY_ROW_NUM - 3-CharDisplayInd2]= DisplayBuf[3].DisplayBuf[ARRAY_ROW_NUM - 3-CharDisplayInd2];
	CharDisplayInd2 += 3;

	if ((CharDisplayInd2 >= ARRAY_ROW_NUM))  //一个汉字显示结束
	{
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
			//DisplayTagFlag = EndFlag;
		}
		//UART_PRINTF("###### --->>CharDisplayInd1 = %d  CharDisplayInd2 = %d\r\n",CharDisplayInd1,CharDisplayInd2);
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);
		//if(DisplayBuf[3].Mode!= DisplayBuf[0].Mode) 	//在这里判断如果显示模式变化。在进入下次调用模式切换时清除显示缓冲
		{
			DisplayModeChangeFlag = 1;  //该种不管模式切不切,每次都需要这个变量等于1去清屏
			DisplayBuf[3] = DisplayBuf[0];   //20180716
		}
	}
}
//从上到下扫描显示
void WjUp2DownScanDisplay(void)
{
	uint8_t i;
	static uint32_t LineMask= 0x800000;
	uint32_t TempValue = 0;
	for (i = 0;i < 24; i++)
	{
		TempValue = ((uint32_t)(DisplayBuf[3].DisplayBuf[3*i])<<16)|
			        ((uint32_t)(DisplayBuf[3].DisplayBuf[3*i+1])<<8)|
			        (uint32_t)(DisplayBuf[3].DisplayBuf[3*i+2]);	
		TempValue = LineMask&TempValue;
		LED2X64[3*i] = (uint8_t)(TempValue>>16);
		LED2X64[3*i+1] = (uint8_t)(TempValue>>8);
		LED2X64[3*i+2] = (uint8_t)(TempValue);
	}
	CharDisplayInd2+=3;
	LineMask = LineMask|(LineMask>>1);

	if (CharDisplayInd2 > ARRAY_ROW_NUM)
	{
		LineMask = 0x800000;
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
			//DisplayTagFlag = EndFlag;
		}
		//UART_PRINTF("###### --->>CharDisplayInd1 = %d  CharDisplayInd2 = %d\r\n",CharDisplayInd1,CharDisplayInd2);
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);
		//if(DisplayBuf[3].Mode!= DisplayBuf[0].Mode) 	//在这里判断如果显示模式变化。在进入下次调用模式切换时清除显示缓冲
		{
			DisplayModeChangeFlag = 1;  //该种不管模式切不切,每次都需要这个变量等于1去清屏
			DisplayBuf[3] = DisplayBuf[0];   //20180716
		}
	}
}
void WjDown2UpScanDisplay(void)
{
	uint8_t i;
	static uint32_t LineMask= 0x1;
	uint32_t TempValue = 0;
	for (i = 0;i < 24; i++)
	{
		TempValue = ((uint32_t)(DisplayBuf[3].DisplayBuf[3*i])<<16)|
			        ((uint32_t)(DisplayBuf[3].DisplayBuf[3*i+1])<<8)|
			        (uint32_t)(DisplayBuf[3].DisplayBuf[3*i+2]);	
		TempValue = LineMask&TempValue;
		LED2X64[3*i] = (uint8_t)(TempValue>>16);
		LED2X64[3*i+1] = (uint8_t)(TempValue>>8);
		LED2X64[3*i+2] = (uint8_t)(TempValue);
	}
	CharDisplayInd2+=3;
	LineMask = LineMask|(LineMask<<1);

	if (CharDisplayInd2 > ARRAY_ROW_NUM)
	{
		LineMask = 0x1;
		CharDisplayInd1++;
		CharDisplayInd2 = 0;
		DisplayTagFlag = MidFlag;
		if (CharDisplayInd1 >= DisplayTotal)  //已经是最后一个汉字了
		{
			CharDisplayInd1 = 0;  //在这里等于0 说明是最后一个汉字
			//DisplayTagFlag = EndFlag;
		}
		//UART_PRINTF("###### --->>CharDisplayInd1 = %d  CharDisplayInd2 = %d\r\n",CharDisplayInd1,CharDisplayInd2);
		flash_read_data((uint8_t *)DisplayBuf,
			FLASH_STORE_LED_ADDR+CharDisplayInd1*FLASH_STORE_LED_ADDR_UNIT, FLASH_STORE_LED_ADDR_UNIT);
		//if(DisplayBuf[3].Mode!= DisplayBuf[0].Mode) 	//在这里判断如果显示模式变化。在进入下次调用模式切换时清除显示缓冲
		{
			DisplayModeChangeFlag = 1;  //该种不管模式切不切,每次都需要这个变量等于1去清屏
			DisplayBuf[3] = DisplayBuf[0];   //20180716
		}
	}
}
void WjLedDisplayModeSelectFun(void)
{
	if (StartDelayFlag)
	{
		WjDelayDisplayNextCharFun();
	}
	if (DisplayModeChangeFlag)
	{
		memset(LED2X64,0,LED2X64LEN);
		CharDisplayInd2 = 0;
		DisplayModeChangeFlag = 0;
	}
	UART_PRINTF("DisplayBuf[3].Mode = %d\r\n",DisplayBuf[3].Mode);
	switch (DisplayBuf[3].Mode)
	{
		case SERIES_LEFT_SHIFT_DISPLAY_MODE:
		case SERIES_RIGHT_SHIFT_DISPLAY_MODE:
			WjSeriesLeftRightShiftDisplay();
			//StartDisplayFlag  = ColumnScan;
			break;
		case SERIES_UP_SHIFT_DISPLAY_MODE:
			WjSeriesUpShiftDisplay();
			//StartDisplayFlag  = ColumnScan;
			break;
		case SERIES_DOWN_SHIFT_DISPLAY_MODE:
			WjSeriesDownShiftDisplay();
			//StartDisplayFlag  = ColumnScan;
			break;
		case STATIC_DISPLAY_MODE:
			WjStaticDisplay();
			//StartDisplayFlag  = ColumnScan;
			break;
		case LEFT_SHIFT_DISPLAY_MODE:         //向左平移   
			WjLeftShiftDisplay();
			//StartDisplayFlag  = ColumnScan;
			break;
		case RIGHT_SHIFT_DISPLAY_MODE:        //向右平移
			WjRightShiftDisplay();
			//StartDisplayFlag = ColumnScan;
			break;		
		case UP_SHIFT_DISPLAY_MODE:           //向上平移
			WjUpShiftDisplay();
			//StartDisplayFlag = ColumnScan;
			break;
		case DOWN_SHIFT_DISPLAY_MODE:         //向下平移
			WjDownShiftDisplay();
			//StartDisplayFlag = ColumnScan;
			break;	
		case LEFT_RIGHT_OPEN_DISPLAY_MODE:    //左右对开 
			WjLeftRightOpenDisplay();
			//StartDisplayFlag = ColumnScan;
			break;	
		case LEFT_RIGHT_CLOSE_DISPLAY_MODE:   //左右闭合
			WjLeftRightCloseDisplay();
			//StartDisplayFlag = ColumnScan;
			break;
		case UP_DOWN_OPEN_DISPLAY_MODE:       //上下对开
			WjUpDownOpenDisplay();
			//StartDisplayFlag = ColumnScan;
			break;
		case UP_DOWN_CLOSE_DISPLAY_MODE:       //上下闭合
			WjUpDownCloseDisplay();
			//StartDisplayFlag = ColumnScan;
			break;
		case LEFT2RIGHT_COLUMN_SCAN_DISPLAY_MODE:  //向右镭射
			WjLeft2RightScanDisplay();
			//StartDisplayFlag = ColumnScan;
			break;
		case RIGHT2LEFT_COLUMN_SCAN_DISPLAY_MODE:  //向左镭射
			WjRight2LeftScanDisplay();
			//StartDisplayFlag = ColumnScan;
			break;
			
		case UP2DOWN_LINE_SCAN_DISPLAY_MODE:       //向下镭射
			WjUp2DownScanDisplay();
			//StartDisplayFlag = ColumnScan;
			break;
		case DOWN2UP_LINE_SCAN_DISPLAY_MODE:       //向上镭射
			WjDown2UpScanDisplay();
			//StartDisplayFlag = ColumnScan;
			break;
		case NO_DISPLAY_MODE:
			WjNoDisplay();
			break;
		
		default:
			break;
		
	}
}

void WjColumn2LineTransform(uint8_t *Obj,uint8_t *Src) //逐列顺向阴码-->> 逐行逆向阴码
{	
	uint8_t SrcInd = 0;
	uint8_t SrcBitInd = 0;
	uint8_t ObjInd = 0;

	memset(Obj,0,ARRAY_ROW_NUM);   //每次要清零
	
	for(SrcBitInd = 0,ObjInd=0; SrcBitInd<8; ObjInd+=3,SrcBitInd++)  //24*24上半部分
	{
		for(SrcInd = 0;SrcInd < 8; SrcInd++)
			Obj[ObjInd] += ((Src[SrcInd*3]>>(7-SrcBitInd))&0x01) << SrcInd; //低位在前
		//UART_PRINTF("0x%x",Obj[ObjInd]);
		for(SrcInd = 0;SrcInd < 8;SrcInd++)
			Obj[ObjInd+1] += ((Src[24+3*SrcInd]>>(7-SrcBitInd))&0x01)<>(7-SrcBitInd))&0x01)<>(7-SrcBitInd))&0x01) << SrcInd; //低位在前
		//UART_PRINTF("0x%x",Obj[ObjInd]);	
		for(SrcInd = 0;SrcInd < 8;SrcInd++)
			Obj[ObjInd+1] += ((Src[25+3*SrcInd]>>(7-SrcBitInd))&0x01)<>(7-SrcBitInd))&0x01)<>(7-SrcBitInd))&0x01) << SrcInd; //低位在前
		//UART_PRINTF("0x%x",Obj[ObjInd]);
		for(SrcInd = 0;SrcInd < 8;SrcInd++)
			Obj[ObjInd+1] += ((Src[26+3*SrcInd]>>(7-SrcBitInd))&0x01)<>(7-SrcBitInd))&0x01)<

74hc595Led.h代码

#ifndef _74HC595LED_H_
#define _74HC595LED_H_


#define ARRAY_RANK_NUM  4
#define ARRAY_ROW_NUM   72    //32      //16*16点阵  
#define SERIES_DISPLAY_END_TO_FIRST_DELAY   100

#define FLASH_STORE_TOTAL_ADDR  0x42000
#define FLASH_STORE_LED_ADDR 0x42100   //用的是扇区擦除,程序中只擦除了0x42000  -->0x43000一个扇区   == (0x43000-0x42100)/75 = 51个汉字
#define FLASH_STORE_LED_ADDR_UNIT 75   //struct DisplayContent 结构体的大小

#define LED2X64LEN 74  //34	

typedef struct DisplayContent
{
	//uint8_t Total;                        //需要显示的总条数
	//uint8_t Colour;                          //显示颜色
	uint8_t Mode;                         //显示模式 
	uint8_t Speed;                        //显示速度   10ms的单位
	uint8_t Time;                         //显示时间
	uint8_t DisplayBuf[ARRAY_ROW_NUM];   //显示的点阵
}DisplayContent;

enum DisPlayMode
{
	NO_DISPLAY_MODE,
		
	STATIC_DISPLAY_MODE,    
		
	SERIES_LEFT_SHIFT_DISPLAY_MODE,
	SERIES_RIGHT_SHIFT_DISPLAY_MODE,
	SERIES_UP_SHIFT_DISPLAY_MODE,
	SERIES_DOWN_SHIFT_DISPLAY_MODE,
	
	LEFT_SHIFT_DISPLAY_MODE,
	RIGHT_SHIFT_DISPLAY_MODE,
	UP_SHIFT_DISPLAY_MODE,
	DOWN_SHIFT_DISPLAY_MODE,
	
	LEFT_RIGHT_OPEN_DISPLAY_MODE,   //0x0a
	LEFT_RIGHT_CLOSE_DISPLAY_MODE,
	UP_DOWN_OPEN_DISPLAY_MODE,
	UP_DOWN_CLOSE_DISPLAY_MODE,
	
	LEFT2RIGHT_COLUMN_SCAN_DISPLAY_MODE,
	RIGHT2LEFT_COLUMN_SCAN_DISPLAY_MODE,
	UP2DOWN_LINE_SCAN_DISPLAY_MODE,
	DOWN2UP_LINE_SCAN_DISPLAY_MODE
};

enum DelayDisplayNum
{
	NO_DELAY_DISPLAY,
	SERIES_DISPLAY_DELAY_NEXT_CHAR_NUM = 4,
	DISORDER_DISPLAY_DELAY_NEXT_CHAR_NUM = 25, // 20 ==>>24_24   38 ==>> 32*32 
	END_DISPLAY_DELAY_NEXT_FRAME_NUM = 30
};

typedef enum DisplayStartMidEndFlag
{
	NoFlag,
	MidFlag,
	EndFlag,
	UpDataFlag
}DisplayTag;

typedef enum ScanDisplayFlag
{
	NoScan,
	ColumnScan,
	LineScan	
}ScanDisplay;

extern uint8_t Mould[3];  								//控制该列的取模值,低电平亮灯,每个模组16行,占2字节   //行
extern uint8_t upright[3];								//控制某一列,高电平亮灯,每个模组16列,占2字节     //列
extern uint8_t LED2X64[LED2X64LEN];							//开辟缓存空间,被定时器随时调用。每列两个字节,多加2个用于移位操作。
extern uint8_t DisplayTotal;
extern uint8_t CharDisplayInd1;
extern uint8_t CharDisplayInd2; 
extern ScanDisplay StartDisplayFlag;
extern bool StartDelayFlag;
extern DisplayTag DisplayTagFlag;
extern DisplayContent DisplayBuf[ARRAY_RANK_NUM];

void HC595WriteLineScan(void);	
void HC595WriteColumnScan(void);

void WjLedDisplayModeSelectFun(void);
void WjColumn2LineTransform(uint8_t *Obj,uint8_t *Src);
	
#endif

在main.c的while循环中调用接口WriteColumnScan,把要显示的点阵数据复制给LED2X64数组ji即可

你可能感兴趣的:(外围驱动)